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.content.Context; 23 import android.content.pm.ApplicationInfo; 24 import android.content.pm.PackageInfo; 25 import android.content.pm.PackageManager; 26 import android.content.pm.PackageManagerInternal; 27 import android.content.pm.Signature; 28 import android.os.Binder; 29 import android.os.Build; 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.GlobalSettingsProto; 38 import android.providers.settings.SettingsOperationProto; 39 import android.text.TextUtils; 40 import android.util.ArrayMap; 41 import android.util.AtomicFile; 42 import android.util.Base64; 43 import android.util.Slog; 44 import android.util.SparseIntArray; 45 import android.util.StatsLog; 46 import android.util.TimeUtils; 47 import android.util.Xml; 48 import android.util.proto.ProtoOutputStream; 49 50 import com.android.internal.annotations.GuardedBy; 51 import com.android.internal.util.ArrayUtils; 52 import com.android.server.LocalServices; 53 54 import libcore.io.IoUtils; 55 56 import org.xmlpull.v1.XmlPullParser; 57 import org.xmlpull.v1.XmlPullParserException; 58 import org.xmlpull.v1.XmlSerializer; 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.charset.StandardCharsets; 67 import java.util.ArrayList; 68 import java.util.List; 69 import java.util.Objects; 70 import java.util.Set; 71 72 /** 73 * This class contains the state for one type of settings. It is responsible 74 * for saving the state asynchronously to an XML file after a mutation and 75 * loading the from an XML file on construction. 76 * <p> 77 * This class uses the same lock as the settings provider to ensure that 78 * multiple changes made by the settings provider, e,g, upgrade, bulk insert, 79 * etc, are atomically persisted since the asynchronous persistence is using 80 * the same lock to grab the current state to write to disk. 81 * </p> 82 */ 83 final class SettingsState { 84 private static final boolean DEBUG = false; 85 private static final boolean DEBUG_PERSISTENCE = false; 86 87 private static final String LOG_TAG = "SettingsState"; 88 89 static final String SYSTEM_PACKAGE_NAME = "android"; 90 91 static final int SETTINGS_VERSION_NEW_ENCODING = 121; 92 93 private static final long WRITE_SETTINGS_DELAY_MILLIS = 200; 94 private static final long MAX_WRITE_SETTINGS_DELAY_MILLIS = 2000; 95 96 public static final int MAX_BYTES_PER_APP_PACKAGE_UNLIMITED = -1; 97 public static final int MAX_BYTES_PER_APP_PACKAGE_LIMITED = 20000; 98 99 public static final int VERSION_UNDEFINED = -1; 100 101 private static final String TAG_SETTINGS = "settings"; 102 private static final String TAG_SETTING = "setting"; 103 private static final String ATTR_PACKAGE = "package"; 104 private static final String ATTR_DEFAULT_SYS_SET = "defaultSysSet"; 105 private static final String ATTR_TAG = "tag"; 106 private static final String ATTR_TAG_BASE64 = "tagBase64"; 107 108 private static final String ATTR_VERSION = "version"; 109 private static final String ATTR_ID = "id"; 110 private static final String ATTR_NAME = "name"; 111 112 /** 113 * Non-binary value will be written in this attributes. 114 */ 115 private static final String ATTR_VALUE = "value"; 116 private static final String ATTR_DEFAULT_VALUE = "defaultValue"; 117 118 /** 119 * KXmlSerializer won't like some characters. We encode such characters 120 * in base64 and store in this attribute. 121 * NOTE: A null value will have *neither* ATTR_VALUE nor ATTR_VALUE_BASE64. 122 */ 123 private static final String ATTR_VALUE_BASE64 = "valueBase64"; 124 private static final String ATTR_DEFAULT_VALUE_BASE64 = "defaultValueBase64"; 125 126 // This was used in version 120 and before. 127 private static final String NULL_VALUE_OLD_STYLE = "null"; 128 129 private static final int HISTORICAL_OPERATION_COUNT = 20; 130 private static final String HISTORICAL_OPERATION_UPDATE = "update"; 131 private static final String HISTORICAL_OPERATION_DELETE = "delete"; 132 private static final String HISTORICAL_OPERATION_PERSIST = "persist"; 133 private static final String HISTORICAL_OPERATION_INITIALIZE = "initialize"; 134 private static final String HISTORICAL_OPERATION_RESET = "reset"; 135 136 private static final String SHELL_PACKAGE_NAME = "com.android.shell"; 137 private static final String ROOT_PACKAGE_NAME = "root"; 138 139 private static final String NULL_VALUE = "null"; 140 141 private static final Object sLock = new Object(); 142 143 @GuardedBy("sLock") 144 private static final SparseIntArray sSystemUids = new SparseIntArray(); 145 146 @GuardedBy("sLock") 147 private static Signature sSystemSignature; 148 149 private final Object mWriteLock = new Object(); 150 151 private final Object mLock; 152 153 private final Handler mHandler; 154 155 @GuardedBy("mLock") 156 private final Context mContext; 157 158 @GuardedBy("mLock") 159 private final ArrayMap<String, Setting> mSettings = new ArrayMap<>(); 160 161 @GuardedBy("mLock") 162 private final ArrayMap<String, Integer> mPackageToMemoryUsage; 163 164 @GuardedBy("mLock") 165 private final int mMaxBytesPerAppPackage; 166 167 @GuardedBy("mLock") 168 private final File mStatePersistFile; 169 170 @GuardedBy("mLock") 171 private final String mStatePersistTag; 172 173 private final Setting mNullSetting = new Setting(null, null, false, null, null) { 174 @Override 175 public boolean isNull() { 176 return true; 177 } 178 }; 179 180 @GuardedBy("mLock") 181 private final List<HistoricalOperation> mHistoricalOperations; 182 183 @GuardedBy("mLock") 184 public final int mKey; 185 186 @GuardedBy("mLock") 187 private int mVersion = VERSION_UNDEFINED; 188 189 @GuardedBy("mLock") 190 private long mLastNotWrittenMutationTimeMillis; 191 192 @GuardedBy("mLock") 193 private boolean mDirty; 194 195 @GuardedBy("mLock") 196 private boolean mWriteScheduled; 197 198 @GuardedBy("mLock") 199 private long mNextId; 200 201 @GuardedBy("mLock") 202 private int mNextHistoricalOpIdx; 203 204 public static final int SETTINGS_TYPE_GLOBAL = 0; 205 public static final int SETTINGS_TYPE_SYSTEM = 1; 206 public static final int SETTINGS_TYPE_SECURE = 2; 207 public static final int SETTINGS_TYPE_SSAID = 3; 208 209 public static final int SETTINGS_TYPE_MASK = 0xF0000000; 210 public static final int SETTINGS_TYPE_SHIFT = 28; 211 makeKey(int type, int userId)212 public static int makeKey(int type, int userId) { 213 return (type << SETTINGS_TYPE_SHIFT) | userId; 214 } 215 getTypeFromKey(int key)216 public static int getTypeFromKey(int key) { 217 return key >>> SETTINGS_TYPE_SHIFT; 218 } 219 getUserIdFromKey(int key)220 public static int getUserIdFromKey(int key) { 221 return key & ~SETTINGS_TYPE_MASK; 222 } 223 settingTypeToString(int type)224 public static String settingTypeToString(int type) { 225 switch (type) { 226 case SETTINGS_TYPE_GLOBAL: { 227 return "SETTINGS_GLOBAL"; 228 } 229 case SETTINGS_TYPE_SECURE: { 230 return "SETTINGS_SECURE"; 231 } 232 case SETTINGS_TYPE_SYSTEM: { 233 return "SETTINGS_SYSTEM"; 234 } 235 case SETTINGS_TYPE_SSAID: { 236 return "SETTINGS_SSAID"; 237 } 238 default: { 239 return "UNKNOWN"; 240 } 241 } 242 } 243 keyToString(int key)244 public static String keyToString(int key) { 245 return "Key[user=" + getUserIdFromKey(key) + ";type=" 246 + settingTypeToString(getTypeFromKey(key)) + "]"; 247 } 248 SettingsState(Context context, Object lock, File file, int key, int maxBytesPerAppPackage, Looper looper)249 public SettingsState(Context context, Object lock, File file, int key, 250 int maxBytesPerAppPackage, Looper looper) { 251 // It is important that we use the same lock as the settings provider 252 // to ensure multiple mutations on this state are atomicaly persisted 253 // as the async persistence should be blocked while we make changes. 254 mContext = context; 255 mLock = lock; 256 mStatePersistFile = file; 257 mStatePersistTag = "settings-" + getTypeFromKey(key) + "-" + getUserIdFromKey(key); 258 mKey = key; 259 mHandler = new MyHandler(looper); 260 if (maxBytesPerAppPackage == MAX_BYTES_PER_APP_PACKAGE_LIMITED) { 261 mMaxBytesPerAppPackage = maxBytesPerAppPackage; 262 mPackageToMemoryUsage = new ArrayMap<>(); 263 } else { 264 mMaxBytesPerAppPackage = maxBytesPerAppPackage; 265 mPackageToMemoryUsage = null; 266 } 267 268 mHistoricalOperations = Build.IS_DEBUGGABLE 269 ? new ArrayList<>(HISTORICAL_OPERATION_COUNT) : null; 270 271 synchronized (mLock) { 272 readStateSyncLocked(); 273 } 274 } 275 276 // The settings provider must hold its lock when calling here. getVersionLocked()277 public int getVersionLocked() { 278 return mVersion; 279 } 280 getNullSetting()281 public Setting getNullSetting() { 282 return mNullSetting; 283 } 284 285 // The settings provider must hold its lock when calling here. setVersionLocked(int version)286 public void setVersionLocked(int version) { 287 if (version == mVersion) { 288 return; 289 } 290 mVersion = version; 291 292 scheduleWriteIfNeededLocked(); 293 } 294 295 // The settings provider must hold its lock when calling here. onPackageRemovedLocked(String packageName)296 public void onPackageRemovedLocked(String packageName) { 297 boolean removedSomething = false; 298 299 final int settingCount = mSettings.size(); 300 for (int i = settingCount - 1; i >= 0; i--) { 301 String name = mSettings.keyAt(i); 302 // Settings defined by us are never dropped. 303 if (Settings.System.PUBLIC_SETTINGS.contains(name) 304 || Settings.System.PRIVATE_SETTINGS.contains(name)) { 305 continue; 306 } 307 Setting setting = mSettings.valueAt(i); 308 if (packageName.equals(setting.packageName)) { 309 mSettings.removeAt(i); 310 removedSomething = true; 311 } 312 } 313 314 if (removedSomething) { 315 scheduleWriteIfNeededLocked(); 316 } 317 } 318 319 // The settings provider must hold its lock when calling here. getSettingNamesLocked()320 public List<String> getSettingNamesLocked() { 321 ArrayList<String> names = new ArrayList<>(); 322 final int settingsCount = mSettings.size(); 323 for (int i = 0; i < settingsCount; i++) { 324 String name = mSettings.keyAt(i); 325 names.add(name); 326 } 327 return names; 328 } 329 330 // The settings provider must hold its lock when calling here. getSettingLocked(String name)331 public Setting getSettingLocked(String name) { 332 if (TextUtils.isEmpty(name)) { 333 return mNullSetting; 334 } 335 Setting setting = mSettings.get(name); 336 if (setting != null) { 337 return new Setting(setting); 338 } 339 return mNullSetting; 340 } 341 342 // The settings provider must hold its lock when calling here. updateSettingLocked(String name, String value, String tag, boolean makeValue, String packageName)343 public boolean updateSettingLocked(String name, String value, String tag, 344 boolean makeValue, String packageName) { 345 if (!hasSettingLocked(name)) { 346 return false; 347 } 348 349 return insertSettingLocked(name, value, tag, makeValue, packageName); 350 } 351 352 // The settings provider must hold its lock when calling here. resetSettingDefaultValueLocked(String name)353 public void resetSettingDefaultValueLocked(String name) { 354 Setting oldSetting = getSettingLocked(name); 355 if (oldSetting != null && !oldSetting.isNull() && oldSetting.getDefaultValue() != null) { 356 String oldValue = oldSetting.getValue(); 357 String oldDefaultValue = oldSetting.getDefaultValue(); 358 Setting newSetting = new Setting(name, oldSetting.getValue(), null, 359 oldSetting.getPackageName(), oldSetting.getTag(), false, 360 oldSetting.getId()); 361 mSettings.put(name, newSetting); 362 updateMemoryUsagePerPackageLocked(newSetting.getPackageName(), oldValue, 363 newSetting.getValue(), oldDefaultValue, newSetting.getDefaultValue()); 364 scheduleWriteIfNeededLocked(); 365 } 366 } 367 368 // The settings provider must hold its lock when calling here. insertSettingLocked(String name, String value, String tag, boolean makeDefault, String packageName)369 public boolean insertSettingLocked(String name, String value, String tag, 370 boolean makeDefault, String packageName) { 371 if (TextUtils.isEmpty(name)) { 372 return false; 373 } 374 375 Setting oldState = mSettings.get(name); 376 String oldValue = (oldState != null) ? oldState.value : null; 377 String oldDefaultValue = (oldState != null) ? oldState.defaultValue : null; 378 Setting newState; 379 380 if (oldState != null) { 381 if (!oldState.update(value, makeDefault, packageName, tag, false)) { 382 return false; 383 } 384 newState = oldState; 385 } else { 386 newState = new Setting(name, value, makeDefault, packageName, tag); 387 mSettings.put(name, newState); 388 } 389 390 StatsLog.write(StatsLog.SETTING_CHANGED, name, value, newState.value, oldValue, tag, 391 makeDefault, getUserIdFromKey(mKey), StatsLog.SETTING_CHANGED__REASON__UPDATED); 392 393 addHistoricalOperationLocked(HISTORICAL_OPERATION_UPDATE, newState); 394 395 updateMemoryUsagePerPackageLocked(packageName, oldValue, value, 396 oldDefaultValue, newState.getDefaultValue()); 397 398 scheduleWriteIfNeededLocked(); 399 400 return true; 401 } 402 403 // The settings provider must hold its lock when calling here. persistSyncLocked()404 public void persistSyncLocked() { 405 mHandler.removeMessages(MyHandler.MSG_PERSIST_SETTINGS); 406 doWriteState(); 407 } 408 409 // The settings provider must hold its lock when calling here. deleteSettingLocked(String name)410 public boolean deleteSettingLocked(String name) { 411 if (TextUtils.isEmpty(name) || !hasSettingLocked(name)) { 412 return false; 413 } 414 415 Setting oldState = mSettings.remove(name); 416 417 StatsLog.write(StatsLog.SETTING_CHANGED, name, /* value= */ "", /* newValue= */ "", 418 oldState.value, /* tag */ "", false, getUserIdFromKey(mKey), 419 StatsLog.SETTING_CHANGED__REASON__DELETED); 420 421 updateMemoryUsagePerPackageLocked(oldState.packageName, oldState.value, 422 null, oldState.defaultValue, null); 423 424 addHistoricalOperationLocked(HISTORICAL_OPERATION_DELETE, oldState); 425 426 scheduleWriteIfNeededLocked(); 427 428 return true; 429 } 430 431 // The settings provider must hold its lock when calling here. resetSettingLocked(String name)432 public boolean resetSettingLocked(String name) { 433 if (TextUtils.isEmpty(name) || !hasSettingLocked(name)) { 434 return false; 435 } 436 437 Setting setting = mSettings.get(name); 438 439 Setting oldSetting = new Setting(setting); 440 String oldValue = setting.getValue(); 441 String oldDefaultValue = setting.getDefaultValue(); 442 443 if (!setting.reset()) { 444 return false; 445 } 446 447 String newValue = setting.getValue(); 448 String newDefaultValue = setting.getDefaultValue(); 449 450 updateMemoryUsagePerPackageLocked(setting.packageName, oldValue, 451 newValue, oldDefaultValue, newDefaultValue); 452 453 addHistoricalOperationLocked(HISTORICAL_OPERATION_RESET, oldSetting); 454 455 scheduleWriteIfNeededLocked(); 456 457 return true; 458 } 459 460 // The settings provider must hold its lock when calling here. destroyLocked(Runnable callback)461 public void destroyLocked(Runnable callback) { 462 mHandler.removeMessages(MyHandler.MSG_PERSIST_SETTINGS); 463 if (callback != null) { 464 if (mDirty) { 465 // Do it without a delay. 466 mHandler.obtainMessage(MyHandler.MSG_PERSIST_SETTINGS, 467 callback).sendToTarget(); 468 return; 469 } 470 callback.run(); 471 } 472 } 473 addHistoricalOperationLocked(String type, Setting setting)474 private void addHistoricalOperationLocked(String type, Setting setting) { 475 if (mHistoricalOperations == null) { 476 return; 477 } 478 HistoricalOperation operation = new HistoricalOperation( 479 SystemClock.elapsedRealtime(), type, 480 setting != null ? new Setting(setting) : null); 481 if (mNextHistoricalOpIdx >= mHistoricalOperations.size()) { 482 mHistoricalOperations.add(operation); 483 } else { 484 mHistoricalOperations.set(mNextHistoricalOpIdx, operation); 485 } 486 mNextHistoricalOpIdx++; 487 if (mNextHistoricalOpIdx >= HISTORICAL_OPERATION_COUNT) { 488 mNextHistoricalOpIdx = 0; 489 } 490 } 491 492 /** 493 * Dump historical operations as a proto buf. 494 * 495 * @param proto The proto buf stream to dump to 496 * @param fieldId The repeated field ID to use to save an operation to. 497 */ dumpHistoricalOperations(@onNull ProtoOutputStream proto, long fieldId)498 void dumpHistoricalOperations(@NonNull ProtoOutputStream proto, long fieldId) { 499 synchronized (mLock) { 500 if (mHistoricalOperations == null) { 501 return; 502 } 503 504 final int operationCount = mHistoricalOperations.size(); 505 for (int i = 0; i < operationCount; i++) { 506 int index = mNextHistoricalOpIdx - 1 - i; 507 if (index < 0) { 508 index = operationCount + index; 509 } 510 HistoricalOperation operation = mHistoricalOperations.get(index); 511 512 final long token = proto.start(fieldId); 513 proto.write(SettingsOperationProto.TIMESTAMP, operation.mTimestamp); 514 proto.write(SettingsOperationProto.OPERATION, operation.mOperation); 515 if (operation.mSetting != null) { 516 // Only add the name of the setting, since we don't know the historical package 517 // and values for it so they would be misleading to add here (all we could 518 // add is what the current data is). 519 proto.write(SettingsOperationProto.SETTING, operation.mSetting.getName()); 520 } 521 proto.end(token); 522 } 523 } 524 } 525 dumpHistoricalOperations(PrintWriter pw)526 public void dumpHistoricalOperations(PrintWriter pw) { 527 synchronized (mLock) { 528 if (mHistoricalOperations == null) { 529 return; 530 } 531 pw.println("Historical operations"); 532 final int operationCount = mHistoricalOperations.size(); 533 for (int i = 0; i < operationCount; i++) { 534 int index = mNextHistoricalOpIdx - 1 - i; 535 if (index < 0) { 536 index = operationCount + index; 537 } 538 HistoricalOperation operation = mHistoricalOperations.get(index); 539 pw.print(TimeUtils.formatForLogging(operation.mTimestamp)); 540 pw.print(" "); 541 pw.print(operation.mOperation); 542 if (operation.mSetting != null) { 543 pw.print(" "); 544 // Only print the name of the setting, since we don't know the 545 // historical package and values for it so they would be misleading 546 // to print here (all we could print is what the current data is). 547 pw.print(operation.mSetting.getName()); 548 } 549 pw.println(); 550 } 551 pw.println(); 552 pw.println(); 553 } 554 } 555 updateMemoryUsagePerPackageLocked(String packageName, String oldValue, String newValue, String oldDefaultValue, String newDefaultValue)556 private void updateMemoryUsagePerPackageLocked(String packageName, String oldValue, 557 String newValue, String oldDefaultValue, String newDefaultValue) { 558 if (mMaxBytesPerAppPackage == MAX_BYTES_PER_APP_PACKAGE_UNLIMITED) { 559 return; 560 } 561 562 if (SYSTEM_PACKAGE_NAME.equals(packageName)) { 563 return; 564 } 565 566 final int oldValueSize = (oldValue != null) ? oldValue.length() : 0; 567 final int newValueSize = (newValue != null) ? newValue.length() : 0; 568 final int oldDefaultValueSize = (oldDefaultValue != null) ? oldDefaultValue.length() : 0; 569 final int newDefaultValueSize = (newDefaultValue != null) ? newDefaultValue.length() : 0; 570 final int deltaSize = newValueSize + newDefaultValueSize 571 - oldValueSize - oldDefaultValueSize; 572 573 Integer currentSize = mPackageToMemoryUsage.get(packageName); 574 final int newSize = Math.max((currentSize != null) 575 ? currentSize + deltaSize : deltaSize, 0); 576 577 if (newSize > mMaxBytesPerAppPackage) { 578 throw new IllegalStateException("You are adding too many system settings. " 579 + "You should stop using system settings for app specific data" 580 + " package: " + packageName); 581 } 582 583 if (DEBUG) { 584 Slog.i(LOG_TAG, "Settings for package: " + packageName 585 + " size: " + newSize + " bytes."); 586 } 587 588 mPackageToMemoryUsage.put(packageName, newSize); 589 } 590 hasSettingLocked(String name)591 private boolean hasSettingLocked(String name) { 592 return mSettings.indexOfKey(name) >= 0; 593 } 594 scheduleWriteIfNeededLocked()595 private void scheduleWriteIfNeededLocked() { 596 // If dirty then we have a write already scheduled. 597 if (!mDirty) { 598 mDirty = true; 599 writeStateAsyncLocked(); 600 } 601 } 602 writeStateAsyncLocked()603 private void writeStateAsyncLocked() { 604 final long currentTimeMillis = SystemClock.uptimeMillis(); 605 606 if (mWriteScheduled) { 607 mHandler.removeMessages(MyHandler.MSG_PERSIST_SETTINGS); 608 609 // If enough time passed, write without holding off anymore. 610 final long timeSinceLastNotWrittenMutationMillis = currentTimeMillis 611 - mLastNotWrittenMutationTimeMillis; 612 if (timeSinceLastNotWrittenMutationMillis >= MAX_WRITE_SETTINGS_DELAY_MILLIS) { 613 mHandler.obtainMessage(MyHandler.MSG_PERSIST_SETTINGS).sendToTarget(); 614 return; 615 } 616 617 // Hold off a bit more as settings are frequently changing. 618 final long maxDelayMillis = Math.max(mLastNotWrittenMutationTimeMillis 619 + MAX_WRITE_SETTINGS_DELAY_MILLIS - currentTimeMillis, 0); 620 final long writeDelayMillis = Math.min(WRITE_SETTINGS_DELAY_MILLIS, maxDelayMillis); 621 622 Message message = mHandler.obtainMessage(MyHandler.MSG_PERSIST_SETTINGS); 623 mHandler.sendMessageDelayed(message, writeDelayMillis); 624 } else { 625 mLastNotWrittenMutationTimeMillis = currentTimeMillis; 626 Message message = mHandler.obtainMessage(MyHandler.MSG_PERSIST_SETTINGS); 627 mHandler.sendMessageDelayed(message, WRITE_SETTINGS_DELAY_MILLIS); 628 mWriteScheduled = true; 629 } 630 } 631 doWriteState()632 private void doWriteState() { 633 boolean wroteState = false; 634 final int version; 635 final ArrayMap<String, Setting> settings; 636 637 synchronized (mLock) { 638 version = mVersion; 639 settings = new ArrayMap<>(mSettings); 640 mDirty = false; 641 mWriteScheduled = false; 642 } 643 644 synchronized (mWriteLock) { 645 if (DEBUG_PERSISTENCE) { 646 Slog.i(LOG_TAG, "[PERSIST START]"); 647 } 648 649 AtomicFile destination = new AtomicFile(mStatePersistFile, mStatePersistTag); 650 FileOutputStream out = null; 651 try { 652 out = destination.startWrite(); 653 654 XmlSerializer serializer = Xml.newSerializer(); 655 serializer.setOutput(out, StandardCharsets.UTF_8.name()); 656 serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", 657 true); 658 serializer.startDocument(null, true); 659 serializer.startTag(null, TAG_SETTINGS); 660 serializer.attribute(null, ATTR_VERSION, String.valueOf(version)); 661 662 final int settingCount = settings.size(); 663 for (int i = 0; i < settingCount; i++) { 664 Setting setting = settings.valueAt(i); 665 666 if (setting.isTransient()) { 667 if (DEBUG_PERSISTENCE) { 668 Slog.i(LOG_TAG, "[SKIPPED PERSISTING]" + setting.getName()); 669 } 670 continue; 671 } 672 673 writeSingleSetting(mVersion, serializer, setting.getId(), setting.getName(), 674 setting.getValue(), setting.getDefaultValue(), setting.getPackageName(), 675 setting.getTag(), setting.isDefaultFromSystem()); 676 677 if (DEBUG_PERSISTENCE) { 678 Slog.i(LOG_TAG, "[PERSISTED]" + setting.getName() + "=" 679 + setting.getValue()); 680 } 681 } 682 683 serializer.endTag(null, TAG_SETTINGS); 684 serializer.endDocument(); 685 destination.finishWrite(out); 686 687 wroteState = true; 688 689 if (DEBUG_PERSISTENCE) { 690 Slog.i(LOG_TAG, "[PERSIST END]"); 691 } 692 } catch (Throwable t) { 693 Slog.wtf(LOG_TAG, "Failed to write settings, restoring backup", t); 694 destination.failWrite(out); 695 } finally { 696 IoUtils.closeQuietly(out); 697 } 698 } 699 700 if (wroteState) { 701 synchronized (mLock) { 702 addHistoricalOperationLocked(HISTORICAL_OPERATION_PERSIST, null); 703 } 704 } 705 } 706 writeSingleSetting(int version, XmlSerializer serializer, String id, String name, String value, String defaultValue, String packageName, String tag, boolean defaultSysSet)707 static void writeSingleSetting(int version, XmlSerializer serializer, String id, 708 String name, String value, String defaultValue, String packageName, 709 String tag, boolean defaultSysSet) throws IOException { 710 if (id == null || isBinary(id) || name == null || isBinary(name) 711 || packageName == null || isBinary(packageName)) { 712 // This shouldn't happen. 713 return; 714 } 715 serializer.startTag(null, TAG_SETTING); 716 serializer.attribute(null, ATTR_ID, id); 717 serializer.attribute(null, ATTR_NAME, name); 718 setValueAttribute(ATTR_VALUE, ATTR_VALUE_BASE64, 719 version, serializer, value); 720 serializer.attribute(null, ATTR_PACKAGE, packageName); 721 if (defaultValue != null) { 722 setValueAttribute(ATTR_DEFAULT_VALUE, ATTR_DEFAULT_VALUE_BASE64, 723 version, serializer, defaultValue); 724 serializer.attribute(null, ATTR_DEFAULT_SYS_SET, Boolean.toString(defaultSysSet)); 725 setValueAttribute(ATTR_TAG, ATTR_TAG_BASE64, 726 version, serializer, tag); 727 } 728 serializer.endTag(null, TAG_SETTING); 729 } 730 setValueAttribute(String attr, String attrBase64, int version, XmlSerializer serializer, String value)731 static void setValueAttribute(String attr, String attrBase64, int version, 732 XmlSerializer serializer, String value) throws IOException { 733 if (version >= SETTINGS_VERSION_NEW_ENCODING) { 734 if (value == null) { 735 // Null value -> No ATTR_VALUE nor ATTR_VALUE_BASE64. 736 } else if (isBinary(value)) { 737 serializer.attribute(null, attrBase64, base64Encode(value)); 738 } else { 739 serializer.attribute(null, attr, value); 740 } 741 } else { 742 // Old encoding. 743 if (value == null) { 744 serializer.attribute(null, attr, NULL_VALUE_OLD_STYLE); 745 } else { 746 serializer.attribute(null, attr, value); 747 } 748 } 749 } 750 getValueAttribute(XmlPullParser parser, String attr, String base64Attr)751 private String getValueAttribute(XmlPullParser parser, String attr, String base64Attr) { 752 if (mVersion >= SETTINGS_VERSION_NEW_ENCODING) { 753 final String value = parser.getAttributeValue(null, attr); 754 if (value != null) { 755 return value; 756 } 757 final String base64 = parser.getAttributeValue(null, base64Attr); 758 if (base64 != null) { 759 return base64Decode(base64); 760 } 761 // null has neither ATTR_VALUE nor ATTR_VALUE_BASE64. 762 return null; 763 } else { 764 // Old encoding. 765 final String stored = parser.getAttributeValue(null, attr); 766 if (NULL_VALUE_OLD_STYLE.equals(stored)) { 767 return null; 768 } else { 769 return stored; 770 } 771 } 772 } 773 readStateSyncLocked()774 private void readStateSyncLocked() { 775 FileInputStream in; 776 try { 777 in = new AtomicFile(mStatePersistFile).openRead(); 778 } catch (FileNotFoundException fnfe) { 779 Slog.i(LOG_TAG, "No settings state " + mStatePersistFile); 780 addHistoricalOperationLocked(HISTORICAL_OPERATION_INITIALIZE, null); 781 return; 782 } 783 try { 784 XmlPullParser parser = Xml.newPullParser(); 785 parser.setInput(in, StandardCharsets.UTF_8.name()); 786 parseStateLocked(parser); 787 } catch (XmlPullParserException | IOException e) { 788 String message = "Failed parsing settings file: " + mStatePersistFile; 789 Slog.wtf(LOG_TAG, message); 790 throw new IllegalStateException(message, e); 791 } finally { 792 IoUtils.closeQuietly(in); 793 } 794 } 795 796 /** 797 * Uses AtomicFile to check if the file or its backup exists. 798 * @param file The file to check for existence 799 * @return whether the original or backup exist 800 */ stateFileExists(File file)801 public static boolean stateFileExists(File file) { 802 AtomicFile stateFile = new AtomicFile(file); 803 return stateFile.exists(); 804 } 805 parseStateLocked(XmlPullParser parser)806 private void parseStateLocked(XmlPullParser parser) 807 throws IOException, XmlPullParserException { 808 final int outerDepth = parser.getDepth(); 809 int type; 810 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 811 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 812 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 813 continue; 814 } 815 816 String tagName = parser.getName(); 817 if (tagName.equals(TAG_SETTINGS)) { 818 parseSettingsLocked(parser); 819 } 820 } 821 } 822 parseSettingsLocked(XmlPullParser parser)823 private void parseSettingsLocked(XmlPullParser parser) 824 throws IOException, XmlPullParserException { 825 826 mVersion = Integer.parseInt(parser.getAttributeValue(null, ATTR_VERSION)); 827 828 final int outerDepth = parser.getDepth(); 829 int type; 830 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 831 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 832 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 833 continue; 834 } 835 836 String tagName = parser.getName(); 837 if (tagName.equals(TAG_SETTING)) { 838 String id = parser.getAttributeValue(null, ATTR_ID); 839 String name = parser.getAttributeValue(null, ATTR_NAME); 840 String value = getValueAttribute(parser, ATTR_VALUE, ATTR_VALUE_BASE64); 841 String packageName = parser.getAttributeValue(null, ATTR_PACKAGE); 842 String defaultValue = getValueAttribute(parser, ATTR_DEFAULT_VALUE, 843 ATTR_DEFAULT_VALUE_BASE64); 844 String tag = null; 845 boolean fromSystem = false; 846 if (defaultValue != null) { 847 fromSystem = Boolean.parseBoolean(parser.getAttributeValue( 848 null, ATTR_DEFAULT_SYS_SET)); 849 tag = getValueAttribute(parser, ATTR_TAG, ATTR_TAG_BASE64); 850 } 851 mSettings.put(name, new Setting(name, value, defaultValue, packageName, tag, 852 fromSystem, id)); 853 854 if (DEBUG_PERSISTENCE) { 855 Slog.i(LOG_TAG, "[RESTORED] " + name + "=" + value); 856 } 857 } 858 } 859 } 860 861 private final class MyHandler extends Handler { 862 public static final int MSG_PERSIST_SETTINGS = 1; 863 MyHandler(Looper looper)864 public MyHandler(Looper looper) { 865 super(looper); 866 } 867 868 @Override handleMessage(Message message)869 public void handleMessage(Message message) { 870 switch (message.what) { 871 case MSG_PERSIST_SETTINGS: { 872 Runnable callback = (Runnable) message.obj; 873 doWriteState(); 874 if (callback != null) { 875 callback.run(); 876 } 877 } 878 break; 879 } 880 } 881 } 882 883 private class HistoricalOperation { 884 final long mTimestamp; 885 final String mOperation; 886 final Setting mSetting; 887 HistoricalOperation(long timestamp, String operation, Setting setting)888 public HistoricalOperation(long timestamp, 889 String operation, Setting setting) { 890 mTimestamp = timestamp; 891 mOperation = operation; 892 mSetting = setting; 893 } 894 } 895 896 class Setting { 897 private String name; 898 private String value; 899 private String defaultValue; 900 private String packageName; 901 private String id; 902 private String tag; 903 // Whether the default is set by the system 904 private boolean defaultFromSystem; 905 Setting(Setting other)906 public Setting(Setting other) { 907 name = other.name; 908 value = other.value; 909 defaultValue = other.defaultValue; 910 packageName = other.packageName; 911 id = other.id; 912 defaultFromSystem = other.defaultFromSystem; 913 tag = other.tag; 914 } 915 Setting(String name, String value, boolean makeDefault, String packageName, String tag)916 public Setting(String name, String value, boolean makeDefault, String packageName, 917 String tag) { 918 this.name = name; 919 update(value, makeDefault, packageName, tag, false); 920 } 921 Setting(String name, String value, String defaultValue, String packageName, String tag, boolean fromSystem, String id)922 public Setting(String name, String value, String defaultValue, 923 String packageName, String tag, boolean fromSystem, String id) { 924 mNextId = Math.max(mNextId, Long.parseLong(id) + 1); 925 if (NULL_VALUE.equals(value)) { 926 value = null; 927 } 928 init(name, value, tag, defaultValue, packageName, fromSystem, id); 929 } 930 init(String name, String value, String tag, String defaultValue, String packageName, boolean fromSystem, String id)931 private void init(String name, String value, String tag, String defaultValue, 932 String packageName, boolean fromSystem, String id) { 933 this.name = name; 934 this.value = value; 935 this.tag = tag; 936 this.defaultValue = defaultValue; 937 this.packageName = packageName; 938 this.id = id; 939 this.defaultFromSystem = fromSystem; 940 } 941 getName()942 public String getName() { 943 return name; 944 } 945 getKey()946 public int getKey() { 947 return mKey; 948 } 949 getValue()950 public String getValue() { 951 return value; 952 } 953 getTag()954 public String getTag() { 955 return tag; 956 } 957 getDefaultValue()958 public String getDefaultValue() { 959 return defaultValue; 960 } 961 getPackageName()962 public String getPackageName() { 963 return packageName; 964 } 965 isDefaultFromSystem()966 public boolean isDefaultFromSystem() { 967 return defaultFromSystem; 968 } 969 getId()970 public String getId() { 971 return id; 972 } 973 isNull()974 public boolean isNull() { 975 return false; 976 } 977 978 /** @return whether the value changed */ reset()979 public boolean reset() { 980 return update(this.defaultValue, false, packageName, null, true); 981 } 982 isTransient()983 public boolean isTransient() { 984 switch (getTypeFromKey(getKey())) { 985 case SETTINGS_TYPE_GLOBAL: 986 return ArrayUtils.contains(Global.TRANSIENT_SETTINGS, getName()); 987 } 988 return false; 989 } 990 update(String value, boolean setDefault, String packageName, String tag, boolean forceNonSystemPackage)991 public boolean update(String value, boolean setDefault, String packageName, String tag, 992 boolean forceNonSystemPackage) { 993 if (NULL_VALUE.equals(value)) { 994 value = null; 995 } 996 997 final boolean callerSystem = !forceNonSystemPackage && 998 !isNull() && isSystemPackage(mContext, packageName); 999 // Settings set by the system are always defaults. 1000 if (callerSystem) { 1001 setDefault = true; 1002 } 1003 1004 String defaultValue = this.defaultValue; 1005 boolean defaultFromSystem = this.defaultFromSystem; 1006 if (setDefault) { 1007 if (!Objects.equals(value, this.defaultValue) 1008 && (!defaultFromSystem || callerSystem)) { 1009 defaultValue = value; 1010 // Default null means no default, so the tag is irrelevant 1011 // since it is used to reset a settings subset their defaults. 1012 // Also it is irrelevant if the system set the canonical default. 1013 if (defaultValue == null) { 1014 tag = null; 1015 defaultFromSystem = false; 1016 } 1017 } 1018 if (!defaultFromSystem && value != null) { 1019 if (callerSystem) { 1020 defaultFromSystem = true; 1021 } 1022 } 1023 } 1024 1025 // Is something gonna change? 1026 if (Objects.equals(value, this.value) 1027 && Objects.equals(defaultValue, this.defaultValue) 1028 && Objects.equals(packageName, this.packageName) 1029 && Objects.equals(tag, this.tag) 1030 && defaultFromSystem == this.defaultFromSystem) { 1031 return false; 1032 } 1033 1034 init(name, value, tag, defaultValue, packageName, defaultFromSystem, 1035 String.valueOf(mNextId++)); 1036 return true; 1037 } 1038 toString()1039 public String toString() { 1040 return "Setting{name=" + name + " value=" + value 1041 + (defaultValue != null ? " default=" + defaultValue : "") 1042 + " packageName=" + packageName + " tag=" + tag 1043 + " defaultFromSystem=" + defaultFromSystem + "}"; 1044 } 1045 } 1046 1047 /** 1048 * @return TRUE if a string is considered "binary" from KXML's point of view. NOTE DO NOT 1049 * pass null. 1050 */ isBinary(String s)1051 public static boolean isBinary(String s) { 1052 if (s == null) { 1053 throw new NullPointerException(); 1054 } 1055 // See KXmlSerializer.writeEscaped 1056 for (int i = 0; i < s.length(); i++) { 1057 char c = s.charAt(i); 1058 boolean allowedInXml = (c >= 0x20 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xfffd); 1059 if (!allowedInXml) { 1060 return true; 1061 } 1062 } 1063 return false; 1064 } 1065 base64Encode(String s)1066 private static String base64Encode(String s) { 1067 return Base64.encodeToString(toBytes(s), Base64.NO_WRAP); 1068 } 1069 base64Decode(String s)1070 private static String base64Decode(String s) { 1071 return fromBytes(Base64.decode(s, Base64.DEFAULT)); 1072 } 1073 1074 // Note the followings are basically just UTF-16 encode/decode. But we want to preserve 1075 // contents as-is, even if it contains broken surrogate pairs, we do it by ourselves, 1076 // since I don't know how Charset would treat them. 1077 toBytes(String s)1078 private static byte[] toBytes(String s) { 1079 final byte[] result = new byte[s.length() * 2]; 1080 int resultIndex = 0; 1081 for (int i = 0; i < s.length(); ++i) { 1082 char ch = s.charAt(i); 1083 result[resultIndex++] = (byte) (ch >> 8); 1084 result[resultIndex++] = (byte) ch; 1085 } 1086 return result; 1087 } 1088 fromBytes(byte[] bytes)1089 private static String fromBytes(byte[] bytes) { 1090 final StringBuffer sb = new StringBuffer(bytes.length / 2); 1091 1092 final int last = bytes.length - 1; 1093 1094 for (int i = 0; i < last; i += 2) { 1095 final char ch = (char) ((bytes[i] & 0xff) << 8 | (bytes[i + 1] & 0xff)); 1096 sb.append(ch); 1097 } 1098 return sb.toString(); 1099 } 1100 isSystemPackage(Context context, String packageName)1101 public static boolean isSystemPackage(Context context, String packageName) { 1102 return isSystemPackage(context, packageName, Binder.getCallingUid()); 1103 } 1104 isSystemPackage(Context context, String packageName, int callingUid)1105 public static boolean isSystemPackage(Context context, String packageName, int callingUid) { 1106 synchronized (sLock) { 1107 if (SYSTEM_PACKAGE_NAME.equals(packageName)) { 1108 return true; 1109 } 1110 1111 // Shell and Root are not considered a part of the system 1112 if (SHELL_PACKAGE_NAME.equals(packageName) 1113 || ROOT_PACKAGE_NAME.equals(packageName)) { 1114 return false; 1115 } 1116 1117 // Native services running as a special UID get a pass 1118 final int callingAppId = UserHandle.getAppId(callingUid); 1119 if (callingAppId < FIRST_APPLICATION_UID) { 1120 sSystemUids.put(callingAppId, callingAppId); 1121 return true; 1122 } 1123 1124 // While some callers may have permissions to manipulate cross user 1125 // settings or some settings are stored in the parent of a managed 1126 // profile for the purpose of determining whether the other end is a 1127 // system component we need to use the user id of the caller for 1128 // pulling information about the caller from the package manager. 1129 final int callingUserId = UserHandle.getUserId(callingUid); 1130 1131 final long identity = Binder.clearCallingIdentity(); 1132 try { 1133 final int uid; 1134 try { 1135 uid = context.getPackageManager().getPackageUidAsUser(packageName, 0, 1136 callingUserId); 1137 } catch (PackageManager.NameNotFoundException e) { 1138 return false; 1139 } 1140 1141 // If the system or a special system UID (like telephony), done. 1142 if (UserHandle.getAppId(uid) < FIRST_APPLICATION_UID) { 1143 sSystemUids.put(uid, uid); 1144 return true; 1145 } 1146 1147 // If already known system component, done. 1148 if (sSystemUids.indexOfKey(uid) >= 0) { 1149 return true; 1150 } 1151 1152 // If SetupWizard, done. 1153 PackageManagerInternal packageManagerInternal = LocalServices.getService( 1154 PackageManagerInternal.class); 1155 if (packageName.equals(packageManagerInternal.getSetupWizardPackageName())) { 1156 sSystemUids.put(uid, uid); 1157 return true; 1158 } 1159 1160 // If a persistent system app, done. 1161 PackageInfo packageInfo; 1162 try { 1163 packageInfo = context.getPackageManager().getPackageInfoAsUser( 1164 packageName, PackageManager.GET_SIGNATURES, callingUserId); 1165 if ((packageInfo.applicationInfo.flags 1166 & ApplicationInfo.FLAG_PERSISTENT) != 0 1167 && (packageInfo.applicationInfo.flags 1168 & ApplicationInfo.FLAG_SYSTEM) != 0) { 1169 sSystemUids.put(uid, uid); 1170 return true; 1171 } 1172 } catch (PackageManager.NameNotFoundException e) { 1173 return false; 1174 } 1175 1176 // Last check if system signed. 1177 if (sSystemSignature == null) { 1178 try { 1179 sSystemSignature = context.getPackageManager().getPackageInfoAsUser( 1180 SYSTEM_PACKAGE_NAME, PackageManager.GET_SIGNATURES, 1181 UserHandle.USER_SYSTEM).signatures[0]; 1182 } catch (PackageManager.NameNotFoundException e) { 1183 /* impossible */ 1184 return false; 1185 } 1186 } 1187 if (sSystemSignature.equals(packageInfo.signatures[0])) { 1188 sSystemUids.put(uid, uid); 1189 return true; 1190 } 1191 } finally { 1192 Binder.restoreCallingIdentity(identity); 1193 } 1194 1195 return false; 1196 } 1197 } 1198 } 1199