Merge changes from topic "app-staging"
* changes: Reverify certain conditions during staged install Ensure staged sessions are not installed in app-staging directory Stop creating extra apk session during post-reboot install phase
This commit is contained in:
committed by
Android (Google) Code Review
commit
b522c02e47
@@ -28,6 +28,8 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
|
||||
import static android.content.pm.PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
|
||||
import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SPLIT;
|
||||
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
|
||||
import static android.content.pm.PackageManager.INSTALL_STAGED;
|
||||
import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
|
||||
import static android.content.pm.PackageParser.APEX_FILE_EXTENSION;
|
||||
import static android.content.pm.PackageParser.APK_FILE_EXTENSION;
|
||||
import static android.system.OsConstants.O_CREAT;
|
||||
@@ -1458,7 +1460,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
mChildSessionsRemaining.removeAt(sessionIndex);
|
||||
if (mChildSessionsRemaining.size() == 0) {
|
||||
destroyInternal();
|
||||
dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED,
|
||||
dispatchSessionFinished(INSTALL_SUCCEEDED,
|
||||
"Session installed", null);
|
||||
}
|
||||
} else if (PackageInstaller.STATUS_PENDING_USER_ACTION == status) {
|
||||
@@ -1533,7 +1535,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
|
||||
synchronized (mLock) {
|
||||
assertCallerIsOwnerOrRootLocked();
|
||||
assertPreparedAndNotDestroyedLocked("commit");
|
||||
assertPreparedAndNotDestroyedLocked("commit of session " + sessionId);
|
||||
assertNoWriteFileTransfersOpenLocked();
|
||||
|
||||
final boolean isSecureFrpEnabled =
|
||||
@@ -1663,7 +1665,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
throws PackageManagerException {
|
||||
try {
|
||||
assertNoWriteFileTransfersOpenLocked();
|
||||
assertPreparedAndNotDestroyedLocked("sealing of session");
|
||||
assertPreparedAndNotDestroyedLocked("sealing of session " + sessionId);
|
||||
mSealed = true;
|
||||
} catch (Throwable e) {
|
||||
// Convert all exceptions into package manager exceptions as only those are handled
|
||||
@@ -1701,6 +1703,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private void onSessionInstallationFailure(int error, String detailedMessage) {
|
||||
Slog.e(TAG, "Install of session " + sessionId + " failed: " + detailedMessage);
|
||||
destroyInternal();
|
||||
dispatchSessionFinished(error, detailedMessage, null);
|
||||
}
|
||||
|
||||
private void onStorageHealthStatusChanged(int status) {
|
||||
final String packageName = getPackageName();
|
||||
if (TextUtils.isEmpty(packageName)) {
|
||||
@@ -1757,15 +1765,18 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
try {
|
||||
sealLocked();
|
||||
|
||||
if (isApexSession()) {
|
||||
// APEX installations rely on certain fields to be populated after reboot.
|
||||
// E.g. mPackageName.
|
||||
validateApexInstallLocked();
|
||||
} else {
|
||||
// Populate mPackageName for this APK session which is required by the staging
|
||||
// manager to check duplicate apk-in-apex.
|
||||
PackageInstallerSession parent = allSessions.get(mParentSessionId);
|
||||
if (parent != null && parent.isStagedSessionReady()) {
|
||||
// Session that are staged, ready and not multi package will be installed during
|
||||
// this boot. As such, we need populate all the fields for successful installation.
|
||||
if (isMultiPackage()) {
|
||||
return;
|
||||
}
|
||||
final PackageInstallerSession root = hasParentSessionId()
|
||||
? allSessions.get(getParentSessionId())
|
||||
: this;
|
||||
if (root != null && root.isStagedSessionReady()) {
|
||||
if (isApexSession()) {
|
||||
validateApexInstallLocked();
|
||||
} else {
|
||||
validateApkInstallLocked();
|
||||
}
|
||||
}
|
||||
@@ -1829,7 +1840,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
mStagingManager.commitSession(this);
|
||||
// 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.
|
||||
dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null);
|
||||
dispatchSessionFinished(INSTALL_SUCCEEDED, "Session staged", null);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1911,12 +1922,53 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs apks of staged session while skipping the verification process for a committed and
|
||||
* ready session.
|
||||
*/
|
||||
void installStagedSession(IntentSender statusReceiver) {
|
||||
assertCallerIsOwnerOrRootOrSystemLocked();
|
||||
Preconditions.checkArgument(!hasParentSessionId()); // Don't allow installing child sessions
|
||||
Preconditions.checkArgument(isCommitted() && isStagedSessionReady());
|
||||
|
||||
// Since staged sessions are installed during boot, the original reference to status
|
||||
// receiver from the owner has already been lost. We can safely replace it with a
|
||||
// status receiver from the system without effecting the flow.
|
||||
updateRemoteStatusReceiver(statusReceiver);
|
||||
install();
|
||||
}
|
||||
|
||||
private void updateRemoteStatusReceiver(IntentSender remoteStatusReceiver) {
|
||||
synchronized (mLock) {
|
||||
mRemoteStatusReceiver = remoteStatusReceiver;
|
||||
if (isMultiPackage()) {
|
||||
final IntentSender childIntentSender =
|
||||
new ChildStatusIntentReceiver(mChildSessions.clone(), remoteStatusReceiver)
|
||||
.getIntentSender();
|
||||
for (int i = mChildSessions.size() - 1; i >= 0; --i) {
|
||||
mChildSessions.valueAt(i).mRemoteStatusReceiver = childIntentSender;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void install() {
|
||||
try {
|
||||
installNonStaged();
|
||||
} catch (PackageManagerException e) {
|
||||
final String completeMsg = ExceptionUtils.getCompleteMessage(e);
|
||||
onSessionInstallationFailure(e.error, completeMsg);
|
||||
}
|
||||
}
|
||||
|
||||
private void installNonStaged()
|
||||
throws PackageManagerException {
|
||||
final PackageManagerService.InstallParams installingSession =
|
||||
makeInstallParams();
|
||||
Preconditions.checkArgument(containsApkSession());
|
||||
|
||||
final PackageManagerService.InstallParams installingSession = makeInstallParams();
|
||||
if (installingSession == null) {
|
||||
return;
|
||||
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
|
||||
"Session should contain at least one apk session for installation");
|
||||
}
|
||||
if (isMultiPackage()) {
|
||||
final List<PackageInstallerSession> childSessions;
|
||||
@@ -2084,7 +2136,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
@Override
|
||||
public void onPackageInstalled(String basePackageName, int returnCode, String msg,
|
||||
Bundle extras) {
|
||||
if (returnCode == PackageManager.INSTALL_SUCCEEDED) {
|
||||
if (returnCode == INSTALL_SUCCEEDED) {
|
||||
onVerificationComplete();
|
||||
} else {
|
||||
onSessionVerificationFailure(returnCode, msg);
|
||||
@@ -2126,20 +2178,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
installNonStaged();
|
||||
} catch (PackageManagerException e) {
|
||||
final String completeMsg = ExceptionUtils.getCompleteMessage(e);
|
||||
Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
|
||||
destroyInternal();
|
||||
dispatchSessionFinished(e.error, completeMsg, null);
|
||||
}
|
||||
install();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stages this session for install and returns a
|
||||
* {@link PackageManagerService.InstallParams} representing this new staged state.
|
||||
*/
|
||||
@Nullable
|
||||
private PackageManagerService.InstallParams makeInstallParams()
|
||||
throws PackageManagerException {
|
||||
synchronized (mLock) {
|
||||
@@ -2153,8 +2199,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
// We've reached point of no return; call into PMS to install the stage.
|
||||
// Regardless of success or failure we always destroy session.
|
||||
// Do not try to install apex session. Parent session will have at least one apk session.
|
||||
if (!isMultiPackage() && isApexSession()) {
|
||||
sendUpdateToRemoteStatusReceiver(INSTALL_SUCCEEDED,
|
||||
"Apex package should have been installed by apexd", null);
|
||||
return null;
|
||||
}
|
||||
|
||||
final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
|
||||
@Override
|
||||
public void onUserActionRequired(Intent intent) {
|
||||
@@ -2164,8 +2215,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
@Override
|
||||
public void onPackageInstalled(String basePackageName, int returnCode, String msg,
|
||||
Bundle extras) {
|
||||
destroyInternal();
|
||||
dispatchSessionFinished(returnCode, msg, extras);
|
||||
if (isStaged()) {
|
||||
sendUpdateToRemoteStatusReceiver(returnCode, msg, extras);
|
||||
} else {
|
||||
// We've reached point of no return; call into PMS to install the stage.
|
||||
// Regardless of success or failure we always destroy session.
|
||||
destroyInternal();
|
||||
dispatchSessionFinished(returnCode, msg, extras);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2176,6 +2233,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
user = new UserHandle(userId);
|
||||
}
|
||||
|
||||
if (params.isStaged) {
|
||||
params.installFlags |= INSTALL_STAGED;
|
||||
}
|
||||
|
||||
synchronized (mLock) {
|
||||
return mPm.new InstallParams(stageDir, localObserver, params, mInstallSource, user,
|
||||
mSigningDetails, mInstallerUid);
|
||||
@@ -2952,7 +3013,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
handle = NativeLibraryHelper.Handle.create(packageDir);
|
||||
final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libDir,
|
||||
abiOverride, isIncrementalInstallation());
|
||||
if (res != PackageManager.INSTALL_SUCCEEDED) {
|
||||
if (res != INSTALL_SUCCEEDED) {
|
||||
throw new PackageManagerException(res,
|
||||
"Failed to extract native libraries, res=" + res);
|
||||
}
|
||||
@@ -3586,31 +3647,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
}
|
||||
|
||||
private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
|
||||
final IntentSender statusReceiver;
|
||||
final String packageName;
|
||||
sendUpdateToRemoteStatusReceiver(returnCode, msg, extras);
|
||||
|
||||
synchronized (mLock) {
|
||||
mFinalStatus = returnCode;
|
||||
mFinalMessage = msg;
|
||||
|
||||
statusReceiver = mRemoteStatusReceiver;
|
||||
packageName = mPackageName;
|
||||
}
|
||||
|
||||
if (statusReceiver != null) {
|
||||
// Execute observer.onPackageInstalled on different thread as we don't want callers
|
||||
// inside the system server have to worry about catching the callbacks while they are
|
||||
// calling into the session
|
||||
final SomeArgs args = SomeArgs.obtain();
|
||||
args.arg1 = packageName;
|
||||
args.arg2 = msg;
|
||||
args.arg3 = extras;
|
||||
args.arg4 = statusReceiver;
|
||||
args.argi1 = returnCode;
|
||||
|
||||
mHandler.obtainMessage(MSG_ON_PACKAGE_INSTALLED, args).sendToTarget();
|
||||
}
|
||||
|
||||
final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);
|
||||
final boolean success = (returnCode == INSTALL_SUCCEEDED);
|
||||
|
||||
// Send broadcast to default launcher only if it's a new install
|
||||
// TODO(b/144270665): Secure the usage of this broadcast.
|
||||
@@ -3625,6 +3669,27 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private void sendUpdateToRemoteStatusReceiver(int returnCode, String msg, Bundle extras) {
|
||||
final IntentSender statusReceiver;
|
||||
final String packageName;
|
||||
synchronized (mLock) {
|
||||
statusReceiver = mRemoteStatusReceiver;
|
||||
packageName = mPackageName;
|
||||
}
|
||||
if (statusReceiver != null) {
|
||||
// Execute observer.onPackageInstalled on different thread as we don't want callers
|
||||
// inside the system server have to worry about catching the callbacks while they are
|
||||
// calling into the session
|
||||
final SomeArgs args = SomeArgs.obtain();
|
||||
args.arg1 = packageName;
|
||||
args.arg2 = msg;
|
||||
args.arg3 = extras;
|
||||
args.arg4 = statusReceiver;
|
||||
args.argi1 = returnCode;
|
||||
mHandler.obtainMessage(MSG_ON_PACKAGE_INSTALLED, args).sendToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
/** {@hide} */
|
||||
void setStagedSessionReady() {
|
||||
synchronized (mLock) {
|
||||
@@ -3834,7 +3899,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
private static void sendOnPackageInstalled(Context context, IntentSender target, int sessionId,
|
||||
boolean showNotification, int userId, String basePackageName, int returnCode,
|
||||
String msg, Bundle extras) {
|
||||
if (PackageManager.INSTALL_SUCCEEDED == returnCode && showNotification) {
|
||||
if (INSTALL_SUCCEEDED == returnCode && showNotification) {
|
||||
boolean update = (extras != null) && extras.getBoolean(Intent.EXTRA_REPLACING);
|
||||
Notification notification = PackageInstallerService.buildSuccessNotification(context,
|
||||
context.getResources()
|
||||
|
||||
@@ -66,6 +66,7 @@ import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTEN
|
||||
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
|
||||
import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_RESTORE;
|
||||
import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_SETUP;
|
||||
import static android.content.pm.PackageManager.INSTALL_STAGED;
|
||||
import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
|
||||
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
|
||||
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
|
||||
@@ -14990,6 +14991,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
@Nullable MultiPackageInstallParams mParentInstallParams;
|
||||
final boolean forceQueryableOverride;
|
||||
final int mDataLoaderType;
|
||||
final long requiredInstalledVersionCode;
|
||||
|
||||
InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
|
||||
int installFlags, InstallSource installSource, String volumeUuid,
|
||||
@@ -15010,6 +15012,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
this.installReason = PackageManager.INSTALL_REASON_UNKNOWN;
|
||||
this.forceQueryableOverride = false;
|
||||
this.mDataLoaderType = DataLoaderType.NONE;
|
||||
this.requiredInstalledVersionCode = PackageManager.VERSION_CODE_HIGHEST;
|
||||
}
|
||||
|
||||
InstallParams(File stagedDir, IPackageInstallObserver2 observer,
|
||||
@@ -15032,6 +15035,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
forceQueryableOverride = sessionParams.forceQueryableOverride;
|
||||
mDataLoaderType = (sessionParams.dataLoaderParams != null)
|
||||
? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE;
|
||||
requiredInstalledVersionCode = sessionParams.requiredInstalledVersionCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -15178,6 +15182,18 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
public void handleStartCopy() {
|
||||
PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
|
||||
origin.resolvedPath, installFlags, packageAbiOverride);
|
||||
|
||||
// For staged session, there is a delay between its verification and install. Device
|
||||
// state can change within this delay and hence we need to re-verify certain conditions.
|
||||
boolean isStaged = (installFlags & INSTALL_STAGED) != 0;
|
||||
if (isStaged) {
|
||||
mRet = verifyReplacingVersionCode(
|
||||
pkgLite, requiredInstalledVersionCode, installFlags);
|
||||
if (mRet != INSTALL_SUCCEEDED) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mRet = overrideInstallLocation(pkgLite);
|
||||
}
|
||||
|
||||
@@ -15324,11 +15340,14 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
|
||||
origin.resolvedPath, installFlags, packageAbiOverride);
|
||||
|
||||
mRet = verifyReplacingVersionCode(pkgLite);
|
||||
mRet = verifyReplacingVersionCode(pkgLite, requiredInstalledVersionCode, installFlags);
|
||||
if (mRet != INSTALL_SUCCEEDED) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform package verification and enable rollback (unless we are simply moving the
|
||||
// package).
|
||||
if (mRet == INSTALL_SUCCEEDED && !origin.existing) {
|
||||
if (!origin.existing) {
|
||||
sendApkVerificationRequest(pkgLite);
|
||||
if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
|
||||
sendEnableRollbackRequest();
|
||||
@@ -15336,54 +15355,6 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
private int verifyReplacingVersionCode(PackageInfoLite pkgLite) {
|
||||
String packageName = pkgLite.packageName;
|
||||
synchronized (mLock) {
|
||||
// Package which currently owns the data that the new package will own if installed.
|
||||
// If an app is uninstalled while keeping data (e.g. adb uninstall -k), installedPkg
|
||||
// will be null whereas dataOwnerPkg will contain information about the package
|
||||
// which was uninstalled while keeping its data.
|
||||
AndroidPackage dataOwnerPkg = mPackages.get(packageName);
|
||||
if (dataOwnerPkg == null) {
|
||||
PackageSetting ps = mSettings.mPackages.get(packageName);
|
||||
if (ps != null) {
|
||||
dataOwnerPkg = ps.pkg;
|
||||
}
|
||||
}
|
||||
|
||||
if (requiredInstalledVersionCode != PackageManager.VERSION_CODE_HIGHEST) {
|
||||
if (dataOwnerPkg == null) {
|
||||
Slog.w(TAG, "Required installed version code was "
|
||||
+ requiredInstalledVersionCode
|
||||
+ " but package is not installed");
|
||||
return PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION;
|
||||
}
|
||||
|
||||
if (dataOwnerPkg.getLongVersionCode() != requiredInstalledVersionCode) {
|
||||
Slog.w(TAG, "Required installed version code was "
|
||||
+ requiredInstalledVersionCode
|
||||
+ " but actual installed version is "
|
||||
+ dataOwnerPkg.getLongVersionCode());
|
||||
return PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION;
|
||||
}
|
||||
}
|
||||
|
||||
if (dataOwnerPkg != null) {
|
||||
if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags,
|
||||
dataOwnerPkg.isDebuggable())) {
|
||||
try {
|
||||
checkDowngrade(dataOwnerPkg, pkgLite);
|
||||
} catch (PackageManagerException e) {
|
||||
Slog.w(TAG, "Downgrade detected: " + e.getMessage());
|
||||
return PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return PackageManager.INSTALL_SUCCEEDED;
|
||||
}
|
||||
|
||||
|
||||
void sendApkVerificationRequest(PackageInfoLite pkgLite) {
|
||||
final int verificationId = mPendingVerificationToken++;
|
||||
|
||||
@@ -15977,7 +15948,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
return false;
|
||||
}
|
||||
|
||||
final File targetDir = codeFile.getParentFile();
|
||||
final File targetDir = resolveTargetDir();
|
||||
final File beforeCodeFile = codeFile;
|
||||
final File afterCodeFile = getNextCodePath(targetDir, parsedPackage.getPackageName());
|
||||
|
||||
@@ -16020,6 +15991,17 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO(b/168126411): Once staged install flow starts using the same folder as non-staged
|
||||
// flow, we won't need this method anymore.
|
||||
private File resolveTargetDir() {
|
||||
boolean isStagedInstall = (installFlags & INSTALL_STAGED) != 0;
|
||||
if (isStagedInstall) {
|
||||
return Environment.getDataAppDirectory(null);
|
||||
} else {
|
||||
return codeFile.getParentFile();
|
||||
}
|
||||
}
|
||||
|
||||
int doPostInstall(int status, int uid) {
|
||||
if (status != PackageManager.INSTALL_SUCCEEDED) {
|
||||
cleanUp();
|
||||
@@ -24197,6 +24179,54 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
private int verifyReplacingVersionCode(PackageInfoLite pkgLite,
|
||||
long requiredInstalledVersionCode, int installFlags) {
|
||||
String packageName = pkgLite.packageName;
|
||||
synchronized (mLock) {
|
||||
// Package which currently owns the data that the new package will own if installed.
|
||||
// If an app is uninstalled while keeping data (e.g. adb uninstall -k), installedPkg
|
||||
// will be null whereas dataOwnerPkg will contain information about the package
|
||||
// which was uninstalled while keeping its data.
|
||||
AndroidPackage dataOwnerPkg = mPackages.get(packageName);
|
||||
if (dataOwnerPkg == null) {
|
||||
PackageSetting ps = mSettings.mPackages.get(packageName);
|
||||
if (ps != null) {
|
||||
dataOwnerPkg = ps.pkg;
|
||||
}
|
||||
}
|
||||
|
||||
if (requiredInstalledVersionCode != PackageManager.VERSION_CODE_HIGHEST) {
|
||||
if (dataOwnerPkg == null) {
|
||||
Slog.w(TAG, "Required installed version code was "
|
||||
+ requiredInstalledVersionCode
|
||||
+ " but package is not installed");
|
||||
return PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION;
|
||||
}
|
||||
|
||||
if (dataOwnerPkg.getLongVersionCode() != requiredInstalledVersionCode) {
|
||||
Slog.w(TAG, "Required installed version code was "
|
||||
+ requiredInstalledVersionCode
|
||||
+ " but actual installed version is "
|
||||
+ dataOwnerPkg.getLongVersionCode());
|
||||
return PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION;
|
||||
}
|
||||
}
|
||||
|
||||
if (dataOwnerPkg != null) {
|
||||
if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags,
|
||||
dataOwnerPkg.isDebuggable())) {
|
||||
try {
|
||||
checkDowngrade(dataOwnerPkg, pkgLite);
|
||||
} catch (PackageManagerException e) {
|
||||
Slog.w(TAG, "Downgrade detected: " + e.getMessage());
|
||||
return PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return PackageManager.INSTALL_SUCCEEDED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check and throw if the given before/after packages would be considered a
|
||||
* downgrade.
|
||||
|
||||
@@ -794,18 +794,18 @@ public class StagingManager {
|
||||
|
||||
private void installApksInSession(PackageInstallerSession session)
|
||||
throws PackageManagerException {
|
||||
final PackageInstallerSession apksToInstall = extractApksInSession(session);
|
||||
if (apksToInstall == null) {
|
||||
if (!session.containsApkSession()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((apksToInstall.params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
|
||||
if ((session.params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
|
||||
// If rollback is available for this session, notify the rollback
|
||||
// manager of the apk session so it can properly enable rollback.
|
||||
final RollbackManagerInternal rm =
|
||||
LocalServices.getService(RollbackManagerInternal.class);
|
||||
try {
|
||||
rm.notifyStagedApkSession(session.sessionId, apksToInstall.sessionId);
|
||||
// TODO(b/136257624): extra apk session id in rollback is now redundant.
|
||||
rm.notifyStagedApkSession(session.sessionId, session.sessionId);
|
||||
} catch (RuntimeException re) {
|
||||
Slog.e(TAG, "Failed to notifyStagedApkSession for session: "
|
||||
+ session.sessionId, re);
|
||||
@@ -813,7 +813,7 @@ public class StagingManager {
|
||||
}
|
||||
|
||||
final LocalIntentReceiverSync receiver = new LocalIntentReceiverSync();
|
||||
apksToInstall.commit(receiver.getIntentSender(), false);
|
||||
session.installStagedSession(receiver.getIntentSender());
|
||||
final Intent result = receiver.getResult();
|
||||
final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
|
||||
PackageInstaller.STATUS_FAILURE);
|
||||
|
||||
Reference in New Issue
Block a user