1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.providers.settings; 18 19 import static android.os.Process.FIRST_APPLICATION_UID; 20 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.content.Context; 24 import android.content.pm.ApplicationInfo; 25 import android.content.pm.PackageInfo; 26 import android.content.pm.PackageManager; 27 import android.os.Binder; 28 import android.os.Build; 29 import android.os.FileUtils; 30 import android.os.Handler; 31 import android.os.Looper; 32 import android.os.Message; 33 import android.os.SystemClock; 34 import android.os.UserHandle; 35 import android.provider.Settings; 36 import android.provider.Settings.Global; 37 import android.providers.settings.SettingsOperationProto; 38 import android.text.TextUtils; 39 import android.util.ArrayMap; 40 import android.util.ArraySet; 41 import android.util.AtomicFile; 42 import android.util.Base64; 43 import android.util.Slog; 44 import android.util.TimeUtils; 45 import android.util.TypedXmlPullParser; 46 import android.util.TypedXmlSerializer; 47 import android.util.Xml; 48 import android.util.proto.ProtoOutputStream; 49 50 import com.android.internal.annotations.GuardedBy; 51 import com.android.internal.annotations.VisibleForTesting; 52 import com.android.internal.util.ArrayUtils; 53 import com.android.internal.util.FrameworkStatsLog; 54 55 import libcore.io.IoUtils; 56 57 import org.xmlpull.v1.XmlPullParser; 58 import org.xmlpull.v1.XmlPullParserException; 59 60 import java.io.File; 61 import java.io.FileInputStream; 62 import java.io.FileNotFoundException; 63 import java.io.FileOutputStream; 64 import java.io.IOException; 65 import java.io.PrintWriter; 66 import java.nio.file.Files; 67 import java.nio.file.Path; 68 import java.util.ArrayList; 69 import java.util.HashSet; 70 import java.util.Iterator; 71 import java.util.List; 72 import java.util.Map; 73 import java.util.Objects; 74 import java.util.Set; 75 76 /** 77 * This class contains the state for one type of settings. It is responsible 78 * for saving the state asynchronously to an XML file after a mutation and 79 * loading the from an XML file on construction. 80 * <p> 81 * This class uses the same lock as the settings provider to ensure that 82 * multiple changes made by the settings provider, e,g, upgrade, bulk insert, 83 * etc, are atomically persisted since the asynchronous persistence is using 84 * the same lock to grab the current state to write to disk. 85 * </p> 86 */ 87 final class SettingsState { 88 private static final boolean DEBUG = false; 89 private static final boolean DEBUG_PERSISTENCE = false; 90 91 private static final String LOG_TAG = "SettingsState"; 92 93 static final String SYSTEM_PACKAGE_NAME = "android"; 94 95 static final int SETTINGS_VERSION_NEW_ENCODING = 121; 96 97 private static final long WRITE_SETTINGS_DELAY_MILLIS = 200; 98 private static final long MAX_WRITE_SETTINGS_DELAY_MILLIS = 2000; 99 100 public static final int MAX_BYTES_PER_APP_PACKAGE_UNLIMITED = -1; 101 public static final int MAX_BYTES_PER_APP_PACKAGE_LIMITED = 20000; 102 103 public static final int VERSION_UNDEFINED = -1; 104 105 public static final String FALLBACK_FILE_SUFFIX = ".fallback"; 106 107 private static final String TAG_SETTINGS = "settings"; 108 private static final String TAG_SETTING = "setting"; 109 private static final String ATTR_PACKAGE = "package"; 110 private static final String ATTR_DEFAULT_SYS_SET = "defaultSysSet"; 111 private static final String ATTR_TAG = "tag"; 112 private static final String ATTR_TAG_BASE64 = "tagBase64"; 113 114 private static final String ATTR_VERSION = "version"; 115 private static final String ATTR_ID = "id"; 116 private static final String ATTR_NAME = "name"; 117 118 private static final String TAG_NAMESPACE_HASHES = "namespaceHashes"; 119 private static final String TAG_NAMESPACE_HASH = "namespaceHash"; 120 private static final String ATTR_NAMESPACE = "namespace"; 121 private static final String ATTR_BANNED_HASH = "bannedHash"; 122 123 private static final String ATTR_PRESERVE_IN_RESTORE = "preserve_in_restore"; 124 125 /** 126 * Non-binary value will be written in this attributes. 127 */ 128 private static final String ATTR_VALUE = "value"; 129 private static final String ATTR_DEFAULT_VALUE = "defaultValue"; 130 131 /** 132 * KXmlSerializer won't like some characters. We encode such characters 133 * in base64 and store in this attribute. 134 * NOTE: A null value will have *neither* ATTR_VALUE nor ATTR_VALUE_BASE64. 135 */ 136 private static final String ATTR_VALUE_BASE64 = "valueBase64"; 137 private static final String ATTR_DEFAULT_VALUE_BASE64 = "defaultValueBase64"; 138 139 // This was used in version 120 and before. 140 private static final String NULL_VALUE_OLD_STYLE = "null"; 141 142 private static final int HISTORICAL_OPERATION_COUNT = 20; 143 private static final String HISTORICAL_OPERATION_UPDATE = "update"; 144 private static final String HISTORICAL_OPERATION_DELETE = "delete"; 145 private static final String HISTORICAL_OPERATION_PERSIST = "persist"; 146 private static final String HISTORICAL_OPERATION_INITIALIZE = "initialize"; 147 private static final String HISTORICAL_OPERATION_RESET = "reset"; 148 149 private static final String SHELL_PACKAGE_NAME = "com.android.shell"; 150 private static final String ROOT_PACKAGE_NAME = "root"; 151 152 private static final String NULL_VALUE = "null"; 153 154 private static final ArraySet<String> sSystemPackages = new ArraySet<>(); 155 156 private final Object mWriteLock = new Object(); 157 158 private final Object mLock; 159 160 private final Handler mHandler; 161 162 @GuardedBy("mLock") 163 private final Context mContext; 164 165 @GuardedBy("mLock") 166 private final ArrayMap<String, Setting> mSettings = new ArrayMap<>(); 167 168 @GuardedBy("mLock") 169 private final ArrayMap<String, String> mNamespaceBannedHashes = new ArrayMap<>(); 170 171 @GuardedBy("mLock") 172 private final ArrayMap<String, Integer> mPackageToMemoryUsage; 173 174 @GuardedBy("mLock") 175 private final int mMaxBytesPerAppPackage; 176 177 @GuardedBy("mLock") 178 private final File mStatePersistFile; 179 180 @GuardedBy("mLock") 181 private final String mStatePersistTag; 182 183 private final Setting mNullSetting = new Setting(null, null, false, null, null) { 184 @Override 185 public boolean isNull() { 186 return true; 187 } 188 }; 189 190 @GuardedBy("mLock") 191 private final List<HistoricalOperation> mHistoricalOperations; 192 193 @GuardedBy("mLock") 194 public final int mKey; 195 196 @GuardedBy("mLock") 197 private int mVersion = VERSION_UNDEFINED; 198 199 @GuardedBy("mLock") 200 private long mLastNotWrittenMutationTimeMillis; 201 202 @GuardedBy("mLock") 203 private boolean mDirty; 204 205 @GuardedBy("mLock") 206 private boolean mWriteScheduled; 207 208 @GuardedBy("mLock") 209 private long mNextId; 210 211 @GuardedBy("mLock") 212 private int mNextHistoricalOpIdx; 213 214 public static final int SETTINGS_TYPE_GLOBAL = 0; 215 public static final int SETTINGS_TYPE_SYSTEM = 1; 216 public static final int SETTINGS_TYPE_SECURE = 2; 217 public static final int SETTINGS_TYPE_SSAID = 3; 218 public static final int SETTINGS_TYPE_CONFIG = 4; 219 220 public static final int SETTINGS_TYPE_MASK = 0xF0000000; 221 public static final int SETTINGS_TYPE_SHIFT = 28; 222 makeKey(int type, int userId)223 public static int makeKey(int type, int userId) { 224 return (type << SETTINGS_TYPE_SHIFT) | userId; 225 } 226 getTypeFromKey(int key)227 public static int getTypeFromKey(int key) { 228 return key >>> SETTINGS_TYPE_SHIFT; 229 } 230 getUserIdFromKey(int key)231 public static int getUserIdFromKey(int key) { 232 return key & ~SETTINGS_TYPE_MASK; 233 } 234 settingTypeToString(int type)235 public static String settingTypeToString(int type) { 236 switch (type) { 237 case SETTINGS_TYPE_CONFIG: { 238 return "SETTINGS_CONFIG"; 239 } 240 case SETTINGS_TYPE_GLOBAL: { 241 return "SETTINGS_GLOBAL"; 242 } 243 case SETTINGS_TYPE_SECURE: { 244 return "SETTINGS_SECURE"; 245 } 246 case SETTINGS_TYPE_SYSTEM: { 247 return "SETTINGS_SYSTEM"; 248 } 249 case SETTINGS_TYPE_SSAID: { 250 return "SETTINGS_SSAID"; 251 } 252 default: { 253 return "UNKNOWN"; 254 } 255 } 256 } 257 keyToString(int key)258 public static String keyToString(int key) { 259 return "Key[user=" + getUserIdFromKey(key) + ";type=" 260 + settingTypeToString(getTypeFromKey(key)) + "]"; 261 } 262 SettingsState(Context context, Object lock, File file, int key, int maxBytesPerAppPackage, Looper looper)263 public SettingsState(Context context, Object lock, File file, int key, 264 int maxBytesPerAppPackage, Looper looper) { 265 // It is important that we use the same lock as the settings provider 266 // to ensure multiple mutations on this state are atomically persisted 267 // as the async persistence should be blocked while we make changes. 268 mContext = context; 269 mLock = lock; 270 mStatePersistFile = file; 271 mStatePersistTag = "settings-" + getTypeFromKey(key) + "-" + getUserIdFromKey(key); 272 mKey = key; 273 mHandler = new MyHandler(looper); 274 if (maxBytesPerAppPackage == MAX_BYTES_PER_APP_PACKAGE_LIMITED) { 275 mMaxBytesPerAppPackage = maxBytesPerAppPackage; 276 mPackageToMemoryUsage = new ArrayMap<>(); 277 } else { 278 mMaxBytesPerAppPackage = maxBytesPerAppPackage; 279 mPackageToMemoryUsage = null; 280 } 281 282 mHistoricalOperations = Build.IS_DEBUGGABLE 283 ? new ArrayList<>(HISTORICAL_OPERATION_COUNT) : null; 284 285 synchronized (mLock) { 286 readStateSyncLocked(); 287 } 288 } 289 290 // The settings provider must hold its lock when calling here. 291 @GuardedBy("mLock") getVersionLocked()292 public int getVersionLocked() { 293 return mVersion; 294 } 295 getNullSetting()296 public Setting getNullSetting() { 297 return mNullSetting; 298 } 299 300 // The settings provider must hold its lock when calling here. 301 @GuardedBy("mLock") setVersionLocked(int version)302 public void setVersionLocked(int version) { 303 if (version == mVersion) { 304 return; 305 } 306 mVersion = version; 307 308 scheduleWriteIfNeededLocked(); 309 } 310 311 // The settings provider must hold its lock when calling here. 312 @GuardedBy("mLock") removeSettingsForPackageLocked(String packageName)313 public void removeSettingsForPackageLocked(String packageName) { 314 boolean removedSomething = false; 315 316 final int settingCount = mSettings.size(); 317 for (int i = settingCount - 1; i >= 0; i--) { 318 String name = mSettings.keyAt(i); 319 // Settings defined by us are never dropped. 320 if (Settings.System.PUBLIC_SETTINGS.contains(name) 321 || Settings.System.PRIVATE_SETTINGS.contains(name)) { 322 continue; 323 } 324 Setting setting = mSettings.valueAt(i); 325 if (packageName.equals(setting.packageName)) { 326 mSettings.removeAt(i); 327 removedSomething = true; 328 } 329 } 330 331 if (removedSomething) { 332 scheduleWriteIfNeededLocked(); 333 } 334 } 335 336 // The settings provider must hold its lock when calling here. 337 @GuardedBy("mLock") getSettingNamesLocked()338 public List<String> getSettingNamesLocked() { 339 ArrayList<String> names = new ArrayList<>(); 340 final int settingsCount = mSettings.size(); 341 for (int i = 0; i < settingsCount; i++) { 342 String name = mSettings.keyAt(i); 343 names.add(name); 344 } 345 return names; 346 } 347 348 // The settings provider must hold its lock when calling here. getSettingLocked(String name)349 public Setting getSettingLocked(String name) { 350 if (TextUtils.isEmpty(name)) { 351 return mNullSetting; 352 } 353 Setting setting = mSettings.get(name); 354 if (setting != null) { 355 return new Setting(setting); 356 } 357 return mNullSetting; 358 } 359 360 // The settings provider must hold its lock when calling here. updateSettingLocked(String name, String value, String tag, boolean makeValue, String packageName)361 public boolean updateSettingLocked(String name, String value, String tag, 362 boolean makeValue, String packageName) { 363 if (!hasSettingLocked(name)) { 364 return false; 365 } 366 367 return insertSettingLocked(name, value, tag, makeValue, packageName); 368 } 369 370 // The settings provider must hold its lock when calling here. 371 @GuardedBy("mLock") resetSettingDefaultValueLocked(String name)372 public void resetSettingDefaultValueLocked(String name) { 373 Setting oldSetting = getSettingLocked(name); 374 if (oldSetting != null && !oldSetting.isNull() && oldSetting.getDefaultValue() != null) { 375 String oldValue = oldSetting.getValue(); 376 String oldDefaultValue = oldSetting.getDefaultValue(); 377 Setting newSetting = new Setting(name, oldSetting.getValue(), null, 378 oldSetting.getPackageName(), oldSetting.getTag(), false, 379 oldSetting.getId()); 380 int newSize = getNewMemoryUsagePerPackageLocked(newSetting.getPackageName(), 0, 381 oldValue, newSetting.getValue(), oldDefaultValue, newSetting.getDefaultValue()); 382 checkNewMemoryUsagePerPackageLocked(newSetting.getPackageName(), newSize); 383 mSettings.put(name, newSetting); 384 updateMemoryUsagePerPackageLocked(newSetting.getPackageName(), newSize); 385 scheduleWriteIfNeededLocked(); 386 } 387 } 388 389 // The settings provider must hold its lock when calling here. insertSettingOverrideableByRestoreLocked(String name, String value, String tag, boolean makeDefault, String packageName)390 public boolean insertSettingOverrideableByRestoreLocked(String name, String value, String tag, 391 boolean makeDefault, String packageName) { 392 return insertSettingLocked(name, value, tag, makeDefault, false, packageName, 393 /* overrideableByRestore */ true); 394 } 395 396 // The settings provider must hold its lock when calling here. 397 @GuardedBy("mLock") insertSettingLocked(String name, String value, String tag, boolean makeDefault, String packageName)398 public boolean insertSettingLocked(String name, String value, String tag, 399 boolean makeDefault, String packageName) { 400 return insertSettingLocked(name, value, tag, makeDefault, false, packageName, 401 /* overrideableByRestore */ false); 402 } 403 404 // The settings provider must hold its lock when calling here. 405 @GuardedBy("mLock") insertSettingLocked(String name, String value, String tag, boolean makeDefault, boolean forceNonSystemPackage, String packageName, boolean overrideableByRestore)406 public boolean insertSettingLocked(String name, String value, String tag, 407 boolean makeDefault, boolean forceNonSystemPackage, String packageName, 408 boolean overrideableByRestore) { 409 if (TextUtils.isEmpty(name)) { 410 return false; 411 } 412 413 Setting oldState = mSettings.get(name); 414 String oldValue = (oldState != null) ? oldState.value : null; 415 String oldDefaultValue = (oldState != null) ? oldState.defaultValue : null; 416 String newDefaultValue = makeDefault ? value : oldDefaultValue; 417 418 int newSize = getNewMemoryUsagePerPackageLocked(packageName, 419 oldValue == null ? name.length() : 0 /* deltaKeySize */, 420 oldValue, value, oldDefaultValue, newDefaultValue); 421 checkNewMemoryUsagePerPackageLocked(packageName, newSize); 422 423 Setting newState; 424 425 if (oldState != null) { 426 if (!oldState.update(value, makeDefault, packageName, tag, forceNonSystemPackage, 427 overrideableByRestore)) { 428 return false; 429 } 430 newState = oldState; 431 } else { 432 newState = new Setting(name, value, makeDefault, packageName, tag, 433 forceNonSystemPackage); 434 mSettings.put(name, newState); 435 } 436 437 FrameworkStatsLog.write(FrameworkStatsLog.SETTING_CHANGED, name, value, newState.value, 438 oldValue, tag, makeDefault, getUserIdFromKey(mKey), 439 FrameworkStatsLog.SETTING_CHANGED__REASON__UPDATED); 440 441 addHistoricalOperationLocked(HISTORICAL_OPERATION_UPDATE, newState); 442 443 updateMemoryUsagePerPackageLocked(packageName, newSize); 444 445 scheduleWriteIfNeededLocked(); 446 447 return true; 448 } 449 450 @GuardedBy("mLock") isNewConfigBannedLocked(String prefix, Map<String, String> keyValues)451 public boolean isNewConfigBannedLocked(String prefix, Map<String, String> keyValues) { 452 // Replaces old style "null" String values with actual null's. This is done to simulate 453 // what will happen to String "null" values when they are written to Settings. This needs to 454 // be done here make sure that config hash computed during is banned check matches the 455 // one computed during banning when values are already stored. 456 keyValues = removeNullValueOldStyle(keyValues); 457 String bannedHash = mNamespaceBannedHashes.get(prefix); 458 if (bannedHash == null) { 459 return false; 460 } 461 return bannedHash.equals(hashCode(keyValues)); 462 } 463 464 @GuardedBy("mLock") unbanAllConfigIfBannedConfigUpdatedLocked(String prefix)465 public void unbanAllConfigIfBannedConfigUpdatedLocked(String prefix) { 466 // If the prefix updated is a banned namespace, clear mNamespaceBannedHashes 467 // to unban all unbanned namespaces. 468 if (mNamespaceBannedHashes.get(prefix) != null) { 469 mNamespaceBannedHashes.clear(); 470 scheduleWriteIfNeededLocked(); 471 } 472 } 473 474 @GuardedBy("mLock") banConfigurationLocked(String prefix, Map<String, String> keyValues)475 public void banConfigurationLocked(String prefix, Map<String, String> keyValues) { 476 if (prefix == null || keyValues.isEmpty()) { 477 return; 478 } 479 // The write is intentionally not scheduled here, banned hashes should and will be written 480 // when the related setting changes are written 481 mNamespaceBannedHashes.put(prefix, hashCode(keyValues)); 482 } 483 484 @GuardedBy("mLock") getAllConfigPrefixesLocked()485 public Set<String> getAllConfigPrefixesLocked() { 486 Set<String> prefixSet = new HashSet<>(); 487 final int settingsCount = mSettings.size(); 488 for (int i = 0; i < settingsCount; i++) { 489 String name = mSettings.keyAt(i); 490 prefixSet.add(name.split("/")[0] + "/"); 491 } 492 return prefixSet; 493 } 494 495 // The settings provider must hold its lock when calling here. 496 // Returns the list of keys which changed (added, updated, or deleted). 497 @GuardedBy("mLock") setSettingsLocked(String prefix, Map<String, String> keyValues, String packageName)498 public List<String> setSettingsLocked(String prefix, Map<String, String> keyValues, 499 String packageName) { 500 List<String> changedKeys = new ArrayList<>(); 501 final Iterator<Map.Entry<String, Setting>> iterator = mSettings.entrySet().iterator(); 502 // Delete old keys with the prefix that are not part of the new set. 503 while (iterator.hasNext()) { 504 Map.Entry<String, Setting> entry = iterator.next(); 505 final String key = entry.getKey(); 506 final Setting oldState = entry.getValue(); 507 if (key != null && key.startsWith(prefix) && !keyValues.containsKey(key)) { 508 iterator.remove(); 509 510 FrameworkStatsLog.write(FrameworkStatsLog.SETTING_CHANGED, key, 511 /* value= */ "", /* newValue= */ "", oldState.value, /* tag */ "", false, 512 getUserIdFromKey(mKey), FrameworkStatsLog.SETTING_CHANGED__REASON__DELETED); 513 addHistoricalOperationLocked(HISTORICAL_OPERATION_DELETE, oldState); 514 changedKeys.add(key); // key was removed 515 } 516 } 517 518 // Update/add new keys 519 for (String key : keyValues.keySet()) { 520 String value = keyValues.get(key); 521 String oldValue = null; 522 Setting state = mSettings.get(key); 523 if (state == null) { 524 state = new Setting(key, value, false, packageName, null); 525 mSettings.put(key, state); 526 changedKeys.add(key); // key was added 527 } else if (state.value != value) { 528 oldValue = state.value; 529 state.update(value, false, packageName, null, true, 530 /* overrideableByRestore */ false); 531 changedKeys.add(key); // key was updated 532 } else { 533 // this key/value already exists, no change and no logging necessary 534 continue; 535 } 536 537 FrameworkStatsLog.write(FrameworkStatsLog.SETTING_CHANGED, key, value, state.value, 538 oldValue, /* tag */ null, /* make default */ false, 539 getUserIdFromKey(mKey), FrameworkStatsLog.SETTING_CHANGED__REASON__UPDATED); 540 addHistoricalOperationLocked(HISTORICAL_OPERATION_UPDATE, state); 541 } 542 543 if (!changedKeys.isEmpty()) { 544 scheduleWriteIfNeededLocked(); 545 } 546 547 return changedKeys; 548 } 549 550 // The settings provider must hold its lock when calling here. persistSyncLocked()551 public void persistSyncLocked() { 552 mHandler.removeMessages(MyHandler.MSG_PERSIST_SETTINGS); 553 doWriteState(); 554 } 555 556 // The settings provider must hold its lock when calling here. 557 @GuardedBy("mLock") deleteSettingLocked(String name)558 public boolean deleteSettingLocked(String name) { 559 if (TextUtils.isEmpty(name) || !hasSettingLocked(name)) { 560 return false; 561 } 562 563 Setting oldState = mSettings.remove(name); 564 if (oldState == null) { 565 return false; 566 } 567 int newSize = getNewMemoryUsagePerPackageLocked(oldState.packageName, 568 -name.length() /* deltaKeySize */, 569 oldState.value, null, oldState.defaultValue, null); 570 571 FrameworkStatsLog.write(FrameworkStatsLog.SETTING_CHANGED, name, /* value= */ "", 572 /* newValue= */ "", oldState.value, /* tag */ "", false, getUserIdFromKey(mKey), 573 FrameworkStatsLog.SETTING_CHANGED__REASON__DELETED); 574 575 updateMemoryUsagePerPackageLocked(oldState.packageName, newSize); 576 577 addHistoricalOperationLocked(HISTORICAL_OPERATION_DELETE, oldState); 578 579 scheduleWriteIfNeededLocked(); 580 581 return true; 582 } 583 584 // The settings provider must hold its lock when calling here. 585 @GuardedBy("mLock") resetSettingLocked(String name)586 public boolean resetSettingLocked(String name) { 587 if (TextUtils.isEmpty(name) || !hasSettingLocked(name)) { 588 return false; 589 } 590 591 Setting setting = mSettings.get(name); 592 if (setting == null) { 593 return false; 594 } 595 596 Setting oldSetting = new Setting(setting); 597 String oldValue = setting.getValue(); 598 String oldDefaultValue = setting.getDefaultValue(); 599 600 int newSize = getNewMemoryUsagePerPackageLocked(setting.packageName, 0, oldValue, 601 oldDefaultValue, oldDefaultValue, oldDefaultValue); 602 checkNewMemoryUsagePerPackageLocked(setting.packageName, newSize); 603 604 if (!setting.reset()) { 605 return false; 606 } 607 608 updateMemoryUsagePerPackageLocked(setting.packageName, newSize); 609 610 addHistoricalOperationLocked(HISTORICAL_OPERATION_RESET, oldSetting); 611 612 scheduleWriteIfNeededLocked(); 613 614 return true; 615 } 616 617 // The settings provider must hold its lock when calling here. 618 @GuardedBy("mLock") destroyLocked(Runnable callback)619 public void destroyLocked(Runnable callback) { 620 mHandler.removeMessages(MyHandler.MSG_PERSIST_SETTINGS); 621 if (callback != null) { 622 if (mDirty) { 623 // Do it without a delay. 624 mHandler.obtainMessage(MyHandler.MSG_PERSIST_SETTINGS, 625 callback).sendToTarget(); 626 return; 627 } 628 callback.run(); 629 } 630 } 631 632 @GuardedBy("mLock") addHistoricalOperationLocked(String type, Setting setting)633 private void addHistoricalOperationLocked(String type, Setting setting) { 634 if (mHistoricalOperations == null) { 635 return; 636 } 637 HistoricalOperation operation = new HistoricalOperation( 638 System.currentTimeMillis(), type, 639 setting != null ? new Setting(setting) : null); 640 if (mNextHistoricalOpIdx >= mHistoricalOperations.size()) { 641 mHistoricalOperations.add(operation); 642 } else { 643 mHistoricalOperations.set(mNextHistoricalOpIdx, operation); 644 } 645 mNextHistoricalOpIdx++; 646 if (mNextHistoricalOpIdx >= HISTORICAL_OPERATION_COUNT) { 647 mNextHistoricalOpIdx = 0; 648 } 649 } 650 651 /** 652 * Dump historical operations as a proto buf. 653 * 654 * @param proto The proto buf stream to dump to 655 * @param fieldId The repeated field ID to use to save an operation to. 656 */ dumpHistoricalOperations(@onNull ProtoOutputStream proto, long fieldId)657 void dumpHistoricalOperations(@NonNull ProtoOutputStream proto, long fieldId) { 658 synchronized (mLock) { 659 if (mHistoricalOperations == null) { 660 return; 661 } 662 663 final int operationCount = mHistoricalOperations.size(); 664 for (int i = 0; i < operationCount; i++) { 665 int index = mNextHistoricalOpIdx - 1 - i; 666 if (index < 0) { 667 index = operationCount + index; 668 } 669 HistoricalOperation operation = mHistoricalOperations.get(index); 670 671 final long token = proto.start(fieldId); 672 proto.write(SettingsOperationProto.TIMESTAMP, operation.mTimestamp); 673 proto.write(SettingsOperationProto.OPERATION, operation.mOperation); 674 if (operation.mSetting != null) { 675 // Only add the name of the setting, since we don't know the historical package 676 // and values for it so they would be misleading to add here (all we could 677 // add is what the current data is). 678 proto.write(SettingsOperationProto.SETTING, operation.mSetting.getName()); 679 } 680 proto.end(token); 681 } 682 } 683 } 684 dumpHistoricalOperations(PrintWriter pw)685 public void dumpHistoricalOperations(PrintWriter pw) { 686 synchronized (mLock) { 687 if (mHistoricalOperations == null) { 688 return; 689 } 690 pw.println("Historical operations"); 691 final int operationCount = mHistoricalOperations.size(); 692 for (int i = 0; i < operationCount; i++) { 693 int index = mNextHistoricalOpIdx - 1 - i; 694 if (index < 0) { 695 index = operationCount + index; 696 } 697 HistoricalOperation operation = mHistoricalOperations.get(index); 698 pw.print(TimeUtils.formatForLogging(operation.mTimestamp)); 699 pw.print(" "); 700 pw.print(operation.mOperation); 701 if (operation.mSetting != null) { 702 pw.print(" "); 703 // Only print the name of the setting, since we don't know the 704 // historical package and values for it so they would be misleading 705 // to print here (all we could print is what the current data is). 706 pw.print(operation.mSetting.getName()); 707 } 708 pw.println(); 709 } 710 pw.println(); 711 pw.println(); 712 } 713 } 714 715 @GuardedBy("mLock") isExemptFromMemoryUsageCap(String packageName)716 private boolean isExemptFromMemoryUsageCap(String packageName) { 717 return mMaxBytesPerAppPackage == MAX_BYTES_PER_APP_PACKAGE_UNLIMITED 718 || SYSTEM_PACKAGE_NAME.equals(packageName); 719 } 720 721 @GuardedBy("mLock") checkNewMemoryUsagePerPackageLocked(String packageName, int newSize)722 private void checkNewMemoryUsagePerPackageLocked(String packageName, int newSize) 723 throws IllegalStateException { 724 if (isExemptFromMemoryUsageCap(packageName)) { 725 return; 726 } 727 if (newSize > mMaxBytesPerAppPackage) { 728 throw new IllegalStateException("You are adding too many system settings. " 729 + "You should stop using system settings for app specific data" 730 + " package: " + packageName); 731 } 732 } 733 734 @GuardedBy("mLock") getNewMemoryUsagePerPackageLocked(String packageName, int deltaKeySize, String oldValue, String newValue, String oldDefaultValue, String newDefaultValue)735 private int getNewMemoryUsagePerPackageLocked(String packageName, int deltaKeySize, 736 String oldValue, String newValue, String oldDefaultValue, String newDefaultValue) { 737 if (isExemptFromMemoryUsageCap(packageName)) { 738 return 0; 739 } 740 final Integer currentSize = mPackageToMemoryUsage.get(packageName); 741 final int oldValueSize = (oldValue != null) ? oldValue.length() : 0; 742 final int newValueSize = (newValue != null) ? newValue.length() : 0; 743 final int oldDefaultValueSize = (oldDefaultValue != null) ? oldDefaultValue.length() : 0; 744 final int newDefaultValueSize = (newDefaultValue != null) ? newDefaultValue.length() : 0; 745 final int deltaSize = deltaKeySize + newValueSize + newDefaultValueSize 746 - oldValueSize - oldDefaultValueSize; 747 return Math.max((currentSize != null) ? currentSize + deltaSize : deltaSize, 0); 748 } 749 750 @GuardedBy("mLock") updateMemoryUsagePerPackageLocked(String packageName, int newSize)751 private void updateMemoryUsagePerPackageLocked(String packageName, int newSize) { 752 if (isExemptFromMemoryUsageCap(packageName)) { 753 return; 754 } 755 if (DEBUG) { 756 Slog.i(LOG_TAG, "Settings for package: " + packageName 757 + " size: " + newSize + " bytes."); 758 } 759 mPackageToMemoryUsage.put(packageName, newSize); 760 } 761 762 @GuardedBy("mLock") hasSettingLocked(String name)763 private boolean hasSettingLocked(String name) { 764 return mSettings.indexOfKey(name) >= 0; 765 } 766 767 @GuardedBy("mLock") scheduleWriteIfNeededLocked()768 private void scheduleWriteIfNeededLocked() { 769 // If dirty then we have a write already scheduled. 770 if (!mDirty) { 771 mDirty = true; 772 writeStateAsyncLocked(); 773 } 774 } 775 776 @GuardedBy("mLock") writeStateAsyncLocked()777 private void writeStateAsyncLocked() { 778 final long currentTimeMillis = SystemClock.uptimeMillis(); 779 780 if (mWriteScheduled) { 781 mHandler.removeMessages(MyHandler.MSG_PERSIST_SETTINGS); 782 783 // If enough time passed, write without holding off anymore. 784 final long timeSinceLastNotWrittenMutationMillis = currentTimeMillis 785 - mLastNotWrittenMutationTimeMillis; 786 if (timeSinceLastNotWrittenMutationMillis >= MAX_WRITE_SETTINGS_DELAY_MILLIS) { 787 mHandler.obtainMessage(MyHandler.MSG_PERSIST_SETTINGS).sendToTarget(); 788 return; 789 } 790 791 // Hold off a bit more as settings are frequently changing. 792 final long maxDelayMillis = Math.max(mLastNotWrittenMutationTimeMillis 793 + MAX_WRITE_SETTINGS_DELAY_MILLIS - currentTimeMillis, 0); 794 final long writeDelayMillis = Math.min(WRITE_SETTINGS_DELAY_MILLIS, maxDelayMillis); 795 796 Message message = mHandler.obtainMessage(MyHandler.MSG_PERSIST_SETTINGS); 797 mHandler.sendMessageDelayed(message, writeDelayMillis); 798 } else { 799 mLastNotWrittenMutationTimeMillis = currentTimeMillis; 800 Message message = mHandler.obtainMessage(MyHandler.MSG_PERSIST_SETTINGS); 801 mHandler.sendMessageDelayed(message, WRITE_SETTINGS_DELAY_MILLIS); 802 mWriteScheduled = true; 803 } 804 } 805 doWriteState()806 private void doWriteState() { 807 boolean wroteState = false; 808 final int version; 809 final ArrayMap<String, Setting> settings; 810 final ArrayMap<String, String> namespaceBannedHashes; 811 812 synchronized (mLock) { 813 version = mVersion; 814 settings = new ArrayMap<>(mSettings); 815 namespaceBannedHashes = new ArrayMap<>(mNamespaceBannedHashes); 816 mDirty = false; 817 mWriteScheduled = false; 818 } 819 820 synchronized (mWriteLock) { 821 if (DEBUG_PERSISTENCE) { 822 Slog.i(LOG_TAG, "[PERSIST START]"); 823 } 824 825 AtomicFile destination = new AtomicFile(mStatePersistFile, mStatePersistTag); 826 FileOutputStream out = null; 827 try { 828 out = destination.startWrite(); 829 830 TypedXmlSerializer serializer = Xml.resolveSerializer(out); 831 serializer.startDocument(null, true); 832 serializer.startTag(null, TAG_SETTINGS); 833 serializer.attributeInt(null, ATTR_VERSION, version); 834 835 final int settingCount = settings.size(); 836 for (int i = 0; i < settingCount; i++) { 837 838 Setting setting = settings.valueAt(i); 839 if (setting.isTransient()) { 840 if (DEBUG_PERSISTENCE) { 841 Slog.i(LOG_TAG, "[SKIPPED PERSISTING]" + setting.getName()); 842 } 843 continue; 844 } 845 846 if (writeSingleSetting(mVersion, serializer, setting.getId(), setting.getName(), 847 setting.getValue(), setting.getDefaultValue(), setting.getPackageName(), 848 setting.getTag(), setting.isDefaultFromSystem(), 849 setting.isValuePreservedInRestore())) { 850 if (DEBUG_PERSISTENCE) { 851 Slog.i(LOG_TAG, "[PERSISTED]" + setting.getName() + "=" 852 + setting.getValue()); 853 } 854 } 855 } 856 serializer.endTag(null, TAG_SETTINGS); 857 858 serializer.startTag(null, TAG_NAMESPACE_HASHES); 859 for (int i = 0; i < namespaceBannedHashes.size(); i++) { 860 String namespace = namespaceBannedHashes.keyAt(i); 861 String bannedHash = namespaceBannedHashes.get(namespace); 862 if (writeSingleNamespaceHash(serializer, namespace, bannedHash)) { 863 if (DEBUG_PERSISTENCE) { 864 Slog.i(LOG_TAG, "[PERSISTED] namespace=" + namespace 865 + ", bannedHash=" + bannedHash); 866 } 867 } 868 } 869 serializer.endTag(null, TAG_NAMESPACE_HASHES); 870 serializer.endDocument(); 871 destination.finishWrite(out); 872 873 wroteState = true; 874 875 if (DEBUG_PERSISTENCE) { 876 Slog.i(LOG_TAG, "[PERSIST END]"); 877 } 878 } catch (Throwable t) { 879 Slog.wtf(LOG_TAG, "Failed to write settings, restoring backup", t); 880 if (t instanceof IOException) { 881 if (DEBUG) { 882 // we failed to create a directory, so log the permissions and existence 883 // state for the settings file and directory 884 logSettingsDirectoryInformation(destination.getBaseFile()); 885 } 886 if (t.getMessage().contains("Couldn't create directory")) { 887 // attempt to create the directory with Files.createDirectories, which 888 // throws more informative errors than File.mkdirs. 889 Path parentPath = destination.getBaseFile().getParentFile().toPath(); 890 try { 891 Files.createDirectories(parentPath); 892 if (DEBUG) { 893 Slog.i(LOG_TAG, "Successfully created " + parentPath); 894 } 895 } catch (Throwable t2) { 896 Slog.e(LOG_TAG, "Failed to write " + parentPath 897 + " with Files.writeDirectories", t2); 898 } 899 } 900 } 901 destination.failWrite(out); 902 } finally { 903 IoUtils.closeQuietly(out); 904 } 905 } 906 907 if (wroteState) { 908 synchronized (mLock) { 909 addHistoricalOperationLocked(HISTORICAL_OPERATION_PERSIST, null); 910 } 911 } 912 } 913 logSettingsDirectoryInformation(File settingsFile)914 private static void logSettingsDirectoryInformation(File settingsFile) { 915 File parent = settingsFile.getParentFile(); 916 Slog.i(LOG_TAG, "directory info for directory/file " + settingsFile 917 + " with stacktrace ", new Exception()); 918 File ancestorDir = parent; 919 while (ancestorDir != null) { 920 if (!ancestorDir.exists()) { 921 Slog.i(LOG_TAG, "ancestor directory " + ancestorDir 922 + " does not exist"); 923 ancestorDir = ancestorDir.getParentFile(); 924 } else { 925 Slog.i(LOG_TAG, "ancestor directory " + ancestorDir 926 + " exists"); 927 Slog.i(LOG_TAG, "ancestor directory " + ancestorDir 928 + " permissions: r: " + ancestorDir.canRead() + " w: " 929 + ancestorDir.canWrite() + " x: " + ancestorDir.canExecute()); 930 File ancestorParent = ancestorDir.getParentFile(); 931 if (ancestorParent != null) { 932 Slog.i(LOG_TAG, "ancestor's parent directory " + ancestorParent 933 + " permissions: r: " + ancestorParent.canRead() + " w: " 934 + ancestorParent.canWrite() + " x: " + ancestorParent.canExecute()); 935 } 936 break; 937 } 938 } 939 } 940 writeSingleSetting(int version, TypedXmlSerializer serializer, String id, String name, String value, String defaultValue, String packageName, String tag, boolean defaultSysSet, boolean isValuePreservedInRestore)941 static boolean writeSingleSetting(int version, TypedXmlSerializer serializer, String id, 942 String name, String value, String defaultValue, String packageName, 943 String tag, boolean defaultSysSet, boolean isValuePreservedInRestore) 944 throws IOException { 945 if (id == null || isBinary(id) || name == null || isBinary(name) 946 || packageName == null || isBinary(packageName)) { 947 if (DEBUG_PERSISTENCE) { 948 Slog.w(LOG_TAG, "Invalid arguments for writeSingleSetting: version=" + version 949 + ", id=" + id + ", name=" + name + ", value=" + value 950 + ", defaultValue=" + defaultValue + ", packageName=" + packageName 951 + ", tag=" + tag + ", defaultSysSet=" + defaultSysSet 952 + ", isValuePreservedInRestore=" + isValuePreservedInRestore); 953 } 954 return false; 955 } 956 serializer.startTag(null, TAG_SETTING); 957 serializer.attribute(null, ATTR_ID, id); 958 serializer.attribute(null, ATTR_NAME, name); 959 setValueAttribute(ATTR_VALUE, ATTR_VALUE_BASE64, 960 version, serializer, value); 961 serializer.attribute(null, ATTR_PACKAGE, packageName); 962 if (defaultValue != null) { 963 setValueAttribute(ATTR_DEFAULT_VALUE, ATTR_DEFAULT_VALUE_BASE64, 964 version, serializer, defaultValue); 965 serializer.attributeBoolean(null, ATTR_DEFAULT_SYS_SET, defaultSysSet); 966 setValueAttribute(ATTR_TAG, ATTR_TAG_BASE64, 967 version, serializer, tag); 968 } 969 if (isValuePreservedInRestore) { 970 serializer.attributeBoolean(null, ATTR_PRESERVE_IN_RESTORE, true); 971 } 972 serializer.endTag(null, TAG_SETTING); 973 return true; 974 } 975 setValueAttribute(String attr, String attrBase64, int version, TypedXmlSerializer serializer, String value)976 static void setValueAttribute(String attr, String attrBase64, int version, 977 TypedXmlSerializer serializer, String value) throws IOException { 978 if (version >= SETTINGS_VERSION_NEW_ENCODING) { 979 if (value == null) { 980 // Null value -> No ATTR_VALUE nor ATTR_VALUE_BASE64. 981 } else if (isBinary(value)) { 982 serializer.attribute(null, attrBase64, base64Encode(value)); 983 } else { 984 serializer.attribute(null, attr, value); 985 } 986 } else { 987 // Old encoding. 988 if (value == null) { 989 serializer.attribute(null, attr, NULL_VALUE_OLD_STYLE); 990 } else { 991 serializer.attribute(null, attr, value); 992 } 993 } 994 } 995 writeSingleNamespaceHash(TypedXmlSerializer serializer, String namespace, String bannedHashCode)996 private static boolean writeSingleNamespaceHash(TypedXmlSerializer serializer, String namespace, 997 String bannedHashCode) throws IOException { 998 if (namespace == null || bannedHashCode == null) { 999 if (DEBUG_PERSISTENCE) { 1000 Slog.w(LOG_TAG, "Invalid arguments for writeSingleNamespaceHash: namespace=" 1001 + namespace + ", bannedHashCode=" + bannedHashCode); 1002 } 1003 return false; 1004 } 1005 serializer.startTag(null, TAG_NAMESPACE_HASH); 1006 serializer.attribute(null, ATTR_NAMESPACE, namespace); 1007 serializer.attribute(null, ATTR_BANNED_HASH, bannedHashCode); 1008 serializer.endTag(null, TAG_NAMESPACE_HASH); 1009 return true; 1010 } 1011 hashCode(Map<String, String> keyValues)1012 private static String hashCode(Map<String, String> keyValues) { 1013 return Integer.toString(keyValues.hashCode()); 1014 } 1015 getValueAttribute(TypedXmlPullParser parser, String attr, String base64Attr)1016 private String getValueAttribute(TypedXmlPullParser parser, String attr, String base64Attr) { 1017 if (mVersion >= SETTINGS_VERSION_NEW_ENCODING) { 1018 final String value = parser.getAttributeValue(null, attr); 1019 if (value != null) { 1020 return value; 1021 } 1022 final String base64 = parser.getAttributeValue(null, base64Attr); 1023 if (base64 != null) { 1024 return base64Decode(base64); 1025 } 1026 // null has neither ATTR_VALUE nor ATTR_VALUE_BASE64. 1027 return null; 1028 } else { 1029 // Old encoding. 1030 final String stored = parser.getAttributeValue(null, attr); 1031 if (NULL_VALUE_OLD_STYLE.equals(stored)) { 1032 return null; 1033 } else { 1034 return stored; 1035 } 1036 } 1037 } 1038 1039 @GuardedBy("mLock") readStateSyncLocked()1040 private void readStateSyncLocked() throws IllegalStateException { 1041 FileInputStream in; 1042 AtomicFile file = new AtomicFile(mStatePersistFile); 1043 try { 1044 in = file.openRead(); 1045 } catch (FileNotFoundException fnfe) { 1046 Slog.w(LOG_TAG, "No settings state " + mStatePersistFile); 1047 if (DEBUG) { 1048 logSettingsDirectoryInformation(mStatePersistFile); 1049 } 1050 addHistoricalOperationLocked(HISTORICAL_OPERATION_INITIALIZE, null); 1051 return; 1052 } 1053 if (parseStateFromXmlStreamLocked(in)) { 1054 return; 1055 } 1056 1057 // Settings file exists but is corrupted. Retry with the fallback file 1058 final File statePersistFallbackFile = new File( 1059 mStatePersistFile.getAbsolutePath() + FALLBACK_FILE_SUFFIX); 1060 Slog.w(LOG_TAG, "Failed parsing settings file: " + mStatePersistFile 1061 + ", retrying with fallback file: " + statePersistFallbackFile); 1062 try { 1063 in = new AtomicFile(statePersistFallbackFile).openRead(); 1064 } catch (FileNotFoundException fnfe) { 1065 final String message = "No fallback file found for: " + mStatePersistFile; 1066 Slog.wtf(LOG_TAG, message); 1067 throw new IllegalStateException(message); 1068 } 1069 if (parseStateFromXmlStreamLocked(in)) { 1070 // Parsed state from fallback file. Restore original file with fallback file 1071 try { 1072 FileUtils.copy(statePersistFallbackFile, mStatePersistFile); 1073 } catch (IOException ignored) { 1074 // Failed to copy, but it's okay because we already parsed states from fallback file 1075 } 1076 } else { 1077 final String message = "Failed parsing settings file: " + mStatePersistFile; 1078 Slog.wtf(LOG_TAG, message); 1079 throw new IllegalStateException(message); 1080 } 1081 } 1082 1083 @GuardedBy("mLock") parseStateFromXmlStreamLocked(FileInputStream in)1084 private boolean parseStateFromXmlStreamLocked(FileInputStream in) { 1085 try { 1086 TypedXmlPullParser parser = Xml.resolvePullParser(in); 1087 parseStateLocked(parser); 1088 return true; 1089 } catch (XmlPullParserException | IOException e) { 1090 return false; 1091 } finally { 1092 IoUtils.closeQuietly(in); 1093 } 1094 } 1095 1096 /** 1097 * Uses AtomicFile to check if the file or its backup exists. 1098 * 1099 * @param file The file to check for existence 1100 * @return whether the original or backup exist 1101 */ stateFileExists(File file)1102 public static boolean stateFileExists(File file) { 1103 AtomicFile stateFile = new AtomicFile(file); 1104 return stateFile.exists(); 1105 } 1106 parseStateLocked(TypedXmlPullParser parser)1107 private void parseStateLocked(TypedXmlPullParser parser) 1108 throws IOException, XmlPullParserException { 1109 final int outerDepth = parser.getDepth(); 1110 int type; 1111 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 1112 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 1113 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 1114 continue; 1115 } 1116 1117 String tagName = parser.getName(); 1118 if (tagName.equals(TAG_SETTINGS)) { 1119 parseSettingsLocked(parser); 1120 } else if (tagName.equals(TAG_NAMESPACE_HASHES)) { 1121 parseNamespaceHash(parser); 1122 } 1123 } 1124 } 1125 1126 @GuardedBy("mLock") parseSettingsLocked(TypedXmlPullParser parser)1127 private void parseSettingsLocked(TypedXmlPullParser parser) 1128 throws IOException, XmlPullParserException { 1129 1130 mVersion = parser.getAttributeInt(null, ATTR_VERSION); 1131 1132 final int outerDepth = parser.getDepth(); 1133 int type; 1134 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 1135 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 1136 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 1137 continue; 1138 } 1139 1140 String tagName = parser.getName(); 1141 if (tagName.equals(TAG_SETTING)) { 1142 String id = parser.getAttributeValue(null, ATTR_ID); 1143 String name = parser.getAttributeValue(null, ATTR_NAME); 1144 String value = getValueAttribute(parser, ATTR_VALUE, ATTR_VALUE_BASE64); 1145 String packageName = parser.getAttributeValue(null, ATTR_PACKAGE); 1146 String defaultValue = getValueAttribute(parser, ATTR_DEFAULT_VALUE, 1147 ATTR_DEFAULT_VALUE_BASE64); 1148 boolean isPreservedInRestore = parser.getAttributeBoolean(null, 1149 ATTR_PRESERVE_IN_RESTORE, false); 1150 String tag = null; 1151 boolean fromSystem = false; 1152 if (defaultValue != null) { 1153 fromSystem = parser.getAttributeBoolean(null, ATTR_DEFAULT_SYS_SET, false); 1154 tag = getValueAttribute(parser, ATTR_TAG, ATTR_TAG_BASE64); 1155 } 1156 mSettings.put(name, new Setting(name, value, defaultValue, packageName, tag, 1157 fromSystem, id, isPreservedInRestore)); 1158 1159 if (DEBUG_PERSISTENCE) { 1160 Slog.i(LOG_TAG, "[RESTORED] " + name + "=" + value); 1161 } 1162 } 1163 } 1164 } 1165 1166 @GuardedBy("mLock") parseNamespaceHash(TypedXmlPullParser parser)1167 private void parseNamespaceHash(TypedXmlPullParser parser) 1168 throws IOException, XmlPullParserException { 1169 1170 final int outerDepth = parser.getDepth(); 1171 int type; 1172 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 1173 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 1174 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 1175 continue; 1176 } 1177 1178 if (parser.getName().equals(TAG_NAMESPACE_HASH)) { 1179 String namespace = parser.getAttributeValue(null, ATTR_NAMESPACE); 1180 String bannedHashCode = parser.getAttributeValue(null, ATTR_BANNED_HASH); 1181 mNamespaceBannedHashes.put(namespace, bannedHashCode); 1182 } 1183 } 1184 } 1185 removeNullValueOldStyle(Map<String, String> keyValues)1186 private static Map<String, String> removeNullValueOldStyle(Map<String, String> keyValues) { 1187 Iterator<Map.Entry<String, String>> it = keyValues.entrySet().iterator(); 1188 while (it.hasNext()) { 1189 Map.Entry<String, String> keyValueEntry = it.next(); 1190 if (NULL_VALUE_OLD_STYLE.equals(keyValueEntry.getValue())) { 1191 keyValueEntry.setValue(null); 1192 } 1193 } 1194 return keyValues; 1195 } 1196 1197 private final class MyHandler extends Handler { 1198 public static final int MSG_PERSIST_SETTINGS = 1; 1199 MyHandler(Looper looper)1200 public MyHandler(Looper looper) { 1201 super(looper); 1202 } 1203 1204 @Override handleMessage(Message message)1205 public void handleMessage(Message message) { 1206 switch (message.what) { 1207 case MSG_PERSIST_SETTINGS: { 1208 Runnable callback = (Runnable) message.obj; 1209 doWriteState(); 1210 if (callback != null) { 1211 callback.run(); 1212 } 1213 } 1214 break; 1215 } 1216 } 1217 } 1218 1219 private class HistoricalOperation { 1220 final long mTimestamp; 1221 final String mOperation; 1222 final Setting mSetting; 1223 HistoricalOperation(long timestamp, String operation, Setting setting)1224 public HistoricalOperation(long timestamp, 1225 String operation, Setting setting) { 1226 mTimestamp = timestamp; 1227 mOperation = operation; 1228 mSetting = setting; 1229 } 1230 } 1231 1232 class Setting { 1233 private String name; 1234 private String value; 1235 private String defaultValue; 1236 private String packageName; 1237 private String id; 1238 private String tag; 1239 // Whether the default is set by the system 1240 private boolean defaultFromSystem; 1241 // Whether the value of this setting will be preserved when restore happens. 1242 private boolean isValuePreservedInRestore; 1243 Setting(Setting other)1244 public Setting(Setting other) { 1245 name = other.name; 1246 value = other.value; 1247 defaultValue = other.defaultValue; 1248 packageName = other.packageName; 1249 id = other.id; 1250 defaultFromSystem = other.defaultFromSystem; 1251 tag = other.tag; 1252 isValuePreservedInRestore = other.isValuePreservedInRestore; 1253 } 1254 Setting(String name, String value, boolean makeDefault, String packageName, String tag)1255 public Setting(String name, String value, boolean makeDefault, String packageName, 1256 String tag) { 1257 this(name, value, makeDefault, packageName, tag, false); 1258 } 1259 Setting(String name, String value, boolean makeDefault, String packageName, String tag, boolean forceNonSystemPackage)1260 Setting(String name, String value, boolean makeDefault, String packageName, 1261 String tag, boolean forceNonSystemPackage) { 1262 this.name = name; 1263 // overrideableByRestore = true as the first initialization isn't considered a 1264 // modification. 1265 update(value, makeDefault, packageName, tag, forceNonSystemPackage, true); 1266 } 1267 Setting(String name, String value, String defaultValue, String packageName, String tag, boolean fromSystem, String id)1268 public Setting(String name, String value, String defaultValue, 1269 String packageName, String tag, boolean fromSystem, String id) { 1270 this(name, value, defaultValue, packageName, tag, fromSystem, id, 1271 /* isOverrideableByRestore */ false); 1272 } 1273 Setting(String name, String value, String defaultValue, String packageName, String tag, boolean fromSystem, String id, boolean isValuePreservedInRestore)1274 Setting(String name, String value, String defaultValue, 1275 String packageName, String tag, boolean fromSystem, String id, 1276 boolean isValuePreservedInRestore) { 1277 mNextId = Math.max(mNextId, Long.parseLong(id) + 1); 1278 if (NULL_VALUE.equals(value)) { 1279 value = null; 1280 } 1281 init(name, value, tag, defaultValue, packageName, fromSystem, id, 1282 isValuePreservedInRestore); 1283 } 1284 init(String name, String value, String tag, String defaultValue, String packageName, boolean fromSystem, String id, boolean isValuePreservedInRestore)1285 private void init(String name, String value, String tag, String defaultValue, 1286 String packageName, boolean fromSystem, String id, 1287 boolean isValuePreservedInRestore) { 1288 this.name = name; 1289 this.value = value; 1290 this.tag = tag; 1291 this.defaultValue = defaultValue; 1292 this.packageName = packageName; 1293 this.id = id; 1294 this.defaultFromSystem = fromSystem; 1295 this.isValuePreservedInRestore = isValuePreservedInRestore; 1296 } 1297 getName()1298 public String getName() { 1299 return name; 1300 } 1301 getKey()1302 public int getKey() { 1303 return mKey; 1304 } 1305 getValue()1306 public String getValue() { 1307 return value; 1308 } 1309 getTag()1310 public String getTag() { 1311 return tag; 1312 } 1313 getDefaultValue()1314 public String getDefaultValue() { 1315 return defaultValue; 1316 } 1317 getPackageName()1318 public String getPackageName() { 1319 return packageName; 1320 } 1321 isDefaultFromSystem()1322 public boolean isDefaultFromSystem() { 1323 return defaultFromSystem; 1324 } 1325 isValuePreservedInRestore()1326 public boolean isValuePreservedInRestore() { 1327 return isValuePreservedInRestore; 1328 } 1329 getId()1330 public String getId() { 1331 return id; 1332 } 1333 isNull()1334 public boolean isNull() { 1335 return false; 1336 } 1337 1338 /** @return whether the value changed */ reset()1339 public boolean reset() { 1340 // overrideableByRestore = true as resetting to default value isn't considered a 1341 // modification. 1342 return update(this.defaultValue, false, packageName, null, true, true, 1343 /* resetToDefault */ true); 1344 } 1345 isTransient()1346 public boolean isTransient() { 1347 switch (getTypeFromKey(getKey())) { 1348 case SETTINGS_TYPE_GLOBAL: 1349 return ArrayUtils.contains(Global.TRANSIENT_SETTINGS, getName()); 1350 } 1351 return false; 1352 } 1353 update(String value, boolean setDefault, String packageName, String tag, boolean forceNonSystemPackage, boolean overrideableByRestore)1354 public boolean update(String value, boolean setDefault, String packageName, String tag, 1355 boolean forceNonSystemPackage, boolean overrideableByRestore) { 1356 return update(value, setDefault, packageName, tag, forceNonSystemPackage, 1357 overrideableByRestore, /* resetToDefault */ false); 1358 } 1359 update(String value, boolean setDefault, String packageName, String tag, boolean forceNonSystemPackage, boolean overrideableByRestore, boolean resetToDefault)1360 private boolean update(String value, boolean setDefault, String packageName, String tag, 1361 boolean forceNonSystemPackage, boolean overrideableByRestore, 1362 boolean resetToDefault) { 1363 if (NULL_VALUE.equals(value)) { 1364 value = null; 1365 } 1366 final boolean callerSystem = !forceNonSystemPackage && 1367 !isNull() && (isCalledFromSystem(packageName) 1368 || isSystemPackage(mContext, packageName)); 1369 // Settings set by the system are always defaults. 1370 if (callerSystem) { 1371 setDefault = true; 1372 } 1373 1374 String defaultValue = this.defaultValue; 1375 boolean defaultFromSystem = this.defaultFromSystem; 1376 if (setDefault) { 1377 if (!Objects.equals(value, this.defaultValue) 1378 && (!defaultFromSystem || callerSystem)) { 1379 defaultValue = value; 1380 // Default null means no default, so the tag is irrelevant 1381 // since it is used to reset a settings subset their defaults. 1382 // Also it is irrelevant if the system set the canonical default. 1383 if (defaultValue == null) { 1384 tag = null; 1385 defaultFromSystem = false; 1386 } 1387 } 1388 if (!defaultFromSystem && value != null) { 1389 if (callerSystem) { 1390 defaultFromSystem = true; 1391 } 1392 } 1393 } 1394 1395 // isValuePreservedInRestore shouldn't change back to false if it has been set to true. 1396 boolean isPreserved = shouldPreserveSetting(overrideableByRestore, resetToDefault, 1397 packageName, value); 1398 1399 // Is something gonna change? 1400 if (Objects.equals(value, this.value) 1401 && Objects.equals(defaultValue, this.defaultValue) 1402 && Objects.equals(packageName, this.packageName) 1403 && Objects.equals(tag, this.tag) 1404 && defaultFromSystem == this.defaultFromSystem 1405 && isPreserved == this.isValuePreservedInRestore) { 1406 return false; 1407 } 1408 1409 init(name, value, tag, defaultValue, packageName, defaultFromSystem, 1410 String.valueOf(mNextId++), isPreserved); 1411 1412 return true; 1413 } 1414 toString()1415 public String toString() { 1416 return "Setting{name=" + name + " value=" + value 1417 + (defaultValue != null ? " default=" + defaultValue : "") 1418 + " packageName=" + packageName + " tag=" + tag 1419 + " defaultFromSystem=" + defaultFromSystem + "}"; 1420 } 1421 shouldPreserveSetting(boolean overrideableByRestore, boolean resetToDefault, String packageName, String value)1422 private boolean shouldPreserveSetting(boolean overrideableByRestore, 1423 boolean resetToDefault, String packageName, String value) { 1424 if (resetToDefault) { 1425 // By default settings are not marked as preserved. 1426 return false; 1427 } 1428 if (value != null && value.equals(this.value) 1429 && SYSTEM_PACKAGE_NAME.equals(packageName)) { 1430 // Do not mark preserved if it's the system reinitializing to the same value. 1431 return false; 1432 } 1433 1434 // isValuePreservedInRestore shouldn't change back to false if it has been set to true. 1435 return this.isValuePreservedInRestore || !overrideableByRestore; 1436 } 1437 } 1438 1439 /** 1440 * @return TRUE if a string is considered "binary" from KXML's point of view. NOTE DO NOT 1441 * pass null. 1442 */ isBinary(String s)1443 public static boolean isBinary(String s) { 1444 if (s == null) { 1445 throw new NullPointerException(); 1446 } 1447 // See KXmlSerializer.writeEscaped 1448 for (int i = 0; i < s.length(); i++) { 1449 char c = s.charAt(i); 1450 boolean allowedInXml = (c >= 0x20 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xfffd); 1451 if (!allowedInXml) { 1452 return true; 1453 } 1454 } 1455 return false; 1456 } 1457 base64Encode(String s)1458 private static String base64Encode(String s) { 1459 return Base64.encodeToString(toBytes(s), Base64.NO_WRAP); 1460 } 1461 base64Decode(String s)1462 private static String base64Decode(String s) { 1463 return fromBytes(Base64.decode(s, Base64.DEFAULT)); 1464 } 1465 1466 // Note the followings are basically just UTF-16 encode/decode. But we want to preserve 1467 // contents as-is, even if it contains broken surrogate pairs, we do it by ourselves, 1468 // since I don't know how Charset would treat them. 1469 toBytes(String s)1470 private static byte[] toBytes(String s) { 1471 final byte[] result = new byte[s.length() * 2]; 1472 int resultIndex = 0; 1473 for (int i = 0; i < s.length(); ++i) { 1474 char ch = s.charAt(i); 1475 result[resultIndex++] = (byte) (ch >> 8); 1476 result[resultIndex++] = (byte) ch; 1477 } 1478 return result; 1479 } 1480 fromBytes(byte[] bytes)1481 private static String fromBytes(byte[] bytes) { 1482 final StringBuilder sb = new StringBuilder(bytes.length / 2); 1483 1484 final int last = bytes.length - 1; 1485 1486 for (int i = 0; i < last; i += 2) { 1487 final char ch = (char) ((bytes[i] & 0xff) << 8 | (bytes[i + 1] & 0xff)); 1488 sb.append(ch); 1489 } 1490 return sb.toString(); 1491 } 1492 1493 // Cache the list of names of system packages. This is only called once on system boot. cacheSystemPackageNamesAndSystemSignature(@onNull Context context)1494 public static void cacheSystemPackageNamesAndSystemSignature(@NonNull Context context) { 1495 final PackageManager packageManager = context.getPackageManager(); 1496 final long identity = Binder.clearCallingIdentity(); 1497 try { 1498 sSystemPackages.add(SYSTEM_PACKAGE_NAME); 1499 // Cache SetupWizard package name. 1500 final String setupWizPackageName = packageManager.getSetupWizardPackageName(); 1501 if (setupWizPackageName != null) { 1502 sSystemPackages.add(setupWizPackageName); 1503 } 1504 final List<PackageInfo> packageInfos = packageManager.getInstalledPackages(0); 1505 final int installedPackagesCount = packageInfos.size(); 1506 for (int i = 0; i < installedPackagesCount; i++) { 1507 if (shouldAddToSystemPackages(packageInfos.get(i))) { 1508 sSystemPackages.add(packageInfos.get(i).packageName); 1509 } 1510 } 1511 } finally { 1512 Binder.restoreCallingIdentity(identity); 1513 } 1514 } 1515 shouldAddToSystemPackages(@onNull PackageInfo packageInfo)1516 private static boolean shouldAddToSystemPackages(@NonNull PackageInfo packageInfo) { 1517 // Shell and Root are not considered a part of the system 1518 if (isShellOrRoot(packageInfo.packageName)) { 1519 return false; 1520 } 1521 // Already added 1522 if (sSystemPackages.contains(packageInfo.packageName)) { 1523 return false; 1524 } 1525 return isSystemPackage(packageInfo.applicationInfo); 1526 } 1527 isShellOrRoot(@onNull String packageName)1528 private static boolean isShellOrRoot(@NonNull String packageName) { 1529 return (SHELL_PACKAGE_NAME.equals(packageName) 1530 || ROOT_PACKAGE_NAME.equals(packageName)); 1531 } 1532 isCalledFromSystem(@onNull String packageName)1533 private static boolean isCalledFromSystem(@NonNull String packageName) { 1534 // Shell and Root are not considered a part of the system 1535 if (isShellOrRoot(packageName)) { 1536 return false; 1537 } 1538 final int callingUid = Binder.getCallingUid(); 1539 // Native services running as a special UID get a pass 1540 final int callingAppId = UserHandle.getAppId(callingUid); 1541 return (callingAppId < FIRST_APPLICATION_UID); 1542 } 1543 isSystemPackage(@onNull Context context, @NonNull String packageName)1544 public static boolean isSystemPackage(@NonNull Context context, @NonNull String packageName) { 1545 // Check shell or root before trying to retrieve ApplicationInfo to fail fast 1546 if (isShellOrRoot(packageName)) { 1547 return false; 1548 } 1549 // If it's a known system package or known to be platform signed 1550 if (sSystemPackages.contains(packageName)) { 1551 return true; 1552 } 1553 1554 ApplicationInfo aInfo = null; 1555 final long identity = Binder.clearCallingIdentity(); 1556 try { 1557 try { 1558 // Notice that this makes a call to package manager inside the lock 1559 aInfo = context.getPackageManager().getApplicationInfo(packageName, 0); 1560 } catch (PackageManager.NameNotFoundException ignored) { 1561 } 1562 } finally { 1563 Binder.restoreCallingIdentity(identity); 1564 } 1565 return isSystemPackage(aInfo); 1566 } 1567 isSystemPackage(@ullable ApplicationInfo aInfo)1568 private static boolean isSystemPackage(@Nullable ApplicationInfo aInfo) { 1569 if (aInfo == null) { 1570 return false; 1571 } 1572 // If the system or a special system UID (like telephony), done. 1573 if (aInfo.uid < FIRST_APPLICATION_UID) { 1574 return true; 1575 } 1576 // If a persistent system app, done. 1577 if ((aInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0 1578 && (aInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 1579 return true; 1580 } 1581 // Platform signed packages are considered to be from the system 1582 if (aInfo.isSignedWithPlatformKey()) { 1583 return true; 1584 } 1585 return false; 1586 } 1587 1588 @VisibleForTesting getMemoryUsage(String packageName)1589 public int getMemoryUsage(String packageName) { 1590 synchronized (mLock) { 1591 return mPackageToMemoryUsage.getOrDefault(packageName, 0); 1592 } 1593 } 1594 } 1595