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