OSDN Git Service

Limit cache update to packages that have changed
authorAmith Yamasani <yamasani@google.com>
Fri, 6 Feb 2015 22:41:40 +0000 (14:41 -0800)
committerAmith Yamasani <yamasani@google.com>
Mon, 9 Feb 2015 19:10:31 +0000 (11:10 -0800)
When updating the RegisteredServicesCache, don't remove any packages
that are not in the list of modified packages.

Bug: 19228972
Change-Id: Id4f264403b7ceca9005854dfbbc25abfd7b54889

core/java/android/content/pm/RegisteredServicesCache.java

index 4a743a5..391ef22 100644 (file)
@@ -35,6 +35,7 @@ import android.util.SparseArray;
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
@@ -155,9 +156,19 @@ public abstract class RegisteredServicesCache<V> {
             // package is going away, but it's the middle of an upgrade: keep the current
             // state and do nothing here.  This clause is intentionally empty.
         } else {
+            int[] uids = null;
             // either we're adding/changing, or it's a removal without replacement, so
-            // we need to recalculate the set of available services
-            generateServicesMap(userId);
+            // we need to update the set of available services
+            if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)
+                    || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
+                uids = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
+            } else {
+                int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+                if (uid > 0) {
+                    uids = new int[] { uid };
+                }
+            }
+            generateServicesMap(uids, userId);
         }
     }
 
@@ -270,7 +281,7 @@ public abstract class RegisteredServicesCache<V> {
             // Find user and lazily populate cache
             final UserServices<V> user = findOrCreateUserLocked(userId);
             if (user.services == null) {
-                generateServicesMap(userId);
+                generateServicesMap(null, userId);
             }
             return user.services.get(type);
         }
@@ -285,7 +296,7 @@ public abstract class RegisteredServicesCache<V> {
             // Find user and lazily populate cache
             final UserServices<V> user = findOrCreateUserLocked(userId);
             if (user.services == null) {
-                generateServicesMap(userId);
+                generateServicesMap(null, userId);
             }
             return Collections.unmodifiableCollection(
                     new ArrayList<ServiceInfo<V>>(user.services.values()));
@@ -311,10 +322,13 @@ public abstract class RegisteredServicesCache<V> {
     /**
      * Populate {@link UserServices#services} by scanning installed packages for
      * given {@link UserHandle}.
+     * @param changedUids the array of uids that have been affected, as mentioned in the broadcast
+     *                    or null to assume that everything is affected.
+     * @param userId the user for whom to update the services map.
      */
-    private void generateServicesMap(int userId) {
+    private void generateServicesMap(int[] changedUids, int userId) {
         if (DEBUG) {
-            Slog.d(TAG, "generateServicesMap() for " + userId);
+            Slog.d(TAG, "generateServicesMap() for " + userId + ", changed UIDs = " + changedUids);
         }
 
         final PackageManager pm = mContext.getPackageManager();
@@ -341,8 +355,6 @@ public abstract class RegisteredServicesCache<V> {
             final boolean firstScan = user.services == null;
             if (firstScan) {
                 user.services = Maps.newHashMap();
-            } else {
-                user.services.clear();
             }
 
             StringBuilder changes = new StringBuilder();
@@ -399,7 +411,10 @@ public abstract class RegisteredServicesCache<V> {
 
             ArrayList<V> toBeRemoved = Lists.newArrayList();
             for (V v1 : user.persistentServices.keySet()) {
-                if (!containsType(serviceInfos, v1)) {
+                // Remove a persisted service that's not in the currently available services list.
+                // And only if it is in the list of changedUids.
+                if (!containsType(serviceInfos, v1)
+                        && containsUid(changedUids, user.persistentServices.get(v1))) {
                     toBeRemoved.add(v1);
                 }
             }
@@ -409,9 +424,20 @@ public abstract class RegisteredServicesCache<V> {
                 }
                 changed = true;
                 user.persistentServices.remove(v1);
+                user.services.remove(v1);
                 notifyListener(v1, userId, true /* removed */);
             }
             if (DEBUG) {
+                Log.d(TAG, "user.services=");
+                for (V v : user.services.keySet()) {
+                    Log.d(TAG, "  " + v + " " + user.services.get(v));
+                }
+                Log.d(TAG, "user.persistentServices=");
+                for (V v : user.persistentServices.keySet()) {
+                    Log.d(TAG, "  " + v + " " + user.persistentServices.get(v));
+                }
+            }
+            if (DEBUG) {
                 if (changes.length() > 0) {
                     Log.d(TAG, "generateServicesMap(" + mInterfaceName + "): " +
                             serviceInfos.size() + " services:\n" + changes);
@@ -426,6 +452,14 @@ public abstract class RegisteredServicesCache<V> {
         }
     }
 
+    /**
+     * Returns true if the list of changed uids is null (wildcard) or the specified uid
+     * is contained in the list of changed uids.
+     */
+    private boolean containsUid(int[] changedUids, int uid) {
+        return changedUids == null || ArrayUtils.contains(changedUids, uid);
+    }
+
     private boolean containsType(ArrayList<ServiceInfo<V>> serviceInfos, V type) {
         for (int i = 0, N = serviceInfos.size(); i < N; i++) {
             if (serviceInfos.get(i).type.equals(type)) {