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 try { 709 in = new AtomicFile(mStatePersistFile).openRead(); 710 } catch (FileNotFoundException fnfe) { 711 Slog.i(LOG_TAG, "No settings state " + mStatePersistFile); 712 addHistoricalOperationLocked(HISTORICAL_OPERATION_INITIALIZE, null); 713 return; 714 } 715 try { 716 XmlPullParser parser = Xml.newPullParser(); 717 parser.setInput(in, StandardCharsets.UTF_8.name()); 718 parseStateLocked(parser); 719 } catch (XmlPullParserException | IOException e) { 720 String message = "Failed parsing settings file: " + mStatePersistFile; 721 Slog.wtf(LOG_TAG, message); 722 throw new IllegalStateException(message, e); 723 } finally { 724 IoUtils.closeQuietly(in); 725 } 726 } 727 728 /** 729 * Uses AtomicFile to check if the file or its backup exists. 730 * @param file The file to check for existence 731 * @return whether the original or backup exist 732 */ stateFileExists(File file)733 public static boolean stateFileExists(File file) { 734 AtomicFile stateFile = new AtomicFile(file); 735 return stateFile.exists(); 736 } 737 parseStateLocked(XmlPullParser parser)738 private void parseStateLocked(XmlPullParser parser) 739 throws IOException, XmlPullParserException { 740 final int outerDepth = parser.getDepth(); 741 int type; 742 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 743 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 744 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 745 continue; 746 } 747 748 String tagName = parser.getName(); 749 if (tagName.equals(TAG_SETTINGS)) { 750 parseSettingsLocked(parser); 751 } 752 } 753 } 754 parseSettingsLocked(XmlPullParser parser)755 private void parseSettingsLocked(XmlPullParser parser) 756 throws IOException, XmlPullParserException { 757 758 mVersion = Integer.parseInt(parser.getAttributeValue(null, ATTR_VERSION)); 759 760 final int outerDepth = parser.getDepth(); 761 int type; 762 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 763 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 764 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 765 continue; 766 } 767 768 String tagName = parser.getName(); 769 if (tagName.equals(TAG_SETTING)) { 770 String id = parser.getAttributeValue(null, ATTR_ID); 771 String name = parser.getAttributeValue(null, ATTR_NAME); 772 String value = getValueAttribute(parser, ATTR_VALUE, ATTR_VALUE_BASE64); 773 String packageName = parser.getAttributeValue(null, ATTR_PACKAGE); 774 String defaultValue = getValueAttribute(parser, ATTR_DEFAULT_VALUE, 775 ATTR_DEFAULT_VALUE_BASE64); 776 String tag = null; 777 boolean fromSystem = false; 778 if (defaultValue != null) { 779 fromSystem = Boolean.parseBoolean(parser.getAttributeValue( 780 null, ATTR_DEFAULT_SYS_SET)); 781 tag = getValueAttribute(parser, ATTR_TAG, ATTR_TAG_BASE64); 782 } 783 mSettings.put(name, new Setting(name, value, defaultValue, packageName, tag, 784 fromSystem, id)); 785 786 if (DEBUG_PERSISTENCE) { 787 Slog.i(LOG_TAG, "[RESTORED] " + name + "=" + value); 788 } 789 } 790 } 791 } 792 793 private final class MyHandler extends Handler { 794 public static final int MSG_PERSIST_SETTINGS = 1; 795 MyHandler(Looper looper)796 public MyHandler(Looper looper) { 797 super(looper); 798 } 799 800 @Override handleMessage(Message message)801 public void handleMessage(Message message) { 802 switch (message.what) { 803 case MSG_PERSIST_SETTINGS: { 804 Runnable callback = (Runnable) message.obj; 805 doWriteState(); 806 if (callback != null) { 807 callback.run(); 808 } 809 } 810 break; 811 } 812 } 813 } 814 815 private class HistoricalOperation { 816 final long mTimestamp; 817 final String mOperation; 818 final Setting mSetting; 819 HistoricalOperation(long timestamp, String operation, Setting setting)820 public HistoricalOperation(long timestamp, 821 String operation, Setting setting) { 822 mTimestamp = timestamp; 823 mOperation = operation; 824 mSetting = setting; 825 } 826 } 827 828 class Setting { 829 private String name; 830 private String value; 831 private String defaultValue; 832 private String packageName; 833 private String id; 834 private String tag; 835 // Whether the default is set by the system 836 private boolean defaultFromSystem; 837 Setting(Setting other)838 public Setting(Setting other) { 839 name = other.name; 840 value = other.value; 841 defaultValue = other.defaultValue; 842 packageName = other.packageName; 843 id = other.id; 844 defaultFromSystem = other.defaultFromSystem; 845 tag = other.tag; 846 } 847 Setting(String name, String value, boolean makeDefault, String packageName, String tag)848 public Setting(String name, String value, boolean makeDefault, String packageName, 849 String tag) { 850 this.name = name; 851 update(value, makeDefault, packageName, tag, false); 852 } 853 Setting(String name, String value, String defaultValue, String packageName, String tag, boolean fromSystem, String id)854 public Setting(String name, String value, String defaultValue, 855 String packageName, String tag, boolean fromSystem, String id) { 856 mNextId = Math.max(mNextId, Long.parseLong(id) + 1); 857 if (NULL_VALUE.equals(value)) { 858 value = null; 859 } 860 init(name, value, tag, defaultValue, packageName, fromSystem, id); 861 } 862 init(String name, String value, String tag, String defaultValue, String packageName, boolean fromSystem, String id)863 private void init(String name, String value, String tag, String defaultValue, 864 String packageName, boolean fromSystem, String id) { 865 this.name = name; 866 this.value = value; 867 this.tag = tag; 868 this.defaultValue = defaultValue; 869 this.packageName = packageName; 870 this.id = id; 871 this.defaultFromSystem = fromSystem; 872 } 873 getName()874 public String getName() { 875 return name; 876 } 877 getKey()878 public int getKey() { 879 return mKey; 880 } 881 getValue()882 public String getValue() { 883 return value; 884 } 885 getTag()886 public String getTag() { 887 return tag; 888 } 889 getDefaultValue()890 public String getDefaultValue() { 891 return defaultValue; 892 } 893 getPackageName()894 public String getPackageName() { 895 return packageName; 896 } 897 isDefaultFromSystem()898 public boolean isDefaultFromSystem() { 899 return defaultFromSystem; 900 } 901 getId()902 public String getId() { 903 return id; 904 } 905 isNull()906 public boolean isNull() { 907 return false; 908 } 909 910 /** @return whether the value changed */ reset()911 public boolean reset() { 912 return update(this.defaultValue, false, packageName, null, true); 913 } 914 update(String value, boolean setDefault, String packageName, String tag, boolean forceNonSystemPackage)915 public boolean update(String value, boolean setDefault, String packageName, String tag, 916 boolean forceNonSystemPackage) { 917 if (NULL_VALUE.equals(value)) { 918 value = null; 919 } 920 921 final boolean callerSystem = !forceNonSystemPackage && 922 !isNull() && isSystemPackage(mContext, packageName); 923 // Settings set by the system are always defaults. 924 if (callerSystem) { 925 setDefault = true; 926 } 927 928 String defaultValue = this.defaultValue; 929 boolean defaultFromSystem = this.defaultFromSystem; 930 if (setDefault) { 931 if (!Objects.equal(value, this.defaultValue) 932 && (!defaultFromSystem || callerSystem)) { 933 defaultValue = value; 934 // Default null means no default, so the tag is irrelevant 935 // since it is used to reset a settings subset their defaults. 936 // Also it is irrelevant if the system set the canonical default. 937 if (defaultValue == null) { 938 tag = null; 939 defaultFromSystem = false; 940 } 941 } 942 if (!defaultFromSystem && value != null) { 943 if (callerSystem) { 944 defaultFromSystem = true; 945 } 946 } 947 } 948 949 // Is something gonna change? 950 if (Objects.equal(value, this.value) 951 && Objects.equal(defaultValue, this.defaultValue) 952 && Objects.equal(packageName, this.packageName) 953 && Objects.equal(tag, this.tag) 954 && defaultFromSystem == this.defaultFromSystem) { 955 return false; 956 } 957 958 init(name, value, tag, defaultValue, packageName, defaultFromSystem, 959 String.valueOf(mNextId++)); 960 return true; 961 } 962 toString()963 public String toString() { 964 return "Setting{name=" + name + " value=" + value 965 + (defaultValue != null ? " default=" + defaultValue : "") 966 + " packageName=" + packageName + " tag=" + tag 967 + " defaultFromSystem=" + defaultFromSystem + "}"; 968 } 969 } 970 971 /** 972 * @return TRUE if a string is considered "binary" from KXML's point of view. NOTE DO NOT 973 * pass null. 974 */ isBinary(String s)975 public static boolean isBinary(String s) { 976 if (s == null) { 977 throw new NullPointerException(); 978 } 979 // See KXmlSerializer.writeEscaped 980 for (int i = 0; i < s.length(); i++) { 981 char c = s.charAt(i); 982 boolean allowedInXml = (c >= 0x20 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xfffd); 983 if (!allowedInXml) { 984 return true; 985 } 986 } 987 return false; 988 } 989 base64Encode(String s)990 private static String base64Encode(String s) { 991 return Base64.encodeToString(toBytes(s), Base64.NO_WRAP); 992 } 993 base64Decode(String s)994 private static String base64Decode(String s) { 995 return fromBytes(Base64.decode(s, Base64.DEFAULT)); 996 } 997 998 // Note the followings are basically just UTF-16 encode/decode. But we want to preserve 999 // contents as-is, even if it contains broken surrogate pairs, we do it by ourselves, 1000 // since I don't know how Charset would treat them. 1001 toBytes(String s)1002 private static byte[] toBytes(String s) { 1003 final byte[] result = new byte[s.length() * 2]; 1004 int resultIndex = 0; 1005 for (int i = 0; i < s.length(); ++i) { 1006 char ch = s.charAt(i); 1007 result[resultIndex++] = (byte) (ch >> 8); 1008 result[resultIndex++] = (byte) ch; 1009 } 1010 return result; 1011 } 1012 fromBytes(byte[] bytes)1013 private static String fromBytes(byte[] bytes) { 1014 final StringBuffer sb = new StringBuffer(bytes.length / 2); 1015 1016 final int last = bytes.length - 1; 1017 1018 for (int i = 0; i < last; i += 2) { 1019 final char ch = (char) ((bytes[i] & 0xff) << 8 | (bytes[i + 1] & 0xff)); 1020 sb.append(ch); 1021 } 1022 return sb.toString(); 1023 } 1024 isSystemPackage(Context context, String packageName)1025 public static boolean isSystemPackage(Context context, String packageName) { 1026 return isSystemPackage(context, packageName, Binder.getCallingUid()); 1027 } 1028 isSystemPackage(Context context, String packageName, int callingUid)1029 public static boolean isSystemPackage(Context context, String packageName, int callingUid) { 1030 synchronized (sLock) { 1031 if (SYSTEM_PACKAGE_NAME.equals(packageName)) { 1032 return true; 1033 } 1034 1035 // Shell and Root are not considered a part of the system 1036 if (SHELL_PACKAGE_NAME.equals(packageName) 1037 || ROOT_PACKAGE_NAME.equals(packageName)) { 1038 return false; 1039 } 1040 1041 // Native services running as a special UID get a pass 1042 final int callingAppId = UserHandle.getAppId(callingUid); 1043 if (callingAppId < FIRST_APPLICATION_UID) { 1044 sSystemUids.put(callingAppId, callingAppId); 1045 return true; 1046 } 1047 1048 // While some callers may have permissions to manipulate cross user 1049 // settings or some settings are stored in the parent of a managed 1050 // profile for the purpose of determining whether the other end is a 1051 // system component we need to use the user id of the caller for 1052 // pulling information about the caller from the package manager. 1053 final int callingUserId = UserHandle.getUserId(callingUid); 1054 1055 final long identity = Binder.clearCallingIdentity(); 1056 try { 1057 final int uid; 1058 try { 1059 uid = context.getPackageManager().getPackageUidAsUser(packageName, 0, 1060 callingUserId); 1061 } catch (PackageManager.NameNotFoundException e) { 1062 return false; 1063 } 1064 1065 // If the system or a special system UID (like telephony), done. 1066 if (UserHandle.getAppId(uid) < FIRST_APPLICATION_UID) { 1067 sSystemUids.put(uid, uid); 1068 return true; 1069 } 1070 1071 // If already known system component, done. 1072 if (sSystemUids.indexOfKey(uid) >= 0) { 1073 return true; 1074 } 1075 1076 // If SetupWizard, done. 1077 PackageManagerInternal packageManagerInternal = LocalServices.getService( 1078 PackageManagerInternal.class); 1079 if (packageName.equals(packageManagerInternal.getSetupWizardPackageName())) { 1080 sSystemUids.put(uid, uid); 1081 return true; 1082 } 1083 1084 // If a persistent system app, done. 1085 PackageInfo packageInfo; 1086 try { 1087 packageInfo = context.getPackageManager().getPackageInfoAsUser( 1088 packageName, PackageManager.GET_SIGNATURES, callingUserId); 1089 if ((packageInfo.applicationInfo.flags 1090 & ApplicationInfo.FLAG_PERSISTENT) != 0 1091 && (packageInfo.applicationInfo.flags 1092 & ApplicationInfo.FLAG_SYSTEM) != 0) { 1093 sSystemUids.put(uid, uid); 1094 return true; 1095 } 1096 } catch (PackageManager.NameNotFoundException e) { 1097 return false; 1098 } 1099 1100 // Last check if system signed. 1101 if (sSystemSignature == null) { 1102 try { 1103 sSystemSignature = context.getPackageManager().getPackageInfoAsUser( 1104 SYSTEM_PACKAGE_NAME, PackageManager.GET_SIGNATURES, 1105 UserHandle.USER_SYSTEM).signatures[0]; 1106 } catch (PackageManager.NameNotFoundException e) { 1107 /* impossible */ 1108 return false; 1109 } 1110 } 1111 if (sSystemSignature.equals(packageInfo.signatures[0])) { 1112 sSystemUids.put(uid, uid); 1113 return true; 1114 } 1115 } finally { 1116 Binder.restoreCallingIdentity(identity); 1117 } 1118 1119 return false; 1120 } 1121 } 1122 } 1123