diff options
3 files changed, 57 insertions, 118 deletions
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java index 497385fef39c..5430f4c8daa0 100644 --- a/services/core/java/com/android/server/pm/ApexManager.java +++ b/services/core/java/com/android/server/pm/ApexManager.java @@ -22,21 +22,22 @@ 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; @@ -45,108 +46,75 @@ 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 */ -public final class ApexManager extends SystemService { - private static final String TAG = "ApexManager"; - private IApexService mApexService; - - private final CountDownLatch mActivePackagesCacheLatch = new CountDownLatch(1); +class ApexManager { + static final String TAG = "ApexManager"; + private final IApexService mApexService; + private final Context mContext; + private final Object mLock = new Object(); + @GuardedBy("mLock") private Map<String, PackageInfo> mActivePackagesCache; - private final CountDownLatch mApexFilesCacheLatch = new CountDownLatch(1); - private ApexInfo[] mApexFiles; - - public ApexManager(Context context) { - super(context); - } - - @Override - public void onStart() { + ApexManager(Context context) { try { mApexService = IApexService.Stub.asInterface( - ServiceManager.getServiceOrThrow("apexservice")); + ServiceManager.getServiceOrThrow("apexservice")); } catch (ServiceNotFoundException e) { throw new IllegalStateException("Required service apexservice not available"); } - publishLocalService(ApexManager.class, this); - HandlerThread oneShotThread = new HandlerThread("ApexManagerOneShotHandler"); - oneShotThread.start(); - oneShotThread.getThreadHandler().post(this::initSequence); - oneShotThread.quitSafely(); - } - - private void initSequence() { - populateApexFilesCache(); - parseApexFiles(); + mContext = context; } - 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"); + 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 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<>(); - // TODO: this can be parallelized. - for (ApexInfo ai : mApexFiles) { + private void populateActivePackagesCacheIfNeeded() { + synchronized (mLock) { + if (mActivePackagesCache != null) { + return; + } 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; - } - list.add(PackageParser.generatePackageInfoFromApex( - new File(ai.packagePath), PackageManager.GET_META_DATA + List<PackageInfo> list = new ArrayList<>(); + final ApexInfo[] activePkgs = mApexService.getActivePackages(); + for (ApexInfo ai : activePkgs) { + // 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); + } catch (PackageParserException pe) { + 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); } } - mActivePackagesCache = list.stream().collect( - Collectors.toMap(p -> p.packageName, Function.identity())); - 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. @@ -155,43 +123,30 @@ public final class ApexManager extends SystemService { * is not found. */ @Nullable PackageInfo getActivePackage(String packageName) { - waitForLatch(mActivePackagesCacheLatch); + populateActivePackagesCacheIfNeeded(); 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() { - waitForLatch(mActivePackagesCacheLatch); + populateActivePackagesCacheIfNeeded(); 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) { - waitForLatch(mApexFilesCacheLatch); - for (ApexInfo ai : mApexFiles) { - if (ai.packageName.equals(packageName)) { - return true; - } - } - return false; + populateActivePackagesCacheIfNeeded(); + return mActivePackagesCache.containsKey(packageName); } /** @@ -319,19 +274,6 @@ public final class ApexManager extends SystemService { } /** - * 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. * * @param pw the {@link PrintWriter} object to send information to. @@ -344,7 +286,7 @@ public final class ApexManager extends SystemService { ipw.println("Active APEX packages:"); ipw.increaseIndent(); try { - waitForLatch(mActivePackagesCacheLatch); + populateActivePackagesCacheIfNeeded(); for (PackageInfo pi : mActivePackagesCache.values()) { if (packageName != null && !packageName.equals(pi.packageName)) { continue; @@ -389,4 +331,8 @@ public final class ApexManager extends SystemService { ipw.println("Couldn't communicate with apexd."); } } + + public void onBootCompleted() { + populateActivePackagesCacheIfNeeded(); + } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index ed83cbced49f..95a88092fd6e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -2375,8 +2375,6 @@ 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, @@ -2473,6 +2471,7 @@ public class PackageManagerService extends IPackageManager.Stub mProtectedPackages = new ProtectedPackages(mContext); + mApexManager = new ApexManager(context); synchronized (mInstallLock) { // writer synchronized (mPackages) { @@ -21531,6 +21530,7 @@ public class PackageManagerService extends IPackageManager.Stub storage.registerListener(mStorageListener); mInstallerService.systemReady(); + mApexManager.systemReady(); mPackageDexOptimizer.systemReady(); getStorageManagerInternal().addExternalStoragePolicy( diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 4ac8342e6e60..be7dd31380ba 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -115,7 +115,6 @@ 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; @@ -628,12 +627,6 @@ 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); |