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 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. 225 public int getVersionLocked() { 226 return mVersion; 227 } 228 229 public Setting getNullSetting() { 230 return mNullSetting; 231 } 232 233 // The settings provider must hold its lock when calling here. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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 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 */ 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 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 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 530 private boolean hasSettingLocked(String name) { 531 return mSettings.indexOfKey(name) >= 0; 532 } 533 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 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 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 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 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 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 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 */ 733 public static boolean stateFileExists(File file) { 734 AtomicFile stateFile = new AtomicFile(file); 735 return stateFile.exists(); 736 } 737 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 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 796 public MyHandler(Looper looper) { 797 super(looper); 798 } 799 800 @Override 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 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 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 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 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 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 874 public String getName() { 875 return name; 876 } 877 878 public int getKey() { 879 return mKey; 880 } 881 882 public String getValue() { 883 return value; 884 } 885 886 public String getTag() { 887 return tag; 888 } 889 890 public String getDefaultValue() { 891 return defaultValue; 892 } 893 894 public String getPackageName() { 895 return packageName; 896 } 897 898 public boolean isDefaultFromSystem() { 899 return defaultFromSystem; 900 } 901 902 public String getId() { 903 return id; 904 } 905 906 public boolean isNull() { 907 return false; 908 } 909 910 /** @return whether the value changed */ 911 public boolean reset() { 912 return update(this.defaultValue, false, packageName, null, true); 913 } 914 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 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 */ 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 990 private static String base64Encode(String s) { 991 return Base64.encodeToString(toBytes(s), Base64.NO_WRAP); 992 } 993 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 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 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 1025 public static boolean isSystemPackage(Context context, String packageName) { 1026 return isSystemPackage(context, packageName, Binder.getCallingUid()); 1027 } 1028 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