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 212 public static int makeKey(int type, int userId) { 213 return (type << SETTINGS_TYPE_SHIFT) | userId; 214 } 215 216 public static int getTypeFromKey(int key) { 217 return key >>> SETTINGS_TYPE_SHIFT; 218 } 219 220 public static int getUserIdFromKey(int key) { 221 return key & ~SETTINGS_TYPE_MASK; 222 } 223 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 244 public static String keyToString(int key) { 245 return "Key[user=" + getUserIdFromKey(key) + ";type=" 246 + settingTypeToString(getTypeFromKey(key)) + "]"; 247 } 248 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. 277 public int getVersionLocked() { 278 return mVersion; 279 } 280 281 public Setting getNullSetting() { 282 return mNullSetting; 283 } 284 285 // The settings provider must hold its lock when calling here. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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 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 */ 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 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 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 591 private boolean hasSettingLocked(String name) { 592 return mSettings.indexOfKey(name) >= 0; 593 } 594 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 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 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 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 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 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 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 */ 801 public static boolean stateFileExists(File file) { 802 AtomicFile stateFile = new AtomicFile(file); 803 return stateFile.exists(); 804 } 805 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 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 864 public MyHandler(Looper looper) { 865 super(looper); 866 } 867 868 @Override 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 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 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 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 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 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 942 public String getName() { 943 return name; 944 } 945 946 public int getKey() { 947 return mKey; 948 } 949 950 public String getValue() { 951 return value; 952 } 953 954 public String getTag() { 955 return tag; 956 } 957 958 public String getDefaultValue() { 959 return defaultValue; 960 } 961 962 public String getPackageName() { 963 return packageName; 964 } 965 966 public boolean isDefaultFromSystem() { 967 return defaultFromSystem; 968 } 969 970 public String getId() { 971 return id; 972 } 973 974 public boolean isNull() { 975 return false; 976 } 977 978 /** @return whether the value changed */ 979 public boolean reset() { 980 return update(this.defaultValue, false, packageName, null, true); 981 } 982 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 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 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 */ 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 1066 private static String base64Encode(String s) { 1067 return Base64.encodeToString(toBytes(s), Base64.NO_WRAP); 1068 } 1069 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 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 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 1101 public static boolean isSystemPackage(Context context, String packageName) { 1102 return isSystemPackage(context, packageName, Binder.getCallingUid()); 1103 } 1104 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