Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 460a7b46 authored by Amith Yamasani's avatar Amith Yamasani
Browse files

Limit cache update to packages that have changed

When updating the RegisteredServicesCache, don't remove any packages
that are not in the list of modified packages.

Bug: 19228972
Change-Id: Id4f264403b7ceca9005854dfbbc25abfd7b54889
parent f789d45b
Loading
Loading
Loading
Loading
+43 −9
Original line number Diff line number Diff line
@@ -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,8 +424,19 @@ 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 + "): " +
@@ -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)) {