Merge "[pm] extract InstallParams from PackageManagerService class"

This commit is contained in:
Songchun Fan
2021-07-28 23:37:43 +00:00
committed by Android (Google) Code Review
32 changed files with 5214 additions and 4622 deletions

View File

@@ -0,0 +1,35 @@
/*
* 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 java.util.Map;
/**
* Package state to commit to memory and disk after reconciliation has completed.
*/
final class CommitRequest {
final Map<String, ReconciledPackage> mReconciledPackages;
@NonNull final int[] mAllUsers;
CommitRequest(Map<String, ReconciledPackage> reconciledPackages,
@NonNull int[] allUsers) {
mReconciledPackages = reconciledPackages;
mAllUsers = allUsers;
}
}

View File

@@ -0,0 +1,36 @@
/*
* 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.os.UserHandle;
final class DeletePackageAction {
public final PackageSetting mDeletingPs;
public final PackageSetting mDisabledPs;
public final PackageRemovedInfo mRemovedInfo;
public final int mFlags;
public final UserHandle mUser;
DeletePackageAction(PackageSetting deletingPs, PackageSetting disabledPs,
PackageRemovedInfo removedInfo, int flags, UserHandle user) {
mDeletingPs = deletingPs;
mDisabledPs = disabledPs;
mRemovedInfo = removedInfo;
mFlags = flags;
mUser = user;
}
}

View File

@@ -0,0 +1,263 @@
/*
* 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 android.app.AppOpsManager.MODE_DEFAULT;
import static android.content.pm.PackageManager.INSTALL_STAGED;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.os.incremental.IncrementalManager.isIncrementalPath;
import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
import static com.android.server.pm.PackageManagerService.TAG;
import static com.android.server.pm.PackageManagerServiceUtils.makeDirRecursive;
import android.content.pm.DataLoaderType;
import android.content.pm.PackageManager;
import android.content.pm.SigningDetails;
import android.content.pm.parsing.ApkLiteParseUtils;
import android.content.pm.parsing.PackageLite;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
import android.os.Environment;
import android.os.FileUtils;
import android.os.SELinux;
import android.os.Trace;
import android.system.ErrnoException;
import android.system.Os;
import android.util.Slog;
import com.android.internal.content.NativeLibraryHelper;
import com.android.server.pm.parsing.pkg.ParsedPackage;
import libcore.io.IoUtils;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
/**
* Logic to handle installation of new applications, including copying
* and renaming logic.
*/
class FileInstallArgs extends InstallArgs {
private File mCodeFile;
// Example topology:
// /data/app/com.example/base.apk
// /data/app/com.example/split_foo.apk
// /data/app/com.example/lib/arm/libfoo.so
// /data/app/com.example/lib/arm64/libfoo.so
// /data/app/com.example/dalvik/arm/base.apk@classes.dex
/** New install */
FileInstallArgs(InstallParams params) {
super(params);
}
/** Existing install */
FileInstallArgs(String codePath, String[] instructionSets, PackageManagerService pm) {
super(OriginInfo.fromNothing(), null, null, 0, InstallSource.EMPTY,
null, null, instructionSets, null, null, null, MODE_DEFAULT, null, 0,
SigningDetails.UNKNOWN,
PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.INSTALL_SCENARIO_DEFAULT,
false, DataLoaderType.NONE, pm);
mCodeFile = (codePath != null) ? new File(codePath) : null;
}
int copyApk() {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
try {
return doCopyApk();
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
private int doCopyApk() {
if (mOriginInfo.mStaged) {
if (DEBUG_INSTALL) Slog.d(TAG, mOriginInfo.mFile + " already staged; skipping copy");
mCodeFile = mOriginInfo.mFile;
return PackageManager.INSTALL_SUCCEEDED;
}
try {
final boolean isEphemeral = (mInstallFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
final File tempDir =
mPm.mInstallerService.allocateStageDirLegacy(mVolumeUuid, isEphemeral);
mCodeFile = tempDir;
} 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(), mCodeFile);
if (ret != PackageManager.INSTALL_SUCCEEDED) {
Slog.e(TAG, "Failed to copy package");
return ret;
}
final boolean isIncremental = isIncrementalPath(mCodeFile.getAbsolutePath());
final File libraryRoot = new File(mCodeFile, LIB_DIR_NAME);
NativeLibraryHelper.Handle handle = null;
try {
handle = NativeLibraryHelper.Handle.create(mCodeFile);
ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
mAbiOverride, isIncremental);
} catch (IOException e) {
Slog.e(TAG, "Copying native libraries failed", e);
ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
} finally {
IoUtils.closeQuietly(handle);
}
return ret;
}
int doPreInstall(int status) {
if (status != PackageManager.INSTALL_SUCCEEDED) {
cleanUp();
}
return status;
}
@Override
boolean doRename(int status, ParsedPackage parsedPackage) {
if (status != PackageManager.INSTALL_SUCCEEDED) {
cleanUp();
return false;
}
final File targetDir = resolveTargetDir();
final File beforeCodeFile = mCodeFile;
final File afterCodeFile = PackageManagerService.getNextCodePath(targetDir,
parsedPackage.getPackageName());
if (DEBUG_INSTALL) Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile);
final boolean onIncremental = mPm.mIncrementalManager != null
&& isIncrementalPath(beforeCodeFile.getAbsolutePath());
try {
makeDirRecursive(afterCodeFile.getParentFile(), 0775);
if (onIncremental) {
// Just link files here. The stage dir will be removed when the installation
// session is completed.
mPm.mIncrementalManager.linkCodePath(beforeCodeFile, afterCodeFile);
} else {
Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath());
}
} catch (IOException | ErrnoException e) {
Slog.w(TAG, "Failed to rename", e);
return false;
}
if (!onIncremental && !SELinux.restoreconRecursive(afterCodeFile)) {
Slog.w(TAG, "Failed to restorecon");
return false;
}
// Reflect the rename internally
mCodeFile = afterCodeFile;
// Reflect the rename in scanned details
try {
parsedPackage.setPath(afterCodeFile.getCanonicalPath());
} catch (IOException e) {
Slog.e(TAG, "Failed to get path: " + afterCodeFile, e);
return false;
}
parsedPackage.setBaseApkPath(FileUtils.rewriteAfterRename(beforeCodeFile,
afterCodeFile, parsedPackage.getBaseApkPath()));
parsedPackage.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
afterCodeFile, parsedPackage.getSplitCodePaths()));
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 = (mInstallFlags & INSTALL_STAGED) != 0;
if (isStagedInstall) {
return Environment.getDataAppDirectory(null);
} else {
return mCodeFile.getParentFile();
}
}
int doPostInstall(int status, int uid) {
if (status != PackageManager.INSTALL_SUCCEEDED) {
cleanUp();
}
return status;
}
@Override
String getCodePath() {
return (mCodeFile != null) ? mCodeFile.getAbsolutePath() : null;
}
private boolean cleanUp() {
if (mCodeFile == null || !mCodeFile.exists()) {
return false;
}
mPm.removeCodePathLI(mCodeFile);
return true;
}
void cleanUpResourcesLI() {
// Try enumerating all code paths before deleting
List<String> allCodePaths = Collections.EMPTY_LIST;
if (mCodeFile != null && mCodeFile.exists()) {
final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
final ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite(
input.reset(), mCodeFile, /* flags */ 0);
if (result.isSuccess()) {
// Ignore error; we tried our best
allCodePaths = result.getResult().getAllApkPaths();
}
}
cleanUp();
removeDexFiles(allCodePaths, mInstructionSets);
}
void removeDexFiles(List<String> allCodePaths, String[] instructionSets) {
if (!allCodePaths.isEmpty()) {
if (instructionSets == null) {
throw new IllegalStateException("instructionSet == null");
}
String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
for (String codePath : allCodePaths) {
for (String dexCodeInstructionSet : dexCodeInstructionSets) {
try {
mPm.mInstaller.rmdex(codePath, dexCodeInstructionSet);
} catch (Installer.InstallerException ignored) {
}
}
}
}
}
boolean doPostDeleteLI(boolean delete) {
// XXX err, shouldn't we respect the delete flag?
cleanUpResourcesLI();
return true;
}
}

View File

@@ -0,0 +1,57 @@
/*
* 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.os.UserHandle;
import android.util.Slog;
import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
import static com.android.server.pm.PackageManagerService.TAG;
abstract class HandlerParams {
/** User handle for the user requesting the information or installation. */
private final UserHandle mUser;
String mTraceMethod;
int mTraceCookie;
HandlerParams(UserHandle user) {
mUser = user;
}
UserHandle getUser() {
return mUser;
}
HandlerParams setTraceMethod(String traceMethod) {
mTraceMethod = traceMethod;
return this;
}
HandlerParams setTraceCookie(int traceCookie) {
mTraceCookie = traceCookie;
return this;
}
final void startCopy() {
if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
handleStartCopy();
handleReturnCode();
}
abstract void handleStartCopy();
abstract void handleReturnCode();
}

View File

@@ -0,0 +1,43 @@
/*
* 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.content.pm.IPackageLoadingProgressCallback;
/**
* Loading progress callback, used to listen for progress changes and update package setting
*/
final class IncrementalProgressListener extends IPackageLoadingProgressCallback.Stub {
private final String mPackageName;
private final PackageManagerService mPm;
IncrementalProgressListener(String packageName, PackageManagerService pm) {
mPackageName = packageName;
mPm = pm;
}
@Override
public void onPackageLoadingProgressChanged(float progress) {
final PackageSetting ps;
synchronized (mPm.mLock) {
ps = mPm.mSettings.getPackageLPr(mPackageName);
if (ps == null) {
return;
}
ps.setLoadingProgress(progress);
}
}
}

View File

@@ -0,0 +1,46 @@
/*
* 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;
/**
* Package states callback, used to listen for package state changes and send broadcasts
*/
final class IncrementalStatesCallback implements IncrementalStates.Callback {
private final String mPackageName;
private final PackageManagerService mPm;
IncrementalStatesCallback(String packageName, PackageManagerService pm) {
mPackageName = packageName;
mPm = pm;
}
@Override
public void onPackageFullyLoaded() {
final String codePath;
synchronized (mPm.mLock) {
final PackageSetting ps = mPm.mSettings.getPackageLPr(mPackageName);
if (ps == null) {
return;
}
codePath = ps.getPathString();
}
// Unregister progress listener
mPm.mIncrementalManager.unregisterLoadingProgressCallbacks(codePath);
// Make sure the information is preserved
mPm.scheduleWriteSettingsLocked();
}
}

View File

@@ -0,0 +1,149 @@
/*
* 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;
import android.content.pm.IPackageInstallObserver2;
import android.content.pm.PackageManager;
import android.content.pm.SigningDetails;
import android.os.UserHandle;
import com.android.internal.util.Preconditions;
import com.android.server.pm.parsing.pkg.ParsedPackage;
import java.util.List;
abstract class InstallArgs {
/** @see InstallParams#mOriginInfo */
final OriginInfo mOriginInfo;
/** @see InstallParams#mMoveInfo */
final MoveInfo mMoveInfo;
final IPackageInstallObserver2 mObserver;
// Always refers to PackageManager flags only
final int mInstallFlags;
@NonNull
final InstallSource mInstallSource;
final String mVolumeUuid;
final UserHandle mUser;
final String mAbiOverride;
final String[] mInstallGrantPermissions;
final List<String> mAllowlistedRestrictedPermissions;
final int mAutoRevokePermissionsMode;
/** If non-null, drop an async trace when the install completes */
final String mTraceMethod;
final int mTraceCookie;
final SigningDetails mSigningDetails;
final int mInstallReason;
final int mInstallScenario;
final boolean mForceQueryableOverride;
final int mDataLoaderType;
// The list of instruction sets supported by this app. This is currently
// only used during the rmdex() phase to clean up resources. We can get rid of this
// if we move dex files under the common app path.
@Nullable String[] mInstructionSets;
@NonNull final PackageManagerService mPm;
InstallArgs(OriginInfo originInfo, MoveInfo moveInfo, IPackageInstallObserver2 observer,
int installFlags, InstallSource installSource, String volumeUuid,
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, PackageManagerService pm) {
mOriginInfo = originInfo;
mMoveInfo = moveInfo;
mInstallFlags = installFlags;
mObserver = observer;
mInstallSource = Preconditions.checkNotNull(installSource);
mVolumeUuid = volumeUuid;
mUser = user;
mInstructionSets = instructionSets;
mAbiOverride = abiOverride;
mInstallGrantPermissions = installGrantPermissions;
mAllowlistedRestrictedPermissions = allowlistedRestrictedPermissions;
mAutoRevokePermissionsMode = autoRevokePermissionsMode;
mTraceMethod = traceMethod;
mTraceCookie = traceCookie;
mSigningDetails = signingDetails;
mInstallReason = installReason;
mInstallScenario = installScenario;
mForceQueryableOverride = forceQueryableOverride;
mDataLoaderType = dataLoaderType;
mPm = pm;
}
/** New install */
InstallArgs(InstallParams 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.mPm);
}
abstract int copyApk();
abstract int doPreInstall(int status);
/**
* Rename package into final resting place. All paths on the given
* scanned package should be updated to reflect the rename.
*/
abstract boolean doRename(int status, ParsedPackage parsedPackage);
abstract int doPostInstall(int status, int uid);
/** @see PackageSettingBase#getPath() */
abstract String getCodePath();
// Need installer lock especially for dex file removal.
abstract void cleanUpResourcesLI();
abstract boolean doPostDeleteLI(boolean delete);
/**
* Called before the source arguments are copied. This is used mostly
* for MoveParams when it needs to read the source file to put it in the
* destination.
*/
int doPreCopy() {
return PackageManager.INSTALL_SUCCEEDED;
}
/**
* Called after the source arguments are copied. This is used mostly for
* MoveParams when it needs to read the source file to put it in the
* destination.
*/
int doPostCopy(int uid) {
return PackageManager.INSTALL_SUCCEEDED;
}
protected boolean isEphemeral() {
return (mInstallFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
}
UserHandle getUser() {
return mUser;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,27 @@
/*
* 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;
final class InstallRequest {
public final InstallArgs mArgs;
public final PackageInstalledInfo mInstallResult;
InstallRequest(InstallArgs args, PackageInstalledInfo res) {
mArgs = args;
mInstallResult = res;
}
}

View File

@@ -0,0 +1,41 @@
/*
* 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;
final class MoveInfo {
final int mMoveId;
final String mFromUuid;
final String mToUuid;
final String mPackageName;
final int mAppId;
final String mSeInfo;
final int mTargetSdkVersion;
final String mFromCodePath;
MoveInfo(int moveId, String fromUuid, String toUuid, String packageName,
int appId, String seInfo, int targetSdkVersion,
String fromCodePath) {
mMoveId = moveId;
mFromUuid = fromUuid;
mToUuid = toUuid;
mPackageName = packageName;
mAppId = appId;
mSeInfo = seInfo;
mTargetSdkVersion = targetSdkVersion;
mFromCodePath = fromCodePath;
}
}

View File

@@ -0,0 +1,133 @@
/*
* 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 android.os.storage.StorageManager.FLAG_STORAGE_CE;
import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
import static com.android.server.pm.PackageManagerService.TAG;
import android.content.pm.PackageManager;
import android.os.Environment;
import android.util.Slog;
import com.android.server.pm.parsing.pkg.ParsedPackage;
import java.io.File;
/**
* Logic to handle movement of existing installed applications.
*/
final class MoveInstallArgs extends InstallArgs {
private File mCodeFile;
/** New install */
MoveInstallArgs(InstallParams params) {
super(params);
}
int copyApk() {
if (DEBUG_INSTALL) {
Slog.d(TAG, "Moving " + mMoveInfo.mPackageName + " from "
+ mMoveInfo.mFromUuid + " to " + mMoveInfo.mToUuid);
}
synchronized (mPm.mInstaller) {
try {
mPm.mInstaller.moveCompleteApp(mMoveInfo.mFromUuid, mMoveInfo.mToUuid,
mMoveInfo.mPackageName, mMoveInfo.mAppId, mMoveInfo.mSeInfo,
mMoveInfo.mTargetSdkVersion, mMoveInfo.mFromCodePath);
} catch (Installer.InstallerException e) {
Slog.w(TAG, "Failed to move app", e);
return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
}
}
final String toPathName = new File(mMoveInfo.mFromCodePath).getName();
mCodeFile = new File(Environment.getDataAppDirectory(mMoveInfo.mToUuid), toPathName);
if (DEBUG_INSTALL) Slog.d(TAG, "codeFile after move is " + mCodeFile);
return PackageManager.INSTALL_SUCCEEDED;
}
int doPreInstall(int status) {
if (status != PackageManager.INSTALL_SUCCEEDED) {
cleanUp(mMoveInfo.mToUuid);
}
return status;
}
@Override
boolean doRename(int status, ParsedPackage parsedPackage) {
if (status != PackageManager.INSTALL_SUCCEEDED) {
cleanUp(mMoveInfo.mToUuid);
return false;
}
return true;
}
int doPostInstall(int status, int uid) {
if (status == PackageManager.INSTALL_SUCCEEDED) {
cleanUp(mMoveInfo.mFromUuid);
} else {
cleanUp(mMoveInfo.mToUuid);
}
return status;
}
@Override
String getCodePath() {
return (mCodeFile != null) ? mCodeFile.getAbsolutePath() : null;
}
private void cleanUp(String volumeUuid) {
final String toPathName = new File(mMoveInfo.mFromCodePath).getName();
final File codeFile = new File(Environment.getDataAppDirectory(volumeUuid),
toPathName);
Slog.d(TAG, "Cleaning up " + mMoveInfo.mPackageName + " on " + volumeUuid);
final int[] userIds = mPm.mUserManager.getUserIds();
synchronized (mPm.mInstallLock) {
// Clean up both app data and code
// All package moves are frozen until finished
// We purposefully exclude FLAG_STORAGE_EXTERNAL here, since
// this task was only focused on moving data on internal storage.
// We don't want ART profiles cleared, because they don't move,
// so we would be deleting the only copy (b/149200535).
final int flags = FLAG_STORAGE_DE | FLAG_STORAGE_CE
| Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES;
for (int userId : userIds) {
try {
mPm.mInstaller.destroyAppData(volumeUuid, mMoveInfo.mPackageName, userId, flags,
0);
} catch (Installer.InstallerException e) {
Slog.w(TAG, String.valueOf(e));
}
}
mPm.removeCodePathLI(codeFile);
}
}
void cleanUpResourcesLI() {
throw new UnsupportedOperationException();
}
boolean doPostDeleteLI(boolean delete) {
throw new UnsupportedOperationException();
}
}

View File

@@ -0,0 +1,68 @@
/*
* 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 java.io.File;
final class OriginInfo {
/**
* Location where install is coming from, before it has been
* copied/renamed into place. This could be a single monolithic APK
* file, or a cluster directory. This location may be untrusted.
*/
final File mFile;
/**
* Flag indicating that {@link #mFile} has already been staged, meaning downstream users
* don't need to defensively copy the contents.
*/
final boolean mStaged;
/**
* Flag indicating that {@link #mFile} is an already installed app that is being moved.
*/
final boolean mExisting;
final String mResolvedPath;
final File mResolvedFile;
static OriginInfo fromNothing() {
return new OriginInfo(null, false, false);
}
static OriginInfo fromExistingFile(File file) {
return new OriginInfo(file, false, true);
}
static OriginInfo fromStagedFile(File file) {
return new OriginInfo(file, true, false);
}
private OriginInfo(File file, boolean staged, boolean existing) {
mFile = file;
mStaged = staged;
mExisting = existing;
if (file != null) {
mResolvedPath = file.getAbsolutePath();
mResolvedFile = file;
} else {
mResolvedPath = null;
mResolvedFile = null;
}
}
}

View File

@@ -0,0 +1,91 @@
/*
* 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.content.pm.PackageManager;
import dalvik.system.CloseGuard;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Class that freezes and kills the given package upon creation, and
* unfreezes it upon closing. This is typically used when doing surgery on
* app code/data to prevent the app from running while you're working.
*/
final class PackageFreezer implements AutoCloseable {
private final String mPackageName;
private final boolean mWeFroze;
private final AtomicBoolean mClosed = new AtomicBoolean();
private final CloseGuard mCloseGuard = CloseGuard.get();
@NonNull
private final PackageManagerService mPm;
/**
* Create and return a stub freezer that doesn't actually do anything,
* typically used when someone requested
* {@link PackageManager#INSTALL_DONT_KILL_APP} or
* {@link PackageManager#DELETE_DONT_KILL_APP}.
*/
PackageFreezer(PackageManagerService pm) {
mPm = pm;
mPackageName = null;
mWeFroze = false;
mCloseGuard.open("close");
}
PackageFreezer(String packageName, int userId, String killReason,
PackageManagerService pm) {
mPm = pm;
mPackageName = packageName;
final PackageSetting ps;
synchronized (mPm.mLock) {
mWeFroze = mPm.mFrozenPackages.add(mPackageName);
ps = mPm.mSettings.getPackageLPr(mPackageName);
}
if (ps != null) {
mPm.killApplication(ps.name, ps.appId, userId, killReason);
}
mCloseGuard.open("close");
}
@Override
protected void finalize() throws Throwable {
try {
mCloseGuard.warnIfOpen();
close();
} finally {
super.finalize();
}
}
@Override
public void close() {
mCloseGuard.close();
if (mClosed.compareAndSet(false, true)) {
synchronized (mPm.mLock) {
if (mWeFroze) {
mPm.mFrozenPackages.remove(mPackageName);
}
}
}
}
}

View File

@@ -0,0 +1,81 @@
/*
* 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.content.pm.PackageParser;
import android.util.ExceptionUtils;
import android.util.Slog;
import com.android.server.pm.parsing.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;
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, PackageParser.PackageParserException e) {
setReturnCode(e.error);
setReturnMessage(ExceptionUtils.getCompleteMessage(msg, e));
Slog.w(TAG, msg, e);
}
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

@@ -2384,8 +2384,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private void verifyNonStaged()
throws PackageManagerException {
final PackageManagerService.VerificationParams verifyingSession =
prepareForVerification();
final VerificationParams verifyingSession = prepareForVerification();
if (isMultiPackage()) {
final List<PackageInstallerSession> childSessions = getChildSessions();
// Spot check to reject a non-staged multi package install of APEXes and APKs.
@@ -2395,14 +2394,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
PackageManager.INSTALL_FAILED_SESSION_INVALID,
"Non-staged multi package install of APEX and APK packages is not supported");
}
List<PackageManagerService.VerificationParams> verifyingChildSessions =
List<VerificationParams> verifyingChildSessions =
new ArrayList<>(childSessions.size());
boolean success = true;
PackageManagerException failure = null;
for (int i = 0; i < childSessions.size(); ++i) {
final PackageInstallerSession session = childSessions.get(i);
try {
final PackageManagerService.VerificationParams verifyingChildSession =
final VerificationParams verifyingChildSession =
session.prepareForVerification();
verifyingChildSessions.add(verifyingChildSession);
} catch (PackageManagerException e) {
@@ -2416,9 +2415,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
failure.error, failure.getLocalizedMessage(), null);
return;
}
mPm.verifyStage(verifyingSession, verifyingChildSessions);
verifyingSession.verifyStage(verifyingChildSessions);
} else {
mPm.verifyStage(verifyingSession);
verifyingSession.verifyStage();
}
}
@@ -2433,21 +2432,20 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private void installNonStaged()
throws PackageManagerException {
final PackageManagerService.InstallParams installingSession = makeInstallParams();
final InstallParams installingSession = makeInstallParams();
if (installingSession == null) {
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
"Session should contain at least one apk session for installation");
}
if (isMultiPackage()) {
final List<PackageInstallerSession> childSessions = getChildSessions();
List<PackageManagerService.InstallParams> installingChildSessions =
new ArrayList<>(childSessions.size());
List<InstallParams> installingChildSessions = new ArrayList<>(childSessions.size());
boolean success = true;
PackageManagerException failure = null;
for (int i = 0; i < childSessions.size(); ++i) {
final PackageInstallerSession session = childSessions.get(i);
try {
final PackageManagerService.InstallParams installingChildSession =
final InstallParams installingChildSession =
session.makeInstallParams();
if (installingChildSession != null) {
installingChildSessions.add(installingChildSession);
@@ -2463,20 +2461,19 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
failure.error, failure.getLocalizedMessage(), null);
return;
}
mPm.installStage(installingSession, installingChildSessions);
installingSession.installStage(installingChildSessions);
} else {
mPm.installStage(installingSession);
installingSession.installStage();
}
}
/**
* Stages this session for verification and returns a
* {@link PackageManagerService.VerificationParams} representing this new staged state or null
* {@link VerificationParams} representing this new staged state or null
* in case permissions need to be requested before verification can proceed.
*/
@NonNull
private PackageManagerService.VerificationParams prepareForVerification()
throws PackageManagerException {
private VerificationParams prepareForVerification() throws PackageManagerException {
assertNotLocked("makeSessionActive");
synchronized (mLock) {
@@ -2603,9 +2600,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@GuardedBy("mLock")
@Nullable
/**
* Returns a {@link com.android.server.pm.PackageManagerService.VerificationParams}
* Returns a {@link com.android.server.pm.VerificationParams}
*/
private PackageManagerService.VerificationParams makeVerificationParamsLocked() {
private VerificationParams makeVerificationParamsLocked() {
final IPackageInstallObserver2 localObserver;
if (!hasParentSessionId()) {
// Avoid attaching this observer to child session since they won't use it.
@@ -2638,8 +2635,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
mRelinquished = true;
return mPm.new VerificationParams(user, stageDir, localObserver, params,
mInstallSource, mInstallerUid, mSigningDetails, sessionId, mPackageLite);
return new VerificationParams(user, stageDir, localObserver, params,
mInstallSource, mInstallerUid, mSigningDetails, sessionId, mPackageLite, mPm);
}
private void onVerificationComplete() {
@@ -2656,10 +2653,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
/**
* Stages this session for install and returns a
* {@link PackageManagerService.InstallParams} representing this new staged state.
* {@link InstallParams} representing this new staged state.
*/
@Nullable
private PackageManagerService.InstallParams makeInstallParams()
private InstallParams makeInstallParams()
throws PackageManagerException {
synchronized (mLock) {
if (mDestroyed) {
@@ -2722,8 +2719,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
synchronized (mLock) {
return mPm.new InstallParams(stageDir, localObserver, params, mInstallSource, user,
mSigningDetails, mInstallerUid, mPackageLite);
return new InstallParams(stageDir, localObserver, params, mInstallSource, user,
mSigningDetails, mInstallerUid, mPackageLite, mPm);
}
}

View File

@@ -0,0 +1,179 @@
/*
* 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 android.os.PowerExemptionManager.REASON_PACKAGE_REPLACED;
import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import android.annotation.NonNull;
import android.app.ActivityManagerInternal;
import android.app.BroadcastOptions;
import android.content.Intent;
import android.os.Bundle;
import android.os.PowerExemptionManager;
import android.util.SparseArray;
import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
final class PackageRemovedInfo {
final PackageSender mPackageSender;
String mRemovedPackage;
String mInstallerPackageName;
int mUid = -1;
int mRemovedAppId = -1;
int[] mOrigUsers;
int[] mRemovedUsers = null;
int[] mBroadcastUsers = null;
int[] mInstantUserIds = null;
SparseArray<Integer> mInstallReasons;
SparseArray<Integer> mUninstallReasons;
boolean mIsRemovedPackageSystemUpdate = false;
boolean mIsUpdate;
boolean mDataRemoved;
boolean mRemovedForAllUsers;
boolean mIsStaticSharedLib;
// a two dimensional array mapping userId to the set of appIds that can receive notice
// of package changes
SparseArray<int[]> mBroadcastAllowList;
// Clean up resources deleted packages.
InstallArgs mArgs = null;
private static final int[] EMPTY_INT_ARRAY = new int[0];
PackageRemovedInfo(PackageSender packageSender) {
mPackageSender = packageSender;
}
void sendPackageRemovedBroadcasts(boolean killApp, boolean removedBySystem) {
sendPackageRemovedBroadcastInternal(killApp, removedBySystem);
}
void sendSystemPackageUpdatedBroadcasts() {
if (mIsRemovedPackageSystemUpdate) {
sendSystemPackageUpdatedBroadcastsInternal();
}
}
private void sendSystemPackageUpdatedBroadcastsInternal() {
Bundle extras = new Bundle(2);
extras.putInt(Intent.EXTRA_UID, mRemovedAppId >= 0 ? mRemovedAppId : mUid);
extras.putBoolean(Intent.EXTRA_REPLACING, true);
mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, mRemovedPackage, extras,
0, null /*targetPackage*/, null, null, null, mBroadcastAllowList, null);
mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, mRemovedPackage,
extras, 0, null /*targetPackage*/, null, null, null, mBroadcastAllowList, null);
mPackageSender.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, null, 0,
mRemovedPackage, null, null, null, null /* broadcastAllowList */,
getTemporaryAppAllowlistBroadcastOptions(REASON_PACKAGE_REPLACED).toBundle());
if (mInstallerPackageName != null) {
mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
mRemovedPackage, extras, 0 /*flags*/,
mInstallerPackageName, null, null, null, null /* broadcastAllowList */,
null);
mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
mRemovedPackage, extras, 0 /*flags*/,
mInstallerPackageName, null, null, null, null /* broadcastAllowList */,
null);
}
}
private static @NonNull BroadcastOptions getTemporaryAppAllowlistBroadcastOptions(
@PowerExemptionManager.ReasonCode int reasonCode) {
long duration = 10_000;
final ActivityManagerInternal amInternal =
LocalServices.getService(ActivityManagerInternal.class);
if (amInternal != null) {
duration = amInternal.getBootTimeTempAllowListDuration();
}
final BroadcastOptions bOptions = BroadcastOptions.makeBasic();
bOptions.setTemporaryAppAllowlist(duration,
TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
reasonCode, "");
return bOptions;
}
private void sendPackageRemovedBroadcastInternal(boolean killApp, boolean removedBySystem) {
// Don't send static shared library removal broadcasts as these
// libs are visible only the apps that depend on them an one
// cannot remove the library if it has a dependency.
if (mIsStaticSharedLib) {
return;
}
Bundle extras = new Bundle(2);
final int removedUid = mRemovedAppId >= 0 ? mRemovedAppId : mUid;
extras.putInt(Intent.EXTRA_UID, removedUid);
extras.putBoolean(Intent.EXTRA_DATA_REMOVED, mDataRemoved);
extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, !killApp);
extras.putBoolean(Intent.EXTRA_USER_INITIATED, !removedBySystem);
if (mIsUpdate || mIsRemovedPackageSystemUpdate) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
extras.putBoolean(Intent.EXTRA_REMOVED_FOR_ALL_USERS, mRemovedForAllUsers);
if (mRemovedPackage != null) {
mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED,
mRemovedPackage, extras, 0, null /*targetPackage*/, null,
mBroadcastUsers, mInstantUserIds, mBroadcastAllowList, null);
if (mInstallerPackageName != null) {
mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED,
mRemovedPackage, extras, 0 /*flags*/,
mInstallerPackageName, null, mBroadcastUsers, mInstantUserIds, null, null);
}
mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED_INTERNAL,
mRemovedPackage, extras, 0 /*flags*/, PLATFORM_PACKAGE_NAME,
null /*finishedReceiver*/, mBroadcastUsers, mInstantUserIds,
mBroadcastAllowList, null /*bOptions*/);
if (mDataRemoved && !mIsRemovedPackageSystemUpdate) {
mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED,
mRemovedPackage, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, null,
null, mBroadcastUsers, mInstantUserIds, mBroadcastAllowList, null);
mPackageSender.notifyPackageRemoved(mRemovedPackage, removedUid);
}
}
if (mRemovedAppId >= 0) {
// If a system app's updates are uninstalled the UID is not actually removed. Some
// services need to know the package name affected.
if (extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
extras.putString(Intent.EXTRA_PACKAGE_NAME, mRemovedPackage);
}
mPackageSender.sendPackageBroadcast(Intent.ACTION_UID_REMOVED,
null, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND,
null, null, mBroadcastUsers, mInstantUserIds, mBroadcastAllowList, null);
}
}
void populateUsers(int[] userIds, PackageSetting deletedPackageSetting) {
mRemovedUsers = userIds;
if (mRemovedUsers == null) {
mBroadcastUsers = null;
return;
}
mBroadcastUsers = EMPTY_INT_ARRAY;
mInstantUserIds = EMPTY_INT_ARRAY;
for (int i = userIds.length - 1; i >= 0; --i) {
final int userId = userIds[i];
if (deletedPackageSetting.getInstantApp(userId)) {
mInstantUserIds = ArrayUtils.appendInt(mInstantUserIds, userId);
} else {
mBroadcastUsers = ArrayUtils.appendInt(mBroadcastUsers, userId);
}
}
}
}

View File

@@ -0,0 +1,39 @@
/*
* 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.Nullable;
import android.content.IIntentReceiver;
import android.os.Bundle;
import android.util.SparseArray;
interface PackageSender {
/**
* @param userIds User IDs where the action occurred on a full application
* @param instantUserIds User IDs where the action occurred on an instant application
*/
void sendPackageBroadcast(String action, String pkg,
Bundle extras, int flags, String targetPkg,
IIntentReceiver finishedReceiver, int[] userIds, int[] instantUserIds,
@Nullable SparseArray<int[]> broadcastAllowList, @Nullable Bundle bOptions);
void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted,
boolean includeStopped, int appId, int[] userIds, int[] instantUserIds,
int dataLoaderType);
void notifyPackageAdded(String packageName, int uid);
void notifyPackageChanged(String packageName, int uid);
void notifyPackageRemoved(String packageName, int uid);
}

View File

@@ -19,8 +19,6 @@ package com.android.server.pm;
import android.content.pm.PackageManager;
import android.util.SparseBooleanArray;
import com.android.server.pm.PackageManagerService.VerificationParams;
/**
* Tracks the package verification state for a particular package. Each package verification has a
* required verifier and zero or more sufficient verifiers. Only one of the sufficient verifier list

View File

@@ -0,0 +1,45 @@
/*
* 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.util.ExceptionUtils;
final class PrepareFailure extends PackageManagerException {
public String mConflictingPackage;
public String mConflictingPermission;
PrepareFailure(int error) {
super(error, "Failed to prepare for install.");
}
PrepareFailure(int error, String detailMessage) {
super(error, detailMessage);
}
PrepareFailure(String message, Exception e) {
super(((PackageManagerException) e).error,
ExceptionUtils.getCompleteMessage(message, e));
}
PrepareFailure conflictsWithExistingPermission(String conflictingPermission,
String conflictingPackage) {
mConflictingPermission = conflictingPermission;
mConflictingPackage = conflictingPackage;
return this;
}
}

View File

@@ -0,0 +1,54 @@
/*
* 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.Nullable;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.ParsedPackage;
/**
* The set of data needed to successfully install the prepared package. This includes data that
* will be used to scan and reconcile the package.
*/
final class PrepareResult {
public final boolean mReplace;
public final int mScanFlags;
public final int mParseFlags;
@Nullable /* The original Package if it is being replaced, otherwise {@code null} */
public final AndroidPackage mExistingPackage;
public final ParsedPackage mPackageToScan;
public final boolean mClearCodeCache;
public final boolean mSystem;
public final PackageSetting mOriginalPs;
public final PackageSetting mDisabledPs;
PrepareResult(boolean replace, int scanFlags,
int parseFlags, AndroidPackage existingPackage,
ParsedPackage packageToScan, boolean clearCodeCache, boolean system,
PackageSetting originalPs, PackageSetting disabledPs) {
mReplace = replace;
mScanFlags = scanFlags;
mParseFlags = parseFlags;
mExistingPackage = existingPackage;
mPackageToScan = packageToScan;
mClearCodeCache = clearCodeCache;
mSystem = system;
mOriginalPs = originalPs;
mDisabledPs = disabledPs;
}
}

View File

@@ -0,0 +1,29 @@
/*
* 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;
final class ReconcileFailure extends PackageManagerException {
ReconcileFailure(String message) {
super("Reconcile failed: " + message);
}
ReconcileFailure(int reason, String message) {
super(reason, "Reconcile failed: " + message);
}
ReconcileFailure(PackageManagerException e) {
this(e.error, e.getMessage());
}
}

View File

@@ -0,0 +1,74 @@
/*
* 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.content.pm.SharedLibraryInfo;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.utils.WatchedLongSparseArray;
import java.util.Collections;
import java.util.Map;
/**
* Package scan results and related request details used to reconcile the potential addition of
* one or more packages to the system.
*
* Reconcile will take a set of package details that need to be committed to the system and make
* sure that they are valid in the context of the system and the other installing apps. Any
* invalid state or app will result in a failed reconciliation and thus whatever operation (such
* as install) led to the request.
*/
final class ReconcileRequest {
public final Map<String, ScanResult> mScannedPackages;
public final Map<String, AndroidPackage> mAllPackages;
public final Map<String, WatchedLongSparseArray<SharedLibraryInfo>> mSharedLibrarySource;
public final Map<String, InstallArgs> mInstallArgs;
public final Map<String, PackageInstalledInfo> mInstallResults;
public final Map<String, PrepareResult> mPreparedPackages;
public final Map<String, Settings.VersionInfo> mVersionInfos;
public final Map<String, PackageSetting> mLastStaticSharedLibSettings;
ReconcileRequest(Map<String, ScanResult> scannedPackages,
Map<String, InstallArgs> installArgs,
Map<String, PackageInstalledInfo> installResults,
Map<String, PrepareResult> preparedPackages,
Map<String, WatchedLongSparseArray<SharedLibraryInfo>> sharedLibrarySource,
Map<String, AndroidPackage> allPackages,
Map<String, Settings.VersionInfo> versionInfos,
Map<String, PackageSetting> lastStaticSharedLibSettings) {
mScannedPackages = scannedPackages;
mInstallArgs = installArgs;
mInstallResults = installResults;
mPreparedPackages = preparedPackages;
mSharedLibrarySource = sharedLibrarySource;
mAllPackages = allPackages;
mVersionInfos = versionInfos;
mLastStaticSharedLibSettings = lastStaticSharedLibSettings;
}
ReconcileRequest(Map<String, ScanResult> scannedPackages,
Map<String, WatchedLongSparseArray<SharedLibraryInfo>> sharedLibrarySource,
Map<String, AndroidPackage> allPackages,
Map<String, Settings.VersionInfo> versionInfos,
Map<String, PackageSetting> lastStaticSharedLibSettings) {
this(scannedPackages, Collections.emptyMap(), Collections.emptyMap(),
Collections.emptyMap(), sharedLibrarySource, allPackages, versionInfos,
lastStaticSharedLibSettings);
}
}

View File

@@ -0,0 +1,90 @@
/*
* 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.Nullable;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.SigningDetails;
import android.util.ArrayMap;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* A container of all data needed to commit a package to in-memory data structures and to disk.
* TODO: move most of the data contained here into a PackageSetting for commit.
*/
final class ReconciledPackage {
public final ReconcileRequest mRequest;
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;
public final DeletePackageAction mDeletePackageAction;
public final List<SharedLibraryInfo> mAllowedSharedLibraryInfos;
public final SigningDetails mSigningDetails;
public final boolean mSharedUserSignaturesChanged;
public ArrayList<SharedLibraryInfo> mCollectedSharedLibraryInfos;
public final boolean mRemoveAppKeySetData;
ReconciledPackage(ReconcileRequest request,
InstallArgs installArgs,
PackageSetting pkgSetting,
PackageInstalledInfo installResult,
PrepareResult prepareResult,
ScanResult scanResult,
DeletePackageAction deletePackageAction,
List<SharedLibraryInfo> allowedSharedLibraryInfos,
SigningDetails signingDetails,
boolean sharedUserSignaturesChanged,
boolean removeAppKeySetData) {
mRequest = request;
mInstallArgs = installArgs;
mPkgSetting = pkgSetting;
mInstallResult = installResult;
mPrepareResult = prepareResult;
mScanResult = scanResult;
mDeletePackageAction = deletePackageAction;
mAllowedSharedLibraryInfos = allowedSharedLibraryInfos;
mSigningDetails = signingDetails;
mSharedUserSignaturesChanged = sharedUserSignaturesChanged;
mRemoveAppKeySetData = removeAppKeySetData;
}
/**
* Returns a combined set of packages containing the packages already installed combined
* with the package(s) currently being installed. The to-be installed packages take
* precedence and may shadow already installed packages.
*/
Map<String, AndroidPackage> getCombinedAvailablePackages() {
final ArrayMap<String, AndroidPackage> combined =
new ArrayMap<>(mRequest.mAllPackages.size() + mRequest.mScannedPackages.size());
combined.putAll(mRequest.mAllPackages);
for (ScanResult scanResult : mRequest.mScannedPackages.values()) {
combined.put(scanResult.mPkgSetting.name, scanResult.mRequest.mParsedPackage);
}
return combined;
}
}

View File

@@ -0,0 +1,87 @@
/*
* 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;
import android.content.pm.parsing.ParsingPackageUtils;
import android.os.UserHandle;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.ParsedPackage;
/** A package to be scanned */
@VisibleForTesting
final class ScanRequest {
/** The parsed package */
@NonNull public final ParsedPackage mParsedPackage;
/** The package this package replaces */
@Nullable public final AndroidPackage mOldPkg;
/** Shared user settings, if the package has a shared user */
@Nullable public final SharedUserSetting mSharedUserSetting;
/**
* Package settings of the currently installed version.
* <p><em>IMPORTANT:</em> The contents of this object may be modified
* during scan.
*/
@Nullable public final PackageSetting mPkgSetting;
/** A copy of the settings for the currently installed version */
@Nullable public final PackageSetting mOldPkgSetting;
/** Package settings for the disabled version on the /system partition */
@Nullable public final PackageSetting mDisabledPkgSetting;
/** Package settings for the installed version under its original package name */
@Nullable public final PackageSetting mOriginalPkgSetting;
/** The real package name of a renamed application */
@Nullable public final String mRealPkgName;
public final @ParsingPackageUtils.ParseFlags int mParseFlags;
public final @PackageManagerService.ScanFlags int mScanFlags;
/** The user for which the package is being scanned */
@Nullable public final UserHandle mUser;
/** Whether or not the platform package is being scanned */
public final boolean mIsPlatformPackage;
/** Override value for package ABI if set during install */
@Nullable public final String mCpuAbiOverride;
ScanRequest(
@NonNull ParsedPackage parsedPackage,
@Nullable SharedUserSetting sharedUserSetting,
@Nullable AndroidPackage oldPkg,
@Nullable PackageSetting pkgSetting,
@Nullable PackageSetting disabledPkgSetting,
@Nullable PackageSetting originalPkgSetting,
@Nullable String realPkgName,
@ParsingPackageUtils.ParseFlags int parseFlags,
@PackageManagerService.ScanFlags int scanFlags,
boolean isPlatformPackage,
@Nullable UserHandle user,
@Nullable String cpuAbiOverride) {
mParsedPackage = parsedPackage;
mOldPkg = oldPkg;
mPkgSetting = pkgSetting;
mSharedUserSetting = sharedUserSetting;
mOldPkgSetting = pkgSetting == null ? null : new PackageSetting(pkgSetting);
mDisabledPkgSetting = disabledPkgSetting;
mOriginalPkgSetting = originalPkgSetting;
mRealPkgName = realPkgName;
mParseFlags = parseFlags;
mScanFlags = scanFlags;
mIsPlatformPackage = isPlatformPackage;
mUser = user;
mCpuAbiOverride = cpuAbiOverride;
}
}

View File

@@ -0,0 +1,65 @@
/*
* 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.Nullable;
import android.content.pm.SharedLibraryInfo;
import com.android.internal.annotations.VisibleForTesting;
import java.util.List;
/** The result of a package scan. */
@VisibleForTesting
final class ScanResult {
/** The request that initiated the scan that produced this result. */
public final ScanRequest mRequest;
/** Whether or not the package scan was successful */
public final boolean mSuccess;
/**
* Whether or not the original PackageSetting needs to be updated with this result on
* commit.
*/
public final boolean mExistingSettingCopied;
/**
* The final package settings. This may be the same object passed in
* the {@link ScanRequest}, but, with modified values.
*/
@Nullable
public final PackageSetting mPkgSetting;
/** ABI code paths that have changed in the package scan */
@Nullable public final List<String> mChangedAbiCodePath;
public final SharedLibraryInfo mStaticSharedLibraryInfo;
public final List<SharedLibraryInfo> mDynamicSharedLibraryInfos;
ScanResult(
ScanRequest request, boolean success,
@Nullable PackageSetting pkgSetting,
@Nullable List<String> changedAbiCodePath, boolean existingSettingCopied,
SharedLibraryInfo staticSharedLibraryInfo,
List<SharedLibraryInfo> dynamicSharedLibraryInfos) {
mRequest = request;
mSuccess = success;
mPkgSetting = pkgSetting;
mChangedAbiCodePath = changedAbiCodePath;
mExistingSettingCopied = existingSettingCopied;
mStaticSharedLibraryInfo = staticSharedLibraryInfo;
mDynamicSharedLibraryInfos = dynamicSharedLibraryInfos;
}
}

View File

@@ -0,0 +1,25 @@
/*
* 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;
final class SystemDeleteException extends Exception {
final PackageManagerException mReason;
SystemDeleteException(PackageManagerException reason) {
mReason = reason;
}
}

View File

@@ -0,0 +1,40 @@
/*
* 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.net.Uri;
final class VerificationInfo {
/** URI referencing where the package was downloaded from. */
final Uri mOriginatingUri;
/** HTTP referrer URI associated with the originatingURI. */
final Uri mReferrer;
/** UID of the application that the install request originated from. */
final int mOriginatingUid;
/** UID of application requesting the install */
final int mInstallerUid;
VerificationInfo(Uri originatingUri, Uri referrer, int originatingUid, int installerUid) {
mOriginatingUri = originatingUri;
mReferrer = referrer;
mOriginatingUid = originatingUid;
mInstallerUid = installerUid;
}
}

View File

@@ -0,0 +1,778 @@
/*
* 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 android.content.Intent.EXTRA_LONG_VERSION_CODE;
import static android.content.Intent.EXTRA_PACKAGE_NAME;
import static android.content.Intent.EXTRA_VERSION_CODE;
import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID;
import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
import static android.content.pm.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V4;
import static android.os.PowerWhitelistManager.REASON_PACKAGE_VERIFIER;
import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static com.android.server.pm.PackageManagerService.CHECK_PENDING_INTEGRITY_VERIFICATION;
import static com.android.server.pm.PackageManagerService.CHECK_PENDING_VERIFICATION;
import static com.android.server.pm.PackageManagerService.DEBUG_VERIFY;
import static com.android.server.pm.PackageManagerService.ENABLE_ROLLBACK_TIMEOUT;
import static com.android.server.pm.PackageManagerService.PACKAGE_MIME_TYPE;
import static com.android.server.pm.PackageManagerService.TAG;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.app.BroadcastOptions;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.DataLoaderType;
import android.content.pm.IPackageInstallObserver2;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
import android.content.pm.SigningDetails;
import android.content.pm.VerifierInfo;
import android.content.pm.parsing.PackageLite;
import android.net.Uri;
import android.os.Bundle;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.util.ArrayMap;
import android.util.Pair;
import android.util.Slog;
import com.android.server.DeviceIdleInternal;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import java.io.File;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
final class VerificationParams extends HandlerParams {
/**
* Whether integrity verification is enabled by default.
*/
private static final boolean DEFAULT_INTEGRITY_VERIFY_ENABLE = true;
/**
* The default maximum time to wait for the integrity verification to return in
* milliseconds.
*/
private static final long DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT = 30 * 1000;
/**
* Whether verification is enabled by default.
*/
private static final boolean DEFAULT_VERIFY_ENABLE = true;
/**
* Timeout duration in milliseconds for enabling package rollback. If we fail to enable
* rollback within that period, the install will proceed without rollback enabled.
*
* <p>If flag value is negative, the default value will be assigned.
*
* Flag type: {@code long}
* Namespace: NAMESPACE_ROLLBACK
*/
private static final String PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS = "enable_rollback_timeout";
/**
* The default duration to wait for rollback to be enabled in
* milliseconds.
*/
private static final long DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS = 10 * 1000;
final OriginInfo mOriginInfo;
final IPackageInstallObserver2 mObserver;
final int mInstallFlags;
@NonNull
final InstallSource mInstallSource;
final String mPackageAbiOverride;
final VerificationInfo mVerificationInfo;
final SigningDetails mSigningDetails;
@Nullable
MultiPackageVerificationParams mParentVerificationParams;
final long mRequiredInstalledVersionCode;
final int mDataLoaderType;
final int mSessionId;
private boolean mWaitForVerificationToComplete;
private boolean mWaitForIntegrityVerificationToComplete;
private boolean mWaitForEnableRollbackToComplete;
private int mRet = PackageManager.INSTALL_SUCCEEDED;
private String mErrorMessage = null;
final PackageLite mPackageLite;
final PackageManagerService mPm;
VerificationParams(UserHandle user, File stagedDir, IPackageInstallObserver2 observer,
PackageInstaller.SessionParams sessionParams, InstallSource installSource,
int installerUid, SigningDetails signingDetails, int sessionId, PackageLite lite,
PackageManagerService pm) {
super(user);
mOriginInfo = OriginInfo.fromStagedFile(stagedDir);
mObserver = observer;
mInstallFlags = sessionParams.installFlags;
mInstallSource = installSource;
mPackageAbiOverride = sessionParams.abiOverride;
mVerificationInfo = new VerificationInfo(
sessionParams.originatingUri,
sessionParams.referrerUri,
sessionParams.originatingUid,
installerUid
);
mSigningDetails = signingDetails;
mRequiredInstalledVersionCode = sessionParams.requiredInstalledVersionCode;
mDataLoaderType = (sessionParams.dataLoaderParams != null)
? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE;
mSessionId = sessionId;
mPackageLite = lite;
mPm = pm;
}
@Override
public String toString() {
return "InstallParams{" + Integer.toHexString(System.identityHashCode(this))
+ " file=" + mOriginInfo.mFile + "}";
}
public void handleStartCopy() {
PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mPm.mContext,
mPackageLite, mOriginInfo.mResolvedPath, mInstallFlags, mPackageAbiOverride);
Pair<Integer, String> ret = mPm.verifyReplacingVersionCode(
pkgLite, mRequiredInstalledVersionCode, mInstallFlags);
setReturnCode(ret.first, ret.second);
if (mRet != INSTALL_SUCCEEDED) {
return;
}
// Perform package verification and enable rollback (unless we are simply moving the
// package).
if (!mOriginInfo.mExisting) {
if ((mInstallFlags & PackageManager.INSTALL_APEX) == 0) {
// TODO(b/182426975): treat APEX as APK when APK verification is concerned
sendApkVerificationRequest(pkgLite);
}
if ((mInstallFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
sendEnableRollbackRequest();
}
}
}
void sendApkVerificationRequest(PackageInfoLite pkgLite) {
final int verificationId = mPm.mPendingVerificationToken++;
PackageVerificationState verificationState =
new PackageVerificationState(this);
mPm.mPendingVerification.append(verificationId, verificationState);
sendIntegrityVerificationRequest(verificationId, pkgLite, verificationState);
sendPackageVerificationRequest(
verificationId, pkgLite, verificationState);
// If both verifications are skipped, we should remove the state.
if (verificationState.areAllVerificationsComplete()) {
mPm.mPendingVerification.remove(verificationId);
}
}
void sendEnableRollbackRequest() {
final int enableRollbackToken = mPm.mPendingEnableRollbackToken++;
Trace.asyncTraceBegin(
TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
mPm.mPendingEnableRollback.append(enableRollbackToken, this);
Intent enableRollbackIntent = new Intent(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK);
enableRollbackIntent.putExtra(
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN,
enableRollbackToken);
enableRollbackIntent.putExtra(
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID,
mSessionId);
enableRollbackIntent.setType(PACKAGE_MIME_TYPE);
enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// Allow the broadcast to be sent before boot complete.
// This is needed when committing the apk part of a staged
// session in early boot. The rollback manager registers
// its receiver early enough during the boot process that
// it will not miss the broadcast.
enableRollbackIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mPm.mContext.sendBroadcastAsUser(enableRollbackIntent, UserHandle.SYSTEM,
android.Manifest.permission.PACKAGE_ROLLBACK_AGENT);
mWaitForEnableRollbackToComplete = true;
// the duration to wait for rollback to be enabled, in millis
long rollbackTimeout = DeviceConfig.getLong(
DeviceConfig.NAMESPACE_ROLLBACK,
PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS);
if (rollbackTimeout < 0) {
rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS;
}
final Message msg = mPm.mHandler.obtainMessage(ENABLE_ROLLBACK_TIMEOUT);
msg.arg1 = enableRollbackToken;
msg.arg2 = mSessionId;
mPm.mHandler.sendMessageDelayed(msg, rollbackTimeout);
}
/**
* Send a request to check the integrity of the package.
*/
void sendIntegrityVerificationRequest(
int verificationId,
PackageInfoLite pkgLite,
PackageVerificationState verificationState) {
if (!isIntegrityVerificationEnabled()) {
// Consider the integrity check as passed.
verificationState.setIntegrityVerificationResult(
PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
return;
}
final Intent integrityVerification =
new Intent(Intent.ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION);
integrityVerification.setDataAndType(Uri.fromFile(new File(mOriginInfo.mResolvedPath)),
PACKAGE_MIME_TYPE);
final int flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND;
integrityVerification.addFlags(flags);
integrityVerification.putExtra(EXTRA_VERIFICATION_ID, verificationId);
integrityVerification.putExtra(EXTRA_PACKAGE_NAME, pkgLite.packageName);
integrityVerification.putExtra(EXTRA_VERSION_CODE, pkgLite.versionCode);
integrityVerification.putExtra(EXTRA_LONG_VERSION_CODE, pkgLite.getLongVersionCode());
populateInstallerExtras(integrityVerification);
// send to integrity component only.
integrityVerification.setPackage("android");
final BroadcastOptions options = BroadcastOptions.makeBasic();
mPm.mContext.sendOrderedBroadcastAsUser(integrityVerification, UserHandle.SYSTEM,
/* receiverPermission= */ null,
/* appOp= */ AppOpsManager.OP_NONE,
/* options= */ options.toBundle(),
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final Message msg =
mPm.mHandler.obtainMessage(CHECK_PENDING_INTEGRITY_VERIFICATION);
msg.arg1 = verificationId;
mPm.mHandler.sendMessageDelayed(msg, getIntegrityVerificationTimeout());
}
}, /* scheduler= */ null,
/* initialCode= */ 0,
/* initialData= */ null,
/* initialExtras= */ null);
Trace.asyncTraceBegin(
TRACE_TAG_PACKAGE_MANAGER, "integrity_verification", verificationId);
// stop the copy until verification succeeds.
mWaitForIntegrityVerificationToComplete = true;
}
/**
* Get the integrity verification timeout.
*
* @return verification timeout in milliseconds
*/
private long getIntegrityVerificationTimeout() {
long timeout = Settings.Global.getLong(mPm.mContext.getContentResolver(),
Settings.Global.APP_INTEGRITY_VERIFICATION_TIMEOUT,
DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT);
// The setting can be used to increase the timeout but not decrease it, since that is
// equivalent to disabling the integrity component.
return Math.max(timeout, DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT);
}
/**
* Check whether or not integrity verification has been enabled.
*/
private boolean isIntegrityVerificationEnabled() {
// We are not exposing this as a user-configurable setting because we don't want to provide
// an easy way to get around the integrity check.
return DEFAULT_INTEGRITY_VERIFY_ENABLE;
}
/**
* Send a request to verifier(s) to verify the package if necessary.
*/
void sendPackageVerificationRequest(
int verificationId,
PackageInfoLite pkgLite,
PackageVerificationState verificationState) {
// TODO: http://b/22976637
// Apps installed for "all" users use the device owner to verify the app
UserHandle verifierUser = getUser();
if (verifierUser == UserHandle.ALL) {
verifierUser = UserHandle.SYSTEM;
}
/*
* Determine if we have any installed package verifiers. If we
* do, then we'll defer to them to verify the packages.
*/
final int requiredUid = mPm.mRequiredVerifierPackage == null ? -1
: mPm.getPackageUid(mPm.mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
verifierUser.getIdentifier());
verificationState.setRequiredVerifierUid(requiredUid);
final int installerUid =
mVerificationInfo == null ? -1 : mVerificationInfo.mInstallerUid;
final boolean isVerificationEnabled = isVerificationEnabled(
pkgLite, verifierUser.getIdentifier(), mInstallFlags, installerUid);
final boolean isV4Signed =
(mSigningDetails.getSignatureSchemeVersion() == SIGNING_BLOCK_V4);
final boolean isIncrementalInstall =
(mDataLoaderType == DataLoaderType.INCREMENTAL);
// NOTE: We purposefully skip verification for only incremental installs when there's
// a v4 signature block. Otherwise, proceed with verification as usual.
if (!mOriginInfo.mExisting
&& isVerificationEnabled
&& (!isIncrementalInstall || !isV4Signed)) {
final Intent verification = new Intent(
Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
verification.setDataAndType(Uri.fromFile(new File(mOriginInfo.mResolvedPath)),
PACKAGE_MIME_TYPE);
verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// Query all live verifiers based on current user state
final ParceledListSlice<ResolveInfo> receivers = mPm.queryIntentReceivers(verification,
PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier());
if (DEBUG_VERIFY) {
Slog.d(TAG, "Found " + receivers.getList().size() + " verifiers for intent "
+ verification.toString() + " with " + pkgLite.verifiers.length
+ " optional verifiers");
}
verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);
verification.putExtra(
PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS, mInstallFlags);
verification.putExtra(
PackageManager.EXTRA_VERIFICATION_PACKAGE_NAME, pkgLite.packageName);
verification.putExtra(
PackageManager.EXTRA_VERIFICATION_VERSION_CODE, pkgLite.versionCode);
verification.putExtra(
PackageManager.EXTRA_VERIFICATION_LONG_VERSION_CODE,
pkgLite.getLongVersionCode());
populateInstallerExtras(verification);
final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
receivers.getList(), verificationState);
DeviceIdleInternal idleController =
mPm.mInjector.getLocalService(DeviceIdleInternal.class);
final long idleDuration = mPm.getVerificationTimeout();
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.setTemporaryAppAllowlist(idleDuration,
TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
REASON_PACKAGE_VERIFIER, "");
/*
* If any sufficient verifiers were listed in the package
* manifest, attempt to ask them.
*/
if (sufficientVerifiers != null) {
final int n = sufficientVerifiers.size();
if (n == 0) {
String errorMsg = "Additional verifiers required, but none installed.";
Slog.i(TAG, errorMsg);
setReturnCode(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE, errorMsg);
} else {
for (int i = 0; i < n; i++) {
final ComponentName verifierComponent = sufficientVerifiers.get(i);
idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
verifierComponent.getPackageName(), idleDuration,
verifierUser.getIdentifier(), false,
REASON_PACKAGE_VERIFIER, "package verifier");
final Intent sufficientIntent = new Intent(verification);
sufficientIntent.setComponent(verifierComponent);
mPm.mContext.sendBroadcastAsUser(sufficientIntent, verifierUser,
/* receiverPermission= */ null,
options.toBundle());
}
}
}
if (mPm.mRequiredVerifierPackage != null) {
final ComponentName requiredVerifierComponent = matchComponentForVerifier(
mPm.mRequiredVerifierPackage, receivers.getList());
/*
* Send the intent to the required verification agent,
* but only start the verification timeout after the
* target BroadcastReceivers have run.
*/
verification.setComponent(requiredVerifierComponent);
idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
mPm.mRequiredVerifierPackage, idleDuration,
verifierUser.getIdentifier(), false,
REASON_PACKAGE_VERIFIER, "package verifier");
mPm.mContext.sendOrderedBroadcastAsUser(verification, verifierUser,
android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
/* appOp= */ AppOpsManager.OP_NONE,
/* options= */ options.toBundle(),
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final Message msg = mPm.mHandler
.obtainMessage(CHECK_PENDING_VERIFICATION);
msg.arg1 = verificationId;
mPm.mHandler.sendMessageDelayed(msg, mPm.getVerificationTimeout());
}
}, null, 0, null, null);
Trace.asyncTraceBegin(
TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
/*
* We don't want the copy to proceed until verification
* succeeds.
*/
mWaitForVerificationToComplete = true;
}
} else {
verificationState.setVerifierResponse(
requiredUid, PackageManager.VERIFICATION_ALLOW);
}
}
private List<ComponentName> matchVerifiers(PackageInfoLite pkgInfo,
List<ResolveInfo> receivers, final PackageVerificationState verificationState) {
if (pkgInfo.verifiers.length == 0) {
return null;
}
final int n = pkgInfo.verifiers.length;
final List<ComponentName> sufficientVerifiers = new ArrayList<>(n + 1);
for (int i = 0; i < n; i++) {
final VerifierInfo verifierInfo = pkgInfo.verifiers[i];
final ComponentName comp = matchComponentForVerifier(verifierInfo.packageName,
receivers);
if (comp == null) {
continue;
}
final int verifierUid = getUidForVerifier(verifierInfo);
if (verifierUid == -1) {
continue;
}
if (DEBUG_VERIFY) {
Slog.d(TAG, "Added sufficient verifier " + verifierInfo.packageName
+ " with the correct signature");
}
sufficientVerifiers.add(comp);
verificationState.addSufficientVerifier(verifierUid);
}
return sufficientVerifiers;
}
private int getUidForVerifier(VerifierInfo verifierInfo) {
synchronized (mPm.mLock) {
final AndroidPackage pkg = mPm.mPackages.get(verifierInfo.packageName);
if (pkg == null) {
return -1;
} else if (pkg.getSigningDetails().getSignatures().length != 1) {
Slog.i(TAG, "Verifier package " + verifierInfo.packageName
+ " has more than one signature; ignoring");
return -1;
}
/*
* If the public key of the package's signature does not match
* our expected public key, then this is a different package and
* we should skip.
*/
final byte[] expectedPublicKey;
try {
final Signature verifierSig = pkg.getSigningDetails().getSignatures()[0];
final PublicKey publicKey = verifierSig.getPublicKey();
expectedPublicKey = publicKey.getEncoded();
} catch (CertificateException e) {
return -1;
}
final byte[] actualPublicKey = verifierInfo.publicKey.getEncoded();
if (!Arrays.equals(actualPublicKey, expectedPublicKey)) {
Slog.i(TAG, "Verifier package " + verifierInfo.packageName
+ " does not have the expected public key; ignoring");
return -1;
}
return pkg.getUid();
}
}
private static ComponentName matchComponentForVerifier(String packageName,
List<ResolveInfo> receivers) {
ActivityInfo targetReceiver = null;
final int nr = receivers.size();
for (int i = 0; i < nr; i++) {
final ResolveInfo info = receivers.get(i);
if (info.activityInfo == null) {
continue;
}
if (packageName.equals(info.activityInfo.packageName)) {
targetReceiver = info.activityInfo;
break;
}
}
if (targetReceiver == null) {
return null;
}
return new ComponentName(targetReceiver.packageName, targetReceiver.name);
}
/**
* Check whether or not package verification has been enabled.
*
* @return true if verification should be performed
*/
private boolean isVerificationEnabled(
PackageInfoLite pkgInfoLite, int userId, int installFlags, int installerUid) {
if (!DEFAULT_VERIFY_ENABLE) {
return false;
}
// Check if installing from ADB
if ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0) {
if (mPm.isUserRestricted(userId, UserManager.ENSURE_VERIFY_APPS)) {
return true;
}
// Check if the developer wants to skip verification for ADB installs
if ((installFlags & PackageManager.INSTALL_DISABLE_VERIFICATION) != 0) {
synchronized (mPm.mLock) {
if (mPm.mSettings.getPackageLPr(pkgInfoLite.packageName) == null) {
// Always verify fresh install
return true;
}
}
// Only skip when apk is debuggable
return !pkgInfoLite.debuggable;
}
return Settings.Global.getInt(mPm.mContext.getContentResolver(),
Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, 1) != 0;
}
// only when not installed from ADB, skip verification for instant apps when
// the installer and verifier are the same.
if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
if (mPm.mInstantAppInstallerActivity != null
&& mPm.mInstantAppInstallerActivity.packageName.equals(
mPm.mRequiredVerifierPackage)) {
try {
mPm.mInjector.getSystemService(AppOpsManager.class)
.checkPackage(installerUid, mPm.mRequiredVerifierPackage);
if (DEBUG_VERIFY) {
Slog.i(TAG, "disable verification for instant app");
}
return false;
} catch (SecurityException ignore) { }
}
}
return true;
}
void populateInstallerExtras(Intent intent) {
intent.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE,
mInstallSource.initiatingPackageName);
if (mVerificationInfo != null) {
if (mVerificationInfo.mOriginatingUri != null) {
intent.putExtra(Intent.EXTRA_ORIGINATING_URI,
mVerificationInfo.mOriginatingUri);
}
if (mVerificationInfo.mReferrer != null) {
intent.putExtra(Intent.EXTRA_REFERRER,
mVerificationInfo.mReferrer);
}
if (mVerificationInfo.mOriginatingUid >= 0) {
intent.putExtra(Intent.EXTRA_ORIGINATING_UID,
mVerificationInfo.mOriginatingUid);
}
if (mVerificationInfo.mInstallerUid >= 0) {
intent.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID,
mVerificationInfo.mInstallerUid);
}
}
}
void setReturnCode(int ret, String message) {
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
// Only update mRet if it was previously INSTALL_SUCCEEDED to
// ensure we do not overwrite any previous failure results.
mRet = ret;
mErrorMessage = message;
}
}
void handleVerificationFinished() {
mWaitForVerificationToComplete = false;
handleReturnCode();
}
void handleIntegrityVerificationFinished() {
mWaitForIntegrityVerificationToComplete = false;
handleReturnCode();
}
void handleRollbackEnabled() {
// TODO(b/112431924): Consider halting the install if we
// couldn't enable rollback.
mWaitForEnableRollbackToComplete = false;
handleReturnCode();
}
@Override
void handleReturnCode() {
if (mWaitForVerificationToComplete || mWaitForIntegrityVerificationToComplete
|| mWaitForEnableRollbackToComplete) {
return;
}
sendVerificationCompleteNotification();
}
private void sendVerificationCompleteNotification() {
if (mParentVerificationParams != null) {
mParentVerificationParams.trySendVerificationCompleteNotification(this, mRet);
} else {
try {
mObserver.onPackageInstalled(null, mRet, mErrorMessage,
new Bundle());
} catch (RemoteException e) {
Slog.i(TAG, "Observer no longer exists.");
}
}
}
public void verifyStage() {
mPm.mHandler.post(this::startCopy);
}
public void verifyStage(List<VerificationParams> children)
throws PackageManagerException {
final MultiPackageVerificationParams params =
new MultiPackageVerificationParams(this, children);
mPm.mHandler.post(params::startCopy);
}
/**
* Container for a multi-package install which refers to all install sessions and args being
* committed together.
*/
static final class MultiPackageVerificationParams extends HandlerParams {
private final IPackageInstallObserver2 mObserver;
private final List<VerificationParams> mChildParams;
private final Map<VerificationParams, Integer> mVerificationState;
MultiPackageVerificationParams(VerificationParams parent, List<VerificationParams> children)
throws PackageManagerException {
super(parent.getUser());
if (children.size() == 0) {
throw new PackageManagerException("No child sessions found!");
}
mChildParams = children;
// Provide every child with reference to this object as parent
for (int i = 0; i < children.size(); i++) {
final VerificationParams childParams = children.get(i);
childParams.mParentVerificationParams = this;
}
mVerificationState = new ArrayMap<>(mChildParams.size());
mObserver = parent.mObserver;
}
@Override
void handleStartCopy() {
for (VerificationParams params : mChildParams) {
params.handleStartCopy();
}
}
@Override
void handleReturnCode() {
for (VerificationParams params : mChildParams) {
params.handleReturnCode();
}
}
void trySendVerificationCompleteNotification(VerificationParams child, int currentStatus) {
mVerificationState.put(child, currentStatus);
if (mVerificationState.size() != mChildParams.size()) {
return;
}
int completeStatus = PackageManager.INSTALL_SUCCEEDED;
String errorMsg = null;
for (VerificationParams params : mVerificationState.keySet()) {
int status = params.mRet;
if (status == PackageManager.INSTALL_UNKNOWN) {
return;
} else if (status != PackageManager.INSTALL_SUCCEEDED) {
completeStatus = status;
errorMsg = params.mErrorMessage;
break;
}
}
try {
mObserver.onPackageInstalled(null, completeStatus,
errorMsg, new Bundle());
} catch (RemoteException e) {
Slog.i(TAG, "Observer no longer exists.");
}
}
}
}

View File

@@ -101,16 +101,15 @@ public class PackageManagerServiceTest {
PackageSenderImpl sender = new PackageSenderImpl();
PackageSetting setting = null;
PackageManagerService.PackageRemovedInfo pri =
new PackageManagerService.PackageRemovedInfo(sender);
PackageRemovedInfo pri = new PackageRemovedInfo(sender);
// Initial conditions: nothing there
Assert.assertNull(pri.removedUsers);
Assert.assertNull(pri.broadcastUsers);
Assert.assertNull(pri.mRemovedUsers);
Assert.assertNull(pri.mBroadcastUsers);
// populateUsers with nothing leaves nothing
pri.populateUsers(null, setting);
Assert.assertNull(pri.broadcastUsers);
Assert.assertNull(pri.mBroadcastUsers);
// Create a real (non-null) PackageSetting and confirm that the removed
// users are copied properly
@@ -126,22 +125,22 @@ public class PackageManagerServiceTest {
pri.populateUsers(new int[] {
1, 2, 3, 4, 5
}, setting);
Assert.assertNotNull(pri.broadcastUsers);
Assert.assertEquals(5, pri.broadcastUsers.length);
Assert.assertNotNull(pri.instantUserIds);
Assert.assertEquals(0, pri.instantUserIds.length);
Assert.assertNotNull(pri.mBroadcastUsers);
Assert.assertEquals(5, pri.mBroadcastUsers.length);
Assert.assertNotNull(pri.mInstantUserIds);
Assert.assertEquals(0, pri.mInstantUserIds.length);
// Exclude a user
pri.broadcastUsers = null;
pri.mBroadcastUsers = null;
final int EXCLUDED_USER_ID = 4;
setting.setInstantApp(true, EXCLUDED_USER_ID);
pri.populateUsers(new int[] {
1, 2, 3, EXCLUDED_USER_ID, 5
}, setting);
Assert.assertNotNull(pri.broadcastUsers);
Assert.assertEquals(4, pri.broadcastUsers.length);
Assert.assertNotNull(pri.instantUserIds);
Assert.assertEquals(1, pri.instantUserIds.length);
Assert.assertNotNull(pri.mBroadcastUsers);
Assert.assertEquals(4, pri.mBroadcastUsers.length);
Assert.assertNotNull(pri.mInstantUserIds);
Assert.assertEquals(1, pri.mInstantUserIds.length);
// TODO: test that sendApplicationHiddenForUser() actually fills in
// broadcastUsers

View File

@@ -108,8 +108,8 @@ class ScanRequestBuilder {
return this;
}
PackageManagerService.ScanRequest build() {
return new PackageManagerService.ScanRequest(
ScanRequest build() {
return new ScanRequest(
mPkg, mSharedUserSetting, mOldPkg, mPkgSetting, mDisabledPkgSetting,
mOriginalPkgSetting, mRealPkgName, mParseFlags, mScanFlags, mIsPlatformPackage,
mUser, mCpuAbiOverride);

View File

@@ -129,16 +129,16 @@ public class ScanTests {
@Test
public void newInstallSimpleAllNominal() throws Exception {
final PackageManagerService.ScanRequest scanRequest =
final ScanRequest scanRequest =
createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
.addScanFlag(PackageManagerService.SCAN_NEW_INSTALL)
.addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
.build();
final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
final ScanResult scanResult = executeScan(scanRequest);
assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
assertThat(scanResult.existingSettingCopied, is(false));
assertThat(scanResult.mExistingSettingCopied, is(false));
assertPathsNotDerived(scanResult);
}
@@ -147,38 +147,38 @@ public class ScanTests {
final int[] userIds = {0, 10, 11};
when(mMockUserManager.getUserIds()).thenReturn(userIds);
final PackageManagerService.ScanRequest scanRequest =
final ScanRequest scanRequest =
createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
.setRealPkgName(null)
.addScanFlag(PackageManagerService.SCAN_NEW_INSTALL)
.addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
.build();
final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
final ScanResult scanResult = executeScan(scanRequest);
for (int uid : userIds) {
assertThat(scanResult.pkgSetting.readUserState(uid).installed, is(true));
assertThat(scanResult.mPkgSetting.readUserState(uid).installed, is(true));
}
}
@Test
public void installRealPackageName() throws Exception {
final PackageManagerService.ScanRequest scanRequest =
final ScanRequest scanRequest =
createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
.setRealPkgName("com.package.real")
.build();
final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
final ScanResult scanResult = executeScan(scanRequest);
assertThat(scanResult.pkgSetting.realName, is("com.package.real"));
assertThat(scanResult.mPkgSetting.realName, is("com.package.real"));
final PackageManagerService.ScanRequest scanRequestNoRealPkg =
final ScanRequest scanRequestNoRealPkg =
createBasicScanRequestBuilder(
createBasicPackage(DUMMY_PACKAGE_NAME)
.setRealPackage("com.package.real"))
.build();
final PackageManagerService.ScanResult scanResultNoReal = executeScan(scanRequestNoRealPkg);
assertThat(scanResultNoReal.pkgSetting.realName, nullValue());
final ScanResult scanResultNoReal = executeScan(scanRequestNoRealPkg);
assertThat(scanResultNoReal.mPkgSetting.realName, nullValue());
}
@Test
@@ -189,25 +189,25 @@ public class ScanTests {
.setPrimaryCpuAbiString("primaryCpuAbi")
.setSecondaryCpuAbiString("secondaryCpuAbi")
.build();
final PackageManagerService.ScanRequest scanRequest =
final ScanRequest scanRequest =
createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
.addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
.setPkgSetting(pkgSetting)
.build();
final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
final ScanResult scanResult = executeScan(scanRequest);
assertThat(scanResult.existingSettingCopied, is(true));
assertThat(scanResult.mExistingSettingCopied, is(true));
// ensure we don't overwrite the existing pkgSetting, in case something post-scan fails
assertNotSame(pkgSetting, scanResult.pkgSetting);
assertNotSame(pkgSetting, scanResult.mPkgSetting);
assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
assertThat(scanResult.pkgSetting.primaryCpuAbiString, is("primaryCpuAbi"));
assertThat(scanResult.pkgSetting.secondaryCpuAbiString, is("secondaryCpuAbi"));
assertThat(scanResult.pkgSetting.cpuAbiOverrideString, nullValue());
assertThat(scanResult.mPkgSetting.primaryCpuAbiString, is("primaryCpuAbi"));
assertThat(scanResult.mPkgSetting.secondaryCpuAbiString, is("secondaryCpuAbi"));
assertThat(scanResult.mPkgSetting.cpuAbiOverrideString, nullValue());
assertPathsNotDerived(scanResult);
}
@@ -221,13 +221,13 @@ public class ScanTests {
.setInstantAppUserState(0, true)
.build();
final PackageManagerService.ScanRequest scanRequest =
final ScanRequest scanRequest =
createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
.setPkgSetting(existingPkgSetting)
.build();
final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
final ScanResult scanResult = executeScan(scanRequest);
assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, true /*isInstant*/);
}
@@ -244,24 +244,24 @@ public class ScanTests {
.setBaseApkPath("/some/path.apk")
.setSplitCodePaths(new String[] {"/some/other/path.apk"});
final PackageManagerService.ScanRequest scanRequest = new ScanRequestBuilder(pkg)
final ScanRequest scanRequest = new ScanRequestBuilder(pkg)
.setUser(UserHandle.of(0)).build();
final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
final ScanResult scanResult = executeScan(scanRequest);
assertThat(scanResult.staticSharedLibraryInfo.getPackageName(), is("static.lib.pkg.123"));
assertThat(scanResult.staticSharedLibraryInfo.getName(), is("static.lib"));
assertThat(scanResult.staticSharedLibraryInfo.getLongVersion(), is(123L));
assertThat(scanResult.staticSharedLibraryInfo.getType(), is(TYPE_STATIC));
assertThat(scanResult.staticSharedLibraryInfo.getDeclaringPackage().getPackageName(),
assertThat(scanResult.mStaticSharedLibraryInfo.getPackageName(), is("static.lib.pkg.123"));
assertThat(scanResult.mStaticSharedLibraryInfo.getName(), is("static.lib"));
assertThat(scanResult.mStaticSharedLibraryInfo.getLongVersion(), is(123L));
assertThat(scanResult.mStaticSharedLibraryInfo.getType(), is(TYPE_STATIC));
assertThat(scanResult.mStaticSharedLibraryInfo.getDeclaringPackage().getPackageName(),
is("static.lib.pkg"));
assertThat(scanResult.staticSharedLibraryInfo.getDeclaringPackage().getLongVersionCode(),
assertThat(scanResult.mStaticSharedLibraryInfo.getDeclaringPackage().getLongVersionCode(),
is(pkg.getLongVersionCode()));
assertThat(scanResult.staticSharedLibraryInfo.getAllCodePaths(),
assertThat(scanResult.mStaticSharedLibraryInfo.getAllCodePaths(),
hasItems("/some/path.apk", "/some/other/path.apk"));
assertThat(scanResult.staticSharedLibraryInfo.getDependencies(), nullValue());
assertThat(scanResult.staticSharedLibraryInfo.getDependentPackages(), empty());
assertThat(scanResult.mStaticSharedLibraryInfo.getDependencies(), nullValue());
assertThat(scanResult.mStaticSharedLibraryInfo.getDependentPackages(), empty());
}
@Test
@@ -276,13 +276,13 @@ public class ScanTests {
.setBaseApkPath("/some/path.apk")
.setSplitCodePaths(new String[] {"/some/other/path.apk"});
final PackageManagerService.ScanRequest scanRequest =
final ScanRequest scanRequest =
new ScanRequestBuilder(pkg).setUser(UserHandle.of(0)).build();
final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
final ScanResult scanResult = executeScan(scanRequest);
final SharedLibraryInfo dynamicLib0 = scanResult.dynamicSharedLibraryInfos.get(0);
final SharedLibraryInfo dynamicLib0 = scanResult.mDynamicSharedLibraryInfos.get(0);
assertThat(dynamicLib0.getPackageName(), is("dynamic.lib.pkg"));
assertThat(dynamicLib0.getName(), is("liba"));
assertThat(dynamicLib0.getLongVersion(), is((long) VERSION_UNDEFINED));
@@ -295,7 +295,7 @@ public class ScanTests {
assertThat(dynamicLib0.getDependencies(), nullValue());
assertThat(dynamicLib0.getDependentPackages(), empty());
final SharedLibraryInfo dynamicLib1 = scanResult.dynamicSharedLibraryInfos.get(1);
final SharedLibraryInfo dynamicLib1 = scanResult.mDynamicSharedLibraryInfos.get(1);
assertThat(dynamicLib1.getPackageName(), is("dynamic.lib.pkg"));
assertThat(dynamicLib1.getName(), is("libb"));
assertThat(dynamicLib1.getLongVersion(), is((long) VERSION_UNDEFINED));
@@ -321,10 +321,10 @@ public class ScanTests {
.hideAsParsed());
final PackageManagerService.ScanResult scanResult = executeScan(
final ScanResult scanResult = executeScan(
new ScanRequestBuilder(basicPackage).setPkgSetting(pkgSetting).build());
assertThat(scanResult.pkgSetting.volumeUuid, is(UUID_TWO.toString()));
assertThat(scanResult.mPkgSetting.volumeUuid, is(UUID_TWO.toString()));
}
@Test
@@ -337,7 +337,7 @@ public class ScanTests {
.hideAsParsed());
final PackageManagerService.ScanResult scanResult = executeScan(new ScanRequestBuilder(
final ScanResult scanResult = executeScan(new ScanRequestBuilder(
basicPackage)
.setPkgSetting(pkgSetting)
.addScanFlag(SCAN_FIRST_BOOT_OR_UPGRADE)
@@ -356,12 +356,12 @@ public class ScanTests {
.hideAsParsed();
final PackageManagerService.ScanResult result =
final ScanResult result =
executeScan(new ScanRequestBuilder(basicPackage)
.setOriginalPkgSetting(originalPkgSetting)
.build());
assertThat(result.request.parsedPackage.getPackageName(), is("original.package"));
assertThat(result.mRequest.mParsedPackage.getPackageName(), is("original.package"));
}
@Test
@@ -373,14 +373,14 @@ public class ScanTests {
.setInstantAppUserState(0, true)
.build();
final PackageManagerService.ScanRequest scanRequest =
final ScanRequest scanRequest =
createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
.setPkgSetting(existingPkgSetting)
.addScanFlag(SCAN_AS_FULL_APP)
.build();
final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
final ScanResult scanResult = executeScan(scanRequest);
assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
}
@@ -394,14 +394,14 @@ public class ScanTests {
.setInstantAppUserState(0, false)
.build();
final PackageManagerService.ScanRequest scanRequest =
final ScanRequest scanRequest =
createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
.setPkgSetting(existingPkgSetting)
.addScanFlag(SCAN_AS_INSTANT_APP)
.build();
final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
final ScanResult scanResult = executeScan(scanRequest);
assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, true /*isInstant*/);
}
@@ -413,17 +413,17 @@ public class ScanTests {
.setPkgFlags(ApplicationInfo.FLAG_SYSTEM)
.build();
final PackageManagerService.ScanRequest scanRequest =
final ScanRequest scanRequest =
createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
.setPkgSetting(existingPkgSetting)
.setDisabledPkgSetting(existingPkgSetting)
.addScanFlag(SCAN_NEW_INSTALL)
.build();
final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
final ScanResult scanResult = executeScan(scanRequest);
int appInfoFlags = PackageInfoUtils.appInfoFlags(scanResult.request.parsedPackage,
scanResult.pkgSetting);
int appInfoFlags = PackageInfoUtils.appInfoFlags(scanResult.mRequest.mParsedPackage,
scanResult.mPkgSetting);
assertThat(appInfoFlags, hasFlag(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP));
}
@@ -432,14 +432,14 @@ public class ScanTests {
final ParsingPackage basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
.addUsesPermission(new ParsedUsesPermission(Manifest.permission.FACTORY_TEST, 0));
final PackageManagerService.ScanResult scanResult = PackageManagerService.scanPackageOnlyLI(
final ScanResult scanResult = PackageManagerService.scanPackageOnlyLI(
createBasicScanRequestBuilder(basicPackage).build(),
mMockInjector,
true /*isUnderFactoryTest*/,
System.currentTimeMillis());
int appInfoFlags = PackageInfoUtils.appInfoFlags(scanResult.request.parsedPackage,
scanResult.request.pkgSetting);
int appInfoFlags = PackageInfoUtils.appInfoFlags(scanResult.mRequest.mParsedPackage,
scanResult.mRequest.mPkgSetting);
assertThat(appInfoFlags, hasFlag(ApplicationInfo.FLAG_FACTORY_TEST));
}
@@ -449,13 +449,13 @@ public class ScanTests {
.hideAsParsed())
.setSystem(true);
final PackageManagerService.ScanRequest scanRequest =
final ScanRequest scanRequest =
createBasicScanRequestBuilder(pkg)
.build();
final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
final ScanResult scanResult = executeScan(scanRequest);
assertThat(scanResult.pkgSetting.installSource.isOrphaned, is(true));
assertThat(scanResult.mPkgSetting.installSource.isOrphaned, is(true));
}
private static Matcher<Integer> hasFlag(final int flag) {
@@ -478,9 +478,9 @@ public class ScanTests {
};
}
private PackageManagerService.ScanResult executeScan(
PackageManagerService.ScanRequest scanRequest) throws PackageManagerException {
PackageManagerService.ScanResult result = PackageManagerService.scanPackageOnlyLI(
private ScanResult executeScan(
ScanRequest scanRequest) throws PackageManagerException {
ScanResult result = PackageManagerService.scanPackageOnlyLI(
scanRequest,
mMockInjector,
false /*isUnderFactoryTest*/,
@@ -488,7 +488,7 @@ public class ScanTests {
// Need to call hideAsFinal to cache derived fields. This is normally done in PMS, but not
// in this cut down flow used for the test.
((ParsedPackage) result.pkgSetting.pkg).hideAsFinal();
((ParsedPackage) result.mPkgSetting.pkg).hideAsFinal();
return result;
}
@@ -529,10 +529,10 @@ public class ScanTests {
}
private static void assertBasicPackageScanResult(
PackageManagerService.ScanResult scanResult, String packageName, boolean isInstant) {
assertThat(scanResult.success, is(true));
ScanResult scanResult, String packageName, boolean isInstant) {
assertThat(scanResult.mSuccess, is(true));
final PackageSetting pkgSetting = scanResult.pkgSetting;
final PackageSetting pkgSetting = scanResult.mPkgSetting;
assertBasicPackageSetting(scanResult, packageName, isInstant, pkgSetting);
final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo(
@@ -540,35 +540,35 @@ public class ScanTests {
assertBasicApplicationInfo(scanResult, applicationInfo);
}
private static void assertBasicPackageSetting(PackageManagerService.ScanResult scanResult,
private static void assertBasicPackageSetting(ScanResult scanResult,
String packageName, boolean isInstant, PackageSetting pkgSetting) {
assertThat(pkgSetting.pkg.getPackageName(), is(packageName));
assertThat(pkgSetting.getInstantApp(0), is(isInstant));
assertThat(pkgSetting.usesStaticLibraries,
arrayContaining("some.static.library", "some.other.static.library"));
assertThat(pkgSetting.usesStaticLibrariesVersions, is(new long[]{234L, 456L}));
assertThat(pkgSetting.pkg, is(scanResult.request.parsedPackage));
assertThat(pkgSetting.pkg, is(scanResult.mRequest.mParsedPackage));
assertThat(pkgSetting.getPath(), is(new File(createCodePath(packageName))));
assertThat(pkgSetting.versionCode, is(PackageInfo.composeLongVersionCode(1, 2345)));
}
private static void assertBasicApplicationInfo(PackageManagerService.ScanResult scanResult,
private static void assertBasicApplicationInfo(ScanResult scanResult,
ApplicationInfo applicationInfo) {
assertThat(applicationInfo.processName,
is(scanResult.request.parsedPackage.getPackageName()));
is(scanResult.mRequest.mParsedPackage.getPackageName()));
final int uid = applicationInfo.uid;
assertThat(UserHandle.getUserId(uid), is(UserHandle.USER_SYSTEM));
final String calculatedCredentialId = Environment.getDataUserCePackageDirectory(
applicationInfo.volumeUuid, UserHandle.USER_SYSTEM,
scanResult.request.parsedPackage.getPackageName()).getAbsolutePath();
scanResult.mRequest.mParsedPackage.getPackageName()).getAbsolutePath();
assertThat(applicationInfo.credentialProtectedDataDir, is(calculatedCredentialId));
assertThat(applicationInfo.dataDir, is(applicationInfo.credentialProtectedDataDir));
}
private static void assertAbiAndPathssDerived(PackageManagerService.ScanResult scanResult) {
PackageSetting pkgSetting = scanResult.pkgSetting;
private static void assertAbiAndPathssDerived(ScanResult scanResult) {
PackageSetting pkgSetting = scanResult.mPkgSetting;
final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo(
pkgSetting.pkg, 0, pkgSetting.readUserState(0), 0, pkgSetting);
assertThat(applicationInfo.primaryCpuAbi, is("derivedPrimary"));
@@ -581,8 +581,8 @@ public class ScanTests {
assertThat(applicationInfo.secondaryNativeLibraryDir, is("derivedNativeDir2"));
}
private static void assertPathsNotDerived(PackageManagerService.ScanResult scanResult) {
PackageSetting pkgSetting = scanResult.pkgSetting;
private static void assertPathsNotDerived(ScanResult scanResult) {
PackageSetting pkgSetting = scanResult.mPkgSetting;
final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo(
pkgSetting.pkg, 0, pkgSetting.readUserState(0), 0, pkgSetting);
assertThat(applicationInfo.nativeLibraryRootDir, is("getRootDir"));