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