Make ApexManager a singleton.

Currently ApexManager is only accessed from PackageManager, but upcoming changes
to allow rollback of apex data directories will require RollbackManager to
access it as well. (See go/apex-data-directories)

Multiple ApexManagers can already be created, but as the class maintains a cache of apex
packages, it would be inefficient to have many of them. This change makes ApexManager
into a singleton so that PackageManager and RollbackManager can use the same one.

Bug: 141148175
Test: atest CtsStagedInstallHostTestCases
Change-Id: Id43a20bf94f349c87d50de5dad7c90bee50f39f1
This commit is contained in:
Oli Lan
2019-11-28 11:34:21 +00:00
parent 3978fd5471
commit be7a423649
3 changed files with 30 additions and 22 deletions

View File

@@ -36,6 +36,7 @@ import android.os.Environment;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.sysprop.ApexProperties;
import android.util.Singleton;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -65,22 +66,31 @@ abstract class ApexManager {
static final int MATCH_ACTIVE_PACKAGE = 1 << 0;
static final int MATCH_FACTORY_PACKAGE = 1 << 1;
private static final Singleton<ApexManager> sApexManagerSingleton =
new Singleton<ApexManager>() {
@Override
protected ApexManager create() {
if (ApexProperties.updatable().orElse(false)) {
try {
return new ApexManagerImpl(IApexService.Stub.asInterface(
ServiceManager.getServiceOrThrow("apexservice")));
} catch (ServiceManager.ServiceNotFoundException e) {
throw new IllegalStateException(
"Required service apexservice not available");
}
} else {
return new ApexManagerFlattenedApex();
}
}
};
/**
* Returns an instance of either {@link ApexManagerImpl} or {@link ApexManagerFlattenedApex}
* depending on whether this device supports APEX, i.e. {@link ApexProperties#updatable()}
* evaluates to {@code true}.
*/
static ApexManager create(Context systemContext) {
if (ApexProperties.updatable().orElse(false)) {
try {
return new ApexManagerImpl(systemContext, IApexService.Stub.asInterface(
ServiceManager.getServiceOrThrow("apexservice")));
} catch (ServiceManager.ServiceNotFoundException e) {
throw new IllegalStateException("Required service apexservice not available");
}
} else {
return new ApexManagerFlattenedApex();
}
static ApexManager getInstance() {
return sApexManagerSingleton.get();
}
/**
@@ -101,7 +111,7 @@ abstract class ApexManager {
*/
abstract List<ActiveApexInfo> getActiveApexInfos();
abstract void systemReady();
abstract void systemReady(Context context);
/**
* Retrieves information about an APEX package.
@@ -248,7 +258,6 @@ abstract class ApexManager {
@VisibleForTesting
static class ApexManagerImpl extends ApexManager {
private final IApexService mApexService;
private final Context mContext;
private final Object mLock = new Object();
/**
* A map from {@code APEX packageName} to the {@Link PackageInfo} generated from the {@code
@@ -260,8 +269,7 @@ abstract class ApexManager {
@GuardedBy("mLock")
private List<PackageInfo> mAllPackagesCache;
ApexManagerImpl(Context context, IApexService apexService) {
mContext = context;
ApexManagerImpl(IApexService apexService) {
mApexService = apexService;
}
@@ -302,14 +310,14 @@ abstract class ApexManager {
}
@Override
void systemReady() {
mContext.registerReceiver(new BroadcastReceiver() {
void systemReady(Context context) {
context.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// Post populateAllPackagesCacheIfNeeded to a background thread, since it's
// expensive to run it in broadcast handler thread.
BackgroundThread.getHandler().post(() -> populateAllPackagesCacheIfNeeded());
mContext.unregisterReceiver(this);
context.unregisterReceiver(this);
}
}, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
}
@@ -643,7 +651,7 @@ abstract class ApexManager {
}
@Override
void systemReady() {
void systemReady(Context context) {
// No-op
}

View File

@@ -2605,7 +2605,7 @@ public class PackageManagerService extends IPackageManager.Stub
mProtectedPackages = new ProtectedPackages(mContext);
mApexManager = ApexManager.create(mContext);
mApexManager = ApexManager.getInstance();
mAppsFilter = mInjector.getAppsFilter();
mDirsToScanAsSystem = new ArrayList<>();
@@ -20371,7 +20371,7 @@ public class PackageManagerService extends IPackageManager.Stub
storage.registerListener(mStorageListener);
mInstallerService.systemReady();
mApexManager.systemReady();
mApexManager.systemReady(mContext);
mPackageDexOptimizer.systemReady();
mInjector.getStorageManagerInternal().addExternalStoragePolicy(

View File

@@ -68,7 +68,7 @@ public class ApexManagerTest {
@Before
public void setUp() throws RemoteException {
mContext = InstrumentationRegistry.getInstrumentation().getContext();
mApexManager = new ApexManager.ApexManagerImpl(mContext, mApexService);
mApexManager = new ApexManager.ApexManagerImpl(mApexService);
}
@Test