diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java index fb77d101f9109..05567480e6bf9 100644 --- a/services/core/java/com/android/server/pm/ApexManager.java +++ b/services/core/java/com/android/server/pm/ApexManager.java @@ -34,6 +34,7 @@ import android.content.pm.PackageManager; import android.content.pm.SigningDetails; import android.content.pm.parsing.PackageInfoWithoutStateUtils; import android.content.pm.parsing.ParsingPackageUtils; +import android.content.pm.parsing.component.ParsedApexSystemService; import android.content.pm.parsing.result.ParseResult; import android.content.pm.parsing.result.ParseTypeImpl; import android.os.Binder; @@ -53,6 +54,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; +import com.android.modules.utils.build.UnboundedSdkLevel; import com.android.server.pm.parsing.PackageParser2; import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.parsing.pkg.ParsedPackage; @@ -410,6 +412,11 @@ public abstract class ApexManager { abstract void installPackage(File apexFile, PackageParser2 packageParser) throws PackageManagerException; + /** + * Get a map of system services defined in an apex mapped to the jar files they reside in. + */ + public abstract Map getApexSystemServices(); + /** * Dumps various state information to the provided {@link PrintWriter} object. * @@ -437,6 +444,12 @@ public abstract class ApexManager { @GuardedBy("mLock") private Set mActiveApexInfosCache; + /** + * Map of all apex system services to the jar files they are contained in. + */ + @GuardedBy("mLock") + private Map mApexSystemServices = new ArrayMap<>(); + /** * Contains the list of {@code packageName}s of apks-in-apex for given * {@code apexModuleName}. See {@link #mPackageNameToApexModuleName} to understand the @@ -573,6 +586,32 @@ public abstract class ApexManager { + ai.modulePath); } mAllPackagesCache.add(packageInfo); + for (ParsedApexSystemService service : + parseResult.parsedPackage.getApexSystemServices()) { + String minSdkVersion = service.getMinSdkVersion(); + if (minSdkVersion != null && !UnboundedSdkLevel.isAtLeast(minSdkVersion)) { + Slog.d(TAG, String.format( + "ApexSystemService %s with min_sdk_version=%s is skipped", + service.getName(), service.getMinSdkVersion())); + continue; + } + String maxSdkVersion = service.getMaxSdkVersion(); + if (maxSdkVersion != null && !UnboundedSdkLevel.isAtMost(maxSdkVersion)) { + Slog.d(TAG, String.format( + "ApexSystemService %s with max_sdk_version=%s is skipped", + service.getName(), service.getMaxSdkVersion())); + continue; + } + + String name = service.getName(); + if (mApexSystemServices.containsKey(name)) { + throw new IllegalStateException(String.format( + "Duplicate apex-system-service %s from %s, %s", + name, mApexSystemServices.get(name), service.getJarPath())); + } + + mApexSystemServices.put(name, service.getJarPath()); + } mPackageNameToApexModuleName.put(packageInfo.packageName, ai.moduleName); if (ai.isActive) { if (activePackagesSet.contains(packageInfo.packageName)) { @@ -1092,6 +1131,15 @@ public abstract class ApexManager { } } + @Override + public Map getApexSystemServices() { + synchronized (mLock) { + Preconditions.checkState(mApexSystemServices != null, + "APEX packages have not been scanned"); + return mApexSystemServices; + } + } + /** * Dump information about the packages contained in a particular cache * @param packagesCache the cache to print information about. @@ -1369,6 +1417,13 @@ public abstract class ApexManager { throw new UnsupportedOperationException("APEX updates are not supported"); } + @Override + public Map getApexSystemServices() { + // TODO(satayev): we can't really support flattened apex use case, and need to migrate + // the manifest entries into system's manifest asap. + return Collections.emptyMap(); + } + @Override void dump(PrintWriter pw, String packageName) { // No-op diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java index 847fe2ecf52dc..7f7c716bc1f05 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java @@ -61,6 +61,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.Map; @SmallTest @Presubmit @@ -129,6 +130,17 @@ public class ApexManagerTest { assertThat(mApexManager.getPackageInfo(TEST_APEX_PKG, 0)).isNull(); } + @Test + public void testGetApexSystemServices() throws RemoteException { + when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(true, false)); + mApexManager.scanApexPackagesTraced(mPackageParser2, + ParallelPackageParser.makeExecutorService()); + + Map services = mApexManager.getApexSystemServices(); + assertThat(services).hasSize(1); + assertThat(services).containsKey("com.android.apex.test.ApexSystemService"); + } + @Test public void testGetActivePackages() throws RemoteException { when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(true, true));