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