Home | History | Annotate | Download | only in settings
      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