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