ContextImpl.java revision ec062f63a2f5fb49f825544da348e594dbf5bf3c
1/*
2 * Copyright (C) 2006 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 android.app;
18
19import com.android.internal.policy.PolicyManager;
20import com.android.internal.util.XmlUtils;
21import com.google.android.collect.Maps;
22
23import org.xmlpull.v1.XmlPullParserException;
24
25import android.content.BroadcastReceiver;
26import android.content.ComponentName;
27import android.content.ContentResolver;
28import android.content.Context;
29import android.content.ContextWrapper;
30import android.content.IContentProvider;
31import android.content.Intent;
32import android.content.IntentFilter;
33import android.content.IIntentReceiver;
34import android.content.IntentSender;
35import android.content.ReceiverCallNotAllowedException;
36import android.content.ServiceConnection;
37import android.content.SharedPreferences;
38import android.content.pm.ActivityInfo;
39import android.content.pm.ApplicationInfo;
40import android.content.pm.ComponentInfo;
41import android.content.pm.FeatureInfo;
42import android.content.pm.IPackageDataObserver;
43import android.content.pm.IPackageDeleteObserver;
44import android.content.pm.IPackageInstallObserver;
45import android.content.pm.IPackageMoveObserver;
46import android.content.pm.IPackageManager;
47import android.content.pm.IPackageStatsObserver;
48import android.content.pm.InstrumentationInfo;
49import android.content.pm.PackageInfo;
50import android.content.pm.PackageManager;
51import android.content.pm.PermissionGroupInfo;
52import android.content.pm.PermissionInfo;
53import android.content.pm.ProviderInfo;
54import android.content.pm.ResolveInfo;
55import android.content.pm.ServiceInfo;
56import android.content.res.AssetManager;
57import android.content.res.Resources;
58import android.content.res.XmlResourceParser;
59import android.database.DatabaseErrorHandler;
60import android.database.sqlite.SQLiteDatabase;
61import android.database.sqlite.SQLiteDatabase.CursorFactory;
62import android.graphics.Bitmap;
63import android.graphics.drawable.Drawable;
64import android.hardware.SensorManager;
65import android.location.CountryDetector;
66import android.location.ICountryDetector;
67import android.location.ILocationManager;
68import android.location.LocationManager;
69import android.media.AudioManager;
70import android.net.ConnectivityManager;
71import android.net.IConnectivityManager;
72import android.net.ThrottleManager;
73import android.net.IThrottleManager;
74import android.net.Uri;
75import android.net.wifi.IWifiManager;
76import android.net.wifi.WifiManager;
77import android.os.Binder;
78import android.os.Build;
79import android.os.Bundle;
80import android.os.DropBoxManager;
81import android.os.Environment;
82import android.os.FileUtils;
83import android.os.Handler;
84import android.os.IBinder;
85import android.os.IPowerManager;
86import android.os.Looper;
87import android.os.PowerManager;
88import android.os.Process;
89import android.os.RemoteException;
90import android.os.ServiceManager;
91import android.os.Vibrator;
92import android.os.FileUtils.FileStatus;
93import android.os.storage.StorageManager;
94import android.telephony.TelephonyManager;
95import android.content.ClipboardManager;
96import android.util.AndroidRuntimeException;
97import android.util.Log;
98import android.view.ContextThemeWrapper;
99import android.view.LayoutInflater;
100import android.view.WindowManagerImpl;
101import android.view.accessibility.AccessibilityManager;
102import android.view.inputmethod.InputMethodManager;
103import android.accounts.AccountManager;
104import android.accounts.IAccountManager;
105import android.app.admin.DevicePolicyManager;
106import com.android.internal.os.IDropBoxManagerService;
107
108import java.io.File;
109import java.io.FileInputStream;
110import java.io.FileNotFoundException;
111import java.io.FileOutputStream;
112import java.io.IOException;
113import java.io.InputStream;
114import java.lang.ref.WeakReference;
115import java.util.ArrayList;
116import java.util.HashMap;
117import java.util.HashSet;
118import java.util.Iterator;
119import java.util.List;
120import java.util.Map;
121import java.util.Map.Entry;
122import java.util.Set;
123import java.util.WeakHashMap;
124import java.util.concurrent.CountDownLatch;
125import java.util.concurrent.ExecutorService;
126
127class ReceiverRestrictedContext extends ContextWrapper {
128    ReceiverRestrictedContext(Context base) {
129        super(base);
130    }
131
132    @Override
133    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
134        return registerReceiver(receiver, filter, null, null);
135    }
136
137    @Override
138    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
139            String broadcastPermission, Handler scheduler) {
140        throw new ReceiverCallNotAllowedException(
141                "IntentReceiver components are not allowed to register to receive intents");
142        //ex.fillInStackTrace();
143        //Log.e("IntentReceiver", ex.getMessage(), ex);
144        //return mContext.registerReceiver(receiver, filter, broadcastPermission,
145        //        scheduler);
146    }
147
148    @Override
149    public boolean bindService(Intent service, ServiceConnection conn, int flags) {
150        throw new ReceiverCallNotAllowedException(
151                "IntentReceiver components are not allowed to bind to services");
152        //ex.fillInStackTrace();
153        //Log.e("IntentReceiver", ex.getMessage(), ex);
154        //return mContext.bindService(service, interfaceName, conn, flags);
155    }
156}
157
158/**
159 * Common implementation of Context API, which provides the base
160 * context object for Activity and other application components.
161 */
162class ContextImpl extends Context {
163    private final static String TAG = "ApplicationContext";
164    private final static boolean DEBUG = false;
165    private final static boolean DEBUG_ICONS = false;
166
167    private static final Object sSync = new Object();
168    private static AlarmManager sAlarmManager;
169    private static PowerManager sPowerManager;
170    private static ConnectivityManager sConnectivityManager;
171    private static ThrottleManager sThrottleManager;
172    private static WifiManager sWifiManager;
173    private static LocationManager sLocationManager;
174    private static CountryDetector sCountryDetector;
175    private static final HashMap<String, SharedPreferencesImpl> sSharedPrefs =
176            new HashMap<String, SharedPreferencesImpl>();
177
178    private AudioManager mAudioManager;
179    /*package*/ LoadedApk mPackageInfo;
180    private Resources mResources;
181    /*package*/ ActivityThread mMainThread;
182    private Context mOuterContext;
183    private IBinder mActivityToken = null;
184    private ApplicationContentResolver mContentResolver;
185    private int mThemeResource = 0;
186    private Resources.Theme mTheme = null;
187    private PackageManager mPackageManager;
188    private NotificationManager mNotificationManager = null;
189    private ActivityManager mActivityManager = null;
190    private WallpaperManager mWallpaperManager = null;
191    private Context mReceiverRestrictedContext = null;
192    private SearchManager mSearchManager = null;
193    private SensorManager mSensorManager = null;
194    private StorageManager mStorageManager = null;
195    private Vibrator mVibrator = null;
196    private LayoutInflater mLayoutInflater = null;
197    private StatusBarManager mStatusBarManager = null;
198    private TelephonyManager mTelephonyManager = null;
199    private ClipboardManager mClipboardManager = null;
200    private boolean mRestricted;
201    private AccountManager mAccountManager; // protected by mSync
202    private DropBoxManager mDropBoxManager = null;
203    private DevicePolicyManager mDevicePolicyManager = null;
204    private UiModeManager mUiModeManager = null;
205    private DownloadManager mDownloadManager = null;
206
207    private final Object mSync = new Object();
208
209    private File mDatabasesDir;
210    private File mPreferencesDir;
211    private File mFilesDir;
212    private File mCacheDir;
213    private File mExternalFilesDir;
214    private File mExternalCacheDir;
215
216    private static final String[] EMPTY_FILE_LIST = {};
217
218    @Override
219    public AssetManager getAssets() {
220        return mResources.getAssets();
221    }
222
223    @Override
224    public Resources getResources() {
225        return mResources;
226    }
227
228    @Override
229    public PackageManager getPackageManager() {
230        if (mPackageManager != null) {
231            return mPackageManager;
232        }
233
234        IPackageManager pm = ActivityThread.getPackageManager();
235        if (pm != null) {
236            // Doesn't matter if we make more than one instance.
237            return (mPackageManager = new ApplicationPackageManager(this, pm));
238        }
239
240        return null;
241    }
242
243    @Override
244    public ContentResolver getContentResolver() {
245        return mContentResolver;
246    }
247
248    @Override
249    public Looper getMainLooper() {
250        return mMainThread.getLooper();
251    }
252
253    @Override
254    public Context getApplicationContext() {
255        return (mPackageInfo != null) ?
256                mPackageInfo.getApplication() : mMainThread.getApplication();
257    }
258
259    @Override
260    public void setTheme(int resid) {
261        mThemeResource = resid;
262    }
263
264    @Override
265    public Resources.Theme getTheme() {
266        if (mTheme == null) {
267            if (mThemeResource == 0) {
268                final Context outerContext = getOuterContext();
269                mThemeResource = (outerContext.getApplicationInfo().targetSdkVersion
270                        >= Build.VERSION_CODES.HONEYCOMB)
271                                ? com.android.internal.R.style.Theme_Holo
272                                : com.android.internal.R.style.Theme;
273            }
274            mTheme = mResources.newTheme();
275            mTheme.applyStyle(mThemeResource, true);
276        }
277        return mTheme;
278    }
279
280    @Override
281    public ClassLoader getClassLoader() {
282        return mPackageInfo != null ?
283                mPackageInfo.getClassLoader() : ClassLoader.getSystemClassLoader();
284    }
285
286    @Override
287    public String getPackageName() {
288        if (mPackageInfo != null) {
289            return mPackageInfo.getPackageName();
290        }
291        throw new RuntimeException("Not supported in system context");
292    }
293
294    @Override
295    public ApplicationInfo getApplicationInfo() {
296        if (mPackageInfo != null) {
297            return mPackageInfo.getApplicationInfo();
298        }
299        throw new RuntimeException("Not supported in system context");
300    }
301
302    @Override
303    public String getPackageResourcePath() {
304        if (mPackageInfo != null) {
305            return mPackageInfo.getResDir();
306        }
307        throw new RuntimeException("Not supported in system context");
308    }
309
310    @Override
311    public String getPackageCodePath() {
312        if (mPackageInfo != null) {
313            return mPackageInfo.getAppDir();
314        }
315        throw new RuntimeException("Not supported in system context");
316    }
317
318    private static File makeBackupFile(File prefsFile) {
319        return new File(prefsFile.getPath() + ".bak");
320    }
321
322    public File getSharedPrefsFile(String name) {
323        return makeFilename(getPreferencesDir(), name + ".xml");
324    }
325
326    @Override
327    public SharedPreferences getSharedPreferences(String name, int mode) {
328        SharedPreferencesImpl sp;
329        File prefsFile;
330        boolean needInitialLoad = false;
331        synchronized (sSharedPrefs) {
332            sp = sSharedPrefs.get(name);
333            if (sp != null && !sp.hasFileChangedUnexpectedly()) {
334                return sp;
335            }
336            prefsFile = getSharedPrefsFile(name);
337            if (sp == null) {
338                sp = new SharedPreferencesImpl(prefsFile, mode, null);
339                sSharedPrefs.put(name, sp);
340                needInitialLoad = true;
341            }
342        }
343
344        synchronized (sp) {
345            if (needInitialLoad && sp.isLoaded()) {
346                // lost the race to load; another thread handled it
347                return sp;
348            }
349            File backup = makeBackupFile(prefsFile);
350            if (backup.exists()) {
351                prefsFile.delete();
352                backup.renameTo(prefsFile);
353            }
354
355            // Debugging
356            if (prefsFile.exists() && !prefsFile.canRead()) {
357                Log.w(TAG, "Attempt to read preferences file " + prefsFile + " without permission");
358            }
359
360            Map map = null;
361            if (prefsFile.exists() && prefsFile.canRead()) {
362                try {
363                    FileInputStream str = new FileInputStream(prefsFile);
364                    map = XmlUtils.readMapXml(str);
365                    str.close();
366                } catch (org.xmlpull.v1.XmlPullParserException e) {
367                    Log.w(TAG, "getSharedPreferences", e);
368                } catch (FileNotFoundException e) {
369                    Log.w(TAG, "getSharedPreferences", e);
370                } catch (IOException e) {
371                    Log.w(TAG, "getSharedPreferences", e);
372                }
373            }
374            sp.replace(map);
375        }
376        return sp;
377    }
378
379    private File getPreferencesDir() {
380        synchronized (mSync) {
381            if (mPreferencesDir == null) {
382                mPreferencesDir = new File(getDataDirFile(), "shared_prefs");
383            }
384            return mPreferencesDir;
385        }
386    }
387
388    @Override
389    public FileInputStream openFileInput(String name)
390        throws FileNotFoundException {
391        File f = makeFilename(getFilesDir(), name);
392        return new FileInputStream(f);
393    }
394
395    @Override
396    public FileOutputStream openFileOutput(String name, int mode)
397        throws FileNotFoundException {
398        final boolean append = (mode&MODE_APPEND) != 0;
399        File f = makeFilename(getFilesDir(), name);
400        try {
401            FileOutputStream fos = new FileOutputStream(f, append);
402            setFilePermissionsFromMode(f.getPath(), mode, 0);
403            return fos;
404        } catch (FileNotFoundException e) {
405        }
406
407        File parent = f.getParentFile();
408        parent.mkdir();
409        FileUtils.setPermissions(
410            parent.getPath(),
411            FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
412            -1, -1);
413        FileOutputStream fos = new FileOutputStream(f, append);
414        setFilePermissionsFromMode(f.getPath(), mode, 0);
415        return fos;
416    }
417
418    @Override
419    public boolean deleteFile(String name) {
420        File f = makeFilename(getFilesDir(), name);
421        return f.delete();
422    }
423
424    @Override
425    public File getFilesDir() {
426        synchronized (mSync) {
427            if (mFilesDir == null) {
428                mFilesDir = new File(getDataDirFile(), "files");
429            }
430            if (!mFilesDir.exists()) {
431                if(!mFilesDir.mkdirs()) {
432                    Log.w(TAG, "Unable to create files directory " + mFilesDir.getPath());
433                    return null;
434                }
435                FileUtils.setPermissions(
436                        mFilesDir.getPath(),
437                        FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
438                        -1, -1);
439            }
440            return mFilesDir;
441        }
442    }
443
444    @Override
445    public File getExternalFilesDir(String type) {
446        synchronized (mSync) {
447            if (mExternalFilesDir == null) {
448                mExternalFilesDir = Environment.getExternalStorageAppFilesDirectory(
449                        getPackageName());
450            }
451            if (!mExternalFilesDir.exists()) {
452                try {
453                    (new File(Environment.getExternalStorageAndroidDataDir(),
454                            ".nomedia")).createNewFile();
455                } catch (IOException e) {
456                }
457                if (!mExternalFilesDir.mkdirs()) {
458                    Log.w(TAG, "Unable to create external files directory");
459                    return null;
460                }
461            }
462            if (type == null) {
463                return mExternalFilesDir;
464            }
465            File dir = new File(mExternalFilesDir, type);
466            if (!dir.exists()) {
467                if (!dir.mkdirs()) {
468                    Log.w(TAG, "Unable to create external media directory " + dir);
469                    return null;
470                }
471            }
472            return dir;
473        }
474    }
475
476    @Override
477    public File getCacheDir() {
478        synchronized (mSync) {
479            if (mCacheDir == null) {
480                mCacheDir = new File(getDataDirFile(), "cache");
481            }
482            if (!mCacheDir.exists()) {
483                if(!mCacheDir.mkdirs()) {
484                    Log.w(TAG, "Unable to create cache directory");
485                    return null;
486                }
487                FileUtils.setPermissions(
488                        mCacheDir.getPath(),
489                        FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
490                        -1, -1);
491            }
492        }
493        return mCacheDir;
494    }
495
496    @Override
497    public File getExternalCacheDir() {
498        synchronized (mSync) {
499            if (mExternalCacheDir == null) {
500                mExternalCacheDir = Environment.getExternalStorageAppCacheDirectory(
501                        getPackageName());
502            }
503            if (!mExternalCacheDir.exists()) {
504                try {
505                    (new File(Environment.getExternalStorageAndroidDataDir(),
506                            ".nomedia")).createNewFile();
507                } catch (IOException e) {
508                }
509                if (!mExternalCacheDir.mkdirs()) {
510                    Log.w(TAG, "Unable to create external cache directory");
511                    return null;
512                }
513            }
514            return mExternalCacheDir;
515        }
516    }
517
518    @Override
519    public File getFileStreamPath(String name) {
520        return makeFilename(getFilesDir(), name);
521    }
522
523    @Override
524    public String[] fileList() {
525        final String[] list = getFilesDir().list();
526        return (list != null) ? list : EMPTY_FILE_LIST;
527    }
528
529    @Override
530    public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory) {
531        File f = validateFilePath(name, true);
532        SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(f, factory);
533        setFilePermissionsFromMode(f.getPath(), mode, 0);
534        return db;
535    }
536
537    @Override
538    public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory,
539            DatabaseErrorHandler errorHandler) {
540        File f = validateFilePath(name, true);
541        SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(f.getPath(), factory, errorHandler);
542        setFilePermissionsFromMode(f.getPath(), mode, 0);
543        return db;
544    }
545
546    @Override
547    public boolean deleteDatabase(String name) {
548        try {
549            File f = validateFilePath(name, false);
550            return f.delete();
551        } catch (Exception e) {
552        }
553        return false;
554    }
555
556    @Override
557    public File getDatabasePath(String name) {
558        return validateFilePath(name, false);
559    }
560
561    @Override
562    public String[] databaseList() {
563        final String[] list = getDatabasesDir().list();
564        return (list != null) ? list : EMPTY_FILE_LIST;
565    }
566
567
568    private File getDatabasesDir() {
569        synchronized (mSync) {
570            if (mDatabasesDir == null) {
571                mDatabasesDir = new File(getDataDirFile(), "databases");
572            }
573            if (mDatabasesDir.getPath().equals("databases")) {
574                mDatabasesDir = new File("/data/system");
575            }
576            return mDatabasesDir;
577        }
578    }
579
580    @Override
581    public Drawable getWallpaper() {
582        return getWallpaperManager().getDrawable();
583    }
584
585    @Override
586    public Drawable peekWallpaper() {
587        return getWallpaperManager().peekDrawable();
588    }
589
590    @Override
591    public int getWallpaperDesiredMinimumWidth() {
592        return getWallpaperManager().getDesiredMinimumWidth();
593    }
594
595    @Override
596    public int getWallpaperDesiredMinimumHeight() {
597        return getWallpaperManager().getDesiredMinimumHeight();
598    }
599
600    @Override
601    public void setWallpaper(Bitmap bitmap) throws IOException  {
602        getWallpaperManager().setBitmap(bitmap);
603    }
604
605    @Override
606    public void setWallpaper(InputStream data) throws IOException {
607        getWallpaperManager().setStream(data);
608    }
609
610    @Override
611    public void clearWallpaper() throws IOException {
612        getWallpaperManager().clear();
613    }
614
615    @Override
616    public void startActivity(Intent intent) {
617        if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
618            throw new AndroidRuntimeException(
619                    "Calling startActivity() from outside of an Activity "
620                    + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
621                    + " Is this really what you want?");
622        }
623        mMainThread.getInstrumentation().execStartActivity(
624            getOuterContext(), mMainThread.getApplicationThread(), null,
625            (Activity)null, intent, -1);
626    }
627
628    @Override
629    public void startIntentSender(IntentSender intent,
630            Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags)
631            throws IntentSender.SendIntentException {
632        try {
633            String resolvedType = null;
634            if (fillInIntent != null) {
635                resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
636            }
637            int result = ActivityManagerNative.getDefault()
638                .startActivityIntentSender(mMainThread.getApplicationThread(), intent,
639                        fillInIntent, resolvedType, null, null,
640                        0, flagsMask, flagsValues);
641            if (result == IActivityManager.START_CANCELED) {
642                throw new IntentSender.SendIntentException();
643            }
644            Instrumentation.checkStartActivityResult(result, null);
645        } catch (RemoteException e) {
646        }
647    }
648
649    @Override
650    public void sendBroadcast(Intent intent) {
651        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
652        try {
653            ActivityManagerNative.getDefault().broadcastIntent(
654                mMainThread.getApplicationThread(), intent, resolvedType, null,
655                Activity.RESULT_OK, null, null, null, false, false);
656        } catch (RemoteException e) {
657        }
658    }
659
660    @Override
661    public void sendBroadcast(Intent intent, String receiverPermission) {
662        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
663        try {
664            ActivityManagerNative.getDefault().broadcastIntent(
665                mMainThread.getApplicationThread(), intent, resolvedType, null,
666                Activity.RESULT_OK, null, null, receiverPermission, false, false);
667        } catch (RemoteException e) {
668        }
669    }
670
671    @Override
672    public void sendOrderedBroadcast(Intent intent,
673            String receiverPermission) {
674        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
675        try {
676            ActivityManagerNative.getDefault().broadcastIntent(
677                mMainThread.getApplicationThread(), intent, resolvedType, null,
678                Activity.RESULT_OK, null, null, receiverPermission, true, false);
679        } catch (RemoteException e) {
680        }
681    }
682
683    @Override
684    public void sendOrderedBroadcast(Intent intent,
685            String receiverPermission, BroadcastReceiver resultReceiver,
686            Handler scheduler, int initialCode, String initialData,
687            Bundle initialExtras) {
688        IIntentReceiver rd = null;
689        if (resultReceiver != null) {
690            if (mPackageInfo != null) {
691                if (scheduler == null) {
692                    scheduler = mMainThread.getHandler();
693                }
694                rd = mPackageInfo.getReceiverDispatcher(
695                    resultReceiver, getOuterContext(), scheduler,
696                    mMainThread.getInstrumentation(), false);
697            } else {
698                if (scheduler == null) {
699                    scheduler = mMainThread.getHandler();
700                }
701                rd = new LoadedApk.ReceiverDispatcher(
702                        resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
703            }
704        }
705        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
706        try {
707            ActivityManagerNative.getDefault().broadcastIntent(
708                mMainThread.getApplicationThread(), intent, resolvedType, rd,
709                initialCode, initialData, initialExtras, receiverPermission,
710                true, false);
711        } catch (RemoteException e) {
712        }
713    }
714
715    @Override
716    public void sendStickyBroadcast(Intent intent) {
717        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
718        try {
719            ActivityManagerNative.getDefault().broadcastIntent(
720                mMainThread.getApplicationThread(), intent, resolvedType, null,
721                Activity.RESULT_OK, null, null, null, false, true);
722        } catch (RemoteException e) {
723        }
724    }
725
726    @Override
727    public void sendStickyOrderedBroadcast(Intent intent,
728            BroadcastReceiver resultReceiver,
729            Handler scheduler, int initialCode, String initialData,
730            Bundle initialExtras) {
731        IIntentReceiver rd = null;
732        if (resultReceiver != null) {
733            if (mPackageInfo != null) {
734                if (scheduler == null) {
735                    scheduler = mMainThread.getHandler();
736                }
737                rd = mPackageInfo.getReceiverDispatcher(
738                    resultReceiver, getOuterContext(), scheduler,
739                    mMainThread.getInstrumentation(), false);
740            } else {
741                if (scheduler == null) {
742                    scheduler = mMainThread.getHandler();
743                }
744                rd = new LoadedApk.ReceiverDispatcher(
745                        resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
746            }
747        }
748        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
749        try {
750            ActivityManagerNative.getDefault().broadcastIntent(
751                mMainThread.getApplicationThread(), intent, resolvedType, rd,
752                initialCode, initialData, initialExtras, null,
753                true, true);
754        } catch (RemoteException e) {
755        }
756    }
757
758    @Override
759    public void removeStickyBroadcast(Intent intent) {
760        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
761        if (resolvedType != null) {
762            intent = new Intent(intent);
763            intent.setDataAndType(intent.getData(), resolvedType);
764        }
765        try {
766            ActivityManagerNative.getDefault().unbroadcastIntent(
767                mMainThread.getApplicationThread(), intent);
768        } catch (RemoteException e) {
769        }
770    }
771
772    @Override
773    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
774        return registerReceiver(receiver, filter, null, null);
775    }
776
777    @Override
778    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
779            String broadcastPermission, Handler scheduler) {
780        return registerReceiverInternal(receiver, filter, broadcastPermission,
781                scheduler, getOuterContext());
782    }
783
784    private Intent registerReceiverInternal(BroadcastReceiver receiver,
785            IntentFilter filter, String broadcastPermission,
786            Handler scheduler, Context context) {
787        IIntentReceiver rd = null;
788        if (receiver != null) {
789            if (mPackageInfo != null && context != null) {
790                if (scheduler == null) {
791                    scheduler = mMainThread.getHandler();
792                }
793                rd = mPackageInfo.getReceiverDispatcher(
794                    receiver, context, scheduler,
795                    mMainThread.getInstrumentation(), true);
796            } else {
797                if (scheduler == null) {
798                    scheduler = mMainThread.getHandler();
799                }
800                rd = new LoadedApk.ReceiverDispatcher(
801                        receiver, context, scheduler, null, true).getIIntentReceiver();
802            }
803        }
804        try {
805            return ActivityManagerNative.getDefault().registerReceiver(
806                    mMainThread.getApplicationThread(),
807                    rd, filter, broadcastPermission);
808        } catch (RemoteException e) {
809            return null;
810        }
811    }
812
813    @Override
814    public void unregisterReceiver(BroadcastReceiver receiver) {
815        if (mPackageInfo != null) {
816            IIntentReceiver rd = mPackageInfo.forgetReceiverDispatcher(
817                    getOuterContext(), receiver);
818            try {
819                ActivityManagerNative.getDefault().unregisterReceiver(rd);
820            } catch (RemoteException e) {
821            }
822        } else {
823            throw new RuntimeException("Not supported in system context");
824        }
825    }
826
827    @Override
828    public ComponentName startService(Intent service) {
829        try {
830            ComponentName cn = ActivityManagerNative.getDefault().startService(
831                mMainThread.getApplicationThread(), service,
832                service.resolveTypeIfNeeded(getContentResolver()));
833            if (cn != null && cn.getPackageName().equals("!")) {
834                throw new SecurityException(
835                        "Not allowed to start service " + service
836                        + " without permission " + cn.getClassName());
837            }
838            return cn;
839        } catch (RemoteException e) {
840            return null;
841        }
842    }
843
844    @Override
845    public boolean stopService(Intent service) {
846        try {
847            int res = ActivityManagerNative.getDefault().stopService(
848                mMainThread.getApplicationThread(), service,
849                service.resolveTypeIfNeeded(getContentResolver()));
850            if (res < 0) {
851                throw new SecurityException(
852                        "Not allowed to stop service " + service);
853            }
854            return res != 0;
855        } catch (RemoteException e) {
856            return false;
857        }
858    }
859
860    @Override
861    public boolean bindService(Intent service, ServiceConnection conn,
862            int flags) {
863        IServiceConnection sd;
864        if (mPackageInfo != null) {
865            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
866                    mMainThread.getHandler(), flags);
867        } else {
868            throw new RuntimeException("Not supported in system context");
869        }
870        try {
871            int res = ActivityManagerNative.getDefault().bindService(
872                mMainThread.getApplicationThread(), getActivityToken(),
873                service, service.resolveTypeIfNeeded(getContentResolver()),
874                sd, flags);
875            if (res < 0) {
876                throw new SecurityException(
877                        "Not allowed to bind to service " + service);
878            }
879            return res != 0;
880        } catch (RemoteException e) {
881            return false;
882        }
883    }
884
885    @Override
886    public void unbindService(ServiceConnection conn) {
887        if (mPackageInfo != null) {
888            IServiceConnection sd = mPackageInfo.forgetServiceDispatcher(
889                    getOuterContext(), conn);
890            try {
891                ActivityManagerNative.getDefault().unbindService(sd);
892            } catch (RemoteException e) {
893            }
894        } else {
895            throw new RuntimeException("Not supported in system context");
896        }
897    }
898
899    @Override
900    public boolean startInstrumentation(ComponentName className,
901            String profileFile, Bundle arguments) {
902        try {
903            return ActivityManagerNative.getDefault().startInstrumentation(
904                    className, profileFile, 0, arguments, null);
905        } catch (RemoteException e) {
906            // System has crashed, nothing we can do.
907        }
908        return false;
909    }
910
911    @Override
912    public Object getSystemService(String name) {
913        if (WINDOW_SERVICE.equals(name)) {
914            return WindowManagerImpl.getDefault();
915        } else if (LAYOUT_INFLATER_SERVICE.equals(name)) {
916            synchronized (mSync) {
917                LayoutInflater inflater = mLayoutInflater;
918                if (inflater != null) {
919                    return inflater;
920                }
921                mLayoutInflater = inflater =
922                    PolicyManager.makeNewLayoutInflater(getOuterContext());
923                return inflater;
924            }
925        } else if (ACTIVITY_SERVICE.equals(name)) {
926            return getActivityManager();
927        } else if (INPUT_METHOD_SERVICE.equals(name)) {
928            return InputMethodManager.getInstance(this);
929        } else if (ALARM_SERVICE.equals(name)) {
930            return getAlarmManager();
931        } else if (ACCOUNT_SERVICE.equals(name)) {
932            return getAccountManager();
933        } else if (POWER_SERVICE.equals(name)) {
934            return getPowerManager();
935        } else if (CONNECTIVITY_SERVICE.equals(name)) {
936            return getConnectivityManager();
937        } else if (THROTTLE_SERVICE.equals(name)) {
938            return getThrottleManager();
939        } else if (WIFI_SERVICE.equals(name)) {
940            return getWifiManager();
941        } else if (NOTIFICATION_SERVICE.equals(name)) {
942            return getNotificationManager();
943        } else if (KEYGUARD_SERVICE.equals(name)) {
944            return new KeyguardManager();
945        } else if (ACCESSIBILITY_SERVICE.equals(name)) {
946            return AccessibilityManager.getInstance(this);
947        } else if (LOCATION_SERVICE.equals(name)) {
948            return getLocationManager();
949        } else if (COUNTRY_DETECTOR.equals(name)) {
950            return getCountryDetector();
951        } else if (SEARCH_SERVICE.equals(name)) {
952            return getSearchManager();
953        } else if (SENSOR_SERVICE.equals(name)) {
954            return getSensorManager();
955        } else if (STORAGE_SERVICE.equals(name)) {
956            return getStorageManager();
957        } else if (VIBRATOR_SERVICE.equals(name)) {
958            return getVibrator();
959        } else if (STATUS_BAR_SERVICE.equals(name)) {
960            synchronized (mSync) {
961                if (mStatusBarManager == null) {
962                    mStatusBarManager = new StatusBarManager(getOuterContext());
963                }
964                return mStatusBarManager;
965            }
966        } else if (AUDIO_SERVICE.equals(name)) {
967            return getAudioManager();
968        } else if (TELEPHONY_SERVICE.equals(name)) {
969            return getTelephonyManager();
970        } else if (CLIPBOARD_SERVICE.equals(name)) {
971            return getClipboardManager();
972        } else if (WALLPAPER_SERVICE.equals(name)) {
973            return getWallpaperManager();
974        } else if (DROPBOX_SERVICE.equals(name)) {
975            return getDropBoxManager();
976        } else if (DEVICE_POLICY_SERVICE.equals(name)) {
977            return getDevicePolicyManager();
978        } else if (UI_MODE_SERVICE.equals(name)) {
979            return getUiModeManager();
980        } else if (DOWNLOAD_SERVICE.equals(name)) {
981            return getDownloadManager();
982        }
983
984        return null;
985    }
986
987    private AccountManager getAccountManager() {
988        synchronized (mSync) {
989            if (mAccountManager == null) {
990                IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);
991                IAccountManager service = IAccountManager.Stub.asInterface(b);
992                mAccountManager = new AccountManager(this, service);
993            }
994            return mAccountManager;
995        }
996    }
997
998    private ActivityManager getActivityManager() {
999        synchronized (mSync) {
1000            if (mActivityManager == null) {
1001                mActivityManager = new ActivityManager(getOuterContext(),
1002                        mMainThread.getHandler());
1003            }
1004        }
1005        return mActivityManager;
1006    }
1007
1008    private AlarmManager getAlarmManager() {
1009        synchronized (sSync) {
1010            if (sAlarmManager == null) {
1011                IBinder b = ServiceManager.getService(ALARM_SERVICE);
1012                IAlarmManager service = IAlarmManager.Stub.asInterface(b);
1013                sAlarmManager = new AlarmManager(service);
1014            }
1015        }
1016        return sAlarmManager;
1017    }
1018
1019    private PowerManager getPowerManager() {
1020        synchronized (sSync) {
1021            if (sPowerManager == null) {
1022                IBinder b = ServiceManager.getService(POWER_SERVICE);
1023                IPowerManager service = IPowerManager.Stub.asInterface(b);
1024                sPowerManager = new PowerManager(service, mMainThread.getHandler());
1025            }
1026        }
1027        return sPowerManager;
1028    }
1029
1030    private ConnectivityManager getConnectivityManager()
1031    {
1032        synchronized (sSync) {
1033            if (sConnectivityManager == null) {
1034                IBinder b = ServiceManager.getService(CONNECTIVITY_SERVICE);
1035                IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
1036                sConnectivityManager = new ConnectivityManager(service);
1037            }
1038        }
1039        return sConnectivityManager;
1040    }
1041
1042    private ThrottleManager getThrottleManager()
1043    {
1044        synchronized (sSync) {
1045            if (sThrottleManager == null) {
1046                IBinder b = ServiceManager.getService(THROTTLE_SERVICE);
1047                IThrottleManager service = IThrottleManager.Stub.asInterface(b);
1048                sThrottleManager = new ThrottleManager(service);
1049            }
1050        }
1051        return sThrottleManager;
1052    }
1053
1054    private WifiManager getWifiManager()
1055    {
1056        synchronized (sSync) {
1057            if (sWifiManager == null) {
1058                IBinder b = ServiceManager.getService(WIFI_SERVICE);
1059                IWifiManager service = IWifiManager.Stub.asInterface(b);
1060                sWifiManager = new WifiManager(service, mMainThread.getHandler());
1061            }
1062        }
1063        return sWifiManager;
1064    }
1065
1066    private NotificationManager getNotificationManager() {
1067        synchronized (mSync) {
1068            if (mNotificationManager == null) {
1069                final Context outerContext = getOuterContext();
1070                mNotificationManager = new NotificationManager(
1071                        new ContextThemeWrapper(outerContext,
1072                                outerContext.getApplicationInfo().targetSdkVersion >=
1073                                    Build.VERSION_CODES.HONEYCOMB
1074                                ? com.android.internal.R.style.Theme_Holo_Dialog
1075                                : com.android.internal.R.style.Theme_Dialog),
1076                        mMainThread.getHandler());
1077            }
1078        }
1079        return mNotificationManager;
1080    }
1081
1082    private WallpaperManager getWallpaperManager() {
1083        synchronized (mSync) {
1084            if (mWallpaperManager == null) {
1085                mWallpaperManager = new WallpaperManager(getOuterContext(),
1086                        mMainThread.getHandler());
1087            }
1088        }
1089        return mWallpaperManager;
1090    }
1091
1092    private TelephonyManager getTelephonyManager() {
1093        synchronized (mSync) {
1094            if (mTelephonyManager == null) {
1095                mTelephonyManager = new TelephonyManager(getOuterContext());
1096            }
1097        }
1098        return mTelephonyManager;
1099    }
1100
1101    private ClipboardManager getClipboardManager() {
1102        synchronized (mSync) {
1103            if (mClipboardManager == null) {
1104                mClipboardManager = new ClipboardManager(getOuterContext(),
1105                        mMainThread.getHandler());
1106            }
1107        }
1108        return mClipboardManager;
1109    }
1110
1111    private LocationManager getLocationManager() {
1112        synchronized (sSync) {
1113            if (sLocationManager == null) {
1114                IBinder b = ServiceManager.getService(LOCATION_SERVICE);
1115                ILocationManager service = ILocationManager.Stub.asInterface(b);
1116                sLocationManager = new LocationManager(service);
1117            }
1118        }
1119        return sLocationManager;
1120    }
1121
1122    private CountryDetector getCountryDetector() {
1123        synchronized (sSync) {
1124            if (sCountryDetector == null) {
1125                IBinder b = ServiceManager.getService(COUNTRY_DETECTOR);
1126                ICountryDetector service = ICountryDetector.Stub.asInterface(b);
1127                sCountryDetector = new CountryDetector(service);
1128            }
1129        }
1130        return sCountryDetector;
1131    }
1132
1133    private SearchManager getSearchManager() {
1134        synchronized (mSync) {
1135            if (mSearchManager == null) {
1136                mSearchManager = new SearchManager(getOuterContext(), mMainThread.getHandler());
1137            }
1138        }
1139        return mSearchManager;
1140    }
1141
1142    private SensorManager getSensorManager() {
1143        synchronized (mSync) {
1144            if (mSensorManager == null) {
1145                mSensorManager = new SensorManager(mMainThread.getHandler().getLooper());
1146            }
1147        }
1148        return mSensorManager;
1149    }
1150
1151    private StorageManager getStorageManager() {
1152        synchronized (mSync) {
1153            if (mStorageManager == null) {
1154                try {
1155                    mStorageManager = new StorageManager(mMainThread.getHandler().getLooper());
1156                } catch (RemoteException rex) {
1157                    Log.e(TAG, "Failed to create StorageManager", rex);
1158                    mStorageManager = null;
1159                }
1160            }
1161        }
1162        return mStorageManager;
1163    }
1164
1165    private Vibrator getVibrator() {
1166        synchronized (mSync) {
1167            if (mVibrator == null) {
1168                mVibrator = new Vibrator();
1169            }
1170        }
1171        return mVibrator;
1172    }
1173
1174    private AudioManager getAudioManager()
1175    {
1176        if (mAudioManager == null) {
1177            mAudioManager = new AudioManager(this);
1178        }
1179        return mAudioManager;
1180    }
1181
1182    /* package */ static DropBoxManager createDropBoxManager() {
1183        IBinder b = ServiceManager.getService(DROPBOX_SERVICE);
1184        IDropBoxManagerService service = IDropBoxManagerService.Stub.asInterface(b);
1185        if (service == null) {
1186            // Don't return a DropBoxManager that will NPE upon use.
1187            // This also avoids caching a broken DropBoxManager in
1188            // getDropBoxManager during early boot, before the
1189            // DROPBOX_SERVICE is registered.
1190            return null;
1191        }
1192        return new DropBoxManager(service);
1193    }
1194
1195    private DropBoxManager getDropBoxManager() {
1196        synchronized (mSync) {
1197            if (mDropBoxManager == null) {
1198                mDropBoxManager = createDropBoxManager();
1199            }
1200        }
1201        return mDropBoxManager;
1202    }
1203
1204    private DevicePolicyManager getDevicePolicyManager() {
1205        synchronized (mSync) {
1206            if (mDevicePolicyManager == null) {
1207                mDevicePolicyManager = DevicePolicyManager.create(this,
1208                        mMainThread.getHandler());
1209            }
1210        }
1211        return mDevicePolicyManager;
1212    }
1213
1214    private UiModeManager getUiModeManager() {
1215        synchronized (mSync) {
1216            if (mUiModeManager == null) {
1217                mUiModeManager = new UiModeManager();
1218            }
1219        }
1220        return mUiModeManager;
1221    }
1222
1223    private DownloadManager getDownloadManager() {
1224        synchronized (mSync) {
1225            if (mDownloadManager == null) {
1226                mDownloadManager = new DownloadManager(getContentResolver(), getPackageName());
1227            }
1228        }
1229        return mDownloadManager;
1230    }
1231
1232    @Override
1233    public int checkPermission(String permission, int pid, int uid) {
1234        if (permission == null) {
1235            throw new IllegalArgumentException("permission is null");
1236        }
1237
1238        if (!Process.supportsProcesses()) {
1239            return PackageManager.PERMISSION_GRANTED;
1240        }
1241        try {
1242            return ActivityManagerNative.getDefault().checkPermission(
1243                    permission, pid, uid);
1244        } catch (RemoteException e) {
1245            return PackageManager.PERMISSION_DENIED;
1246        }
1247    }
1248
1249    @Override
1250    public int checkCallingPermission(String permission) {
1251        if (permission == null) {
1252            throw new IllegalArgumentException("permission is null");
1253        }
1254
1255        if (!Process.supportsProcesses()) {
1256            return PackageManager.PERMISSION_GRANTED;
1257        }
1258        int pid = Binder.getCallingPid();
1259        if (pid != Process.myPid()) {
1260            return checkPermission(permission, pid,
1261                    Binder.getCallingUid());
1262        }
1263        return PackageManager.PERMISSION_DENIED;
1264    }
1265
1266    @Override
1267    public int checkCallingOrSelfPermission(String permission) {
1268        if (permission == null) {
1269            throw new IllegalArgumentException("permission is null");
1270        }
1271
1272        return checkPermission(permission, Binder.getCallingPid(),
1273                Binder.getCallingUid());
1274    }
1275
1276    private void enforce(
1277            String permission, int resultOfCheck,
1278            boolean selfToo, int uid, String message) {
1279        if (resultOfCheck != PackageManager.PERMISSION_GRANTED) {
1280            throw new SecurityException(
1281                    (message != null ? (message + ": ") : "") +
1282                    (selfToo
1283                     ? "Neither user " + uid + " nor current process has "
1284                     : "User " + uid + " does not have ") +
1285                    permission +
1286                    ".");
1287        }
1288    }
1289
1290    public void enforcePermission(
1291            String permission, int pid, int uid, String message) {
1292        enforce(permission,
1293                checkPermission(permission, pid, uid),
1294                false,
1295                uid,
1296                message);
1297    }
1298
1299    public void enforceCallingPermission(String permission, String message) {
1300        enforce(permission,
1301                checkCallingPermission(permission),
1302                false,
1303                Binder.getCallingUid(),
1304                message);
1305    }
1306
1307    public void enforceCallingOrSelfPermission(
1308            String permission, String message) {
1309        enforce(permission,
1310                checkCallingOrSelfPermission(permission),
1311                true,
1312                Binder.getCallingUid(),
1313                message);
1314    }
1315
1316    @Override
1317    public void grantUriPermission(String toPackage, Uri uri, int modeFlags) {
1318         try {
1319            ActivityManagerNative.getDefault().grantUriPermission(
1320                    mMainThread.getApplicationThread(), toPackage, uri,
1321                    modeFlags);
1322        } catch (RemoteException e) {
1323        }
1324    }
1325
1326    @Override
1327    public void revokeUriPermission(Uri uri, int modeFlags) {
1328         try {
1329            ActivityManagerNative.getDefault().revokeUriPermission(
1330                    mMainThread.getApplicationThread(), uri,
1331                    modeFlags);
1332        } catch (RemoteException e) {
1333        }
1334    }
1335
1336    @Override
1337    public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
1338        if (!Process.supportsProcesses()) {
1339            return PackageManager.PERMISSION_GRANTED;
1340        }
1341        try {
1342            return ActivityManagerNative.getDefault().checkUriPermission(
1343                    uri, pid, uid, modeFlags);
1344        } catch (RemoteException e) {
1345            return PackageManager.PERMISSION_DENIED;
1346        }
1347    }
1348
1349    @Override
1350    public int checkCallingUriPermission(Uri uri, int modeFlags) {
1351        if (!Process.supportsProcesses()) {
1352            return PackageManager.PERMISSION_GRANTED;
1353        }
1354        int pid = Binder.getCallingPid();
1355        if (pid != Process.myPid()) {
1356            return checkUriPermission(uri, pid,
1357                    Binder.getCallingUid(), modeFlags);
1358        }
1359        return PackageManager.PERMISSION_DENIED;
1360    }
1361
1362    @Override
1363    public int checkCallingOrSelfUriPermission(Uri uri, int modeFlags) {
1364        return checkUriPermission(uri, Binder.getCallingPid(),
1365                Binder.getCallingUid(), modeFlags);
1366    }
1367
1368    @Override
1369    public int checkUriPermission(Uri uri, String readPermission,
1370            String writePermission, int pid, int uid, int modeFlags) {
1371        if (DEBUG) {
1372            Log.i("foo", "checkUriPermission: uri=" + uri + "readPermission="
1373                    + readPermission + " writePermission=" + writePermission
1374                    + " pid=" + pid + " uid=" + uid + " mode" + modeFlags);
1375        }
1376        if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
1377            if (readPermission == null
1378                    || checkPermission(readPermission, pid, uid)
1379                    == PackageManager.PERMISSION_GRANTED) {
1380                return PackageManager.PERMISSION_GRANTED;
1381            }
1382        }
1383        if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
1384            if (writePermission == null
1385                    || checkPermission(writePermission, pid, uid)
1386                    == PackageManager.PERMISSION_GRANTED) {
1387                return PackageManager.PERMISSION_GRANTED;
1388            }
1389        }
1390        return uri != null ? checkUriPermission(uri, pid, uid, modeFlags)
1391                : PackageManager.PERMISSION_DENIED;
1392    }
1393
1394    private String uriModeFlagToString(int uriModeFlags) {
1395        switch (uriModeFlags) {
1396            case Intent.FLAG_GRANT_READ_URI_PERMISSION |
1397                    Intent.FLAG_GRANT_WRITE_URI_PERMISSION:
1398                return "read and write";
1399            case Intent.FLAG_GRANT_READ_URI_PERMISSION:
1400                return "read";
1401            case Intent.FLAG_GRANT_WRITE_URI_PERMISSION:
1402                return "write";
1403        }
1404        throw new IllegalArgumentException(
1405                "Unknown permission mode flags: " + uriModeFlags);
1406    }
1407
1408    private void enforceForUri(
1409            int modeFlags, int resultOfCheck, boolean selfToo,
1410            int uid, Uri uri, String message) {
1411        if (resultOfCheck != PackageManager.PERMISSION_GRANTED) {
1412            throw new SecurityException(
1413                    (message != null ? (message + ": ") : "") +
1414                    (selfToo
1415                     ? "Neither user " + uid + " nor current process has "
1416                     : "User " + uid + " does not have ") +
1417                    uriModeFlagToString(modeFlags) +
1418                    " permission on " +
1419                    uri +
1420                    ".");
1421        }
1422    }
1423
1424    public void enforceUriPermission(
1425            Uri uri, int pid, int uid, int modeFlags, String message) {
1426        enforceForUri(
1427                modeFlags, checkUriPermission(uri, pid, uid, modeFlags),
1428                false, uid, uri, message);
1429    }
1430
1431    public void enforceCallingUriPermission(
1432            Uri uri, int modeFlags, String message) {
1433        enforceForUri(
1434                modeFlags, checkCallingUriPermission(uri, modeFlags),
1435                false, Binder.getCallingUid(), uri, message);
1436    }
1437
1438    public void enforceCallingOrSelfUriPermission(
1439            Uri uri, int modeFlags, String message) {
1440        enforceForUri(
1441                modeFlags,
1442                checkCallingOrSelfUriPermission(uri, modeFlags), true,
1443                Binder.getCallingUid(), uri, message);
1444    }
1445
1446    public void enforceUriPermission(
1447            Uri uri, String readPermission, String writePermission,
1448            int pid, int uid, int modeFlags, String message) {
1449        enforceForUri(modeFlags,
1450                      checkUriPermission(
1451                              uri, readPermission, writePermission, pid, uid,
1452                              modeFlags),
1453                      false,
1454                      uid,
1455                      uri,
1456                      message);
1457    }
1458
1459    @Override
1460    public Context createPackageContext(String packageName, int flags)
1461        throws PackageManager.NameNotFoundException {
1462        if (packageName.equals("system") || packageName.equals("android")) {
1463            return new ContextImpl(mMainThread.getSystemContext());
1464        }
1465
1466        LoadedApk pi =
1467            mMainThread.getPackageInfo(packageName, flags);
1468        if (pi != null) {
1469            ContextImpl c = new ContextImpl();
1470            c.mRestricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
1471            c.init(pi, null, mMainThread, mResources);
1472            if (c.mResources != null) {
1473                return c;
1474            }
1475        }
1476
1477        // Should be a better exception.
1478        throw new PackageManager.NameNotFoundException(
1479            "Application package " + packageName + " not found");
1480    }
1481
1482    @Override
1483    public boolean isRestricted() {
1484        return mRestricted;
1485    }
1486
1487    private File getDataDirFile() {
1488        if (mPackageInfo != null) {
1489            return mPackageInfo.getDataDirFile();
1490        }
1491        throw new RuntimeException("Not supported in system context");
1492    }
1493
1494    @Override
1495    public File getDir(String name, int mode) {
1496        name = "app_" + name;
1497        File file = makeFilename(getDataDirFile(), name);
1498        if (!file.exists()) {
1499            file.mkdir();
1500            setFilePermissionsFromMode(file.getPath(), mode,
1501                    FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH);
1502        }
1503        return file;
1504    }
1505
1506    static ContextImpl createSystemContext(ActivityThread mainThread) {
1507        ContextImpl context = new ContextImpl();
1508        context.init(Resources.getSystem(), mainThread);
1509        return context;
1510    }
1511
1512    ContextImpl() {
1513        mOuterContext = this;
1514    }
1515
1516    /**
1517     * Create a new ApplicationContext from an existing one.  The new one
1518     * works and operates the same as the one it is copying.
1519     *
1520     * @param context Existing application context.
1521     */
1522    public ContextImpl(ContextImpl context) {
1523        mPackageInfo = context.mPackageInfo;
1524        mResources = context.mResources;
1525        mMainThread = context.mMainThread;
1526        mContentResolver = context.mContentResolver;
1527        mOuterContext = this;
1528    }
1529
1530    final void init(LoadedApk packageInfo,
1531            IBinder activityToken, ActivityThread mainThread) {
1532        init(packageInfo, activityToken, mainThread, null);
1533    }
1534
1535    final void init(LoadedApk packageInfo,
1536                IBinder activityToken, ActivityThread mainThread,
1537                Resources container) {
1538        mPackageInfo = packageInfo;
1539        mResources = mPackageInfo.getResources(mainThread);
1540
1541        if (mResources != null && container != null
1542                && container.getCompatibilityInfo().applicationScale !=
1543                        mResources.getCompatibilityInfo().applicationScale) {
1544            if (DEBUG) {
1545                Log.d(TAG, "loaded context has different scaling. Using container's" +
1546                        " compatiblity info:" + container.getDisplayMetrics());
1547            }
1548            mResources = mainThread.getTopLevelResources(
1549                    mPackageInfo.getResDir(), container.getCompatibilityInfo().copy());
1550        }
1551        mMainThread = mainThread;
1552        mContentResolver = new ApplicationContentResolver(this, mainThread);
1553
1554        setActivityToken(activityToken);
1555    }
1556
1557    final void init(Resources resources, ActivityThread mainThread) {
1558        mPackageInfo = null;
1559        mResources = resources;
1560        mMainThread = mainThread;
1561        mContentResolver = new ApplicationContentResolver(this, mainThread);
1562    }
1563
1564    final void scheduleFinalCleanup(String who, String what) {
1565        mMainThread.scheduleContextCleanup(this, who, what);
1566    }
1567
1568    final void performFinalCleanup(String who, String what) {
1569        //Log.i(TAG, "Cleanup up context: " + this);
1570        mPackageInfo.removeContextRegistrations(getOuterContext(), who, what);
1571    }
1572
1573    final Context getReceiverRestrictedContext() {
1574        if (mReceiverRestrictedContext != null) {
1575            return mReceiverRestrictedContext;
1576        }
1577        return mReceiverRestrictedContext = new ReceiverRestrictedContext(getOuterContext());
1578    }
1579
1580    final void setActivityToken(IBinder token) {
1581        mActivityToken = token;
1582    }
1583
1584    final void setOuterContext(Context context) {
1585        mOuterContext = context;
1586    }
1587
1588    final Context getOuterContext() {
1589        return mOuterContext;
1590    }
1591
1592    final IBinder getActivityToken() {
1593        return mActivityToken;
1594    }
1595
1596    private static void setFilePermissionsFromMode(String name, int mode,
1597            int extraPermissions) {
1598        int perms = FileUtils.S_IRUSR|FileUtils.S_IWUSR
1599            |FileUtils.S_IRGRP|FileUtils.S_IWGRP
1600            |extraPermissions;
1601        if ((mode&MODE_WORLD_READABLE) != 0) {
1602            perms |= FileUtils.S_IROTH;
1603        }
1604        if ((mode&MODE_WORLD_WRITEABLE) != 0) {
1605            perms |= FileUtils.S_IWOTH;
1606        }
1607        if (DEBUG) {
1608            Log.i(TAG, "File " + name + ": mode=0x" + Integer.toHexString(mode)
1609                  + ", perms=0x" + Integer.toHexString(perms));
1610        }
1611        FileUtils.setPermissions(name, perms, -1, -1);
1612    }
1613
1614    private File validateFilePath(String name, boolean createDirectory) {
1615        File dir;
1616        File f;
1617
1618        if (name.charAt(0) == File.separatorChar) {
1619            String dirPath = name.substring(0, name.lastIndexOf(File.separatorChar));
1620            dir = new File(dirPath);
1621            name = name.substring(name.lastIndexOf(File.separatorChar));
1622            f = new File(dir, name);
1623        } else {
1624            dir = getDatabasesDir();
1625            f = makeFilename(dir, name);
1626        }
1627
1628        if (createDirectory && !dir.isDirectory() && dir.mkdir()) {
1629            FileUtils.setPermissions(dir.getPath(),
1630                FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
1631                -1, -1);
1632        }
1633
1634        return f;
1635    }
1636
1637    private File makeFilename(File base, String name) {
1638        if (name.indexOf(File.separatorChar) < 0) {
1639            return new File(base, name);
1640        }
1641        throw new IllegalArgumentException(
1642                "File " + name + " contains a path separator");
1643    }
1644
1645    // ----------------------------------------------------------------------
1646    // ----------------------------------------------------------------------
1647    // ----------------------------------------------------------------------
1648
1649    private static final class ApplicationContentResolver extends ContentResolver {
1650        public ApplicationContentResolver(Context context, ActivityThread mainThread) {
1651            super(context);
1652            mMainThread = mainThread;
1653        }
1654
1655        @Override
1656        protected IContentProvider acquireProvider(Context context, String name) {
1657            return mMainThread.acquireProvider(context, name);
1658        }
1659
1660        @Override
1661        protected IContentProvider acquireExistingProvider(Context context, String name) {
1662            return mMainThread.acquireExistingProvider(context, name);
1663        }
1664
1665        @Override
1666        public boolean releaseProvider(IContentProvider provider) {
1667            return mMainThread.releaseProvider(provider);
1668        }
1669
1670        private final ActivityThread mMainThread;
1671    }
1672
1673    // ----------------------------------------------------------------------
1674    // ----------------------------------------------------------------------
1675    // ----------------------------------------------------------------------
1676
1677    /*package*/
1678    static final class ApplicationPackageManager extends PackageManager {
1679        @Override
1680        public PackageInfo getPackageInfo(String packageName, int flags)
1681                throws NameNotFoundException {
1682            try {
1683                PackageInfo pi = mPM.getPackageInfo(packageName, flags);
1684                if (pi != null) {
1685                    return pi;
1686                }
1687            } catch (RemoteException e) {
1688                throw new RuntimeException("Package manager has died", e);
1689            }
1690
1691            throw new NameNotFoundException(packageName);
1692        }
1693
1694        @Override
1695        public String[] currentToCanonicalPackageNames(String[] names) {
1696            try {
1697                return mPM.currentToCanonicalPackageNames(names);
1698            } catch (RemoteException e) {
1699                throw new RuntimeException("Package manager has died", e);
1700            }
1701        }
1702
1703        @Override
1704        public String[] canonicalToCurrentPackageNames(String[] names) {
1705            try {
1706                return mPM.canonicalToCurrentPackageNames(names);
1707            } catch (RemoteException e) {
1708                throw new RuntimeException("Package manager has died", e);
1709            }
1710        }
1711
1712        @Override
1713        public Intent getLaunchIntentForPackage(String packageName) {
1714            // First see if the package has an INFO activity; the existence of
1715            // such an activity is implied to be the desired front-door for the
1716            // overall package (such as if it has multiple launcher entries).
1717            Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
1718            intentToResolve.addCategory(Intent.CATEGORY_INFO);
1719            intentToResolve.setPackage(packageName);
1720            ResolveInfo resolveInfo = resolveActivity(intentToResolve, 0);
1721
1722            // Otherwise, try to find a main launcher activity.
1723            if (resolveInfo == null) {
1724                // reuse the intent instance
1725                intentToResolve.removeCategory(Intent.CATEGORY_INFO);
1726                intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
1727                intentToResolve.setPackage(packageName);
1728                resolveInfo = resolveActivity(intentToResolve, 0);
1729            }
1730            if (resolveInfo == null) {
1731                return null;
1732            }
1733            Intent intent = new Intent(intentToResolve);
1734            intent.setClassName(resolveInfo.activityInfo.applicationInfo.packageName,
1735                                resolveInfo.activityInfo.name);
1736            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1737            return intent;
1738        }
1739
1740        @Override
1741        public int[] getPackageGids(String packageName)
1742            throws NameNotFoundException {
1743            try {
1744                int[] gids = mPM.getPackageGids(packageName);
1745                if (gids == null || gids.length > 0) {
1746                    return gids;
1747                }
1748            } catch (RemoteException e) {
1749                throw new RuntimeException("Package manager has died", e);
1750            }
1751
1752            throw new NameNotFoundException(packageName);
1753        }
1754
1755        @Override
1756        public PermissionInfo getPermissionInfo(String name, int flags)
1757            throws NameNotFoundException {
1758            try {
1759                PermissionInfo pi = mPM.getPermissionInfo(name, flags);
1760                if (pi != null) {
1761                    return pi;
1762                }
1763            } catch (RemoteException e) {
1764                throw new RuntimeException("Package manager has died", e);
1765            }
1766
1767            throw new NameNotFoundException(name);
1768        }
1769
1770        @Override
1771        public List<PermissionInfo> queryPermissionsByGroup(String group, int flags)
1772                throws NameNotFoundException {
1773            try {
1774                List<PermissionInfo> pi = mPM.queryPermissionsByGroup(group, flags);
1775                if (pi != null) {
1776                    return pi;
1777                }
1778            } catch (RemoteException e) {
1779                throw new RuntimeException("Package manager has died", e);
1780            }
1781
1782            throw new NameNotFoundException(group);
1783        }
1784
1785        @Override
1786        public PermissionGroupInfo getPermissionGroupInfo(String name,
1787                int flags) throws NameNotFoundException {
1788            try {
1789                PermissionGroupInfo pgi = mPM.getPermissionGroupInfo(name, flags);
1790                if (pgi != null) {
1791                    return pgi;
1792                }
1793            } catch (RemoteException e) {
1794                throw new RuntimeException("Package manager has died", e);
1795            }
1796
1797            throw new NameNotFoundException(name);
1798        }
1799
1800        @Override
1801        public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
1802            try {
1803                return mPM.getAllPermissionGroups(flags);
1804            } catch (RemoteException e) {
1805                throw new RuntimeException("Package manager has died", e);
1806            }
1807        }
1808
1809        @Override
1810        public ApplicationInfo getApplicationInfo(String packageName, int flags)
1811            throws NameNotFoundException {
1812            try {
1813                ApplicationInfo ai = mPM.getApplicationInfo(packageName, flags);
1814                if (ai != null) {
1815                    return ai;
1816                }
1817            } catch (RemoteException e) {
1818                throw new RuntimeException("Package manager has died", e);
1819            }
1820
1821            throw new NameNotFoundException(packageName);
1822        }
1823
1824        @Override
1825        public ActivityInfo getActivityInfo(ComponentName className, int flags)
1826            throws NameNotFoundException {
1827            try {
1828                ActivityInfo ai = mPM.getActivityInfo(className, flags);
1829                if (ai != null) {
1830                    return ai;
1831                }
1832            } catch (RemoteException e) {
1833                throw new RuntimeException("Package manager has died", e);
1834            }
1835
1836            throw new NameNotFoundException(className.toString());
1837        }
1838
1839        @Override
1840        public ActivityInfo getReceiverInfo(ComponentName className, int flags)
1841            throws NameNotFoundException {
1842            try {
1843                ActivityInfo ai = mPM.getReceiverInfo(className, flags);
1844                if (ai != null) {
1845                    return ai;
1846                }
1847            } catch (RemoteException e) {
1848                throw new RuntimeException("Package manager has died", e);
1849            }
1850
1851            throw new NameNotFoundException(className.toString());
1852        }
1853
1854        @Override
1855        public ServiceInfo getServiceInfo(ComponentName className, int flags)
1856            throws NameNotFoundException {
1857            try {
1858                ServiceInfo si = mPM.getServiceInfo(className, flags);
1859                if (si != null) {
1860                    return si;
1861                }
1862            } catch (RemoteException e) {
1863                throw new RuntimeException("Package manager has died", e);
1864            }
1865
1866            throw new NameNotFoundException(className.toString());
1867        }
1868
1869        @Override
1870        public ProviderInfo getProviderInfo(ComponentName className, int flags)
1871            throws NameNotFoundException {
1872            try {
1873                ProviderInfo pi = mPM.getProviderInfo(className, flags);
1874                if (pi != null) {
1875                    return pi;
1876                }
1877            } catch (RemoteException e) {
1878                throw new RuntimeException("Package manager has died", e);
1879            }
1880
1881            throw new NameNotFoundException(className.toString());
1882        }
1883
1884        @Override
1885        public String[] getSystemSharedLibraryNames() {
1886             try {
1887                 return mPM.getSystemSharedLibraryNames();
1888             } catch (RemoteException e) {
1889                 throw new RuntimeException("Package manager has died", e);
1890             }
1891        }
1892
1893        @Override
1894        public FeatureInfo[] getSystemAvailableFeatures() {
1895            try {
1896                return mPM.getSystemAvailableFeatures();
1897            } catch (RemoteException e) {
1898                throw new RuntimeException("Package manager has died", e);
1899            }
1900        }
1901
1902        @Override
1903        public boolean hasSystemFeature(String name) {
1904            try {
1905                return mPM.hasSystemFeature(name);
1906            } catch (RemoteException e) {
1907                throw new RuntimeException("Package manager has died", e);
1908            }
1909        }
1910
1911        @Override
1912        public int checkPermission(String permName, String pkgName) {
1913            try {
1914                return mPM.checkPermission(permName, pkgName);
1915            } catch (RemoteException e) {
1916                throw new RuntimeException("Package manager has died", e);
1917            }
1918        }
1919
1920        @Override
1921        public boolean addPermission(PermissionInfo info) {
1922            try {
1923                return mPM.addPermission(info);
1924            } catch (RemoteException e) {
1925                throw new RuntimeException("Package manager has died", e);
1926            }
1927        }
1928
1929        @Override
1930        public boolean addPermissionAsync(PermissionInfo info) {
1931            try {
1932                return mPM.addPermissionAsync(info);
1933            } catch (RemoteException e) {
1934                throw new RuntimeException("Package manager has died", e);
1935            }
1936        }
1937
1938        @Override
1939        public void removePermission(String name) {
1940            try {
1941                mPM.removePermission(name);
1942            } catch (RemoteException e) {
1943                throw new RuntimeException("Package manager has died", e);
1944            }
1945        }
1946
1947        @Override
1948        public int checkSignatures(String pkg1, String pkg2) {
1949            try {
1950                return mPM.checkSignatures(pkg1, pkg2);
1951            } catch (RemoteException e) {
1952                throw new RuntimeException("Package manager has died", e);
1953            }
1954        }
1955
1956        @Override
1957        public int checkSignatures(int uid1, int uid2) {
1958            try {
1959                return mPM.checkUidSignatures(uid1, uid2);
1960            } catch (RemoteException e) {
1961                throw new RuntimeException("Package manager has died", e);
1962            }
1963        }
1964
1965        @Override
1966        public String[] getPackagesForUid(int uid) {
1967            try {
1968                return mPM.getPackagesForUid(uid);
1969            } catch (RemoteException e) {
1970                throw new RuntimeException("Package manager has died", e);
1971            }
1972        }
1973
1974        @Override
1975        public String getNameForUid(int uid) {
1976            try {
1977                return mPM.getNameForUid(uid);
1978            } catch (RemoteException e) {
1979                throw new RuntimeException("Package manager has died", e);
1980            }
1981        }
1982
1983        @Override
1984        public int getUidForSharedUser(String sharedUserName)
1985                throws NameNotFoundException {
1986            try {
1987                int uid = mPM.getUidForSharedUser(sharedUserName);
1988                if(uid != -1) {
1989                    return uid;
1990                }
1991            } catch (RemoteException e) {
1992                throw new RuntimeException("Package manager has died", e);
1993            }
1994            throw new NameNotFoundException("No shared userid for user:"+sharedUserName);
1995        }
1996
1997        @Override
1998        public List<PackageInfo> getInstalledPackages(int flags) {
1999            try {
2000                return mPM.getInstalledPackages(flags);
2001            } catch (RemoteException e) {
2002                throw new RuntimeException("Package manager has died", e);
2003            }
2004        }
2005
2006        @Override
2007        public List<ApplicationInfo> getInstalledApplications(int flags) {
2008            try {
2009                return mPM.getInstalledApplications(flags);
2010            } catch (RemoteException e) {
2011                throw new RuntimeException("Package manager has died", e);
2012            }
2013        }
2014
2015        @Override
2016        public ResolveInfo resolveActivity(Intent intent, int flags) {
2017            try {
2018                return mPM.resolveIntent(
2019                    intent,
2020                    intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2021                    flags);
2022            } catch (RemoteException e) {
2023                throw new RuntimeException("Package manager has died", e);
2024            }
2025        }
2026
2027        @Override
2028        public List<ResolveInfo> queryIntentActivities(Intent intent,
2029                int flags) {
2030            try {
2031                return mPM.queryIntentActivities(
2032                    intent,
2033                    intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2034                    flags);
2035            } catch (RemoteException e) {
2036                throw new RuntimeException("Package manager has died", e);
2037            }
2038        }
2039
2040        @Override
2041        public List<ResolveInfo> queryIntentActivityOptions(
2042                ComponentName caller, Intent[] specifics, Intent intent,
2043                int flags) {
2044            final ContentResolver resolver = mContext.getContentResolver();
2045
2046            String[] specificTypes = null;
2047            if (specifics != null) {
2048                final int N = specifics.length;
2049                for (int i=0; i<N; i++) {
2050                    Intent sp = specifics[i];
2051                    if (sp != null) {
2052                        String t = sp.resolveTypeIfNeeded(resolver);
2053                        if (t != null) {
2054                            if (specificTypes == null) {
2055                                specificTypes = new String[N];
2056                            }
2057                            specificTypes[i] = t;
2058                        }
2059                    }
2060                }
2061            }
2062
2063            try {
2064                return mPM.queryIntentActivityOptions(caller, specifics,
2065                    specificTypes, intent, intent.resolveTypeIfNeeded(resolver),
2066                    flags);
2067            } catch (RemoteException e) {
2068                throw new RuntimeException("Package manager has died", e);
2069            }
2070        }
2071
2072        @Override
2073        public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags) {
2074            try {
2075                return mPM.queryIntentReceivers(
2076                    intent,
2077                    intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2078                    flags);
2079            } catch (RemoteException e) {
2080                throw new RuntimeException("Package manager has died", e);
2081            }
2082        }
2083
2084        @Override
2085        public ResolveInfo resolveService(Intent intent, int flags) {
2086            try {
2087                return mPM.resolveService(
2088                    intent,
2089                    intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2090                    flags);
2091            } catch (RemoteException e) {
2092                throw new RuntimeException("Package manager has died", e);
2093            }
2094        }
2095
2096        @Override
2097        public List<ResolveInfo> queryIntentServices(Intent intent, int flags) {
2098            try {
2099                return mPM.queryIntentServices(
2100                    intent,
2101                    intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2102                    flags);
2103            } catch (RemoteException e) {
2104                throw new RuntimeException("Package manager has died", e);
2105            }
2106        }
2107
2108        @Override
2109        public ProviderInfo resolveContentProvider(String name,
2110                int flags) {
2111            try {
2112                return mPM.resolveContentProvider(name, flags);
2113            } catch (RemoteException e) {
2114                throw new RuntimeException("Package manager has died", e);
2115            }
2116        }
2117
2118        @Override
2119        public List<ProviderInfo> queryContentProviders(String processName,
2120                int uid, int flags) {
2121            try {
2122                return mPM.queryContentProviders(processName, uid, flags);
2123            } catch (RemoteException e) {
2124                throw new RuntimeException("Package manager has died", e);
2125            }
2126        }
2127
2128        @Override
2129        public InstrumentationInfo getInstrumentationInfo(
2130                ComponentName className, int flags)
2131                throws NameNotFoundException {
2132            try {
2133                InstrumentationInfo ii = mPM.getInstrumentationInfo(
2134                        className, flags);
2135                if (ii != null) {
2136                    return ii;
2137                }
2138            } catch (RemoteException e) {
2139                throw new RuntimeException("Package manager has died", e);
2140            }
2141
2142            throw new NameNotFoundException(className.toString());
2143        }
2144
2145        @Override
2146        public List<InstrumentationInfo> queryInstrumentation(
2147                String targetPackage, int flags) {
2148            try {
2149                return mPM.queryInstrumentation(targetPackage, flags);
2150            } catch (RemoteException e) {
2151                throw new RuntimeException("Package manager has died", e);
2152            }
2153        }
2154
2155        @Override public Drawable getDrawable(String packageName, int resid,
2156                ApplicationInfo appInfo) {
2157            ResourceName name = new ResourceName(packageName, resid);
2158            Drawable dr = getCachedIcon(name);
2159            if (dr != null) {
2160                return dr;
2161            }
2162            if (appInfo == null) {
2163                try {
2164                    appInfo = getApplicationInfo(packageName, 0);
2165                } catch (NameNotFoundException e) {
2166                    return null;
2167                }
2168            }
2169            try {
2170                Resources r = getResourcesForApplication(appInfo);
2171                dr = r.getDrawable(resid);
2172                if (false) {
2173                    RuntimeException e = new RuntimeException("here");
2174                    e.fillInStackTrace();
2175                    Log.w(TAG, "Getting drawable 0x" + Integer.toHexString(resid)
2176                            + " from package " + packageName
2177                            + ": app scale=" + r.getCompatibilityInfo().applicationScale
2178                            + ", caller scale=" + mContext.getResources().getCompatibilityInfo().applicationScale,
2179                            e);
2180                }
2181                if (DEBUG_ICONS) Log.v(TAG, "Getting drawable 0x"
2182                        + Integer.toHexString(resid) + " from " + r
2183                        + ": " + dr);
2184                putCachedIcon(name, dr);
2185                return dr;
2186            } catch (NameNotFoundException e) {
2187                Log.w("PackageManager", "Failure retrieving resources for"
2188                        + appInfo.packageName);
2189            } catch (RuntimeException e) {
2190                // If an exception was thrown, fall through to return
2191                // default icon.
2192                Log.w("PackageManager", "Failure retrieving icon 0x"
2193                        + Integer.toHexString(resid) + " in package "
2194                        + packageName, e);
2195            }
2196            return null;
2197        }
2198
2199        @Override public Drawable getActivityIcon(ComponentName activityName)
2200                throws NameNotFoundException {
2201            return getActivityInfo(activityName, 0).loadIcon(this);
2202        }
2203
2204        @Override public Drawable getActivityIcon(Intent intent)
2205                throws NameNotFoundException {
2206            if (intent.getComponent() != null) {
2207                return getActivityIcon(intent.getComponent());
2208            }
2209
2210            ResolveInfo info = resolveActivity(
2211                intent, PackageManager.MATCH_DEFAULT_ONLY);
2212            if (info != null) {
2213                return info.activityInfo.loadIcon(this);
2214            }
2215
2216            throw new NameNotFoundException(intent.toURI());
2217        }
2218
2219        @Override public Drawable getDefaultActivityIcon() {
2220            return Resources.getSystem().getDrawable(
2221                com.android.internal.R.drawable.sym_def_app_icon);
2222        }
2223
2224        @Override public Drawable getApplicationIcon(ApplicationInfo info) {
2225            return info.loadIcon(this);
2226        }
2227
2228        @Override public Drawable getApplicationIcon(String packageName)
2229                throws NameNotFoundException {
2230            return getApplicationIcon(getApplicationInfo(packageName, 0));
2231        }
2232
2233        @Override
2234        public Drawable getActivityLogo(ComponentName activityName)
2235                throws NameNotFoundException {
2236            return getActivityInfo(activityName, 0).loadLogo(this);
2237        }
2238
2239        @Override
2240        public Drawable getActivityLogo(Intent intent)
2241                throws NameNotFoundException {
2242            if (intent.getComponent() != null) {
2243                return getActivityLogo(intent.getComponent());
2244            }
2245
2246            ResolveInfo info = resolveActivity(
2247                    intent, PackageManager.MATCH_DEFAULT_ONLY);
2248            if (info != null) {
2249                return info.activityInfo.loadLogo(this);
2250            }
2251
2252            throw new NameNotFoundException(intent.toUri(0));
2253        }
2254
2255        @Override
2256        public Drawable getApplicationLogo(ApplicationInfo info) {
2257            return info.loadLogo(this);
2258        }
2259
2260        @Override
2261        public Drawable getApplicationLogo(String packageName)
2262                throws NameNotFoundException {
2263            return getApplicationLogo(getApplicationInfo(packageName, 0));
2264        }
2265
2266        @Override public Resources getResourcesForActivity(
2267                ComponentName activityName) throws NameNotFoundException {
2268            return getResourcesForApplication(
2269                getActivityInfo(activityName, 0).applicationInfo);
2270        }
2271
2272        @Override public Resources getResourcesForApplication(
2273                ApplicationInfo app) throws NameNotFoundException {
2274            if (app.packageName.equals("system")) {
2275                return mContext.mMainThread.getSystemContext().getResources();
2276            }
2277            Resources r = mContext.mMainThread.getTopLevelResources(
2278                    app.uid == Process.myUid() ? app.sourceDir
2279                    : app.publicSourceDir, mContext.mPackageInfo);
2280            if (r != null) {
2281                return r;
2282            }
2283            throw new NameNotFoundException("Unable to open " + app.publicSourceDir);
2284        }
2285
2286        @Override public Resources getResourcesForApplication(
2287                String appPackageName) throws NameNotFoundException {
2288            return getResourcesForApplication(
2289                getApplicationInfo(appPackageName, 0));
2290        }
2291
2292        int mCachedSafeMode = -1;
2293        @Override public boolean isSafeMode() {
2294            try {
2295                if (mCachedSafeMode < 0) {
2296                    mCachedSafeMode = mPM.isSafeMode() ? 1 : 0;
2297                }
2298                return mCachedSafeMode != 0;
2299            } catch (RemoteException e) {
2300                throw new RuntimeException("Package manager has died", e);
2301            }
2302        }
2303
2304        static void configurationChanged() {
2305            synchronized (sSync) {
2306                sIconCache.clear();
2307                sStringCache.clear();
2308            }
2309        }
2310
2311        ApplicationPackageManager(ContextImpl context,
2312                IPackageManager pm) {
2313            mContext = context;
2314            mPM = pm;
2315        }
2316
2317        private Drawable getCachedIcon(ResourceName name) {
2318            synchronized (sSync) {
2319                WeakReference<Drawable> wr = sIconCache.get(name);
2320                if (DEBUG_ICONS) Log.v(TAG, "Get cached weak drawable ref for "
2321                        + name + ": " + wr);
2322                if (wr != null) {   // we have the activity
2323                    Drawable dr = wr.get();
2324                    if (dr != null) {
2325                        if (DEBUG_ICONS) Log.v(TAG, "Get cached drawable for "
2326                                + name + ": " + dr);
2327                        return dr;
2328                    }
2329                    // our entry has been purged
2330                    sIconCache.remove(name);
2331                }
2332            }
2333            return null;
2334        }
2335
2336        private void putCachedIcon(ResourceName name, Drawable dr) {
2337            synchronized (sSync) {
2338                sIconCache.put(name, new WeakReference<Drawable>(dr));
2339                if (DEBUG_ICONS) Log.v(TAG, "Added cached drawable for "
2340                        + name + ": " + dr);
2341            }
2342        }
2343
2344        static final void handlePackageBroadcast(int cmd, String[] pkgList,
2345                boolean hasPkgInfo) {
2346            boolean immediateGc = false;
2347            if (cmd == IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE) {
2348                immediateGc = true;
2349            }
2350            if (pkgList != null && (pkgList.length > 0)) {
2351                boolean needCleanup = false;
2352                for (String ssp : pkgList) {
2353                    synchronized (sSync) {
2354                        if (sIconCache.size() > 0) {
2355                            Iterator<ResourceName> it = sIconCache.keySet().iterator();
2356                            while (it.hasNext()) {
2357                                ResourceName nm = it.next();
2358                                if (nm.packageName.equals(ssp)) {
2359                                    //Log.i(TAG, "Removing cached drawable for " + nm);
2360                                    it.remove();
2361                                    needCleanup = true;
2362                                }
2363                            }
2364                        }
2365                        if (sStringCache.size() > 0) {
2366                            Iterator<ResourceName> it = sStringCache.keySet().iterator();
2367                            while (it.hasNext()) {
2368                                ResourceName nm = it.next();
2369                                if (nm.packageName.equals(ssp)) {
2370                                    //Log.i(TAG, "Removing cached string for " + nm);
2371                                    it.remove();
2372                                    needCleanup = true;
2373                                }
2374                            }
2375                        }
2376                    }
2377                }
2378                if (needCleanup || hasPkgInfo) {
2379                    if (immediateGc) {
2380                        // Schedule an immediate gc.
2381                        Runtime.getRuntime().gc();
2382                    } else {
2383                        ActivityThread.currentActivityThread().scheduleGcIdler();
2384                    }
2385                }
2386            }
2387        }
2388
2389        private static final class ResourceName {
2390            final String packageName;
2391            final int iconId;
2392
2393            ResourceName(String _packageName, int _iconId) {
2394                packageName = _packageName;
2395                iconId = _iconId;
2396            }
2397
2398            ResourceName(ApplicationInfo aInfo, int _iconId) {
2399                this(aInfo.packageName, _iconId);
2400            }
2401
2402            ResourceName(ComponentInfo cInfo, int _iconId) {
2403                this(cInfo.applicationInfo.packageName, _iconId);
2404            }
2405
2406            ResourceName(ResolveInfo rInfo, int _iconId) {
2407                this(rInfo.activityInfo.applicationInfo.packageName, _iconId);
2408            }
2409
2410            @Override
2411            public boolean equals(Object o) {
2412                if (this == o) return true;
2413                if (o == null || getClass() != o.getClass()) return false;
2414
2415                ResourceName that = (ResourceName) o;
2416
2417                if (iconId != that.iconId) return false;
2418                return !(packageName != null ?
2419                        !packageName.equals(that.packageName) : that.packageName != null);
2420
2421            }
2422
2423            @Override
2424            public int hashCode() {
2425                int result;
2426                result = packageName.hashCode();
2427                result = 31 * result + iconId;
2428                return result;
2429            }
2430
2431            @Override
2432            public String toString() {
2433                return "{ResourceName " + packageName + " / " + iconId + "}";
2434            }
2435        }
2436
2437        private CharSequence getCachedString(ResourceName name) {
2438            synchronized (sSync) {
2439                WeakReference<CharSequence> wr = sStringCache.get(name);
2440                if (wr != null) {   // we have the activity
2441                    CharSequence cs = wr.get();
2442                    if (cs != null) {
2443                        return cs;
2444                    }
2445                    // our entry has been purged
2446                    sStringCache.remove(name);
2447                }
2448            }
2449            return null;
2450        }
2451
2452        private void putCachedString(ResourceName name, CharSequence cs) {
2453            synchronized (sSync) {
2454                sStringCache.put(name, new WeakReference<CharSequence>(cs));
2455            }
2456        }
2457
2458        @Override
2459        public CharSequence getText(String packageName, int resid,
2460                ApplicationInfo appInfo) {
2461            ResourceName name = new ResourceName(packageName, resid);
2462            CharSequence text = getCachedString(name);
2463            if (text != null) {
2464                return text;
2465            }
2466            if (appInfo == null) {
2467                try {
2468                    appInfo = getApplicationInfo(packageName, 0);
2469                } catch (NameNotFoundException e) {
2470                    return null;
2471                }
2472            }
2473            try {
2474                Resources r = getResourcesForApplication(appInfo);
2475                text = r.getText(resid);
2476                putCachedString(name, text);
2477                return text;
2478            } catch (NameNotFoundException e) {
2479                Log.w("PackageManager", "Failure retrieving resources for"
2480                        + appInfo.packageName);
2481            } catch (RuntimeException e) {
2482                // If an exception was thrown, fall through to return
2483                // default icon.
2484                Log.w("PackageManager", "Failure retrieving text 0x"
2485                        + Integer.toHexString(resid) + " in package "
2486                        + packageName, e);
2487            }
2488            return null;
2489        }
2490
2491        @Override
2492        public XmlResourceParser getXml(String packageName, int resid,
2493                ApplicationInfo appInfo) {
2494            if (appInfo == null) {
2495                try {
2496                    appInfo = getApplicationInfo(packageName, 0);
2497                } catch (NameNotFoundException e) {
2498                    return null;
2499                }
2500            }
2501            try {
2502                Resources r = getResourcesForApplication(appInfo);
2503                return r.getXml(resid);
2504            } catch (RuntimeException e) {
2505                // If an exception was thrown, fall through to return
2506                // default icon.
2507                Log.w("PackageManager", "Failure retrieving xml 0x"
2508                        + Integer.toHexString(resid) + " in package "
2509                        + packageName, e);
2510            } catch (NameNotFoundException e) {
2511                Log.w("PackageManager", "Failure retrieving resources for"
2512                        + appInfo.packageName);
2513            }
2514            return null;
2515        }
2516
2517        @Override
2518        public CharSequence getApplicationLabel(ApplicationInfo info) {
2519            return info.loadLabel(this);
2520        }
2521
2522        @Override
2523        public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
2524                String installerPackageName) {
2525            try {
2526                mPM.installPackage(packageURI, observer, flags, installerPackageName);
2527            } catch (RemoteException e) {
2528                // Should never happen!
2529            }
2530        }
2531
2532        @Override
2533        public void movePackage(String packageName, IPackageMoveObserver observer, int flags) {
2534            try {
2535                mPM.movePackage(packageName, observer, flags);
2536            } catch (RemoteException e) {
2537                // Should never happen!
2538            }
2539        }
2540
2541        @Override
2542        public String getInstallerPackageName(String packageName) {
2543            try {
2544                return mPM.getInstallerPackageName(packageName);
2545            } catch (RemoteException e) {
2546                // Should never happen!
2547            }
2548            return null;
2549        }
2550
2551        @Override
2552        public void deletePackage(String packageName, IPackageDeleteObserver observer, int flags) {
2553            try {
2554                mPM.deletePackage(packageName, observer, flags);
2555            } catch (RemoteException e) {
2556                // Should never happen!
2557            }
2558        }
2559        @Override
2560        public void clearApplicationUserData(String packageName,
2561                IPackageDataObserver observer) {
2562            try {
2563                mPM.clearApplicationUserData(packageName, observer);
2564            } catch (RemoteException e) {
2565                // Should never happen!
2566            }
2567        }
2568        @Override
2569        public void deleteApplicationCacheFiles(String packageName,
2570                IPackageDataObserver observer) {
2571            try {
2572                mPM.deleteApplicationCacheFiles(packageName, observer);
2573            } catch (RemoteException e) {
2574                // Should never happen!
2575            }
2576        }
2577        @Override
2578        public void freeStorageAndNotify(long idealStorageSize, IPackageDataObserver observer) {
2579            try {
2580                mPM.freeStorageAndNotify(idealStorageSize, observer);
2581            } catch (RemoteException e) {
2582                // Should never happen!
2583            }
2584        }
2585
2586        @Override
2587        public void freeStorage(long freeStorageSize, IntentSender pi) {
2588            try {
2589                mPM.freeStorage(freeStorageSize, pi);
2590            } catch (RemoteException e) {
2591                // Should never happen!
2592            }
2593        }
2594
2595        @Override
2596        public void getPackageSizeInfo(String packageName,
2597                IPackageStatsObserver observer) {
2598            try {
2599                mPM.getPackageSizeInfo(packageName, observer);
2600            } catch (RemoteException e) {
2601                // Should never happen!
2602            }
2603        }
2604        @Override
2605        public void addPackageToPreferred(String packageName) {
2606            try {
2607                mPM.addPackageToPreferred(packageName);
2608            } catch (RemoteException e) {
2609                // Should never happen!
2610            }
2611        }
2612
2613        @Override
2614        public void removePackageFromPreferred(String packageName) {
2615            try {
2616                mPM.removePackageFromPreferred(packageName);
2617            } catch (RemoteException e) {
2618                // Should never happen!
2619            }
2620        }
2621
2622        @Override
2623        public List<PackageInfo> getPreferredPackages(int flags) {
2624            try {
2625                return mPM.getPreferredPackages(flags);
2626            } catch (RemoteException e) {
2627                // Should never happen!
2628            }
2629            return new ArrayList<PackageInfo>();
2630        }
2631
2632        @Override
2633        public void addPreferredActivity(IntentFilter filter,
2634                int match, ComponentName[] set, ComponentName activity) {
2635            try {
2636                mPM.addPreferredActivity(filter, match, set, activity);
2637            } catch (RemoteException e) {
2638                // Should never happen!
2639            }
2640        }
2641
2642        @Override
2643        public void replacePreferredActivity(IntentFilter filter,
2644                int match, ComponentName[] set, ComponentName activity) {
2645            try {
2646                mPM.replacePreferredActivity(filter, match, set, activity);
2647            } catch (RemoteException e) {
2648                // Should never happen!
2649            }
2650        }
2651
2652        @Override
2653        public void clearPackagePreferredActivities(String packageName) {
2654            try {
2655                mPM.clearPackagePreferredActivities(packageName);
2656            } catch (RemoteException e) {
2657                // Should never happen!
2658            }
2659        }
2660
2661        @Override
2662        public int getPreferredActivities(List<IntentFilter> outFilters,
2663                List<ComponentName> outActivities, String packageName) {
2664            try {
2665                return mPM.getPreferredActivities(outFilters, outActivities, packageName);
2666            } catch (RemoteException e) {
2667                // Should never happen!
2668            }
2669            return 0;
2670        }
2671
2672        @Override
2673        public void setComponentEnabledSetting(ComponentName componentName,
2674                int newState, int flags) {
2675            try {
2676                mPM.setComponentEnabledSetting(componentName, newState, flags);
2677            } catch (RemoteException e) {
2678                // Should never happen!
2679            }
2680        }
2681
2682        @Override
2683        public int getComponentEnabledSetting(ComponentName componentName) {
2684            try {
2685                return mPM.getComponentEnabledSetting(componentName);
2686            } catch (RemoteException e) {
2687                // Should never happen!
2688            }
2689            return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
2690        }
2691
2692        @Override
2693        public void setApplicationEnabledSetting(String packageName,
2694                int newState, int flags) {
2695            try {
2696                mPM.setApplicationEnabledSetting(packageName, newState, flags);
2697            } catch (RemoteException e) {
2698                // Should never happen!
2699            }
2700        }
2701
2702        @Override
2703        public int getApplicationEnabledSetting(String packageName) {
2704            try {
2705                return mPM.getApplicationEnabledSetting(packageName);
2706            } catch (RemoteException e) {
2707                // Should never happen!
2708            }
2709            return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
2710        }
2711
2712        @Override
2713        public void setPackageObbPath(String packageName, String path) {
2714            try {
2715                mPM.setPackageObbPath(packageName, path);
2716            } catch (RemoteException e) {
2717                // Should never happen!
2718            }
2719        }
2720
2721        private final ContextImpl mContext;
2722        private final IPackageManager mPM;
2723
2724        private static final Object sSync = new Object();
2725        private static HashMap<ResourceName, WeakReference<Drawable> > sIconCache
2726                = new HashMap<ResourceName, WeakReference<Drawable> >();
2727        private static HashMap<ResourceName, WeakReference<CharSequence> > sStringCache
2728                = new HashMap<ResourceName, WeakReference<CharSequence> >();
2729    }
2730
2731    // ----------------------------------------------------------------------
2732    // ----------------------------------------------------------------------
2733    // ----------------------------------------------------------------------
2734
2735    private static final class SharedPreferencesImpl implements SharedPreferences {
2736
2737        // Lock ordering rules:
2738        //  - acquire SharedPreferencesImpl.this before EditorImpl.this
2739        //  - acquire mWritingToDiskLock before EditorImpl.this
2740
2741        private final File mFile;
2742        private final File mBackupFile;
2743        private final int mMode;
2744
2745        private Map<String, Object> mMap;     // guarded by 'this'
2746        private int mDiskWritesInFlight = 0;  // guarded by 'this'
2747        private boolean mLoaded = false;      // guarded by 'this'
2748        private long mStatTimestamp;          // guarded by 'this'
2749        private long mStatSize;               // guarded by 'this'
2750
2751        private final Object mWritingToDiskLock = new Object();
2752        private static final Object mContent = new Object();
2753        private final WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners;
2754
2755        SharedPreferencesImpl(
2756            File file, int mode, Map initialContents) {
2757            mFile = file;
2758            mBackupFile = makeBackupFile(file);
2759            mMode = mode;
2760            mLoaded = initialContents != null;
2761            mMap = initialContents != null ? initialContents : new HashMap<String, Object>();
2762            FileStatus stat = new FileStatus();
2763            if (FileUtils.getFileStatus(file.getPath(), stat)) {
2764                mStatTimestamp = stat.mtime;
2765            }
2766            mListeners = new WeakHashMap<OnSharedPreferenceChangeListener, Object>();
2767        }
2768
2769        // Has this SharedPreferences ever had values assigned to it?
2770        boolean isLoaded() {
2771            synchronized (this) {
2772                return mLoaded;
2773            }
2774        }
2775
2776        // Has the file changed out from under us?  i.e. writes that
2777        // we didn't instigate.
2778        public boolean hasFileChangedUnexpectedly() {
2779            synchronized (this) {
2780                if (mDiskWritesInFlight > 0) {
2781                    // If we know we caused it, it's not unexpected.
2782                    if (DEBUG) Log.d(TAG, "disk write in flight, not unexpected.");
2783                    return false;
2784                }
2785            }
2786            FileStatus stat = new FileStatus();
2787            if (!FileUtils.getFileStatus(mFile.getPath(), stat)) {
2788                return true;
2789            }
2790            synchronized (this) {
2791                return mStatTimestamp != stat.mtime || mStatSize != stat.size;
2792            }
2793        }
2794
2795        public void replace(Map newContents) {
2796            synchronized (this) {
2797                mLoaded = true;
2798                if (newContents != null) {
2799                    mMap = newContents;
2800                }
2801            }
2802        }
2803
2804        public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
2805            synchronized(this) {
2806                mListeners.put(listener, mContent);
2807            }
2808        }
2809
2810        public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
2811            synchronized(this) {
2812                mListeners.remove(listener);
2813            }
2814        }
2815
2816        public Map<String, ?> getAll() {
2817            synchronized(this) {
2818                //noinspection unchecked
2819                return new HashMap<String, Object>(mMap);
2820            }
2821        }
2822
2823        public String getString(String key, String defValue) {
2824            synchronized (this) {
2825                String v = (String)mMap.get(key);
2826                return v != null ? v : defValue;
2827            }
2828        }
2829
2830        public Set<String> getStringSet(String key, Set<String> defValues) {
2831            synchronized (this) {
2832                Set<String> v = (Set<String>) mMap.get(key);
2833                return v != null ? v : defValues;
2834            }
2835        }
2836
2837        public int getInt(String key, int defValue) {
2838            synchronized (this) {
2839                Integer v = (Integer)mMap.get(key);
2840                return v != null ? v : defValue;
2841            }
2842        }
2843        public long getLong(String key, long defValue) {
2844            synchronized (this) {
2845                Long v = (Long)mMap.get(key);
2846                return v != null ? v : defValue;
2847            }
2848        }
2849        public float getFloat(String key, float defValue) {
2850            synchronized (this) {
2851                Float v = (Float)mMap.get(key);
2852                return v != null ? v : defValue;
2853            }
2854        }
2855        public boolean getBoolean(String key, boolean defValue) {
2856            synchronized (this) {
2857                Boolean v = (Boolean)mMap.get(key);
2858                return v != null ? v : defValue;
2859            }
2860        }
2861
2862        public boolean contains(String key) {
2863            synchronized (this) {
2864                return mMap.containsKey(key);
2865            }
2866        }
2867
2868        public Editor edit() {
2869            return new EditorImpl();
2870        }
2871
2872        // Return value from EditorImpl#commitToMemory()
2873        private static class MemoryCommitResult {
2874            public boolean changesMade;  // any keys different?
2875            public List<String> keysModified;  // may be null
2876            public Set<OnSharedPreferenceChangeListener> listeners;  // may be null
2877            public Map<?, ?> mapToWriteToDisk;
2878            public final CountDownLatch writtenToDiskLatch = new CountDownLatch(1);
2879            public volatile boolean writeToDiskResult = false;
2880
2881            public void setDiskWriteResult(boolean result) {
2882                writeToDiskResult = result;
2883                writtenToDiskLatch.countDown();
2884            }
2885        }
2886
2887        public final class EditorImpl implements Editor {
2888            private final Map<String, Object> mModified = Maps.newHashMap();
2889            private boolean mClear = false;
2890
2891            public Editor putString(String key, String value) {
2892                synchronized (this) {
2893                    mModified.put(key, value);
2894                    return this;
2895                }
2896            }
2897            public Editor putStringSet(String key, Set<String> values) {
2898                synchronized (this) {
2899                    mModified.put(key, values);
2900                    return this;
2901                }
2902            }
2903            public Editor putInt(String key, int value) {
2904                synchronized (this) {
2905                    mModified.put(key, value);
2906                    return this;
2907                }
2908            }
2909            public Editor putLong(String key, long value) {
2910                synchronized (this) {
2911                    mModified.put(key, value);
2912                    return this;
2913                }
2914            }
2915            public Editor putFloat(String key, float value) {
2916                synchronized (this) {
2917                    mModified.put(key, value);
2918                    return this;
2919                }
2920            }
2921            public Editor putBoolean(String key, boolean value) {
2922                synchronized (this) {
2923                    mModified.put(key, value);
2924                    return this;
2925                }
2926            }
2927
2928            public Editor remove(String key) {
2929                synchronized (this) {
2930                    mModified.put(key, this);
2931                    return this;
2932                }
2933            }
2934
2935            public Editor clear() {
2936                synchronized (this) {
2937                    mClear = true;
2938                    return this;
2939                }
2940            }
2941
2942            public void apply() {
2943                final MemoryCommitResult mcr = commitToMemory();
2944                final Runnable awaitCommit = new Runnable() {
2945                        public void run() {
2946                            try {
2947                                mcr.writtenToDiskLatch.await();
2948                            } catch (InterruptedException ignored) {
2949                            }
2950                        }
2951                    };
2952
2953                QueuedWork.add(awaitCommit);
2954
2955                Runnable postWriteRunnable = new Runnable() {
2956                        public void run() {
2957                            awaitCommit.run();
2958                            QueuedWork.remove(awaitCommit);
2959                        }
2960                    };
2961
2962                SharedPreferencesImpl.this.enqueueDiskWrite(mcr, postWriteRunnable);
2963
2964                // Okay to notify the listeners before it's hit disk
2965                // because the listeners should always get the same
2966                // SharedPreferences instance back, which has the
2967                // changes reflected in memory.
2968                notifyListeners(mcr);
2969            }
2970
2971            // Returns true if any changes were made
2972            private MemoryCommitResult commitToMemory() {
2973                MemoryCommitResult mcr = new MemoryCommitResult();
2974                synchronized (SharedPreferencesImpl.this) {
2975                    // We optimistically don't make a deep copy until
2976                    // a memory commit comes in when we're already
2977                    // writing to disk.
2978                    if (mDiskWritesInFlight > 0) {
2979                        // We can't modify our mMap as a currently
2980                        // in-flight write owns it.  Clone it before
2981                        // modifying it.
2982                        // noinspection unchecked
2983                        mMap = new HashMap<String, Object>(mMap);
2984                    }
2985                    mcr.mapToWriteToDisk = mMap;
2986                    mDiskWritesInFlight++;
2987
2988                    boolean hasListeners = mListeners.size() > 0;
2989                    if (hasListeners) {
2990                        mcr.keysModified = new ArrayList<String>();
2991                        mcr.listeners =
2992                            new HashSet<OnSharedPreferenceChangeListener>(mListeners.keySet());
2993                    }
2994
2995                    synchronized (this) {
2996                        if (mClear) {
2997                            if (!mMap.isEmpty()) {
2998                                mcr.changesMade = true;
2999                                mMap.clear();
3000                            }
3001                            mClear = false;
3002                        }
3003
3004                        for (Entry<String, Object> e : mModified.entrySet()) {
3005                            String k = e.getKey();
3006                            Object v = e.getValue();
3007                            if (v == this) {  // magic value for a removal mutation
3008                                if (!mMap.containsKey(k)) {
3009                                    continue;
3010                                }
3011                                mMap.remove(k);
3012                            } else {
3013                                boolean isSame = false;
3014                                if (mMap.containsKey(k)) {
3015                                    Object existingValue = mMap.get(k);
3016                                    if (existingValue != null && existingValue.equals(v)) {
3017                                        continue;
3018                                    }
3019                                }
3020                                mMap.put(k, v);
3021                            }
3022
3023                            mcr.changesMade = true;
3024                            if (hasListeners) {
3025                                mcr.keysModified.add(k);
3026                            }
3027                        }
3028
3029                        mModified.clear();
3030                    }
3031                }
3032                return mcr;
3033            }
3034
3035            public boolean commit() {
3036                MemoryCommitResult mcr = commitToMemory();
3037                SharedPreferencesImpl.this.enqueueDiskWrite(
3038                    mcr, null /* sync write on this thread okay */);
3039                try {
3040                    mcr.writtenToDiskLatch.await();
3041                } catch (InterruptedException e) {
3042                    return false;
3043                }
3044                notifyListeners(mcr);
3045                return mcr.writeToDiskResult;
3046            }
3047
3048            private void notifyListeners(final MemoryCommitResult mcr) {
3049                if (mcr.listeners == null || mcr.keysModified == null ||
3050                    mcr.keysModified.size() == 0) {
3051                    return;
3052                }
3053                if (Looper.myLooper() == Looper.getMainLooper()) {
3054                    for (int i = mcr.keysModified.size() - 1; i >= 0; i--) {
3055                        final String key = mcr.keysModified.get(i);
3056                        for (OnSharedPreferenceChangeListener listener : mcr.listeners) {
3057                            if (listener != null) {
3058                                listener.onSharedPreferenceChanged(SharedPreferencesImpl.this, key);
3059                            }
3060                        }
3061                    }
3062                } else {
3063                    // Run this function on the main thread.
3064                    ActivityThread.sMainThreadHandler.post(new Runnable() {
3065                            public void run() {
3066                                notifyListeners(mcr);
3067                            }
3068                        });
3069                }
3070            }
3071        }
3072
3073        /**
3074         * Enqueue an already-committed-to-memory result to be written
3075         * to disk.
3076         *
3077         * They will be written to disk one-at-a-time in the order
3078         * that they're enqueued.
3079         *
3080         * @param postWriteRunnable if non-null, we're being called
3081         *   from apply() and this is the runnable to run after
3082         *   the write proceeds.  if null (from a regular commit()),
3083         *   then we're allowed to do this disk write on the main
3084         *   thread (which in addition to reducing allocations and
3085         *   creating a background thread, this has the advantage that
3086         *   we catch them in userdebug StrictMode reports to convert
3087         *   them where possible to apply() ...)
3088         */
3089        private void enqueueDiskWrite(final MemoryCommitResult mcr,
3090                                      final Runnable postWriteRunnable) {
3091            final Runnable writeToDiskRunnable = new Runnable() {
3092                    public void run() {
3093                        synchronized (mWritingToDiskLock) {
3094                            writeToFile(mcr);
3095                        }
3096                        synchronized (SharedPreferencesImpl.this) {
3097                            mDiskWritesInFlight--;
3098                        }
3099                        if (postWriteRunnable != null) {
3100                            postWriteRunnable.run();
3101                        }
3102                    }
3103                };
3104
3105            final boolean isFromSyncCommit = (postWriteRunnable == null);
3106
3107            // Typical #commit() path with fewer allocations, doing a write on
3108            // the current thread.
3109            if (isFromSyncCommit) {
3110                boolean wasEmpty = false;
3111                synchronized (SharedPreferencesImpl.this) {
3112                    wasEmpty = mDiskWritesInFlight == 1;
3113                }
3114                if (wasEmpty) {
3115                    writeToDiskRunnable.run();
3116                    return;
3117                }
3118            }
3119
3120            QueuedWork.singleThreadExecutor().execute(writeToDiskRunnable);
3121        }
3122
3123        private static FileOutputStream createFileOutputStream(File file) {
3124            FileOutputStream str = null;
3125            try {
3126                str = new FileOutputStream(file);
3127            } catch (FileNotFoundException e) {
3128                File parent = file.getParentFile();
3129                if (!parent.mkdir()) {
3130                    Log.e(TAG, "Couldn't create directory for SharedPreferences file " + file);
3131                    return null;
3132                }
3133                FileUtils.setPermissions(
3134                    parent.getPath(),
3135                    FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
3136                    -1, -1);
3137                try {
3138                    str = new FileOutputStream(file);
3139                } catch (FileNotFoundException e2) {
3140                    Log.e(TAG, "Couldn't create SharedPreferences file " + file, e2);
3141                }
3142            }
3143            return str;
3144        }
3145
3146        // Note: must hold mWritingToDiskLock
3147        private void writeToFile(MemoryCommitResult mcr) {
3148            // Rename the current file so it may be used as a backup during the next read
3149            if (mFile.exists()) {
3150                if (!mcr.changesMade) {
3151                    // If the file already exists, but no changes were
3152                    // made to the underlying map, it's wasteful to
3153                    // re-write the file.  Return as if we wrote it
3154                    // out.
3155                    mcr.setDiskWriteResult(true);
3156                    return;
3157                }
3158                if (!mBackupFile.exists()) {
3159                    if (!mFile.renameTo(mBackupFile)) {
3160                        Log.e(TAG, "Couldn't rename file " + mFile
3161                                + " to backup file " + mBackupFile);
3162                        mcr.setDiskWriteResult(false);
3163                        return;
3164                    }
3165                } else {
3166                    mFile.delete();
3167                }
3168            }
3169
3170            // Attempt to write the file, delete the backup and return true as atomically as
3171            // possible.  If any exception occurs, delete the new file; next time we will restore
3172            // from the backup.
3173            try {
3174                FileOutputStream str = createFileOutputStream(mFile);
3175                if (str == null) {
3176                    mcr.setDiskWriteResult(false);
3177                    return;
3178                }
3179                XmlUtils.writeMapXml(mcr.mapToWriteToDisk, str);
3180                FileUtils.sync(str);
3181                str.close();
3182                setFilePermissionsFromMode(mFile.getPath(), mMode, 0);
3183                FileStatus stat = new FileStatus();
3184                if (FileUtils.getFileStatus(mFile.getPath(), stat)) {
3185                    synchronized (this) {
3186                        mStatTimestamp = stat.mtime;
3187                        mStatSize = stat.size;
3188                    }
3189                }
3190                // Writing was successful, delete the backup file if there is one.
3191                mBackupFile.delete();
3192                mcr.setDiskWriteResult(true);
3193                return;
3194            } catch (XmlPullParserException e) {
3195                Log.w(TAG, "writeToFile: Got exception:", e);
3196            } catch (IOException e) {
3197                Log.w(TAG, "writeToFile: Got exception:", e);
3198            }
3199            // Clean up an unsuccessfully written file
3200            if (mFile.exists()) {
3201                if (!mFile.delete()) {
3202                    Log.e(TAG, "Couldn't clean up partially-written file " + mFile);
3203                }
3204            }
3205            mcr.setDiskWriteResult(false);
3206        }
3207    }
3208}
3209