Merge "ApexManager: Request apexservice only when needed" into rvc-dev am: c44b78d47a

Change-Id: I709b3f36c6c8154c151582ca34994e62d04668c9
This commit is contained in:
Jon Spivack
2020-03-31 18:48:56 +00:00
committed by Automerger Merge Worker
2 changed files with 37 additions and 29 deletions

View File

@@ -32,9 +32,9 @@ import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.PackageParser; import android.content.pm.PackageParser;
import android.content.pm.parsing.PackageInfoWithoutStateUtils; import android.content.pm.parsing.PackageInfoWithoutStateUtils;
import android.os.Binder;
import android.os.Environment; import android.os.Environment;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.Trace; import android.os.Trace;
import android.sysprop.ApexProperties; import android.sysprop.ApexProperties;
import android.util.ArrayMap; import android.util.ArrayMap;
@@ -81,13 +81,7 @@ public abstract class ApexManager {
@Override @Override
protected ApexManager create() { protected ApexManager create() {
if (ApexProperties.updatable().orElse(false)) { if (ApexProperties.updatable().orElse(false)) {
try { return new ApexManagerImpl();
return new ApexManagerImpl(IApexService.Stub.asInterface(
ServiceManager.getServiceOrThrow("apexservice")));
} catch (ServiceManager.ServiceNotFoundException e) {
throw new IllegalStateException(
"Required service apexservice not available");
}
} else { } else {
return new ApexManagerFlattenedApex(); return new ApexManagerFlattenedApex();
} }
@@ -358,8 +352,7 @@ public abstract class ApexManager {
* APEX packages. * APEX packages.
*/ */
@VisibleForTesting @VisibleForTesting
static class ApexManagerImpl extends ApexManager { protected static class ApexManagerImpl extends ApexManager {
private final IApexService mApexService;
private final Object mLock = new Object(); private final Object mLock = new Object();
@GuardedBy("mLock") @GuardedBy("mLock")
@@ -388,10 +381,6 @@ public abstract class ApexManager {
@GuardedBy("mLock") @GuardedBy("mLock")
private ArrayMap<String, String> mPackageNameToApexModuleName; private ArrayMap<String, String> mPackageNameToApexModuleName;
ApexManagerImpl(IApexService apexService) {
mApexService = apexService;
}
/** /**
* Whether an APEX package is active or not. * Whether an APEX package is active or not.
* *
@@ -402,6 +391,19 @@ public abstract class ApexManager {
return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0; return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0;
} }
/**
* Retrieve the service from ServiceManager. If the service is not running, it will be
* started, and this function will block until it is ready.
*/
@VisibleForTesting
protected IApexService waitForApexService() {
try {
return IApexService.Stub.asInterface(Binder.waitForService("apexservice"));
} catch (RemoteException e) {
throw new IllegalStateException("Required service apexservice not available");
}
}
@Override @Override
public List<ActiveApexInfo> getActiveApexInfos() { public List<ActiveApexInfo> getActiveApexInfos() {
final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing", final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
@@ -411,7 +413,7 @@ public abstract class ApexManager {
t.traceBegin("getActiveApexInfos_noCache"); t.traceBegin("getActiveApexInfos_noCache");
try { try {
mActiveApexInfosCache = new ArraySet<>(); mActiveApexInfosCache = new ArraySet<>();
final ApexInfo[] activePackages = mApexService.getActivePackages(); final ApexInfo[] activePackages = waitForApexService().getActivePackages();
for (int i = 0; i < activePackages.length; i++) { for (int i = 0; i < activePackages.length; i++) {
ApexInfo apexInfo = activePackages[i]; ApexInfo apexInfo = activePackages[i];
mActiveApexInfosCache.add(new ActiveApexInfo(apexInfo)); mActiveApexInfosCache.add(new ActiveApexInfo(apexInfo));
@@ -449,7 +451,7 @@ public abstract class ApexManager {
try { try {
mAllPackagesCache = new ArrayList<>(); mAllPackagesCache = new ArrayList<>();
mPackageNameToApexModuleName = new ArrayMap<>(); mPackageNameToApexModuleName = new ArrayMap<>();
allPkgs = mApexService.getAllPackages(); allPkgs = waitForApexService().getAllPackages();
} catch (RemoteException re) { } catch (RemoteException re) {
Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString()); Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
throw new RuntimeException(re); throw new RuntimeException(re);
@@ -620,7 +622,8 @@ public abstract class ApexManager {
@Override @Override
@Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) { @Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) {
try { try {
ApexSessionInfo apexSessionInfo = mApexService.getStagedSessionInfo(sessionId); ApexSessionInfo apexSessionInfo =
waitForApexService().getStagedSessionInfo(sessionId);
if (apexSessionInfo.isUnknown) { if (apexSessionInfo.isUnknown) {
return null; return null;
} }
@@ -635,7 +638,7 @@ public abstract class ApexManager {
ApexInfoList submitStagedSession(ApexSessionParams params) throws PackageManagerException { ApexInfoList submitStagedSession(ApexSessionParams params) throws PackageManagerException {
try { try {
final ApexInfoList apexInfoList = new ApexInfoList(); final ApexInfoList apexInfoList = new ApexInfoList();
mApexService.submitStagedSession(params, apexInfoList); waitForApexService().submitStagedSession(params, apexInfoList);
return apexInfoList; return apexInfoList;
} catch (RemoteException re) { } catch (RemoteException re) {
Slog.e(TAG, "Unable to contact apexservice", re); Slog.e(TAG, "Unable to contact apexservice", re);
@@ -650,7 +653,7 @@ public abstract class ApexManager {
@Override @Override
void markStagedSessionReady(int sessionId) throws PackageManagerException { void markStagedSessionReady(int sessionId) throws PackageManagerException {
try { try {
mApexService.markStagedSessionReady(sessionId); waitForApexService().markStagedSessionReady(sessionId);
} catch (RemoteException re) { } catch (RemoteException re) {
Slog.e(TAG, "Unable to contact apexservice", re); Slog.e(TAG, "Unable to contact apexservice", re);
throw new RuntimeException(re); throw new RuntimeException(re);
@@ -664,7 +667,7 @@ public abstract class ApexManager {
@Override @Override
void markStagedSessionSuccessful(int sessionId) { void markStagedSessionSuccessful(int sessionId) {
try { try {
mApexService.markStagedSessionSuccessful(sessionId); waitForApexService().markStagedSessionSuccessful(sessionId);
} catch (RemoteException re) { } catch (RemoteException re) {
Slog.e(TAG, "Unable to contact apexservice", re); Slog.e(TAG, "Unable to contact apexservice", re);
throw new RuntimeException(re); throw new RuntimeException(re);
@@ -683,7 +686,7 @@ public abstract class ApexManager {
@Override @Override
boolean revertActiveSessions() { boolean revertActiveSessions() {
try { try {
mApexService.revertActiveSessions(); waitForApexService().revertActiveSessions();
return true; return true;
} catch (RemoteException re) { } catch (RemoteException re) {
Slog.e(TAG, "Unable to contact apexservice", re); Slog.e(TAG, "Unable to contact apexservice", re);
@@ -697,7 +700,7 @@ public abstract class ApexManager {
@Override @Override
boolean abortStagedSession(int sessionId) throws PackageManagerException { boolean abortStagedSession(int sessionId) throws PackageManagerException {
try { try {
mApexService.abortStagedSession(sessionId); waitForApexService().abortStagedSession(sessionId);
return true; return true;
} catch (RemoteException re) { } catch (RemoteException re) {
Slog.e(TAG, "Unable to contact apexservice", re); Slog.e(TAG, "Unable to contact apexservice", re);
@@ -712,7 +715,7 @@ public abstract class ApexManager {
@Override @Override
boolean uninstallApex(String apexPackagePath) { boolean uninstallApex(String apexPackagePath) {
try { try {
mApexService.unstagePackages(Collections.singletonList(apexPackagePath)); waitForApexService().unstagePackages(Collections.singletonList(apexPackagePath));
return true; return true;
} catch (Exception e) { } catch (Exception e) {
return false; return false;
@@ -773,7 +776,7 @@ public abstract class ApexManager {
return -1; return -1;
} }
try { try {
return mApexService.snapshotCeData(userId, rollbackId, apexModuleName); return waitForApexService().snapshotCeData(userId, rollbackId, apexModuleName);
} catch (Exception e) { } catch (Exception e) {
Slog.e(TAG, e.getMessage(), e); Slog.e(TAG, e.getMessage(), e);
return -1; return -1;
@@ -793,7 +796,7 @@ public abstract class ApexManager {
return false; return false;
} }
try { try {
mApexService.restoreCeData(userId, rollbackId, apexModuleName); waitForApexService().restoreCeData(userId, rollbackId, apexModuleName);
return true; return true;
} catch (Exception e) { } catch (Exception e) {
Slog.e(TAG, e.getMessage(), e); Slog.e(TAG, e.getMessage(), e);
@@ -804,7 +807,7 @@ public abstract class ApexManager {
@Override @Override
public boolean destroyDeSnapshots(int rollbackId) { public boolean destroyDeSnapshots(int rollbackId) {
try { try {
mApexService.destroyDeSnapshots(rollbackId); waitForApexService().destroyDeSnapshots(rollbackId);
return true; return true;
} catch (Exception e) { } catch (Exception e) {
Slog.e(TAG, e.getMessage(), e); Slog.e(TAG, e.getMessage(), e);
@@ -815,7 +818,7 @@ public abstract class ApexManager {
@Override @Override
public boolean destroyCeSnapshotsNotSpecified(int userId, int[] retainRollbackIds) { public boolean destroyCeSnapshotsNotSpecified(int userId, int[] retainRollbackIds) {
try { try {
mApexService.destroyCeSnapshotsNotSpecified(userId, retainRollbackIds); waitForApexService().destroyCeSnapshotsNotSpecified(userId, retainRollbackIds);
return true; return true;
} catch (Exception e) { } catch (Exception e) {
Slog.e(TAG, e.getMessage(), e); Slog.e(TAG, e.getMessage(), e);
@@ -859,7 +862,7 @@ public abstract class ApexManager {
ipw.println(); ipw.println();
ipw.println("APEX session state:"); ipw.println("APEX session state:");
ipw.increaseIndent(); ipw.increaseIndent();
final ApexSessionInfo[] sessions = mApexService.getSessions(); final ApexSessionInfo[] sessions = waitForApexService().getSessions();
for (ApexSessionInfo si : sessions) { for (ApexSessionInfo si : sessions) {
ipw.println("Session ID: " + si.sessionId); ipw.println("Session ID: " + si.sessionId);
ipw.increaseIndent(); ipw.increaseIndent();

View File

@@ -21,8 +21,10 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@@ -58,6 +60,7 @@ import java.io.InputStream;
@SmallTest @SmallTest
@Presubmit @Presubmit
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class ApexManagerTest { public class ApexManagerTest {
private static final String TEST_APEX_PKG = "com.android.apex.test"; private static final String TEST_APEX_PKG = "com.android.apex.test";
private static final int TEST_SESSION_ID = 99999999; private static final int TEST_SESSION_ID = 99999999;
@@ -71,7 +74,9 @@ public class ApexManagerTest {
@Before @Before
public void setUp() throws RemoteException { public void setUp() throws RemoteException {
mContext = InstrumentationRegistry.getInstrumentation().getContext(); mContext = InstrumentationRegistry.getInstrumentation().getContext();
mApexManager = new ApexManager.ApexManagerImpl(mApexService); ApexManager.ApexManagerImpl managerImpl = spy(new ApexManager.ApexManagerImpl());
doReturn(mApexService).when(managerImpl).waitForApexService();
mApexManager = managerImpl;
mPackageParser2 = new PackageParser2(null, false, null, null, null); mPackageParser2 = new PackageParser2(null, false, null, null, null);
} }