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