summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/content/pm/RegisteredServicesCache.java69
-rw-r--r--core/java/android/content/pm/flags.aconfig8
-rw-r--r--core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java5
3 files changed, 73 insertions, 9 deletions
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index 0333942b7f3e..9d11710a2cad 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.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -30,6 +31,7 @@ import android.os.Environment;
import android.os.Handler;
import android.os.UserHandle;
import android.os.UserManager;
+import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.AttributeSet;
import android.util.IntArray;
@@ -45,11 +47,11 @@ import com.android.internal.util.ArrayUtils;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
-import libcore.io.IoUtils;
-
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
+import libcore.io.IoUtils;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -94,6 +96,9 @@ public abstract class RegisteredServicesCache<V> {
@GuardedBy("mServicesLock")
private final SparseArray<UserServices<V>> mUserServices = new SparseArray<UserServices<V>>(2);
+ @GuardedBy("mServicesLock")
+ private final ArrayMap<String, ServiceInfo<V>> mServiceInfoCaches = new ArrayMap<>();
+
private static class UserServices<V> {
@GuardedBy("mServicesLock")
final Map<V, Integer> persistentServices = Maps.newHashMap();
@@ -323,13 +328,16 @@ public abstract class RegisteredServicesCache<V> {
public final ComponentName componentName;
@UnsupportedAppUsage
public final int uid;
+ public final long lastUpdateTime;
/** @hide */
- public ServiceInfo(V type, ComponentInfo componentInfo, ComponentName componentName) {
+ public ServiceInfo(V type, ComponentInfo componentInfo, ComponentName componentName,
+ long lastUpdateTime) {
this.type = type;
this.componentInfo = componentInfo;
this.componentName = componentName;
this.uid = (componentInfo != null) ? componentInfo.applicationInfo.uid : -1;
+ this.lastUpdateTime = lastUpdateTime;
}
@Override
@@ -490,7 +498,7 @@ public abstract class RegisteredServicesCache<V> {
final List<ResolveInfo> resolveInfos = queryIntentServices(userId);
for (ResolveInfo resolveInfo : resolveInfos) {
try {
- ServiceInfo<V> info = parseServiceInfo(resolveInfo);
+ ServiceInfo<V> info = parseServiceInfo(resolveInfo, userId);
if (info == null) {
Log.w(TAG, "Unable to load service info " + resolveInfo.toString());
continue;
@@ -638,13 +646,31 @@ public abstract class RegisteredServicesCache<V> {
}
@VisibleForTesting
- protected ServiceInfo<V> parseServiceInfo(ResolveInfo service)
+ protected ServiceInfo<V> parseServiceInfo(ResolveInfo service, int userId)
throws XmlPullParserException, IOException {
android.content.pm.ServiceInfo si = service.serviceInfo;
ComponentName componentName = new ComponentName(si.packageName, si.name);
PackageManager pm = mContext.getPackageManager();
+ // Check if the service has been in the service cache.
+ long lastUpdateTime = -1;
+ if (Flags.optimizeParsingInRegisteredServicesCache()) {
+ try {
+ PackageInfo packageInfo = pm.getPackageInfoAsUser(si.packageName,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
+ lastUpdateTime = packageInfo.lastUpdateTime;
+
+ ServiceInfo<V> serviceInfo = getServiceInfoFromServiceCache(si, lastUpdateTime);
+ if (serviceInfo != null) {
+ return serviceInfo;
+ }
+ } catch (NameNotFoundException | SecurityException e) {
+ Slog.d(TAG, "Fail to get the PackageInfo in parseServiceInfo: " + e);
+ }
+ }
+
XmlResourceParser parser = null;
try {
parser = si.loadXmlMetaData(pm, mMetaDataName);
@@ -670,8 +696,13 @@ public abstract class RegisteredServicesCache<V> {
if (v == null) {
return null;
}
- final android.content.pm.ServiceInfo serviceInfo = service.serviceInfo;
- return new ServiceInfo<V>(v, serviceInfo, componentName);
+ ServiceInfo<V> serviceInfo = new ServiceInfo<V>(v, si, componentName, lastUpdateTime);
+ if (Flags.optimizeParsingInRegisteredServicesCache()) {
+ synchronized (mServicesLock) {
+ mServiceInfoCaches.put(getServiceCacheKey(si), serviceInfo);
+ }
+ }
+ return serviceInfo;
} catch (NameNotFoundException e) {
throw new XmlPullParserException(
"Unable to load resources for pacakge " + si.packageName);
@@ -841,4 +872,28 @@ public abstract class RegisteredServicesCache<V> {
mContext.unregisterReceiver(mExternalReceiver);
mContext.unregisterReceiver(mUserRemovedReceiver);
}
+
+ private static String getServiceCacheKey(@NonNull android.content.pm.ServiceInfo serviceInfo) {
+ StringBuilder sb = new StringBuilder(serviceInfo.packageName);
+ sb.append('-');
+ sb.append(serviceInfo.name);
+ return sb.toString();
+ }
+
+ private ServiceInfo<V> getServiceInfoFromServiceCache(
+ @NonNull android.content.pm.ServiceInfo serviceInfo, long lastUpdateTime) {
+ String serviceCacheKey = getServiceCacheKey(serviceInfo);
+ synchronized (mServicesLock) {
+ ServiceInfo<V> serviceCache = mServiceInfoCaches.get(serviceCacheKey);
+ if (serviceCache == null) {
+ return null;
+ }
+ if (serviceCache.lastUpdateTime == lastUpdateTime) {
+ return serviceCache;
+ }
+ // The service is not latest, remove it from the cache.
+ mServiceInfoCaches.remove(serviceCacheKey);
+ return null;
+ }
+ }
}
diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig
index 7bba06c87813..e4b8c90d381d 100644
--- a/core/java/android/content/pm/flags.aconfig
+++ b/core/java/android/content/pm/flags.aconfig
@@ -383,3 +383,11 @@ flag {
bug: "334024639"
description: "Feature flag to check whether a given UID can access a content provider"
}
+
+flag {
+ name: "optimize_parsing_in_registered_services_cache"
+ namespace: "package_manager_service"
+ description: "Feature flag to optimize RegisteredServicesCache ServiceInfo parsing by using caches."
+ bug: "319137634"
+ is_fixed_read_only: true
+}
diff --git a/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java b/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
index 37ef6cba8814..939bf2ec4b0a 100644
--- a/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
+++ b/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
@@ -207,7 +207,8 @@ public class RegisteredServicesCacheTest extends AndroidTestCase {
final ComponentInfo info = new ComponentInfo();
info.applicationInfo = new ApplicationInfo();
info.applicationInfo.uid = uid;
- return new RegisteredServicesCache.ServiceInfo<>(type, info, null);
+ return new RegisteredServicesCache.ServiceInfo<>(type, info, null /* componentName */,
+ 0 /* lastUpdateTime */);
}
private void assertNotEmptyFileCreated(TestServicesCache cache, int userId) {
@@ -301,7 +302,7 @@ public class RegisteredServicesCacheTest extends AndroidTestCase {
@Override
protected ServiceInfo<TestServiceType> parseServiceInfo(
- ResolveInfo resolveInfo) throws XmlPullParserException, IOException {
+ ResolveInfo resolveInfo, int userId) throws XmlPullParserException, IOException {
int size = mServices.size();
for (int i = 0; i < size; i++) {
Map<ResolveInfo, ServiceInfo<TestServiceType>> map = mServices.valueAt(i);