summaryrefslogtreecommitdiff
path: root/core/java
diff options
context:
space:
mode:
authorNg Zhi An <zhin@google.com>2019-01-24 13:45:57 -0800
committerZhi An Ng <zhin@google.com>2019-02-12 23:15:52 +0000
commit1033db8ddfb0aafba84e07f08c44139fd1466f52 (patch)
tree507ad3f2b33e44072d6cec8ae4e61e483e39ee0c /core/java
parent8eacbb3396e22c91e3fd88471ae87e7fe44e5385 (diff)
Do not load xml metadata for unchanged packages in RegisteredServicesCache
RegisteredServicesCache caches services in an xml, so the system doesn't have to scan all the apks. Whenever a package is changed (add/remove/replaced), the broadcast receiver in RegisteredServicesCache will refresh this cache by quering all matching services and reading their xml metadata. There is extra work done here, because only the changed package will have services added/removed. The edge case is after a cache is invalidated, we want to query package manager for everything, regardless of what changedUids is (we could have arrived here if invalidateCache is called, and then a package change event fires, before a getAllServices is called to rescan everything). Add a new test to verify that the optimization takes care of the case when the cache is invalidated. Bug: 117755076 Bug: 122912184 Test: atest RegisteredServicesCache Test: dumpsys content # check sync adapters Change-Id: I5c1f57108c4b67d24b198000d57216c63d35290a (cherry picked from commit dc66ef5ed383a889779adcd455826dcd1534ccf9)
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/content/pm/RegisteredServicesCache.java59
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) {