ContextImpl.java revision 170e548ac839b268beee208e95fc497b34fde1ba
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        return new DropBoxManager(service);
1186    }
1187
1188    private DropBoxManager getDropBoxManager() {
1189        synchronized (mSync) {
1190            if (mDropBoxManager == null) {
1191                mDropBoxManager = createDropBoxManager();
1192            }
1193        }
1194        return mDropBoxManager;
1195    }
1196
1197    private DevicePolicyManager getDevicePolicyManager() {
1198        synchronized (mSync) {
1199            if (mDevicePolicyManager == null) {
1200                mDevicePolicyManager = DevicePolicyManager.create(this,
1201                        mMainThread.getHandler());
1202            }
1203        }
1204        return mDevicePolicyManager;
1205    }
1206
1207    private UiModeManager getUiModeManager() {
1208        synchronized (mSync) {
1209            if (mUiModeManager == null) {
1210                mUiModeManager = new UiModeManager();
1211            }
1212        }
1213        return mUiModeManager;
1214    }
1215
1216    private DownloadManager getDownloadManager() {
1217        synchronized (mSync) {
1218            if (mDownloadManager == null) {
1219                mDownloadManager = new DownloadManager(getContentResolver(), getPackageName());
1220            }
1221        }
1222        return mDownloadManager;
1223    }
1224
1225    @Override
1226    public int checkPermission(String permission, int pid, int uid) {
1227        if (permission == null) {
1228            throw new IllegalArgumentException("permission is null");
1229        }
1230
1231        if (!Process.supportsProcesses()) {
1232            return PackageManager.PERMISSION_GRANTED;
1233        }
1234        try {
1235            return ActivityManagerNative.getDefault().checkPermission(
1236                    permission, pid, uid);
1237        } catch (RemoteException e) {
1238            return PackageManager.PERMISSION_DENIED;
1239        }
1240    }
1241
1242    @Override
1243    public int checkCallingPermission(String permission) {
1244        if (permission == null) {
1245            throw new IllegalArgumentException("permission is null");
1246        }
1247
1248        if (!Process.supportsProcesses()) {
1249            return PackageManager.PERMISSION_GRANTED;
1250        }
1251        int pid = Binder.getCallingPid();
1252        if (pid != Process.myPid()) {
1253            return checkPermission(permission, pid,
1254                    Binder.getCallingUid());
1255        }
1256        return PackageManager.PERMISSION_DENIED;
1257    }
1258
1259    @Override
1260    public int checkCallingOrSelfPermission(String permission) {
1261        if (permission == null) {
1262            throw new IllegalArgumentException("permission is null");
1263        }
1264
1265        return checkPermission(permission, Binder.getCallingPid(),
1266                Binder.getCallingUid());
1267    }
1268
1269    private void enforce(
1270            String permission, int resultOfCheck,
1271            boolean selfToo, int uid, String message) {
1272        if (resultOfCheck != PackageManager.PERMISSION_GRANTED) {
1273            throw new SecurityException(
1274                    (message != null ? (message + ": ") : "") +
1275                    (selfToo
1276                     ? "Neither user " + uid + " nor current process has "
1277                     : "User " + uid + " does not have ") +
1278                    permission +
1279                    ".");
1280        }
1281    }
1282
1283    public void enforcePermission(
1284            String permission, int pid, int uid, String message) {
1285        enforce(permission,
1286                checkPermission(permission, pid, uid),
1287                false,
1288                uid,
1289                message);
1290    }
1291
1292    public void enforceCallingPermission(String permission, String message) {
1293        enforce(permission,
1294                checkCallingPermission(permission),
1295                false,
1296                Binder.getCallingUid(),
1297                message);
1298    }
1299
1300    public void enforceCallingOrSelfPermission(
1301            String permission, String message) {
1302        enforce(permission,
1303                checkCallingOrSelfPermission(permission),
1304                true,
1305                Binder.getCallingUid(),
1306                message);
1307    }
1308
1309    @Override
1310    public void grantUriPermission(String toPackage, Uri uri, int modeFlags) {
1311         try {
1312            ActivityManagerNative.getDefault().grantUriPermission(
1313                    mMainThread.getApplicationThread(), toPackage, uri,
1314                    modeFlags);
1315        } catch (RemoteException e) {
1316        }
1317    }
1318
1319    @Override
1320    public void revokeUriPermission(Uri uri, int modeFlags) {
1321         try {
1322            ActivityManagerNative.getDefault().revokeUriPermission(
1323                    mMainThread.getApplicationThread(), uri,
1324                    modeFlags);
1325        } catch (RemoteException e) {
1326        }
1327    }
1328
1329    @Override
1330    public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
1331        if (!Process.supportsProcesses()) {
1332            return PackageManager.PERMISSION_GRANTED;
1333        }
1334        try {
1335            return ActivityManagerNative.getDefault().checkUriPermission(
1336                    uri, pid, uid, modeFlags);
1337        } catch (RemoteException e) {
1338            return PackageManager.PERMISSION_DENIED;
1339        }
1340    }
1341
1342    @Override
1343    public int checkCallingUriPermission(Uri uri, int modeFlags) {
1344        if (!Process.supportsProcesses()) {
1345            return PackageManager.PERMISSION_GRANTED;
1346        }
1347        int pid = Binder.getCallingPid();
1348        if (pid != Process.myPid()) {
1349            return checkUriPermission(uri, pid,
1350                    Binder.getCallingUid(), modeFlags);
1351        }
1352        return PackageManager.PERMISSION_DENIED;
1353    }
1354
1355    @Override
1356    public int checkCallingOrSelfUriPermission(Uri uri, int modeFlags) {
1357        return checkUriPermission(uri, Binder.getCallingPid(),
1358                Binder.getCallingUid(), modeFlags);
1359    }
1360
1361    @Override
1362    public int checkUriPermission(Uri uri, String readPermission,
1363            String writePermission, int pid, int uid, int modeFlags) {
1364        if (DEBUG) {
1365            Log.i("foo", "checkUriPermission: uri=" + uri + "readPermission="
1366                    + readPermission + " writePermission=" + writePermission
1367                    + " pid=" + pid + " uid=" + uid + " mode" + modeFlags);
1368        }
1369        if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
1370            if (readPermission == null
1371                    || checkPermission(readPermission, pid, uid)
1372                    == PackageManager.PERMISSION_GRANTED) {
1373                return PackageManager.PERMISSION_GRANTED;
1374            }
1375        }
1376        if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
1377            if (writePermission == null
1378                    || checkPermission(writePermission, pid, uid)
1379                    == PackageManager.PERMISSION_GRANTED) {
1380                return PackageManager.PERMISSION_GRANTED;
1381            }
1382        }
1383        return uri != null ? checkUriPermission(uri, pid, uid, modeFlags)
1384                : PackageManager.PERMISSION_DENIED;
1385    }
1386
1387    private String uriModeFlagToString(int uriModeFlags) {
1388        switch (uriModeFlags) {
1389            case Intent.FLAG_GRANT_READ_URI_PERMISSION |
1390                    Intent.FLAG_GRANT_WRITE_URI_PERMISSION:
1391                return "read and write";
1392            case Intent.FLAG_GRANT_READ_URI_PERMISSION:
1393                return "read";
1394            case Intent.FLAG_GRANT_WRITE_URI_PERMISSION:
1395                return "write";
1396        }
1397        throw new IllegalArgumentException(
1398                "Unknown permission mode flags: " + uriModeFlags);
1399    }
1400
1401    private void enforceForUri(
1402            int modeFlags, int resultOfCheck, boolean selfToo,
1403            int uid, Uri uri, String message) {
1404        if (resultOfCheck != PackageManager.PERMISSION_GRANTED) {
1405            throw new SecurityException(
1406                    (message != null ? (message + ": ") : "") +
1407                    (selfToo
1408                     ? "Neither user " + uid + " nor current process has "
1409                     : "User " + uid + " does not have ") +
1410                    uriModeFlagToString(modeFlags) +
1411                    " permission on " +
1412                    uri +
1413                    ".");
1414        }
1415    }
1416
1417    public void enforceUriPermission(
1418            Uri uri, int pid, int uid, int modeFlags, String message) {
1419        enforceForUri(
1420                modeFlags, checkUriPermission(uri, pid, uid, modeFlags),
1421                false, uid, uri, message);
1422    }
1423
1424    public void enforceCallingUriPermission(
1425            Uri uri, int modeFlags, String message) {
1426        enforceForUri(
1427                modeFlags, checkCallingUriPermission(uri, modeFlags),
1428                false, Binder.getCallingUid(), uri, message);
1429    }
1430
1431    public void enforceCallingOrSelfUriPermission(
1432            Uri uri, int modeFlags, String message) {
1433        enforceForUri(
1434                modeFlags,
1435                checkCallingOrSelfUriPermission(uri, modeFlags), true,
1436                Binder.getCallingUid(), uri, message);
1437    }
1438
1439    public void enforceUriPermission(
1440            Uri uri, String readPermission, String writePermission,
1441            int pid, int uid, int modeFlags, String message) {
1442        enforceForUri(modeFlags,
1443                      checkUriPermission(
1444                              uri, readPermission, writePermission, pid, uid,
1445                              modeFlags),
1446                      false,
1447                      uid,
1448                      uri,
1449                      message);
1450    }
1451
1452    @Override
1453    public Context createPackageContext(String packageName, int flags)
1454        throws PackageManager.NameNotFoundException {
1455        if (packageName.equals("system") || packageName.equals("android")) {
1456            return new ContextImpl(mMainThread.getSystemContext());
1457        }
1458
1459        LoadedApk pi =
1460            mMainThread.getPackageInfo(packageName, flags);
1461        if (pi != null) {
1462            ContextImpl c = new ContextImpl();
1463            c.mRestricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
1464            c.init(pi, null, mMainThread, mResources);
1465            if (c.mResources != null) {
1466                return c;
1467            }
1468        }
1469
1470        // Should be a better exception.
1471        throw new PackageManager.NameNotFoundException(
1472            "Application package " + packageName + " not found");
1473    }
1474
1475    @Override
1476    public boolean isRestricted() {
1477        return mRestricted;
1478    }
1479
1480    private File getDataDirFile() {
1481        if (mPackageInfo != null) {
1482            return mPackageInfo.getDataDirFile();
1483        }
1484        throw new RuntimeException("Not supported in system context");
1485    }
1486
1487    @Override
1488    public File getDir(String name, int mode) {
1489        name = "app_" + name;
1490        File file = makeFilename(getDataDirFile(), name);
1491        if (!file.exists()) {
1492            file.mkdir();
1493            setFilePermissionsFromMode(file.getPath(), mode,
1494                    FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH);
1495        }
1496        return file;
1497    }
1498
1499    static ContextImpl createSystemContext(ActivityThread mainThread) {
1500        ContextImpl context = new ContextImpl();
1501        context.init(Resources.getSystem(), mainThread);
1502        return context;
1503    }
1504
1505    ContextImpl() {
1506        mOuterContext = this;
1507    }
1508
1509    /**
1510     * Create a new ApplicationContext from an existing one.  The new one
1511     * works and operates the same as the one it is copying.
1512     *
1513     * @param context Existing application context.
1514     */
1515    public ContextImpl(ContextImpl context) {
1516        mPackageInfo = context.mPackageInfo;
1517        mResources = context.mResources;
1518        mMainThread = context.mMainThread;
1519        mContentResolver = context.mContentResolver;
1520        mOuterContext = this;
1521    }
1522
1523    final void init(LoadedApk packageInfo,
1524            IBinder activityToken, ActivityThread mainThread) {
1525        init(packageInfo, activityToken, mainThread, null);
1526    }
1527
1528    final void init(LoadedApk packageInfo,
1529                IBinder activityToken, ActivityThread mainThread,
1530                Resources container) {
1531        mPackageInfo = packageInfo;
1532        mResources = mPackageInfo.getResources(mainThread);
1533
1534        if (mResources != null && container != null
1535                && container.getCompatibilityInfo().applicationScale !=
1536                        mResources.getCompatibilityInfo().applicationScale) {
1537            if (DEBUG) {
1538                Log.d(TAG, "loaded context has different scaling. Using container's" +
1539                        " compatiblity info:" + container.getDisplayMetrics());
1540            }
1541            mResources = mainThread.getTopLevelResources(
1542                    mPackageInfo.getResDir(), container.getCompatibilityInfo().copy());
1543        }
1544        mMainThread = mainThread;
1545        mContentResolver = new ApplicationContentResolver(this, mainThread);
1546
1547        setActivityToken(activityToken);
1548    }
1549
1550    final void init(Resources resources, ActivityThread mainThread) {
1551        mPackageInfo = null;
1552        mResources = resources;
1553        mMainThread = mainThread;
1554        mContentResolver = new ApplicationContentResolver(this, mainThread);
1555    }
1556
1557    final void scheduleFinalCleanup(String who, String what) {
1558        mMainThread.scheduleContextCleanup(this, who, what);
1559    }
1560
1561    final void performFinalCleanup(String who, String what) {
1562        //Log.i(TAG, "Cleanup up context: " + this);
1563        mPackageInfo.removeContextRegistrations(getOuterContext(), who, what);
1564    }
1565
1566    final Context getReceiverRestrictedContext() {
1567        if (mReceiverRestrictedContext != null) {
1568            return mReceiverRestrictedContext;
1569        }
1570        return mReceiverRestrictedContext = new ReceiverRestrictedContext(getOuterContext());
1571    }
1572
1573    final void setActivityToken(IBinder token) {
1574        mActivityToken = token;
1575    }
1576
1577    final void setOuterContext(Context context) {
1578        mOuterContext = context;
1579    }
1580
1581    final Context getOuterContext() {
1582        return mOuterContext;
1583    }
1584
1585    final IBinder getActivityToken() {
1586        return mActivityToken;
1587    }
1588
1589    private static void setFilePermissionsFromMode(String name, int mode,
1590            int extraPermissions) {
1591        int perms = FileUtils.S_IRUSR|FileUtils.S_IWUSR
1592            |FileUtils.S_IRGRP|FileUtils.S_IWGRP
1593            |extraPermissions;
1594        if ((mode&MODE_WORLD_READABLE) != 0) {
1595            perms |= FileUtils.S_IROTH;
1596        }
1597        if ((mode&MODE_WORLD_WRITEABLE) != 0) {
1598            perms |= FileUtils.S_IWOTH;
1599        }
1600        if (DEBUG) {
1601            Log.i(TAG, "File " + name + ": mode=0x" + Integer.toHexString(mode)
1602                  + ", perms=0x" + Integer.toHexString(perms));
1603        }
1604        FileUtils.setPermissions(name, perms, -1, -1);
1605    }
1606
1607    private File validateFilePath(String name, boolean createDirectory) {
1608        File dir;
1609        File f;
1610
1611        if (name.charAt(0) == File.separatorChar) {
1612            String dirPath = name.substring(0, name.lastIndexOf(File.separatorChar));
1613            dir = new File(dirPath);
1614            name = name.substring(name.lastIndexOf(File.separatorChar));
1615            f = new File(dir, name);
1616        } else {
1617            dir = getDatabasesDir();
1618            f = makeFilename(dir, name);
1619        }
1620
1621        if (createDirectory && !dir.isDirectory() && dir.mkdir()) {
1622            FileUtils.setPermissions(dir.getPath(),
1623                FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
1624                -1, -1);
1625        }
1626
1627        return f;
1628    }
1629
1630    private File makeFilename(File base, String name) {
1631        if (name.indexOf(File.separatorChar) < 0) {
1632            return new File(base, name);
1633        }
1634        throw new IllegalArgumentException(
1635                "File " + name + " contains a path separator");
1636    }
1637
1638    // ----------------------------------------------------------------------
1639    // ----------------------------------------------------------------------
1640    // ----------------------------------------------------------------------
1641
1642    private static final class ApplicationContentResolver extends ContentResolver {
1643        public ApplicationContentResolver(Context context, ActivityThread mainThread) {
1644            super(context);
1645            mMainThread = mainThread;
1646        }
1647
1648        @Override
1649        protected IContentProvider acquireProvider(Context context, String name) {
1650            return mMainThread.acquireProvider(context, name);
1651        }
1652
1653        @Override
1654        protected IContentProvider acquireExistingProvider(Context context, String name) {
1655            return mMainThread.acquireExistingProvider(context, name);
1656        }
1657
1658        @Override
1659        public boolean releaseProvider(IContentProvider provider) {
1660            return mMainThread.releaseProvider(provider);
1661        }
1662
1663        private final ActivityThread mMainThread;
1664    }
1665
1666    // ----------------------------------------------------------------------
1667    // ----------------------------------------------------------------------
1668    // ----------------------------------------------------------------------
1669
1670    /*package*/
1671    static final class ApplicationPackageManager extends PackageManager {
1672        @Override
1673        public PackageInfo getPackageInfo(String packageName, int flags)
1674                throws NameNotFoundException {
1675            try {
1676                PackageInfo pi = mPM.getPackageInfo(packageName, flags);
1677                if (pi != null) {
1678                    return pi;
1679                }
1680            } catch (RemoteException e) {
1681                throw new RuntimeException("Package manager has died", e);
1682            }
1683
1684            throw new NameNotFoundException(packageName);
1685        }
1686
1687        @Override
1688        public String[] currentToCanonicalPackageNames(String[] names) {
1689            try {
1690                return mPM.currentToCanonicalPackageNames(names);
1691            } catch (RemoteException e) {
1692                throw new RuntimeException("Package manager has died", e);
1693            }
1694        }
1695
1696        @Override
1697        public String[] canonicalToCurrentPackageNames(String[] names) {
1698            try {
1699                return mPM.canonicalToCurrentPackageNames(names);
1700            } catch (RemoteException e) {
1701                throw new RuntimeException("Package manager has died", e);
1702            }
1703        }
1704
1705        @Override
1706        public Intent getLaunchIntentForPackage(String packageName) {
1707            // First see if the package has an INFO activity; the existence of
1708            // such an activity is implied to be the desired front-door for the
1709            // overall package (such as if it has multiple launcher entries).
1710            Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
1711            intentToResolve.addCategory(Intent.CATEGORY_INFO);
1712            intentToResolve.setPackage(packageName);
1713            ResolveInfo resolveInfo = resolveActivity(intentToResolve, 0);
1714
1715            // Otherwise, try to find a main launcher activity.
1716            if (resolveInfo == null) {
1717                // reuse the intent instance
1718                intentToResolve.removeCategory(Intent.CATEGORY_INFO);
1719                intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
1720                intentToResolve.setPackage(packageName);
1721                resolveInfo = resolveActivity(intentToResolve, 0);
1722            }
1723            if (resolveInfo == null) {
1724                return null;
1725            }
1726            Intent intent = new Intent(intentToResolve);
1727            intent.setClassName(resolveInfo.activityInfo.applicationInfo.packageName,
1728                                resolveInfo.activityInfo.name);
1729            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1730            return intent;
1731        }
1732
1733        @Override
1734        public int[] getPackageGids(String packageName)
1735            throws NameNotFoundException {
1736            try {
1737                int[] gids = mPM.getPackageGids(packageName);
1738                if (gids == null || gids.length > 0) {
1739                    return gids;
1740                }
1741            } catch (RemoteException e) {
1742                throw new RuntimeException("Package manager has died", e);
1743            }
1744
1745            throw new NameNotFoundException(packageName);
1746        }
1747
1748        @Override
1749        public PermissionInfo getPermissionInfo(String name, int flags)
1750            throws NameNotFoundException {
1751            try {
1752                PermissionInfo pi = mPM.getPermissionInfo(name, flags);
1753                if (pi != null) {
1754                    return pi;
1755                }
1756            } catch (RemoteException e) {
1757                throw new RuntimeException("Package manager has died", e);
1758            }
1759
1760            throw new NameNotFoundException(name);
1761        }
1762
1763        @Override
1764        public List<PermissionInfo> queryPermissionsByGroup(String group, int flags)
1765                throws NameNotFoundException {
1766            try {
1767                List<PermissionInfo> pi = mPM.queryPermissionsByGroup(group, flags);
1768                if (pi != null) {
1769                    return pi;
1770                }
1771            } catch (RemoteException e) {
1772                throw new RuntimeException("Package manager has died", e);
1773            }
1774
1775            throw new NameNotFoundException(group);
1776        }
1777
1778        @Override
1779        public PermissionGroupInfo getPermissionGroupInfo(String name,
1780                int flags) throws NameNotFoundException {
1781            try {
1782                PermissionGroupInfo pgi = mPM.getPermissionGroupInfo(name, flags);
1783                if (pgi != null) {
1784                    return pgi;
1785                }
1786            } catch (RemoteException e) {
1787                throw new RuntimeException("Package manager has died", e);
1788            }
1789
1790            throw new NameNotFoundException(name);
1791        }
1792
1793        @Override
1794        public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
1795            try {
1796                return mPM.getAllPermissionGroups(flags);
1797            } catch (RemoteException e) {
1798                throw new RuntimeException("Package manager has died", e);
1799            }
1800        }
1801
1802        @Override
1803        public ApplicationInfo getApplicationInfo(String packageName, int flags)
1804            throws NameNotFoundException {
1805            try {
1806                ApplicationInfo ai = mPM.getApplicationInfo(packageName, flags);
1807                if (ai != null) {
1808                    return ai;
1809                }
1810            } catch (RemoteException e) {
1811                throw new RuntimeException("Package manager has died", e);
1812            }
1813
1814            throw new NameNotFoundException(packageName);
1815        }
1816
1817        @Override
1818        public ActivityInfo getActivityInfo(ComponentName className, int flags)
1819            throws NameNotFoundException {
1820            try {
1821                ActivityInfo ai = mPM.getActivityInfo(className, flags);
1822                if (ai != null) {
1823                    return ai;
1824                }
1825            } catch (RemoteException e) {
1826                throw new RuntimeException("Package manager has died", e);
1827            }
1828
1829            throw new NameNotFoundException(className.toString());
1830        }
1831
1832        @Override
1833        public ActivityInfo getReceiverInfo(ComponentName className, int flags)
1834            throws NameNotFoundException {
1835            try {
1836                ActivityInfo ai = mPM.getReceiverInfo(className, flags);
1837                if (ai != null) {
1838                    return ai;
1839                }
1840            } catch (RemoteException e) {
1841                throw new RuntimeException("Package manager has died", e);
1842            }
1843
1844            throw new NameNotFoundException(className.toString());
1845        }
1846
1847        @Override
1848        public ServiceInfo getServiceInfo(ComponentName className, int flags)
1849            throws NameNotFoundException {
1850            try {
1851                ServiceInfo si = mPM.getServiceInfo(className, flags);
1852                if (si != null) {
1853                    return si;
1854                }
1855            } catch (RemoteException e) {
1856                throw new RuntimeException("Package manager has died", e);
1857            }
1858
1859            throw new NameNotFoundException(className.toString());
1860        }
1861
1862        @Override
1863        public ProviderInfo getProviderInfo(ComponentName className, int flags)
1864            throws NameNotFoundException {
1865            try {
1866                ProviderInfo pi = mPM.getProviderInfo(className, flags);
1867                if (pi != null) {
1868                    return pi;
1869                }
1870            } catch (RemoteException e) {
1871                throw new RuntimeException("Package manager has died", e);
1872            }
1873
1874            throw new NameNotFoundException(className.toString());
1875        }
1876
1877        @Override
1878        public String[] getSystemSharedLibraryNames() {
1879             try {
1880                 return mPM.getSystemSharedLibraryNames();
1881             } catch (RemoteException e) {
1882                 throw new RuntimeException("Package manager has died", e);
1883             }
1884        }
1885
1886        @Override
1887        public FeatureInfo[] getSystemAvailableFeatures() {
1888            try {
1889                return mPM.getSystemAvailableFeatures();
1890            } catch (RemoteException e) {
1891                throw new RuntimeException("Package manager has died", e);
1892            }
1893        }
1894
1895        @Override
1896        public boolean hasSystemFeature(String name) {
1897            try {
1898                return mPM.hasSystemFeature(name);
1899            } catch (RemoteException e) {
1900                throw new RuntimeException("Package manager has died", e);
1901            }
1902        }
1903
1904        @Override
1905        public int checkPermission(String permName, String pkgName) {
1906            try {
1907                return mPM.checkPermission(permName, pkgName);
1908            } catch (RemoteException e) {
1909                throw new RuntimeException("Package manager has died", e);
1910            }
1911        }
1912
1913        @Override
1914        public boolean addPermission(PermissionInfo info) {
1915            try {
1916                return mPM.addPermission(info);
1917            } catch (RemoteException e) {
1918                throw new RuntimeException("Package manager has died", e);
1919            }
1920        }
1921
1922        @Override
1923        public boolean addPermissionAsync(PermissionInfo info) {
1924            try {
1925                return mPM.addPermissionAsync(info);
1926            } catch (RemoteException e) {
1927                throw new RuntimeException("Package manager has died", e);
1928            }
1929        }
1930
1931        @Override
1932        public void removePermission(String name) {
1933            try {
1934                mPM.removePermission(name);
1935            } catch (RemoteException e) {
1936                throw new RuntimeException("Package manager has died", e);
1937            }
1938        }
1939
1940        @Override
1941        public int checkSignatures(String pkg1, String pkg2) {
1942            try {
1943                return mPM.checkSignatures(pkg1, pkg2);
1944            } catch (RemoteException e) {
1945                throw new RuntimeException("Package manager has died", e);
1946            }
1947        }
1948
1949        @Override
1950        public int checkSignatures(int uid1, int uid2) {
1951            try {
1952                return mPM.checkUidSignatures(uid1, uid2);
1953            } catch (RemoteException e) {
1954                throw new RuntimeException("Package manager has died", e);
1955            }
1956        }
1957
1958        @Override
1959        public String[] getPackagesForUid(int uid) {
1960            try {
1961                return mPM.getPackagesForUid(uid);
1962            } catch (RemoteException e) {
1963                throw new RuntimeException("Package manager has died", e);
1964            }
1965        }
1966
1967        @Override
1968        public String getNameForUid(int uid) {
1969            try {
1970                return mPM.getNameForUid(uid);
1971            } catch (RemoteException e) {
1972                throw new RuntimeException("Package manager has died", e);
1973            }
1974        }
1975
1976        @Override
1977        public int getUidForSharedUser(String sharedUserName)
1978                throws NameNotFoundException {
1979            try {
1980                int uid = mPM.getUidForSharedUser(sharedUserName);
1981                if(uid != -1) {
1982                    return uid;
1983                }
1984            } catch (RemoteException e) {
1985                throw new RuntimeException("Package manager has died", e);
1986            }
1987            throw new NameNotFoundException("No shared userid for user:"+sharedUserName);
1988        }
1989
1990        @Override
1991        public List<PackageInfo> getInstalledPackages(int flags) {
1992            try {
1993                return mPM.getInstalledPackages(flags);
1994            } catch (RemoteException e) {
1995                throw new RuntimeException("Package manager has died", e);
1996            }
1997        }
1998
1999        @Override
2000        public List<ApplicationInfo> getInstalledApplications(int flags) {
2001            try {
2002                return mPM.getInstalledApplications(flags);
2003            } catch (RemoteException e) {
2004                throw new RuntimeException("Package manager has died", e);
2005            }
2006        }
2007
2008        @Override
2009        public ResolveInfo resolveActivity(Intent intent, int flags) {
2010            try {
2011                return mPM.resolveIntent(
2012                    intent,
2013                    intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2014                    flags);
2015            } catch (RemoteException e) {
2016                throw new RuntimeException("Package manager has died", e);
2017            }
2018        }
2019
2020        @Override
2021        public List<ResolveInfo> queryIntentActivities(Intent intent,
2022                int flags) {
2023            try {
2024                return mPM.queryIntentActivities(
2025                    intent,
2026                    intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2027                    flags);
2028            } catch (RemoteException e) {
2029                throw new RuntimeException("Package manager has died", e);
2030            }
2031        }
2032
2033        @Override
2034        public List<ResolveInfo> queryIntentActivityOptions(
2035                ComponentName caller, Intent[] specifics, Intent intent,
2036                int flags) {
2037            final ContentResolver resolver = mContext.getContentResolver();
2038
2039            String[] specificTypes = null;
2040            if (specifics != null) {
2041                final int N = specifics.length;
2042                for (int i=0; i<N; i++) {
2043                    Intent sp = specifics[i];
2044                    if (sp != null) {
2045                        String t = sp.resolveTypeIfNeeded(resolver);
2046                        if (t != null) {
2047                            if (specificTypes == null) {
2048                                specificTypes = new String[N];
2049                            }
2050                            specificTypes[i] = t;
2051                        }
2052                    }
2053                }
2054            }
2055
2056            try {
2057                return mPM.queryIntentActivityOptions(caller, specifics,
2058                    specificTypes, intent, intent.resolveTypeIfNeeded(resolver),
2059                    flags);
2060            } catch (RemoteException e) {
2061                throw new RuntimeException("Package manager has died", e);
2062            }
2063        }
2064
2065        @Override
2066        public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags) {
2067            try {
2068                return mPM.queryIntentReceivers(
2069                    intent,
2070                    intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2071                    flags);
2072            } catch (RemoteException e) {
2073                throw new RuntimeException("Package manager has died", e);
2074            }
2075        }
2076
2077        @Override
2078        public ResolveInfo resolveService(Intent intent, int flags) {
2079            try {
2080                return mPM.resolveService(
2081                    intent,
2082                    intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2083                    flags);
2084            } catch (RemoteException e) {
2085                throw new RuntimeException("Package manager has died", e);
2086            }
2087        }
2088
2089        @Override
2090        public List<ResolveInfo> queryIntentServices(Intent intent, int flags) {
2091            try {
2092                return mPM.queryIntentServices(
2093                    intent,
2094                    intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2095                    flags);
2096            } catch (RemoteException e) {
2097                throw new RuntimeException("Package manager has died", e);
2098            }
2099        }
2100
2101        @Override
2102        public ProviderInfo resolveContentProvider(String name,
2103                int flags) {
2104            try {
2105                return mPM.resolveContentProvider(name, flags);
2106            } catch (RemoteException e) {
2107                throw new RuntimeException("Package manager has died", e);
2108            }
2109        }
2110
2111        @Override
2112        public List<ProviderInfo> queryContentProviders(String processName,
2113                int uid, int flags) {
2114            try {
2115                return mPM.queryContentProviders(processName, uid, flags);
2116            } catch (RemoteException e) {
2117                throw new RuntimeException("Package manager has died", e);
2118            }
2119        }
2120
2121        @Override
2122        public InstrumentationInfo getInstrumentationInfo(
2123                ComponentName className, int flags)
2124                throws NameNotFoundException {
2125            try {
2126                InstrumentationInfo ii = mPM.getInstrumentationInfo(
2127                        className, flags);
2128                if (ii != null) {
2129                    return ii;
2130                }
2131            } catch (RemoteException e) {
2132                throw new RuntimeException("Package manager has died", e);
2133            }
2134
2135            throw new NameNotFoundException(className.toString());
2136        }
2137
2138        @Override
2139        public List<InstrumentationInfo> queryInstrumentation(
2140                String targetPackage, int flags) {
2141            try {
2142                return mPM.queryInstrumentation(targetPackage, flags);
2143            } catch (RemoteException e) {
2144                throw new RuntimeException("Package manager has died", e);
2145            }
2146        }
2147
2148        @Override public Drawable getDrawable(String packageName, int resid,
2149                ApplicationInfo appInfo) {
2150            ResourceName name = new ResourceName(packageName, resid);
2151            Drawable dr = getCachedIcon(name);
2152            if (dr != null) {
2153                return dr;
2154            }
2155            if (appInfo == null) {
2156                try {
2157                    appInfo = getApplicationInfo(packageName, 0);
2158                } catch (NameNotFoundException e) {
2159                    return null;
2160                }
2161            }
2162            try {
2163                Resources r = getResourcesForApplication(appInfo);
2164                dr = r.getDrawable(resid);
2165                if (false) {
2166                    RuntimeException e = new RuntimeException("here");
2167                    e.fillInStackTrace();
2168                    Log.w(TAG, "Getting drawable 0x" + Integer.toHexString(resid)
2169                            + " from package " + packageName
2170                            + ": app scale=" + r.getCompatibilityInfo().applicationScale
2171                            + ", caller scale=" + mContext.getResources().getCompatibilityInfo().applicationScale,
2172                            e);
2173                }
2174                if (DEBUG_ICONS) Log.v(TAG, "Getting drawable 0x"
2175                        + Integer.toHexString(resid) + " from " + r
2176                        + ": " + dr);
2177                putCachedIcon(name, dr);
2178                return dr;
2179            } catch (NameNotFoundException e) {
2180                Log.w("PackageManager", "Failure retrieving resources for"
2181                        + appInfo.packageName);
2182            } catch (RuntimeException e) {
2183                // If an exception was thrown, fall through to return
2184                // default icon.
2185                Log.w("PackageManager", "Failure retrieving icon 0x"
2186                        + Integer.toHexString(resid) + " in package "
2187                        + packageName, e);
2188            }
2189            return null;
2190        }
2191
2192        @Override public Drawable getActivityIcon(ComponentName activityName)
2193                throws NameNotFoundException {
2194            return getActivityInfo(activityName, 0).loadIcon(this);
2195        }
2196
2197        @Override public Drawable getActivityIcon(Intent intent)
2198                throws NameNotFoundException {
2199            if (intent.getComponent() != null) {
2200                return getActivityIcon(intent.getComponent());
2201            }
2202
2203            ResolveInfo info = resolveActivity(
2204                intent, PackageManager.MATCH_DEFAULT_ONLY);
2205            if (info != null) {
2206                return info.activityInfo.loadIcon(this);
2207            }
2208
2209            throw new NameNotFoundException(intent.toURI());
2210        }
2211
2212        @Override public Drawable getDefaultActivityIcon() {
2213            return Resources.getSystem().getDrawable(
2214                com.android.internal.R.drawable.sym_def_app_icon);
2215        }
2216
2217        @Override public Drawable getApplicationIcon(ApplicationInfo info) {
2218            return info.loadIcon(this);
2219        }
2220
2221        @Override public Drawable getApplicationIcon(String packageName)
2222                throws NameNotFoundException {
2223            return getApplicationIcon(getApplicationInfo(packageName, 0));
2224        }
2225
2226        @Override
2227        public Drawable getActivityLogo(ComponentName activityName)
2228                throws NameNotFoundException {
2229            return getActivityInfo(activityName, 0).loadLogo(this);
2230        }
2231
2232        @Override
2233        public Drawable getActivityLogo(Intent intent)
2234                throws NameNotFoundException {
2235            if (intent.getComponent() != null) {
2236                return getActivityLogo(intent.getComponent());
2237            }
2238
2239            ResolveInfo info = resolveActivity(
2240                    intent, PackageManager.MATCH_DEFAULT_ONLY);
2241            if (info != null) {
2242                return info.activityInfo.loadLogo(this);
2243            }
2244
2245            throw new NameNotFoundException(intent.toUri(0));
2246        }
2247
2248        @Override
2249        public Drawable getApplicationLogo(ApplicationInfo info) {
2250            return info.loadLogo(this);
2251        }
2252
2253        @Override
2254        public Drawable getApplicationLogo(String packageName)
2255                throws NameNotFoundException {
2256            return getApplicationLogo(getApplicationInfo(packageName, 0));
2257        }
2258
2259        @Override public Resources getResourcesForActivity(
2260                ComponentName activityName) throws NameNotFoundException {
2261            return getResourcesForApplication(
2262                getActivityInfo(activityName, 0).applicationInfo);
2263        }
2264
2265        @Override public Resources getResourcesForApplication(
2266                ApplicationInfo app) throws NameNotFoundException {
2267            if (app.packageName.equals("system")) {
2268                return mContext.mMainThread.getSystemContext().getResources();
2269            }
2270            Resources r = mContext.mMainThread.getTopLevelResources(
2271                    app.uid == Process.myUid() ? app.sourceDir
2272                    : app.publicSourceDir, mContext.mPackageInfo);
2273            if (r != null) {
2274                return r;
2275            }
2276            throw new NameNotFoundException("Unable to open " + app.publicSourceDir);
2277        }
2278
2279        @Override public Resources getResourcesForApplication(
2280                String appPackageName) throws NameNotFoundException {
2281            return getResourcesForApplication(
2282                getApplicationInfo(appPackageName, 0));
2283        }
2284
2285        int mCachedSafeMode = -1;
2286        @Override public boolean isSafeMode() {
2287            try {
2288                if (mCachedSafeMode < 0) {
2289                    mCachedSafeMode = mPM.isSafeMode() ? 1 : 0;
2290                }
2291                return mCachedSafeMode != 0;
2292            } catch (RemoteException e) {
2293                throw new RuntimeException("Package manager has died", e);
2294            }
2295        }
2296
2297        static void configurationChanged() {
2298            synchronized (sSync) {
2299                sIconCache.clear();
2300                sStringCache.clear();
2301            }
2302        }
2303
2304        ApplicationPackageManager(ContextImpl context,
2305                IPackageManager pm) {
2306            mContext = context;
2307            mPM = pm;
2308        }
2309
2310        private Drawable getCachedIcon(ResourceName name) {
2311            synchronized (sSync) {
2312                WeakReference<Drawable> wr = sIconCache.get(name);
2313                if (DEBUG_ICONS) Log.v(TAG, "Get cached weak drawable ref for "
2314                        + name + ": " + wr);
2315                if (wr != null) {   // we have the activity
2316                    Drawable dr = wr.get();
2317                    if (dr != null) {
2318                        if (DEBUG_ICONS) Log.v(TAG, "Get cached drawable for "
2319                                + name + ": " + dr);
2320                        return dr;
2321                    }
2322                    // our entry has been purged
2323                    sIconCache.remove(name);
2324                }
2325            }
2326            return null;
2327        }
2328
2329        private void putCachedIcon(ResourceName name, Drawable dr) {
2330            synchronized (sSync) {
2331                sIconCache.put(name, new WeakReference<Drawable>(dr));
2332                if (DEBUG_ICONS) Log.v(TAG, "Added cached drawable for "
2333                        + name + ": " + dr);
2334            }
2335        }
2336
2337        static final void handlePackageBroadcast(int cmd, String[] pkgList,
2338                boolean hasPkgInfo) {
2339            boolean immediateGc = false;
2340            if (cmd == IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE) {
2341                immediateGc = true;
2342            }
2343            if (pkgList != null && (pkgList.length > 0)) {
2344                boolean needCleanup = false;
2345                for (String ssp : pkgList) {
2346                    synchronized (sSync) {
2347                        if (sIconCache.size() > 0) {
2348                            Iterator<ResourceName> it = sIconCache.keySet().iterator();
2349                            while (it.hasNext()) {
2350                                ResourceName nm = it.next();
2351                                if (nm.packageName.equals(ssp)) {
2352                                    //Log.i(TAG, "Removing cached drawable for " + nm);
2353                                    it.remove();
2354                                    needCleanup = true;
2355                                }
2356                            }
2357                        }
2358                        if (sStringCache.size() > 0) {
2359                            Iterator<ResourceName> it = sStringCache.keySet().iterator();
2360                            while (it.hasNext()) {
2361                                ResourceName nm = it.next();
2362                                if (nm.packageName.equals(ssp)) {
2363                                    //Log.i(TAG, "Removing cached string for " + nm);
2364                                    it.remove();
2365                                    needCleanup = true;
2366                                }
2367                            }
2368                        }
2369                    }
2370                }
2371                if (needCleanup || hasPkgInfo) {
2372                    if (immediateGc) {
2373                        // Schedule an immediate gc.
2374                        Runtime.getRuntime().gc();
2375                    } else {
2376                        ActivityThread.currentActivityThread().scheduleGcIdler();
2377                    }
2378                }
2379            }
2380        }
2381
2382        private static final class ResourceName {
2383            final String packageName;
2384            final int iconId;
2385
2386            ResourceName(String _packageName, int _iconId) {
2387                packageName = _packageName;
2388                iconId = _iconId;
2389            }
2390
2391            ResourceName(ApplicationInfo aInfo, int _iconId) {
2392                this(aInfo.packageName, _iconId);
2393            }
2394
2395            ResourceName(ComponentInfo cInfo, int _iconId) {
2396                this(cInfo.applicationInfo.packageName, _iconId);
2397            }
2398
2399            ResourceName(ResolveInfo rInfo, int _iconId) {
2400                this(rInfo.activityInfo.applicationInfo.packageName, _iconId);
2401            }
2402
2403            @Override
2404            public boolean equals(Object o) {
2405                if (this == o) return true;
2406                if (o == null || getClass() != o.getClass()) return false;
2407
2408                ResourceName that = (ResourceName) o;
2409
2410                if (iconId != that.iconId) return false;
2411                return !(packageName != null ?
2412                        !packageName.equals(that.packageName) : that.packageName != null);
2413
2414            }
2415
2416            @Override
2417            public int hashCode() {
2418                int result;
2419                result = packageName.hashCode();
2420                result = 31 * result + iconId;
2421                return result;
2422            }
2423
2424            @Override
2425            public String toString() {
2426                return "{ResourceName " + packageName + " / " + iconId + "}";
2427            }
2428        }
2429
2430        private CharSequence getCachedString(ResourceName name) {
2431            synchronized (sSync) {
2432                WeakReference<CharSequence> wr = sStringCache.get(name);
2433                if (wr != null) {   // we have the activity
2434                    CharSequence cs = wr.get();
2435                    if (cs != null) {
2436                        return cs;
2437                    }
2438                    // our entry has been purged
2439                    sStringCache.remove(name);
2440                }
2441            }
2442            return null;
2443        }
2444
2445        private void putCachedString(ResourceName name, CharSequence cs) {
2446            synchronized (sSync) {
2447                sStringCache.put(name, new WeakReference<CharSequence>(cs));
2448            }
2449        }
2450
2451        @Override
2452        public CharSequence getText(String packageName, int resid,
2453                ApplicationInfo appInfo) {
2454            ResourceName name = new ResourceName(packageName, resid);
2455            CharSequence text = getCachedString(name);
2456            if (text != null) {
2457                return text;
2458            }
2459            if (appInfo == null) {
2460                try {
2461                    appInfo = getApplicationInfo(packageName, 0);
2462                } catch (NameNotFoundException e) {
2463                    return null;
2464                }
2465            }
2466            try {
2467                Resources r = getResourcesForApplication(appInfo);
2468                text = r.getText(resid);
2469                putCachedString(name, text);
2470                return text;
2471            } catch (NameNotFoundException e) {
2472                Log.w("PackageManager", "Failure retrieving resources for"
2473                        + appInfo.packageName);
2474            } catch (RuntimeException e) {
2475                // If an exception was thrown, fall through to return
2476                // default icon.
2477                Log.w("PackageManager", "Failure retrieving text 0x"
2478                        + Integer.toHexString(resid) + " in package "
2479                        + packageName, e);
2480            }
2481            return null;
2482        }
2483
2484        @Override
2485        public XmlResourceParser getXml(String packageName, int resid,
2486                ApplicationInfo appInfo) {
2487            if (appInfo == null) {
2488                try {
2489                    appInfo = getApplicationInfo(packageName, 0);
2490                } catch (NameNotFoundException e) {
2491                    return null;
2492                }
2493            }
2494            try {
2495                Resources r = getResourcesForApplication(appInfo);
2496                return r.getXml(resid);
2497            } catch (RuntimeException e) {
2498                // If an exception was thrown, fall through to return
2499                // default icon.
2500                Log.w("PackageManager", "Failure retrieving xml 0x"
2501                        + Integer.toHexString(resid) + " in package "
2502                        + packageName, e);
2503            } catch (NameNotFoundException e) {
2504                Log.w("PackageManager", "Failure retrieving resources for"
2505                        + appInfo.packageName);
2506            }
2507            return null;
2508        }
2509
2510        @Override
2511        public CharSequence getApplicationLabel(ApplicationInfo info) {
2512            return info.loadLabel(this);
2513        }
2514
2515        @Override
2516        public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
2517                String installerPackageName) {
2518            try {
2519                mPM.installPackage(packageURI, observer, flags, installerPackageName);
2520            } catch (RemoteException e) {
2521                // Should never happen!
2522            }
2523        }
2524
2525        @Override
2526        public void movePackage(String packageName, IPackageMoveObserver observer, int flags) {
2527            try {
2528                mPM.movePackage(packageName, observer, flags);
2529            } catch (RemoteException e) {
2530                // Should never happen!
2531            }
2532        }
2533
2534        @Override
2535        public String getInstallerPackageName(String packageName) {
2536            try {
2537                return mPM.getInstallerPackageName(packageName);
2538            } catch (RemoteException e) {
2539                // Should never happen!
2540            }
2541            return null;
2542        }
2543
2544        @Override
2545        public void deletePackage(String packageName, IPackageDeleteObserver observer, int flags) {
2546            try {
2547                mPM.deletePackage(packageName, observer, flags);
2548            } catch (RemoteException e) {
2549                // Should never happen!
2550            }
2551        }
2552        @Override
2553        public void clearApplicationUserData(String packageName,
2554                IPackageDataObserver observer) {
2555            try {
2556                mPM.clearApplicationUserData(packageName, observer);
2557            } catch (RemoteException e) {
2558                // Should never happen!
2559            }
2560        }
2561        @Override
2562        public void deleteApplicationCacheFiles(String packageName,
2563                IPackageDataObserver observer) {
2564            try {
2565                mPM.deleteApplicationCacheFiles(packageName, observer);
2566            } catch (RemoteException e) {
2567                // Should never happen!
2568            }
2569        }
2570        @Override
2571        public void freeStorageAndNotify(long idealStorageSize, IPackageDataObserver observer) {
2572            try {
2573                mPM.freeStorageAndNotify(idealStorageSize, observer);
2574            } catch (RemoteException e) {
2575                // Should never happen!
2576            }
2577        }
2578
2579        @Override
2580        public void freeStorage(long freeStorageSize, IntentSender pi) {
2581            try {
2582                mPM.freeStorage(freeStorageSize, pi);
2583            } catch (RemoteException e) {
2584                // Should never happen!
2585            }
2586        }
2587
2588        @Override
2589        public void getPackageSizeInfo(String packageName,
2590                IPackageStatsObserver observer) {
2591            try {
2592                mPM.getPackageSizeInfo(packageName, observer);
2593            } catch (RemoteException e) {
2594                // Should never happen!
2595            }
2596        }
2597        @Override
2598        public void addPackageToPreferred(String packageName) {
2599            try {
2600                mPM.addPackageToPreferred(packageName);
2601            } catch (RemoteException e) {
2602                // Should never happen!
2603            }
2604        }
2605
2606        @Override
2607        public void removePackageFromPreferred(String packageName) {
2608            try {
2609                mPM.removePackageFromPreferred(packageName);
2610            } catch (RemoteException e) {
2611                // Should never happen!
2612            }
2613        }
2614
2615        @Override
2616        public List<PackageInfo> getPreferredPackages(int flags) {
2617            try {
2618                return mPM.getPreferredPackages(flags);
2619            } catch (RemoteException e) {
2620                // Should never happen!
2621            }
2622            return new ArrayList<PackageInfo>();
2623        }
2624
2625        @Override
2626        public void addPreferredActivity(IntentFilter filter,
2627                int match, ComponentName[] set, ComponentName activity) {
2628            try {
2629                mPM.addPreferredActivity(filter, match, set, activity);
2630            } catch (RemoteException e) {
2631                // Should never happen!
2632            }
2633        }
2634
2635        @Override
2636        public void replacePreferredActivity(IntentFilter filter,
2637                int match, ComponentName[] set, ComponentName activity) {
2638            try {
2639                mPM.replacePreferredActivity(filter, match, set, activity);
2640            } catch (RemoteException e) {
2641                // Should never happen!
2642            }
2643        }
2644
2645        @Override
2646        public void clearPackagePreferredActivities(String packageName) {
2647            try {
2648                mPM.clearPackagePreferredActivities(packageName);
2649            } catch (RemoteException e) {
2650                // Should never happen!
2651            }
2652        }
2653
2654        @Override
2655        public int getPreferredActivities(List<IntentFilter> outFilters,
2656                List<ComponentName> outActivities, String packageName) {
2657            try {
2658                return mPM.getPreferredActivities(outFilters, outActivities, packageName);
2659            } catch (RemoteException e) {
2660                // Should never happen!
2661            }
2662            return 0;
2663        }
2664
2665        @Override
2666        public void setComponentEnabledSetting(ComponentName componentName,
2667                int newState, int flags) {
2668            try {
2669                mPM.setComponentEnabledSetting(componentName, newState, flags);
2670            } catch (RemoteException e) {
2671                // Should never happen!
2672            }
2673        }
2674
2675        @Override
2676        public int getComponentEnabledSetting(ComponentName componentName) {
2677            try {
2678                return mPM.getComponentEnabledSetting(componentName);
2679            } catch (RemoteException e) {
2680                // Should never happen!
2681            }
2682            return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
2683        }
2684
2685        @Override
2686        public void setApplicationEnabledSetting(String packageName,
2687                int newState, int flags) {
2688            try {
2689                mPM.setApplicationEnabledSetting(packageName, newState, flags);
2690            } catch (RemoteException e) {
2691                // Should never happen!
2692            }
2693        }
2694
2695        @Override
2696        public int getApplicationEnabledSetting(String packageName) {
2697            try {
2698                return mPM.getApplicationEnabledSetting(packageName);
2699            } catch (RemoteException e) {
2700                // Should never happen!
2701            }
2702            return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
2703        }
2704
2705        @Override
2706        public void setPackageObbPath(String packageName, String path) {
2707            try {
2708                mPM.setPackageObbPath(packageName, path);
2709            } catch (RemoteException e) {
2710                // Should never happen!
2711            }
2712        }
2713
2714        private final ContextImpl mContext;
2715        private final IPackageManager mPM;
2716
2717        private static final Object sSync = new Object();
2718        private static HashMap<ResourceName, WeakReference<Drawable> > sIconCache
2719                = new HashMap<ResourceName, WeakReference<Drawable> >();
2720        private static HashMap<ResourceName, WeakReference<CharSequence> > sStringCache
2721                = new HashMap<ResourceName, WeakReference<CharSequence> >();
2722    }
2723
2724    // ----------------------------------------------------------------------
2725    // ----------------------------------------------------------------------
2726    // ----------------------------------------------------------------------
2727
2728    private static final class SharedPreferencesImpl implements SharedPreferences {
2729
2730        // Lock ordering rules:
2731        //  - acquire SharedPreferencesImpl.this before EditorImpl.this
2732        //  - acquire mWritingToDiskLock before EditorImpl.this
2733
2734        private final File mFile;
2735        private final File mBackupFile;
2736        private final int mMode;
2737
2738        private Map<String, Object> mMap;     // guarded by 'this'
2739        private int mDiskWritesInFlight = 0;  // guarded by 'this'
2740        private boolean mLoaded = false;      // guarded by 'this'
2741        private long mStatTimestamp;          // guarded by 'this'
2742        private long mStatSize;               // guarded by 'this'
2743
2744        private final Object mWritingToDiskLock = new Object();
2745        private static final Object mContent = new Object();
2746        private final WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners;
2747
2748        SharedPreferencesImpl(
2749            File file, int mode, Map initialContents) {
2750            mFile = file;
2751            mBackupFile = makeBackupFile(file);
2752            mMode = mode;
2753            mLoaded = initialContents != null;
2754            mMap = initialContents != null ? initialContents : new HashMap<String, Object>();
2755            FileStatus stat = new FileStatus();
2756            if (FileUtils.getFileStatus(file.getPath(), stat)) {
2757                mStatTimestamp = stat.mtime;
2758            }
2759            mListeners = new WeakHashMap<OnSharedPreferenceChangeListener, Object>();
2760        }
2761
2762        // Has this SharedPreferences ever had values assigned to it?
2763        boolean isLoaded() {
2764            synchronized (this) {
2765                return mLoaded;
2766            }
2767        }
2768
2769        // Has the file changed out from under us?  i.e. writes that
2770        // we didn't instigate.
2771        public boolean hasFileChangedUnexpectedly() {
2772            synchronized (this) {
2773                if (mDiskWritesInFlight > 0) {
2774                    // If we know we caused it, it's not unexpected.
2775                    if (DEBUG) Log.d(TAG, "disk write in flight, not unexpected.");
2776                    return false;
2777                }
2778            }
2779            FileStatus stat = new FileStatus();
2780            if (!FileUtils.getFileStatus(mFile.getPath(), stat)) {
2781                return true;
2782            }
2783            synchronized (this) {
2784                return mStatTimestamp != stat.mtime || mStatSize != stat.size;
2785            }
2786        }
2787
2788        public void replace(Map newContents) {
2789            synchronized (this) {
2790                mLoaded = true;
2791                if (newContents != null) {
2792                    mMap = newContents;
2793                }
2794            }
2795        }
2796
2797        public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
2798            synchronized(this) {
2799                mListeners.put(listener, mContent);
2800            }
2801        }
2802
2803        public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
2804            synchronized(this) {
2805                mListeners.remove(listener);
2806            }
2807        }
2808
2809        public Map<String, ?> getAll() {
2810            synchronized(this) {
2811                //noinspection unchecked
2812                return new HashMap<String, Object>(mMap);
2813            }
2814        }
2815
2816        public String getString(String key, String defValue) {
2817            synchronized (this) {
2818                String v = (String)mMap.get(key);
2819                return v != null ? v : defValue;
2820            }
2821        }
2822
2823        public Set<String> getStringSet(String key, Set<String> defValues) {
2824            synchronized (this) {
2825                Set<String> v = (Set<String>) mMap.get(key);
2826                return v != null ? v : defValues;
2827            }
2828        }
2829
2830        public int getInt(String key, int defValue) {
2831            synchronized (this) {
2832                Integer v = (Integer)mMap.get(key);
2833                return v != null ? v : defValue;
2834            }
2835        }
2836        public long getLong(String key, long defValue) {
2837            synchronized (this) {
2838                Long v = (Long)mMap.get(key);
2839                return v != null ? v : defValue;
2840            }
2841        }
2842        public float getFloat(String key, float defValue) {
2843            synchronized (this) {
2844                Float v = (Float)mMap.get(key);
2845                return v != null ? v : defValue;
2846            }
2847        }
2848        public boolean getBoolean(String key, boolean defValue) {
2849            synchronized (this) {
2850                Boolean v = (Boolean)mMap.get(key);
2851                return v != null ? v : defValue;
2852            }
2853        }
2854
2855        public boolean contains(String key) {
2856            synchronized (this) {
2857                return mMap.containsKey(key);
2858            }
2859        }
2860
2861        public Editor edit() {
2862            return new EditorImpl();
2863        }
2864
2865        // Return value from EditorImpl#commitToMemory()
2866        private static class MemoryCommitResult {
2867            public boolean changesMade;  // any keys different?
2868            public List<String> keysModified;  // may be null
2869            public Set<OnSharedPreferenceChangeListener> listeners;  // may be null
2870            public Map<?, ?> mapToWriteToDisk;
2871            public final CountDownLatch writtenToDiskLatch = new CountDownLatch(1);
2872            public volatile boolean writeToDiskResult = false;
2873
2874            public void setDiskWriteResult(boolean result) {
2875                writeToDiskResult = result;
2876                writtenToDiskLatch.countDown();
2877            }
2878        }
2879
2880        public final class EditorImpl implements Editor {
2881            private final Map<String, Object> mModified = Maps.newHashMap();
2882            private boolean mClear = false;
2883
2884            public Editor putString(String key, String value) {
2885                synchronized (this) {
2886                    mModified.put(key, value);
2887                    return this;
2888                }
2889            }
2890            public Editor putStringSet(String key, Set<String> values) {
2891                synchronized (this) {
2892                    mModified.put(key, values);
2893                    return this;
2894                }
2895            }
2896            public Editor putInt(String key, int value) {
2897                synchronized (this) {
2898                    mModified.put(key, value);
2899                    return this;
2900                }
2901            }
2902            public Editor putLong(String key, long value) {
2903                synchronized (this) {
2904                    mModified.put(key, value);
2905                    return this;
2906                }
2907            }
2908            public Editor putFloat(String key, float value) {
2909                synchronized (this) {
2910                    mModified.put(key, value);
2911                    return this;
2912                }
2913            }
2914            public Editor putBoolean(String key, boolean value) {
2915                synchronized (this) {
2916                    mModified.put(key, value);
2917                    return this;
2918                }
2919            }
2920
2921            public Editor remove(String key) {
2922                synchronized (this) {
2923                    mModified.put(key, this);
2924                    return this;
2925                }
2926            }
2927
2928            public Editor clear() {
2929                synchronized (this) {
2930                    mClear = true;
2931                    return this;
2932                }
2933            }
2934
2935            public void apply() {
2936                final MemoryCommitResult mcr = commitToMemory();
2937                final Runnable awaitCommit = new Runnable() {
2938                        public void run() {
2939                            try {
2940                                mcr.writtenToDiskLatch.await();
2941                            } catch (InterruptedException ignored) {
2942                            }
2943                        }
2944                    };
2945
2946                QueuedWork.add(awaitCommit);
2947
2948                Runnable postWriteRunnable = new Runnable() {
2949                        public void run() {
2950                            awaitCommit.run();
2951                            QueuedWork.remove(awaitCommit);
2952                        }
2953                    };
2954
2955                SharedPreferencesImpl.this.enqueueDiskWrite(mcr, postWriteRunnable);
2956
2957                // Okay to notify the listeners before it's hit disk
2958                // because the listeners should always get the same
2959                // SharedPreferences instance back, which has the
2960                // changes reflected in memory.
2961                notifyListeners(mcr);
2962            }
2963
2964            // Returns true if any changes were made
2965            private MemoryCommitResult commitToMemory() {
2966                MemoryCommitResult mcr = new MemoryCommitResult();
2967                synchronized (SharedPreferencesImpl.this) {
2968                    // We optimistically don't make a deep copy until
2969                    // a memory commit comes in when we're already
2970                    // writing to disk.
2971                    if (mDiskWritesInFlight > 0) {
2972                        // We can't modify our mMap as a currently
2973                        // in-flight write owns it.  Clone it before
2974                        // modifying it.
2975                        // noinspection unchecked
2976                        mMap = new HashMap<String, Object>(mMap);
2977                    }
2978                    mcr.mapToWriteToDisk = mMap;
2979                    mDiskWritesInFlight++;
2980
2981                    boolean hasListeners = mListeners.size() > 0;
2982                    if (hasListeners) {
2983                        mcr.keysModified = new ArrayList<String>();
2984                        mcr.listeners =
2985                            new HashSet<OnSharedPreferenceChangeListener>(mListeners.keySet());
2986                    }
2987
2988                    synchronized (this) {
2989                        if (mClear) {
2990                            if (!mMap.isEmpty()) {
2991                                mcr.changesMade = true;
2992                                mMap.clear();
2993                            }
2994                            mClear = false;
2995                        }
2996
2997                        for (Entry<String, Object> e : mModified.entrySet()) {
2998                            String k = e.getKey();
2999                            Object v = e.getValue();
3000                            if (v == this) {  // magic value for a removal mutation
3001                                if (!mMap.containsKey(k)) {
3002                                    continue;
3003                                }
3004                                mMap.remove(k);
3005                            } else {
3006                                boolean isSame = false;
3007                                if (mMap.containsKey(k)) {
3008                                    Object existingValue = mMap.get(k);
3009                                    if (existingValue != null && existingValue.equals(v)) {
3010                                        continue;
3011                                    }
3012                                }
3013                                mMap.put(k, v);
3014                            }
3015
3016                            mcr.changesMade = true;
3017                            if (hasListeners) {
3018                                mcr.keysModified.add(k);
3019                            }
3020                        }
3021
3022                        mModified.clear();
3023                    }
3024                }
3025                return mcr;
3026            }
3027
3028            public boolean commit() {
3029                MemoryCommitResult mcr = commitToMemory();
3030                SharedPreferencesImpl.this.enqueueDiskWrite(
3031                    mcr, null /* sync write on this thread okay */);
3032                try {
3033                    mcr.writtenToDiskLatch.await();
3034                } catch (InterruptedException e) {
3035                    return false;
3036                }
3037                notifyListeners(mcr);
3038                return mcr.writeToDiskResult;
3039            }
3040
3041            private void notifyListeners(final MemoryCommitResult mcr) {
3042                if (mcr.listeners == null || mcr.keysModified == null ||
3043                    mcr.keysModified.size() == 0) {
3044                    return;
3045                }
3046                if (Looper.myLooper() == Looper.getMainLooper()) {
3047                    for (int i = mcr.keysModified.size() - 1; i >= 0; i--) {
3048                        final String key = mcr.keysModified.get(i);
3049                        for (OnSharedPreferenceChangeListener listener : mcr.listeners) {
3050                            if (listener != null) {
3051                                listener.onSharedPreferenceChanged(SharedPreferencesImpl.this, key);
3052                            }
3053                        }
3054                    }
3055                } else {
3056                    // Run this function on the main thread.
3057                    ActivityThread.sMainThreadHandler.post(new Runnable() {
3058                            public void run() {
3059                                notifyListeners(mcr);
3060                            }
3061                        });
3062                }
3063            }
3064        }
3065
3066        /**
3067         * Enqueue an already-committed-to-memory result to be written
3068         * to disk.
3069         *
3070         * They will be written to disk one-at-a-time in the order
3071         * that they're enqueued.
3072         *
3073         * @param postWriteRunnable if non-null, we're being called
3074         *   from apply() and this is the runnable to run after
3075         *   the write proceeds.  if null (from a regular commit()),
3076         *   then we're allowed to do this disk write on the main
3077         *   thread (which in addition to reducing allocations and
3078         *   creating a background thread, this has the advantage that
3079         *   we catch them in userdebug StrictMode reports to convert
3080         *   them where possible to apply() ...)
3081         */
3082        private void enqueueDiskWrite(final MemoryCommitResult mcr,
3083                                      final Runnable postWriteRunnable) {
3084            final Runnable writeToDiskRunnable = new Runnable() {
3085                    public void run() {
3086                        synchronized (mWritingToDiskLock) {
3087                            writeToFile(mcr);
3088                        }
3089                        synchronized (SharedPreferencesImpl.this) {
3090                            mDiskWritesInFlight--;
3091                        }
3092                        if (postWriteRunnable != null) {
3093                            postWriteRunnable.run();
3094                        }
3095                    }
3096                };
3097
3098            final boolean isFromSyncCommit = (postWriteRunnable == null);
3099
3100            // Typical #commit() path with fewer allocations, doing a write on
3101            // the current thread.
3102            if (isFromSyncCommit) {
3103                boolean wasEmpty = false;
3104                synchronized (SharedPreferencesImpl.this) {
3105                    wasEmpty = mDiskWritesInFlight == 1;
3106                }
3107                if (wasEmpty) {
3108                    writeToDiskRunnable.run();
3109                    return;
3110                }
3111            }
3112
3113            QueuedWork.singleThreadExecutor().execute(writeToDiskRunnable);
3114        }
3115
3116        private static FileOutputStream createFileOutputStream(File file) {
3117            FileOutputStream str = null;
3118            try {
3119                str = new FileOutputStream(file);
3120            } catch (FileNotFoundException e) {
3121                File parent = file.getParentFile();
3122                if (!parent.mkdir()) {
3123                    Log.e(TAG, "Couldn't create directory for SharedPreferences file " + file);
3124                    return null;
3125                }
3126                FileUtils.setPermissions(
3127                    parent.getPath(),
3128                    FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
3129                    -1, -1);
3130                try {
3131                    str = new FileOutputStream(file);
3132                } catch (FileNotFoundException e2) {
3133                    Log.e(TAG, "Couldn't create SharedPreferences file " + file, e2);
3134                }
3135            }
3136            return str;
3137        }
3138
3139        // Note: must hold mWritingToDiskLock
3140        private void writeToFile(MemoryCommitResult mcr) {
3141            // Rename the current file so it may be used as a backup during the next read
3142            if (mFile.exists()) {
3143                if (!mcr.changesMade) {
3144                    // If the file already exists, but no changes were
3145                    // made to the underlying map, it's wasteful to
3146                    // re-write the file.  Return as if we wrote it
3147                    // out.
3148                    mcr.setDiskWriteResult(true);
3149                    return;
3150                }
3151                if (!mBackupFile.exists()) {
3152                    if (!mFile.renameTo(mBackupFile)) {
3153                        Log.e(TAG, "Couldn't rename file " + mFile
3154                                + " to backup file " + mBackupFile);
3155                        mcr.setDiskWriteResult(false);
3156                        return;
3157                    }
3158                } else {
3159                    mFile.delete();
3160                }
3161            }
3162
3163            // Attempt to write the file, delete the backup and return true as atomically as
3164            // possible.  If any exception occurs, delete the new file; next time we will restore
3165            // from the backup.
3166            try {
3167                FileOutputStream str = createFileOutputStream(mFile);
3168                if (str == null) {
3169                    mcr.setDiskWriteResult(false);
3170                    return;
3171                }
3172                XmlUtils.writeMapXml(mcr.mapToWriteToDisk, str);
3173                FileUtils.sync(str);
3174                str.close();
3175                setFilePermissionsFromMode(mFile.getPath(), mMode, 0);
3176                FileStatus stat = new FileStatus();
3177                if (FileUtils.getFileStatus(mFile.getPath(), stat)) {
3178                    synchronized (this) {
3179                        mStatTimestamp = stat.mtime;
3180                        mStatSize = stat.size;
3181                    }
3182                }
3183                // Writing was successful, delete the backup file if there is one.
3184                mBackupFile.delete();
3185                mcr.setDiskWriteResult(true);
3186                return;
3187            } catch (XmlPullParserException e) {
3188                Log.w(TAG, "writeToFile: Got exception:", e);
3189            } catch (IOException e) {
3190                Log.w(TAG, "writeToFile: Got exception:", e);
3191            }
3192            // Clean up an unsuccessfully written file
3193            if (mFile.exists()) {
3194                if (!mFile.delete()) {
3195                    Log.e(TAG, "Couldn't clean up partially-written file " + mFile);
3196                }
3197            }
3198            mcr.setDiskWriteResult(false);
3199        }
3200    }
3201}
3202