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