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