Loading core/java/android/content/pm/RegisteredServicesCache.java +62 −7 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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 Loading Loading @@ -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; Loading Loading @@ -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); Loading @@ -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); Loading Loading @@ -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; } } } core/java/android/content/pm/flags.aconfig +8 −0 Original line number Diff line number Diff line Loading @@ -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 } core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java +3 −2 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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); Loading Loading
core/java/android/content/pm/RegisteredServicesCache.java +62 −7 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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 Loading Loading @@ -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; Loading Loading @@ -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); Loading @@ -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); Loading Loading @@ -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; } } }
core/java/android/content/pm/flags.aconfig +8 −0 Original line number Diff line number Diff line Loading @@ -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 }
core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java +3 −2 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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); Loading