Merge "Revert "Populate active apexes cache in a background thread"" into qt-dev

am: 39789e86f7

Change-Id: Ic09fd7408fcfe0e5abcd2b72c65f73a3c2f18675
This commit is contained in:
Mohammad Samiul Islam
2019-05-09 04:34:04 -07:00
committed by android-build-merger
3 changed files with 57 additions and 118 deletions

View File

@@ -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();
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 @@ 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);
}
/**
@@ -318,19 +273,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.
*
@@ -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();
}
}

View File

@@ -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(

View File

@@ -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);