Loading services/core/java/com/android/server/pm/ApexManager.java +109 −55 Original line number Diff line number Diff line Loading @@ -22,22 +22,21 @@ import android.apex.ApexInfo; import android.apex.ApexInfoList; import android.apex.ApexSessionInfo; import android.apex.IApexService; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageParser; import android.content.pm.PackageParser.PackageParserException; import android.os.HandlerThread; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceManager.ServiceNotFoundException; import android.os.SystemClock; import android.sysprop.ApexProperties; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; import com.android.server.SystemService; import java.io.File; import java.io.PrintWriter; Loading @@ -46,75 +45,108 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.function.Function; import java.util.stream.Collectors; /** * ApexManager class handles communications with the apex service to perform operation and queries, * as well as providing caching to avoid unnecessary calls to the service. * * @hide */ class ApexManager { static final String TAG = "ApexManager"; private final IApexService mApexService; private final Context mContext; private final Object mLock = new Object(); @GuardedBy("mLock") public final class ApexManager extends SystemService { private static final String TAG = "ApexManager"; private IApexService mApexService; private final CountDownLatch mActivePackagesCacheLatch = new CountDownLatch(1); private Map<String, PackageInfo> mActivePackagesCache; ApexManager(Context context) { private final CountDownLatch mApexFilesCacheLatch = new CountDownLatch(1); private ApexInfo[] mApexFiles; public ApexManager(Context context) { super(context); } @Override public void onStart() { try { mApexService = IApexService.Stub.asInterface( ServiceManager.getServiceOrThrow("apexservice")); } catch (ServiceNotFoundException e) { throw new IllegalStateException("Required service apexservice not available"); } mContext = context; publishLocalService(ApexManager.class, this); HandlerThread oneShotThread = new HandlerThread("ApexManagerOneShotHandler"); oneShotThread.start(); oneShotThread.getThreadHandler().post(this::initSequence); oneShotThread.quitSafely(); } void systemReady() { mContext.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { onBootCompleted(); mContext.unregisterReceiver(this); } }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); private void initSequence() { populateApexFilesCache(); parseApexFiles(); } private void populateActivePackagesCacheIfNeeded() { synchronized (mLock) { if (mActivePackagesCache != null) { private void populateApexFilesCache() { if (mApexFiles != null) { return; } long startTimeMicros = SystemClock.currentTimeMicro(); Slog.i(TAG, "Starting to populate apex files cache"); try { mApexFiles = mApexService.getActivePackages(); Slog.i(TAG, "IPC to apexd finished in " + (SystemClock.currentTimeMicro() - startTimeMicros) + " μs"); } catch (RemoteException re) { // TODO: make sure this error is propagated to system server. Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString()); re.rethrowAsRuntimeException(); } mApexFilesCacheLatch.countDown(); Slog.i(TAG, "Finished populating apex files cache in " + (SystemClock.currentTimeMicro() - startTimeMicros) + " μs"); } private void parseApexFiles() { waitForLatch(mApexFilesCacheLatch); if (mApexFiles == null) { throw new IllegalStateException("mApexFiles must be populated"); } long startTimeMicros = SystemClock.currentTimeMicro(); Slog.i(TAG, "Starting to parse apex files"); List<PackageInfo> list = new ArrayList<>(); final ApexInfo[] activePkgs = mApexService.getActivePackages(); for (ApexInfo ai : activePkgs) { // TODO: this can be parallelized. for (ApexInfo ai : mApexFiles) { try { // If the device is using flattened APEX, don't report any APEX // packages since they won't be managed or updated by PackageManager. if ((new File(ai.packagePath)).isDirectory()) { break; } try { list.add(PackageParser.generatePackageInfoFromApex( new File(ai.packagePath), PackageManager.GET_META_DATA | PackageManager.GET_SIGNING_CERTIFICATES)); } catch (PackageParserException pe) { // TODO: make sure this error is propagated to system server. throw new IllegalStateException("Unable to parse: " + ai, pe); } } mActivePackagesCache = list.stream().collect( Collectors.toMap(p -> p.packageName, Function.identity())); } catch (RemoteException re) { Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString()); throw new RuntimeException(re); } } mActivePackagesCacheLatch.countDown(); Slog.i(TAG, "Finished parsing apex files in " + (SystemClock.currentTimeMicro() - startTimeMicros) + " μs"); } /** * Retrieves information about an active APEX package. * * <p>This method blocks caller thread until {@link #parseApexFiles()} succeeds. Note that in * case {@link #parseApexFiles()}} throws an exception this method will never finish * essentially putting device into a boot loop. * * @param packageName the package name to look for. Note that this is the package name reported * in the APK container manifest (i.e. AndroidManifest.xml), which might * differ from the one reported in the APEX manifest (i.e. Loading @@ -123,30 +155,43 @@ class ApexManager { * is not found. */ @Nullable PackageInfo getActivePackage(String packageName) { populateActivePackagesCacheIfNeeded(); waitForLatch(mActivePackagesCacheLatch); return mActivePackagesCache.get(packageName); } /** * Retrieves information about all active APEX packages. * * <p>This method blocks caller thread until {@link #parseApexFiles()} succeeds. Note that in * case {@link #parseApexFiles()}} throws an exception this method will never finish * essentially putting device into a boot loop. * * @return a Collection of PackageInfo object, each one containing information about a different * active package. */ Collection<PackageInfo> getActivePackages() { populateActivePackagesCacheIfNeeded(); waitForLatch(mActivePackagesCacheLatch); return mActivePackagesCache.values(); } /** * Checks if {@code packageName} is an apex package. * * <p>This method blocks caller thread until {@link #populateApexFilesCache()} succeeds. Note * that in case {@link #populateApexFilesCache()} throws an exception this method will never * finish essentially putting device into a boot loop. * * @param packageName package to check. * @return {@code true} if {@code packageName} is an apex package. */ boolean isApexPackage(String packageName) { populateActivePackagesCacheIfNeeded(); return mActivePackagesCache.containsKey(packageName); waitForLatch(mApexFilesCacheLatch); for (ApexInfo ai : mApexFiles) { if (ai.packageName.equals(packageName)) { return true; } } return false; } /** Loading Loading @@ -273,6 +318,19 @@ class ApexManager { } } /** * Blocks current thread until {@code latch} has counted down to zero. * * @throws RuntimeException if thread was interrupted while waiting. */ private void waitForLatch(CountDownLatch latch) { try { latch.await(); } catch (InterruptedException e) { throw new RuntimeException("Interrupted waiting for cache to be populated", e); } } /** * Dumps various state information to the provided {@link PrintWriter} object. * Loading @@ -286,7 +344,7 @@ class ApexManager { ipw.println("Active APEX packages:"); ipw.increaseIndent(); try { populateActivePackagesCacheIfNeeded(); waitForLatch(mActivePackagesCacheLatch); for (PackageInfo pi : mActivePackagesCache.values()) { if (packageName != null && !packageName.equals(pi.packageName)) { continue; Loading Loading @@ -331,8 +389,4 @@ class ApexManager { ipw.println("Couldn't communicate with apexd."); } } public void onBootCompleted() { populateActivePackagesCacheIfNeeded(); } } services/core/java/com/android/server/pm/PackageManagerService.java +2 −2 Original line number Diff line number Diff line Loading @@ -2374,6 +2374,8 @@ public class PackageManagerService extends IPackageManager.Stub public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { mApexManager = LocalServices.getService(ApexManager.class); LockGuard.installLock(mPackages, LockGuard.INDEX_PACKAGES); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "create package manager"); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START, Loading Loading @@ -2470,7 +2472,6 @@ public class PackageManagerService extends IPackageManager.Stub mProtectedPackages = new ProtectedPackages(mContext); mApexManager = new ApexManager(context); synchronized (mInstallLock) { // writer synchronized (mPackages) { Loading Loading @@ -21467,7 +21468,6 @@ public class PackageManagerService extends IPackageManager.Stub storage.registerListener(mStorageListener); mInstallerService.systemReady(); mApexManager.systemReady(); mPackageDexOptimizer.systemReady(); getStorageManagerInternal().addExternalStoragePolicy( services/java/com/android/server/SystemServer.java +7 −0 Original line number Diff line number Diff line Loading @@ -115,6 +115,7 @@ import com.android.server.om.OverlayManagerService; import com.android.server.os.BugreportManagerService; import com.android.server.os.DeviceIdentifiersPolicyService; import com.android.server.os.SchedulingPolicyService; import com.android.server.pm.ApexManager; import com.android.server.pm.BackgroundDexOptService; import com.android.server.pm.CrossProfileAppsService; import com.android.server.pm.DynamicCodeLoggingService; Loading Loading @@ -629,6 +630,12 @@ public final class SystemServer { watchdog.start(); traceEnd(); // Start ApexManager as early as we can to give it enough time to call apexd and populate // cache of known apex packages. Note that calling apexd will happen asynchronously. traceBeginAndSlog("StartApexManager"); mSystemServiceManager.startService(ApexManager.class); traceEnd(); Slog.i(TAG, "Reading configuration..."); final String TAG_SYSTEM_CONFIG = "ReadingSystemConfig"; traceBeginAndSlog(TAG_SYSTEM_CONFIG); Loading Loading
services/core/java/com/android/server/pm/ApexManager.java +109 −55 Original line number Diff line number Diff line Loading @@ -22,22 +22,21 @@ import android.apex.ApexInfo; import android.apex.ApexInfoList; import android.apex.ApexSessionInfo; import android.apex.IApexService; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageParser; import android.content.pm.PackageParser.PackageParserException; import android.os.HandlerThread; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceManager.ServiceNotFoundException; import android.os.SystemClock; import android.sysprop.ApexProperties; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; import com.android.server.SystemService; import java.io.File; import java.io.PrintWriter; Loading @@ -46,75 +45,108 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.function.Function; import java.util.stream.Collectors; /** * ApexManager class handles communications with the apex service to perform operation and queries, * as well as providing caching to avoid unnecessary calls to the service. * * @hide */ class ApexManager { static final String TAG = "ApexManager"; private final IApexService mApexService; private final Context mContext; private final Object mLock = new Object(); @GuardedBy("mLock") public final class ApexManager extends SystemService { private static final String TAG = "ApexManager"; private IApexService mApexService; private final CountDownLatch mActivePackagesCacheLatch = new CountDownLatch(1); private Map<String, PackageInfo> mActivePackagesCache; ApexManager(Context context) { private final CountDownLatch mApexFilesCacheLatch = new CountDownLatch(1); private ApexInfo[] mApexFiles; public ApexManager(Context context) { super(context); } @Override public void onStart() { try { mApexService = IApexService.Stub.asInterface( ServiceManager.getServiceOrThrow("apexservice")); } catch (ServiceNotFoundException e) { throw new IllegalStateException("Required service apexservice not available"); } mContext = context; publishLocalService(ApexManager.class, this); HandlerThread oneShotThread = new HandlerThread("ApexManagerOneShotHandler"); oneShotThread.start(); oneShotThread.getThreadHandler().post(this::initSequence); oneShotThread.quitSafely(); } void systemReady() { mContext.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { onBootCompleted(); mContext.unregisterReceiver(this); } }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); private void initSequence() { populateApexFilesCache(); parseApexFiles(); } private void populateActivePackagesCacheIfNeeded() { synchronized (mLock) { if (mActivePackagesCache != null) { private void populateApexFilesCache() { if (mApexFiles != null) { return; } long startTimeMicros = SystemClock.currentTimeMicro(); Slog.i(TAG, "Starting to populate apex files cache"); try { mApexFiles = mApexService.getActivePackages(); Slog.i(TAG, "IPC to apexd finished in " + (SystemClock.currentTimeMicro() - startTimeMicros) + " μs"); } catch (RemoteException re) { // TODO: make sure this error is propagated to system server. Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString()); re.rethrowAsRuntimeException(); } mApexFilesCacheLatch.countDown(); Slog.i(TAG, "Finished populating apex files cache in " + (SystemClock.currentTimeMicro() - startTimeMicros) + " μs"); } private void parseApexFiles() { waitForLatch(mApexFilesCacheLatch); if (mApexFiles == null) { throw new IllegalStateException("mApexFiles must be populated"); } long startTimeMicros = SystemClock.currentTimeMicro(); Slog.i(TAG, "Starting to parse apex files"); List<PackageInfo> list = new ArrayList<>(); final ApexInfo[] activePkgs = mApexService.getActivePackages(); for (ApexInfo ai : activePkgs) { // TODO: this can be parallelized. for (ApexInfo ai : mApexFiles) { try { // If the device is using flattened APEX, don't report any APEX // packages since they won't be managed or updated by PackageManager. if ((new File(ai.packagePath)).isDirectory()) { break; } try { list.add(PackageParser.generatePackageInfoFromApex( new File(ai.packagePath), PackageManager.GET_META_DATA | PackageManager.GET_SIGNING_CERTIFICATES)); } catch (PackageParserException pe) { // TODO: make sure this error is propagated to system server. throw new IllegalStateException("Unable to parse: " + ai, pe); } } mActivePackagesCache = list.stream().collect( Collectors.toMap(p -> p.packageName, Function.identity())); } catch (RemoteException re) { Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString()); throw new RuntimeException(re); } } mActivePackagesCacheLatch.countDown(); Slog.i(TAG, "Finished parsing apex files in " + (SystemClock.currentTimeMicro() - startTimeMicros) + " μs"); } /** * Retrieves information about an active APEX package. * * <p>This method blocks caller thread until {@link #parseApexFiles()} succeeds. Note that in * case {@link #parseApexFiles()}} throws an exception this method will never finish * essentially putting device into a boot loop. * * @param packageName the package name to look for. Note that this is the package name reported * in the APK container manifest (i.e. AndroidManifest.xml), which might * differ from the one reported in the APEX manifest (i.e. Loading @@ -123,30 +155,43 @@ class ApexManager { * is not found. */ @Nullable PackageInfo getActivePackage(String packageName) { populateActivePackagesCacheIfNeeded(); waitForLatch(mActivePackagesCacheLatch); return mActivePackagesCache.get(packageName); } /** * Retrieves information about all active APEX packages. * * <p>This method blocks caller thread until {@link #parseApexFiles()} succeeds. Note that in * case {@link #parseApexFiles()}} throws an exception this method will never finish * essentially putting device into a boot loop. * * @return a Collection of PackageInfo object, each one containing information about a different * active package. */ Collection<PackageInfo> getActivePackages() { populateActivePackagesCacheIfNeeded(); waitForLatch(mActivePackagesCacheLatch); return mActivePackagesCache.values(); } /** * Checks if {@code packageName} is an apex package. * * <p>This method blocks caller thread until {@link #populateApexFilesCache()} succeeds. Note * that in case {@link #populateApexFilesCache()} throws an exception this method will never * finish essentially putting device into a boot loop. * * @param packageName package to check. * @return {@code true} if {@code packageName} is an apex package. */ boolean isApexPackage(String packageName) { populateActivePackagesCacheIfNeeded(); return mActivePackagesCache.containsKey(packageName); waitForLatch(mApexFilesCacheLatch); for (ApexInfo ai : mApexFiles) { if (ai.packageName.equals(packageName)) { return true; } } return false; } /** Loading Loading @@ -273,6 +318,19 @@ class ApexManager { } } /** * Blocks current thread until {@code latch} has counted down to zero. * * @throws RuntimeException if thread was interrupted while waiting. */ private void waitForLatch(CountDownLatch latch) { try { latch.await(); } catch (InterruptedException e) { throw new RuntimeException("Interrupted waiting for cache to be populated", e); } } /** * Dumps various state information to the provided {@link PrintWriter} object. * Loading @@ -286,7 +344,7 @@ class ApexManager { ipw.println("Active APEX packages:"); ipw.increaseIndent(); try { populateActivePackagesCacheIfNeeded(); waitForLatch(mActivePackagesCacheLatch); for (PackageInfo pi : mActivePackagesCache.values()) { if (packageName != null && !packageName.equals(pi.packageName)) { continue; Loading Loading @@ -331,8 +389,4 @@ class ApexManager { ipw.println("Couldn't communicate with apexd."); } } public void onBootCompleted() { populateActivePackagesCacheIfNeeded(); } }
services/core/java/com/android/server/pm/PackageManagerService.java +2 −2 Original line number Diff line number Diff line Loading @@ -2374,6 +2374,8 @@ public class PackageManagerService extends IPackageManager.Stub public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { mApexManager = LocalServices.getService(ApexManager.class); LockGuard.installLock(mPackages, LockGuard.INDEX_PACKAGES); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "create package manager"); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START, Loading Loading @@ -2470,7 +2472,6 @@ public class PackageManagerService extends IPackageManager.Stub mProtectedPackages = new ProtectedPackages(mContext); mApexManager = new ApexManager(context); synchronized (mInstallLock) { // writer synchronized (mPackages) { Loading Loading @@ -21467,7 +21468,6 @@ public class PackageManagerService extends IPackageManager.Stub storage.registerListener(mStorageListener); mInstallerService.systemReady(); mApexManager.systemReady(); mPackageDexOptimizer.systemReady(); getStorageManagerInternal().addExternalStoragePolicy(
services/java/com/android/server/SystemServer.java +7 −0 Original line number Diff line number Diff line Loading @@ -115,6 +115,7 @@ import com.android.server.om.OverlayManagerService; import com.android.server.os.BugreportManagerService; import com.android.server.os.DeviceIdentifiersPolicyService; import com.android.server.os.SchedulingPolicyService; import com.android.server.pm.ApexManager; import com.android.server.pm.BackgroundDexOptService; import com.android.server.pm.CrossProfileAppsService; import com.android.server.pm.DynamicCodeLoggingService; Loading Loading @@ -629,6 +630,12 @@ public final class SystemServer { watchdog.start(); traceEnd(); // Start ApexManager as early as we can to give it enough time to call apexd and populate // cache of known apex packages. Note that calling apexd will happen asynchronously. traceBeginAndSlog("StartApexManager"); mSystemServiceManager.startService(ApexManager.class); traceEnd(); Slog.i(TAG, "Reading configuration..."); final String TAG_SYSTEM_CONFIG = "ReadingSystemConfig"; traceBeginAndSlog(TAG_SYSTEM_CONFIG); Loading