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