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