Fix one child MultiPackage session user action fails
* validateApkInstallLocked stores the target SDK version of the base apk in mValidatedTargetSdk used in IsSolvedUserAction. * Moves checking UserAction stuff from prepareForVerification to IsSolvedUserAction. * setPermissionsResult triggers either itself or its parent session to be installed. * Package Verification gets rid of UserAction Fixes: 183919452 Test: atest CtsSilentUpdateHostTestCases CtsPackageInstallTestCases Change-Id: I2be662c91f46299da2e47aa8531df33ba2f8e8c3
This commit is contained in:
@@ -46,9 +46,11 @@ import static com.android.internal.util.XmlUtils.writeUriAttribute;
|
||||
import static com.android.server.pm.PackageInstallerService.prepareStageDir;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.AnyThread;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.WorkerThread;
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
@@ -262,6 +264,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
private static final int INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS = 7000;
|
||||
private static final int INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS = 60000;
|
||||
|
||||
/**
|
||||
* The default value of {@link #mValidatedTargetSdk} is {@link Integer#MAX_VALUE}. If {@link
|
||||
* #mValidatedTargetSdk} is compared with {@link Build.VERSION_CODES#Q} before getting the
|
||||
* target sdk version from a validated apk in {@link #validateApkInstallLocked()}, the compared
|
||||
* result will not trigger any user action in
|
||||
* {@link #checkUserActionRequirement(PackageInstallerSession)}.
|
||||
*/
|
||||
private static final int INVALID_TARGET_SDK_VERSION = Integer.MAX_VALUE;
|
||||
|
||||
// TODO: enforce INSTALL_ALLOW_TEST
|
||||
// TODO: enforce INSTALL_ALLOW_DOWNGRADE
|
||||
|
||||
@@ -796,6 +807,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
@GuardedBy("mLock")
|
||||
private PackageLite mPackageLite;
|
||||
|
||||
/**
|
||||
* Keep the target sdk of a validated apk.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
private int mValidatedTargetSdk = INVALID_TARGET_SDK_VERSION;
|
||||
|
||||
private static final FileFilter sAddedApkFilter = new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File file) {
|
||||
@@ -1727,6 +1744,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
mHandler.obtainMessage(MSG_STREAM_VALIDATE_AND_COMMIT).sendToTarget();
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private void handleStreamValidateAndCommit() {
|
||||
PackageManagerException unrecoverableFailure = null;
|
||||
// This will track whether the session and any children were validated and are ready to
|
||||
@@ -1976,6 +1994,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
* exception is thrown.
|
||||
* @throws PackageManagerException on an unrecoverable error.
|
||||
*/
|
||||
@WorkerThread
|
||||
private boolean streamValidateAndCommit() throws PackageManagerException {
|
||||
// TODO(patb): since the work done here for a parent session in a multi-package install is
|
||||
// mostly superficial, consider splitting this method for the parent and
|
||||
@@ -2137,6 +2156,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
* immutable by the caller during the method call. Used to resolve child
|
||||
* sessions Ids to actual object reference.
|
||||
*/
|
||||
@AnyThread
|
||||
void onAfterSessionRead(SparseArray<PackageInstallerSession> allSessions) {
|
||||
synchronized (mLock) {
|
||||
// Resolve null values to actual object references
|
||||
@@ -2222,6 +2242,51 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private static boolean checkUserActionRequirement(PackageInstallerSession session) {
|
||||
if (session.isMultiPackage()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@UserActionRequirement int userActionRequirement = USER_ACTION_NOT_NEEDED;
|
||||
// TODO(b/159331446): Move this to makeSessionActiveForInstall and update javadoc
|
||||
userActionRequirement = session.computeUserActionRequirement();
|
||||
if (userActionRequirement == USER_ACTION_REQUIRED) {
|
||||
session.sendPendingUserActionIntent();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!session.isApexSession() && userActionRequirement == USER_ACTION_PENDING_APK_PARSING) {
|
||||
final int validatedTargetSdk;
|
||||
synchronized (session.mLock) {
|
||||
validatedTargetSdk = session.mValidatedTargetSdk;
|
||||
}
|
||||
|
||||
if (validatedTargetSdk != INVALID_TARGET_SDK_VERSION
|
||||
&& validatedTargetSdk < Build.VERSION_CODES.Q) {
|
||||
session.sendPendingUserActionIntent();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out any session needs user action.
|
||||
*
|
||||
* @return true if the session set requires user action for the installation, otherwise false.
|
||||
*/
|
||||
@WorkerThread
|
||||
private boolean sendPendingUserActionIntentIfNeeded() {
|
||||
synchronized (mLock) {
|
||||
assertNotChildLocked("PackageInstallerSession#sendPendingUserActionIntentIfNeeded");
|
||||
}
|
||||
|
||||
return sessionContains(PackageInstallerSession::checkUserActionRequirement);
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private void handleInstall() {
|
||||
if (isInstallerDeviceOwnerOrAffiliatedProfileOwner()) {
|
||||
DevicePolicyEventLogger
|
||||
@@ -2229,6 +2294,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
.setAdmin(mInstallSource.installerPackageName)
|
||||
.write();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the installation of the whole session set if one session needs user action
|
||||
* in its belong session set. When the user answers the yes,
|
||||
* {@link #setPermissionsResult(boolean)} is called and then {@link #MSG_INSTALL} is
|
||||
* handled to come back here to check again.
|
||||
*/
|
||||
if (sendPendingUserActionIntentIfNeeded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (params.isStaged) {
|
||||
// TODO(b/136257624): CTS test fails if we don't send session finished broadcast, even
|
||||
// though ideally, we just need to send session committed broadcast.
|
||||
@@ -2253,9 +2329,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
throws PackageManagerException {
|
||||
final PackageManagerService.VerificationParams verifyingSession =
|
||||
prepareForVerification();
|
||||
if (verifyingSession == null) {
|
||||
return;
|
||||
}
|
||||
if (isMultiPackage()) {
|
||||
final List<PackageInstallerSession> childSessions;
|
||||
synchronized (mLock) {
|
||||
@@ -2270,9 +2343,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
try {
|
||||
final PackageManagerService.VerificationParams verifyingChildSession =
|
||||
session.prepareForVerification();
|
||||
if (verifyingChildSession != null) {
|
||||
verifyingChildSessions.add(verifyingChildSession);
|
||||
}
|
||||
verifyingChildSessions.add(verifyingChildSession);
|
||||
} catch (PackageManagerException e) {
|
||||
failure = e;
|
||||
success = false;
|
||||
@@ -2355,22 +2426,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
* {@link PackageManagerService.VerificationParams} representing this new staged state or null
|
||||
* in case permissions need to be requested before verification can proceed.
|
||||
*/
|
||||
@Nullable
|
||||
@NonNull
|
||||
private PackageManagerService.VerificationParams prepareForVerification()
|
||||
throws PackageManagerException {
|
||||
assertNotLocked("makeSessionActive");
|
||||
|
||||
@UserActionRequirement
|
||||
int userActionRequirement = USER_ACTION_NOT_NEEDED;
|
||||
// TODO(b/159331446): Move this to makeSessionActiveForInstall and update javadoc
|
||||
if (!params.isMultiPackage) {
|
||||
userActionRequirement = computeUserActionRequirement();
|
||||
if (userActionRequirement == USER_ACTION_REQUIRED) {
|
||||
sendPendingUserActionIntent();
|
||||
return null;
|
||||
} // else, we'll wait until we parse to determine if we need to
|
||||
}
|
||||
|
||||
synchronized (mLock) {
|
||||
if (mRelinquished) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
|
||||
@@ -2395,12 +2455,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
|
||||
extractNativeLibraries(
|
||||
mPackageLite, stageDir, params.abiOverride, mayInheritNativeLibs());
|
||||
|
||||
if (userActionRequirement == USER_ACTION_PENDING_APK_PARSING
|
||||
&& (result.getTargetSdk() < Build.VERSION_CODES.Q)) {
|
||||
sendPendingUserActionIntent();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return makeVerificationParamsLocked();
|
||||
@@ -2807,7 +2861,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
@GuardedBy("mLock")
|
||||
private PackageLite validateApkInstallLocked() throws PackageManagerException {
|
||||
ApkLite baseApk = null;
|
||||
PackageLite packageLite = null;
|
||||
final PackageLite packageLite;
|
||||
mPackageLite = null;
|
||||
mPackageName = null;
|
||||
mVersionCode = -1;
|
||||
@@ -3114,6 +3168,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
mIncrementalFileStorages.disallowReadLogs();
|
||||
}
|
||||
}
|
||||
|
||||
// {@link #sendPendingUserActionIntentIfNeeded} needs to use
|
||||
// {@link PackageLite#getTargetSdk()}
|
||||
mValidatedTargetSdk = packageLite.getTargetSdk();
|
||||
|
||||
return packageLite;
|
||||
}
|
||||
|
||||
@@ -3525,8 +3584,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
// Mark and kick off another install pass
|
||||
synchronized (mLock) {
|
||||
mPermissionsManuallyAccepted = true;
|
||||
mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
|
||||
}
|
||||
|
||||
PackageInstallerSession root =
|
||||
(hasParentSessionId())
|
||||
? mSessionProvider.getSession(getParentSessionId())
|
||||
: this;
|
||||
root.mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
|
||||
} else {
|
||||
destroyInternal();
|
||||
dispatchSessionFinished(INSTALL_FAILED_ABORTED, "User rejected permissions", null);
|
||||
|
||||
Reference in New Issue
Block a user