diff options
Diffstat (limited to 'core/java/android/content/pm/RegisteredServicesCache.java')
-rw-r--r-- | core/java/android/content/pm/RegisteredServicesCache.java | 59 |
1 files changed, 39 insertions, 20 deletions
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java index a8c3b889421b..d7c4439f8258 100644 --- a/core/java/android/content/pm/RegisteredServicesCache.java +++ b/core/java/android/content/pm/RegisteredServicesCache.java @@ -17,6 +17,7 @@ package android.content.pm; import android.Manifest; +import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -176,7 +177,8 @@ public abstract class RegisteredServicesCache<V> { mContext.registerReceiver(mUserRemovedReceiver, userFilter); } - private final void handlePackageEvent(Intent intent, int userId) { + @VisibleForTesting + protected void handlePackageEvent(Intent intent, int userId) { // Don't regenerate the services map when the package is removed or its // ASEC container unmounted as a step in replacement. The subsequent // _ADDED / _AVAILABLE call will regenerate the map in the final state. @@ -238,6 +240,9 @@ public abstract class RegisteredServicesCache<V> { public void invalidateCache(int userId) { synchronized (mServicesLock) { + if (DEBUG) { + Slog.d(TAG, "invalidating cache for " + userId + " " + mInterfaceName); + } final UserServices<V> user = findOrCreateUserLocked(userId); user.services = null; onServicesChangedLocked(userId); @@ -465,34 +470,48 @@ public abstract class RegisteredServicesCache<V> { * or null to assume that everything is affected. * @param userId the user for whom to update the services map. */ - private void generateServicesMap(int[] changedUids, int userId) { + private void generateServicesMap(@Nullable int[] changedUids, int userId) { if (DEBUG) { Slog.d(TAG, "generateServicesMap() for " + userId + ", changed UIDs = " + Arrays.toString(changedUids)); } - final ArrayList<ServiceInfo<V>> serviceInfos = new ArrayList<>(); - final List<ResolveInfo> resolveInfos = queryIntentServices(userId); - for (ResolveInfo resolveInfo : resolveInfos) { - try { - ServiceInfo<V> info = parseServiceInfo(resolveInfo); - if (info == null) { - Log.w(TAG, "Unable to load service info " + resolveInfo.toString()); - continue; - } - serviceInfos.add(info); - } catch (XmlPullParserException|IOException e) { - Log.w(TAG, "Unable to load service info " + resolveInfo.toString(), e); - } - } - synchronized (mServicesLock) { final UserServices<V> user = findOrCreateUserLocked(userId); - final boolean firstScan = user.services == null; - if (firstScan) { + final boolean cacheInvalid = user.services == null; + if (cacheInvalid) { user.services = Maps.newHashMap(); } + final ArrayList<ServiceInfo<V>> serviceInfos = new ArrayList<>(); + final List<ResolveInfo> resolveInfos = queryIntentServices(userId); + + for (ResolveInfo resolveInfo : resolveInfos) { + try { + // when changedUids == null, we want to do a rescan of everything, this means + // it's the initial scan, and containsUid will trivially return true + // when changedUids != null, we got here because a package changed, but + // invalidateCache could have been called (thus user.services == null), and we + // should query from PackageManager again + if (!cacheInvalid + && !containsUid( + changedUids, resolveInfo.serviceInfo.applicationInfo.uid)) { + if (DEBUG) { + Slog.d(TAG, "Skipping parseServiceInfo for " + resolveInfo); + } + continue; + } + ServiceInfo<V> info = parseServiceInfo(resolveInfo); + if (info == null) { + Log.w(TAG, "Unable to load service info " + resolveInfo.toString()); + continue; + } + serviceInfos.add(info); + } catch (XmlPullParserException | IOException e) { + Log.w(TAG, "Unable to load service info " + resolveInfo.toString(), e); + } + } + StringBuilder changes = new StringBuilder(); boolean changed = false; for (ServiceInfo<V> info : serviceInfos) { @@ -513,7 +532,7 @@ public abstract class RegisteredServicesCache<V> { changed = true; user.services.put(info.type, info); user.persistentServices.put(info.type, info.uid); - if (!(user.mPersistentServicesFileDidNotExist && firstScan)) { + if (!(user.mPersistentServicesFileDidNotExist && cacheInvalid)) { notifyListener(info.type, userId, false /* removed */); } } else if (previousUid == info.uid) { |