Revert "Populate active apexes cache in a background thread"
This reverts commit 97fc6d9c29dd08f75f4f7d82d17d9f422ec44147.
Reason for revert: b/132236259
Change-Id: I5270140580ebad16a9dc1db6b2e5f9faa977f54a
Bug: 132236259
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 497385f..5430f4c 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.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.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();
+ mContext = context;
}
- private void initSequence() {
- populateApexFilesCache();
- parseApexFiles();
+ 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 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<>();
- // 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 @@
* 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 @@
}
/**
- * 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 @@
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 @@
ipw.println("Couldn't communicate with apexd.");
}
}
+
+ public void onBootCompleted() {
+ populateActivePackagesCacheIfNeeded();
+ }
}