Merge changes from topics "cherrypick-non-staged-flag-ussa3zkzzhp", "forced-non-staged-apex-update-udc-dev-plus-aosp" into udc-dev-plus-aosp

* changes:
  Add an install flag to force non-staged APEX update
  Add --non-staged flag
This commit is contained in:
Nikita Ioffe
2023-07-29 00:34:37 +00:00
committed by Android (Google) Code Review
10 changed files with 99 additions and 28 deletions

View File

@@ -2369,6 +2369,8 @@ public class PackageInstaller {
public int requireUserAction = USER_ACTION_UNSPECIFIED; public int requireUserAction = USER_ACTION_UNSPECIFIED;
/** {@hide} */ /** {@hide} */
public boolean applicationEnabledSettingPersistent = false; public boolean applicationEnabledSettingPersistent = false;
/** {@hide} */
public int developmentInstallFlags = 0;
private final ArrayMap<String, Integer> mPermissionStates; private final ArrayMap<String, Integer> mPermissionStates;
@@ -2418,6 +2420,7 @@ public class PackageInstaller {
requireUserAction = source.readInt(); requireUserAction = source.readInt();
packageSource = source.readInt(); packageSource = source.readInt();
applicationEnabledSettingPersistent = source.readBoolean(); applicationEnabledSettingPersistent = source.readBoolean();
developmentInstallFlags = source.readInt();
} }
/** {@hide} */ /** {@hide} */
@@ -2449,6 +2452,7 @@ public class PackageInstaller {
ret.requireUserAction = requireUserAction; ret.requireUserAction = requireUserAction;
ret.packageSource = packageSource; ret.packageSource = packageSource;
ret.applicationEnabledSettingPersistent = applicationEnabledSettingPersistent; ret.applicationEnabledSettingPersistent = applicationEnabledSettingPersistent;
ret.developmentInstallFlags = developmentInstallFlags;
return ret; return ret;
} }
@@ -3113,6 +3117,7 @@ public class PackageInstaller {
pw.printPair("rollbackDataPolicy", rollbackDataPolicy); pw.printPair("rollbackDataPolicy", rollbackDataPolicy);
pw.printPair("applicationEnabledSettingPersistent", pw.printPair("applicationEnabledSettingPersistent",
applicationEnabledSettingPersistent); applicationEnabledSettingPersistent);
pw.printHexPair("developmentInstallFlags", developmentInstallFlags);
pw.println(); pw.println();
} }
@@ -3154,6 +3159,7 @@ public class PackageInstaller {
dest.writeInt(requireUserAction); dest.writeInt(requireUserAction);
dest.writeInt(packageSource); dest.writeInt(packageSource);
dest.writeBoolean(applicationEnabledSettingPersistent); dest.writeBoolean(applicationEnabledSettingPersistent);
dest.writeInt(developmentInstallFlags);
} }
public static final Parcelable.Creator<SessionParams> public static final Parcelable.Creator<SessionParams>

View File

@@ -1453,6 +1453,16 @@ public abstract class PackageManager {
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
public @interface InstallFlags {} public @interface InstallFlags {}
/**
* Install flags that can only be used in development workflows (e.g. {@code adb install}).
* @hide
*/
@IntDef(flag = true, prefix = { "INSTALL_DEVELOPMENT_" }, value = {
INSTALL_DEVELOPMENT_FORCE_NON_STAGED_APEX_UPDATE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface DevelopmentInstallFlags {}
/** /**
* Flag parameter for {@link #installPackage} to indicate that you want to * Flag parameter for {@link #installPackage} to indicate that you want to
* replace an already installed package, if one exists. * replace an already installed package, if one exists.
@@ -1663,6 +1673,14 @@ public abstract class PackageManager {
*/ */
public static final int INSTALL_FROM_MANAGED_USER_OR_PROFILE = 1 << 26; public static final int INSTALL_FROM_MANAGED_USER_OR_PROFILE = 1 << 26;
/**
* Flag parameter for {@link #installPackage} to force a non-staged update of an APEX. This is
* a development-only feature and should not be used on end user devices.
*
* @hide
*/
public static final int INSTALL_DEVELOPMENT_FORCE_NON_STAGED_APEX_UPDATE = 1;
/** @hide */ /** @hide */
@IntDef(flag = true, value = { @IntDef(flag = true, value = {
DONT_KILL_APP, DONT_KILL_APP,

View File

@@ -363,9 +363,13 @@ public abstract class ApexManager {
/** /**
* Performs a non-staged install of the given {@code apexFile}. * Performs a non-staged install of the given {@code apexFile}.
* *
* If {@code force} is {@code true}, then update is forced even for APEXes that do not support
* non-staged update. This feature is only available on debuggable builds to improve development
* velocity of the teams that have their code packaged in an APEX.
*
* @return {@code ApeInfo} about the newly installed APEX package. * @return {@code ApeInfo} about the newly installed APEX package.
*/ */
abstract ApexInfo installPackage(File apexFile) throws PackageManagerException; abstract ApexInfo installPackage(File apexFile, boolean force) throws PackageManagerException;
/** /**
* Get a list of apex system services implemented in an apex. * Get a list of apex system services implemented in an apex.
@@ -910,10 +914,11 @@ public abstract class ApexManager {
} }
@Override @Override
ApexInfo installPackage(File apexFile) ApexInfo installPackage(File apexFile, boolean force)
throws PackageManagerException { throws PackageManagerException {
try { try {
return waitForApexService().installAndActivatePackage(apexFile.getAbsolutePath()); return waitForApexService().installAndActivatePackage(apexFile.getAbsolutePath(),
force);
} catch (RemoteException e) { } catch (RemoteException e) {
throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
"apexservice not available"); "apexservice not available");
@@ -1170,7 +1175,7 @@ public abstract class ApexManager {
} }
@Override @Override
ApexInfo installPackage(File apexFile) { ApexInfo installPackage(File apexFile, boolean force) {
throw new UnsupportedOperationException("APEX updates are not supported"); throw new UnsupportedOperationException("APEX updates are not supported");
} }

View File

@@ -43,6 +43,7 @@ final class InstallArgs {
final IPackageInstallObserver2 mObserver; final IPackageInstallObserver2 mObserver;
// Always refers to PackageManager flags only // Always refers to PackageManager flags only
final int mInstallFlags; final int mInstallFlags;
final int mDevelopmentInstallFlags;
@NonNull @NonNull
final InstallSource mInstallSource; final InstallSource mInstallSource;
final String mVolumeUuid; final String mVolumeUuid;
@@ -69,8 +70,8 @@ final class InstallArgs {
@Nullable String[] mInstructionSets; @Nullable String[] mInstructionSets;
InstallArgs(OriginInfo originInfo, MoveInfo moveInfo, IPackageInstallObserver2 observer, InstallArgs(OriginInfo originInfo, MoveInfo moveInfo, IPackageInstallObserver2 observer,
int installFlags, InstallSource installSource, String volumeUuid, int installFlags, int developmentInstallFlags, InstallSource installSource,
UserHandle user, String[] instructionSets, String abiOverride, String volumeUuid, UserHandle user, String[] instructionSets, String abiOverride,
@NonNull ArrayMap<String, Integer> permissionStates, @NonNull ArrayMap<String, Integer> permissionStates,
List<String> allowlistedRestrictedPermissions, List<String> allowlistedRestrictedPermissions,
int autoRevokePermissionsMode, String traceMethod, int traceCookie, int autoRevokePermissionsMode, String traceMethod, int traceCookie,
@@ -80,6 +81,7 @@ final class InstallArgs {
mOriginInfo = originInfo; mOriginInfo = originInfo;
mMoveInfo = moveInfo; mMoveInfo = moveInfo;
mInstallFlags = installFlags; mInstallFlags = installFlags;
mDevelopmentInstallFlags = developmentInstallFlags;
mObserver = observer; mObserver = observer;
mInstallSource = Preconditions.checkNotNull(installSource); mInstallSource = Preconditions.checkNotNull(installSource);
mVolumeUuid = volumeUuid; mVolumeUuid = volumeUuid;
@@ -105,7 +107,7 @@ final class InstallArgs {
* when cleaning up old installs, or used as a move source. * when cleaning up old installs, or used as a move source.
*/ */
InstallArgs(String codePath, String[] instructionSets) { InstallArgs(String codePath, String[] instructionSets) {
this(OriginInfo.fromNothing(), null, null, 0, InstallSource.EMPTY, null, null, this(OriginInfo.fromNothing(), null, null, 0, 0, InstallSource.EMPTY, null, null,
instructionSets, null, new ArrayMap<>(), null, MODE_DEFAULT, null, 0, instructionSets, null, new ArrayMap<>(), null, MODE_DEFAULT, null, 0,
SigningDetails.UNKNOWN, PackageManager.INSTALL_REASON_UNKNOWN, SigningDetails.UNKNOWN, PackageManager.INSTALL_REASON_UNKNOWN,
PackageManager.INSTALL_SCENARIO_DEFAULT, false, DataLoaderType.NONE, PackageManager.INSTALL_SCENARIO_DEFAULT, false, DataLoaderType.NONE,

View File

@@ -134,12 +134,13 @@ final class InstallRequest {
InstallRequest(InstallingSession params) { InstallRequest(InstallingSession params) {
mUserId = params.getUser().getIdentifier(); mUserId = params.getUser().getIdentifier();
mInstallArgs = new InstallArgs(params.mOriginInfo, params.mMoveInfo, params.mObserver, mInstallArgs = new InstallArgs(params.mOriginInfo, params.mMoveInfo, params.mObserver,
params.mInstallFlags, params.mInstallSource, params.mVolumeUuid, params.mInstallFlags, params.mDevelopmentInstallFlags, params.mInstallSource,
params.getUser(), null /*instructionSets*/, params.mPackageAbiOverride, params.mVolumeUuid, params.getUser(), null /*instructionSets*/,
params.mPermissionStates, params.mAllowlistedRestrictedPermissions, params.mPackageAbiOverride, params.mPermissionStates,
params.mAutoRevokePermissionsMode, params.mTraceMethod, params.mTraceCookie, params.mAllowlistedRestrictedPermissions, params.mAutoRevokePermissionsMode,
params.mSigningDetails, params.mInstallReason, params.mInstallScenario, params.mTraceMethod, params.mTraceCookie, params.mSigningDetails,
params.mForceQueryableOverride, params.mDataLoaderType, params.mPackageSource, params.mInstallReason, params.mInstallScenario, params.mForceQueryableOverride,
params.mDataLoaderType, params.mPackageSource,
params.mApplicationEnabledSettingPersistent); params.mApplicationEnabledSettingPersistent);
mPackageMetrics = new PackageMetrics(this); mPackageMetrics = new PackageMetrics(this);
mIsInstallInherit = params.mIsInherit; mIsInstallInherit = params.mIsInherit;
@@ -286,6 +287,10 @@ final class InstallRequest {
return mInstallArgs == null ? 0 : mInstallArgs.mInstallFlags; return mInstallArgs == null ? 0 : mInstallArgs.mInstallFlags;
} }
public int getDevelopmentInstallFlags() {
return mInstallArgs == null ? 0 : mInstallArgs.mDevelopmentInstallFlags;
}
public int getInstallReason() { public int getInstallReason() {
return mInstallArgs == null ? INSTALL_REASON_UNKNOWN : mInstallArgs.mInstallReason; return mInstallArgs == null ? INSTALL_REASON_UNKNOWN : mInstallArgs.mInstallReason;
} }

View File

@@ -68,6 +68,7 @@ class InstallingSession {
final MoveInfo mMoveInfo; final MoveInfo mMoveInfo;
final IPackageInstallObserver2 mObserver; final IPackageInstallObserver2 mObserver;
int mInstallFlags; int mInstallFlags;
int mDevelopmentInstallFlags;
@NonNull @NonNull
final InstallSource mInstallSource; final InstallSource mInstallSource;
final String mVolumeUuid; final String mVolumeUuid;
@@ -102,8 +103,8 @@ class InstallingSession {
// For move install // For move install
InstallingSession(OriginInfo originInfo, MoveInfo moveInfo, IPackageInstallObserver2 observer, InstallingSession(OriginInfo originInfo, MoveInfo moveInfo, IPackageInstallObserver2 observer,
int installFlags, InstallSource installSource, String volumeUuid, int installFlags, int developmentInstallFlags, InstallSource installSource,
UserHandle user, String packageAbiOverride, int packageSource, String volumeUuid, UserHandle user, String packageAbiOverride, int packageSource,
PackageLite packageLite, PackageManagerService pm) { PackageLite packageLite, PackageManagerService pm) {
mPm = pm; mPm = pm;
mUser = user; mUser = user;
@@ -113,6 +114,7 @@ class InstallingSession {
mMoveInfo = moveInfo; mMoveInfo = moveInfo;
mObserver = observer; mObserver = observer;
mInstallFlags = installFlags; mInstallFlags = installFlags;
mDevelopmentInstallFlags = developmentInstallFlags;
mInstallSource = Preconditions.checkNotNull(installSource); mInstallSource = Preconditions.checkNotNull(installSource);
mVolumeUuid = volumeUuid; mVolumeUuid = volumeUuid;
mPackageAbiOverride = packageAbiOverride; mPackageAbiOverride = packageAbiOverride;
@@ -149,6 +151,7 @@ class InstallingSession {
mInstallScenario = sessionParams.installScenario; mInstallScenario = sessionParams.installScenario;
mObserver = observer; mObserver = observer;
mInstallFlags = sessionParams.installFlags; mInstallFlags = sessionParams.installFlags;
mDevelopmentInstallFlags = sessionParams.developmentInstallFlags;
mInstallSource = installSource; mInstallSource = installSource;
mVolumeUuid = sessionParams.volumeUuid; mVolumeUuid = sessionParams.volumeUuid;
mPackageAbiOverride = sessionParams.abiOverride; mPackageAbiOverride = sessionParams.abiOverride;
@@ -592,6 +595,10 @@ class InstallingSession {
"Only a non-staged install of a single APEX is supported"); "Only a non-staged install of a single APEX is supported");
} }
InstallRequest request = requests.get(0); InstallRequest request = requests.get(0);
boolean force =
(request.getDevelopmentInstallFlags()
& PackageManager.INSTALL_DEVELOPMENT_FORCE_NON_STAGED_APEX_UPDATE)
!= 0;
try { try {
// Should directory scanning logic be moved to ApexManager for better test coverage? // Should directory scanning logic be moved to ApexManager for better test coverage?
final File dir = request.getOriginInfo().mResolvedFile; final File dir = request.getOriginInfo().mResolvedFile;
@@ -608,7 +615,7 @@ class InstallingSession {
PackageManagerException.INTERNAL_ERROR_APEX_MORE_THAN_ONE_FILE); PackageManagerException.INTERNAL_ERROR_APEX_MORE_THAN_ONE_FILE);
} }
try (PackageParser2 packageParser = mPm.mInjector.getScanningPackageParser()) { try (PackageParser2 packageParser = mPm.mInjector.getScanningPackageParser()) {
ApexInfo apexInfo = mPm.mApexManager.installPackage(apexes[0]); ApexInfo apexInfo = mPm.mApexManager.installPackage(apexes[0], force);
// APEX has been handled successfully by apexd. Let's continue the install flow // APEX has been handled successfully by apexd. Let's continue the install flow
// so it will be scanned and registered with the system. // so it will be scanned and registered with the system.
// TODO(b/225756739): Improve atomicity of rebootless APEX install. // TODO(b/225756739): Improve atomicity of rebootless APEX install.

View File

@@ -305,8 +305,9 @@ public final class MovePackageHelper {
new File(origin.mResolvedPath), /* flags */ 0); new File(origin.mResolvedPath), /* flags */ 0);
final PackageLite lite = ret.isSuccess() ? ret.getResult() : null; final PackageLite lite = ret.isSuccess() ? ret.getResult() : null;
final InstallingSession installingSession = new InstallingSession(origin, move, final InstallingSession installingSession = new InstallingSession(origin, move,
installObserver, installFlags, installSource, volumeUuid, user, packageAbiOverride, installObserver, installFlags, /* developmentInstallFlags= */ 0, installSource,
PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED, lite, mPm); volumeUuid, user, packageAbiOverride, PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED,
lite, mPm);
installingSession.movePackage(); installingSession.movePackage();
} }

View File

@@ -709,6 +709,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
!= PackageManager.PERMISSION_GRANTED) { != PackageManager.PERMISSION_GRANTED) {
params.installFlags &= ~PackageManager.INSTALL_ALLOW_TEST; params.installFlags &= ~PackageManager.INSTALL_ALLOW_TEST;
} }
// developmentInstallFlags can ony be set by shell or root.
params.developmentInstallFlags = 0;
} }
String originatingPackageName = null; String originatingPackageName = null;

View File

@@ -3211,6 +3211,13 @@ class PackageManagerShellCommand extends ShellCommand {
// Set package source to other by default // Set package source to other by default
sessionParams.setPackageSource(PackageInstaller.PACKAGE_SOURCE_OTHER); sessionParams.setPackageSource(PackageInstaller.PACKAGE_SOURCE_OTHER);
// Encodes one of the states:
// 1. Install request explicitly specified --staged, then value will be true.
// 2. Install request explicitly specified --non-staged, then value will be false.
// 3. Install request did not specify either --staged or --non-staged, then for APEX
// installs the value will be true, and for apk installs it will be false.
Boolean staged = null;
String opt; String opt;
boolean replaceExisting = true; boolean replaceExisting = true;
boolean forceNonStaged = false; boolean forceNonStaged = false;
@@ -3319,7 +3326,6 @@ class PackageManagerShellCommand extends ShellCommand {
break; break;
case "--apex": case "--apex":
sessionParams.setInstallAsApex(); sessionParams.setInstallAsApex();
sessionParams.setStaged();
break; break;
case "--force-non-staged": case "--force-non-staged":
forceNonStaged = true; forceNonStaged = true;
@@ -3328,7 +3334,10 @@ class PackageManagerShellCommand extends ShellCommand {
sessionParams.setMultiPackage(); sessionParams.setMultiPackage();
break; break;
case "--staged": case "--staged":
sessionParams.setStaged(); staged = true;
break;
case "--non-staged":
staged = false;
break; break;
case "--force-queryable": case "--force-queryable":
sessionParams.setForceQueryable(); sessionParams.setForceQueryable();
@@ -3363,11 +3372,18 @@ class PackageManagerShellCommand extends ShellCommand {
throw new IllegalArgumentException("Unknown option " + opt); throw new IllegalArgumentException("Unknown option " + opt);
} }
} }
if (staged == null) {
staged = (sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0;
}
if (replaceExisting) { if (replaceExisting) {
sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
} }
if (forceNonStaged) { if (forceNonStaged) {
sessionParams.isStaged = false; sessionParams.isStaged = false;
sessionParams.developmentInstallFlags |=
PackageManager.INSTALL_DEVELOPMENT_FORCE_NON_STAGED_APEX_UPDATE;
} else if (staged) {
sessionParams.setStaged();
} }
return params; return params;
} }
@@ -4231,7 +4247,8 @@ class PackageManagerShellCommand extends ShellCommand {
pw.println(" [--preload] [--instant] [--full] [--dont-kill]"); pw.println(" [--preload] [--instant] [--full] [--dont-kill]");
pw.println(" [--enable-rollback]"); pw.println(" [--enable-rollback]");
pw.println(" [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES]"); pw.println(" [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES]");
pw.println(" [--apex] [--force-non-staged] [--staged-ready-timeout TIMEOUT]"); pw.println(" [--apex] [--non-staged] [--force-non-staged]");
pw.println(" [--staged-ready-timeout TIMEOUT]");
pw.println(" [PATH [SPLIT...]|-]"); pw.println(" [PATH [SPLIT...]|-]");
pw.println(" Install an application. Must provide the apk data to install, either as"); pw.println(" Install an application. Must provide the apk data to install, either as");
pw.println(" file path(s) or '-' to read from stdin. Options are:"); pw.println(" file path(s) or '-' to read from stdin. Options are:");
@@ -4260,8 +4277,12 @@ class PackageManagerShellCommand extends ShellCommand {
pw.println(" --update-ownership: request the update ownership enforcement"); pw.println(" --update-ownership: request the update ownership enforcement");
pw.println(" --force-uuid: force install on to disk volume with given UUID"); pw.println(" --force-uuid: force install on to disk volume with given UUID");
pw.println(" --apex: install an .apex file, not an .apk"); pw.println(" --apex: install an .apex file, not an .apk");
pw.println(" --non-staged: explicitly set this installation to be non-staged.");
pw.println(" This flag is only useful for APEX installs that are implicitly");
pw.println(" assumed to be staged.");
pw.println(" --force-non-staged: force the installation to run under a non-staged"); pw.println(" --force-non-staged: force the installation to run under a non-staged");
pw.println(" session, which may complete without requiring a reboot"); pw.println(" session, which may complete without requiring a reboot. This will");
pw.println(" force a rebootless update even for APEXes that don't support it");
pw.println(" --staged-ready-timeout: By default, staged sessions wait " pw.println(" --staged-ready-timeout: By default, staged sessions wait "
+ DEFAULT_STAGED_READY_TIMEOUT_MS); + DEFAULT_STAGED_READY_TIMEOUT_MS);
pw.println(" milliseconds for pre-reboot verification to complete when"); pw.println(" milliseconds for pre-reboot verification to complete when");

View File

@@ -19,6 +19,7 @@ package com.android.server.pm;
import static com.google.common.truth.Truth.assertThat; 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.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doAnswer;
@@ -368,10 +369,11 @@ public class ApexManagerTest {
File finalApex = extractResource("test.rebootles_apex_v2", "test.rebootless_apex_v2.apex"); File finalApex = extractResource("test.rebootles_apex_v2", "test.rebootless_apex_v2.apex");
ApexInfo newApexInfo = createApexInfo("test.apex_rebootless", 2, /* isActive= */ true, ApexInfo newApexInfo = createApexInfo("test.apex_rebootless", 2, /* isActive= */ true,
/* isFactory= */ false, finalApex); /* isFactory= */ false, finalApex);
when(mApexService.installAndActivatePackage(anyString())).thenReturn(newApexInfo); when(mApexService.installAndActivatePackage(anyString(), anyBoolean())).thenReturn(
newApexInfo);
File installedApex = extractResource("installed", "test.rebootless_apex_v2.apex"); File installedApex = extractResource("installed", "test.rebootless_apex_v2.apex");
newApexInfo = mApexManager.installPackage(installedApex); newApexInfo = mApexManager.installPackage(installedApex, /* force= */ false);
var newPkg = mockParsePackage(mPackageParser2, newApexInfo); var newPkg = mockParsePackage(mPackageParser2, newApexInfo);
assertThat(newPkg.getBaseApkPath()).isEqualTo(finalApex.getAbsolutePath()); assertThat(newPkg.getBaseApkPath()).isEqualTo(finalApex.getAbsolutePath());
@@ -398,10 +400,11 @@ public class ApexManagerTest {
File finalApex = extractResource("test.rebootles_apex_v2", "test.rebootless_apex_v2.apex"); File finalApex = extractResource("test.rebootles_apex_v2", "test.rebootless_apex_v2.apex");
ApexInfo newApexInfo = createApexInfo("test.apex_rebootless", 2, /* isActive= */ true, ApexInfo newApexInfo = createApexInfo("test.apex_rebootless", 2, /* isActive= */ true,
/* isFactory= */ false, finalApex); /* isFactory= */ false, finalApex);
when(mApexService.installAndActivatePackage(anyString())).thenReturn(newApexInfo); when(mApexService.installAndActivatePackage(anyString(), anyBoolean())).thenReturn(
newApexInfo);
File installedApex = extractResource("installed", "test.rebootless_apex_v2.apex"); File installedApex = extractResource("installed", "test.rebootless_apex_v2.apex");
newApexInfo = mApexManager.installPackage(installedApex); newApexInfo = mApexManager.installPackage(installedApex, /* force= */ false);
var newPkg = mockParsePackage(mPackageParser2, newApexInfo); var newPkg = mockParsePackage(mPackageParser2, newApexInfo);
assertThat(newPkg.getBaseApkPath()).isEqualTo(finalApex.getAbsolutePath()); assertThat(newPkg.getBaseApkPath()).isEqualTo(finalApex.getAbsolutePath());
@@ -416,13 +419,13 @@ public class ApexManagerTest {
@Test @Test
public void testInstallPackageBinderCallFails() throws Exception { public void testInstallPackageBinderCallFails() throws Exception {
when(mApexService.installAndActivatePackage(anyString())).thenThrow( when(mApexService.installAndActivatePackage(anyString(), anyBoolean())).thenThrow(
new RuntimeException("install failed :(")); new RuntimeException("install failed :("));
File installedApex = extractResource("test.apex_rebootless_v1", File installedApex = extractResource("test.apex_rebootless_v1",
"test.rebootless_apex_v1.apex"); "test.rebootless_apex_v1.apex");
assertThrows(PackageManagerException.class, assertThrows(PackageManagerException.class,
() -> mApexManager.installPackage(installedApex)); () -> mApexManager.installPackage(installedApex, /* force= */ false));
} }
@Test @Test