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