Merge "[pm] consolidate InstallRequest and InstalledPackageInfo"

This commit is contained in:
Song Chun Fan
2022-09-20 18:20:43 +00:00
committed by Android (Google) Code Review
14 changed files with 752 additions and 514 deletions

View File

@@ -271,7 +271,8 @@ final class DeletePackageHelper {
// other processes clean up before deleting resources.
synchronized (mPm.mInstallLock) {
if (info.mArgs != null) {
mRemovePackageHelper.cleanUpResources(info.mArgs);
mRemovePackageHelper.cleanUpResources(info.mArgs.mCodeFile,
info.mArgs.mInstructionSets);
}
boolean reEnableStub = false;

View File

@@ -70,10 +70,9 @@ final class InstallArgs {
UserHandle user, String[] instructionSets,
String abiOverride, String[] installGrantPermissions,
List<String> allowlistedRestrictedPermissions,
int autoRevokePermissionsMode,
String traceMethod, int traceCookie, SigningDetails signingDetails,
int installReason, int installScenario, boolean forceQueryableOverride,
int dataLoaderType, int packageSource) {
int autoRevokePermissionsMode, String traceMethod, int traceCookie,
SigningDetails signingDetails, int installReason, int installScenario,
boolean forceQueryableOverride, int dataLoaderType, int packageSource) {
mOriginInfo = originInfo;
mMoveInfo = moveInfo;
mInstallFlags = installFlags;
@@ -96,18 +95,6 @@ final class InstallArgs {
mPackageSource = packageSource;
}
/** New install */
InstallArgs(InstallingSession params) {
this(params.mOriginInfo, params.mMoveInfo, params.mObserver, params.mInstallFlags,
params.mInstallSource, params.mVolumeUuid,
params.getUser(), null /*instructionSets*/, params.mPackageAbiOverride,
params.mGrantedRuntimePermissions, params.mAllowlistedRestrictedPermissions,
params.mAutoRevokePermissionsMode,
params.mTraceMethod, params.mTraceCookie, params.mSigningDetails,
params.mInstallReason, params.mInstallScenario, params.mForceQueryableOverride,
params.mDataLoaderType, params.mPackageSource);
}
/**
* Create args that describe an existing installed package. Typically used
* when cleaning up old installs, or used as a move source.

View File

@@ -16,12 +16,389 @@
package com.android.server.pm;
final class InstallRequest {
public final InstallArgs mArgs;
public final PackageInstalledInfo mInstallResult;
import static android.content.pm.PackageManager.INSTALL_REASON_UNKNOWN;
import static android.content.pm.PackageManager.INSTALL_SCENARIO_DEFAULT;
InstallRequest(InstallArgs args, PackageInstalledInfo res) {
mArgs = args;
mInstallResult = res;
import static com.android.server.pm.PackageManagerService.TAG;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.apex.ApexInfo;
import android.app.AppOpsManager;
import android.content.pm.DataLoaderType;
import android.content.pm.IPackageInstallObserver2;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.SigningDetails;
import android.net.Uri;
import android.os.UserHandle;
import android.util.ExceptionUtils;
import android.util.Slog;
import com.android.server.pm.pkg.AndroidPackage;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
final class InstallRequest {
private final int mUserId;
@Nullable
private final InstallArgs mInstallArgs;
@NonNull
private final PackageInstalledInfo mInstalledInfo;
@Nullable
private Runnable mPostInstallRunnable;
@Nullable
private PackageRemovedInfo mRemovedInfo;
// New install
InstallRequest(InstallingSession params) {
mUserId = params.getUser().getIdentifier();
mInstallArgs = new InstallArgs(params.mOriginInfo, params.mMoveInfo, params.mObserver,
params.mInstallFlags, params.mInstallSource, params.mVolumeUuid,
params.getUser(), null /*instructionSets*/, params.mPackageAbiOverride,
params.mGrantedRuntimePermissions, params.mAllowlistedRestrictedPermissions,
params.mAutoRevokePermissionsMode,
params.mTraceMethod, params.mTraceCookie, params.mSigningDetails,
params.mInstallReason, params.mInstallScenario, params.mForceQueryableOverride,
params.mDataLoaderType, params.mPackageSource);
mInstalledInfo = new PackageInstalledInfo();
}
// Install existing package as user
InstallRequest(int userId, int returnCode, AndroidPackage pkg, int[] newUsers,
Runnable runnable) {
mUserId = userId;
mInstallArgs = null;
mInstalledInfo = new PackageInstalledInfo();
mInstalledInfo.mReturnCode = returnCode;
mInstalledInfo.mPkg = pkg;
mInstalledInfo.mNewUsers = newUsers;
mPostInstallRunnable = runnable;
}
private static class PackageInstalledInfo {
String mName;
int mUid = -1;
// The set of users that originally had this package installed.
int[] mOrigUsers;
// The set of users that now have this package installed.
int[] mNewUsers;
AndroidPackage mPkg;
int mReturnCode;
String mReturnMsg;
String mInstallerPackageName;
// The set of packages consuming this shared library or null if no consumers exist.
ArrayList<AndroidPackage> mLibraryConsumers;
PackageFreezer mFreezer;
// In some error cases we want to convey more info back to the observer
String mOrigPackage;
String mOrigPermission;
// The ApexInfo returned by ApexManager#installPackage, used by rebootless APEX install
ApexInfo mApexInfo;
}
public String getName() {
return mInstalledInfo.mName;
}
public String getReturnMsg() {
return mInstalledInfo.mReturnMsg;
}
public OriginInfo getOriginInfo() {
return mInstallArgs == null ? null : mInstallArgs.mOriginInfo;
}
public PackageRemovedInfo getRemovedInfo() {
return mRemovedInfo;
}
public String getOrigPackage() {
return mInstalledInfo.mOrigPackage;
}
public String getOrigPermission() {
return mInstalledInfo.mOrigPermission;
}
@Nullable
public File getCodeFile() {
return mInstallArgs == null ? null : mInstallArgs.mCodeFile;
}
@Nullable
public String getCodePath() {
return (mInstallArgs != null && mInstallArgs.mCodeFile != null)
? mInstallArgs.mCodeFile.getAbsolutePath() : null;
}
@Nullable
public String getAbiOverride() {
return mInstallArgs == null ? null : mInstallArgs.mAbiOverride;
}
public int getReturnCode() {
return mInstalledInfo.mReturnCode;
}
@Nullable
public IPackageInstallObserver2 getObserver() {
return mInstallArgs == null ? null : mInstallArgs.mObserver;
}
public boolean isMoveInstall() {
return mInstallArgs != null && mInstallArgs.mMoveInfo != null;
}
@Nullable
public String getMoveToUuid() {
return (mInstallArgs != null && mInstallArgs.mMoveInfo != null)
? mInstallArgs.mMoveInfo.mToUuid : null;
}
@Nullable
public String getMovePackageName() {
return (mInstallArgs != null && mInstallArgs.mMoveInfo != null)
? mInstallArgs.mMoveInfo.mPackageName : null;
}
@Nullable
public String getMoveFromCodePath() {
return (mInstallArgs != null && mInstallArgs.mMoveInfo != null)
? mInstallArgs.mMoveInfo.mFromCodePath : null;
}
@Nullable
public File getOldCodeFile() {
return (mRemovedInfo != null && mRemovedInfo.mArgs != null)
? mRemovedInfo.mArgs.mCodeFile : null;
}
@Nullable
public String[] getOldInstructionSet() {
return (mRemovedInfo != null && mRemovedInfo.mArgs != null)
? mRemovedInfo.mArgs.mInstructionSets : null;
}
public UserHandle getUser() {
return new UserHandle(mUserId);
}
public int getUserId() {
return mUserId;
}
public int getInstallFlags() {
return mInstallArgs == null ? 0 : mInstallArgs.mInstallFlags;
}
public int getInstallReason() {
return mInstallArgs == null ? INSTALL_REASON_UNKNOWN : mInstallArgs.mInstallReason;
}
@Nullable
public String getVolumeUuid() {
return mInstallArgs == null ? null : mInstallArgs.mVolumeUuid;
}
public AndroidPackage getPkg() {
return mInstalledInfo.mPkg;
}
@Nullable
public String getTraceMethod() {
return mInstallArgs == null ? null : mInstallArgs.mTraceMethod;
}
public int getTraceCookie() {
return mInstallArgs == null ? 0 : mInstallArgs.mTraceCookie;
}
public boolean isUpdate() {
return mRemovedInfo != null && mRemovedInfo.mRemovedPackage != null;
}
@Nullable
public String getRemovedPackage() {
return mRemovedInfo != null ? mRemovedInfo.mRemovedPackage : null;
}
public boolean isInstallForExistingUser() {
return mInstallArgs == null;
}
@Nullable
public InstallSource getInstallSource() {
return mInstallArgs == null ? null : mInstallArgs.mInstallSource;
}
@Nullable
public String getInstallerPackageName() {
return (mInstallArgs != null && mInstallArgs.mInstallSource != null)
? mInstallArgs.mInstallSource.installerPackageName : null;
}
public int getDataLoaderType() {
return mInstallArgs == null ? DataLoaderType.NONE : mInstallArgs.mDataLoaderType;
}
public int getSignatureSchemeVersion() {
return mInstallArgs == null ? SigningDetails.SignatureSchemeVersion.UNKNOWN
: mInstallArgs.mSigningDetails.getSignatureSchemeVersion();
}
@NonNull
public SigningDetails getSigningDetails() {
return mInstallArgs == null ? SigningDetails.UNKNOWN : mInstallArgs.mSigningDetails;
}
@Nullable
public Uri getOriginUri() {
return mInstallArgs == null ? null : Uri.fromFile(mInstallArgs.mOriginInfo.mResolvedFile);
}
public ApexInfo getApexInfo() {
return mInstalledInfo.mApexInfo;
}
public String getSourceInstallerPackageName() {
return mInstallArgs.mInstallSource.installerPackageName;
}
public boolean isRollback() {
return mInstallArgs != null
&& mInstallArgs.mInstallReason == PackageManager.INSTALL_REASON_ROLLBACK;
}
public int[] getNewUsers() {
return mInstalledInfo.mNewUsers;
}
public int[] getOriginUsers() {
return mInstalledInfo.mOrigUsers;
}
public int getUid() {
return mInstalledInfo.mUid;
}
@Nullable
public String[] getInstallGrantPermissions() {
return mInstallArgs == null ? null : mInstallArgs.mInstallGrantPermissions;
}
public ArrayList<AndroidPackage> getLibraryConsumers() {
return mInstalledInfo.mLibraryConsumers;
}
@Nullable
public List<String> getAllowlistedRestrictedPermissions() {
return mInstallArgs == null ? null : mInstallArgs.mAllowlistedRestrictedPermissions;
}
public int getAutoRevokePermissionsMode() {
return mInstallArgs == null
? AppOpsManager.MODE_DEFAULT : mInstallArgs.mAutoRevokePermissionsMode;
}
public int getPackageSource() {
return mInstallArgs == null
? PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED : mInstallArgs.mPackageSource;
}
public int getInstallScenario() {
return mInstallArgs == null ? INSTALL_SCENARIO_DEFAULT : mInstallArgs.mInstallScenario;
}
public boolean isForceQueryableOverride() {
return mInstallArgs != null && mInstallArgs.mForceQueryableOverride;
}
public void closeFreezer() {
if (mInstalledInfo.mFreezer != null) {
mInstalledInfo.mFreezer.close();
}
}
public void runPostInstallRunnable() {
if (mPostInstallRunnable != null) {
mPostInstallRunnable.run();
}
}
public void setCodeFile(File codeFile) {
if (mInstallArgs != null) {
mInstallArgs.mCodeFile = codeFile;
}
}
public void setError(int code, String msg) {
setReturnCode(code);
setReturnMessage(msg);
Slog.w(TAG, msg);
}
public void setError(String msg, PackageManagerException e) {
mInstalledInfo.mReturnCode = e.error;
setReturnMessage(ExceptionUtils.getCompleteMessage(msg, e));
Slog.w(TAG, msg, e);
}
public void setReturnCode(int returnCode) {
mInstalledInfo.mReturnCode = returnCode;
}
public void setReturnMessage(String returnMsg) {
mInstalledInfo.mReturnMsg = returnMsg;
}
public void setApexInfo(ApexInfo apexInfo) {
mInstalledInfo.mApexInfo = apexInfo;
}
public void setPkg(AndroidPackage pkg) {
mInstalledInfo.mPkg = pkg;
}
public void setUid(int uid) {
mInstalledInfo.mUid = uid;
}
public void setNewUsers(int[] newUsers) {
mInstalledInfo.mNewUsers = newUsers;
}
public void setOriginPackage(String originPackage) {
mInstalledInfo.mOrigPackage = originPackage;
}
public void setOriginPermission(String originPermission) {
mInstalledInfo.mOrigPermission = originPermission;
}
public void setInstallerPackageName(String installerPackageName) {
mInstalledInfo.mInstallerPackageName = installerPackageName;
}
public void setName(String packageName) {
mInstalledInfo.mName = packageName;
}
public void setOriginUsers(int[] userIds) {
mInstalledInfo.mOrigUsers = userIds;
}
public void setFreezer(PackageFreezer freezer) {
mInstalledInfo.mFreezer = freezer;
}
public void setRemovedInfo(PackageRemovedInfo removedInfo) {
mRemovedInfo = removedInfo;
}
public void setLibraryConsumers(ArrayList<AndroidPackage> libraryConsumers) {
mInstalledInfo.mLibraryConsumers = libraryConsumers;
}
}

View File

@@ -253,68 +253,69 @@ class InstallingSession {
}
private void processPendingInstall() {
InstallArgs args = new InstallArgs(this);
InstallRequest installRequest = new InstallRequest(this);
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
mRet = copyApk(args);
mRet = copyApk(installRequest);
}
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
F2fsUtils.releaseCompressedBlocks(
mPm.mContext.getContentResolver(), new File(args.getCodePath()));
mPm.mContext.getContentResolver(), new File(installRequest.getCodePath()));
}
installRequest.setReturnCode(mRet);
if (mParentInstallingSession != null) {
mParentInstallingSession.tryProcessInstallRequest(args, mRet);
mParentInstallingSession.tryProcessInstallRequest(installRequest);
} else {
PackageInstalledInfo res = new PackageInstalledInfo(mRet);
// Queue up an async operation since the package installation may take a little while.
mPm.mHandler.post(() -> processInstallRequests(
res.mReturnCode == PackageManager.INSTALL_SUCCEEDED /* success */,
Collections.singletonList(new InstallRequest(args, res))));
mRet == PackageManager.INSTALL_SUCCEEDED /* success */,
Collections.singletonList(installRequest)));
}
}
private int copyApk(InstallArgs args) {
private int copyApk(InstallRequest request) {
if (mMoveInfo == null) {
return copyApkForFileInstall(args);
return copyApkForFileInstall(request);
} else {
return copyApkForMoveInstall(args);
return copyApkForMoveInstall(request);
}
}
private int copyApkForFileInstall(InstallArgs args) {
private int copyApkForFileInstall(InstallRequest request) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
try {
if (mOriginInfo.mStaged) {
if (DEBUG_INSTALL) {
Slog.d(TAG, mOriginInfo.mFile + " already staged; skipping copy");
}
args.mCodeFile = mOriginInfo.mFile;
request.setCodeFile(mOriginInfo.mFile);
return PackageManager.INSTALL_SUCCEEDED;
}
try {
final boolean isEphemeral =
(mInstallFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
args.mCodeFile =
mPm.mInstallerService.allocateStageDirLegacy(mVolumeUuid, isEphemeral);
request.setCodeFile(
mPm.mInstallerService.allocateStageDirLegacy(mVolumeUuid, isEphemeral));
} catch (IOException e) {
Slog.w(TAG, "Failed to create copy file: " + e);
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
int ret = PackageManagerServiceUtils.copyPackage(
mOriginInfo.mFile.getAbsolutePath(), args.mCodeFile);
mOriginInfo.mFile.getAbsolutePath(), request.getCodeFile());
if (ret != PackageManager.INSTALL_SUCCEEDED) {
Slog.e(TAG, "Failed to copy package");
return ret;
}
final boolean isIncremental = isIncrementalPath(args.mCodeFile.getAbsolutePath());
final File libraryRoot = new File(args.mCodeFile, LIB_DIR_NAME);
final boolean isIncremental = isIncrementalPath(
request.getCodeFile().getAbsolutePath());
final File libraryRoot = new File(request.getCodeFile(), LIB_DIR_NAME);
NativeLibraryHelper.Handle handle = null;
try {
handle = NativeLibraryHelper.Handle.create(args.mCodeFile);
handle = NativeLibraryHelper.Handle.create(request.getCodeFile());
ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
args.mAbiOverride, isIncremental);
request.getAbiOverride(), isIncremental);
} catch (IOException e) {
Slog.e(TAG, "Copying native libraries failed", e);
ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
@@ -328,7 +329,7 @@ class InstallingSession {
}
}
private int copyApkForMoveInstall(InstallArgs args) {
private int copyApkForMoveInstall(InstallRequest request) {
if (DEBUG_INSTALL) {
Slog.d(TAG, "Moving " + mMoveInfo.mPackageName + " from "
+ mMoveInfo.mFromUuid + " to " + mMoveInfo.mToUuid);
@@ -345,8 +346,9 @@ class InstallingSession {
}
final String toPathName = new File(mMoveInfo.mFromCodePath).getName();
args.mCodeFile = new File(Environment.getDataAppDirectory(mMoveInfo.mToUuid), toPathName);
if (DEBUG_INSTALL) Slog.d(TAG, "codeFile after move is " + args.mCodeFile);
request.setCodeFile(
new File(Environment.getDataAppDirectory(mMoveInfo.mToUuid), toPathName));
if (DEBUG_INSTALL) Slog.d(TAG, "codeFile after move is " + request.getCodeFile());
return PackageManager.INSTALL_SUCCEEDED;
}
@@ -460,7 +462,7 @@ class InstallingSession {
List<InstallRequest> apexInstallRequests = new ArrayList<>();
List<InstallRequest> apkInstallRequests = new ArrayList<>();
for (InstallRequest request : installRequests) {
if ((request.mArgs.mInstallFlags & PackageManager.INSTALL_APEX) != 0) {
if ((request.getInstallFlags() & PackageManager.INSTALL_APEX) != 0) {
apexInstallRequests.add(request);
} else {
apkInstallRequests.add(request);
@@ -485,7 +487,7 @@ class InstallingSession {
// processInstallRequestAsync. In that case just notify the observer about the
// failure.
InstallRequest request = apexInstallRequests.get(0);
mPm.notifyInstallObserver(request.mInstallResult, request.mArgs.mObserver);
mPm.notifyInstallObserver(request);
}
return;
}
@@ -496,28 +498,25 @@ class InstallingSession {
private void processApkInstallRequests(boolean success, List<InstallRequest> installRequests) {
if (success) {
for (InstallRequest request : installRequests) {
if (request.mInstallResult.mReturnCode != PackageManager.INSTALL_SUCCEEDED) {
cleanUpForFailedInstall(request.mArgs);
if (request.getReturnCode() != PackageManager.INSTALL_SUCCEEDED) {
cleanUpForFailedInstall(request);
}
}
mInstallPackageHelper.installPackagesTraced(installRequests);
for (InstallRequest request : installRequests) {
doPostInstall(request.mInstallResult.mReturnCode, request.mArgs);
doPostInstall(request);
}
}
for (InstallRequest request : installRequests) {
mInstallPackageHelper.restoreAndPostInstall(request.mArgs.mUser.getIdentifier(),
request.mInstallResult,
new PostInstallData(request.mArgs,
request.mInstallResult, null));
mInstallPackageHelper.restoreAndPostInstall(request);
}
}
private void doPostInstall(int status, InstallArgs args) {
private void doPostInstall(InstallRequest request) {
if (mMoveInfo != null) {
if (status == PackageManager.INSTALL_SUCCEEDED) {
if (request.getReturnCode() == PackageManager.INSTALL_SUCCEEDED) {
mRemovePackageHelper.cleanUpForMoveInstall(mMoveInfo.mFromUuid,
mMoveInfo.mPackageName, mMoveInfo.mFromCodePath);
} else {
@@ -525,18 +524,18 @@ class InstallingSession {
mMoveInfo.mPackageName, mMoveInfo.mFromCodePath);
}
} else {
if (status != PackageManager.INSTALL_SUCCEEDED) {
mRemovePackageHelper.removeCodePath(args.mCodeFile);
if (request.getReturnCode() != PackageManager.INSTALL_SUCCEEDED) {
mRemovePackageHelper.removeCodePath(request.getCodeFile());
}
}
}
private void cleanUpForFailedInstall(InstallArgs args) {
if (args.mMoveInfo != null) {
mRemovePackageHelper.cleanUpForMoveInstall(args.mMoveInfo.mToUuid,
args.mMoveInfo.mPackageName, args.mMoveInfo.mFromCodePath);
private void cleanUpForFailedInstall(InstallRequest request) {
if (request.isMoveInstall()) {
mRemovePackageHelper.cleanUpForMoveInstall(request.getMoveToUuid(),
request.getMovePackageName(), request.getMoveFromCodePath());
} else {
mRemovePackageHelper.removeCodePath(args.mCodeFile);
mRemovePackageHelper.removeCodePath(request.getCodeFile());
}
}
@@ -560,7 +559,7 @@ class InstallingSession {
InstallRequest request = requests.get(0);
try {
// Should directory scanning logic be moved to ApexManager for better test coverage?
final File dir = request.mArgs.mOriginInfo.mResolvedFile;
final File dir = request.getOriginInfo().mResolvedFile;
final File[] apexes = dir.listFiles();
if (apexes == null) {
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
@@ -580,7 +579,7 @@ class InstallingSession {
// The newly installed APEX will not be reverted even if
// processApkInstallRequests() fails. Need a way to keep info stored in apexd
// and PMS in sync in the face of install failures.
request.mInstallResult.mApexInfo = apexInfo;
request.setApexInfo(apexInfo);
mPm.mHandler.post(() -> processApkInstallRequests(true, requests));
return;
} else {
@@ -588,10 +587,10 @@ class InstallingSession {
}
}
} catch (PackageManagerException e) {
request.mInstallResult.setError("APEX installation failed", e);
request.setError("APEX installation failed", e);
}
PackageManagerService.invalidatePackageInfoCache();
mPm.notifyInstallObserver(request.mInstallResult, request.mArgs.mObserver);
mPm.notifyInstallObserver(request);
}
/**
@@ -600,7 +599,7 @@ class InstallingSession {
*/
private class MultiPackageInstallingSession {
private final List<InstallingSession> mChildInstallingSessions;
private final Map<InstallArgs, Integer> mCurrentState;
private final Map<InstallRequest, Integer> mCurrentState;
@NonNull
final PackageManagerService mPm;
final UserHandle mUser;
@@ -636,8 +635,8 @@ class InstallingSession {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
public void tryProcessInstallRequest(InstallArgs args, int currentStatus) {
mCurrentState.put(args, currentStatus);
public void tryProcessInstallRequest(InstallRequest request) {
mCurrentState.put(request, request.getReturnCode());
if (mCurrentState.size() != mChildInstallingSessions.size()) {
return;
}
@@ -651,9 +650,9 @@ class InstallingSession {
}
}
final List<InstallRequest> installRequests = new ArrayList<>(mCurrentState.size());
for (Map.Entry<InstallArgs, Integer> entry : mCurrentState.entrySet()) {
installRequests.add(new InstallRequest(entry.getKey(),
new PackageInstalledInfo(completeStatus)));
for (Map.Entry<InstallRequest, Integer> entry : mCurrentState.entrySet()) {
entry.getKey().setReturnCode(completeStatus);
installRequests.add(entry.getKey());
}
int finalCompleteStatus = completeStatus;
mPm.mHandler.post(() -> processInstallRequests(

View File

@@ -89,18 +89,14 @@ final class PackageHandler extends Handler {
case POST_INSTALL: {
if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
PostInstallData data = mPm.mRunningInstalls.get(msg.arg1);
InstallRequest request = mPm.mRunningInstalls.get(msg.arg1);
final boolean didRestore = (msg.arg2 != 0);
mPm.mRunningInstalls.delete(msg.arg1);
if (data != null && data.res.mFreezer != null) {
data.res.mFreezer.close();
}
if (data != null && data.mPostInstallRunnable != null) {
data.mPostInstallRunnable.run();
} else if (data != null && data.args != null) {
mInstallPackageHelper.handlePackagePostInstall(data.res, data.args, didRestore);
request.closeFreezer();
request.runPostInstallRunnable();
if (!request.isInstallForExistingUser()) {
mInstallPackageHelper.handlePackagePostInstall(request, didRestore);
} else if (DEBUG_INSTALL) {
// No post-install when we run restore from installExistingPackageForUser
Slog.i(TAG, "Nothing to do for post-install token " + msg.arg1);
@@ -111,7 +107,7 @@ final class PackageHandler extends Handler {
case DEFERRED_NO_KILL_POST_DELETE: {
InstallArgs args = (InstallArgs) msg.obj;
if (args != null) {
mRemovePackageHelper.cleanUpResources(args);
mRemovePackageHelper.cleanUpResources(args.mCodeFile, args.mInstructionSets);
}
} break;
case DEFERRED_NO_KILL_INSTALL_OBSERVER:

View File

@@ -1,78 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.pm;
import static com.android.server.pm.PackageManagerService.TAG;
import android.apex.ApexInfo;
import android.util.ExceptionUtils;
import android.util.Slog;
import com.android.server.pm.pkg.AndroidPackage;
import java.util.ArrayList;
final class PackageInstalledInfo {
String mName;
int mUid;
// The set of users that originally had this package installed.
int[] mOrigUsers;
// The set of users that now have this package installed.
int[] mNewUsers;
AndroidPackage mPkg;
int mReturnCode;
String mReturnMsg;
String mInstallerPackageName;
PackageRemovedInfo mRemovedInfo;
// The set of packages consuming this shared library or null if no consumers exist.
ArrayList<AndroidPackage> mLibraryConsumers;
PackageFreezer mFreezer;
// In some error cases we want to convey more info back to the observer
String mOrigPackage;
String mOrigPermission;
// The ApexInfo returned by ApexManager#installPackage, used by rebootless APEX install
ApexInfo mApexInfo;
PackageInstalledInfo(int currentStatus) {
mReturnCode = currentStatus;
mUid = -1;
mPkg = null;
mRemovedInfo = null;
}
public void setError(int code, String msg) {
setReturnCode(code);
setReturnMessage(msg);
Slog.w(TAG, msg);
}
public void setError(String msg, PackageManagerException e) {
mReturnCode = e.error;
setReturnMessage(ExceptionUtils.getCompleteMessage(msg, e));
Slog.w(TAG, msg, e);
}
public void setReturnCode(int returnCode) {
mReturnCode = returnCode;
}
private void setReturnMessage(String returnMsg) {
mReturnMsg = returnMsg;
}
}

View File

@@ -82,7 +82,6 @@ import android.content.pm.IDexModuleRegisterCallback;
import android.content.pm.IOnChecksumsReadyListener;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageDeleteObserver2;
import android.content.pm.IPackageInstallObserver2;
import android.content.pm.IPackageLoadingProgressCallback;
import android.content.pm.IPackageManager;
import android.content.pm.IPackageMoveObserver;
@@ -826,10 +825,10 @@ public class PackageManagerService implements PackageSender, TestUtilityService
@Watched(manual = true)
private final ResolveInfo mInstantAppInstallerInfo = new ResolveInfo();
private final Map<String, Pair<PackageInstalledInfo, IPackageInstallObserver2>>
private final Map<String, InstallRequest>
mNoKillInstallObservers = Collections.synchronizedMap(new HashMap<>());
private final Map<String, Pair<PackageInstalledInfo, IPackageInstallObserver2>>
private final Map<String, InstallRequest>
mPendingKillInstallObservers = Collections.synchronizedMap(new HashMap<>());
// Internal interface for permission manager
@@ -908,7 +907,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
// Stores a list of users whose package restrictions file needs to be updated
final ArraySet<Integer> mDirtyUsers = new ArraySet<>();
final SparseArray<PostInstallData> mRunningInstalls = new SparseArray<>();
final SparseArray<InstallRequest> mRunningInstalls = new SparseArray<>();
int mNextInstallToken = 1; // nonzero; will be wrapped back to 1 when ++ overflows
final @NonNull String[] mRequiredVerifierPackages;
@@ -1155,32 +1154,30 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
void notifyInstallObserver(String packageName, boolean killApp) {
final Pair<PackageInstalledInfo, IPackageInstallObserver2> pair =
final InstallRequest installRequest =
killApp ? mPendingKillInstallObservers.remove(packageName)
: mNoKillInstallObservers.remove(packageName);
if (pair != null) {
notifyInstallObserver(pair.first, pair.second);
if (installRequest != null) {
notifyInstallObserver(installRequest);
}
}
void notifyInstallObserver(PackageInstalledInfo info,
IPackageInstallObserver2 installObserver) {
if (installObserver != null) {
void notifyInstallObserver(InstallRequest request) {
if (request.getObserver() != null) {
try {
Bundle extras = extrasForInstallResult(info);
installObserver.onPackageInstalled(info.mName, info.mReturnCode,
info.mReturnMsg, extras);
Bundle extras = extrasForInstallResult(request);
request.getObserver().onPackageInstalled(request.getName(),
request.getReturnCode(), request.getReturnMsg(), extras);
} catch (RemoteException e) {
Slog.i(TAG, "Observer no longer exists.");
}
}
}
void scheduleDeferredNoKillInstallObserver(PackageInstalledInfo info,
IPackageInstallObserver2 observer) {
String packageName = info.mPkg.getPackageName();
mNoKillInstallObservers.put(packageName, Pair.create(info, observer));
void scheduleDeferredNoKillInstallObserver(InstallRequest request) {
String packageName = request.getPkg().getPackageName();
mNoKillInstallObservers.put(packageName, request);
Message message = mHandler.obtainMessage(DEFERRED_NO_KILL_INSTALL_OBSERVER, packageName);
mHandler.sendMessageDelayed(message, DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS);
}
@@ -1196,10 +1193,9 @@ public class PackageManagerService implements PackageSender, TestUtilityService
delay ? getPruneUnusedSharedLibrariesDelay() : 0);
}
void scheduleDeferredPendingKillInstallObserver(PackageInstalledInfo info,
IPackageInstallObserver2 observer) {
final String packageName = info.mPkg.getPackageName();
mPendingKillInstallObservers.put(packageName, Pair.create(info, observer));
void scheduleDeferredPendingKillInstallObserver(InstallRequest request) {
final String packageName = request.getPkg().getPackageName();
mPendingKillInstallObservers.put(packageName, request);
final Message message = mHandler.obtainMessage(DEFERRED_PENDING_KILL_INSTALL_OBSERVER,
packageName);
mHandler.sendMessageDelayed(message, DEFERRED_PENDING_KILL_INSTALL_OBSERVER_DELAY_MS);
@@ -1312,21 +1308,22 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
}
private static Bundle extrasForInstallResult(PackageInstalledInfo res) {
private static Bundle extrasForInstallResult(InstallRequest request) {
Bundle extras = null;
switch (res.mReturnCode) {
switch (request.getReturnCode()) {
case PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION: {
extras = new Bundle();
extras.putString(PackageManager.EXTRA_FAILURE_EXISTING_PERMISSION,
res.mOrigPermission);
request.getOrigPermission());
extras.putString(PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE,
res.mOrigPackage);
request.getOrigPackage());
break;
}
case PackageManager.INSTALL_SUCCEEDED: {
extras = new Bundle();
extras.putBoolean(Intent.EXTRA_REPLACING,
res.mRemovedInfo != null && res.mRemovedInfo.mRemovedPackage != null);
request.getRemovedInfo() != null
&& request.getRemovedInfo().mRemovedPackage != null);
break;
}
}
@@ -3111,14 +3108,14 @@ public class PackageManagerService implements PackageSender, TestUtilityService
// state for observers to see the FIRST_LAUNCH signal.
mHandler.post(() -> {
for (int i = 0; i < mRunningInstalls.size(); i++) {
final PostInstallData data = mRunningInstalls.valueAt(i);
if (data.res.mReturnCode != PackageManager.INSTALL_SUCCEEDED) {
final InstallRequest installRequest = mRunningInstalls.valueAt(i);
if (installRequest.getReturnCode() != PackageManager.INSTALL_SUCCEEDED) {
continue;
}
if (packageName.equals(data.res.mPkg.getPackageName())) {
if (packageName.equals(installRequest.getPkg().getPackageName())) {
// right package; but is it for the right user?
for (int uIndex = 0; uIndex < data.res.mNewUsers.length; uIndex++) {
if (userId == data.res.mNewUsers[uIndex]) {
for (int uIndex = 0; uIndex < installRequest.getNewUsers().length; uIndex++) {
if (userId == installRequest.getNewUsers()[uIndex]) {
if (DEBUG_BACKUP) {
Slog.i(TAG, "Package " + packageName
+ " being restored so deferring FIRST_LAUNCH");

View File

@@ -28,6 +28,7 @@ import android.content.Intent;
import android.os.Bundle;
import android.os.PowerExemptionManager;
import android.util.SparseArray;
import android.util.SparseIntArray;
import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
@@ -42,8 +43,8 @@ final class PackageRemovedInfo {
int[] mRemovedUsers = null;
int[] mBroadcastUsers = null;
int[] mInstantUserIds = null;
SparseArray<Integer> mInstallReasons;
SparseArray<Integer> mUninstallReasons;
SparseIntArray mInstallReasons;
SparseIntArray mUninstallReasons;
boolean mIsRemovedPackageSystemUpdate = false;
boolean mIsUpdate;
boolean mDataRemoved;

View File

@@ -1,40 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.pm;
import android.annotation.NonNull;
import android.annotation.Nullable;
/**
* Record-keeping of restore-after-install operations that are currently in flight
* between the Package Manager and the Backup Manager
*/
public final class PostInstallData {
@Nullable
public final InstallArgs args;
@NonNull
public final PackageInstalledInfo res;
@Nullable
public final Runnable mPostInstallRunnable;
PostInstallData(@Nullable InstallArgs args, @NonNull PackageInstalledInfo res,
@Nullable Runnable postInstallRunnable) {
this.args = args;
this.res = res;
mPostInstallRunnable = postInstallRunnable;
}
}

View File

@@ -77,11 +77,10 @@ final class ReconcilePackageUtils {
}
// the following may be null if we're just reconciling on boot (and not during install)
final InstallArgs installArgs = request.mInstallArgs.get(installPackageName);
final PackageInstalledInfo res = request.mInstallResults.get(installPackageName);
final InstallRequest installRequest = request.mInstallRequests.get(installPackageName);
final PrepareResult prepareResult = request.mPreparedPackages.get(installPackageName);
final boolean isInstall = installArgs != null;
if (isInstall && (res == null || prepareResult == null)) {
final boolean isInstall = installRequest != null;
if (isInstall && prepareResult == null) {
throw new ReconcileFailure("Reconcile arguments are not balanced for "
+ installPackageName + "!");
}
@@ -92,7 +91,8 @@ final class ReconcilePackageUtils {
final boolean killApp = (scanResult.mRequest.mScanFlags & SCAN_DONT_KILL_APP) == 0;
final int deleteFlags = PackageManager.DELETE_KEEP_DATA
| (killApp ? 0 : PackageManager.DELETE_DONT_KILL_APP);
deletePackageAction = DeletePackageHelper.mayDeletePackageLocked(res.mRemovedInfo,
deletePackageAction = DeletePackageHelper.mayDeletePackageLocked(
installRequest.getRemovedInfo(),
prepareResult.mOriginalPs, prepareResult.mDisabledPs,
deleteFlags, null /* all users */);
if (deletePackageAction == null) {
@@ -146,8 +146,8 @@ final class ReconcilePackageUtils {
request.mVersionInfos.get(installPackageName);
final boolean compareCompat = isCompatSignatureUpdateNeeded(versionInfo);
final boolean compareRecover = isRecoverSignatureUpdateNeeded(versionInfo);
final boolean isRollback = installArgs != null
&& installArgs.mInstallReason == PackageManager.INSTALL_REASON_ROLLBACK;
final boolean isRollback = installRequest != null
&& installRequest.isRollback();
final boolean compatMatch =
PackageManagerServiceUtils.verifySignatures(signatureCheckPs,
sharedUserSetting, disabledPkgSetting,
@@ -257,8 +257,8 @@ final class ReconcilePackageUtils {
}
result.put(installPackageName,
new ReconciledPackage(request, installArgs, scanResult.mPkgSetting,
res, request.mPreparedPackages.get(installPackageName), scanResult,
new ReconciledPackage(request, installRequest, scanResult.mPkgSetting,
request.mPreparedPackages.get(installPackageName), scanResult,
deletePackageAction, allowedSharedLibInfos, signingDetails,
sharedUserSignaturesChanged, removeAppKeySetData));
}

View File

@@ -34,20 +34,17 @@ final class ReconcileRequest {
public final Map<String, ScanResult> mScannedPackages;
public final Map<String, AndroidPackage> mAllPackages;
public final Map<String, InstallArgs> mInstallArgs;
public final Map<String, PackageInstalledInfo> mInstallResults;
public final Map<String, InstallRequest> mInstallRequests;
public final Map<String, PrepareResult> mPreparedPackages;
public final Map<String, Settings.VersionInfo> mVersionInfos;
ReconcileRequest(Map<String, ScanResult> scannedPackages,
Map<String, InstallArgs> installArgs,
Map<String, PackageInstalledInfo> installResults,
Map<String, InstallRequest> installRequests,
Map<String, PrepareResult> preparedPackages,
Map<String, AndroidPackage> allPackages,
Map<String, Settings.VersionInfo> versionInfos) {
mScannedPackages = scannedPackages;
mInstallArgs = installArgs;
mInstallResults = installResults;
mInstallRequests = installRequests;
mPreparedPackages = preparedPackages;
mAllPackages = allPackages;
mVersionInfos = versionInfos;
@@ -56,7 +53,7 @@ final class ReconcileRequest {
ReconcileRequest(Map<String, ScanResult> scannedPackages,
Map<String, AndroidPackage> allPackages,
Map<String, Settings.VersionInfo> versionInfos) {
this(scannedPackages, Collections.emptyMap(), Collections.emptyMap(),
this(scannedPackages, Collections.emptyMap(),
Collections.emptyMap(), allPackages, versionInfos);
}
}

View File

@@ -37,9 +37,8 @@ final class ReconciledPackage {
public final PackageSetting mPkgSetting;
public final ScanResult mScanResult;
// TODO: Remove install-specific details from the reconcile result
public final PackageInstalledInfo mInstallResult;
@Nullable public final PrepareResult mPrepareResult;
@Nullable public final InstallArgs mInstallArgs;
@Nullable public final InstallRequest mInstallRequest;
public final DeletePackageAction mDeletePackageAction;
public final List<SharedLibraryInfo> mAllowedSharedLibraryInfos;
public final SigningDetails mSigningDetails;
@@ -48,9 +47,8 @@ final class ReconciledPackage {
public final boolean mRemoveAppKeySetData;
ReconciledPackage(ReconcileRequest request,
InstallArgs installArgs,
InstallRequest installRequest,
PackageSetting pkgSetting,
PackageInstalledInfo installResult,
PrepareResult prepareResult,
ScanResult scanResult,
DeletePackageAction deletePackageAction,
@@ -59,9 +57,8 @@ final class ReconciledPackage {
boolean sharedUserSignaturesChanged,
boolean removeAppKeySetData) {
mRequest = request;
mInstallArgs = installArgs;
mInstallRequest = installRequest;
mPkgSetting = pkgSetting;
mInstallResult = installResult;
mPrepareResult = prepareResult;
mScanResult = scanResult;
mDeletePackageAction = deletePackageAction;

View File

@@ -385,29 +385,29 @@ final class RemovePackageHelper {
}
}
void cleanUpResources(InstallArgs args) {
void cleanUpResources(File codeFile, String[] instructionSets) {
synchronized (mPm.mInstallLock) {
cleanUpResourcesLI(args);
cleanUpResourcesLI(codeFile, instructionSets);
}
}
// Need installer lock especially for dex file removal.
@GuardedBy("mPm.mInstallLock")
private void cleanUpResourcesLI(InstallArgs args) {
private void cleanUpResourcesLI(File codeFile, String[] instructionSets) {
// Try enumerating all code paths before deleting
List<String> allCodePaths = Collections.EMPTY_LIST;
if (args.mCodeFile != null && args.mCodeFile.exists()) {
if (codeFile != null && codeFile.exists()) {
final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
final ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite(
input.reset(), args.mCodeFile, /* flags */ 0);
input.reset(), codeFile, /* flags */ 0);
if (result.isSuccess()) {
// Ignore error; we tried our best
allCodePaths = result.getResult().getAllApkPaths();
}
}
removeCodePathLI(args.mCodeFile);
removeDexFilesLI(allCodePaths, args.mInstructionSets);
removeCodePathLI(codeFile);
removeDexFilesLI(allCodePaths, instructionSets);
}
@GuardedBy("mPm.mInstallLock")