ApplicationPackageManager.java revision e6cd0c747e76723bc51a23925c239ae10f9d3b5c
1/*
2 * Copyright (C) 2010 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 android.content.ComponentName;
20import android.content.ContentResolver;
21import android.content.Intent;
22import android.content.IntentFilter;
23import android.content.IntentSender;
24import android.content.pm.ActivityInfo;
25import android.content.pm.ApplicationInfo;
26import android.content.pm.ComponentInfo;
27import android.content.pm.FeatureInfo;
28import android.content.pm.IPackageDataObserver;
29import android.content.pm.IPackageDeleteObserver;
30import android.content.pm.IPackageInstallObserver;
31import android.content.pm.IPackageManager;
32import android.content.pm.IPackageMoveObserver;
33import android.content.pm.IPackageStatsObserver;
34import android.content.pm.InstrumentationInfo;
35import android.content.pm.PackageInfo;
36import android.content.pm.PackageManager.NameNotFoundException;
37import android.content.pm.PackageManager;
38import android.content.pm.ParceledListSlice;
39import android.content.pm.PermissionGroupInfo;
40import android.content.pm.PermissionInfo;
41import android.content.pm.ProviderInfo;
42import android.content.pm.ResolveInfo;
43import android.content.pm.ServiceInfo;
44import android.content.res.Resources;
45import android.content.res.XmlResourceParser;
46import android.graphics.drawable.Drawable;
47import android.net.Uri;
48import android.os.Parcel;
49import android.os.Process;
50import android.os.RemoteException;
51import android.util.Log;
52
53import java.lang.ref.WeakReference;
54import java.util.ArrayList;
55import java.util.HashMap;
56import java.util.Iterator;
57import java.util.List;
58
59/*package*/
60final class ApplicationPackageManager extends PackageManager {
61    private static final String TAG = "ApplicationPackageManager";
62    private final static boolean DEBUG = false;
63    private final static boolean DEBUG_ICONS = false;
64
65    @Override
66    public PackageInfo getPackageInfo(String packageName, int flags)
67            throws NameNotFoundException {
68        try {
69            PackageInfo pi = mPM.getPackageInfo(packageName, flags);
70            if (pi != null) {
71                return pi;
72            }
73        } catch (RemoteException e) {
74            throw new RuntimeException("Package manager has died", e);
75        }
76
77        throw new NameNotFoundException(packageName);
78    }
79
80    @Override
81    public String[] currentToCanonicalPackageNames(String[] names) {
82        try {
83            return mPM.currentToCanonicalPackageNames(names);
84        } catch (RemoteException e) {
85            throw new RuntimeException("Package manager has died", e);
86        }
87    }
88
89    @Override
90    public String[] canonicalToCurrentPackageNames(String[] names) {
91        try {
92            return mPM.canonicalToCurrentPackageNames(names);
93        } catch (RemoteException e) {
94            throw new RuntimeException("Package manager has died", e);
95        }
96    }
97
98    @Override
99    public Intent getLaunchIntentForPackage(String packageName) {
100        // First see if the package has an INFO activity; the existence of
101        // such an activity is implied to be the desired front-door for the
102        // overall package (such as if it has multiple launcher entries).
103        Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
104        intentToResolve.addCategory(Intent.CATEGORY_INFO);
105        intentToResolve.setPackage(packageName);
106        List<ResolveInfo> ris = queryIntentActivities(intentToResolve, 0);
107
108        // Otherwise, try to find a main launcher activity.
109        if (ris == null || ris.size() <= 0) {
110            // reuse the intent instance
111            intentToResolve.removeCategory(Intent.CATEGORY_INFO);
112            intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
113            intentToResolve.setPackage(packageName);
114            ris = queryIntentActivities(intentToResolve, 0);
115        }
116        if (ris == null || ris.size() <= 0) {
117            return null;
118        }
119        Intent intent = new Intent(intentToResolve);
120        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
121        intent.setClassName(ris.get(0).activityInfo.packageName,
122                ris.get(0).activityInfo.name);
123        return intent;
124    }
125
126    @Override
127    public int[] getPackageGids(String packageName)
128            throws NameNotFoundException {
129        try {
130            int[] gids = mPM.getPackageGids(packageName);
131            if (gids == null || gids.length > 0) {
132                return gids;
133            }
134        } catch (RemoteException e) {
135            throw new RuntimeException("Package manager has died", e);
136        }
137
138        throw new NameNotFoundException(packageName);
139    }
140
141    @Override
142    public PermissionInfo getPermissionInfo(String name, int flags)
143            throws NameNotFoundException {
144        try {
145            PermissionInfo pi = mPM.getPermissionInfo(name, flags);
146            if (pi != null) {
147                return pi;
148            }
149        } catch (RemoteException e) {
150            throw new RuntimeException("Package manager has died", e);
151        }
152
153        throw new NameNotFoundException(name);
154    }
155
156    @Override
157    public List<PermissionInfo> queryPermissionsByGroup(String group, int flags)
158            throws NameNotFoundException {
159        try {
160            List<PermissionInfo> pi = mPM.queryPermissionsByGroup(group, flags);
161            if (pi != null) {
162                return pi;
163            }
164        } catch (RemoteException e) {
165            throw new RuntimeException("Package manager has died", e);
166        }
167
168        throw new NameNotFoundException(group);
169    }
170
171    @Override
172    public PermissionGroupInfo getPermissionGroupInfo(String name,
173                                                      int flags) throws NameNotFoundException {
174        try {
175            PermissionGroupInfo pgi = mPM.getPermissionGroupInfo(name, flags);
176            if (pgi != null) {
177                return pgi;
178            }
179        } catch (RemoteException e) {
180            throw new RuntimeException("Package manager has died", e);
181        }
182
183        throw new NameNotFoundException(name);
184    }
185
186    @Override
187    public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
188        try {
189            return mPM.getAllPermissionGroups(flags);
190        } catch (RemoteException e) {
191            throw new RuntimeException("Package manager has died", e);
192        }
193    }
194
195    @Override
196    public ApplicationInfo getApplicationInfo(String packageName, int flags)
197            throws NameNotFoundException {
198        try {
199            ApplicationInfo ai = mPM.getApplicationInfo(packageName, flags);
200            if (ai != null) {
201                return ai;
202            }
203        } catch (RemoteException e) {
204            throw new RuntimeException("Package manager has died", e);
205        }
206
207        throw new NameNotFoundException(packageName);
208    }
209
210    @Override
211    public ActivityInfo getActivityInfo(ComponentName className, int flags)
212            throws NameNotFoundException {
213        try {
214            ActivityInfo ai = mPM.getActivityInfo(className, flags);
215            if (ai != null) {
216                return ai;
217            }
218        } catch (RemoteException e) {
219            throw new RuntimeException("Package manager has died", e);
220        }
221
222        throw new NameNotFoundException(className.toString());
223    }
224
225    @Override
226    public ActivityInfo getReceiverInfo(ComponentName className, int flags)
227            throws NameNotFoundException {
228        try {
229            ActivityInfo ai = mPM.getReceiverInfo(className, flags);
230            if (ai != null) {
231                return ai;
232            }
233        } catch (RemoteException e) {
234            throw new RuntimeException("Package manager has died", e);
235        }
236
237        throw new NameNotFoundException(className.toString());
238    }
239
240    @Override
241    public ServiceInfo getServiceInfo(ComponentName className, int flags)
242            throws NameNotFoundException {
243        try {
244            ServiceInfo si = mPM.getServiceInfo(className, flags);
245            if (si != null) {
246                return si;
247            }
248        } catch (RemoteException e) {
249            throw new RuntimeException("Package manager has died", e);
250        }
251
252        throw new NameNotFoundException(className.toString());
253    }
254
255    @Override
256    public ProviderInfo getProviderInfo(ComponentName className, int flags)
257            throws NameNotFoundException {
258        try {
259            ProviderInfo pi = mPM.getProviderInfo(className, flags);
260            if (pi != null) {
261                return pi;
262            }
263        } catch (RemoteException e) {
264            throw new RuntimeException("Package manager has died", e);
265        }
266
267        throw new NameNotFoundException(className.toString());
268    }
269
270    @Override
271    public String[] getSystemSharedLibraryNames() {
272        try {
273            return mPM.getSystemSharedLibraryNames();
274        } catch (RemoteException e) {
275            throw new RuntimeException("Package manager has died", e);
276        }
277    }
278
279    @Override
280    public FeatureInfo[] getSystemAvailableFeatures() {
281        try {
282            return mPM.getSystemAvailableFeatures();
283        } catch (RemoteException e) {
284            throw new RuntimeException("Package manager has died", e);
285        }
286    }
287
288    @Override
289    public boolean hasSystemFeature(String name) {
290        try {
291            return mPM.hasSystemFeature(name);
292        } catch (RemoteException e) {
293            throw new RuntimeException("Package manager has died", e);
294        }
295    }
296
297    @Override
298    public int checkPermission(String permName, String pkgName) {
299        try {
300            return mPM.checkPermission(permName, pkgName);
301        } catch (RemoteException e) {
302            throw new RuntimeException("Package manager has died", e);
303        }
304    }
305
306    @Override
307    public boolean addPermission(PermissionInfo info) {
308        try {
309            return mPM.addPermission(info);
310        } catch (RemoteException e) {
311            throw new RuntimeException("Package manager has died", e);
312        }
313    }
314
315    @Override
316    public boolean addPermissionAsync(PermissionInfo info) {
317        try {
318            return mPM.addPermissionAsync(info);
319        } catch (RemoteException e) {
320            throw new RuntimeException("Package manager has died", e);
321        }
322    }
323
324    @Override
325    public void removePermission(String name) {
326        try {
327            mPM.removePermission(name);
328        } catch (RemoteException e) {
329            throw new RuntimeException("Package manager has died", e);
330        }
331    }
332
333    @Override
334    public int checkSignatures(String pkg1, String pkg2) {
335        try {
336            return mPM.checkSignatures(pkg1, pkg2);
337        } catch (RemoteException e) {
338            throw new RuntimeException("Package manager has died", e);
339        }
340    }
341
342    @Override
343    public int checkSignatures(int uid1, int uid2) {
344        try {
345            return mPM.checkUidSignatures(uid1, uid2);
346        } catch (RemoteException e) {
347            throw new RuntimeException("Package manager has died", e);
348        }
349    }
350
351    @Override
352    public String[] getPackagesForUid(int uid) {
353        try {
354            return mPM.getPackagesForUid(uid);
355        } catch (RemoteException e) {
356            throw new RuntimeException("Package manager has died", e);
357        }
358    }
359
360    @Override
361    public String getNameForUid(int uid) {
362        try {
363            return mPM.getNameForUid(uid);
364        } catch (RemoteException e) {
365            throw new RuntimeException("Package manager has died", e);
366        }
367    }
368
369    @Override
370    public int getUidForSharedUser(String sharedUserName)
371            throws NameNotFoundException {
372        try {
373            int uid = mPM.getUidForSharedUser(sharedUserName);
374            if(uid != -1) {
375                return uid;
376            }
377        } catch (RemoteException e) {
378            throw new RuntimeException("Package manager has died", e);
379        }
380        throw new NameNotFoundException("No shared userid for user:"+sharedUserName);
381    }
382
383    @SuppressWarnings("unchecked")
384    @Override
385    public List<PackageInfo> getInstalledPackages(int flags) {
386        try {
387            final List<PackageInfo> packageInfos = new ArrayList<PackageInfo>();
388            PackageInfo lastItem = null;
389            ParceledListSlice<PackageInfo> slice;
390
391            do {
392                final String lastKey = lastItem != null ? lastItem.packageName : null;
393                slice = mPM.getInstalledPackages(flags, lastKey);
394                lastItem = slice.populateList(packageInfos, PackageInfo.CREATOR);
395            } while (!slice.isLastSlice());
396
397            return packageInfos;
398        } catch (RemoteException e) {
399            throw new RuntimeException("Package manager has died", e);
400        }
401    }
402
403    @SuppressWarnings("unchecked")
404    @Override
405    public List<ApplicationInfo> getInstalledApplications(int flags) {
406        try {
407            final List<ApplicationInfo> applicationInfos = new ArrayList<ApplicationInfo>();
408            ApplicationInfo lastItem = null;
409            ParceledListSlice<ApplicationInfo> slice;
410
411            do {
412                final String lastKey = lastItem != null ? lastItem.packageName : null;
413                slice = mPM.getInstalledApplications(flags, lastKey);
414                lastItem = slice.populateList(applicationInfos, ApplicationInfo.CREATOR);
415            } while (!slice.isLastSlice());
416
417            return applicationInfos;
418        } catch (RemoteException e) {
419            throw new RuntimeException("Package manager has died", e);
420        }
421    }
422
423    @Override
424    public ResolveInfo resolveActivity(Intent intent, int flags) {
425        try {
426            return mPM.resolveIntent(
427                intent,
428                intent.resolveTypeIfNeeded(mContext.getContentResolver()),
429                flags);
430        } catch (RemoteException e) {
431            throw new RuntimeException("Package manager has died", e);
432        }
433    }
434
435    @Override
436    public List<ResolveInfo> queryIntentActivities(Intent intent,
437                                                   int flags) {
438        try {
439            return mPM.queryIntentActivities(
440                intent,
441                intent.resolveTypeIfNeeded(mContext.getContentResolver()),
442                flags);
443        } catch (RemoteException e) {
444            throw new RuntimeException("Package manager has died", e);
445        }
446    }
447
448    @Override
449    public List<ResolveInfo> queryIntentActivityOptions(
450        ComponentName caller, Intent[] specifics, Intent intent,
451        int flags) {
452        final ContentResolver resolver = mContext.getContentResolver();
453
454        String[] specificTypes = null;
455        if (specifics != null) {
456            final int N = specifics.length;
457            for (int i=0; i<N; i++) {
458                Intent sp = specifics[i];
459                if (sp != null) {
460                    String t = sp.resolveTypeIfNeeded(resolver);
461                    if (t != null) {
462                        if (specificTypes == null) {
463                            specificTypes = new String[N];
464                        }
465                        specificTypes[i] = t;
466                    }
467                }
468            }
469        }
470
471        try {
472            return mPM.queryIntentActivityOptions(caller, specifics,
473                                                  specificTypes, intent, intent.resolveTypeIfNeeded(resolver),
474                                                  flags);
475        } catch (RemoteException e) {
476            throw new RuntimeException("Package manager has died", e);
477        }
478    }
479
480    @Override
481    public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags) {
482        try {
483            return mPM.queryIntentReceivers(
484                intent,
485                intent.resolveTypeIfNeeded(mContext.getContentResolver()),
486                flags);
487        } catch (RemoteException e) {
488            throw new RuntimeException("Package manager has died", e);
489        }
490    }
491
492    @Override
493    public ResolveInfo resolveService(Intent intent, int flags) {
494        try {
495            return mPM.resolveService(
496                intent,
497                intent.resolveTypeIfNeeded(mContext.getContentResolver()),
498                flags);
499        } catch (RemoteException e) {
500            throw new RuntimeException("Package manager has died", e);
501        }
502    }
503
504    @Override
505    public List<ResolveInfo> queryIntentServices(Intent intent, int flags) {
506        try {
507            return mPM.queryIntentServices(
508                intent,
509                intent.resolveTypeIfNeeded(mContext.getContentResolver()),
510                flags);
511        } catch (RemoteException e) {
512            throw new RuntimeException("Package manager has died", e);
513        }
514    }
515
516    @Override
517    public ProviderInfo resolveContentProvider(String name,
518                                               int flags) {
519        try {
520            return mPM.resolveContentProvider(name, flags);
521        } catch (RemoteException e) {
522            throw new RuntimeException("Package manager has died", e);
523        }
524    }
525
526    @Override
527    public List<ProviderInfo> queryContentProviders(String processName,
528                                                    int uid, int flags) {
529        try {
530            return mPM.queryContentProviders(processName, uid, flags);
531        } catch (RemoteException e) {
532            throw new RuntimeException("Package manager has died", e);
533        }
534    }
535
536    @Override
537    public InstrumentationInfo getInstrumentationInfo(
538        ComponentName className, int flags)
539            throws NameNotFoundException {
540        try {
541            InstrumentationInfo ii = mPM.getInstrumentationInfo(
542                className, flags);
543            if (ii != null) {
544                return ii;
545            }
546        } catch (RemoteException e) {
547            throw new RuntimeException("Package manager has died", e);
548        }
549
550        throw new NameNotFoundException(className.toString());
551    }
552
553    @Override
554    public List<InstrumentationInfo> queryInstrumentation(
555        String targetPackage, int flags) {
556        try {
557            return mPM.queryInstrumentation(targetPackage, flags);
558        } catch (RemoteException e) {
559            throw new RuntimeException("Package manager has died", e);
560        }
561    }
562
563    @Override public Drawable getDrawable(String packageName, int resid,
564                                          ApplicationInfo appInfo) {
565        ResourceName name = new ResourceName(packageName, resid);
566        Drawable dr = getCachedIcon(name);
567        if (dr != null) {
568            return dr;
569        }
570        if (appInfo == null) {
571            try {
572                appInfo = getApplicationInfo(packageName, 0);
573            } catch (NameNotFoundException e) {
574                return null;
575            }
576        }
577        try {
578            Resources r = getResourcesForApplication(appInfo);
579            dr = r.getDrawable(resid);
580            if (false) {
581                RuntimeException e = new RuntimeException("here");
582                e.fillInStackTrace();
583                Log.w(TAG, "Getting drawable 0x" + Integer.toHexString(resid)
584                      + " from package " + packageName
585                      + ": app scale=" + r.getCompatibilityInfo().applicationScale
586                      + ", caller scale=" + mContext.getResources().getCompatibilityInfo().applicationScale,
587                      e);
588            }
589            if (DEBUG_ICONS) Log.v(TAG, "Getting drawable 0x"
590                                   + Integer.toHexString(resid) + " from " + r
591                                   + ": " + dr);
592            putCachedIcon(name, dr);
593            return dr;
594        } catch (NameNotFoundException e) {
595            Log.w("PackageManager", "Failure retrieving resources for"
596                  + appInfo.packageName);
597        } catch (Resources.NotFoundException e) {
598            Log.w("PackageManager", "Failure retrieving resources for"
599                  + appInfo.packageName + ": " + e.getMessage());
600        } catch (RuntimeException e) {
601            // If an exception was thrown, fall through to return
602            // default icon.
603            Log.w("PackageManager", "Failure retrieving icon 0x"
604                  + Integer.toHexString(resid) + " in package "
605                  + packageName, e);
606        }
607        return null;
608    }
609
610    @Override public Drawable getActivityIcon(ComponentName activityName)
611            throws NameNotFoundException {
612        return getActivityInfo(activityName, 0).loadIcon(this);
613    }
614
615    @Override public Drawable getActivityIcon(Intent intent)
616            throws NameNotFoundException {
617        if (intent.getComponent() != null) {
618            return getActivityIcon(intent.getComponent());
619        }
620
621        ResolveInfo info = resolveActivity(
622            intent, PackageManager.MATCH_DEFAULT_ONLY);
623        if (info != null) {
624            return info.activityInfo.loadIcon(this);
625        }
626
627        throw new NameNotFoundException(intent.toURI());
628    }
629
630    @Override public Drawable getDefaultActivityIcon() {
631        return Resources.getSystem().getDrawable(
632            com.android.internal.R.drawable.sym_def_app_icon);
633    }
634
635    @Override public Drawable getApplicationIcon(ApplicationInfo info) {
636        return info.loadIcon(this);
637    }
638
639    @Override public Drawable getApplicationIcon(String packageName)
640            throws NameNotFoundException {
641        return getApplicationIcon(getApplicationInfo(packageName, 0));
642    }
643
644    @Override
645    public Drawable getActivityLogo(ComponentName activityName)
646            throws NameNotFoundException {
647        return getActivityInfo(activityName, 0).loadLogo(this);
648    }
649
650    @Override
651    public Drawable getActivityLogo(Intent intent)
652            throws NameNotFoundException {
653        if (intent.getComponent() != null) {
654            return getActivityLogo(intent.getComponent());
655        }
656
657        ResolveInfo info = resolveActivity(
658            intent, PackageManager.MATCH_DEFAULT_ONLY);
659        if (info != null) {
660            return info.activityInfo.loadLogo(this);
661        }
662
663        throw new NameNotFoundException(intent.toUri(0));
664    }
665
666    @Override
667    public Drawable getApplicationLogo(ApplicationInfo info) {
668        return info.loadLogo(this);
669    }
670
671    @Override
672    public Drawable getApplicationLogo(String packageName)
673            throws NameNotFoundException {
674        return getApplicationLogo(getApplicationInfo(packageName, 0));
675    }
676
677    @Override public Resources getResourcesForActivity(
678        ComponentName activityName) throws NameNotFoundException {
679        return getResourcesForApplication(
680            getActivityInfo(activityName, 0).applicationInfo);
681    }
682
683    @Override public Resources getResourcesForApplication(
684        ApplicationInfo app) throws NameNotFoundException {
685        if (app.packageName.equals("system")) {
686            return mContext.mMainThread.getSystemContext().getResources();
687        }
688        Resources r = mContext.mMainThread.getTopLevelResources(
689            app.uid == Process.myUid() ? app.sourceDir
690            : app.publicSourceDir, mContext.mPackageInfo);
691        if (r != null) {
692            return r;
693        }
694        throw new NameNotFoundException("Unable to open " + app.publicSourceDir);
695    }
696
697    @Override public Resources getResourcesForApplication(
698        String appPackageName) throws NameNotFoundException {
699        return getResourcesForApplication(
700            getApplicationInfo(appPackageName, 0));
701    }
702
703    int mCachedSafeMode = -1;
704    @Override public boolean isSafeMode() {
705        try {
706            if (mCachedSafeMode < 0) {
707                mCachedSafeMode = mPM.isSafeMode() ? 1 : 0;
708            }
709            return mCachedSafeMode != 0;
710        } catch (RemoteException e) {
711            throw new RuntimeException("Package manager has died", e);
712        }
713    }
714
715    static void configurationChanged() {
716        synchronized (sSync) {
717            sIconCache.clear();
718            sStringCache.clear();
719        }
720    }
721
722    ApplicationPackageManager(ContextImpl context,
723                              IPackageManager pm) {
724        mContext = context;
725        mPM = pm;
726    }
727
728    private Drawable getCachedIcon(ResourceName name) {
729        synchronized (sSync) {
730            WeakReference<Drawable> wr = sIconCache.get(name);
731            if (DEBUG_ICONS) Log.v(TAG, "Get cached weak drawable ref for "
732                                   + name + ": " + wr);
733            if (wr != null) {   // we have the activity
734                Drawable dr = wr.get();
735                if (dr != null) {
736                    if (DEBUG_ICONS) Log.v(TAG, "Get cached drawable for "
737                                           + name + ": " + dr);
738                    return dr;
739                }
740                // our entry has been purged
741                sIconCache.remove(name);
742            }
743        }
744        return null;
745    }
746
747    private void putCachedIcon(ResourceName name, Drawable dr) {
748        synchronized (sSync) {
749            sIconCache.put(name, new WeakReference<Drawable>(dr));
750            if (DEBUG_ICONS) Log.v(TAG, "Added cached drawable for "
751                                   + name + ": " + dr);
752        }
753    }
754
755    static final void handlePackageBroadcast(int cmd, String[] pkgList,
756                                             boolean hasPkgInfo) {
757        boolean immediateGc = false;
758        if (cmd == IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE) {
759            immediateGc = true;
760        }
761        if (pkgList != null && (pkgList.length > 0)) {
762            boolean needCleanup = false;
763            for (String ssp : pkgList) {
764                synchronized (sSync) {
765                    if (sIconCache.size() > 0) {
766                        Iterator<ResourceName> it = sIconCache.keySet().iterator();
767                        while (it.hasNext()) {
768                            ResourceName nm = it.next();
769                            if (nm.packageName.equals(ssp)) {
770                                //Log.i(TAG, "Removing cached drawable for " + nm);
771                                it.remove();
772                                needCleanup = true;
773                            }
774                        }
775                    }
776                    if (sStringCache.size() > 0) {
777                        Iterator<ResourceName> it = sStringCache.keySet().iterator();
778                        while (it.hasNext()) {
779                            ResourceName nm = it.next();
780                            if (nm.packageName.equals(ssp)) {
781                                //Log.i(TAG, "Removing cached string for " + nm);
782                                it.remove();
783                                needCleanup = true;
784                            }
785                        }
786                    }
787                }
788            }
789            if (needCleanup || hasPkgInfo) {
790                if (immediateGc) {
791                    // Schedule an immediate gc.
792                    Runtime.getRuntime().gc();
793                } else {
794                    ActivityThread.currentActivityThread().scheduleGcIdler();
795                }
796            }
797        }
798    }
799
800    private static final class ResourceName {
801        final String packageName;
802        final int iconId;
803
804        ResourceName(String _packageName, int _iconId) {
805            packageName = _packageName;
806            iconId = _iconId;
807        }
808
809        ResourceName(ApplicationInfo aInfo, int _iconId) {
810            this(aInfo.packageName, _iconId);
811        }
812
813        ResourceName(ComponentInfo cInfo, int _iconId) {
814            this(cInfo.applicationInfo.packageName, _iconId);
815        }
816
817        ResourceName(ResolveInfo rInfo, int _iconId) {
818            this(rInfo.activityInfo.applicationInfo.packageName, _iconId);
819        }
820
821        @Override
822        public boolean equals(Object o) {
823            if (this == o) return true;
824            if (o == null || getClass() != o.getClass()) return false;
825
826            ResourceName that = (ResourceName) o;
827
828            if (iconId != that.iconId) return false;
829            return !(packageName != null ?
830                     !packageName.equals(that.packageName) : that.packageName != null);
831
832        }
833
834        @Override
835        public int hashCode() {
836            int result;
837            result = packageName.hashCode();
838            result = 31 * result + iconId;
839            return result;
840        }
841
842        @Override
843        public String toString() {
844            return "{ResourceName " + packageName + " / " + iconId + "}";
845        }
846    }
847
848    private CharSequence getCachedString(ResourceName name) {
849        synchronized (sSync) {
850            WeakReference<CharSequence> wr = sStringCache.get(name);
851            if (wr != null) {   // we have the activity
852                CharSequence cs = wr.get();
853                if (cs != null) {
854                    return cs;
855                }
856                // our entry has been purged
857                sStringCache.remove(name);
858            }
859        }
860        return null;
861    }
862
863    private void putCachedString(ResourceName name, CharSequence cs) {
864        synchronized (sSync) {
865            sStringCache.put(name, new WeakReference<CharSequence>(cs));
866        }
867    }
868
869    @Override
870    public CharSequence getText(String packageName, int resid,
871                                ApplicationInfo appInfo) {
872        ResourceName name = new ResourceName(packageName, resid);
873        CharSequence text = getCachedString(name);
874        if (text != null) {
875            return text;
876        }
877        if (appInfo == null) {
878            try {
879                appInfo = getApplicationInfo(packageName, 0);
880            } catch (NameNotFoundException e) {
881                return null;
882            }
883        }
884        try {
885            Resources r = getResourcesForApplication(appInfo);
886            text = r.getText(resid);
887            putCachedString(name, text);
888            return text;
889        } catch (NameNotFoundException e) {
890            Log.w("PackageManager", "Failure retrieving resources for"
891                  + appInfo.packageName);
892        } catch (RuntimeException e) {
893            // If an exception was thrown, fall through to return
894            // default icon.
895            Log.w("PackageManager", "Failure retrieving text 0x"
896                  + Integer.toHexString(resid) + " in package "
897                  + packageName, e);
898        }
899        return null;
900    }
901
902    @Override
903    public XmlResourceParser getXml(String packageName, int resid,
904                                    ApplicationInfo appInfo) {
905        if (appInfo == null) {
906            try {
907                appInfo = getApplicationInfo(packageName, 0);
908            } catch (NameNotFoundException e) {
909                return null;
910            }
911        }
912        try {
913            Resources r = getResourcesForApplication(appInfo);
914            return r.getXml(resid);
915        } catch (RuntimeException e) {
916            // If an exception was thrown, fall through to return
917            // default icon.
918            Log.w("PackageManager", "Failure retrieving xml 0x"
919                  + Integer.toHexString(resid) + " in package "
920                  + packageName, e);
921        } catch (NameNotFoundException e) {
922            Log.w("PackageManager", "Failure retrieving resources for "
923                  + appInfo.packageName);
924        }
925        return null;
926    }
927
928    @Override
929    public CharSequence getApplicationLabel(ApplicationInfo info) {
930        return info.loadLabel(this);
931    }
932
933    @Override
934    public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
935                               String installerPackageName) {
936        try {
937            mPM.installPackage(packageURI, observer, flags, installerPackageName);
938        } catch (RemoteException e) {
939            // Should never happen!
940        }
941    }
942
943    @Override
944    public void setInstallerPackageName(String targetPackage,
945            String installerPackageName) {
946        try {
947            mPM.setInstallerPackageName(targetPackage, installerPackageName);
948        } catch (RemoteException e) {
949            // Should never happen!
950        }
951    }
952
953    @Override
954    public void movePackage(String packageName, IPackageMoveObserver observer, int flags) {
955        try {
956            mPM.movePackage(packageName, observer, flags);
957        } catch (RemoteException e) {
958            // Should never happen!
959        }
960    }
961
962    @Override
963    public String getInstallerPackageName(String packageName) {
964        try {
965            return mPM.getInstallerPackageName(packageName);
966        } catch (RemoteException e) {
967            // Should never happen!
968        }
969        return null;
970    }
971
972    @Override
973    public void deletePackage(String packageName, IPackageDeleteObserver observer, int flags) {
974        try {
975            mPM.deletePackage(packageName, observer, flags);
976        } catch (RemoteException e) {
977            // Should never happen!
978        }
979    }
980    @Override
981    public void clearApplicationUserData(String packageName,
982                                         IPackageDataObserver observer) {
983        try {
984            mPM.clearApplicationUserData(packageName, observer);
985        } catch (RemoteException e) {
986            // Should never happen!
987        }
988    }
989    @Override
990    public void deleteApplicationCacheFiles(String packageName,
991                                            IPackageDataObserver observer) {
992        try {
993            mPM.deleteApplicationCacheFiles(packageName, observer);
994        } catch (RemoteException e) {
995            // Should never happen!
996        }
997    }
998    @Override
999    public void freeStorageAndNotify(long idealStorageSize, IPackageDataObserver observer) {
1000        try {
1001            mPM.freeStorageAndNotify(idealStorageSize, observer);
1002        } catch (RemoteException e) {
1003            // Should never happen!
1004        }
1005    }
1006
1007    @Override
1008    public void freeStorage(long freeStorageSize, IntentSender pi) {
1009        try {
1010            mPM.freeStorage(freeStorageSize, pi);
1011        } catch (RemoteException e) {
1012            // Should never happen!
1013        }
1014    }
1015
1016    @Override
1017    public void getPackageSizeInfo(String packageName,
1018                                   IPackageStatsObserver observer) {
1019        try {
1020            mPM.getPackageSizeInfo(packageName, observer);
1021        } catch (RemoteException e) {
1022            // Should never happen!
1023        }
1024    }
1025    @Override
1026    public void addPackageToPreferred(String packageName) {
1027        try {
1028            mPM.addPackageToPreferred(packageName);
1029        } catch (RemoteException e) {
1030            // Should never happen!
1031        }
1032    }
1033
1034    @Override
1035    public void removePackageFromPreferred(String packageName) {
1036        try {
1037            mPM.removePackageFromPreferred(packageName);
1038        } catch (RemoteException e) {
1039            // Should never happen!
1040        }
1041    }
1042
1043    @Override
1044    public List<PackageInfo> getPreferredPackages(int flags) {
1045        try {
1046            return mPM.getPreferredPackages(flags);
1047        } catch (RemoteException e) {
1048            // Should never happen!
1049        }
1050        return new ArrayList<PackageInfo>();
1051    }
1052
1053    @Override
1054    public void addPreferredActivity(IntentFilter filter,
1055                                     int match, ComponentName[] set, ComponentName activity) {
1056        try {
1057            mPM.addPreferredActivity(filter, match, set, activity);
1058        } catch (RemoteException e) {
1059            // Should never happen!
1060        }
1061    }
1062
1063    @Override
1064    public void replacePreferredActivity(IntentFilter filter,
1065                                         int match, ComponentName[] set, ComponentName activity) {
1066        try {
1067            mPM.replacePreferredActivity(filter, match, set, activity);
1068        } catch (RemoteException e) {
1069            // Should never happen!
1070        }
1071    }
1072
1073    @Override
1074    public void clearPackagePreferredActivities(String packageName) {
1075        try {
1076            mPM.clearPackagePreferredActivities(packageName);
1077        } catch (RemoteException e) {
1078            // Should never happen!
1079        }
1080    }
1081
1082    @Override
1083    public int getPreferredActivities(List<IntentFilter> outFilters,
1084                                      List<ComponentName> outActivities, String packageName) {
1085        try {
1086            return mPM.getPreferredActivities(outFilters, outActivities, packageName);
1087        } catch (RemoteException e) {
1088            // Should never happen!
1089        }
1090        return 0;
1091    }
1092
1093    @Override
1094    public void setComponentEnabledSetting(ComponentName componentName,
1095                                           int newState, int flags) {
1096        try {
1097            mPM.setComponentEnabledSetting(componentName, newState, flags);
1098        } catch (RemoteException e) {
1099            // Should never happen!
1100        }
1101    }
1102
1103    @Override
1104    public int getComponentEnabledSetting(ComponentName componentName) {
1105        try {
1106            return mPM.getComponentEnabledSetting(componentName);
1107        } catch (RemoteException e) {
1108            // Should never happen!
1109        }
1110        return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
1111    }
1112
1113    @Override
1114    public void setApplicationEnabledSetting(String packageName,
1115                                             int newState, int flags) {
1116        try {
1117            mPM.setApplicationEnabledSetting(packageName, newState, flags);
1118        } catch (RemoteException e) {
1119            // Should never happen!
1120        }
1121    }
1122
1123    @Override
1124    public int getApplicationEnabledSetting(String packageName) {
1125        try {
1126            return mPM.getApplicationEnabledSetting(packageName);
1127        } catch (RemoteException e) {
1128            // Should never happen!
1129        }
1130        return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
1131    }
1132
1133    private final ContextImpl mContext;
1134    private final IPackageManager mPM;
1135
1136    private static final Object sSync = new Object();
1137    private static HashMap<ResourceName, WeakReference<Drawable> > sIconCache
1138            = new HashMap<ResourceName, WeakReference<Drawable> >();
1139    private static HashMap<ResourceName, WeakReference<CharSequence> > sStringCache
1140            = new HashMap<ResourceName, WeakReference<CharSequence> >();
1141}
1142