From 296502a3c347db1d37d5071b8d22816f09632a37 Mon Sep 17 00:00:00 2001 From: Songchun Fan Date: Mon, 26 Jul 2021 13:38:47 -0700 Subject: [PATCH] [pm] extract InstallParams from PackageManagerService class Extract InstallParams and related logic from PackageManagerService. This is not a structural refactor, but just re-organizing code into separate files. This aligns with the goal to separate installation logic out from PackageManagerService. Due to shared code paths between addForInit and regular installation, there are still methods that are in PackageManagerService that are called by InstallParams. The next step is to address those methods. Once we can clearly see which codes require PackageManagerService locks, we can encapsulate those into new PackageManagerInternal interfaces. + also removed some unused code BYPASS_INCLUSIVE_LANGUAGE_REASON=need to change some public APIs first BUG: 194319951 Test: builds and presubmit Change-Id: Ibf5a914f463b784857a3ca6774b2a7709c93ebd4 --- .../com/android/server/pm/CommitRequest.java | 35 + .../server/pm/DeletePackageAction.java | 36 + .../android/server/pm/FileInstallArgs.java | 263 + .../com/android/server/pm/HandlerParams.java | 57 + .../pm/IncrementalProgressListener.java | 43 + .../server/pm/IncrementalStatesCallback.java | 46 + .../com/android/server/pm/InstallArgs.java | 149 + .../com/android/server/pm/InstallParams.java | 2159 ++++++++ .../com/android/server/pm/InstallRequest.java | 27 + .../java/com/android/server/pm/MoveInfo.java | 41 + .../android/server/pm/MoveInstallArgs.java | 133 + .../com/android/server/pm/OriginInfo.java | 68 + .../com/android/server/pm/PackageFreezer.java | 91 + .../server/pm/PackageInstalledInfo.java | 81 + .../server/pm/PackageInstallerSession.java | 43 +- .../server/pm/PackageManagerService.java | 4884 ++--------------- .../android/server/pm/PackageRemovedInfo.java | 179 + .../com/android/server/pm/PackageSender.java | 39 + .../server/pm/PackageVerificationState.java | 2 - .../com/android/server/pm/PrepareFailure.java | 45 + .../com/android/server/pm/PrepareResult.java | 54 + .../android/server/pm/ReconcileFailure.java | 29 + .../android/server/pm/ReconcileRequest.java | 74 + .../android/server/pm/ReconciledPackage.java | 90 + .../com/android/server/pm/ScanRequest.java | 87 + .../com/android/server/pm/ScanResult.java | 65 + .../server/pm/SystemDeleteException.java | 25 + .../android/server/pm/VerificationInfo.java | 40 + .../android/server/pm/VerificationParams.java | 778 +++ .../server/pm/PackageManagerServiceTest.java | 27 +- .../android/server/pm/ScanRequestBuilder.java | 4 +- .../src/com/android/server/pm/ScanTests.java | 142 +- 32 files changed, 5214 insertions(+), 4622 deletions(-) create mode 100644 services/core/java/com/android/server/pm/CommitRequest.java create mode 100644 services/core/java/com/android/server/pm/DeletePackageAction.java create mode 100644 services/core/java/com/android/server/pm/FileInstallArgs.java create mode 100644 services/core/java/com/android/server/pm/HandlerParams.java create mode 100644 services/core/java/com/android/server/pm/IncrementalProgressListener.java create mode 100644 services/core/java/com/android/server/pm/IncrementalStatesCallback.java create mode 100644 services/core/java/com/android/server/pm/InstallArgs.java create mode 100644 services/core/java/com/android/server/pm/InstallParams.java create mode 100644 services/core/java/com/android/server/pm/InstallRequest.java create mode 100644 services/core/java/com/android/server/pm/MoveInfo.java create mode 100644 services/core/java/com/android/server/pm/MoveInstallArgs.java create mode 100644 services/core/java/com/android/server/pm/OriginInfo.java create mode 100644 services/core/java/com/android/server/pm/PackageFreezer.java create mode 100644 services/core/java/com/android/server/pm/PackageInstalledInfo.java create mode 100644 services/core/java/com/android/server/pm/PackageRemovedInfo.java create mode 100644 services/core/java/com/android/server/pm/PackageSender.java create mode 100644 services/core/java/com/android/server/pm/PrepareFailure.java create mode 100644 services/core/java/com/android/server/pm/PrepareResult.java create mode 100644 services/core/java/com/android/server/pm/ReconcileFailure.java create mode 100644 services/core/java/com/android/server/pm/ReconcileRequest.java create mode 100644 services/core/java/com/android/server/pm/ReconciledPackage.java create mode 100644 services/core/java/com/android/server/pm/ScanRequest.java create mode 100644 services/core/java/com/android/server/pm/ScanResult.java create mode 100644 services/core/java/com/android/server/pm/SystemDeleteException.java create mode 100644 services/core/java/com/android/server/pm/VerificationInfo.java create mode 100644 services/core/java/com/android/server/pm/VerificationParams.java diff --git a/services/core/java/com/android/server/pm/CommitRequest.java b/services/core/java/com/android/server/pm/CommitRequest.java new file mode 100644 index 0000000000000..d1a6002590f2d --- /dev/null +++ b/services/core/java/com/android/server/pm/CommitRequest.java @@ -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 mReconciledPackages; + @NonNull final int[] mAllUsers; + + CommitRequest(Map reconciledPackages, + @NonNull int[] allUsers) { + mReconciledPackages = reconciledPackages; + mAllUsers = allUsers; + } +} diff --git a/services/core/java/com/android/server/pm/DeletePackageAction.java b/services/core/java/com/android/server/pm/DeletePackageAction.java new file mode 100644 index 0000000000000..8ef6601f7684a --- /dev/null +++ b/services/core/java/com/android/server/pm/DeletePackageAction.java @@ -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; + } +} diff --git a/services/core/java/com/android/server/pm/FileInstallArgs.java b/services/core/java/com/android/server/pm/FileInstallArgs.java new file mode 100644 index 0000000000000..3e18374d3d689 --- /dev/null +++ b/services/core/java/com/android/server/pm/FileInstallArgs.java @@ -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 allCodePaths = Collections.EMPTY_LIST; + if (mCodeFile != null && mCodeFile.exists()) { + final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); + final ParseResult 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 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; + } +} diff --git a/services/core/java/com/android/server/pm/HandlerParams.java b/services/core/java/com/android/server/pm/HandlerParams.java new file mode 100644 index 0000000000000..b8c2eb87e0c5f --- /dev/null +++ b/services/core/java/com/android/server/pm/HandlerParams.java @@ -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(); +} diff --git a/services/core/java/com/android/server/pm/IncrementalProgressListener.java b/services/core/java/com/android/server/pm/IncrementalProgressListener.java new file mode 100644 index 0000000000000..bb797cb93b92c --- /dev/null +++ b/services/core/java/com/android/server/pm/IncrementalProgressListener.java @@ -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); + } + } +} diff --git a/services/core/java/com/android/server/pm/IncrementalStatesCallback.java b/services/core/java/com/android/server/pm/IncrementalStatesCallback.java new file mode 100644 index 0000000000000..478c99b2445d2 --- /dev/null +++ b/services/core/java/com/android/server/pm/IncrementalStatesCallback.java @@ -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(); + } +} diff --git a/services/core/java/com/android/server/pm/InstallArgs.java b/services/core/java/com/android/server/pm/InstallArgs.java new file mode 100644 index 0000000000000..07c712331cf1f --- /dev/null +++ b/services/core/java/com/android/server/pm/InstallArgs.java @@ -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 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 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; + } +} diff --git a/services/core/java/com/android/server/pm/InstallParams.java b/services/core/java/com/android/server/pm/InstallParams.java new file mode 100644 index 0000000000000..e87dbed9d58ac --- /dev/null +++ b/services/core/java/com/android/server/pm/InstallParams.java @@ -0,0 +1,2159 @@ +/* + * 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.COMPONENT_ENABLED_STATE_DEFAULT; +import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS; +import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_PERMISSION_GROUP; +import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE; +import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION; +import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION_GROUP; +import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; +import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR; +import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK; +import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; +import static android.content.pm.PackageManager.INSTALL_FAILED_SESSION_INVALID; +import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE; +import static android.content.pm.PackageManager.INSTALL_FAILED_TEST_ONLY; +import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE; +import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_RESTORE; +import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_SETUP; +import static android.content.pm.PackageManager.INSTALL_STAGED; +import static android.content.pm.PackageManager.INSTALL_SUCCEEDED; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN; +import static android.content.pm.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V4; +import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; +import static android.os.incremental.IncrementalManager.isIncrementalPath; +import static android.os.storage.StorageManager.FLAG_STORAGE_CE; +import static android.os.storage.StorageManager.FLAG_STORAGE_DE; +import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL; + +import static com.android.server.pm.InstructionSets.getAppDexInstructionSets; +import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL; +import static com.android.server.pm.PackageManagerService.DEBUG_INSTANT; +import static com.android.server.pm.PackageManagerService.INIT_COPY; +import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; +import static com.android.server.pm.PackageManagerService.PRECOMPILE_LAYOUTS; +import static com.android.server.pm.PackageManagerService.SCAN_AS_FULL_APP; +import static com.android.server.pm.PackageManagerService.SCAN_AS_INSTANT_APP; +import static com.android.server.pm.PackageManagerService.SCAN_AS_ODM; +import static com.android.server.pm.PackageManagerService.SCAN_AS_OEM; +import static com.android.server.pm.PackageManagerService.SCAN_AS_PRIVILEGED; +import static com.android.server.pm.PackageManagerService.SCAN_AS_PRODUCT; +import static com.android.server.pm.PackageManagerService.SCAN_AS_SYSTEM; +import static com.android.server.pm.PackageManagerService.SCAN_AS_SYSTEM_EXT; +import static com.android.server.pm.PackageManagerService.SCAN_AS_VENDOR; +import static com.android.server.pm.PackageManagerService.SCAN_AS_VIRTUAL_PRELOAD; +import static com.android.server.pm.PackageManagerService.SCAN_DONT_KILL_APP; +import static com.android.server.pm.PackageManagerService.SCAN_INITIAL; +import static com.android.server.pm.PackageManagerService.SCAN_MOVE; +import static com.android.server.pm.PackageManagerService.SCAN_NEW_INSTALL; +import static com.android.server.pm.PackageManagerService.SCAN_NO_DEX; +import static com.android.server.pm.PackageManagerService.SCAN_UPDATE_SIGNATURE; +import static com.android.server.pm.PackageManagerService.TAG; +import static com.android.server.pm.PackageManagerServiceUtils.deriveAbiOverride; +import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.ApplicationPackageManager; +import android.content.pm.DataLoaderType; +import android.content.pm.IPackageInstallObserver2; +import android.content.pm.PackageChangeEvent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageInfoLite; +import android.content.pm.PackageInstaller; +import android.content.pm.PackageManager; +import android.content.pm.PermissionGroupInfo; +import android.content.pm.PermissionInfo; +import android.content.pm.SharedLibraryInfo; +import android.content.pm.SigningDetails; +import android.content.pm.dex.DexMetadataHelper; +import android.content.pm.parsing.PackageLite; +import android.content.pm.parsing.ParsingPackageUtils; +import android.content.pm.parsing.component.ParsedPermission; +import android.content.pm.parsing.component.ParsedPermissionGroup; +import android.content.pm.parsing.result.ParseResult; +import android.content.pm.parsing.result.ParseTypeImpl; +import android.net.Uri; +import android.os.Build; +import android.os.Environment; +import android.os.Message; +import android.os.SystemProperties; +import android.os.Trace; +import android.os.UserHandle; +import android.os.incremental.IncrementalManager; +import android.os.incremental.IncrementalStorage; +import android.os.storage.StorageManager; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.EventLog; +import android.util.Pair; +import android.util.Slog; +import android.util.SparseArray; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.content.F2fsUtils; +import com.android.internal.content.PackageHelper; +import com.android.internal.security.VerityUtils; +import com.android.internal.util.ArrayUtils; +import com.android.internal.util.Preconditions; +import com.android.server.Watchdog; +import com.android.server.pm.dex.DexoptOptions; +import com.android.server.pm.parsing.PackageParser2; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.AndroidPackageUtils; +import com.android.server.pm.parsing.pkg.ParsedPackage; +import com.android.server.pm.permission.Permission; +import com.android.server.pm.permission.PermissionManagerServiceInternal; + +import libcore.io.IoUtils; + +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.DigestException; +import java.security.DigestInputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +final class InstallParams extends HandlerParams { + final OriginInfo mOriginInfo; + final MoveInfo mMoveInfo; + final IPackageInstallObserver2 mObserver; + int mInstallFlags; + @NonNull + final InstallSource mInstallSource; + final String mVolumeUuid; + int mRet; + final String mPackageAbiOverride; + final String[] mGrantedRuntimePermissions; + final List mAllowlistedRestrictedPermissions; + final int mAutoRevokePermissionsMode; + final SigningDetails mSigningDetails; + final int mInstallReason; + final int mInstallScenario; + @Nullable + MultiPackageInstallParams mParentInstallParams; + final boolean mForceQueryableOverride; + final int mDataLoaderType; + final long mRequiredInstalledVersionCode; + final PackageLite mPackageLite; + @NonNull final PackageManagerService mPm; + + InstallParams(OriginInfo originInfo, MoveInfo moveInfo, IPackageInstallObserver2 observer, + int installFlags, InstallSource installSource, String volumeUuid, + UserHandle user, String packageAbiOverride, PackageLite packageLite, + PackageManagerService pm) { + super(user); + mPm = pm; + mOriginInfo = originInfo; + mMoveInfo = moveInfo; + mObserver = observer; + mInstallFlags = installFlags; + mInstallSource = Preconditions.checkNotNull(installSource); + mVolumeUuid = volumeUuid; + mPackageAbiOverride = packageAbiOverride; + + mGrantedRuntimePermissions = null; + mAllowlistedRestrictedPermissions = null; + mAutoRevokePermissionsMode = MODE_DEFAULT; + mSigningDetails = SigningDetails.UNKNOWN; + mInstallReason = PackageManager.INSTALL_REASON_UNKNOWN; + mInstallScenario = PackageManager.INSTALL_SCENARIO_DEFAULT; + mForceQueryableOverride = false; + mDataLoaderType = DataLoaderType.NONE; + mRequiredInstalledVersionCode = PackageManager.VERSION_CODE_HIGHEST; + mPackageLite = packageLite; + } + + InstallParams(File stagedDir, IPackageInstallObserver2 observer, + PackageInstaller.SessionParams sessionParams, InstallSource installSource, + UserHandle user, SigningDetails signingDetails, int installerUid, + PackageLite packageLite, PackageManagerService pm) { + super(user); + mPm = pm; + mOriginInfo = OriginInfo.fromStagedFile(stagedDir); + mMoveInfo = null; + mInstallReason = fixUpInstallReason( + installSource.installerPackageName, installerUid, sessionParams.installReason); + mInstallScenario = sessionParams.installScenario; + mObserver = observer; + mInstallFlags = sessionParams.installFlags; + mInstallSource = installSource; + mVolumeUuid = sessionParams.volumeUuid; + mPackageAbiOverride = sessionParams.abiOverride; + mGrantedRuntimePermissions = sessionParams.grantedRuntimePermissions; + mAllowlistedRestrictedPermissions = sessionParams.whitelistedRestrictedPermissions; + mAutoRevokePermissionsMode = sessionParams.autoRevokePermissionsMode; + mSigningDetails = signingDetails; + mForceQueryableOverride = sessionParams.forceQueryableOverride; + mDataLoaderType = (sessionParams.dataLoaderParams != null) + ? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE; + mRequiredInstalledVersionCode = sessionParams.requiredInstalledVersionCode; + mPackageLite = packageLite; + } + + @Override + public String toString() { + return "InstallParams{" + Integer.toHexString(System.identityHashCode(this)) + + " file=" + mOriginInfo.mFile + "}"; + } + + private int installLocationPolicy(PackageInfoLite pkgLite) { + String packageName = pkgLite.packageName; + int installLocation = pkgLite.installLocation; + // reader + synchronized (mPm.mLock) { + // Currently installed package which the new package is attempting to replace or + // null if no such package is installed. + AndroidPackage installedPkg = mPm.mPackages.get(packageName); + + if (installedPkg != null) { + if ((mInstallFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) { + // Check for updated system application. + if (installedPkg.isSystem()) { + return PackageHelper.RECOMMEND_INSTALL_INTERNAL; + } else { + // If current upgrade specifies particular preference + if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) { + // Application explicitly specified internal. + return PackageHelper.RECOMMEND_INSTALL_INTERNAL; + } else if ( + installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) { + // App explicitly prefers external. Let policy decide + } else { + // Prefer previous location + if (installedPkg.isExternalStorage()) { + return PackageHelper.RECOMMEND_INSTALL_EXTERNAL; + } + return PackageHelper.RECOMMEND_INSTALL_INTERNAL; + } + } + } else { + // Invalid install. Return error code + return PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS; + } + } + } + return pkgLite.recommendedInstallLocation; + } + + /** + * Override install location based on default policy if needed. + * + * Only {@link #mInstallFlags} may mutate in this method. + * + * Only {@link PackageManager#INSTALL_INTERNAL} flag may mutate in + * {@link #mInstallFlags} + */ + private int overrideInstallLocation(PackageInfoLite pkgLite) { + final boolean ephemeral = (mInstallFlags & PackageManager.INSTALL_INSTANT_APP) != 0; + if (DEBUG_INSTANT && ephemeral) { + Slog.v(TAG, "pkgLite for install: " + pkgLite); + } + + if (mOriginInfo.mStaged) { + // If we're already staged, we've firmly committed to an install location + if (mOriginInfo.mFile != null) { + mInstallFlags |= PackageManager.INSTALL_INTERNAL; + } else { + throw new IllegalStateException("Invalid stage location"); + } + } else if (pkgLite.recommendedInstallLocation + == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) { + /* + * If we are not staged and have too little free space, try to free cache + * before giving up. + */ + // TODO: focus freeing disk space on the target device + final StorageManager storage = StorageManager.from(mPm.mContext); + final long lowThreshold = storage.getStorageLowBytes( + Environment.getDataDirectory()); + + final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize( + mOriginInfo.mResolvedPath, mPackageAbiOverride); + if (sizeBytes >= 0) { + try { + mPm.mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0); + pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mPm.mContext, + mPackageLite, mOriginInfo.mResolvedPath, mInstallFlags, + mPackageAbiOverride); + } catch (Installer.InstallerException e) { + Slog.w(TAG, "Failed to free cache", e); + } + } + + /* + * The cache free must have deleted the file we downloaded to install. + * + * TODO: fix the "freeCache" call to not delete the file we care about. + */ + if (pkgLite.recommendedInstallLocation + == PackageHelper.RECOMMEND_FAILED_INVALID_URI) { + pkgLite.recommendedInstallLocation = + PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE; + } + } + + int ret = INSTALL_SUCCEEDED; + int loc = pkgLite.recommendedInstallLocation; + if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) { + ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; + } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) { + ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS; + } else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) { + ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) { + ret = PackageManager.INSTALL_FAILED_INVALID_APK; + } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) { + ret = PackageManager.INSTALL_FAILED_INVALID_URI; + } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) { + ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE; + } else { + // Override with defaults if needed. + loc = installLocationPolicy(pkgLite); + + final boolean onInt = (mInstallFlags & PackageManager.INSTALL_INTERNAL) != 0; + + if (!onInt) { + // Override install location with flags + if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) { + // Set the flag to install on external media. + mInstallFlags &= ~PackageManager.INSTALL_INTERNAL; + } else { + // Make sure the flag for installing on external + // media is unset + mInstallFlags |= PackageManager.INSTALL_INTERNAL; + } + } + } + return ret; + } + + /* + * Invoke remote method to get package information and install + * location values. Override install location based on default + * policy if needed and then create install arguments based + * on the install location. + */ + public void handleStartCopy() { + if ((mInstallFlags & PackageManager.INSTALL_APEX) != 0) { + mRet = INSTALL_SUCCEEDED; + return; + } + PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mPm.mContext, + mPackageLite, mOriginInfo.mResolvedPath, mInstallFlags, mPackageAbiOverride); + + // For staged session, there is a delay between its verification and install. Device + // state can change within this delay and hence we need to re-verify certain conditions. + boolean isStaged = (mInstallFlags & INSTALL_STAGED) != 0; + if (isStaged) { + Pair ret = mPm.verifyReplacingVersionCode( + pkgLite, mRequiredInstalledVersionCode, mInstallFlags); + mRet = ret.first; + if (mRet != INSTALL_SUCCEEDED) { + return; + } + } + + mRet = overrideInstallLocation(pkgLite); + } + + @Override + void handleReturnCode() { + processPendingInstall(); + } + + private void processPendingInstall() { + InstallArgs args = createInstallArgs(this); + if (mRet == PackageManager.INSTALL_SUCCEEDED) { + mRet = args.copyApk(); + } + if (mRet == PackageManager.INSTALL_SUCCEEDED) { + F2fsUtils.releaseCompressedBlocks( + mPm.mContext.getContentResolver(), new File(args.getCodePath())); + } + if (mParentInstallParams != null) { + mParentInstallParams.tryProcessInstallRequest(args, mRet); + } else { + PackageInstalledInfo res = new PackageInstalledInfo(mRet); + processInstallRequestsAsync( + res.mReturnCode == PackageManager.INSTALL_SUCCEEDED, + Collections.singletonList(new InstallRequest(args, res))); + } + } + + private InstallArgs createInstallArgs(InstallParams params) { + if (params.mMoveInfo != null) { + return new MoveInstallArgs(params); + } else { + return new FileInstallArgs(params); + } + } + + // Queue up an async operation since the package installation may take a little while. + private void processInstallRequestsAsync(boolean success, + List installRequests) { + mPm.mHandler.post(() -> { + List apexInstallRequests = new ArrayList<>(); + List apkInstallRequests = new ArrayList<>(); + for (InstallRequest request : installRequests) { + if ((request.mArgs.mInstallFlags & PackageManager.INSTALL_APEX) != 0) { + apexInstallRequests.add(request); + } else { + apkInstallRequests.add(request); + } + } + // Note: supporting multi package install of both APEXes and APKs might requir some + // thinking to ensure atomicity of the install. + if (!apexInstallRequests.isEmpty() && !apkInstallRequests.isEmpty()) { + // This should've been caught at the validation step, but for some reason wasn't. + throw new IllegalStateException( + "Attempted to do a multi package install of both APEXes and APKs"); + } + if (!apexInstallRequests.isEmpty()) { + if (success) { + // Since installApexPackages requires talking to external service (apexd), we + // schedule to run it async. Once it finishes, it will resume the install. + Thread t = new Thread(() -> installApexPackagesTraced(apexInstallRequests), + "installApexPackages"); + t.start(); + } else { + // Non-staged APEX installation failed somewhere before + // processInstallRequestAsync. In that case just notify the observer about the + // failure. + InstallRequest request = apexInstallRequests.get(0); + mPm.notifyInstallObserver(request.mInstallResult, request.mArgs.mObserver); + } + return; + } + if (success) { + for (InstallRequest request : apkInstallRequests) { + request.mArgs.doPreInstall(request.mInstallResult.mReturnCode); + } + synchronized (mPm.mInstallLock) { + installPackagesTracedLI(apkInstallRequests); + } + for (InstallRequest request : apkInstallRequests) { + request.mArgs.doPostInstall( + request.mInstallResult.mReturnCode, request.mInstallResult.mUid); + } + } + for (InstallRequest request : apkInstallRequests) { + mPm.restoreAndPostInstall(request.mArgs.mUser.getIdentifier(), + request.mInstallResult, + new PackageManagerService.PostInstallData(request.mArgs, + request.mInstallResult, null)); + } + }); + } + + private void installApexPackagesTraced(List requests) { + try { + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installApexPackages"); + installApexPackages(requests); + } finally { + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + } + + private void installApexPackages(List requests) { + if (requests.isEmpty()) { + return; + } + if (requests.size() != 1) { + throw new IllegalStateException( + "Only a non-staged install of a single APEX is supported"); + } + InstallRequest request = requests.get(0); + try { + // Should directory scanning logic be moved to ApexManager for better test coverage? + final File dir = request.mArgs.mOriginInfo.mResolvedFile; + final File[] apexes = dir.listFiles(); + if (apexes == null) { + throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, + dir.getAbsolutePath() + " is not a directory"); + } + if (apexes.length != 1) { + throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, + "Expected exactly one .apex file under " + dir.getAbsolutePath() + + " got: " + apexes.length); + } + try (PackageParser2 packageParser = mPm.mInjector.getScanningPackageParser()) { + mPm.mApexManager.installPackage(apexes[0], packageParser); + } + } catch (PackageManagerException e) { + request.mInstallResult.setError("APEX installation failed", e); + } + PackageManagerService.invalidatePackageInfoCache(); + mPm.notifyInstallObserver(request.mInstallResult, request.mArgs.mObserver); + } + + @GuardedBy("mInstallLock") + private void installPackagesTracedLI(List requests) { + try { + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages"); + installPackagesLI(requests); + } finally { + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + } + + /** + * Installs one or more packages atomically. This operation is broken up into four phases: + *
    + *
  • Prepare + *
    Analyzes any current install state, parses the package and does initial + * validation on it.
  • + *
  • Scan + *
    Interrogates the parsed packages given the context collected in prepare.
  • + *
  • Reconcile + *
    Validates scanned packages in the context of each other and the current system + * state to ensure that the install will be successful. + *
  • Commit + *
    Commits all scanned packages and updates system state. This is the only place + * that system state may be modified in the install flow and all predictable errors + * must be determined before this phase.
  • + *
+ * + * Failure at any phase will result in a full failure to install all packages. + */ + @GuardedBy("mInstallLock") + private void installPackagesLI(List requests) { + final Map preparedScans = new ArrayMap<>(requests.size()); + final Map installArgs = new ArrayMap<>(requests.size()); + final Map installResults = new ArrayMap<>(requests.size()); + final Map prepareResults = new ArrayMap<>(requests.size()); + final Map versionInfos = new ArrayMap<>(requests.size()); + final Map lastStaticSharedLibSettings = + new ArrayMap<>(requests.size()); + final Map createdAppId = new ArrayMap<>(requests.size()); + boolean success = false; + try { + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI"); + for (InstallRequest request : requests) { + // TODO(b/109941548): remove this once we've pulled everything from it and into + // scan, reconcile or commit. + final PrepareResult prepareResult; + try { + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage"); + prepareResult = + preparePackageLI(request.mArgs, request.mInstallResult); + } catch (PrepareFailure prepareFailure) { + request.mInstallResult.setError(prepareFailure.error, + prepareFailure.getMessage()); + request.mInstallResult.mOrigPackage = prepareFailure.mConflictingPackage; + request.mInstallResult.mOrigPermission = prepareFailure.mConflictingPermission; + return; + } finally { + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + request.mInstallResult.setReturnCode(PackageManager.INSTALL_SUCCEEDED); + request.mInstallResult.mInstallerPackageName = + request.mArgs.mInstallSource.installerPackageName; + + final String packageName = prepareResult.mPackageToScan.getPackageName(); + prepareResults.put(packageName, prepareResult); + installResults.put(packageName, request.mInstallResult); + installArgs.put(packageName, request.mArgs); + try { + final ScanResult result = mPm.scanPackageTracedLI( + prepareResult.mPackageToScan, prepareResult.mParseFlags, + prepareResult.mScanFlags, System.currentTimeMillis(), + request.mArgs.mUser, request.mArgs.mAbiOverride); + if (null != preparedScans.put(result.mPkgSetting.pkg.getPackageName(), + result)) { + request.mInstallResult.setError( + PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE, + "Duplicate package " + result.mPkgSetting.pkg.getPackageName() + + " in multi-package install request."); + return; + } + createdAppId.put(packageName, mPm.optimisticallyRegisterAppId(result)); + versionInfos.put(result.mPkgSetting.pkg.getPackageName(), + mPm.getSettingsVersionForPackage(result.mPkgSetting.pkg)); + if (result.mStaticSharedLibraryInfo != null) { + final PackageSetting sharedLibLatestVersionSetting = + mPm.getSharedLibLatestVersionSetting(result); + if (sharedLibLatestVersionSetting != null) { + lastStaticSharedLibSettings.put(result.mPkgSetting.pkg.getPackageName(), + sharedLibLatestVersionSetting); + } + } + } catch (PackageManagerException e) { + request.mInstallResult.setError("Scanning Failed.", e); + return; + } + } + ReconcileRequest + reconcileRequest = new ReconcileRequest(preparedScans, installArgs, + installResults, + prepareResults, + mPm.mSharedLibraries, + Collections.unmodifiableMap(mPm.mPackages), versionInfos, + lastStaticSharedLibSettings); + CommitRequest commitRequest = null; + synchronized (mPm.mLock) { + Map reconciledPackages; + try { + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages"); + reconciledPackages = PackageManagerService.reconcilePackagesLocked( + reconcileRequest, mPm.mSettings.getKeySetManagerService(), + mPm.mInjector); + } catch (ReconcileFailure e) { + for (InstallRequest request : requests) { + request.mInstallResult.setError("Reconciliation failed...", e); + } + return; + } finally { + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + try { + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages"); + commitRequest = new CommitRequest(reconciledPackages, + mPm.mUserManager.getUserIds()); + commitPackagesLocked(commitRequest); + success = true; + } finally { + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + } + executePostCommitSteps(commitRequest); + } finally { + if (success) { + for (InstallRequest request : requests) { + final InstallArgs args = request.mArgs; + if (args.mDataLoaderType != DataLoaderType.INCREMENTAL) { + continue; + } + if (args.mSigningDetails.getSignatureSchemeVersion() != SIGNING_BLOCK_V4) { + continue; + } + // For incremental installs, we bypass the verifier prior to install. Now + // that we know the package is valid, send a notice to the verifier with + // the root hash of the base.apk. + final String baseCodePath = request.mInstallResult.mPkg.getBaseApkPath(); + final String[] splitCodePaths = request.mInstallResult.mPkg.getSplitCodePaths(); + final Uri originUri = Uri.fromFile(args.mOriginInfo.mResolvedFile); + final int verificationId = mPm.mPendingVerificationToken++; + final String rootHashString = PackageManagerServiceUtils + .buildVerificationRootHashString(baseCodePath, splitCodePaths); + mPm.broadcastPackageVerified(verificationId, originUri, + PackageManager.VERIFICATION_ALLOW, rootHashString, + args.mDataLoaderType, args.getUser()); + } + } else { + for (ScanResult result : preparedScans.values()) { + if (createdAppId.getOrDefault(result.mRequest.mParsedPackage.getPackageName(), + false)) { + mPm.cleanUpAppIdCreation(result); + } + } + // TODO(b/194319951): create a more descriptive reason than unknown + // mark all non-failure installs as UNKNOWN so we do not treat them as success + for (InstallRequest request : requests) { + if (request.mInstallResult.mFreezer != null) { + request.mInstallResult.mFreezer.close(); + } + if (request.mInstallResult.mReturnCode == PackageManager.INSTALL_SUCCEEDED) { + request.mInstallResult.mReturnCode = PackageManager.INSTALL_UNKNOWN; + } + } + } + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + } + + @GuardedBy("mInstallLock") + private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res) + throws PrepareFailure { + final int installFlags = args.mInstallFlags; + final File tmpPackageFile = new File(args.getCodePath()); + final boolean onExternal = args.mVolumeUuid != null; + final boolean instantApp = ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0); + final boolean fullApp = ((installFlags & PackageManager.INSTALL_FULL_APP) != 0); + final boolean virtualPreload = + ((installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0); + final boolean isRollback = args.mInstallReason == PackageManager.INSTALL_REASON_ROLLBACK; + @PackageManagerService.ScanFlags int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE; + if (args.mMoveInfo != null) { + // moving a complete application; perform an initial scan on the new install location + scanFlags |= SCAN_INITIAL; + } + if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) { + scanFlags |= SCAN_DONT_KILL_APP; + } + if (instantApp) { + scanFlags |= SCAN_AS_INSTANT_APP; + } + if (fullApp) { + scanFlags |= SCAN_AS_FULL_APP; + } + if (virtualPreload) { + scanFlags |= SCAN_AS_VIRTUAL_PRELOAD; + } + + if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile); + + // Validity check + if (instantApp && onExternal) { + Slog.i(TAG, "Incompatible ephemeral install; external=" + onExternal); + throw new PrepareFailure(PackageManager.INSTALL_FAILED_SESSION_INVALID); + } + + // Retrieve PackageSettings and parse package + @ParsingPackageUtils.ParseFlags final int parseFlags = + mPm.mDefParseFlags | ParsingPackageUtils.PARSE_CHATTY + | ParsingPackageUtils.PARSE_ENFORCE_CODE + | (onExternal ? ParsingPackageUtils.PARSE_EXTERNAL_STORAGE : 0); + + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage"); + final ParsedPackage parsedPackage; + try (PackageParser2 pp = mPm.mInjector.getPreparingPackageParser()) { + parsedPackage = pp.parsePackage(tmpPackageFile, parseFlags, false); + AndroidPackageUtils.validatePackageDexMetadata(parsedPackage); + } catch (PackageManagerException e) { + throw new PrepareFailure("Failed parse during installPackageLI", e); + } finally { + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + + // Instant apps have several additional install-time checks. + if (instantApp) { + if (parsedPackage.getTargetSdkVersion() < Build.VERSION_CODES.O) { + Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName() + + " does not target at least O"); + throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID, + "Instant app package must target at least O"); + } + if (parsedPackage.getSharedUserId() != null) { + Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName() + + " may not declare sharedUserId."); + throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID, + "Instant app package may not declare a sharedUserId"); + } + } + + if (parsedPackage.isStaticSharedLibrary()) { + // Static shared libraries have synthetic package names + PackageManagerService.renameStaticSharedLibraryPackage(parsedPackage); + + // No static shared libs on external storage + if (onExternal) { + Slog.i(TAG, "Static shared libs can only be installed on internal storage."); + throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION, + "Packages declaring static-shared libs cannot be updated"); + } + } + + String pkgName = res.mName = parsedPackage.getPackageName(); + if (parsedPackage.isTestOnly()) { + if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) { + throw new PrepareFailure(INSTALL_FAILED_TEST_ONLY, "installPackageLI"); + } + } + + // either use what we've been given or parse directly from the APK + if (args.mSigningDetails != SigningDetails.UNKNOWN) { + parsedPackage.setSigningDetails(args.mSigningDetails); + } else { + final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); + final ParseResult result = ParsingPackageUtils.getSigningDetails( + input, parsedPackage, false /*skipVerify*/); + if (result.isError()) { + throw new PrepareFailure("Failed collect during installPackageLI", + result.getException()); + } + parsedPackage.setSigningDetails(result.getResult()); + } + + if (instantApp && parsedPackage.getSigningDetails().getSignatureSchemeVersion() + < SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2) { + Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName() + + " is not signed with at least APK Signature Scheme v2"); + throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID, + "Instant app package must be signed with APK Signature Scheme v2 or greater"); + } + + boolean systemApp = false; + boolean replace = false; + synchronized (mPm.mLock) { + // Check if installing already existing package + if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) { + String oldName = mPm.mSettings.getRenamedPackageLPr(pkgName); + if (parsedPackage.getOriginalPackages().contains(oldName) + && mPm.mPackages.containsKey(oldName)) { + // This package is derived from an original package, + // and this device has been updating from that original + // name. We must continue using the original name, so + // rename the new package here. + parsedPackage.setPackageName(oldName); + pkgName = parsedPackage.getPackageName(); + replace = true; + if (DEBUG_INSTALL) { + Slog.d(TAG, "Replacing existing renamed package: oldName=" + + oldName + " pkgName=" + pkgName); + } + } else if (mPm.mPackages.containsKey(pkgName)) { + // This package, under its official name, already exists + // on the device; we should replace it. + replace = true; + if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing package: " + pkgName); + } + + if (replace) { + // Prevent apps opting out from runtime permissions + AndroidPackage oldPackage = mPm.mPackages.get(pkgName); + final int oldTargetSdk = oldPackage.getTargetSdkVersion(); + final int newTargetSdk = parsedPackage.getTargetSdkVersion(); + if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1 + && newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) { + throw new PrepareFailure( + PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE, + "Package " + parsedPackage.getPackageName() + + " new target SDK " + newTargetSdk + + " doesn't support runtime permissions but the old" + + " target SDK " + oldTargetSdk + " does."); + } + // Prevent persistent apps from being updated + if (oldPackage.isPersistent() + && ((installFlags & PackageManager.INSTALL_STAGED) == 0)) { + throw new PrepareFailure(PackageManager.INSTALL_FAILED_INVALID_APK, + "Package " + oldPackage.getPackageName() + " is a persistent app. " + + "Persistent apps are not updateable."); + } + } + } + + PackageSetting ps = mPm.mSettings.getPackageLPr(pkgName); + if (ps != null) { + if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps); + + // Static shared libs have same package with different versions where + // we internally use a synthetic package name to allow multiple versions + // of the same package, therefore we need to compare signatures against + // the package setting for the latest library version. + PackageSetting signatureCheckPs = ps; + if (parsedPackage.isStaticSharedLibrary()) { + SharedLibraryInfo libraryInfo = mPm.getLatestSharedLibraVersionLPr( + parsedPackage); + if (libraryInfo != null) { + signatureCheckPs = mPm.mSettings.getPackageLPr( + libraryInfo.getPackageName()); + } + } + + // Quick validity check that we're signed correctly if updating; + // we'll check this again later when scanning, but we want to + // bail early here before tripping over redefined permissions. + final KeySetManagerService ksms = mPm.mSettings.getKeySetManagerService(); + if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) { + if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, parsedPackage)) { + throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package " + + parsedPackage.getPackageName() + " upgrade keys do not match the " + + "previously installed version"); + } + } else { + try { + final boolean compareCompat = mPm.isCompatSignatureUpdateNeeded( + parsedPackage); + final boolean compareRecover = mPm.isRecoverSignatureUpdateNeeded( + parsedPackage); + // We don't care about disabledPkgSetting on install for now. + final boolean compatMatch = verifySignatures(signatureCheckPs, null, + parsedPackage.getSigningDetails(), compareCompat, compareRecover, + isRollback); + // The new KeySets will be re-added later in the scanning process. + if (compatMatch) { + synchronized (mPm.mLock) { + ksms.removeAppKeySetDataLPw(parsedPackage.getPackageName()); + } + } + } catch (PackageManagerException e) { + throw new PrepareFailure(e.error, e.getMessage()); + } + } + + if (ps.pkg != null) { + systemApp = ps.pkg.isSystem(); + } + res.mOrigUsers = ps.queryInstalledUsers(mPm.mUserManager.getUserIds(), true); + } + + final int numGroups = ArrayUtils.size(parsedPackage.getPermissionGroups()); + for (int groupNum = 0; groupNum < numGroups; groupNum++) { + final ParsedPermissionGroup group = + parsedPackage.getPermissionGroups().get(groupNum); + final PermissionGroupInfo sourceGroup = mPm.getPermissionGroupInfo(group.getName(), + 0); + + if (sourceGroup != null && cannotInstallWithBadPermissionGroups(parsedPackage)) { + final String sourcePackageName = sourceGroup.packageName; + + if ((replace || !parsedPackage.getPackageName().equals(sourcePackageName)) + && !doesSignatureMatchForPermissions(sourcePackageName, parsedPackage, + scanFlags)) { + EventLog.writeEvent(0x534e4554, "146211400", -1, + parsedPackage.getPackageName()); + + throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PERMISSION_GROUP, + "Package " + + parsedPackage.getPackageName() + + " attempting to redeclare permission group " + + group.getName() + " already owned by " + + sourcePackageName); + } + } + } + + // TODO: Move logic for checking permission compatibility into PermissionManagerService + final int n = ArrayUtils.size(parsedPackage.getPermissions()); + for (int i = n - 1; i >= 0; i--) { + final ParsedPermission perm = parsedPackage.getPermissions().get(i); + final Permission bp = mPm.mPermissionManager.getPermissionTEMP(perm.getName()); + + // Don't allow anyone but the system to define ephemeral permissions. + if ((perm.getProtectionLevel() & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0 + && !systemApp) { + Slog.w(TAG, "Non-System package " + parsedPackage.getPackageName() + + " attempting to delcare ephemeral permission " + + perm.getName() + "; Removing ephemeral."); + perm.setProtectionLevel( + perm.getProtectionLevel() & ~PermissionInfo.PROTECTION_FLAG_INSTANT); + } + + // Check whether the newly-scanned package wants to define an already-defined perm + if (bp != null) { + final String sourcePackageName = bp.getPackageName(); + + if (!doesSignatureMatchForPermissions(sourcePackageName, parsedPackage, + scanFlags)) { + // If the owning package is the system itself, we log but allow + // install to proceed; we fail the install on all other permission + // redefinitions. + if (!sourcePackageName.equals("android")) { + throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PERMISSION, + "Package " + + parsedPackage.getPackageName() + + " attempting to redeclare permission " + + perm.getName() + " already owned by " + + sourcePackageName) + .conflictsWithExistingPermission(perm.getName(), + sourcePackageName); + } else { + Slog.w(TAG, "Package " + parsedPackage.getPackageName() + + " attempting to redeclare system permission " + + perm.getName() + "; ignoring new declaration"); + parsedPackage.removePermission(i); + } + } else if (!PLATFORM_PACKAGE_NAME.equals(parsedPackage.getPackageName())) { + // Prevent apps to change protection level to dangerous from any other + // type as this would allow a privilege escalation where an app adds a + // normal/signature permission in other app's group and later redefines + // it as dangerous leading to the group auto-grant. + if ((perm.getProtectionLevel() & PermissionInfo.PROTECTION_MASK_BASE) + == PermissionInfo.PROTECTION_DANGEROUS) { + if (bp != null && !bp.isRuntime()) { + Slog.w(TAG, "Package " + parsedPackage.getPackageName() + + " trying to change a non-runtime permission " + + perm.getName() + + " to runtime; keeping old protection level"); + perm.setProtectionLevel(bp.getProtectionLevel()); + } + } + } + } + + if (perm.getGroup() != null + && cannotInstallWithBadPermissionGroups(parsedPackage)) { + boolean isPermGroupDefinedByPackage = false; + for (int groupNum = 0; groupNum < numGroups; groupNum++) { + if (parsedPackage.getPermissionGroups().get(groupNum).getName() + .equals(perm.getGroup())) { + isPermGroupDefinedByPackage = true; + break; + } + } + + if (!isPermGroupDefinedByPackage) { + final PermissionGroupInfo sourceGroup = + mPm.getPermissionGroupInfo(perm.getGroup(), 0); + + if (sourceGroup == null) { + EventLog.writeEvent(0x534e4554, "146211400", -1, + parsedPackage.getPackageName()); + + throw new PrepareFailure(INSTALL_FAILED_BAD_PERMISSION_GROUP, + "Package " + + parsedPackage.getPackageName() + + " attempting to declare permission " + + perm.getName() + " in non-existing group " + + perm.getGroup()); + } else { + String groupSourcePackageName = sourceGroup.packageName; + + if (!PLATFORM_PACKAGE_NAME.equals(groupSourcePackageName) + && !doesSignatureMatchForPermissions(groupSourcePackageName, + parsedPackage, scanFlags)) { + EventLog.writeEvent(0x534e4554, "146211400", -1, + parsedPackage.getPackageName()); + + throw new PrepareFailure(INSTALL_FAILED_BAD_PERMISSION_GROUP, + "Package " + + parsedPackage.getPackageName() + + " attempting to declare permission " + + perm.getName() + " in group " + + perm.getGroup() + " owned by package " + + groupSourcePackageName + + " with incompatible certificate"); + } + } + } + } + } + } + + if (systemApp) { + if (onExternal) { + // Abort update; system app can't be replaced with app on sdcard + throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION, + "Cannot install updates to system apps on sdcard"); + } else if (instantApp) { + // Abort update; system app can't be replaced with an instant app + throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID, + "Cannot update a system app with an instant app"); + } + } + + if (args.mMoveInfo != null) { + // We did an in-place move, so dex is ready to roll + scanFlags |= SCAN_NO_DEX; + scanFlags |= SCAN_MOVE; + + synchronized (mPm.mLock) { + final PackageSetting ps = mPm.mSettings.getPackageLPr(pkgName); + if (ps == null) { + res.setError(INSTALL_FAILED_INTERNAL_ERROR, + "Missing settings for moved package " + pkgName); + } + + // We moved the entire application as-is, so bring over the + // previously derived ABI information. + parsedPackage.setPrimaryCpuAbi(ps.primaryCpuAbiString) + .setSecondaryCpuAbi(ps.secondaryCpuAbiString); + } + + } else { + // Enable SCAN_NO_DEX flag to skip dexopt at a later stage + scanFlags |= SCAN_NO_DEX; + + try { + PackageSetting pkgSetting; + synchronized (mPm.mLock) { + pkgSetting = mPm.mSettings.getPackageLPr(pkgName); + } + boolean isUpdatedSystemAppFromExistingSetting = pkgSetting != null + && pkgSetting.getPkgState().isUpdatedSystemApp(); + final String abiOverride = deriveAbiOverride(args.mAbiOverride); + AndroidPackage oldPackage = mPm.mPackages.get(pkgName); + boolean isUpdatedSystemAppInferred = oldPackage != null && oldPackage.isSystem(); + final Pair + derivedAbi = mPm.mInjector.getAbiHelper().derivePackageAbi(parsedPackage, + isUpdatedSystemAppFromExistingSetting || isUpdatedSystemAppInferred, + abiOverride, mPm.mAppLib32InstallDir); + derivedAbi.first.applyTo(parsedPackage); + derivedAbi.second.applyTo(parsedPackage); + } catch (PackageManagerException pme) { + Slog.e(TAG, "Error deriving application ABI", pme); + throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR, + "Error deriving application ABI: " + pme.getMessage()); + } + } + + if (!args.doRename(res.mReturnCode, parsedPackage)) { + throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename"); + } + + try { + setUpFsVerityIfPossible(parsedPackage); + } catch (Installer.InstallerException | IOException | DigestException + | NoSuchAlgorithmException e) { + throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR, + "Failed to set up verity: " + e); + } + + final PackageFreezer freezer = + freezePackageForInstall(pkgName, installFlags, "installPackageLI"); + boolean shouldCloseFreezerBeforeReturn = true; + try { + final AndroidPackage existingPackage; + String renamedPackage = null; + boolean sysPkg = false; + int targetScanFlags = scanFlags; + int targetParseFlags = parseFlags; + final PackageSetting ps; + final PackageSetting disabledPs; + if (replace) { + if (parsedPackage.isStaticSharedLibrary()) { + // Static libs have a synthetic package name containing the version + // and cannot be updated as an update would get a new package name, + // unless this is installed from adb which is useful for development. + AndroidPackage existingPkg = mPm.mPackages.get(parsedPackage.getPackageName()); + if (existingPkg != null + && (installFlags & PackageManager.INSTALL_FROM_ADB) == 0) { + throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PACKAGE, + "Packages declaring " + + "static-shared libs cannot be updated"); + } + } + + final boolean isInstantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0; + + final AndroidPackage oldPackage; + final String pkgName11 = parsedPackage.getPackageName(); + final int[] allUsers; + final int[] installedUsers; + final int[] uninstalledUsers; + + synchronized (mPm.mLock) { + oldPackage = mPm.mPackages.get(pkgName11); + existingPackage = oldPackage; + if (DEBUG_INSTALL) { + Slog.d(TAG, + "replacePackageLI: new=" + parsedPackage + ", old=" + oldPackage); + } + + ps = mPm.mSettings.getPackageLPr(pkgName11); + disabledPs = mPm.mSettings.getDisabledSystemPkgLPr(ps); + + // verify signatures are valid + final KeySetManagerService ksms = mPm.mSettings.getKeySetManagerService(); + if (ksms.shouldCheckUpgradeKeySetLocked(ps, scanFlags)) { + if (!ksms.checkUpgradeKeySetLocked(ps, parsedPackage)) { + throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, + "New package not signed by keys specified by upgrade-keysets: " + + pkgName11); + } + } else { + SigningDetails parsedPkgSigningDetails = parsedPackage.getSigningDetails(); + SigningDetails oldPkgSigningDetails = oldPackage.getSigningDetails(); + // default to original signature matching + if (!parsedPkgSigningDetails.checkCapability(oldPkgSigningDetails, + SigningDetails.CertCapabilities.INSTALLED_DATA) + && !oldPkgSigningDetails.checkCapability(parsedPkgSigningDetails, + SigningDetails.CertCapabilities.ROLLBACK)) { + // Allow the update to proceed if this is a rollback and the parsed + // package's current signing key is the current signer or in the lineage + // of the old package; this allows a rollback to a previously installed + // version after an app's signing key has been rotated without requiring + // the rollback capability on the previous signing key. + if (!isRollback || !oldPkgSigningDetails.hasAncestorOrSelf( + parsedPkgSigningDetails)) { + throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, + "New package has a different signature: " + pkgName11); + } + } + } + + // don't allow a system upgrade unless the upgrade hash matches + if (oldPackage.getRestrictUpdateHash() != null && oldPackage.isSystem()) { + final byte[] digestBytes; + try { + final MessageDigest digest = MessageDigest.getInstance("SHA-512"); + updateDigest(digest, new File(parsedPackage.getBaseApkPath())); + if (!ArrayUtils.isEmpty(parsedPackage.getSplitCodePaths())) { + for (String path : parsedPackage.getSplitCodePaths()) { + updateDigest(digest, new File(path)); + } + } + digestBytes = digest.digest(); + } catch (NoSuchAlgorithmException | IOException e) { + throw new PrepareFailure(INSTALL_FAILED_INVALID_APK, + "Could not compute hash: " + pkgName11); + } + if (!Arrays.equals(oldPackage.getRestrictUpdateHash(), digestBytes)) { + throw new PrepareFailure(INSTALL_FAILED_INVALID_APK, + "New package fails restrict-update check: " + pkgName11); + } + // retain upgrade restriction + parsedPackage.setRestrictUpdateHash(oldPackage.getRestrictUpdateHash()); + } + + // Check for shared user id changes + String invalidPackageName = null; + if (!Objects.equals(oldPackage.getSharedUserId(), + parsedPackage.getSharedUserId())) { + invalidPackageName = parsedPackage.getPackageName(); + } + + if (invalidPackageName != null) { + throw new PrepareFailure(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE, + "Package " + invalidPackageName + " tried to change user " + + oldPackage.getSharedUserId()); + } + + // In case of rollback, remember per-user/profile install state + allUsers = mPm.mUserManager.getUserIds(); + installedUsers = ps.queryInstalledUsers(allUsers, true); + uninstalledUsers = ps.queryInstalledUsers(allUsers, false); + + + // don't allow an upgrade from full to ephemeral + if (isInstantApp) { + if (args.mUser == null + || args.mUser.getIdentifier() == UserHandle.USER_ALL) { + for (int currentUser : allUsers) { + if (!ps.getInstantApp(currentUser)) { + // can't downgrade from full to instant + Slog.w(TAG, + "Can't replace full app with instant app: " + pkgName11 + + " for user: " + currentUser); + throw new PrepareFailure( + PackageManager.INSTALL_FAILED_SESSION_INVALID); + } + } + } else if (!ps.getInstantApp(args.mUser.getIdentifier())) { + // can't downgrade from full to instant + Slog.w(TAG, "Can't replace full app with instant app: " + pkgName11 + + " for user: " + args.mUser.getIdentifier()); + throw new PrepareFailure( + PackageManager.INSTALL_FAILED_SESSION_INVALID); + } + } + } + + // Update what is removed + res.mRemovedInfo = new PackageRemovedInfo(mPm); + res.mRemovedInfo.mUid = oldPackage.getUid(); + res.mRemovedInfo.mRemovedPackage = oldPackage.getPackageName(); + res.mRemovedInfo.mInstallerPackageName = ps.installSource.installerPackageName; + res.mRemovedInfo.mIsStaticSharedLib = + parsedPackage.getStaticSharedLibName() != null; + res.mRemovedInfo.mIsUpdate = true; + res.mRemovedInfo.mOrigUsers = installedUsers; + res.mRemovedInfo.mInstallReasons = new SparseArray<>(installedUsers.length); + for (int i = 0; i < installedUsers.length; i++) { + final int userId = installedUsers[i]; + res.mRemovedInfo.mInstallReasons.put(userId, ps.getInstallReason(userId)); + } + res.mRemovedInfo.mUninstallReasons = new SparseArray<>(uninstalledUsers.length); + for (int i = 0; i < uninstalledUsers.length; i++) { + final int userId = uninstalledUsers[i]; + res.mRemovedInfo.mUninstallReasons.put(userId, ps.getUninstallReason(userId)); + } + + sysPkg = oldPackage.isSystem(); + if (sysPkg) { + // Set the system/privileged/oem/vendor/product flags as needed + final boolean privileged = oldPackage.isPrivileged(); + final boolean oem = oldPackage.isOem(); + final boolean vendor = oldPackage.isVendor(); + final boolean product = oldPackage.isProduct(); + final boolean odm = oldPackage.isOdm(); + final boolean systemExt = oldPackage.isSystemExt(); + final @ParsingPackageUtils.ParseFlags int systemParseFlags = parseFlags; + final @PackageManagerService.ScanFlags int systemScanFlags = scanFlags + | SCAN_AS_SYSTEM + | (privileged ? SCAN_AS_PRIVILEGED : 0) + | (oem ? SCAN_AS_OEM : 0) + | (vendor ? SCAN_AS_VENDOR : 0) + | (product ? SCAN_AS_PRODUCT : 0) + | (odm ? SCAN_AS_ODM : 0) + | (systemExt ? SCAN_AS_SYSTEM_EXT : 0); + + if (DEBUG_INSTALL) { + Slog.d(TAG, "replaceSystemPackageLI: new=" + parsedPackage + + ", old=" + oldPackage); + } + res.setReturnCode(PackageManager.INSTALL_SUCCEEDED); + targetParseFlags = systemParseFlags; + targetScanFlags = systemScanFlags; + } else { // non system replace + replace = true; + if (DEBUG_INSTALL) { + Slog.d(TAG, + "replaceNonSystemPackageLI: new=" + parsedPackage + ", old=" + + oldPackage); + } + } + } else { // new package install + ps = null; + disabledPs = null; + replace = false; + existingPackage = null; + // Remember this for later, in case we need to rollback this install + String pkgName1 = parsedPackage.getPackageName(); + + if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + parsedPackage); + + // TODO(b/194319951): MOVE TO RECONCILE + synchronized (mPm.mLock) { + renamedPackage = mPm.mSettings.getRenamedPackageLPr(pkgName1); + if (renamedPackage != null) { + // A package with the same name is already installed, though + // it has been renamed to an older name. The package we + // are trying to install should be installed as an update to + // the existing one, but that has not been requested, so bail. + throw new PrepareFailure(INSTALL_FAILED_ALREADY_EXISTS, + "Attempt to re-install " + pkgName1 + + " without first uninstalling package running as " + + renamedPackage); + } + if (mPm.mPackages.containsKey(pkgName1)) { + // Don't allow installation over an existing package with the same name. + throw new PrepareFailure(INSTALL_FAILED_ALREADY_EXISTS, + "Attempt to re-install " + pkgName1 + + " without first uninstalling."); + } + } + } + // we're passing the freezer back to be closed in a later phase of install + shouldCloseFreezerBeforeReturn = false; + + return new PrepareResult(replace, targetScanFlags, targetParseFlags, + existingPackage, parsedPackage, replace /* clearCodeCache */, sysPkg, + ps, disabledPs); + } finally { + res.mFreezer = freezer; + if (shouldCloseFreezerBeforeReturn) { + freezer.close(); + } + } + } + + /* + * Cannot properly check CANNOT_INSTALL_WITH_BAD_PERMISSION_GROUPS using CompatChanges + * as this only works for packages that are installed + * + * TODO: Move logic for permission group compatibility into PermissionManagerService + */ + @SuppressWarnings("AndroidFrameworkCompatChange") + private static boolean cannotInstallWithBadPermissionGroups(ParsedPackage parsedPackage) { + return parsedPackage.getTargetSdkVersion() >= Build.VERSION_CODES.S; + } + + private boolean doesSignatureMatchForPermissions(@NonNull String sourcePackageName, + @NonNull ParsedPackage parsedPackage, int scanFlags) { + // If the defining package is signed with our cert, it's okay. This + // also includes the "updating the same package" case, of course. + // "updating same package" could also involve key-rotation. + + final PackageSetting sourcePackageSetting; + synchronized (mPm.mLock) { + sourcePackageSetting = mPm.mSettings.getPackageLPr(sourcePackageName); + } + + final SigningDetails sourceSigningDetails = (sourcePackageSetting == null + ? SigningDetails.UNKNOWN : sourcePackageSetting.getSigningDetails()); + final KeySetManagerService ksms = mPm.mSettings.getKeySetManagerService(); + if (sourcePackageName.equals(parsedPackage.getPackageName()) + && (ksms.shouldCheckUpgradeKeySetLocked( + sourcePackageSetting, scanFlags))) { + return ksms.checkUpgradeKeySetLocked(sourcePackageSetting, parsedPackage); + } else { + + // in the event of signing certificate rotation, we need to see if the + // package's certificate has rotated from the current one, or if it is an + // older certificate with which the current is ok with sharing permissions + if (sourceSigningDetails.checkCapability( + parsedPackage.getSigningDetails(), + SigningDetails.CertCapabilities.PERMISSION)) { + return true; + } else if (parsedPackage.getSigningDetails().checkCapability( + sourceSigningDetails, + SigningDetails.CertCapabilities.PERMISSION)) { + // the scanned package checks out, has signing certificate rotation + // history, and is newer; bring it over + synchronized (mPm.mLock) { + sourcePackageSetting.signatures.mSigningDetails = + parsedPackage.getSigningDetails(); + } + return true; + } else { + return false; + } + } + } + + /** + * Set up fs-verity for the given package if possible. This requires a feature flag of system + * property to be enabled only if the kernel supports fs-verity. + * + *

When the feature flag is set to legacy mode, only APK is supported (with some experimental + * kernel patches). In normal mode, all file format can be supported. + */ + private void setUpFsVerityIfPossible(AndroidPackage pkg) throws Installer.InstallerException, + PrepareFailure, IOException, DigestException, NoSuchAlgorithmException { + final boolean standardMode = PackageManagerServiceUtils.isApkVerityEnabled(); + final boolean legacyMode = PackageManagerServiceUtils.isLegacyApkVerityEnabled(); + if (!standardMode && !legacyMode) { + return; + } + + if (isIncrementalPath(pkg.getPath()) && IncrementalManager.getVersion() + < IncrementalManager.MIN_VERSION_TO_SUPPORT_FSVERITY) { + return; + } + + // Collect files we care for fs-verity setup. + ArrayMap fsverityCandidates = new ArrayMap<>(); + if (legacyMode) { + synchronized (mPm.mLock) { + final PackageSetting ps = mPm.mSettings.getPackageLPr(pkg.getPackageName()); + if (ps != null && ps.isPrivileged()) { + fsverityCandidates.put(pkg.getBaseApkPath(), null); + if (pkg.getSplitCodePaths() != null) { + for (String splitPath : pkg.getSplitCodePaths()) { + fsverityCandidates.put(splitPath, null); + } + } + } + } + } else { + // NB: These files will become only accessible if the signing key is loaded in kernel's + // .fs-verity keyring. + fsverityCandidates.put(pkg.getBaseApkPath(), + VerityUtils.getFsveritySignatureFilePath(pkg.getBaseApkPath())); + + final String dmPath = DexMetadataHelper.buildDexMetadataPathForApk( + pkg.getBaseApkPath()); + if (new File(dmPath).exists()) { + fsverityCandidates.put(dmPath, VerityUtils.getFsveritySignatureFilePath(dmPath)); + } + + if (pkg.getSplitCodePaths() != null) { + for (String path : pkg.getSplitCodePaths()) { + fsverityCandidates.put(path, VerityUtils.getFsveritySignatureFilePath(path)); + + final String splitDmPath = DexMetadataHelper.buildDexMetadataPathForApk(path); + if (new File(splitDmPath).exists()) { + fsverityCandidates.put(splitDmPath, + VerityUtils.getFsveritySignatureFilePath(splitDmPath)); + } + } + } + } + + for (Map.Entry entry : fsverityCandidates.entrySet()) { + final String filePath = entry.getKey(); + final String signaturePath = entry.getValue(); + + if (!legacyMode) { + // fs-verity is optional for now. Only set up if signature is provided. + if (new File(signaturePath).exists() && !VerityUtils.hasFsverity(filePath)) { + try { + VerityUtils.setUpFsverity(filePath, signaturePath); + } catch (IOException e) { + throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE, + "Failed to enable fs-verity: " + e); + } + } + continue; + } + + // In legacy mode, fs-verity can only be enabled by process with CAP_SYS_ADMIN. + final VerityUtils.SetupResult result = VerityUtils.generateApkVeritySetupData(filePath); + if (result.isOk()) { + if (Build.IS_DEBUGGABLE) Slog.i(TAG, "Enabling verity to " + filePath); + final FileDescriptor fd = result.getUnownedFileDescriptor(); + try { + final byte[] rootHash = VerityUtils.generateApkVerityRootHash(filePath); + try { + // A file may already have fs-verity, e.g. when reused during a split + // install. If the measurement succeeds, no need to attempt to set up. + mPm.mInstaller.assertFsverityRootHashMatches(filePath, rootHash); + } catch (Installer.InstallerException e) { + mPm.mInstaller.installApkVerity(filePath, fd, result.getContentSize()); + mPm.mInstaller.assertFsverityRootHashMatches(filePath, rootHash); + } + } finally { + IoUtils.closeQuietly(fd); + } + } else if (result.isFailed()) { + throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE, + "Failed to generate verity"); + } + } + } + + private PackageFreezer freezePackageForInstall(String packageName, int installFlags, + String killReason) { + return freezePackageForInstall(packageName, UserHandle.USER_ALL, installFlags, killReason); + } + + private PackageFreezer freezePackageForInstall(String packageName, int userId, int installFlags, + String killReason) { + if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) { + return new PackageFreezer(mPm); + } else { + return mPm.freezePackage(packageName, userId, killReason); + } + } + + private static void updateDigest(MessageDigest digest, File file) throws IOException { + try (DigestInputStream digestStream = + new DigestInputStream(new FileInputStream(file), digest)) { + int length, total = 0; + while ((length = digestStream.read()) != -1) { + total += length; + } // just plow through the file + } + } + + @GuardedBy("mLock") + private void commitPackagesLocked(final CommitRequest request) { + // TODO: remove any expected failures from this method; this should only be able to fail due + // to unavoidable errors (I/O, etc.) + for (ReconciledPackage reconciledPkg : request.mReconciledPackages.values()) { + final ScanResult scanResult = reconciledPkg.mScanResult; + final ScanRequest scanRequest = scanResult.mRequest; + final ParsedPackage parsedPackage = scanRequest.mParsedPackage; + final String packageName = parsedPackage.getPackageName(); + final PackageInstalledInfo res = reconciledPkg.mInstallResult; + + if (reconciledPkg.mPrepareResult.mReplace) { + AndroidPackage oldPackage = mPm.mPackages.get(packageName); + + // Set the update and install times + PackageSetting deletedPkgSetting = mPm.getPackageSetting( + oldPackage.getPackageName()); + reconciledPkg.mPkgSetting.firstInstallTime = deletedPkgSetting.firstInstallTime; + reconciledPkg.mPkgSetting.lastUpdateTime = System.currentTimeMillis(); + + res.mRemovedInfo.mBroadcastAllowList = mPm.mAppsFilter.getVisibilityAllowList( + reconciledPkg.mPkgSetting, request.mAllUsers, + mPm.mSettings.getPackagesLocked()); + if (reconciledPkg.mPrepareResult.mSystem) { + // Remove existing system package + mPm.removePackageLI(oldPackage, true); + if (!disableSystemPackageLPw(oldPackage)) { + // We didn't need to disable the .apk as a current system package, + // which means we are replacing another update that is already + // installed. We need to make sure to delete the older one's .apk. + res.mRemovedInfo.mArgs = mPm.createInstallArgsForExisting( + oldPackage.getPath(), + getAppDexInstructionSets( + AndroidPackageUtils.getPrimaryCpuAbi(oldPackage, + deletedPkgSetting), + AndroidPackageUtils.getSecondaryCpuAbi(oldPackage, + deletedPkgSetting))); + } else { + res.mRemovedInfo.mArgs = null; + } + } else { + try { + // Settings will be written during the call to updateSettingsLI(). + mPm.executeDeletePackageLIF(reconciledPkg.mDeletePackageAction, packageName, + true, request.mAllUsers, false); + } catch (SystemDeleteException e) { + if (mPm.mIsEngBuild) { + throw new RuntimeException("Unexpected failure", e); + // ignore; not possible for non-system app + } + } + // Successfully deleted the old package; proceed with replace. + + // If deleted package lived in a container, give users a chance to + // relinquish resources before killing. + if (oldPackage.isExternalStorage()) { + if (DEBUG_INSTALL) { + Slog.i(TAG, "upgrading pkg " + oldPackage + + " is ASEC-hosted -> UNAVAILABLE"); + } + final int[] uidArray = new int[]{oldPackage.getUid()}; + final ArrayList pkgList = new ArrayList<>(1); + pkgList.add(oldPackage.getPackageName()); + mPm.sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null); + } + + // Update the in-memory copy of the previous code paths. + PackageSetting ps1 = mPm.mSettings.getPackageLPr( + reconciledPkg.mPrepareResult.mExistingPackage.getPackageName()); + if ((reconciledPkg.mInstallArgs.mInstallFlags & PackageManager.DONT_KILL_APP) + == 0) { + if (ps1.mOldCodePaths == null) { + ps1.mOldCodePaths = new ArraySet<>(); + } + Collections.addAll(ps1.mOldCodePaths, oldPackage.getBaseApkPath()); + if (oldPackage.getSplitCodePaths() != null) { + Collections.addAll(ps1.mOldCodePaths, oldPackage.getSplitCodePaths()); + } + } else { + ps1.mOldCodePaths = null; + } + + if (reconciledPkg.mInstallResult.mReturnCode + == PackageManager.INSTALL_SUCCEEDED) { + PackageSetting ps2 = mPm.mSettings.getPackageLPr( + parsedPackage.getPackageName()); + if (ps2 != null) { + res.mRemovedInfo.mRemovedForAllUsers = + mPm.mPackages.get(ps2.name) == null; + } + } + } + } + + AndroidPackage pkg = mPm.commitReconciledScanResultLocked(reconciledPkg, + request.mAllUsers); + updateSettingsLI(pkg, reconciledPkg.mInstallArgs, request.mAllUsers, res); + + final PackageSetting ps = mPm.mSettings.getPackageLPr(packageName); + if (ps != null) { + res.mNewUsers = ps.queryInstalledUsers(mPm.mUserManager.getUserIds(), true); + ps.setUpdateAvailable(false /*updateAvailable*/); + } + if (res.mReturnCode == PackageManager.INSTALL_SUCCEEDED) { + mPm.updateSequenceNumberLP(ps, res.mNewUsers); + mPm.updateInstantAppInstallerLocked(packageName); + } + } + ApplicationPackageManager.invalidateGetPackagesForUidCache(); + } + + @GuardedBy("mLock") + private boolean disableSystemPackageLPw(AndroidPackage oldPkg) { + return mPm.mSettings.disableSystemPackageLPw(oldPkg.getPackageName(), true); + } + + private void updateSettingsLI(AndroidPackage newPackage, InstallArgs installArgs, + int[] allUsers, PackageInstalledInfo res) { + updateSettingsInternalLI(newPackage, installArgs, allUsers, res); + } + + private void updateSettingsInternalLI(AndroidPackage pkg, InstallArgs installArgs, + int[] allUsers, PackageInstalledInfo res) { + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings"); + + final String pkgName = pkg.getPackageName(); + final int[] installedForUsers = res.mOrigUsers; + final int installReason = installArgs.mInstallReason; + InstallSource installSource = installArgs.mInstallSource; + final String installerPackageName = installSource.installerPackageName; + + if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.getPath()); + synchronized (mPm.mLock) { + // For system-bundled packages, we assume that installing an upgraded version + // of the package implies that the user actually wants to run that new code, + // so we enable the package. + final PackageSetting ps = mPm.mSettings.getPackageLPr(pkgName); + final int userId = installArgs.mUser.getIdentifier(); + if (ps != null) { + if (pkg.isSystem()) { + if (DEBUG_INSTALL) { + Slog.d(TAG, "Implicitly enabling system package on upgrade: " + pkgName); + } + // Enable system package for requested users + if (res.mOrigUsers != null) { + for (int origUserId : res.mOrigUsers) { + if (userId == UserHandle.USER_ALL || userId == origUserId) { + ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, + origUserId, installerPackageName); + } + } + } + // Also convey the prior install/uninstall state + if (allUsers != null && installedForUsers != null) { + for (int currentUserId : allUsers) { + final boolean installed = ArrayUtils.contains( + installedForUsers, currentUserId); + if (DEBUG_INSTALL) { + Slog.d(TAG, " user " + currentUserId + " => " + installed); + } + ps.setInstalled(installed, currentUserId); + } + // these install state changes will be persisted in the + // upcoming call to mSettings.writeLPr(). + } + + if (allUsers != null) { + for (int currentUserId : allUsers) { + ps.resetOverrideComponentLabelIcon(currentUserId); + } + } + } + + // Retrieve the overlays for shared libraries of the package. + if (!ps.getPkgState().getUsesLibraryInfos().isEmpty()) { + for (SharedLibraryInfo sharedLib : ps.getPkgState().getUsesLibraryInfos()) { + for (int currentUserId : UserManagerService.getInstance().getUserIds()) { + if (!sharedLib.isDynamic()) { + // TODO(146804378): Support overlaying static shared libraries + continue; + } + final PackageSetting libPs = mPm.mSettings.getPackageLPr( + sharedLib.getPackageName()); + if (libPs == null) { + continue; + } + ps.setOverlayPathsForLibrary(sharedLib.getName(), + libPs.getOverlayPaths(currentUserId), currentUserId); + } + } + } + + // It's implied that when a user requests installation, they want the app to be + // installed and enabled. (This does not apply to USER_ALL, which here means only + // install on users for which the app is already installed). + if (userId != UserHandle.USER_ALL) { + ps.setInstalled(true, userId); + ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName); + } + + mPm.mSettings.addInstallerPackageNames(ps.installSource); + + // When replacing an existing package, preserve the original install reason for all + // users that had the package installed before. Similarly for uninstall reasons. + final Set previousUserIds = new ArraySet<>(); + if (res.mRemovedInfo != null && res.mRemovedInfo.mInstallReasons != null) { + final int installReasonCount = res.mRemovedInfo.mInstallReasons.size(); + for (int i = 0; i < installReasonCount; i++) { + final int previousUserId = res.mRemovedInfo.mInstallReasons.keyAt(i); + final int previousInstallReason = + res.mRemovedInfo.mInstallReasons.valueAt(i); + ps.setInstallReason(previousInstallReason, previousUserId); + previousUserIds.add(previousUserId); + } + } + if (res.mRemovedInfo != null && res.mRemovedInfo.mUninstallReasons != null) { + for (int i = 0; i < res.mRemovedInfo.mUninstallReasons.size(); i++) { + final int previousUserId = res.mRemovedInfo.mUninstallReasons.keyAt(i); + final int previousReason = res.mRemovedInfo.mUninstallReasons.valueAt(i); + ps.setUninstallReason(previousReason, previousUserId); + } + } + + // Set install reason for users that are having the package newly installed. + final int[] allUsersList = mPm.mUserManager.getUserIds(); + if (userId == UserHandle.USER_ALL) { + // TODO(b/152629990): It appears that the package doesn't actually get newly + // installed in this case, so the installReason shouldn't get modified? + for (int currentUserId : allUsersList) { + if (!previousUserIds.contains(currentUserId)) { + ps.setInstallReason(installReason, currentUserId); + } + } + } else if (!previousUserIds.contains(userId)) { + ps.setInstallReason(installReason, userId); + } + + // TODO(b/169721400): generalize Incremental States and create a Callback object + // that can be used for all the packages. + final String codePath = ps.getPathString(); + if (IncrementalManager.isIncrementalPath(codePath) + && mPm.mIncrementalManager != null) { + final IncrementalStatesCallback incrementalStatesCallback = + new IncrementalStatesCallback(ps.name, mPm); + ps.setIncrementalStatesCallback(incrementalStatesCallback); + mPm.mIncrementalManager.registerLoadingProgressCallback(codePath, + new IncrementalProgressListener(ps.name, mPm)); + } + + // Ensure that the uninstall reason is UNKNOWN for users with the package installed. + for (int currentUserId : allUsersList) { + if (ps.getInstalled(currentUserId)) { + ps.setUninstallReason(UNINSTALL_REASON_UNKNOWN, currentUserId); + } + } + + mPm.mSettings.writeKernelMappingLPr(ps); + + final PermissionManagerServiceInternal.PackageInstalledParams.Builder + permissionParamsBuilder = + new PermissionManagerServiceInternal.PackageInstalledParams.Builder(); + final boolean grantPermissions = (installArgs.mInstallFlags + & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0; + if (grantPermissions) { + final List grantedPermissions = + installArgs.mInstallGrantPermissions != null + ? Arrays.asList(installArgs.mInstallGrantPermissions) + : pkg.getRequestedPermissions(); + permissionParamsBuilder.setGrantedPermissions(grantedPermissions); + } + final boolean allowlistAllRestrictedPermissions = + (installArgs.mInstallFlags + & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0; + final List allowlistedRestrictedPermissions = + allowlistAllRestrictedPermissions ? pkg.getRequestedPermissions() + : installArgs.mAllowlistedRestrictedPermissions; + if (allowlistedRestrictedPermissions != null) { + permissionParamsBuilder.setAllowlistedRestrictedPermissions( + allowlistedRestrictedPermissions); + } + final int autoRevokePermissionsMode = installArgs.mAutoRevokePermissionsMode; + permissionParamsBuilder.setAutoRevokePermissionsMode(autoRevokePermissionsMode); + mPm.mPermissionManager.onPackageInstalled(pkg, permissionParamsBuilder.build(), + userId); + } + res.mName = pkgName; + res.mUid = pkg.getUid(); + res.mPkg = pkg; + res.setReturnCode(PackageManager.INSTALL_SUCCEEDED); + //to update install status + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "writeSettings"); + mPm.writeSettingsLPrTEMP(); + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + + /** + * On successful install, executes remaining steps after commit completes and the package lock + * is released. These are typically more expensive or require calls to installd, which often + * locks on {@link com.android.server.pm.PackageManagerService.mLock}. + */ + private void executePostCommitSteps(CommitRequest commitRequest) { + final ArraySet incrementalStorages = new ArraySet<>(); + for (ReconciledPackage reconciledPkg : commitRequest.mReconciledPackages.values()) { + final boolean instantApp = ((reconciledPkg.mScanResult.mRequest.mScanFlags + & SCAN_AS_INSTANT_APP) != 0); + final AndroidPackage pkg = reconciledPkg.mPkgSetting.pkg; + final String packageName = pkg.getPackageName(); + final String codePath = pkg.getPath(); + final boolean onIncremental = mPm.mIncrementalManager != null + && isIncrementalPath(codePath); + if (onIncremental) { + IncrementalStorage storage = mPm.mIncrementalManager.openStorage(codePath); + if (storage == null) { + throw new IllegalArgumentException( + "Install: null storage for incremental package " + packageName); + } + incrementalStorages.add(storage); + } + mPm.prepareAppDataAfterInstallLIF(pkg); + if (reconciledPkg.mPrepareResult.mClearCodeCache) { + mPm.clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE + | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY); + } + if (reconciledPkg.mPrepareResult.mReplace) { + mPm.getDexManager().notifyPackageUpdated(pkg.getPackageName(), + pkg.getBaseApkPath(), pkg.getSplitCodePaths()); + } + + // Prepare the application profiles for the new code paths. + // This needs to be done before invoking dexopt so that any install-time profile + // can be used for optimizations. + mPm.mArtManagerService.prepareAppProfiles( + pkg, + mPm.resolveUserIds(reconciledPkg.mInstallArgs.mUser.getIdentifier()), + /* updateReferenceProfileContent= */ true); + + // Compute the compilation reason from the installation scenario. + final int compilationReason = + mPm.getDexManager().getCompilationReasonForInstallScenario( + reconciledPkg.mInstallArgs.mInstallScenario); + + // Construct the DexoptOptions early to see if we should skip running dexopt. + // + // Do not run PackageDexOptimizer through the local performDexOpt + // method because `pkg` may not be in `mPackages` yet. + // + // Also, don't fail application installs if the dexopt step fails. + final boolean isBackupOrRestore = + reconciledPkg.mInstallArgs.mInstallReason == INSTALL_REASON_DEVICE_RESTORE + || reconciledPkg.mInstallArgs.mInstallReason + == INSTALL_REASON_DEVICE_SETUP; + + final int dexoptFlags = DexoptOptions.DEXOPT_BOOT_COMPLETE + | DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE + | (isBackupOrRestore ? DexoptOptions.DEXOPT_FOR_RESTORE : 0); + DexoptOptions dexoptOptions = + new DexoptOptions(packageName, compilationReason, dexoptFlags); + + // Check whether we need to dexopt the app. + // + // NOTE: it is IMPORTANT to call dexopt: + // - after doRename which will sync the package data from AndroidPackage and + // its corresponding ApplicationInfo. + // - after installNewPackageLIF or replacePackageLIF which will update result with the + // uid of the application (pkg.applicationInfo.uid). + // This update happens in place! + // + // We only need to dexopt if the package meets ALL of the following conditions: + // 1) it is not an instant app or if it is then dexopt is enabled via gservices. + // 2) it is not debuggable. + // 3) it is not on Incremental File System. + // + // Note that we do not dexopt instant apps by default. dexopt can take some time to + // complete, so we skip this step during installation. Instead, we'll take extra time + // the first time the instant app starts. It's preferred to do it this way to provide + // continuous progress to the useur instead of mysteriously blocking somewhere in the + // middle of running an instant app. The default behaviour can be overridden + // via gservices. + // + // Furthermore, dexopt may be skipped, depending on the install scenario and current + // state of the device. + // + // TODO(b/174695087): instantApp and onIncremental should be removed and their install + // path moved to SCENARIO_FAST. + final boolean performDexopt = + (!instantApp || android.provider.Settings.Global.getInt( + mPm.mContext.getContentResolver(), + android.provider.Settings.Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0) + && !pkg.isDebuggable() + && (!onIncremental) + && dexoptOptions.isCompilationEnabled(); + + if (performDexopt) { + // Compile the layout resources. + if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) { + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "compileLayouts"); + mPm.mViewCompiler.compileLayouts(pkg); + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt"); + ScanResult result = reconciledPkg.mScanResult; + + // This mirrors logic from commitReconciledScanResultLocked, where the library files + // needed for dexopt are assigned. + // TODO: Fix this to have 1 mutable PackageSetting for scan/install. If the previous + // setting needs to be passed to have a comparison, hide it behind an immutable + // interface. There's no good reason to have 3 different ways to access the real + // PackageSetting object, only one of which is actually correct. + PackageSetting realPkgSetting = result.mExistingSettingCopied + ? result.mRequest.mPkgSetting : result.mPkgSetting; + if (realPkgSetting == null) { + realPkgSetting = reconciledPkg.mPkgSetting; + } + + // Unfortunately, the updated system app flag is only tracked on this PackageSetting + boolean isUpdatedSystemApp = reconciledPkg.mPkgSetting.getPkgState() + .isUpdatedSystemApp(); + + realPkgSetting.getPkgState().setUpdatedSystemApp(isUpdatedSystemApp); + + mPm.mPackageDexOptimizer.performDexOpt(pkg, realPkgSetting, + null /* instructionSets */, + mPm.getOrCreateCompilerPackageStats(pkg), + mPm.getDexManager().getPackageUseInfoOrDefault(packageName), + dexoptOptions); + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + + // Notify BackgroundDexOptService that the package has been changed. + // If this is an update of a package which used to fail to compile, + // BackgroundDexOptService will remove it from its denylist. + // TODO: Layering violation + BackgroundDexOptService.notifyPackageChanged(packageName); + + notifyPackageChangeObserversOnUpdate(reconciledPkg); + } + waitForNativeBinariesExtraction(incrementalStorages); + } + + private void notifyPackageChangeObserversOnUpdate(ReconciledPackage reconciledPkg) { + final PackageSetting pkgSetting = reconciledPkg.mPkgSetting; + final PackageInstalledInfo pkgInstalledInfo = reconciledPkg.mInstallResult; + final PackageRemovedInfo pkgRemovedInfo = pkgInstalledInfo.mRemovedInfo; + + PackageChangeEvent pkgChangeEvent = new PackageChangeEvent(); + pkgChangeEvent.packageName = pkgSetting.pkg.getPackageName(); + pkgChangeEvent.version = pkgSetting.versionCode; + pkgChangeEvent.lastUpdateTimeMillis = pkgSetting.lastUpdateTime; + pkgChangeEvent.newInstalled = (pkgRemovedInfo == null || !pkgRemovedInfo.mIsUpdate); + pkgChangeEvent.dataRemoved = (pkgRemovedInfo != null && pkgRemovedInfo.mDataRemoved); + pkgChangeEvent.isDeleted = false; + + mPm.notifyPackageChangeObservers(pkgChangeEvent); + } + + static void waitForNativeBinariesExtraction( + ArraySet incrementalStorages) { + if (incrementalStorages.isEmpty()) { + return; + } + try { + // Native library extraction may take very long time: each page could potentially + // wait for either 10s or 100ms (adb vs non-adb data loader), and that easily adds + // up to a full watchdog timeout of 1 min, killing the system after that. It doesn't + // make much sense as blocking here doesn't lock up the framework, but only blocks + // the installation session and the following ones. + Watchdog.getInstance().pauseWatchingCurrentThread("native_lib_extract"); + for (int i = 0; i < incrementalStorages.size(); ++i) { + IncrementalStorage storage = incrementalStorages.valueAtUnchecked(i); + storage.waitForNativeBinariesExtraction(); + } + } finally { + Watchdog.getInstance().resumeWatchingCurrentThread("native_lib_extract"); + } + } + + /** + * Ensure that the install reason matches what we know about the package installer (e.g. whether + * it is acting on behalf on an enterprise or the user). + * + * Note that the ordering of the conditionals in this method is important. The checks we perform + * are as follows, in this order: + * + * 1) If the install is being performed by a system app, we can trust the app to have set the + * install reason correctly. Thus, we pass through the install reason unchanged, no matter + * what it is. + * 2) If the install is being performed by a device or profile owner app, the install reason + * should be enterprise policy. However, we cannot be sure that the device or profile owner + * set the install reason correctly. If the app targets an older SDK version where install + * reasons did not exist yet, or if the app author simply forgot, the install reason may be + * unset or wrong. Thus, we force the install reason to be enterprise policy. + * 3) In all other cases, the install is being performed by a regular app that is neither part + * of the system nor a device or profile owner. We have no reason to believe that this app is + * acting on behalf of the enterprise admin. Thus, we check whether the install reason was + * set to enterprise policy and if so, change it to unknown instead. + */ + private int fixUpInstallReason(String installerPackageName, int installerUid, + int installReason) { + if (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, installerUid) + == PERMISSION_GRANTED) { + // If the install is being performed by a system app, we trust that app to have set the + // install reason correctly. + return installReason; + } + final String ownerPackage = mPm.mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage( + UserHandle.getUserId(installerUid)); + if (ownerPackage != null && ownerPackage.equals(installerPackageName)) { + // If the install is being performed by a device or profile owner, the install + // reason should be enterprise policy. + return PackageManager.INSTALL_REASON_POLICY; + } + + + if (installReason == PackageManager.INSTALL_REASON_POLICY) { + // If the install is being performed by a regular app (i.e. neither system app nor + // device or profile owner), we have no reason to believe that the app is acting on + // behalf of an enterprise. If the app set the install reason to enterprise policy, + // change it to unknown instead. + return PackageManager.INSTALL_REASON_UNKNOWN; + } + + // If the install is being performed by a regular app and the install reason was set to any + // value but enterprise policy, leave the install reason unchanged. + return installReason; + } + + public void installStage() { + final Message msg = mPm.mHandler.obtainMessage(INIT_COPY); + setTraceMethod("installStage").setTraceCookie(System.identityHashCode(this)); + msg.obj = this; + + Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage", + System.identityHashCode(msg.obj)); + Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall", + System.identityHashCode(msg.obj)); + + mPm.mHandler.sendMessage(msg); + } + + public void installStage(List children) + throws PackageManagerException { + final Message msg = mPm.mHandler.obtainMessage(INIT_COPY); + final MultiPackageInstallParams params = + new MultiPackageInstallParams(this, children); + params.setTraceMethod("installStageMultiPackage") + .setTraceCookie(System.identityHashCode(params)); + msg.obj = params; + + Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStageMultiPackage", + System.identityHashCode(msg.obj)); + Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall", + System.identityHashCode(msg.obj)); + mPm.mHandler.sendMessage(msg); + } + + public void movePackage() { + final Message msg = mPm.mHandler.obtainMessage(INIT_COPY); + setTraceMethod("movePackage").setTraceCookie(System.identityHashCode(this)); + msg.obj = this; + + Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "movePackage", + System.identityHashCode(msg.obj)); + Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall", + System.identityHashCode(msg.obj)); + mPm.mHandler.sendMessage(msg); + } + + /** + * Container for a multi-package install which refers to all install sessions and args being + * committed together. + */ + final class MultiPackageInstallParams extends HandlerParams { + private final List mChildParams; + private final Map mCurrentState; + + MultiPackageInstallParams(InstallParams parent, List childParams) + throws PackageManagerException { + super(parent.getUser()); + if (childParams.size() == 0) { + throw new PackageManagerException("No child sessions found!"); + } + mChildParams = childParams; + for (int i = 0; i < childParams.size(); i++) { + final InstallParams childParam = childParams.get(i); + childParam.mParentInstallParams = this; + } + this.mCurrentState = new ArrayMap<>(mChildParams.size()); + } + + @Override + void handleStartCopy() { + for (InstallParams params : mChildParams) { + params.handleStartCopy(); + } + } + + @Override + void handleReturnCode() { + for (InstallParams params : mChildParams) { + params.handleReturnCode(); + } + } + + void tryProcessInstallRequest(InstallArgs args, int currentStatus) { + mCurrentState.put(args, currentStatus); + if (mCurrentState.size() != mChildParams.size()) { + return; + } + int completeStatus = PackageManager.INSTALL_SUCCEEDED; + for (Integer status : mCurrentState.values()) { + if (status == PackageManager.INSTALL_UNKNOWN) { + return; + } else if (status != PackageManager.INSTALL_SUCCEEDED) { + completeStatus = status; + break; + } + } + final List installRequests = new ArrayList<>(mCurrentState.size()); + for (Map.Entry entry : mCurrentState.entrySet()) { + installRequests.add(new InstallRequest(entry.getKey(), + new PackageInstalledInfo(completeStatus))); + } + processInstallRequestsAsync( + completeStatus == PackageManager.INSTALL_SUCCEEDED, + installRequests); + } + } +} diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java new file mode 100644 index 0000000000000..753d012a32e38 --- /dev/null +++ b/services/core/java/com/android/server/pm/InstallRequest.java @@ -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; + } +} diff --git a/services/core/java/com/android/server/pm/MoveInfo.java b/services/core/java/com/android/server/pm/MoveInfo.java new file mode 100644 index 0000000000000..5ab86d626e8ba --- /dev/null +++ b/services/core/java/com/android/server/pm/MoveInfo.java @@ -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; + } +} diff --git a/services/core/java/com/android/server/pm/MoveInstallArgs.java b/services/core/java/com/android/server/pm/MoveInstallArgs.java new file mode 100644 index 0000000000000..35827a196a398 --- /dev/null +++ b/services/core/java/com/android/server/pm/MoveInstallArgs.java @@ -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(); + } +} diff --git a/services/core/java/com/android/server/pm/OriginInfo.java b/services/core/java/com/android/server/pm/OriginInfo.java new file mode 100644 index 0000000000000..b2fbd32da983d --- /dev/null +++ b/services/core/java/com/android/server/pm/OriginInfo.java @@ -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; + } + } +} diff --git a/services/core/java/com/android/server/pm/PackageFreezer.java b/services/core/java/com/android/server/pm/PackageFreezer.java new file mode 100644 index 0000000000000..395f3b43426ff --- /dev/null +++ b/services/core/java/com/android/server/pm/PackageFreezer.java @@ -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); + } + } + } + } +} diff --git a/services/core/java/com/android/server/pm/PackageInstalledInfo.java b/services/core/java/com/android/server/pm/PackageInstalledInfo.java new file mode 100644 index 0000000000000..afe6bb2cc792d --- /dev/null +++ b/services/core/java/com/android/server/pm/PackageInstalledInfo.java @@ -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 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; + } +} diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index ed6823fa30fc4..fdbcf850cbbd5 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -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 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 verifyingChildSessions = + List 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 childSessions = getChildSessions(); - List installingChildSessions = - new ArrayList<>(childSessions.size()); + List 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); } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 4d0a5a39804cd..b44e2ed3dd886 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -21,14 +21,10 @@ import static android.Manifest.permission.MANAGE_DEVICE_ADMINS; import static android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS; import static android.Manifest.permission.REQUEST_DELETE_PACKAGES; import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS; -import static android.app.AppOpsManager.MODE_DEFAULT; import static android.app.AppOpsManager.MODE_IGNORED; import static android.content.Intent.ACTION_MAIN; import static android.content.Intent.CATEGORY_DEFAULT; import static android.content.Intent.CATEGORY_HOME; -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.CERT_INPUT_RAW_X509; import static android.content.pm.PackageManager.CERT_INPUT_SHA256; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; @@ -36,36 +32,17 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; -import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID; -import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT; -import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED; -import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT; -import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED; -import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED; -import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET; -import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS; -import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_PERMISSION_GROUP; import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE; -import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION; -import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION_GROUP; -import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; -import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR; import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK; import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY; import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED; import static android.content.pm.PackageManager.INSTALL_FAILED_PROCESS_NOT_DEFINED; -import static android.content.pm.PackageManager.INSTALL_FAILED_SESSION_INVALID; -import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE; -import static android.content.pm.PackageManager.INSTALL_FAILED_TEST_ONLY; import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE; import static android.content.pm.PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE; import static android.content.pm.PackageManager.INSTALL_INTERNAL; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES; -import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_RESTORE; -import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_SETUP; -import static android.content.pm.PackageManager.INSTALL_STAGED; import static android.content.pm.PackageManager.INSTALL_SUCCEEDED; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; import static android.content.pm.PackageManager.MATCH_ALL; @@ -95,11 +72,9 @@ import static android.content.pm.PackageManager.TYPE_SERVICE; import static android.content.pm.PackageManager.TYPE_UNKNOWN; import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN; import static android.content.pm.PackageManagerInternal.LAST_KNOWN_PACKAGE; -import static android.content.pm.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V4; import static android.content.pm.parsing.ApkLiteParseUtils.isApkFile; import static android.os.PowerWhitelistManager.REASON_LOCKED_BOOT_COMPLETED; import static android.os.PowerWhitelistManager.REASON_PACKAGE_REPLACED; -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 android.os.incremental.IncrementalManager.isIncrementalPath; @@ -118,7 +93,6 @@ import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATI import static com.android.server.pm.ComponentResolver.RESOLVE_PRIORITY_SORTER; import static com.android.server.pm.InstructionSets.getAppDexInstructionSets; import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet; -import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; import static com.android.server.pm.InstructionSets.getPreferredInstructionSet; import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter; import static com.android.server.pm.PackageManagerServiceUtils.comparePackageSignatures; @@ -211,7 +185,6 @@ import android.content.pm.PackageManager.PropertyLocation; import android.content.pm.PackageManagerInternal; import android.content.pm.PackageManagerInternal.PackageListObserver; import android.content.pm.PackageManagerInternal.PrivateResolveFlags; -import android.content.pm.PackageParser; import android.content.pm.PackagePartitions; import android.content.pm.PackagePartitions.SystemPartition; import android.content.pm.PackageStats; @@ -233,10 +206,8 @@ import android.content.pm.SuspendDialogInfo; import android.content.pm.TestUtilityService; import android.content.pm.UserInfo; import android.content.pm.VerifierDeviceIdentity; -import android.content.pm.VerifierInfo; import android.content.pm.VersionedPackage; import android.content.pm.dex.ArtManager; -import android.content.pm.dex.DexMetadataHelper; import android.content.pm.dex.IArtManager; import android.content.pm.overlay.OverlayPaths; import android.content.pm.parsing.ApkLiteParseUtils; @@ -247,8 +218,6 @@ import android.content.pm.parsing.ParsingPackageUtils.ParseFlags; import android.content.pm.parsing.component.ParsedActivity; import android.content.pm.parsing.component.ParsedInstrumentation; import android.content.pm.parsing.component.ParsedMainComponent; -import android.content.pm.parsing.component.ParsedPermission; -import android.content.pm.parsing.component.ParsedPermissionGroup; import android.content.pm.parsing.component.ParsedProcess; import android.content.pm.parsing.component.ParsedProvider; import android.content.pm.parsing.component.ParsedService; @@ -279,7 +248,6 @@ import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ResultReceiver; -import android.os.SELinux; import android.os.ServiceManager; import android.os.ShellCallback; import android.os.SystemClock; @@ -288,7 +256,6 @@ import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; import android.os.incremental.IncrementalManager; -import android.os.incremental.IncrementalStorage; import android.os.incremental.PerUidReadTimeouts; import android.os.storage.DiskInfo; import android.os.storage.IStorageManager; @@ -303,11 +270,9 @@ import android.provider.DeviceConfig; import android.provider.Settings.Global; import android.provider.Settings.Secure; import android.security.KeyStore; -import android.security.SystemKeyStore; import android.service.pm.PackageServiceDumpProto; import android.stats.storage.StorageEnums; import android.system.ErrnoException; -import android.system.Os; import android.text.TextUtils; import android.text.format.DateUtils; import android.util.ArrayMap; @@ -393,7 +358,6 @@ import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.parsing.pkg.ParsedPackage; import com.android.server.pm.permission.LegacyPermissionManagerInternal; import com.android.server.pm.permission.LegacyPermissionManagerService; -import com.android.server.pm.permission.Permission; import com.android.server.pm.permission.PermissionManagerService; import com.android.server.pm.permission.PermissionManagerServiceInternal; import com.android.server.pm.verify.domain.DomainVerificationManagerInternal; @@ -416,7 +380,6 @@ import com.android.server.utils.WatchedSparseIntArray; import com.android.server.utils.Watcher; import com.android.server.wm.ActivityTaskManagerInternal; -import dalvik.system.CloseGuard; import dalvik.system.VMRuntime; import libcore.io.IoUtils; @@ -431,7 +394,6 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileDescriptor; -import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -442,10 +404,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.nio.charset.StandardCharsets; import java.security.DigestException; -import java.security.DigestInputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.security.PublicKey; import java.security.SecureRandom; import java.security.cert.Certificate; import java.security.cert.CertificateException; @@ -531,7 +491,7 @@ public class PackageManagerService extends IPackageManager.Stub private static final boolean DEBUG_PACKAGE_INFO = false; private static final boolean DEBUG_INTENT_MATCHING = false; public static final boolean DEBUG_PACKAGE_SCANNING = false; - private static final boolean DEBUG_VERIFY = false; + static final boolean DEBUG_VERIFY = false; public static final boolean DEBUG_PERMISSIONS = false; private static final boolean DEBUG_SHARED_LIBRARIES = false; public static final boolean DEBUG_COMPRESSION = Build.IS_DEBUGGABLE; @@ -544,7 +504,7 @@ public class PackageManagerService extends IPackageManager.Stub public static final boolean DEBUG_DEXOPT = false; static final boolean DEBUG_ABI_SELECTION = false; - private static final boolean DEBUG_INSTANT = Build.IS_DEBUGGABLE; + public static final boolean DEBUG_INSTANT = Build.IS_DEBUGGABLE; private static final boolean DEBUG_APP_DATA = false; /** REMOVE. According to Svet, this was only used to reset permissions during development. */ @@ -552,7 +512,7 @@ public class PackageManagerService extends IPackageManager.Stub private static final boolean HIDE_EPHEMERAL_APIS = false; - private static final String PRECOMPILE_LAYOUTS = "pm.precompile_layouts"; + static final String PRECOMPILE_LAYOUTS = "pm.precompile_layouts"; private static final int RADIO_UID = Process.PHONE_UID; private static final int LOG_UID = Process.LOG_UID; @@ -679,44 +639,11 @@ public class PackageManagerService extends IPackageManager.Stub */ private static final long DEFAULT_MANDATORY_FSTRIM_INTERVAL = 3 * DateUtils.DAY_IN_MILLIS; - /** - * Whether verification is enabled by default. - */ - private static final boolean DEFAULT_VERIFY_ENABLE = true; - - /** - * Whether integrity verification is enabled by default. - */ - private static final boolean DEFAULT_INTEGRITY_VERIFY_ENABLE = true; - /** * The default maximum time to wait for the verification agent to return in * milliseconds. */ - private static final long DEFAULT_VERIFICATION_TIMEOUT = 10 * 1000; - - /** - * The default maximum time to wait for the integrity verification to return in - * milliseconds. - */ - private static final long DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT = 30 * 1000; - - /** - * Timeout duration in milliseconds for enabling package rollback. If we fail to enable - * rollback within that period, the install will proceed without rollback enabled. - * - *

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; + static final long DEFAULT_VERIFICATION_TIMEOUT = 10 * 1000; /** * Default IncFs timeouts. Maximum values in IncFs is 1hr. @@ -776,7 +703,7 @@ public class PackageManagerService extends IPackageManager.Stub public static final String PLATFORM_PACKAGE_NAME = "android"; - private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive"; + static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive"; private static final String PACKAGE_SCHEME = "package"; @@ -943,7 +870,7 @@ public class PackageManagerService extends IPackageManager.Stub boolean mFirstBoot; - private final boolean mIsEngBuild; + final boolean mIsEngBuild; private final boolean mIsUserDebugBuild; private final String mIncrementalVersion; @@ -974,16 +901,11 @@ public class PackageManagerService extends IPackageManager.Stub @GuardedBy("mLock") final private ArraySet mPackageListObservers = new ArraySet<>(); - @GuardedBy("mLock") - private final SparseIntArray mDefaultPermissionsGrantedUsers = new SparseIntArray(); - private final ModuleInfoProvider mModuleInfoProvider; - private final ApexManager mApexManager; + final ApexManager mApexManager; - private final Injector mInjector; - - private final SystemWrapper mSystemWrapper; + final Injector mInjector; /** * The list of all system partitions that may contain packages in ascending order of @@ -1402,17 +1324,16 @@ public class PackageManagerService extends IPackageManager.Stub public ArrayMap packages; public boolean enableFreeCacheV2; public int sdkVersion; - public SystemWrapper systemWrapper; public File appInstallDir; public File appLib32InstallDir; public boolean isEngBuild; public boolean isUserDebugBuild; public int sdkInt = Build.VERSION.SDK_INT; - public String incrementalVersion = Build.VERSION.INCREMENTAL; + public final String incrementalVersion = Build.VERSION.INCREMENTAL; } @Watched - private final AppsFilter mAppsFilter; + final AppsFilter mAppsFilter; final PackageParser2.Callback mPackageParserCallback; @@ -1460,24 +1381,24 @@ public class PackageManagerService extends IPackageManager.Stub final ArtManagerService mArtManagerService; - private final PackageDexOptimizer mPackageDexOptimizer; + final PackageDexOptimizer mPackageDexOptimizer; // DexManager handles the usage of dex files (e.g. secondary files, whether or not a package // is used by other apps). private final DexManager mDexManager; - private final ViewCompiler mViewCompiler; + final ViewCompiler mViewCompiler; - private AtomicInteger mNextMoveId = new AtomicInteger(); + private final AtomicInteger mNextMoveId = new AtomicInteger(); private final MoveCallbacks mMoveCallbacks; // Cache of users who need badging. private final SparseBooleanArray mUserNeedsBadging = new SparseBooleanArray(); /** Token for keys in mPendingVerification. */ - private int mPendingVerificationToken = 0; + int mPendingVerificationToken = 0; /** Token for keys in mPendingEnableRollback. */ - private int mPendingEnableRollbackToken = 0; + int mPendingEnableRollbackToken = 0; @Watched(manual = true) volatile boolean mSystemReady; @@ -1510,7 +1431,7 @@ public class PackageManagerService extends IPackageManager.Stub /** Activity used to install instant applications */ @Watched(manual = true) - private ActivityInfo mInstantAppInstallerActivity; + ActivityInfo mInstantAppInstallerActivity; @Watched(manual = true) private final ResolveInfo mInstantAppInstallerInfo = new ResolveInfo(); @@ -1518,7 +1439,7 @@ public class PackageManagerService extends IPackageManager.Stub mNoKillInstallObservers = Collections.synchronizedMap(new HashMap<>()); // Internal interface for permission manager - private final PermissionManagerServiceInternal mPermissionManager; + final PermissionManagerServiceInternal mPermissionManager; @Watched private final ComponentResolver mComponentResolver; @@ -1533,7 +1454,7 @@ public class PackageManagerService extends IPackageManager.Stub private Future mPrepareAppDataFuture; - private final IncrementalManager mIncrementalManager; + final IncrementalManager mIncrementalManager; private final DefaultAppProvider mDefaultAppProvider; @@ -1645,7 +1566,7 @@ public class PackageManagerService extends IPackageManager.Stub final UserManagerService mUserManager; // Stores a list of users whose package restrictions file needs to be updated - private ArraySet mDirtyUsers = new ArraySet<>(); + private final ArraySet mDirtyUsers = new ArraySet<>(); // Recordkeeping of restore-after-install operations that are currently in flight // between the Package Manager and the Backup Manager @@ -1671,31 +1592,6 @@ public class PackageManagerService extends IPackageManager.Stub // XML tags for backup/restore of various bits of state private static final String TAG_PREFERRED_BACKUP = "pa"; private static final String TAG_DEFAULT_APPS = "da"; - private static final String TAG_INTENT_FILTER_VERIFICATION = "iv"; - - private static final String TAG_PERMISSION_BACKUP = "perm-grant-backup"; - private static final String TAG_ALL_GRANTS = "rt-grants"; - private static final String TAG_GRANT = "grant"; - private static final String ATTR_PACKAGE_NAME = "pkg"; - - private static final String TAG_PERMISSION = "perm"; - private static final String ATTR_PERMISSION_NAME = "name"; - private static final String ATTR_IS_GRANTED = "g"; - private static final String ATTR_USER_SET = "set"; - private static final String ATTR_USER_FIXED = "fixed"; - private static final String ATTR_REVOKE_ON_UPGRADE = "rou"; - - // System/policy permission grants are not backed up - private static final int SYSTEM_RUNTIME_GRANT_MASK = - FLAG_PERMISSION_POLICY_FIXED - | FLAG_PERMISSION_SYSTEM_FIXED - | FLAG_PERMISSION_GRANTED_BY_DEFAULT; - - // And we back up these user-adjusted states - private static final int USER_RUNTIME_GRANT_MASK = - FLAG_PERMISSION_USER_SET - | FLAG_PERMISSION_USER_FIXED - | FLAG_PERMISSION_REVOKED_COMPAT; final @Nullable String mRequiredVerifierPackage; final @NonNull String mRequiredInstallerPackage; @@ -1838,7 +1734,7 @@ public class PackageManagerService extends IPackageManager.Stub private final Watcher mWatcher = new Watcher() { @Override public void onChange(@Nullable Watchable what) { - PackageManagerService.this.onChange(what); + PackageManagerService.onChange(what); } }; @@ -1959,7 +1855,7 @@ public class PackageManagerService extends IPackageManager.Stub */ @Target({ ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) - public @interface LiveImplementation { + @interface LiveImplementation { // A Computer method must be annotated with one of the following values: // MANDATORY - the method must be overridden in ComputerEngineLive. The // format of the override is a call to the super method, wrapped in a @@ -2324,11 +2220,10 @@ public class PackageManagerService extends IPackageManager.Stub } } - List result = applyPostResolutionFilter( + return applyPostResolutionFilter( list, instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart, userId, intent); - return result; } QueryIntentActivitiesResult lockedResult = @@ -3969,10 +3864,8 @@ public class PackageManagerService extends IPackageManager.Stub return true; } // TODO(b/122900055) Change/Remove this and replace with new permission role. - if (mAppPredictionServicePackage != null - && isCallerSameApp(mAppPredictionServicePackage, callingUid)) { - return true; - } + return mAppPredictionServicePackage != null + && isCallerSameApp(mAppPredictionServicePackage, callingUid); } return false; } @@ -4074,10 +3967,7 @@ public class PackageManagerService extends IPackageManager.Stub if (isComponentVisibleToInstantApp(component, TYPE_SERVICE)) { return true; } - if (isComponentVisibleToInstantApp(component, TYPE_PROVIDER)) { - return true; - } - return false; + return isComponentVisibleToInstantApp(component, TYPE_PROVIDER); } public final boolean isComponentVisibleToInstantApp( @@ -4314,11 +4204,8 @@ public class PackageManagerService extends IPackageManager.Stub final String instantAppPkgName = getInstantAppPackageName(callingUid); final boolean callerIsInstantApp = instantAppPkgName != null; if (ps == null) { - if (callerIsInstantApp) { - // pretend the application exists, but, needs to be filtered - return true; - } - return false; + // pretend the application exists, but, needs to be filtered + return callerIsInstantApp; } // if the target and caller are the same application, don't filter if (isCallerSameApp(ps.name, callingUid)) { @@ -5046,13 +4933,13 @@ public class PackageManagerService extends IPackageManager.Stub // a live computer. private final AtomicInteger mReusedLive = new AtomicInteger(0); - private PackageManagerService mService; + private final PackageManagerService mService; ComputerTracker(PackageManagerService s) { mService = s; } private ThreadComputer live() { - ThreadComputer current = mService.sThreadComputer.get(); + ThreadComputer current = sThreadComputer.get(); if (current.mRefCount > 0) { current.acquire(); mReusedLive.incrementAndGet(); @@ -5063,7 +4950,7 @@ public class PackageManagerService extends IPackageManager.Stub } private ThreadComputer snapshot() { - ThreadComputer current = mService.sThreadComputer.get(); + ThreadComputer current = sThreadComputer.get(); if (current.mRefCount > 0) { current.acquire(); mReusedSnapshot.incrementAndGet(); @@ -5623,13 +5510,13 @@ public class PackageManagerService extends IPackageManager.Stub // set from outside classes. The attribute may be set to true anywhere, although it // should only be set true while holding mLock. However, the attribute id guaranteed // to be set false only while mLock and mSnapshotLock are both held. - private static AtomicBoolean sSnapshotInvalid = new AtomicBoolean(true); + private static final AtomicBoolean sSnapshotInvalid = new AtomicBoolean(true); // The package manager that is using snapshots. private static PackageManagerService sSnapshotConsumer = null; // If true, the snapshot is corked. Do not create a new snapshot but use the live // computer. This throttles snapshot creation during periods of churn in Package // Manager. - private static AtomicInteger sSnapshotCorked = new AtomicInteger(0); + private static final AtomicInteger sSnapshotCorked = new AtomicInteger(0); /** * This class records the Computer being used by a thread and the Computer's reference @@ -5657,7 +5544,7 @@ public class PackageManagerService extends IPackageManager.Stub } } } - private static ThreadLocal sThreadComputer = new ThreadLocal<>() { + private static final ThreadLocal sThreadComputer = new ThreadLocal<>() { @Override protected ThreadComputer initialValue() { return new ThreadComputer(); }}; @@ -5834,10 +5721,10 @@ public class PackageManagerService extends IPackageManager.Stub break; } case SEND_PENDING_BROADCAST: { - String packages[]; - ArrayList components[]; + String[] packages; + ArrayList[] components; int size = 0; - int uids[]; + int[] uids; Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); synchronized (mLock) { size = mPendingBroadcasts.size(); @@ -5883,8 +5770,8 @@ public class PackageManagerService extends IPackageManager.Stub final boolean didRestore = (msg.arg2 != 0); mRunningInstalls.delete(msg.arg1); - if (data != null && data.res.freezer != null) { - data.res.freezer.close(); + if (data != null && data.res.mFreezer != null) { + data.res.mFreezer.close(); } if (data != null && data.mPostInstallRunnable != null) { @@ -5893,19 +5780,19 @@ public class PackageManagerService extends IPackageManager.Stub InstallArgs args = data.args; PackageInstalledInfo parentRes = data.res; - final boolean killApp = (args.installFlags + final boolean killApp = (args.mInstallFlags & PackageManager.INSTALL_DONT_KILL_APP) == 0; - final boolean virtualPreload = ((args.installFlags + final boolean virtualPreload = ((args.mInstallFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0); handlePackagePostInstall(parentRes, killApp, virtualPreload, - didRestore, args.installSource.installerPackageName, args.observer, - args.mDataLoaderType); + didRestore, args.mInstallSource.installerPackageName, + args.mObserver, args.mDataLoaderType); // Log tracing if needed - if (args.traceMethod != null) { - Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, args.traceMethod, - args.traceCookie); + if (args.mTraceMethod != null) { + Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, args.mTraceMethod, + args.mTraceCookie); } } else if (DEBUG_INSTALL) { // No post-install when we run restore from installExistingPackageForUser @@ -5964,7 +5851,7 @@ public class PackageManagerService extends IPackageManager.Stub if ((state != null) && !state.isVerificationComplete() && !state.timeoutExtended()) { final VerificationParams params = state.getVerificationParams(); - final Uri originUri = Uri.fromFile(params.origin.resolvedFile); + final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile); String errorMsg = "Verification timed out for " + originUri; Slog.i(TAG, errorMsg); @@ -6006,7 +5893,7 @@ public class PackageManagerService extends IPackageManager.Stub if (state != null && !state.isIntegrityVerificationComplete()) { final VerificationParams params = state.getVerificationParams(); - final Uri originUri = Uri.fromFile(params.origin.resolvedFile); + final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile); String errorMsg = "Integrity verification timed out for " + originUri; Slog.i(TAG, errorMsg); @@ -6053,7 +5940,7 @@ public class PackageManagerService extends IPackageManager.Stub if (state.isVerificationComplete()) { final VerificationParams params = state.getVerificationParams(); - final Uri originUri = Uri.fromFile(params.origin.resolvedFile); + final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile); if (state.isInstallAllowed()) { broadcastPackageVerified(verificationId, originUri, @@ -6088,7 +5975,7 @@ public class PackageManagerService extends IPackageManager.Stub final int response = (Integer) msg.obj; final VerificationParams params = state.getVerificationParams(); - final Uri originUri = Uri.fromFile(params.origin.resolvedFile); + final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile); state.setIntegrityVerificationResult(response); @@ -6134,7 +6021,7 @@ public class PackageManagerService extends IPackageManager.Stub mPendingEnableRollback.remove(enableRollbackToken); if (enableRollbackCode != PackageManagerInternal.ENABLE_ROLLBACK_SUCCEEDED) { - final Uri originUri = Uri.fromFile(params.origin.resolvedFile); + final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile); Slog.w(TAG, "Failed to enable rollback for " + originUri); Slog.w(TAG, "Continuing with installation of " + originUri); } @@ -6151,7 +6038,7 @@ public class PackageManagerService extends IPackageManager.Stub final VerificationParams params = mPendingEnableRollback.get(enableRollbackToken); if (params != null) { - final Uri originUri = Uri.fromFile(params.origin.resolvedFile); + final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile); Slog.w(TAG, "Enable rollback timed out for " + originUri); mPendingEnableRollback.remove(enableRollbackToken); @@ -6192,20 +6079,21 @@ public class PackageManagerService extends IPackageManager.Stub private void handlePackagePostInstall(PackageInstalledInfo res, boolean killApp, boolean virtualPreload, boolean launchedForRestore, String installerPackage, IPackageInstallObserver2 installObserver, int dataLoaderType) { - boolean succeeded = res.returnCode == PackageManager.INSTALL_SUCCEEDED; - final boolean update = res.removedInfo != null && res.removedInfo.removedPackage != null; - final String packageName = res.name; + boolean succeeded = res.mReturnCode == PackageManager.INSTALL_SUCCEEDED; + final boolean update = res.mRemovedInfo != null && res.mRemovedInfo.mRemovedPackage != null; + final String packageName = res.mName; final PackageSetting pkgSetting = succeeded ? getPackageSetting(packageName) : null; final boolean removedBeforeUpdate = (pkgSetting == null) - || (pkgSetting.isSystem() && !pkgSetting.getPathString().equals(res.pkg.getPath())); + || (pkgSetting.isSystem() && !pkgSetting.getPathString().equals( + res.mPkg.getPath())); if (succeeded && removedBeforeUpdate) { Slog.e(TAG, packageName + " was removed before handlePackagePostInstall " + "could be executed"); - res.returnCode = INSTALL_FAILED_PACKAGE_CHANGED; - res.returnMsg = "Package was removed before install could complete."; + res.mReturnCode = INSTALL_FAILED_PACKAGE_CHANGED; + res.mReturnMsg = "Package was removed before install could complete."; // Remove the update failed package's older resources safely now - InstallArgs args = res.removedInfo != null ? res.removedInfo.args : null; + InstallArgs args = res.mRemovedInfo != null ? res.mRemovedInfo.mArgs : null; if (args != null) { synchronized (mInstallLock) { args.doPostDeleteLI(true); @@ -6220,19 +6108,19 @@ public class PackageManagerService extends IPackageManager.Stub mPerUidReadTimeoutsCache = null; // Send the removed broadcasts - if (res.removedInfo != null) { - res.removedInfo.sendPackageRemovedBroadcasts(killApp, false /*removedBySystem*/); + if (res.mRemovedInfo != null) { + res.mRemovedInfo.sendPackageRemovedBroadcasts(killApp, false /*removedBySystem*/); } final String installerPackageName = - res.installerPackageName != null - ? res.installerPackageName - : res.removedInfo != null - ? res.removedInfo.installerPackageName + res.mInstallerPackageName != null + ? res.mInstallerPackageName + : res.mRemovedInfo != null + ? res.mRemovedInfo.mInstallerPackageName : null; synchronized (mLock) { - mInstantAppRegistry.onPackageInstalledLPw(res.pkg, res.newUsers); + mInstantAppRegistry.onPackageInstalledLPw(res.mPkg, res.mNewUsers); } // Determine the set of users who are adding this package for @@ -6241,10 +6129,9 @@ public class PackageManagerService extends IPackageManager.Stub int[] firstInstantUserIds = EMPTY_INT_ARRAY; int[] updateUserIds = EMPTY_INT_ARRAY; int[] instantUserIds = EMPTY_INT_ARRAY; - final boolean allNewUsers = res.origUsers == null || res.origUsers.length == 0; - final PackageSetting ps = pkgSetting; - for (int newUser : res.newUsers) { - final boolean isInstantApp = ps.getInstantApp(newUser); + final boolean allNewUsers = res.mOrigUsers == null || res.mOrigUsers.length == 0; + for (int newUser : res.mNewUsers) { + final boolean isInstantApp = pkgSetting.getInstantApp(newUser); if (allNewUsers) { if (isInstantApp) { firstInstantUserIds = ArrayUtils.appendInt(firstInstantUserIds, newUser); @@ -6254,7 +6141,7 @@ public class PackageManagerService extends IPackageManager.Stub continue; } boolean isNew = true; - for (int origUser : res.origUsers) { + for (int origUser : res.mOrigUsers) { if (origUser == newUser) { isNew = false; break; @@ -6276,20 +6163,20 @@ public class PackageManagerService extends IPackageManager.Stub } // Send installed broadcasts if the package is not a static shared lib. - if (res.pkg.getStaticSharedLibName() == null) { - mProcessLoggingHandler.invalidateBaseApkHash(res.pkg.getBaseApkPath()); + if (res.mPkg.getStaticSharedLibName() == null) { + mProcessLoggingHandler.invalidateBaseApkHash(res.mPkg.getBaseApkPath()); // Send added for users that see the package for the first time // sendPackageAddedForNewUsers also deals with system apps - int appId = UserHandle.getAppId(res.uid); - boolean isSystem = res.pkg.isSystem(); + int appId = UserHandle.getAppId(res.mUid); + boolean isSystem = res.mPkg.isSystem(); sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload, virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds, dataLoaderType); // Send added for users that don't see the package for the first time Bundle extras = new Bundle(1); - extras.putInt(Intent.EXTRA_UID, res.uid); + extras.putInt(Intent.EXTRA_UID, res.mUid); if (update) { extras.putBoolean(Intent.EXTRA_REPLACING, true); } @@ -6299,7 +6186,7 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mLock) { newBroadcastAllowList = mAppsFilter.getVisibilityAllowList( - getPackageSettingInternal(res.name, Process.SYSTEM_UID), + getPackageSettingInternal(res.mName, Process.SYSTEM_UID), updateUserIds, mSettings.getPackagesLocked()); } sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, @@ -6337,7 +6224,7 @@ public class PackageManagerService extends IPackageManager.Stub sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, extras, 0 /*flags*/, null /*targetPackage*/, null /*finishedReceiver*/, - updateUserIds, instantUserIds, res.removedInfo.broadcastAllowList, + updateUserIds, instantUserIds, res.mRemovedInfo.mBroadcastAllowList, null); if (installerPackageName != null) { sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, @@ -6358,7 +6245,7 @@ public class PackageManagerService extends IPackageManager.Stub null /*broadcastAllowList*/, getTemporaryAppAllowlistBroadcastOptions(REASON_PACKAGE_REPLACED) .toBundle()); - } else if (launchedForRestore && !res.pkg.isSystem()) { + } else if (launchedForRestore && !res.mPkg.isSystem()) { // First-install and we did a restore, so we're responsible for the // first-launch broadcast. if (DEBUG_BACKUP) { @@ -6370,15 +6257,15 @@ public class PackageManagerService extends IPackageManager.Stub } // Send broadcast package appeared if external for all users - if (res.pkg.isExternalStorage()) { + if (res.mPkg.isExternalStorage()) { if (!update) { final StorageManager storage = mInjector.getSystemService( StorageManager.class); VolumeInfo volume = storage.findVolumeByUuid( - res.pkg.getStorageUuid().toString()); + res.mPkg.getStorageUuid().toString()); int packageExternalStorageType = - getPackageExternalStorageType(volume, res.pkg.isExternalStorage()); + getPackageExternalStorageType(volume, res.mPkg.isExternalStorage()); // If the package was installed externally, log it. if (packageExternalStorageType != StorageEnums.UNKNOWN) { FrameworkStatsLog.write( @@ -6387,17 +6274,16 @@ public class PackageManagerService extends IPackageManager.Stub } } if (DEBUG_INSTALL) { - Slog.i(TAG, "upgrading pkg " + res.pkg + " is external"); + Slog.i(TAG, "upgrading pkg " + res.mPkg + " is external"); } - final int[] uidArray = new int[]{res.pkg.getUid()}; + final int[] uidArray = new int[]{res.mPkg.getUid()}; ArrayList pkgList = new ArrayList<>(1); pkgList.add(packageName); sendResourcesChangedBroadcast(true, true, pkgList, uidArray, null); } - } else if (!ArrayUtils.isEmpty(res.libraryConsumers)) { // if static shared lib - int[] allUsers = mInjector.getUserManagerService().getUserIds(); - for (int i = 0; i < res.libraryConsumers.size(); i++) { - AndroidPackage pkg = res.libraryConsumers.get(i); + } else if (!ArrayUtils.isEmpty(res.mLibraryConsumers)) { // if static shared lib + for (int i = 0; i < res.mLibraryConsumers.size(); i++) { + AndroidPackage pkg = res.mLibraryConsumers.get(i); // send broadcast that all consumers of the static shared library have changed sendPackageChangedBroadcast(pkg.getPackageName(), false /* dontKillApp */, new ArrayList<>(Collections.singletonList(pkg.getPackageName())), @@ -6409,14 +6295,14 @@ public class PackageManagerService extends IPackageManager.Stub if (firstUserIds != null && firstUserIds.length > 0) { for (int userId : firstUserIds) { restorePermissionsAndUpdateRolesForNewUserInstall(packageName, - pkgSetting.getInstallReason(userId), userId); + userId); } } if (allNewUsers && !update) { - notifyPackageAdded(packageName, res.uid); + notifyPackageAdded(packageName, res.mUid); } else { - notifyPackageChanged(packageName, res.uid); + notifyPackageChanged(packageName, res.mUid); } // Log current value of "unknown sources" setting @@ -6424,7 +6310,7 @@ public class PackageManagerService extends IPackageManager.Stub getUnknownSourcesSettings()); // Remove the replaced package's older resources safely now - InstallArgs args = res.removedInfo != null ? res.removedInfo.args : null; + InstallArgs args = res.mRemovedInfo != null ? res.mRemovedInfo.mArgs : null; if (args != null) { if (!killApp) { // If we didn't kill the app, defer the deletion of code/resource files, since @@ -6483,7 +6369,7 @@ public class PackageManagerService extends IPackageManager.Stub } } - private void notifyInstallObserver(String packageName) { + void notifyInstallObserver(String packageName) { Pair pair = mNoKillInstallObservers.remove(packageName); @@ -6492,13 +6378,13 @@ public class PackageManagerService extends IPackageManager.Stub } } - private void notifyInstallObserver(PackageInstalledInfo info, + void notifyInstallObserver(PackageInstalledInfo info, IPackageInstallObserver2 installObserver) { if (installObserver != null) { try { Bundle extras = extrasForInstallResult(info); - installObserver.onPackageInstalled(info.name, info.returnCode, - info.returnMsg, extras); + installObserver.onPackageInstalled(info.mName, info.mReturnCode, + info.mReturnMsg, extras); } catch (RemoteException e) { Slog.i(TAG, "Observer no longer exists."); } @@ -6512,7 +6398,7 @@ public class PackageManagerService extends IPackageManager.Stub private void scheduleDeferredNoKillInstallObserver(PackageInstalledInfo info, IPackageInstallObserver2 observer) { - String packageName = info.pkg.getPackageName(); + String packageName = info.mPkg.getPackageName(); mNoKillInstallObservers.put(packageName, Pair.create(info, observer)); Message message = mHandler.obtainMessage(DEFERRED_NO_KILL_INSTALL_OBSERVER, packageName); mHandler.sendMessageDelayed(message, DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS); @@ -6617,7 +6503,7 @@ public class PackageManagerService extends IPackageManager.Stub return StorageEnums.UNKNOWN; } - private StorageEventListener mStorageListener = new StorageEventListener() { + private final StorageEventListener mStorageListener = new StorageEventListener() { @Override public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) { if (vol.type == VolumeInfo.TYPE_PRIVATE) { @@ -6671,19 +6557,19 @@ public class PackageManagerService extends IPackageManager.Stub Bundle extrasForInstallResult(PackageInstalledInfo res) { Bundle extras = null; - switch (res.returnCode) { + switch (res.mReturnCode) { case PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION: { extras = new Bundle(); extras.putString(PackageManager.EXTRA_FAILURE_EXISTING_PERMISSION, - res.origPermission); + res.mOrigPermission); extras.putString(PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE, - res.origPackage); + res.mOrigPackage); break; } case PackageManager.INSTALL_SUCCEEDED: { extras = new Bundle(); extras.putBoolean(Intent.EXTRA_REPLACING, - res.removedInfo != null && res.removedInfo.removedPackage != null); + res.mRemovedInfo != null && res.mRemovedInfo.mRemovedPackage != null); break; } } @@ -6872,7 +6758,7 @@ public class PackageManagerService extends IPackageManager.Stub * reasons. This simply requests that the copy takes place and awaits confirmation of its * completion. See platform/system/extras/cppreopt/ for the implementation of the actual copy. */ - private static void requestCopyPreoptedFiles(Injector injector) { + private static void requestCopyPreoptedFiles() { final int WAIT_TIME_MS = 100; final String CP_PREOPT_PROPERTY = "sys.cppreopt"; if (SystemProperties.getInt("ro.cp_system_other_odex", 0) == 1) { @@ -7047,7 +6933,6 @@ public class PackageManagerService extends IPackageManager.Stub mPackages.putAll(testParams.packages); mEnableFreeCacheV2 = testParams.enableFreeCacheV2; mSdkVersion = testParams.sdkVersion; - mSystemWrapper = testParams.systemWrapper; mAppInstallDir = testParams.appInstallDir; mAppLib32InstallDir = testParams.appLib32InstallDir; mIsEngBuild = testParams.isEngBuild; @@ -7077,7 +6962,6 @@ public class PackageManagerService extends IPackageManager.Stub LockGuard.installLock(mLock, LockGuard.INDEX_PACKAGES); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START, SystemClock.uptimeMillis()); - mSystemWrapper = injector.getSystemWrapper(); mContext = injector.getContext(); mFactoryTest = factoryTest; @@ -7260,7 +7144,7 @@ public class PackageManagerService extends IPackageManager.Stub mPermissionManager.readLegacyPermissionsTEMP(mSettings.mPermissions); if (!mOnlyCore && mFirstBoot) { - requestCopyPreoptedFiles(mInjector); + requestCopyPreoptedFiles(); } String customResolverActivityName = Resources.getSystem().getString( @@ -8142,7 +8026,7 @@ public class PackageManagerService extends IPackageManager.Stub } @GuardedBy("mLock") - private void updateInstantAppInstallerLocked(String modifiedPackage) { + void updateInstantAppInstallerLocked(String modifiedPackage) { // we're only interested in updating the installer appliction when 1) it's not // already set or 2) the modified package is the installer if (mInstantAppInstallerActivity != null @@ -8411,11 +8295,7 @@ public class PackageManagerService extends IPackageManager.Stub return null; } synchronized (mLock) { - final ComponentName instantAppResolver = getInstantAppResolverLPr(); - if (instantAppResolver == null) { - return null; - } - return instantAppResolver; + return getInstantAppResolverLPr(); } } @@ -8671,16 +8551,6 @@ public class PackageManagerService extends IPackageManager.Stub flags, filterCallingUid, userId); } - private boolean isComponentVisibleToInstantApp(@Nullable ComponentName component) { - return mComputer.isComponentVisibleToInstantApp(component); - } - - private boolean isComponentVisibleToInstantApp( - @Nullable ComponentName component, @ComponentType int type) { - return mComputer.isComponentVisibleToInstantApp( - component, type); - } - /** * Returns whether or not access to the application should be filtered. *

@@ -8999,14 +8869,13 @@ public class PackageManagerService extends IPackageManager.Stub if (freeBytesRequired > 0) { smInternal.freeCache(volumeUuid, freeBytesRequired); } - if (file.getUsableSpace() >= bytes) return; } else { try { mInstaller.freeCache(volumeUuid, bytes, 0, 0); } catch (InstallerException ignored) { } - if (file.getUsableSpace() >= bytes) return; } + if (file.getUsableSpace() >= bytes) return; throw new IOException("Failed to free " + bytes + " on storage device at " + file); } @@ -9020,7 +8889,6 @@ public class PackageManagerService extends IPackageManager.Stub final long now = System.currentTimeMillis(); synchronized (mLock) { - final int[] allUsers = mUserManager.getUserIds(); final int libCount = mSharedLibraries.size(); for (int i = 0; i < libCount; i++) { final WatchedLongSparseArray versionedLib @@ -9133,14 +9001,6 @@ public class PackageManagerService extends IPackageManager.Stub wantInstantApps, isImplicitImageCaptureIntentAndNotSetByDpc); } - private int updateFlagsForResolve(int flags, int userId, int callingUid, - boolean wantInstantApps, boolean onlyExposedExplicitly, - boolean isImplicitImageCaptureIntentAndNotSetByDpc) { - return mComputer.updateFlagsForResolve(flags, userId, callingUid, - wantInstantApps, onlyExposedExplicitly, - isImplicitImageCaptureIntentAndNotSetByDpc); - } - @Override public int getTargetSdkVersion(String packageName) { synchronized (mLock) { @@ -9560,7 +9420,7 @@ public class PackageManagerService extends IPackageManager.Stub } @GuardedBy("mLock") - private void updateSequenceNumberLP(PackageSetting pkgSetting, int[] userList) { + void updateSequenceNumberLP(PackageSetting pkgSetting, int[] userList) { for (int i = userList.length - 1; i >= 0; --i) { final int userId = userList[i]; SparseArray changedPackages = mChangedPackages.get(userId); @@ -9914,7 +9774,7 @@ public class PackageManagerService extends IPackageManager.Stub * external storage) is less than the version where package signatures * were updated, return true. */ - private boolean isCompatSignatureUpdateNeeded(AndroidPackage pkg) { + boolean isCompatSignatureUpdateNeeded(AndroidPackage pkg) { return isCompatSignatureUpdateNeeded(getSettingsVersionForPackage(pkg)); } @@ -9922,7 +9782,7 @@ public class PackageManagerService extends IPackageManager.Stub return ver.databaseVersion < DatabaseVersion.SIGNATURE_END_ENTITY; } - private boolean isRecoverSignatureUpdateNeeded(AndroidPackage pkg) { + boolean isRecoverSignatureUpdateNeeded(AndroidPackage pkg) { return isRecoverSignatureUpdateNeeded(getSettingsVersionForPackage(pkg)); } @@ -10295,7 +10155,7 @@ public class PackageManagerService extends IPackageManager.Stub userId); // Find any earlier preferred or last chosen entries and nuke them findPreferredActivityNotLocked( - intent, resolvedType, flags, query, 0, false, true, false, userId); + intent, resolvedType, flags, query, false, true, false, userId); // Add the new activity as the last chosen for this filter addPreferredActivity(filter, match, null, activity, false, userId, "Setting last chosen", false); @@ -10311,7 +10171,7 @@ public class PackageManagerService extends IPackageManager.Stub final List query = queryIntentActivitiesInternal(intent, resolvedType, flags, userId); return findPreferredActivityNotLocked( - intent, resolvedType, flags, query, 0, false, false, false, userId); + intent, resolvedType, flags, query, false, false, false, userId); } private void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj, @@ -10353,7 +10213,7 @@ public class PackageManagerService extends IPackageManager.Stub // If we have saved a preference for a preferred activity for // this Intent, use that. ResolveInfo ri = findPreferredActivityNotLocked(intent, resolvedType, - flags, query, r0.priority, true, false, debug, userId, queryMayBeFiltered); + flags, query, true, false, debug, userId, queryMayBeFiltered); if (ri != null) { return ri; } @@ -10530,17 +10390,17 @@ public class PackageManagerService extends IPackageManager.Stub } ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags, - List query, int priority, boolean always, + List query, boolean always, boolean removeMatches, boolean debug, int userId) { return findPreferredActivityNotLocked( - intent, resolvedType, flags, query, priority, always, removeMatches, debug, userId, + intent, resolvedType, flags, query, always, removeMatches, debug, userId, UserHandle.getAppId(Binder.getCallingUid()) >= Process.FIRST_APPLICATION_UID); } // TODO: handle preferred activities missing while user has amnesia /** must not hold {@link #mLock} */ ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags, - List query, int priority, boolean always, + List query, boolean always, boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) { if (Thread.holdsLock(mLock)) { Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() @@ -10848,16 +10708,6 @@ public class PackageManagerService extends IPackageManager.Stub filterCallingUid, userId, resolveForStart, allowDynamicSplits); } - private @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody( - Intent intent, String resolvedType, int flags, int filterCallingUid, int userId, - boolean resolveForStart, boolean allowDynamicSplits, String pkgName, - String instantAppPkgName) { - return mComputer.queryIntentActivitiesInternalBody( - intent, resolvedType, flags, filterCallingUid, userId, - resolveForStart, allowDynamicSplits, pkgName, - instantAppPkgName); - } - private static class CrossProfileDomainInfo { /* ResolveInfo for IntentForwarderActivity to send the intent to the other profile */ ResolveInfo resolveInfo; @@ -11981,7 +11831,7 @@ public class PackageManagerService extends IPackageManager.Stub return; } - clearAppProfilesLIF(pkg, UserHandle.USER_ALL); + clearAppProfilesLIF(pkg); if (DEBUG_INSTALL) { Slog.d(TAG, originalPkgSetting.name + " clear profile due to version change " @@ -12155,11 +12005,12 @@ public class PackageManagerService extends IPackageManager.Stub null, disabledPkgSetting /* pkgSetting */, null /* disabledPkgSetting */, null /* originalPkgSetting */, null, parseFlags, scanFlags, isPlatformPackage, user, null); - applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage, true); + applyPolicy(parsedPackage, scanFlags, mPlatformPackage, true); final ScanResult scanResult = scanPackageOnlyLI(request, mInjector, mFactoryTest, -1L); - if (scanResult.existingSettingCopied && scanResult.request.pkgSetting != null) { - scanResult.request.pkgSetting.updateFrom(scanResult.pkgSetting); + if (scanResult.mExistingSettingCopied + && scanResult.mRequest.mPkgSetting != null) { + scanResult.mRequest.mPkgSetting.updateFrom(scanResult.mPkgSetting); } } } @@ -12206,7 +12057,7 @@ public class PackageManagerService extends IPackageManager.Stub // for the package. Which means it needs to be finalized here to cache derived fields. // This is relevant for cases where the disabled system package is used for flags or // other metadata. - ((ParsedPackage) parsedPackage).hideAsFinal(); + parsedPackage.hideAsFinal(); throw new PackageManagerException(Log.WARN, "Package " + parsedPackage.getPackageName() + " at " + parsedPackage.getPath() + " ignored: updated version " + pkgSetting.versionCode + " better than this " @@ -12258,7 +12109,7 @@ public class PackageManagerService extends IPackageManager.Stub parsedPackage.getPackageName(), "scanPackageInternalLI")) { deletePackageLIF(parsedPackage.getPackageName(), null, true, - mUserManager.getUserIds(), 0, null, false, null); + mUserManager.getUserIds(), 0, null, false); } pkgSetting = null; } else if (newPkgVersionGreater) { @@ -12295,11 +12146,11 @@ public class PackageManagerService extends IPackageManager.Stub final ScanResult scanResult = scanPackageNewLI(parsedPackage, parseFlags, scanFlags | SCAN_UPDATE_SIGNATURE, currentTime, user, null); - if (scanResult.success) { + if (scanResult.mSuccess) { synchronized (mLock) { boolean appIdCreated = false; try { - final String pkgName = scanResult.pkgSetting.name; + final String pkgName = scanResult.mPkgSetting.name; final Map reconcileResult = reconcilePackagesLocked( new ReconcileRequest( Collections.singletonMap(pkgName, scanResult), @@ -12331,19 +12182,17 @@ public class PackageManagerService extends IPackageManager.Stub if (pkgSetting != null && pkgSetting.isPackageLoading()) { // Continue monitoring loading progress of active incremental packages final IncrementalStatesCallback incrementalStatesCallback = - new IncrementalStatesCallback(parsedPackage.getPackageName(), - UserHandle.getUid(UserHandle.USER_ALL, pkgSetting.appId), - getInstalledUsers(pkgSetting, UserHandle.USER_ALL)); + new IncrementalStatesCallback(parsedPackage.getPackageName(), this); pkgSetting.setIncrementalStatesCallback(incrementalStatesCallback); mIncrementalManager.registerLoadingProgressCallback(parsedPackage.getPath(), - new IncrementalProgressListener(parsedPackage.getPackageName())); + new IncrementalProgressListener(parsedPackage.getPackageName(), this)); } } - return scanResult.pkgSetting.pkg; + return scanResult.mPkgSetting.pkg; } // TODO:(b/135203078): Move to parsing - private static void renameStaticSharedLibraryPackage(ParsedPackage parsedPackage) { + static void renameStaticSharedLibraryPackage(ParsedPackage parsedPackage) { // Derive the new package synthetic package name parsedPackage.setPackageName(toStaticSharedLibraryPackageName( parsedPackage.getPackageName(), parsedPackage.getStaticSharedLibVersion())); @@ -12354,13 +12203,6 @@ public class PackageManagerService extends IPackageManager.Stub return packageName + STATIC_SHARED_LIB_DELIMITER + libraryVersion; } - static String fixProcessName(String defProcessName, String processName) { - if (processName == null) { - return defProcessName; - } - return processName; - } - /** * Enforces that only the system UID or root's UID can call a method exposed * via Binder. @@ -12402,24 +12244,6 @@ public class PackageManagerService extends IPackageManager.Stub requireFullPermission, checkShell, message); } - /** - * Enforces the request is from the system or an app that has INTERACT_ACROSS_USERS - * or INTERACT_ACROSS_USERS_FULL permissions, if the {@code userId} is not for the caller. - * - * @param checkShell whether to prevent shell from access if there's a debugging restriction - * @param requirePermissionWhenSameUser When {@code true}, still require the cross user - * permission to be held even if the callingUid and userId - * reference the same user. - * @param message the message to log on security exception - */ - private void enforceCrossUserPermission(int callingUid, @UserIdInt int userId, - boolean requireFullPermission, boolean checkShell, - boolean requirePermissionWhenSameUser, String message) { - mComputer.enforceCrossUserPermission(callingUid, userId, - requireFullPermission, checkShell, - requirePermissionWhenSameUser, message); - } - /** * Checks if the request is from the system or an app that has the appropriate cross-user * permissions defined as follows: @@ -12440,10 +12264,6 @@ public class PackageManagerService extends IPackageManager.Stub requireFullPermission, checkShell, message); } - private boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId) { - return mComputer.isSameProfileGroup(callerUserId, userId); - } - private static String buildInvalidCrossUserPermissionMessage(int callingUid, @UserIdInt int userId, String message, boolean requireFullPermission) { StringBuilder builder = new StringBuilder(); @@ -13095,7 +12915,7 @@ public class PackageManagerService extends IPackageManager.Stub return versionedLib.get(version); } - private SharedLibraryInfo getLatestSharedLibraVersionLPr(AndroidPackage pkg) { + SharedLibraryInfo getLatestSharedLibraVersionLPr(AndroidPackage pkg) { WatchedLongSparseArray versionedLib = mSharedLibraries.get( pkg.getStaticSharedLibName()); if (versionedLib == null) { @@ -13115,13 +12935,12 @@ public class PackageManagerService extends IPackageManager.Stub return null; } - @Nullable - private PackageSetting getSharedLibLatestVersionSetting(@NonNull ScanResult scanResult) { + PackageSetting getSharedLibLatestVersionSetting(@NonNull ScanResult scanResult) { PackageSetting sharedLibPackage = null; synchronized (mLock) { final SharedLibraryInfo latestSharedLibraVersionLPr = - getLatestSharedLibraVersionLPr(scanResult.request.parsedPackage); + getLatestSharedLibraVersionLPr(scanResult.mRequest.mParsedPackage); if (latestSharedLibraVersionLPr != null) { sharedLibPackage = mSettings.getPackageLPr( latestSharedLibraVersionLPr.getPackageName()); @@ -13261,18 +13080,18 @@ public class PackageManagerService extends IPackageManager.Stub cacher.cleanCachedResult(codePath); } - private int[] resolveUserIds(int userId) { + int[] resolveUserIds(int userId) { return (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[] { userId }; } - private void clearAppDataLIF(AndroidPackage pkg, int userId, int flags) { + void clearAppDataLIF(AndroidPackage pkg, int userId, int flags) { if (pkg == null) { return; } clearAppDataLeafLIF(pkg, userId, flags); if ((flags & Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES) == 0) { - clearAppProfilesLIF(pkg, UserHandle.USER_ALL); + clearAppProfilesLIF(pkg); } } @@ -13333,7 +13152,7 @@ public class PackageManagerService extends IPackageManager.Stub } } - private void clearAppProfilesLIF(AndroidPackage pkg, int userId) { + private void clearAppProfilesLIF(AndroidPackage pkg) { if (pkg == null) { Slog.wtf(TAG, "Package was null!", new Throwable()); return; @@ -13673,7 +13492,7 @@ public class PackageManagerService extends IPackageManager.Stub ? PackageManager.DELETE_KEEP_DATA : 0; deletePackageLIF(pkg.getPackageName(), null, true, mUserManager.getUserIds(), flags, null, - true, null); + true); } Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage()); } @@ -13697,7 +13516,7 @@ public class PackageManagerService extends IPackageManager.Stub } @GuardedBy({"mInstallLock", "mLock"}) - private ScanResult scanPackageTracedLI(ParsedPackage parsedPackage, + ScanResult scanPackageTracedLI(ParsedPackage parsedPackage, final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime, @Nullable UserHandle user, String cpuAbiOverride) throws PackageManagerException { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage"); @@ -13709,106 +13528,9 @@ public class PackageManagerService extends IPackageManager.Stub } } - /** The result of a package scan. */ - @VisibleForTesting - static class ScanResult { - /** The request that initiated the scan that produced this result. */ - public final ScanRequest request; - /** Whether or not the package scan was successful */ - public final boolean success; - /** - * Whether or not the original PackageSetting needs to be updated with this result on - * commit. - */ - public final boolean existingSettingCopied; - /** - * The final package settings. This may be the same object passed in - * the {@link ScanRequest}, but, with modified values. - */ - @Nullable public final PackageSetting pkgSetting; - /** ABI code paths that have changed in the package scan */ - @Nullable public final List changedAbiCodePath; - public final SharedLibraryInfo staticSharedLibraryInfo; - public final List dynamicSharedLibraryInfos; - public ScanResult( - ScanRequest request, boolean success, - @Nullable PackageSetting pkgSetting, - @Nullable List changedAbiCodePath, boolean existingSettingCopied, - SharedLibraryInfo staticSharedLibraryInfo, - List dynamicSharedLibraryInfos) { - this.request = request; - this.success = success; - this.pkgSetting = pkgSetting; - this.changedAbiCodePath = changedAbiCodePath; - this.existingSettingCopied = existingSettingCopied; - this.staticSharedLibraryInfo = staticSharedLibraryInfo; - this.dynamicSharedLibraryInfos = dynamicSharedLibraryInfos; - } - } - - /** A package to be scanned */ - @VisibleForTesting - static class ScanRequest { - /** The parsed package */ - @NonNull public final ParsedPackage parsedPackage; - /** The package this package replaces */ - @Nullable public final AndroidPackage oldPkg; - /** Shared user settings, if the package has a shared user */ - @Nullable public final SharedUserSetting sharedUserSetting; - /** - * Package settings of the currently installed version. - *

IMPORTANT: The contents of this object may be modified - * during scan. - */ - @Nullable public final PackageSetting pkgSetting; - /** A copy of the settings for the currently installed version */ - @Nullable public final PackageSetting oldPkgSetting; - /** Package settings for the disabled version on the /system partition */ - @Nullable public final PackageSetting disabledPkgSetting; - /** Package settings for the installed version under its original package name */ - @Nullable public final PackageSetting originalPkgSetting; - /** The real package name of a renamed application */ - @Nullable public final String realPkgName; - public final @ParseFlags int parseFlags; - public final @ScanFlags int scanFlags; - /** The user for which the package is being scanned */ - @Nullable public final UserHandle user; - /** Whether or not the platform package is being scanned */ - public final boolean isPlatformPackage; - /** Override value for package ABI if set during install */ - @Nullable - public final String cpuAbiOverride; - public ScanRequest( - @NonNull ParsedPackage parsedPackage, - @Nullable SharedUserSetting sharedUserSetting, - @Nullable AndroidPackage oldPkg, - @Nullable PackageSetting pkgSetting, - @Nullable PackageSetting disabledPkgSetting, - @Nullable PackageSetting originalPkgSetting, - @Nullable String realPkgName, - @ParseFlags int parseFlags, - @ScanFlags int scanFlags, - boolean isPlatformPackage, - @Nullable UserHandle user, - @Nullable String cpuAbiOverride) { - this.parsedPackage = parsedPackage; - this.oldPkg = oldPkg; - this.pkgSetting = pkgSetting; - this.sharedUserSetting = sharedUserSetting; - this.oldPkgSetting = pkgSetting == null ? null : new PackageSetting(pkgSetting); - this.disabledPkgSetting = disabledPkgSetting; - this.originalPkgSetting = originalPkgSetting; - this.realPkgName = realPkgName; - this.parseFlags = parseFlags; - this.scanFlags = scanFlags; - this.isPlatformPackage = isPlatformPackage; - this.user = user; - this.cpuAbiOverride = cpuAbiOverride; - } - } /** * Returns the actual scan flags depending upon the state of the other settings. @@ -13942,7 +13664,7 @@ public class PackageManagerService extends IPackageManager.Stub } else { isUpdatedSystemApp = disabledPkgSetting != null; } - applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage, isUpdatedSystemApp); + applyPolicy(parsedPackage, scanFlags, mPlatformPackage, isUpdatedSystemApp); assertPackageIsValid(parsedPackage, parseFlags, scanFlags); SharedUserSetting sharedUserSetting = null; @@ -13969,19 +13691,18 @@ public class PackageManagerService extends IPackageManager.Stub } } - /** * Prepares the system to commit a {@link ScanResult} in a way that will not fail by registering * the app ID required for reconcile. * @return {@code true} if a new app ID was registered and will need to be cleaned up on * failure. */ - private boolean optimisticallyRegisterAppId(@NonNull ScanResult result) + boolean optimisticallyRegisterAppId(@NonNull ScanResult result) throws PackageManagerException { - if (!result.existingSettingCopied) { + if (!result.mExistingSettingCopied) { // THROWS: when we can't allocate a user id. add call to check if there's // enough space to ensure we won't throw; otherwise, don't modify state - return mSettings.registerAppIdLPw(result.pkgSetting); + return mSettings.registerAppIdLPw(result.mPkgSetting); } return false; } @@ -13991,11 +13712,11 @@ public class PackageManagerService extends IPackageManager.Stub * {@link #optimisticallyRegisterAppId(ScanResult)}. Note: this is only necessary if the * referenced method returned true. */ - private void cleanUpAppIdCreation(@NonNull ScanResult result) { + void cleanUpAppIdCreation(@NonNull ScanResult result) { // iff we've acquired an app ID for a new package setting, remove it so that it can be // acquired by another request. - if (result.pkgSetting.appId > 0) { - mSettings.removeAppIdLPw(result.pkgSetting.appId); + if (result.mPkgSetting.appId > 0) { + mSettings.removeAppIdLPw(result.mPkgSetting.appId); } } @@ -14007,37 +13728,37 @@ public class PackageManagerService extends IPackageManager.Stub * possible and the system is not left in an inconsistent state. */ @GuardedBy({"mLock", "mInstallLock"}) - private AndroidPackage commitReconciledScanResultLocked( + AndroidPackage commitReconciledScanResultLocked( @NonNull ReconciledPackage reconciledPkg, int[] allUsers) { - final ScanResult result = reconciledPkg.scanResult; - final ScanRequest request = result.request; + final ScanResult result = reconciledPkg.mScanResult; + final ScanRequest request = result.mRequest; // TODO(b/135203078): Move this even further away - ParsedPackage parsedPackage = request.parsedPackage; + ParsedPackage parsedPackage = request.mParsedPackage; if ("android".equals(parsedPackage.getPackageName())) { // TODO(b/135203078): Move this to initial parse parsedPackage.setVersionCode(mSdkVersion) .setVersionCodeMajor(0); } - final AndroidPackage oldPkg = request.oldPkg; - final @ParseFlags int parseFlags = request.parseFlags; - final @ScanFlags int scanFlags = request.scanFlags; - final PackageSetting oldPkgSetting = request.oldPkgSetting; - final PackageSetting originalPkgSetting = request.originalPkgSetting; - final UserHandle user = request.user; - final String realPkgName = request.realPkgName; - final List changedAbiCodePath = result.changedAbiCodePath; + final AndroidPackage oldPkg = request.mOldPkg; + final @ParseFlags int parseFlags = request.mParseFlags; + final @ScanFlags int scanFlags = request.mScanFlags; + final PackageSetting oldPkgSetting = request.mOldPkgSetting; + final PackageSetting originalPkgSetting = request.mOriginalPkgSetting; + final UserHandle user = request.mUser; + final String realPkgName = request.mRealPkgName; + final List changedAbiCodePath = result.mChangedAbiCodePath; final PackageSetting pkgSetting; - if (request.pkgSetting != null && request.pkgSetting.sharedUser != null - && request.pkgSetting.sharedUser != result.pkgSetting.sharedUser) { + if (request.mPkgSetting != null && request.mPkgSetting.sharedUser != null + && request.mPkgSetting.sharedUser != result.mPkgSetting.sharedUser) { // shared user changed, remove from old shared user - request.pkgSetting.sharedUser.removePackage(request.pkgSetting); + request.mPkgSetting.sharedUser.removePackage(request.mPkgSetting); } - if (result.existingSettingCopied) { - pkgSetting = request.pkgSetting; - pkgSetting.updateFrom(result.pkgSetting); + if (result.mExistingSettingCopied) { + pkgSetting = request.mPkgSetting; + pkgSetting.updateFrom(result.mPkgSetting); } else { - pkgSetting = result.pkgSetting; + pkgSetting = result.mPkgSetting; if (originalPkgSetting != null) { mSettings.addRenamedPackageLPw(parsedPackage.getRealPackage(), originalPkgSetting.name); @@ -14049,14 +13770,15 @@ public class PackageManagerService extends IPackageManager.Stub if (pkgSetting.sharedUser != null) { pkgSetting.sharedUser.addPackage(pkgSetting); } - if (reconciledPkg.installArgs != null && reconciledPkg.installArgs.forceQueryableOverride) { + if (reconciledPkg.mInstallArgs != null + && reconciledPkg.mInstallArgs.mForceQueryableOverride) { pkgSetting.forceQueryableOverride = true; } // If this is part of a standard install, set the initiating package name, else rely on // previous device state. - if (reconciledPkg.installArgs != null) { - InstallSource installSource = reconciledPkg.installArgs.installSource; + if (reconciledPkg.mInstallArgs != null) { + InstallSource installSource = reconciledPkg.mInstallArgs.mInstallSource; if (installSource.initiatingPackageName != null) { final PackageSetting ips = mSettings.getPackageLPr( installSource.initiatingPackageName); @@ -14083,20 +13805,20 @@ public class PackageManagerService extends IPackageManager.Stub mTransferredPackages.add(pkg.getPackageName()); } - if (reconciledPkg.collectedSharedLibraryInfos != null) { + if (reconciledPkg.mCollectedSharedLibraryInfos != null) { executeSharedLibrariesUpdateLPr(pkg, pkgSetting, null, null, - reconciledPkg.collectedSharedLibraryInfos, allUsers); + reconciledPkg.mCollectedSharedLibraryInfos, allUsers); } final KeySetManagerService ksms = mSettings.getKeySetManagerService(); - if (reconciledPkg.removeAppKeySetData) { + if (reconciledPkg.mRemoveAppKeySetData) { ksms.removeAppKeySetDataLPw(pkg.getPackageName()); } - if (reconciledPkg.sharedUserSignaturesChanged) { + if (reconciledPkg.mSharedUserSignaturesChanged) { pkgSetting.sharedUser.signaturesChanged = Boolean.TRUE; - pkgSetting.sharedUser.signatures.mSigningDetails = reconciledPkg.signingDetails; + pkgSetting.sharedUser.signatures.mSigningDetails = reconciledPkg.mSigningDetails; } - pkgSetting.signatures.mSigningDetails = reconciledPkg.signingDetails; + pkgSetting.signatures.mSigningDetails = reconciledPkg.mSigningDetails; if (changedAbiCodePath != null && changedAbiCodePath.size() > 0) { for (int i = changedAbiCodePath.size() - 1; i >= 0; --i) { @@ -14285,7 +14007,6 @@ public class PackageManagerService extends IPackageManager.Stub } } - /** * Just scans the package without any side effects. *

Not entirely true at the moment. There is still one side effect -- this @@ -14306,17 +14027,16 @@ public class PackageManagerService extends IPackageManager.Stub boolean isUnderFactoryTest, long currentTime) throws PackageManagerException { final PackageAbiHelper packageAbiHelper = injector.getAbiHelper(); - final UserManagerInternal userManager = injector.getUserManagerInternal(); - ParsedPackage parsedPackage = request.parsedPackage; - PackageSetting pkgSetting = request.pkgSetting; - final PackageSetting disabledPkgSetting = request.disabledPkgSetting; - final PackageSetting originalPkgSetting = request.originalPkgSetting; - final @ParseFlags int parseFlags = request.parseFlags; - final @ScanFlags int scanFlags = request.scanFlags; - final String realPkgName = request.realPkgName; - final SharedUserSetting sharedUserSetting = request.sharedUserSetting; - final UserHandle user = request.user; - final boolean isPlatformPackage = request.isPlatformPackage; + ParsedPackage parsedPackage = request.mParsedPackage; + PackageSetting pkgSetting = request.mPkgSetting; + final PackageSetting disabledPkgSetting = request.mDisabledPkgSetting; + final PackageSetting originalPkgSetting = request.mOriginalPkgSetting; + final @ParseFlags int parseFlags = request.mParseFlags; + final @ScanFlags int scanFlags = request.mScanFlags; + final String realPkgName = request.mRealPkgName; + final SharedUserSetting sharedUserSetting = request.mSharedUserSetting; + final UserHandle user = request.mUser; + final boolean isPlatformPackage = request.mIsPlatformPackage; List changedAbiCodePath = null; @@ -14453,7 +14173,7 @@ public class PackageManagerService extends IPackageManager.Stub configurePackageComponents(parsedPackage); } - final String cpuAbiOverride = deriveAbiOverride(request.cpuAbiOverride); + final String cpuAbiOverride = deriveAbiOverride(request.mCpuAbiOverride); final boolean isUpdatedSystemApp = pkgSetting.getPkgState().isUpdatedSystemApp(); final File appLib32InstallDir = getAppLib32InstallDir(); @@ -14694,7 +14414,7 @@ public class PackageManagerService extends IPackageManager.Stub * Implementation detail: This method must NOT have any side effect. It would * ideally be static, but, it requires locks to read system state. */ - private static void applyPolicy(ParsedPackage parsedPackage, final @ParseFlags int parseFlags, + private static void applyPolicy(ParsedPackage parsedPackage, final @ScanFlags int scanFlags, AndroidPackage platformPkg, boolean isUpdatedSystemApp) { if ((scanFlags & SCAN_AS_SYSTEM) != 0) { @@ -14751,14 +14471,6 @@ public class PackageManagerService extends IPackageManager.Stub PackageBackwardCompatibility.modifySharedLibraries(parsedPackage, isUpdatedSystemApp); } - private static @NonNull T assertNotNull(@Nullable T object, String message) - throws PackageManagerException { - if (object == null) { - throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, message); - } - return object; - } - private void assertPackageProcesses(AndroidPackage pkg, List components, Map procs, String compName) @@ -15143,19 +14855,18 @@ public class PackageManagerService extends IPackageManager.Stub } @GuardedBy("mLock") - private boolean addBuiltInSharedLibraryLocked(SystemConfig.SharedLibraryEntry entry) { + private void addBuiltInSharedLibraryLocked(SystemConfig.SharedLibraryEntry entry) { if (nonStaticSharedLibExistsLocked(entry.name)) { - return false; + return; } SharedLibraryInfo libraryInfo = new SharedLibraryInfo(entry.filename, null, null, - entry.name, (long) SharedLibraryInfo.VERSION_UNDEFINED, + entry.name, SharedLibraryInfo.VERSION_UNDEFINED, SharedLibraryInfo.TYPE_BUILTIN, new VersionedPackage(PLATFORM_PACKAGE_NAME, (long)0), null, null, entry.isNative); commitSharedLibraryInfoLocked(libraryInfo); - return true; } @GuardedBy("mLock") @@ -15166,10 +14877,7 @@ public class PackageManagerService extends IPackageManager.Stub private static boolean sharedLibExists(final String name, final long version, Map> librarySource) { WatchedLongSparseArray versionedLib = librarySource.get(name); - if (versionedLib != null && versionedLib.indexOfKey(version) >= 0) { - return true; - } - return false; + return versionedLib != null && versionedLib.indexOfKey(version) >= 0; } @GuardedBy("mLock") @@ -15314,8 +15022,8 @@ public class PackageManagerService extends IPackageManager.Stub ArrayList clientLibPkgs = null; // writer synchronized (mLock) { - if (!ArrayUtils.isEmpty(reconciledPkg.allowedSharedLibraryInfos)) { - for (SharedLibraryInfo info : reconciledPkg.allowedSharedLibraryInfos) { + if (!ArrayUtils.isEmpty(reconciledPkg.mAllowedSharedLibraryInfos)) { + for (SharedLibraryInfo info : reconciledPkg.mAllowedSharedLibraryInfos) { commitSharedLibraryInfoLocked(info); } final Map combinedSigningDetails = @@ -15335,8 +15043,8 @@ public class PackageManagerService extends IPackageManager.Stub } } } - if (reconciledPkg.installResult != null) { - reconciledPkg.installResult.libraryConsumers = clientLibPkgs; + if (reconciledPkg.mInstallResult != null) { + reconciledPkg.mInstallResult.mLibraryConsumers = clientLibPkgs; } if ((scanFlags & SCAN_BOOTING) != 0) { @@ -15380,7 +15088,7 @@ public class PackageManagerService extends IPackageManager.Stub mComponentResolver.addAllComponents(pkg, chatty); final boolean isReplace = - reconciledPkg.prepareResult != null && reconciledPkg.prepareResult.replace; + reconciledPkg.mPrepareResult != null && reconciledPkg.mPrepareResult.mReplace; mAppsFilter.addPackage(pkgSetting, isReplace); mPackageProperty.addAllProperties(pkg); @@ -15490,7 +15198,7 @@ public class PackageManagerService extends IPackageManager.Stub killApplication(pkgName, appId, UserHandle.USER_ALL, reason); } - private void killApplication(String pkgName, @AppIdInt int appId, + void killApplication(String pkgName, @AppIdInt int appId, @UserIdInt int userId, String reason) { // Request the ActivityManager to kill the process(only for existing packages) // so that we do not end up in a confused state while the user is still using the older @@ -15509,7 +15217,7 @@ public class PackageManagerService extends IPackageManager.Stub } } - private void removePackageLI(AndroidPackage pkg, boolean chatty) { + void removePackageLI(AndroidPackage pkg, boolean chatty) { // Remove the parent package setting PackageSetting ps = getPackageSetting(pkg.getPackageName()); if (ps != null) { @@ -15615,10 +15323,10 @@ public class PackageManagerService extends IPackageManager.Stub } else { resolvedUserIds = userIds; } - doSendBroadcast(am, action, pkg, extras, flags, targetPkg, finishedReceiver, + doSendBroadcast(action, pkg, extras, flags, targetPkg, finishedReceiver, resolvedUserIds, false, broadcastAllowList, bOptions); if (instantUserIds != null && instantUserIds != EMPTY_INT_ARRAY) { - doSendBroadcast(am, action, pkg, extras, flags, targetPkg, finishedReceiver, + doSendBroadcast(action, pkg, extras, flags, targetPkg, finishedReceiver, instantUserIds, true, null, bOptions); } } catch (RemoteException ex) { @@ -15687,7 +15395,7 @@ public class PackageManagerService extends IPackageManager.Stub * the system and applications allowed to see instant applications to receive package * lifecycle events for instant applications. */ - private void doSendBroadcast(IActivityManager am, String action, String pkg, Bundle extras, + private void doSendBroadcast(String action, String pkg, Bundle extras, int flags, String targetPkg, IIntentReceiver finishedReceiver, int[] userIds, boolean isInstantApp, @Nullable SparseArray broadcastAllowList, @Nullable Bundle bOptions) { @@ -15728,109 +15436,6 @@ public class PackageManagerService extends IPackageManager.Stub } } - /** - * Check if the external storage media is available. This is true if there - * is a mounted external storage medium or if the external storage is - * emulated. - */ - private boolean isExternalMediaAvailable() { - return mMediaMounted || Environment.isExternalStorageEmulated(); - } - - /** - * Ensure that the install reason matches what we know about the package installer (e.g. whether - * it is acting on behalf on an enterprise or the user). - * - * Note that the ordering of the conditionals in this method is important. The checks we perform - * are as follows, in this order: - * - * 1) If the install is being performed by a system app, we can trust the app to have set the - * install reason correctly. Thus, we pass through the install reason unchanged, no matter - * what it is. - * 2) If the install is being performed by a device or profile owner app, the install reason - * should be enterprise policy. However, we cannot be sure that the device or profile owner - * set the install reason correctly. If the app targets an older SDK version where install - * reasons did not exist yet, or if the app author simply forgot, the install reason may be - * unset or wrong. Thus, we force the install reason to be enterprise policy. - * 3) In all other cases, the install is being performed by a regular app that is neither part - * of the system nor a device or profile owner. We have no reason to believe that this app is - * acting on behalf of the enterprise admin. Thus, we check whether the install reason was - * set to enterprise policy and if so, change it to unknown instead. - */ - private int fixUpInstallReason(String installerPackageName, int installerUid, - int installReason) { - if (checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, installerUid) - == PERMISSION_GRANTED) { - // If the install is being performed by a system app, we trust that app to have set the - // install reason correctly. - return installReason; - } - final String ownerPackage = mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage( - UserHandle.getUserId(installerUid)); - if (ownerPackage != null && ownerPackage.equals(installerPackageName)) { - // If the install is being performed by a device or profile owner, the install - // reason should be enterprise policy. - return PackageManager.INSTALL_REASON_POLICY; - } - - - if (installReason == PackageManager.INSTALL_REASON_POLICY) { - // If the install is being performed by a regular app (i.e. neither system app nor - // device or profile owner), we have no reason to believe that the app is acting on - // behalf of an enterprise. If the app set the install reason to enterprise policy, - // change it to unknown instead. - return PackageManager.INSTALL_REASON_UNKNOWN; - } - - // If the install is being performed by a regular app and the install reason was set to any - // value but enterprise policy, leave the install reason unchanged. - return installReason; - } - - void installStage(InstallParams params) { - final Message msg = mHandler.obtainMessage(INIT_COPY); - params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params)); - msg.obj = params; - - Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage", - System.identityHashCode(msg.obj)); - Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall", - System.identityHashCode(msg.obj)); - - mHandler.sendMessage(msg); - } - - void installStage(InstallParams parent, List children) - throws PackageManagerException { - final Message msg = mHandler.obtainMessage(INIT_COPY); - final MultiPackageInstallParams params = - new MultiPackageInstallParams(parent, children); - params.setTraceMethod("installStageMultiPackage") - .setTraceCookie(System.identityHashCode(params)); - msg.obj = params; - - Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStageMultiPackage", - System.identityHashCode(msg.obj)); - Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall", - System.identityHashCode(msg.obj)); - mHandler.sendMessage(msg); - } - - void verifyStage(VerificationParams params) { - mHandler.post(()-> { - params.startCopy(); - }); - } - - void verifyStage(VerificationParams parent, List children) - throws PackageManagerException { - final MultiPackageVerificationParams params = - new MultiPackageVerificationParams(parent, children); - mHandler.post(()-> { - params.startCopy(); - }); - } - private void sendPackageAddedForUser(String packageName, PackageSetting pkgSetting, int userId, int dataLoaderType) { final boolean isSystem = isSystemApp(pkgSetting) || isUpdatedSystemApp(pkgSetting); @@ -16075,11 +15680,11 @@ public class PackageManagerService extends IPackageManager.Stub private void sendApplicationHiddenForUser(String packageName, PackageSetting pkgSetting, int userId) { final PackageRemovedInfo info = new PackageRemovedInfo(this); - info.removedPackage = packageName; - info.installerPackageName = pkgSetting.installSource.installerPackageName; - info.removedUsers = new int[] {userId}; - info.broadcastUsers = new int[] {userId}; - info.uid = UserHandle.getUid(userId, pkgSetting.appId); + info.mRemovedPackage = packageName; + info.mInstallerPackageName = pkgSetting.installSource.installerPackageName; + info.mRemovedUsers = new int[] {userId}; + info.mBroadcastUsers = new int[] {userId}; + info.mUid = UserHandle.getUid(userId, pkgSetting.appId); info.sendPackageRemovedBroadcasts(true /*killApp*/, false /*removedBySystem*/); } @@ -16279,17 +15884,17 @@ public class PackageManagerService extends IPackageManager.Stub updateSequenceNumberLP(pkgSetting, new int[]{ userId }); } // start async restore with no post-install since we finish install here - PackageInstalledInfo res = - createPackageInstalledInfo(PackageManager.INSTALL_SUCCEEDED); - res.pkg = pkgSetting.pkg; - res.newUsers = new int[]{ userId }; + PackageInstalledInfo res = new PackageInstalledInfo( + PackageManager.INSTALL_SUCCEEDED); + res.mPkg = pkgSetting.pkg; + res.mNewUsers = new int[]{ userId }; PostInstallData postInstallData = new PostInstallData(null, res, () -> { restorePermissionsAndUpdateRolesForNewUserInstall(packageName, - pkgSetting.getInstallReason(userId), userId); + userId); if (intentSender != null) { - onRestoreComplete(res.returnCode, mContext, intentSender); + onRestoreComplete(res.mReturnCode, mContext, intentSender); } }); restoreAndPostInstall(userId, res, postInstallData); @@ -16564,7 +16169,7 @@ public class PackageManagerService extends IPackageManager.Stub } else { intentExtras = null; } - doSendBroadcast(am, action, null, intentExtras, + doSendBroadcast(action, null, intentExtras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, packageName, null, targetUserIds, false, null, null); } @@ -16864,7 +16469,7 @@ public class PackageManagerService extends IPackageManager.Stub } } - private void broadcastPackageVerified(int verificationId, Uri packageUri, + void broadcastPackageVerified(int verificationId, Uri packageUri, int verificationCode, @Nullable String rootHashString, int dataLoaderType, UserHandle user) { final Intent intent = new Intent(Intent.ACTION_PACKAGE_VERIFIED); @@ -16881,101 +16486,6 @@ public class PackageManagerService extends IPackageManager.Stub android.Manifest.permission.PACKAGE_VERIFICATION_AGENT); } - private ComponentName matchComponentForVerifier(String packageName, - List 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); - } - - private List matchVerifiers(PackageInfoLite pkgInfo, - List receivers, final PackageVerificationState verificationState) { - if (pkgInfo.verifiers.length == 0) { - return null; - } - - final int N = pkgInfo.verifiers.length; - final List 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 (mLock) { - final AndroidPackage pkg = 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 void setEnableRollbackCode(int token, int enableRollbackCode) { final Message msg = mHandler.obtainMessage(ENABLE_ROLLBACK_STATUS); msg.arg1 = token; @@ -17002,7 +16512,7 @@ public class PackageManagerService extends IPackageManager.Stub * * @return verification timeout in milliseconds */ - private long getVerificationTimeout() { + long getVerificationTimeout() { long timeout = Global.getLong(mContext.getContentResolver(), Global.PACKAGE_VERIFIER_TIMEOUT, DEFAULT_VERIFICATION_TIMEOUT); // The setting can be used to increase the timeout but not decrease it, since that is @@ -17010,18 +16520,6 @@ public class PackageManagerService extends IPackageManager.Stub return Math.max(timeout, DEFAULT_VERIFICATION_TIMEOUT); } - /** - * Get the integrity verification timeout. - * - * @return verification timeout in milliseconds - */ - private long getIntegrityVerificationTimeout() { - long timeout = Global.getLong(mContext.getContentResolver(), - 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); - } /** * Get the default verification agent response code. @@ -17046,65 +16544,6 @@ public class PackageManagerService extends IPackageManager.Stub return PackageManager.VERIFICATION_REJECT; } - /** - * 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 (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 (mLock) { - if (mSettings.getPackageLPr(pkgInfoLite.packageName) == null) { - // Always verify fresh install - return true; - } - } - // Only skip when apk is debuggable - return !pkgInfoLite.debuggable; - } - return Global.getInt(mContext.getContentResolver(), - 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 (mInstantAppInstallerActivity != null - && mInstantAppInstallerActivity.packageName.equals( - mRequiredVerifierPackage)) { - try { - mInjector.getSystemService(AppOpsManager.class) - .checkPackage(installerUid, mRequiredVerifierPackage); - if (DEBUG_VERIFY) { - Slog.i(TAG, "disable verification for instant app"); - } - return false; - } catch (SecurityException ignore) { } - } - } - return true; - } - - /** - * 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; - } - @Deprecated @Override public void verifyIntentFilter(int id, int verificationCode, List failedDomains) { @@ -17317,124 +16756,18 @@ public class PackageManagerService extends IPackageManager.Stub } } - // Queue up an async operation since the package installation may take a little while. - private void processInstallRequestsAsync(boolean success, - List installRequests) { - mHandler.post(() -> { - List apexInstallRequests = new ArrayList<>(); - List apkInstallRequests = new ArrayList<>(); - for (InstallRequest request : installRequests) { - if ((request.args.installFlags & PackageManager.INSTALL_APEX) != 0) { - apexInstallRequests.add(request); - } else { - apkInstallRequests.add(request); - } - } - // Note: supporting multi package install of both APEXes and APKs might requir some - // thinking to ensure atomicity of the install. - if (!apexInstallRequests.isEmpty() && !apkInstallRequests.isEmpty()) { - // This should've been caught at the validation step, but for some reason wasn't. - throw new IllegalStateException( - "Attempted to do a multi package install of both APEXes and APKs"); - } - if (!apexInstallRequests.isEmpty()) { - if (success) { - // Since installApexPackages requires talking to external service (apexd), we - // schedule to run it async. Once it finishes, it will resume the install. - Thread t = new Thread(() -> installApexPackagesTraced(apexInstallRequests), - "installApexPackages"); - t.start(); - } else { - // Non-staged APEX installation failed somewhere before - // processInstallRequestAsync. In that case just notify the observer about the - // failure. - InstallRequest request = apexInstallRequests.get(0); - notifyInstallObserver(request.installResult, request.args.observer); - } - return; - } - if (success) { - for (InstallRequest request : apkInstallRequests) { - request.args.doPreInstall(request.installResult.returnCode); - } - synchronized (mInstallLock) { - installPackagesTracedLI(apkInstallRequests); - } - for (InstallRequest request : apkInstallRequests) { - request.args.doPostInstall( - request.installResult.returnCode, request.installResult.uid); - } - } - for (InstallRequest request : apkInstallRequests) { - restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult, - new PostInstallData(request.args, request.installResult, null)); - } - }); - } - - private void installApexPackagesTraced(List requests) { - try { - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installApexPackages"); - installApexPackages(requests); - } finally { - Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); - } - } - - private void installApexPackages(List requests) { - if (requests.isEmpty()) { - return; - } - if (requests.size() != 1) { - throw new IllegalStateException( - "Only a non-staged install of a single APEX is supported"); - } - InstallRequest request = requests.get(0); - try { - // Should directory scanning logic be moved to ApexManager for better test coverage? - final File dir = request.args.origin.resolvedFile; - final File[] apexes = dir.listFiles(); - if (apexes == null) { - throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, - dir.getAbsolutePath() + " is not a directory"); - } - if (apexes.length != 1) { - throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, - "Expected exactly one .apex file under " + dir.getAbsolutePath() - + " got: " + apexes.length); - } - try (PackageParser2 packageParser = mInjector.getScanningPackageParser()) { - mApexManager.installPackage(apexes[0], packageParser); - } - } catch (PackageManagerException e) { - request.installResult.setError("APEX installation failed", e); - } - invalidatePackageInfoCache(); - notifyInstallObserver(request.installResult, request.args.observer); - } - - private PackageInstalledInfo createPackageInstalledInfo( - int currentStatus) { - PackageInstalledInfo res = new PackageInstalledInfo(); - res.setReturnCode(currentStatus); - res.uid = -1; - res.pkg = null; - res.removedInfo = null; - return res; - } - /** @param data Post-install is performed only if this is non-null. */ - private void restoreAndPostInstall( + void restoreAndPostInstall( int userId, PackageInstalledInfo res, @Nullable PostInstallData data) { if (DEBUG_INSTALL) { - Log.v(TAG, "restoreAndPostInstall userId=" + userId + " package=" + res.pkg); + Log.v(TAG, "restoreAndPostInstall userId=" + userId + " package=" + res.mPkg); } // A restore should be requested at this point if (a) the install // succeeded, (b) the operation is not an update. - final boolean update = res.removedInfo != null - && res.removedInfo.removedPackage != null; - boolean doRestore = !update && res.pkg != null; + final boolean update = res.mRemovedInfo != null + && res.mRemovedInfo.mRemovedPackage != null; + boolean doRestore = !update && res.mPkg != null; // Set up the post-install work request bookkeeping. This will be used // and cleaned up by the post-install event handling regardless of whether @@ -17450,13 +16783,13 @@ public class PackageManagerService extends IPackageManager.Stub if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token); - if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) { + if (res.mReturnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) { // Pass responsibility to the Backup Manager. It will perform a // restore if appropriate, then pass responsibility back to the // Package Manager to run the post-install observer callbacks // and broadcasts. - if (res.freezer != null) { - res.freezer.close(); + if (res.mFreezer != null) { + res.mFreezer.close(); } doRestore = performBackupManagerRestore(userId, token, res); } @@ -17466,7 +16799,7 @@ public class PackageManagerService extends IPackageManager.Stub // need to be snapshotted or restored for the package. // // TODO(narayan): Get this working for cases where userId == UserHandle.USER_ALL. - if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && !doRestore && update) { + if (res.mReturnCode == PackageManager.INSTALL_SUCCEEDED && !doRestore && update) { doRestore = performRollbackManagerRestore(userId, token, res, data); } @@ -17502,7 +16835,7 @@ public class PackageManagerService extends IPackageManager.Stub try { if (bm.isUserReadyForBackup(userId)) { bm.restoreAtInstallForUser( - userId, res.pkg.getPackageName(), token); + userId, res.mPkg.getPackageName(), token); } else { Slog.w(TAG, "User " + userId + " is not ready. Restore at install " + "didn't take place."); @@ -17529,7 +16862,7 @@ public class PackageManagerService extends IPackageManager.Stub PostInstallData data) { RollbackManagerInternal rm = mInjector.getLocalService(RollbackManagerInternal.class); - final String packageName = res.pkg.getPackageName(); + final String packageName = res.mPkg.getPackageName(); final int[] allUsers = mUserManager.getUserIds(); final int[] installedUsers; @@ -17549,11 +16882,11 @@ public class PackageManagerService extends IPackageManager.Stub } boolean doSnapshotOrRestore = data != null && data.args != null - && ((data.args.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0 - || (data.args.installFlags & PackageManager.INSTALL_REQUEST_DOWNGRADE) != 0); + && ((data.args.mInstallFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0 + || (data.args.mInstallFlags & PackageManager.INSTALL_REQUEST_DOWNGRADE) != 0); if (ps != null && doSnapshotOrRestore) { - final String seInfo = AndroidPackageUtils.getSeInfo(res.pkg, ps); + final String seInfo = AndroidPackageUtils.getSeInfo(res.mPkg, ps); rm.snapshotAndRestoreUserData(packageName, UserHandle.toUserHandles(installedUsers), appId, ceDataInode, seInfo, token); return true; @@ -17581,13 +16914,13 @@ public class PackageManagerService extends IPackageManager.Stub mHandler.post(() -> { for (int i = 0; i < mRunningInstalls.size(); i++) { final PostInstallData data = mRunningInstalls.valueAt(i); - if (data.res.returnCode != PackageManager.INSTALL_SUCCEEDED) { + if (data.res.mReturnCode != PackageManager.INSTALL_SUCCEEDED) { continue; } - if (packageName.equals(data.res.pkg.getPackageName())) { + if (packageName.equals(data.res.mPkg.getPackageName())) { // right package; but is it for the right user? - for (int uIndex = 0; uIndex < data.res.newUsers.length; uIndex++) { - if (userId == data.res.newUsers[uIndex]) { + for (int uIndex = 0; uIndex < data.res.mNewUsers.length; uIndex++) { + if (userId == data.res.mNewUsers[uIndex]) { if (DEBUG_BACKUP) { Slog.i(TAG, "Package " + packageName + " being restored so deferring FIRST_LAUNCH"); @@ -17614,1388 +16947,12 @@ public class PackageManagerService extends IPackageManager.Stub installerPkg, null, userIds, instantUserIds, null /* broadcastAllowList */, null); } - private abstract class HandlerParams { - /** User handle for the user requesting the information or installation. */ - private final UserHandle mUser; - String traceMethod; - int traceCookie; - - HandlerParams(UserHandle user) { - mUser = user; - } - - UserHandle getUser() { - return mUser; - } - - HandlerParams setTraceMethod(String traceMethod) { - this.traceMethod = traceMethod; - return this; - } - - HandlerParams setTraceCookie(int traceCookie) { - this.traceCookie = traceCookie; - return this; - } - - final void startCopy() { - if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this); - handleStartCopy(); - handleReturnCode(); - } - - abstract void handleStartCopy(); - abstract void handleReturnCode(); - } - - static 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 file; - - /** - * Flag indicating that {@link #file} has already been staged, meaning downstream users - * don't need to defensively copy the contents. - */ - final boolean staged; - - /** - * Flag indicating that {@link #file} is an already installed app that is being moved. - */ - final boolean existing; - - final String resolvedPath; - final File resolvedFile; - - static OriginInfo fromNothing() { - return new OriginInfo(null, false, false); - } - - static OriginInfo fromUntrustedFile(File file) { - return new OriginInfo(file, 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) { - this.file = file; - this.staged = staged; - this.existing = existing; - - if (file != null) { - resolvedPath = file.getAbsolutePath(); - resolvedFile = file; - } else { - resolvedPath = null; - resolvedFile = null; - } - } - } - - static class MoveInfo { - final int moveId; - final String fromUuid; - final String toUuid; - final String packageName; - final int appId; - final String seinfo; - final int targetSdkVersion; - final String fromCodePath; - - public MoveInfo(int moveId, String fromUuid, String toUuid, String packageName, - int appId, String seinfo, int targetSdkVersion, - String fromCodePath) { - this.moveId = moveId; - this.fromUuid = fromUuid; - this.toUuid = toUuid; - this.packageName = packageName; - this.appId = appId; - this.seinfo = seinfo; - this.targetSdkVersion = targetSdkVersion; - this.fromCodePath = fromCodePath; - } - } - - static class VerificationInfo { - /** A constant used to indicate that a uid value is not present. */ - public static final int NO_UID = -1; - - /** URI referencing where the package was downloaded from. */ - final Uri originatingUri; - - /** HTTP referrer URI associated with the originatingURI. */ - final Uri referrer; - - /** UID of the application that the install request originated from. */ - final int originatingUid; - - /** UID of application requesting the install */ - final int installerUid; - - VerificationInfo(Uri originatingUri, Uri referrer, int originatingUid, int installerUid) { - this.originatingUri = originatingUri; - this.referrer = referrer; - this.originatingUid = originatingUid; - this.installerUid = installerUid; - } - } - - /** - * Container for a multi-package install which refers to all install sessions and args being - * committed together. - */ - class MultiPackageInstallParams extends HandlerParams { - private final List mChildParams; - private final Map mCurrentState; - - MultiPackageInstallParams(InstallParams parent, List childParams) - throws PackageManagerException { - super(parent.getUser()); - if (childParams.size() == 0) { - throw new PackageManagerException("No child sessions found!"); - } - mChildParams = childParams; - for (int i = 0; i < childParams.size(); i++) { - final InstallParams childParam = childParams.get(i); - childParam.mParentInstallParams = this; - } - this.mCurrentState = new ArrayMap<>(mChildParams.size()); - } - - @Override - void handleStartCopy() { - for (InstallParams params : mChildParams) { - params.handleStartCopy(); - } - } - - @Override - void handleReturnCode() { - for (InstallParams params : mChildParams) { - params.handleReturnCode(); - } - } - - void tryProcessInstallRequest(InstallArgs args, int currentStatus) { - mCurrentState.put(args, currentStatus); - if (mCurrentState.size() != mChildParams.size()) { - return; - } - int completeStatus = PackageManager.INSTALL_SUCCEEDED; - for (Integer status : mCurrentState.values()) { - if (status == PackageManager.INSTALL_UNKNOWN) { - return; - } else if (status != PackageManager.INSTALL_SUCCEEDED) { - completeStatus = status; - break; - } - } - final List installRequests = new ArrayList<>(mCurrentState.size()); - for (Map.Entry entry : mCurrentState.entrySet()) { - installRequests.add(new InstallRequest(entry.getKey(), - createPackageInstalledInfo(completeStatus))); - } - processInstallRequestsAsync( - completeStatus == PackageManager.INSTALL_SUCCEEDED, - installRequests); - } - } - - class InstallParams extends HandlerParams { - final OriginInfo origin; - final MoveInfo move; - final IPackageInstallObserver2 observer; - int installFlags; - @NonNull final InstallSource installSource; - final String volumeUuid; - int mRet; - final String packageAbiOverride; - final String[] grantedRuntimePermissions; - final List whitelistedRestrictedPermissions; - final int autoRevokePermissionsMode; - final SigningDetails signingDetails; - final int installReason; - final int mInstallScenario; - @Nullable MultiPackageInstallParams mParentInstallParams; - final boolean forceQueryableOverride; - final int mDataLoaderType; - final long requiredInstalledVersionCode; - final PackageLite mPackageLite; - - InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer, - int installFlags, InstallSource installSource, String volumeUuid, - UserHandle user, String packageAbiOverride, PackageLite packageLite) { - super(user); - this.origin = origin; - this.move = move; - this.observer = observer; - this.installFlags = installFlags; - this.installSource = Preconditions.checkNotNull(installSource); - this.volumeUuid = volumeUuid; - this.packageAbiOverride = packageAbiOverride; - - this.grantedRuntimePermissions = null; - this.whitelistedRestrictedPermissions = null; - this.autoRevokePermissionsMode = MODE_DEFAULT; - this.signingDetails = SigningDetails.UNKNOWN; - this.installReason = PackageManager.INSTALL_REASON_UNKNOWN; - this.mInstallScenario = PackageManager.INSTALL_SCENARIO_DEFAULT; - this.forceQueryableOverride = false; - this.mDataLoaderType = DataLoaderType.NONE; - this.requiredInstalledVersionCode = PackageManager.VERSION_CODE_HIGHEST; - this.mPackageLite = packageLite; - } - - InstallParams(File stagedDir, IPackageInstallObserver2 observer, - PackageInstaller.SessionParams sessionParams, InstallSource installSource, - UserHandle user, SigningDetails signingDetails, int installerUid, - PackageLite packageLite) { - super(user); - origin = OriginInfo.fromStagedFile(stagedDir); - move = null; - installReason = fixUpInstallReason( - installSource.installerPackageName, installerUid, sessionParams.installReason); - mInstallScenario = sessionParams.installScenario; - this.observer = observer; - installFlags = sessionParams.installFlags; - this.installSource = installSource; - volumeUuid = sessionParams.volumeUuid; - packageAbiOverride = sessionParams.abiOverride; - grantedRuntimePermissions = sessionParams.grantedRuntimePermissions; - whitelistedRestrictedPermissions = sessionParams.whitelistedRestrictedPermissions; - autoRevokePermissionsMode = sessionParams.autoRevokePermissionsMode; - this.signingDetails = signingDetails; - forceQueryableOverride = sessionParams.forceQueryableOverride; - mDataLoaderType = (sessionParams.dataLoaderParams != null) - ? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE; - requiredInstalledVersionCode = sessionParams.requiredInstalledVersionCode; - mPackageLite = packageLite; - } - - @Override - public String toString() { - return "InstallParams{" + Integer.toHexString(System.identityHashCode(this)) - + " file=" + origin.file + "}"; - } - - private int installLocationPolicy(PackageInfoLite pkgLite) { - String packageName = pkgLite.packageName; - int installLocation = pkgLite.installLocation; - // reader - synchronized (mLock) { - // Currently installed package which the new package is attempting to replace or - // null if no such package is installed. - AndroidPackage installedPkg = mPackages.get(packageName); - - if (installedPkg != null) { - if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) { - // Check for updated system application. - if (installedPkg.isSystem()) { - return PackageHelper.RECOMMEND_INSTALL_INTERNAL; - } else { - // If current upgrade specifies particular preference - if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) { - // Application explicitly specified internal. - return PackageHelper.RECOMMEND_INSTALL_INTERNAL; - } else if (installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) { - // App explictly prefers external. Let policy decide - } else { - // Prefer previous location - if (installedPkg.isExternalStorage()) { - return PackageHelper.RECOMMEND_INSTALL_EXTERNAL; - } - return PackageHelper.RECOMMEND_INSTALL_INTERNAL; - } - } - } else { - // Invalid install. Return error code - return PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS; - } - } - } - return pkgLite.recommendedInstallLocation; - } - - /** - * Override install location based on default policy if needed. - * - * Only {@link #installFlags} may mutate in this method. - * - * Only {@link PackageManager#INSTALL_INTERNAL} flag may mutate in - * {@link #installFlags} - */ - private int overrideInstallLocation(PackageInfoLite pkgLite) { - final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0; - if (DEBUG_INSTANT && ephemeral) { - Slog.v(TAG, "pkgLite for install: " + pkgLite); - } - - if (origin.staged) { - // If we're already staged, we've firmly committed to an install location - if (origin.file != null) { - installFlags |= PackageManager.INSTALL_INTERNAL; - } else { - throw new IllegalStateException("Invalid stage location"); - } - } else if (pkgLite.recommendedInstallLocation - == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) { - /* - * If we are not staged and have too little free space, try to free cache - * before giving up. - */ - // TODO: focus freeing disk space on the target device - final StorageManager storage = StorageManager.from(mContext); - final long lowThreshold = storage.getStorageLowBytes( - Environment.getDataDirectory()); - - final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize( - origin.resolvedPath, packageAbiOverride); - if (sizeBytes >= 0) { - try { - mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0); - pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext, - mPackageLite, origin.resolvedPath, installFlags, - packageAbiOverride); - } catch (InstallerException e) { - Slog.w(TAG, "Failed to free cache", e); - } - } - - /* - * The cache free must have deleted the file we downloaded to install. - * - * TODO: fix the "freeCache" call to not delete the file we care about. - */ - if (pkgLite.recommendedInstallLocation - == PackageHelper.RECOMMEND_FAILED_INVALID_URI) { - pkgLite.recommendedInstallLocation - = PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE; - } - } - - int ret = INSTALL_SUCCEEDED; - int loc = pkgLite.recommendedInstallLocation; - if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) { - ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; - } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) { - ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS; - } else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) { - ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) { - ret = PackageManager.INSTALL_FAILED_INVALID_APK; - } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) { - ret = PackageManager.INSTALL_FAILED_INVALID_URI; - } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) { - ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE; - } else { - // Override with defaults if needed. - loc = installLocationPolicy(pkgLite); - - final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0; - - if (!onInt) { - // Override install location with flags - if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) { - // Set the flag to install on external media. - installFlags &= ~PackageManager.INSTALL_INTERNAL; - } else { - // Make sure the flag for installing on external - // media is unset - installFlags |= PackageManager.INSTALL_INTERNAL; - } - } - } - return ret; - } - - /* - * Invoke remote method to get package information and install - * location values. Override install location based on default - * policy if needed and then create install arguments based - * on the install location. - */ - public void handleStartCopy() { - if ((installFlags & PackageManager.INSTALL_APEX) != 0) { - mRet = INSTALL_SUCCEEDED; - return; - } - PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext, - mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride); - - // For staged session, there is a delay between its verification and install. Device - // state can change within this delay and hence we need to re-verify certain conditions. - boolean isStaged = (installFlags & INSTALL_STAGED) != 0; - if (isStaged) { - Pair ret = verifyReplacingVersionCode( - pkgLite, requiredInstalledVersionCode, installFlags); - mRet = ret.first; - if (mRet != INSTALL_SUCCEEDED) { - return; - } - } - - mRet = overrideInstallLocation(pkgLite); - } - - @Override - void handleReturnCode() { - processPendingInstall(); - } - - private void processPendingInstall() { - InstallArgs args = createInstallArgs(this); - if (mRet == PackageManager.INSTALL_SUCCEEDED) { - mRet = args.copyApk(); - } - if (mRet == PackageManager.INSTALL_SUCCEEDED) { - F2fsUtils.releaseCompressedBlocks( - mContext.getContentResolver(), new File(args.getCodePath())); - } - if (mParentInstallParams != null) { - mParentInstallParams.tryProcessInstallRequest(args, mRet); - } else { - PackageInstalledInfo res = createPackageInstalledInfo(mRet); - processInstallRequestsAsync( - res.returnCode == PackageManager.INSTALL_SUCCEEDED, - Collections.singletonList(new InstallRequest(args, res))); - } - } - } - - /** - * Container for a multi-package install which refers to all install sessions and args being - * committed together. - */ - class MultiPackageVerificationParams extends HandlerParams { - private final IPackageInstallObserver2 mObserver; - private final List mChildParams; - private final Map mVerificationState; - - MultiPackageVerificationParams( - VerificationParams parent, - List 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; - } - this.mVerificationState = new ArrayMap<>(mChildParams.size()); - mObserver = parent.observer; - } - - @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."); - } - } - } - - class VerificationParams extends HandlerParams { - final OriginInfo origin; - final IPackageInstallObserver2 observer; - final int installFlags; - @NonNull final InstallSource installSource; - final String packageAbiOverride; - final VerificationInfo verificationInfo; - final SigningDetails signingDetails; - @Nullable MultiPackageVerificationParams mParentVerificationParams; - final long requiredInstalledVersionCode; - 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; - - VerificationParams(UserHandle user, File stagedDir, IPackageInstallObserver2 observer, - PackageInstaller.SessionParams sessionParams, InstallSource installSource, - int installerUid, SigningDetails signingDetails, int sessionId, PackageLite lite) { - super(user); - origin = OriginInfo.fromStagedFile(stagedDir); - this.observer = observer; - installFlags = sessionParams.installFlags; - this.installSource = installSource; - packageAbiOverride = sessionParams.abiOverride; - verificationInfo = new VerificationInfo( - sessionParams.originatingUri, - sessionParams.referrerUri, - sessionParams.originatingUid, - installerUid - ); - this.signingDetails = signingDetails; - requiredInstalledVersionCode = sessionParams.requiredInstalledVersionCode; - mDataLoaderType = (sessionParams.dataLoaderParams != null) - ? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE; - mSessionId = sessionId; - mPackageLite = lite; - } - - @Override - public String toString() { - return "InstallParams{" + Integer.toHexString(System.identityHashCode(this)) - + " file=" + origin.file + "}"; - } - - public void handleStartCopy() { - PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext, - mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride); - - Pair ret = verifyReplacingVersionCode( - pkgLite, requiredInstalledVersionCode, installFlags); - setReturnCode(ret.first, ret.second); - if (mRet != INSTALL_SUCCEEDED) { - return; - } - - // Perform package verification and enable rollback (unless we are simply moving the - // package). - if (!origin.existing) { - if ((installFlags & PackageManager.INSTALL_APEX) == 0) { - // TODO(b/182426975): treat APEX as APK when APK verification is concerned - sendApkVerificationRequest(pkgLite); - } - if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) { - sendEnableRollbackRequest(); - } - } - } - - void sendApkVerificationRequest(PackageInfoLite pkgLite) { - final int verificationId = mPendingVerificationToken++; - - PackageVerificationState verificationState = - new PackageVerificationState(this); - 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()) { - mPendingVerification.remove(verificationId); - } - } - - void sendEnableRollbackRequest() { - final int enableRollbackToken = mPendingEnableRollbackToken++; - Trace.asyncTraceBegin( - TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken); - 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); - - 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 = mHandler.obtainMessage(ENABLE_ROLLBACK_TIMEOUT); - msg.arg1 = enableRollbackToken; - msg.arg2 = mSessionId; - 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(origin.resolvedPath)), - 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(); - - 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 = - mHandler.obtainMessage(CHECK_PENDING_INTEGRITY_VERIFICATION); - msg.arg1 = verificationId; - 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; - } - - /** - * 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 = mRequiredVerifierPackage == null ? -1 - : getPackageUid(mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING, - verifierUser.getIdentifier()); - verificationState.setRequiredVerifierUid(requiredUid); - final int installerUid = - verificationInfo == null ? -1 : verificationInfo.installerUid; - final boolean isVerificationEnabled = isVerificationEnabled( - pkgLite, verifierUser.getIdentifier(), installFlags, installerUid); - final boolean isV4Signed = - (signingDetails.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 (!origin.existing - && 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(origin.resolvedPath)), - PACKAGE_MIME_TYPE); - verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - - // Query all live verifiers based on current user state - final List receivers = queryIntentReceiversInternal(verification, - PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier(), - false /*allowDynamicSplits*/); - - if (DEBUG_VERIFY) { - Slog.d(TAG, "Found " + receivers.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, installFlags); - - 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 sufficientVerifiers = matchVerifiers(pkgLite, - receivers, verificationState); - - DeviceIdleInternal idleController = - mInjector.getLocalService(DeviceIdleInternal.class); - final long idleDuration = 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); - mContext.sendBroadcastAsUser(sufficientIntent, verifierUser, - /* receiverPermission= */ null, - options.toBundle()); - } - } - } - - if (mRequiredVerifierPackage != null) { - final ComponentName requiredVerifierComponent = matchComponentForVerifier( - mRequiredVerifierPackage, receivers); - /* - * 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(), - mRequiredVerifierPackage, idleDuration, - verifierUser.getIdentifier(), false, - REASON_PACKAGE_VERIFIER, "package verifier"); - 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 = mHandler - .obtainMessage(CHECK_PENDING_VERIFICATION); - msg.arg1 = verificationId; - mHandler.sendMessageDelayed(msg, 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); - } - } - - void populateInstallerExtras(Intent intent) { - intent.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE, - installSource.initiatingPackageName); - - if (verificationInfo != null) { - if (verificationInfo.originatingUri != null) { - intent.putExtra(Intent.EXTRA_ORIGINATING_URI, - verificationInfo.originatingUri); - } - if (verificationInfo.referrer != null) { - intent.putExtra(Intent.EXTRA_REFERRER, - verificationInfo.referrer); - } - if (verificationInfo.originatingUid >= 0) { - intent.putExtra(Intent.EXTRA_ORIGINATING_UID, - verificationInfo.originatingUid); - } - if (verificationInfo.installerUid >= 0) { - intent.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID, - verificationInfo.installerUid); - } - } - } - - 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(ruhler) 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 { - observer.onPackageInstalled(null, mRet, mErrorMessage, - new Bundle()); - } catch (RemoteException e) { - Slog.i(TAG, "Observer no longer exists."); - } - } - } - } - - private InstallArgs createInstallArgs(InstallParams params) { - if (params.move != null) { - return new MoveInstallArgs(params); - } else { - return new FileInstallArgs(params); - } - } - /** * Create args that describe an existing installed package. Typically used * when cleaning up old installs, or used as a move source. */ - private InstallArgs createInstallArgsForExisting(String codePath, String[] instructionSets) { - return new FileInstallArgs(codePath, instructionSets); - } - - static abstract class InstallArgs { - /** @see InstallParams#origin */ - final OriginInfo origin; - /** @see InstallParams#move */ - final MoveInfo move; - - final IPackageInstallObserver2 observer; - // Always refers to PackageManager flags only - final int installFlags; - @NonNull final InstallSource installSource; - final String volumeUuid; - final UserHandle user; - final String abiOverride; - final String[] installGrantPermissions; - final List whitelistedRestrictedPermissions; - final int autoRevokePermissionsMode; - /** If non-null, drop an async trace when the install completes */ - final String traceMethod; - final int traceCookie; - final SigningDetails signingDetails; - final int installReason; - final int mInstallScenario; - final boolean forceQueryableOverride; - 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[] instructionSets; - - InstallArgs(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer, - int installFlags, InstallSource installSource, String volumeUuid, - UserHandle user, String[] instructionSets, - String abiOverride, String[] installGrantPermissions, - List whitelistedRestrictedPermissions, - int autoRevokePermissionsMode, - String traceMethod, int traceCookie, SigningDetails signingDetails, - int installReason, int installScenario, boolean forceQueryableOverride, - int dataLoaderType) { - this.origin = origin; - this.move = move; - this.installFlags = installFlags; - this.observer = observer; - this.installSource = Preconditions.checkNotNull(installSource); - this.volumeUuid = volumeUuid; - this.user = user; - this.instructionSets = instructionSets; - this.abiOverride = abiOverride; - this.installGrantPermissions = installGrantPermissions; - this.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions; - this.autoRevokePermissionsMode = autoRevokePermissionsMode; - this.traceMethod = traceMethod; - this.traceCookie = traceCookie; - this.signingDetails = signingDetails; - this.installReason = installReason; - this.mInstallScenario = installScenario; - this.forceQueryableOverride = forceQueryableOverride; - this.mDataLoaderType = dataLoaderType; - } - - /** New install */ - InstallArgs(InstallParams params) { - this(params.origin, params.move, params.observer, params.installFlags, - params.installSource, params.volumeUuid, - params.getUser(), null /*instructionSets*/, params.packageAbiOverride, - params.grantedRuntimePermissions, params.whitelistedRestrictedPermissions, - params.autoRevokePermissionsMode, - params.traceMethod, params.traceCookie, params.signingDetails, - params.installReason, params.mInstallScenario, params.forceQueryableOverride, - params.mDataLoaderType); - } - - 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 (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0; - } - - UserHandle getUser() { - return user; - } - } - - void removeDexFiles(List 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 { - mInstaller.rmdex(codePath, dexCodeInstructionSet); - } catch (InstallerException ignored) { - } - } - } - } - } - - /** - * Logic to handle installation of new applications, including copying - * and renaming logic. - */ - class FileInstallArgs extends InstallArgs { - private File codeFile; - private File resourceFile; - - // 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) { - 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); - this.codeFile = (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 (origin.staged) { - if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy"); - codeFile = origin.file; - return PackageManager.INSTALL_SUCCEEDED; - } - - try { - final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0; - final File tempDir = - mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral); - codeFile = tempDir; - } catch (IOException e) { - Slog.w(TAG, "Failed to create copy file: " + e); - return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - } - - int ret = PackageManagerServiceUtils.copyPackage( - origin.file.getAbsolutePath(), codeFile); - if (ret != PackageManager.INSTALL_SUCCEEDED) { - Slog.e(TAG, "Failed to copy package"); - return ret; - } - - final boolean isIncremental = isIncrementalPath(codeFile.getAbsolutePath()); - final File libraryRoot = new File(codeFile, LIB_DIR_NAME); - NativeLibraryHelper.Handle handle = null; - try { - handle = NativeLibraryHelper.Handle.create(codeFile); - ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot, - abiOverride, 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 = codeFile; - final File afterCodeFile = getNextCodePath(targetDir, parsedPackage.getPackageName()); - - if (DEBUG_INSTALL) Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile); - final boolean onIncremental = 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. - 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 - codeFile = 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 = (installFlags & INSTALL_STAGED) != 0; - if (isStagedInstall) { - return Environment.getDataAppDirectory(null); - } else { - return codeFile.getParentFile(); - } - } - - int doPostInstall(int status, int uid) { - if (status != PackageManager.INSTALL_SUCCEEDED) { - cleanUp(); - } - return status; - } - - @Override - String getCodePath() { - return (codeFile != null) ? codeFile.getAbsolutePath() : null; - } - - private boolean cleanUp() { - if (codeFile == null || !codeFile.exists()) { - return false; - } - removeCodePathLI(codeFile); - return true; - } - - void cleanUpResourcesLI() { - // Try enumerating all code paths before deleting - List allCodePaths = Collections.EMPTY_LIST; - if (codeFile != null && codeFile.exists()) { - final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); - final ParseResult result = ApkLiteParseUtils.parsePackageLite( - input.reset(), codeFile, /* flags */ 0); - if (result.isSuccess()) { - // Ignore error; we tried our best - allCodePaths = result.getResult().getAllApkPaths(); - } - } - - cleanUp(); - removeDexFiles(allCodePaths, instructionSets); - } - - boolean doPostDeleteLI(boolean delete) { - // XXX err, shouldn't we respect the delete flag? - cleanUpResourcesLI(); - return true; - } - } - - /** - * Logic to handle movement of existing installed applications. - */ - class MoveInstallArgs extends InstallArgs { - private File codeFile; - - /** New install */ - MoveInstallArgs(InstallParams params) { - super(params); - } - - int copyApk() { - if (DEBUG_INSTALL) Slog.d(TAG, "Moving " + move.packageName + " from " - + move.fromUuid + " to " + move.toUuid); - synchronized (mInstaller) { - try { - mInstaller.moveCompleteApp(move.fromUuid, move.toUuid, move.packageName, - move.appId, move.seinfo, move.targetSdkVersion, - move.fromCodePath); - } catch (InstallerException e) { - Slog.w(TAG, "Failed to move app", e); - return PackageManager.INSTALL_FAILED_INTERNAL_ERROR; - } - } - - final String toPathName = new File(move.fromCodePath).getName(); - codeFile = new File(Environment.getDataAppDirectory(move.toUuid), toPathName); - if (DEBUG_INSTALL) Slog.d(TAG, "codeFile after move is " + codeFile); - - return PackageManager.INSTALL_SUCCEEDED; - } - - int doPreInstall(int status) { - if (status != PackageManager.INSTALL_SUCCEEDED) { - cleanUp(move.toUuid); - } - return status; - } - - @Override - boolean doRename(int status, ParsedPackage parsedPackage) { - if (status != PackageManager.INSTALL_SUCCEEDED) { - cleanUp(move.toUuid); - return false; - } - - return true; - } - - int doPostInstall(int status, int uid) { - if (status == PackageManager.INSTALL_SUCCEEDED) { - cleanUp(move.fromUuid); - } else { - cleanUp(move.toUuid); - } - return status; - } - - @Override - String getCodePath() { - return (codeFile != null) ? codeFile.getAbsolutePath() : null; - } - - private boolean cleanUp(String volumeUuid) { - final String toPathName = new File(move.fromCodePath).getName(); - final File codeFile = new File(Environment.getDataAppDirectory(volumeUuid), - toPathName); - Slog.d(TAG, "Cleaning up " + move.packageName + " on " + volumeUuid); - final int[] userIds = mUserManager.getUserIds(); - synchronized (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 { - mInstaller.destroyAppData(volumeUuid, move.packageName, userId, flags, 0); - } catch (InstallerException e) { - Slog.w(TAG, String.valueOf(e)); - } - } - removeCodePathLI(codeFile); - } - return true; - } - - void cleanUpResourcesLI() { - throw new UnsupportedOperationException(); - } - - boolean doPostDeleteLI(boolean delete) { - throw new UnsupportedOperationException(); - } + InstallArgs createInstallArgsForExisting(String codePath, String[] instructionSets) { + return new FileInstallArgs(codePath, instructionSets, this); } /** @@ -19008,7 +16965,7 @@ public class PackageManagerService extends IPackageManager.Stub * directory. * @return File object for the directory that should hold the code files of {@code packageName}. */ - private File getNextCodePath(File targetDir, String packageName) { + static File getNextCodePath(File targetDir, String packageName) { SecureRandom random = new SecureRandom(); byte[] bytes = new byte[16]; File firstLevelDir; @@ -19023,54 +16980,6 @@ public class PackageManagerService extends IPackageManager.Stub return new File(firstLevelDir, packageName + "-" + suffix); } - static class PackageInstalledInfo { - String name; - int uid; - // The set of users that originally had this package installed. - int[] origUsers; - // The set of users that now have this package installed. - int[] newUsers; - AndroidPackage pkg; - int returnCode; - String returnMsg; - String installerPackageName; - PackageRemovedInfo removedInfo; - // The set of packages consuming this shared library or null if no consumers exist. - ArrayList libraryConsumers; - PackageFreezer freezer; - - public void setError(int code, String msg) { - setReturnCode(code); - setReturnMessage(msg); - Slog.w(TAG, msg); - } - - public void setError(String msg, PackageManagerException e) { - returnCode = e.error; - setReturnMessage(ExceptionUtils.getCompleteMessage(msg, e)); - Slog.w(TAG, msg, e); - } - - public void setReturnCode(int returnCode) { - this.returnCode = returnCode; - } - - private void setReturnMessage(String returnMsg) { - this.returnMsg = returnMsg; - } - - // In some error cases we want to convey more info back to the observer - String origPackage; - String origPermission; - } - - private static void updateDigest(MessageDigest digest, File file) throws IOException { - try (DigestInputStream digestStream = - new DigestInputStream(new FileInputStream(file), digest)) { - while (digestStream.read() != -1) {} // nothing to do; just plow through the file - } - } - private void removeNativeBinariesLI(PackageSetting ps) { if (ps != null) { NativeLibraryHelper.removeNativeBinariesLI(ps.legacyNativeLibraryPathString); @@ -19083,361 +16992,18 @@ public class PackageManagerService extends IPackageManager.Stub } @GuardedBy("mLock") - private boolean disableSystemPackageLPw(AndroidPackage oldPkg) { - return mSettings.disableSystemPackageLPw(oldPkg.getPackageName(), true); - } - - private void updateSettingsLI(AndroidPackage newPackage, InstallArgs installArgs, - int[] allUsers, PackageInstalledInfo res) { - updateSettingsInternalLI(newPackage, installArgs, allUsers, res); - } - - private void updateSettingsInternalLI(AndroidPackage pkg, InstallArgs installArgs, - int[] allUsers, PackageInstalledInfo res) { - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings"); - - final String pkgName = pkg.getPackageName(); - final int[] installedForUsers = res.origUsers; - final int installReason = installArgs.installReason; - InstallSource installSource = installArgs.installSource; - final String installerPackageName = installSource.installerPackageName; - - if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.getPath()); - synchronized (mLock) { - // For system-bundled packages, we assume that installing an upgraded version - // of the package implies that the user actually wants to run that new code, - // so we enable the package. - final PackageSetting ps = mSettings.getPackageLPr(pkgName); - final int userId = installArgs.user.getIdentifier(); - if (ps != null) { - if (pkg.isSystem()) { - if (DEBUG_INSTALL) { - Slog.d(TAG, "Implicitly enabling system package on upgrade: " + pkgName); - } - // Enable system package for requested users - if (res.origUsers != null) { - for (int origUserId : res.origUsers) { - if (userId == UserHandle.USER_ALL || userId == origUserId) { - ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, - origUserId, installerPackageName); - } - } - } - // Also convey the prior install/uninstall state - if (allUsers != null && installedForUsers != null) { - for (int currentUserId : allUsers) { - final boolean installed = ArrayUtils.contains( - installedForUsers, currentUserId); - if (DEBUG_INSTALL) { - Slog.d(TAG, " user " + currentUserId + " => " + installed); - } - ps.setInstalled(installed, currentUserId); - } - // these install state changes will be persisted in the - // upcoming call to mSettings.writeLPr(). - } - - if (allUsers != null) { - for (int currentUserId : allUsers) { - ps.resetOverrideComponentLabelIcon(currentUserId); - } - } - } - - // Retrieve the overlays for shared libraries of the package. - if (!ps.getPkgState().getUsesLibraryInfos().isEmpty()) { - for (SharedLibraryInfo sharedLib : ps.getPkgState().getUsesLibraryInfos()) { - for (int currentUserId : UserManagerService.getInstance().getUserIds()) { - if (!sharedLib.isDynamic()) { - // TODO(146804378): Support overlaying static shared libraries - continue; - } - final PackageSetting libPs = mSettings.getPackageLPr( - sharedLib.getPackageName()); - if (libPs == null) { - continue; - } - ps.setOverlayPathsForLibrary(sharedLib.getName(), - libPs.getOverlayPaths(currentUserId), currentUserId); - } - } - } - - // It's implied that when a user requests installation, they want the app to be - // installed and enabled. (This does not apply to USER_ALL, which here means only - // install on users for which the app is already installed). - if (userId != UserHandle.USER_ALL) { - ps.setInstalled(true, userId); - ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName); - } - - mSettings.addInstallerPackageNames(ps.installSource); - - // When replacing an existing package, preserve the original install reason for all - // users that had the package installed before. Similarly for uninstall reasons. - final Set previousUserIds = new ArraySet<>(); - if (res.removedInfo != null && res.removedInfo.installReasons != null) { - final int installReasonCount = res.removedInfo.installReasons.size(); - for (int i = 0; i < installReasonCount; i++) { - final int previousUserId = res.removedInfo.installReasons.keyAt(i); - final int previousInstallReason = res.removedInfo.installReasons.valueAt(i); - ps.setInstallReason(previousInstallReason, previousUserId); - previousUserIds.add(previousUserId); - } - } - if (res.removedInfo != null && res.removedInfo.uninstallReasons != null) { - for (int i = 0; i < res.removedInfo.uninstallReasons.size(); i++) { - final int previousUserId = res.removedInfo.uninstallReasons.keyAt(i); - final int previousReason = res.removedInfo.uninstallReasons.valueAt(i); - ps.setUninstallReason(previousReason, previousUserId); - } - } - - // Set install reason for users that are having the package newly installed. - final int[] allUsersList = mUserManager.getUserIds(); - if (userId == UserHandle.USER_ALL) { - // TODO(b/152629990): It appears that the package doesn't actually get newly - // installed in this case, so the installReason shouldn't get modified? - for (int currentUserId : allUsersList) { - if (!previousUserIds.contains(currentUserId)) { - ps.setInstallReason(installReason, currentUserId); - } - } - } else if (!previousUserIds.contains(userId)) { - ps.setInstallReason(installReason, userId); - } - - // TODO(b/169721400): generalize Incremental States and create a Callback object - // that can be used for all the packages. - final String codePath = ps.getPathString(); - if (IncrementalManager.isIncrementalPath(codePath) && mIncrementalManager != null) { - final IncrementalStatesCallback incrementalStatesCallback = - new IncrementalStatesCallback(ps.name, - UserHandle.getUid(userId, ps.appId), - getInstalledUsers(ps, userId)); - ps.setIncrementalStatesCallback(incrementalStatesCallback); - mIncrementalManager.registerLoadingProgressCallback(codePath, - new IncrementalProgressListener(ps.name)); - } - - // Ensure that the uninstall reason is UNKNOWN for users with the package installed. - for (int currentUserId : allUsersList) { - if (ps.getInstalled(currentUserId)) { - ps.setUninstallReason(UNINSTALL_REASON_UNKNOWN, currentUserId); - } - } - - mSettings.writeKernelMappingLPr(ps); - - final PermissionManagerServiceInternal.PackageInstalledParams.Builder - permissionParamsBuilder = - new PermissionManagerServiceInternal.PackageInstalledParams.Builder(); - final boolean grantPermissions = (installArgs.installFlags - & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0; - if (grantPermissions) { - final List grantedPermissions = - installArgs.installGrantPermissions != null - ? Arrays.asList(installArgs.installGrantPermissions) - : pkg.getRequestedPermissions(); - permissionParamsBuilder.setGrantedPermissions(grantedPermissions); - } - final boolean allowlistAllRestrictedPermissions = - (installArgs.installFlags - & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0; - final List allowlistedRestrictedPermissions = - allowlistAllRestrictedPermissions ? pkg.getRequestedPermissions() - : installArgs.whitelistedRestrictedPermissions; - if (allowlistedRestrictedPermissions != null) { - permissionParamsBuilder.setAllowlistedRestrictedPermissions( - allowlistedRestrictedPermissions); - } - final int autoRevokePermissionsMode = installArgs.autoRevokePermissionsMode; - permissionParamsBuilder.setAutoRevokePermissionsMode(autoRevokePermissionsMode); - mPermissionManager.onPackageInstalled(pkg, permissionParamsBuilder.build(), userId); - } - res.name = pkgName; - res.uid = pkg.getUid(); - res.pkg = pkg; - res.setReturnCode(PackageManager.INSTALL_SUCCEEDED); - //to update install status - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "writeSettings"); - writeSettingsLPrTEMP(); - Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); - } - - Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); - } - - private static class InstallRequest { - public final InstallArgs args; - public final PackageInstalledInfo installResult; - - private InstallRequest(InstallArgs args, PackageInstalledInfo res) { - this.args = args; - this.installResult = res; - } - } - - @GuardedBy("mInstallLock") - private void installPackagesTracedLI(List requests) { - try { - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages"); - installPackagesLI(requests); - } finally { - Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); - } - } - - /** - * Package state to commit to memory and disk after reconciliation has completed. - */ - private static class CommitRequest { - final Map reconciledPackages; - @NonNull - final int[] mAllUsers; - - private CommitRequest(Map reconciledPackages, - @NonNull int[] allUsers) { - this.reconciledPackages = reconciledPackages; - this.mAllUsers = allUsers; - } - } - - /** - * 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. - */ - private static class ReconcileRequest { - public final Map scannedPackages; - - public final Map allPackages; - public final Map> sharedLibrarySource; - public final Map installArgs; - public final Map installResults; - public final Map preparedPackages; - public final Map versionInfos; - public final Map lastStaticSharedLibSettings; - - private ReconcileRequest(Map scannedPackages, - Map installArgs, - Map installResults, - Map preparedPackages, - Map> sharedLibrarySource, - Map allPackages, - Map versionInfos, - Map lastStaticSharedLibSettings) { - this.scannedPackages = scannedPackages; - this.installArgs = installArgs; - this.installResults = installResults; - this.preparedPackages = preparedPackages; - this.sharedLibrarySource = sharedLibrarySource; - this.allPackages = allPackages; - this.versionInfos = versionInfos; - this.lastStaticSharedLibSettings = lastStaticSharedLibSettings; - } - - private ReconcileRequest(Map scannedPackages, - Map> sharedLibrarySource, - Map allPackages, - Map versionInfos, - Map lastStaticSharedLibSettings) { - this(scannedPackages, Collections.emptyMap(), Collections.emptyMap(), - Collections.emptyMap(), sharedLibrarySource, allPackages, versionInfos, - lastStaticSharedLibSettings); - } - } - private static 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()); - } - } - - /** - * 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. - */ - private static class ReconciledPackage { - public final ReconcileRequest request; - public final PackageSetting pkgSetting; - public final ScanResult scanResult; - // TODO: Remove install-specific details from the reconcile result - public final PackageInstalledInfo installResult; - @Nullable public final PrepareResult prepareResult; - @Nullable public final InstallArgs installArgs; - public final DeletePackageAction deletePackageAction; - public final List allowedSharedLibraryInfos; - public final SigningDetails signingDetails; - public final boolean sharedUserSignaturesChanged; - public ArrayList collectedSharedLibraryInfos; - public final boolean removeAppKeySetData; - - private ReconciledPackage(ReconcileRequest request, - InstallArgs installArgs, - PackageSetting pkgSetting, - PackageInstalledInfo installResult, - PrepareResult prepareResult, - ScanResult scanResult, - DeletePackageAction deletePackageAction, - List allowedSharedLibraryInfos, - SigningDetails signingDetails, - boolean sharedUserSignaturesChanged, - boolean removeAppKeySetData) { - this.request = request; - this.installArgs = installArgs; - this.pkgSetting = pkgSetting; - this.installResult = installResult; - this.prepareResult = prepareResult; - this.scanResult = scanResult; - this.deletePackageAction = deletePackageAction; - this.allowedSharedLibraryInfos = allowedSharedLibraryInfos; - this.signingDetails = signingDetails; - this.sharedUserSignaturesChanged = sharedUserSignaturesChanged; - this.removeAppKeySetData = 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. - */ - private Map getCombinedAvailablePackages() { - final ArrayMap combined = - new ArrayMap<>(request.allPackages.size() + request.scannedPackages.size()); - - combined.putAll(request.allPackages); - - for (ScanResult scanResult : request.scannedPackages.values()) { - combined.put(scanResult.pkgSetting.name, scanResult.request.parsedPackage); - } - - return combined; - } - } - - @GuardedBy("mLock") - private static Map reconcilePackagesLocked( + static Map reconcilePackagesLocked( final ReconcileRequest request, KeySetManagerService ksms, Injector injector) throws ReconcileFailure { - final Map scannedPackages = request.scannedPackages; + final Map scannedPackages = request.mScannedPackages; final Map result = new ArrayMap<>(scannedPackages.size()); // make a copy of the existing set of packages so we can combine them with incoming packages final ArrayMap combinedPackages = - new ArrayMap<>(request.allPackages.size() + scannedPackages.size()); + new ArrayMap<>(request.mAllPackages.size() + scannedPackages.size()); - combinedPackages.putAll(request.allPackages); + combinedPackages.putAll(request.mAllPackages); final Map> incomingSharedLibraries = new ArrayMap<>(); @@ -19446,12 +17012,12 @@ public class PackageManagerService extends IPackageManager.Stub final ScanResult scanResult = scannedPackages.get(installPackageName); // add / replace existing with incoming packages - combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.parsedPackage); + combinedPackages.put(scanResult.mPkgSetting.name, scanResult.mRequest.mParsedPackage); // in the first pass, we'll build up the set of incoming shared libraries final List allowedSharedLibInfos = - getAllowedSharedLibInfos(scanResult, request.sharedLibrarySource); - final SharedLibraryInfo staticLib = scanResult.staticSharedLibraryInfo; + getAllowedSharedLibInfos(scanResult, request.mSharedLibrarySource); + final SharedLibraryInfo staticLib = scanResult.mStaticSharedLibraryInfo; if (allowedSharedLibInfos != null) { for (SharedLibraryInfo info : allowedSharedLibInfos) { if (!addSharedLibraryToPackageVersionMap(incomingSharedLibraries, info)) { @@ -19462,9 +17028,9 @@ public class PackageManagerService extends IPackageManager.Stub } // the following may be null if we're just reconciling on boot (and not during install) - final InstallArgs installArgs = request.installArgs.get(installPackageName); - final PackageInstalledInfo res = request.installResults.get(installPackageName); - final PrepareResult prepareResult = request.preparedPackages.get(installPackageName); + final InstallArgs installArgs = request.mInstallArgs.get(installPackageName); + final PackageInstalledInfo res = request.mInstallResults.get(installPackageName); + final PrepareResult prepareResult = request.mPreparedPackages.get(installPackageName); final boolean isInstall = installArgs != null; if (isInstall && (res == null || prepareResult == null)) { throw new ReconcileFailure("Reconcile arguments are not balanced for " @@ -19473,12 +17039,12 @@ public class PackageManagerService extends IPackageManager.Stub final DeletePackageAction deletePackageAction; // we only want to try to delete for non system apps - if (isInstall && prepareResult.replace && !prepareResult.system) { - final boolean killApp = (scanResult.request.scanFlags & SCAN_DONT_KILL_APP) == 0; + if (isInstall && prepareResult.mReplace && !prepareResult.mSystem) { + final boolean killApp = (scanResult.mRequest.mScanFlags & SCAN_DONT_KILL_APP) == 0; final int deleteFlags = PackageManager.DELETE_KEEP_DATA | (killApp ? 0 : PackageManager.DELETE_DONT_KILL_APP); - deletePackageAction = mayDeletePackageLocked(res.removedInfo, - prepareResult.originalPs, prepareResult.disabledPs, + deletePackageAction = mayDeletePackageLocked(res.mRemovedInfo, + prepareResult.mOriginalPs, prepareResult.mDisabledPs, deleteFlags, null /* all users */); if (deletePackageAction == null) { throw new ReconcileFailure( @@ -19489,17 +17055,17 @@ public class PackageManagerService extends IPackageManager.Stub deletePackageAction = null; } - final int scanFlags = scanResult.request.scanFlags; - final int parseFlags = scanResult.request.parseFlags; - final ParsedPackage parsedPackage = scanResult.request.parsedPackage; + final int scanFlags = scanResult.mRequest.mScanFlags; + final int parseFlags = scanResult.mRequest.mParseFlags; + final ParsedPackage parsedPackage = scanResult.mRequest.mParsedPackage; - final PackageSetting disabledPkgSetting = scanResult.request.disabledPkgSetting; + final PackageSetting disabledPkgSetting = scanResult.mRequest.mDisabledPkgSetting; final PackageSetting lastStaticSharedLibSetting = - request.lastStaticSharedLibSettings.get(installPackageName); + request.mLastStaticSharedLibSettings.get(installPackageName); final PackageSetting signatureCheckPs = (prepareResult != null && lastStaticSharedLibSetting != null) ? lastStaticSharedLibSetting - : scanResult.pkgSetting; + : scanResult.mPkgSetting; boolean removeAppKeySetData = false; boolean sharedUserSignaturesChanged = false; SigningDetails signingDetails = null; @@ -19522,11 +17088,11 @@ public class PackageManagerService extends IPackageManager.Stub signingDetails = parsedPackage.getSigningDetails(); } else { try { - final VersionInfo versionInfo = request.versionInfos.get(installPackageName); + final VersionInfo versionInfo = request.mVersionInfos.get(installPackageName); final boolean compareCompat = isCompatSignatureUpdateNeeded(versionInfo); final boolean compareRecover = isRecoverSignatureUpdateNeeded(versionInfo); final boolean isRollback = installArgs != null - && installArgs.installReason == PackageManager.INSTALL_REASON_ROLLBACK; + && installArgs.mInstallReason == PackageManager.INSTALL_REASON_ROLLBACK; final boolean compatMatch = verifySignatures(signatureCheckPs, disabledPkgSetting, parsedPackage.getSigningDetails(), compareCompat, compareRecover, isRollback); @@ -19590,7 +17156,7 @@ public class PackageManagerService extends IPackageManager.Stub throw new ReconcileFailure( INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, "Signature mismatch for shared user: " - + scanResult.pkgSetting.sharedUser); + + scanResult.mPkgSetting.sharedUser); } else { // Treat mismatched signatures on system packages using a shared // UID as @@ -19600,7 +17166,7 @@ public class PackageManagerService extends IPackageManager.Stub "Signature mismatch on system package " + parsedPackage.getPackageName() + " for shared user " - + scanResult.pkgSetting.sharedUser); + + scanResult.mPkgSetting.sharedUser); } } @@ -19623,8 +17189,8 @@ public class PackageManagerService extends IPackageManager.Stub } result.put(installPackageName, - new ReconciledPackage(request, installArgs, scanResult.pkgSetting, - res, request.preparedPackages.get(installPackageName), scanResult, + new ReconciledPackage(request, installArgs, scanResult.mPkgSetting, + res, request.mPreparedPackages.get(installPackageName), scanResult, deletePackageAction, allowedSharedLibInfos, signingDetails, sharedUserSignaturesChanged, removeAppKeySetData)); } @@ -19638,15 +17204,15 @@ public class PackageManagerService extends IPackageManager.Stub // scan don't update any libs as we do this wholesale after all // apps are scanned to avoid dependency based scanning. final ScanResult scanResult = scannedPackages.get(installPackageName); - if ((scanResult.request.scanFlags & SCAN_BOOTING) != 0 - || (scanResult.request.parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) + if ((scanResult.mRequest.mScanFlags & SCAN_BOOTING) != 0 + || (scanResult.mRequest.mParseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0) { continue; } try { - result.get(installPackageName).collectedSharedLibraryInfos = - collectSharedLibraryInfos(scanResult.request.parsedPackage, - combinedPackages, request.sharedLibrarySource, + result.get(installPackageName).mCollectedSharedLibraryInfos = + collectSharedLibraryInfos(scanResult.mRequest.mParsedPackage, + combinedPackages, request.mSharedLibrarySource, incomingSharedLibraries, injector.getCompatibility()); } catch (PackageManagerException e) { @@ -19665,29 +17231,29 @@ public class PackageManagerService extends IPackageManager.Stub ScanResult scanResult, Map> existingSharedLibraries) { // Let's used the parsed package as scanResult.pkgSetting may be null - final ParsedPackage parsedPackage = scanResult.request.parsedPackage; - if (scanResult.staticSharedLibraryInfo == null - && scanResult.dynamicSharedLibraryInfos == null) { + final ParsedPackage parsedPackage = scanResult.mRequest.mParsedPackage; + if (scanResult.mStaticSharedLibraryInfo == null + && scanResult.mDynamicSharedLibraryInfos == null) { return null; } // Any app can add new static shared libraries - if (scanResult.staticSharedLibraryInfo != null) { - return Collections.singletonList(scanResult.staticSharedLibraryInfo); + if (scanResult.mStaticSharedLibraryInfo != null) { + return Collections.singletonList(scanResult.mStaticSharedLibraryInfo); } final boolean hasDynamicLibraries = parsedPackage.isSystem() - && scanResult.dynamicSharedLibraryInfos != null; + && scanResult.mDynamicSharedLibraryInfos != null; if (!hasDynamicLibraries) { return null; } - final boolean isUpdatedSystemApp = scanResult.pkgSetting.getPkgState() + final boolean isUpdatedSystemApp = scanResult.mPkgSetting.getPkgState() .isUpdatedSystemApp(); // We may not yet have disabled the updated package yet, so be sure to grab the // current setting if that's the case. final PackageSetting updatedSystemPs = isUpdatedSystemApp - ? scanResult.request.disabledPkgSetting == null - ? scanResult.request.oldPkgSetting - : scanResult.request.disabledPkgSetting + ? scanResult.mRequest.mDisabledPkgSetting == null + ? scanResult.mRequest.mOldPkgSetting + : scanResult.mRequest.mDisabledPkgSetting : null; if (isUpdatedSystemApp && (updatedSystemPs.pkg == null || updatedSystemPs.pkg.getLibraryNames() == null)) { @@ -19696,8 +17262,8 @@ public class PackageManagerService extends IPackageManager.Stub return null; } final ArrayList infos = - new ArrayList<>(scanResult.dynamicSharedLibraryInfos.size()); - for (SharedLibraryInfo info : scanResult.dynamicSharedLibraryInfos) { + new ArrayList<>(scanResult.mDynamicSharedLibraryInfos.size()); + for (SharedLibraryInfo info : scanResult.mDynamicSharedLibraryInfos) { final String name = info.getName(); if (isUpdatedSystemApp) { // New library entries can only be added through the @@ -19751,509 +17317,6 @@ public class PackageManagerService extends IPackageManager.Stub return true; } - @GuardedBy("mLock") - private void commitPackagesLocked(final CommitRequest request) { - // TODO: remove any expected failures from this method; this should only be able to fail due - // to unavoidable errors (I/O, etc.) - for (ReconciledPackage reconciledPkg : request.reconciledPackages.values()) { - final ScanResult scanResult = reconciledPkg.scanResult; - final ScanRequest scanRequest = scanResult.request; - final ParsedPackage parsedPackage = scanRequest.parsedPackage; - final String packageName = parsedPackage.getPackageName(); - final PackageInstalledInfo res = reconciledPkg.installResult; - - if (reconciledPkg.prepareResult.replace) { - AndroidPackage oldPackage = mPackages.get(packageName); - - // Set the update and install times - PackageSetting deletedPkgSetting = getPackageSetting(oldPackage.getPackageName()); - reconciledPkg.pkgSetting.firstInstallTime = deletedPkgSetting.firstInstallTime; - reconciledPkg.pkgSetting.lastUpdateTime = System.currentTimeMillis(); - - res.removedInfo.broadcastAllowList = mAppsFilter.getVisibilityAllowList( - reconciledPkg.pkgSetting, request.mAllUsers, mSettings.getPackagesLocked()); - if (reconciledPkg.prepareResult.system) { - // Remove existing system package - removePackageLI(oldPackage, true); - if (!disableSystemPackageLPw(oldPackage)) { - // We didn't need to disable the .apk as a current system package, - // which means we are replacing another update that is already - // installed. We need to make sure to delete the older one's .apk. - res.removedInfo.args = createInstallArgsForExisting( - oldPackage.getPath(), - getAppDexInstructionSets( - AndroidPackageUtils.getPrimaryCpuAbi(oldPackage, - deletedPkgSetting), - AndroidPackageUtils.getSecondaryCpuAbi(oldPackage, - deletedPkgSetting))); - } else { - res.removedInfo.args = null; - } - } else { - try { - // Settings will be written during the call to updateSettingsLI(). - executeDeletePackageLIF(reconciledPkg.deletePackageAction, packageName, - true, request.mAllUsers, false, parsedPackage); - } catch (SystemDeleteException e) { - if (mIsEngBuild) { - throw new RuntimeException("Unexpected failure", e); - // ignore; not possible for non-system app - } - } - // Successfully deleted the old package; proceed with replace. - - // If deleted package lived in a container, give users a chance to - // relinquish resources before killing. - if (oldPackage.isExternalStorage()) { - if (DEBUG_INSTALL) { - Slog.i(TAG, "upgrading pkg " + oldPackage - + " is ASEC-hosted -> UNAVAILABLE"); - } - final int[] uidArray = new int[]{oldPackage.getUid()}; - final ArrayList pkgList = new ArrayList<>(1); - pkgList.add(oldPackage.getPackageName()); - sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null); - } - - // Update the in-memory copy of the previous code paths. - PackageSetting ps1 = mSettings.getPackageLPr( - reconciledPkg.prepareResult.existingPackage.getPackageName()); - if ((reconciledPkg.installArgs.installFlags & PackageManager.DONT_KILL_APP) - == 0) { - if (ps1.mOldCodePaths == null) { - ps1.mOldCodePaths = new ArraySet<>(); - } - Collections.addAll(ps1.mOldCodePaths, oldPackage.getBaseApkPath()); - if (oldPackage.getSplitCodePaths() != null) { - Collections.addAll(ps1.mOldCodePaths, oldPackage.getSplitCodePaths()); - } - } else { - ps1.mOldCodePaths = null; - } - - if (reconciledPkg.installResult.returnCode - == PackageManager.INSTALL_SUCCEEDED) { - PackageSetting ps2 = mSettings.getPackageLPr( - parsedPackage.getPackageName()); - if (ps2 != null) { - res.removedInfo.removedForAllUsers = mPackages.get(ps2.name) == null; - } - } - } - } - - AndroidPackage pkg = commitReconciledScanResultLocked(reconciledPkg, request.mAllUsers); - updateSettingsLI(pkg, reconciledPkg.installArgs, request.mAllUsers, res); - - final PackageSetting ps = mSettings.getPackageLPr(packageName); - if (ps != null) { - res.newUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true); - ps.setUpdateAvailable(false /*updateAvailable*/); - } - if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { - updateSequenceNumberLP(ps, res.newUsers); - updateInstantAppInstallerLocked(packageName); - } - } - ApplicationPackageManager.invalidateGetPackagesForUidCache(); - } - - /** - * Installs one or more packages atomically. This operation is broken up into four phases: - *

    - *
  • Prepare - *
    Analyzes any current install state, parses the package and does initial - * validation on it.
  • - *
  • Scan - *
    Interrogates the parsed packages given the context collected in prepare.
  • - *
  • Reconcile - *
    Validates scanned packages in the context of each other and the current system - * state to ensure that the install will be successful. - *
  • Commit - *
    Commits all scanned packages and updates system state. This is the only place - * that system state may be modified in the install flow and all predictable errors - * must be determined before this phase.
  • - *
- * - * Failure at any phase will result in a full failure to install all packages. - */ - @GuardedBy("mInstallLock") - private void installPackagesLI(List requests) { - final Map preparedScans = new ArrayMap<>(requests.size()); - final Map installArgs = new ArrayMap<>(requests.size()); - final Map installResults = new ArrayMap<>(requests.size()); - final Map prepareResults = new ArrayMap<>(requests.size()); - final Map versionInfos = new ArrayMap<>(requests.size()); - final Map lastStaticSharedLibSettings = - new ArrayMap<>(requests.size()); - final Map createdAppId = new ArrayMap<>(requests.size()); - boolean success = false; - try { - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI"); - for (InstallRequest request : requests) { - // TODO(b/109941548): remove this once we've pulled everything from it and into - // scan, reconcile or commit. - final PrepareResult prepareResult; - try { - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage"); - prepareResult = - preparePackageLI(request.args, request.installResult); - } catch (PrepareFailure prepareFailure) { - request.installResult.setError(prepareFailure.error, - prepareFailure.getMessage()); - request.installResult.origPackage = prepareFailure.conflictingPackage; - request.installResult.origPermission = prepareFailure.conflictingPermission; - return; - } finally { - Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); - } - request.installResult.setReturnCode(PackageManager.INSTALL_SUCCEEDED); - request.installResult.installerPackageName = - request.args.installSource.installerPackageName; - - final String packageName = prepareResult.packageToScan.getPackageName(); - prepareResults.put(packageName, prepareResult); - installResults.put(packageName, request.installResult); - installArgs.put(packageName, request.args); - try { - final ScanResult result = scanPackageTracedLI( - prepareResult.packageToScan, prepareResult.parseFlags, - prepareResult.scanFlags, System.currentTimeMillis(), - request.args.user, request.args.abiOverride); - if (null != preparedScans.put(result.pkgSetting.pkg.getPackageName(), result)) { - request.installResult.setError( - PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE, - "Duplicate package " + result.pkgSetting.pkg.getPackageName() - + " in multi-package install request."); - return; - } - createdAppId.put(packageName, optimisticallyRegisterAppId(result)); - versionInfos.put(result.pkgSetting.pkg.getPackageName(), - getSettingsVersionForPackage(result.pkgSetting.pkg)); - if (result.staticSharedLibraryInfo != null) { - final PackageSetting sharedLibLatestVersionSetting = - getSharedLibLatestVersionSetting(result); - if (sharedLibLatestVersionSetting != null) { - lastStaticSharedLibSettings.put(result.pkgSetting.pkg.getPackageName(), - sharedLibLatestVersionSetting); - } - } - } catch (PackageManagerException e) { - request.installResult.setError("Scanning Failed.", e); - return; - } - } - ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs, - installResults, - prepareResults, - mSharedLibraries, - Collections.unmodifiableMap(mPackages), versionInfos, - lastStaticSharedLibSettings); - CommitRequest commitRequest = null; - synchronized (mLock) { - Map reconciledPackages; - try { - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages"); - reconciledPackages = reconcilePackagesLocked( - reconcileRequest, mSettings.getKeySetManagerService(), mInjector); - } catch (ReconcileFailure e) { - for (InstallRequest request : requests) { - request.installResult.setError("Reconciliation failed...", e); - } - return; - } finally { - Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); - } - try { - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages"); - commitRequest = new CommitRequest(reconciledPackages, - mUserManager.getUserIds()); - commitPackagesLocked(commitRequest); - success = true; - } finally { - Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); - } - } - executePostCommitSteps(commitRequest); - } finally { - if (success) { - for (InstallRequest request : requests) { - final InstallArgs args = request.args; - if (args.mDataLoaderType != DataLoaderType.INCREMENTAL) { - continue; - } - if (args.signingDetails.getSignatureSchemeVersion() != SIGNING_BLOCK_V4) { - continue; - } - // For incremental installs, we bypass the verifier prior to install. Now - // that we know the package is valid, send a notice to the verifier with - // the root hash of the base.apk. - final String baseCodePath = request.installResult.pkg.getBaseApkPath(); - final String[] splitCodePaths = request.installResult.pkg.getSplitCodePaths(); - final Uri originUri = Uri.fromFile(args.origin.resolvedFile); - final int verificationId = mPendingVerificationToken++; - final String rootHashString = PackageManagerServiceUtils - .buildVerificationRootHashString(baseCodePath, splitCodePaths); - broadcastPackageVerified(verificationId, originUri, - PackageManager.VERIFICATION_ALLOW, rootHashString, - args.mDataLoaderType, args.getUser()); - } - } else { - for (ScanResult result : preparedScans.values()) { - if (createdAppId.getOrDefault(result.request.parsedPackage.getPackageName(), - false)) { - cleanUpAppIdCreation(result); - } - } - // TODO(patb): create a more descriptive reason than unknown in future release - // mark all non-failure installs as UNKNOWN so we do not treat them as success - for (InstallRequest request : requests) { - if (request.installResult.freezer != null) { - request.installResult.freezer.close(); - } - if (request.installResult.returnCode == PackageManager.INSTALL_SUCCEEDED) { - request.installResult.returnCode = PackageManager.INSTALL_UNKNOWN; - } - } - } - Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); - } - } - - /** - * On successful install, executes remaining steps after commit completes and the package lock - * is released. These are typically more expensive or require calls to installd, which often - * locks on {@link #mLock}. - */ - private void executePostCommitSteps(CommitRequest commitRequest) { - final ArraySet incrementalStorages = new ArraySet<>(); - for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) { - final boolean instantApp = ((reconciledPkg.scanResult.request.scanFlags - & PackageManagerService.SCAN_AS_INSTANT_APP) != 0); - final AndroidPackage pkg = reconciledPkg.pkgSetting.pkg; - final String packageName = pkg.getPackageName(); - final String codePath = pkg.getPath(); - final boolean onIncremental = mIncrementalManager != null - && isIncrementalPath(codePath); - if (onIncremental) { - IncrementalStorage storage = mIncrementalManager.openStorage(codePath); - if (storage == null) { - throw new IllegalArgumentException( - "Install: null storage for incremental package " + packageName); - } - incrementalStorages.add(storage); - } - prepareAppDataAfterInstallLIF(pkg); - if (reconciledPkg.prepareResult.clearCodeCache) { - clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE - | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY); - } - if (reconciledPkg.prepareResult.replace) { - mDexManager.notifyPackageUpdated(pkg.getPackageName(), - pkg.getBaseApkPath(), pkg.getSplitCodePaths()); - } - - // Prepare the application profiles for the new code paths. - // This needs to be done before invoking dexopt so that any install-time profile - // can be used for optimizations. - mArtManagerService.prepareAppProfiles( - pkg, - resolveUserIds(reconciledPkg.installArgs.user.getIdentifier()), - /* updateReferenceProfileContent= */ true); - - // Compute the compilation reason from the installation scenario. - final int compilationReason = mDexManager.getCompilationReasonForInstallScenario( - reconciledPkg.installArgs.mInstallScenario); - - // Construct the DexoptOptions early to see if we should skip running dexopt. - // - // Do not run PackageDexOptimizer through the local performDexOpt - // method because `pkg` may not be in `mPackages` yet. - // - // Also, don't fail application installs if the dexopt step fails. - final boolean isBackupOrRestore = - reconciledPkg.installArgs.installReason == INSTALL_REASON_DEVICE_RESTORE - || reconciledPkg.installArgs.installReason == INSTALL_REASON_DEVICE_SETUP; - - final int dexoptFlags = DexoptOptions.DEXOPT_BOOT_COMPLETE - | DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE - | (isBackupOrRestore ? DexoptOptions.DEXOPT_FOR_RESTORE : 0); - DexoptOptions dexoptOptions = - new DexoptOptions(packageName, compilationReason, dexoptFlags); - - // Check whether we need to dexopt the app. - // - // NOTE: it is IMPORTANT to call dexopt: - // - after doRename which will sync the package data from AndroidPackage and - // its corresponding ApplicationInfo. - // - after installNewPackageLIF or replacePackageLIF which will update result with the - // uid of the application (pkg.applicationInfo.uid). - // This update happens in place! - // - // We only need to dexopt if the package meets ALL of the following conditions: - // 1) it is not an instant app or if it is then dexopt is enabled via gservices. - // 2) it is not debuggable. - // 3) it is not on Incremental File System. - // - // Note that we do not dexopt instant apps by default. dexopt can take some time to - // complete, so we skip this step during installation. Instead, we'll take extra time - // the first time the instant app starts. It's preferred to do it this way to provide - // continuous progress to the useur instead of mysteriously blocking somewhere in the - // middle of running an instant app. The default behaviour can be overridden - // via gservices. - // - // Furthermore, dexopt may be skipped, depending on the install scenario and current - // state of the device. - // - // TODO(b/174695087): instantApp and onIncremental should be removed and their install - // path moved to SCENARIO_FAST. - final boolean performDexopt = - (!instantApp || Global.getInt(mContext.getContentResolver(), - Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0) - && !pkg.isDebuggable() - && (!onIncremental) - && dexoptOptions.isCompilationEnabled(); - - if (performDexopt) { - // Compile the layout resources. - if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) { - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "compileLayouts"); - mViewCompiler.compileLayouts(pkg); - Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); - } - - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt"); - ScanResult result = reconciledPkg.scanResult; - - // This mirrors logic from commitReconciledScanResultLocked, where the library files - // needed for dexopt are assigned. - // TODO: Fix this to have 1 mutable PackageSetting for scan/install. If the previous - // setting needs to be passed to have a comparison, hide it behind an immutable - // interface. There's no good reason to have 3 different ways to access the real - // PackageSetting object, only one of which is actually correct. - PackageSetting realPkgSetting = result.existingSettingCopied - ? result.request.pkgSetting : result.pkgSetting; - if (realPkgSetting == null) { - realPkgSetting = reconciledPkg.pkgSetting; - } - - // Unfortunately, the updated system app flag is only tracked on this PackageSetting - boolean isUpdatedSystemApp = reconciledPkg.pkgSetting.getPkgState() - .isUpdatedSystemApp(); - - realPkgSetting.getPkgState().setUpdatedSystemApp(isUpdatedSystemApp); - - mPackageDexOptimizer.performDexOpt(pkg, realPkgSetting, - null /* instructionSets */, - getOrCreateCompilerPackageStats(pkg), - mDexManager.getPackageUseInfoOrDefault(packageName), - dexoptOptions); - Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); - } - - // Notify BackgroundDexOptService that the package has been changed. - // If this is an update of a package which used to fail to compile, - // BackgroundDexOptService will remove it from its denylist. - // TODO: Layering violation - BackgroundDexOptService.notifyPackageChanged(packageName); - - notifyPackageChangeObserversOnUpdate(reconciledPkg); - } - waitForNativeBinariesExtraction(incrementalStorages); - } - - static void waitForNativeBinariesExtraction( - ArraySet incrementalStorages) { - if (incrementalStorages.isEmpty()) { - return; - } - try { - // Native library extraction may take very long time: each page could potentially - // wait for either 10s or 100ms (adb vs non-adb data loader), and that easily adds - // up to a full watchdog timeout of 1 min, killing the system after that. It doesn't - // make much sense as blocking here doesn't lock up the framework, but only blocks - // the installation session and the following ones. - Watchdog.getInstance().pauseWatchingCurrentThread("native_lib_extract"); - for (int i = 0; i < incrementalStorages.size(); ++i) { - IncrementalStorage storage = incrementalStorages.valueAtUnchecked(i); - storage.waitForNativeBinariesExtraction(); - } - } finally { - Watchdog.getInstance().resumeWatchingCurrentThread("native_lib_extract"); - } - } - - private int[] getInstalledUsers(PackageSetting ps, int userId) { - final int[] allUserIds = resolveUserIds(userId); - final ArrayList installedUserIdsList = new ArrayList<>(); - for (int i = 0; i < allUserIds.length; i++) { - if (ps.getInstalled(allUserIds[i])) { - installedUserIdsList.add(allUserIds[i]); - } - } - final int numInstalledUserId = installedUserIdsList.size(); - final int[] installedUserIds = new int[numInstalledUserId]; - for (int i = 0; i < numInstalledUserId; i++) { - installedUserIds[i] = installedUserIdsList.get(i); - } - return installedUserIds; - } - - /** - * Package states callback, used to listen for package state changes and send broadcasts - */ - private final class IncrementalStatesCallback implements IncrementalStates.Callback { - private final String mPackageName; - private final int mUid; - private final int[] mInstalledUserIds; - IncrementalStatesCallback(String packageName, int uid, int[] installedUserIds) { - mPackageName = packageName; - mUid = uid; - mInstalledUserIds = installedUserIds; - } - - @Override - public void onPackageFullyLoaded() { - final SparseArray newBroadcastAllowList; - final String codePath; - synchronized (mLock) { - final PackageSetting ps = mSettings.getPackageLPr(mPackageName); - if (ps == null) { - return; - } - newBroadcastAllowList = mAppsFilter.getVisibilityAllowList( - ps, mInstalledUserIds, mSettings.getPackagesLocked()); - codePath = ps.getPathString(); - } - // Unregister progress listener - mIncrementalManager.unregisterLoadingProgressCallbacks(codePath); - // Make sure the information is preserved - scheduleWriteSettingsLocked(); - } - } - - /** - * Loading progress callback, used to listen for progress changes and update package setting - */ - private class IncrementalProgressListener extends IPackageLoadingProgressCallback.Stub { - private final String mPackageName; - IncrementalProgressListener(String packageName) { - mPackageName = packageName; - } - - @Override - public void onPackageLoadingProgressChanged(float progress) { - final PackageSetting ps; - synchronized (mLock) { - ps = mSettings.getPackageLPr(mPackageName); - if (ps == null) { - return; - } - ps.setLoadingProgress(progress); - } - } - } - @Nullable PackageSetting getPackageSettingForUser(String packageName, int callingUid, int userId) { final PackageSetting ps; @@ -20278,914 +17341,33 @@ public class PackageManagerService extends IPackageManager.Stub return ps; } - private void notifyPackageChangeObserversOnUpdate(ReconciledPackage reconciledPkg) { - final PackageSetting pkgSetting = reconciledPkg.pkgSetting; - final PackageInstalledInfo pkgInstalledInfo = reconciledPkg.installResult; - final PackageRemovedInfo pkgRemovedInfo = pkgInstalledInfo.removedInfo; - - PackageChangeEvent pkgChangeEvent = new PackageChangeEvent(); - pkgChangeEvent.packageName = pkgSetting.pkg.getPackageName(); - pkgChangeEvent.version = pkgSetting.versionCode; - pkgChangeEvent.lastUpdateTimeMillis = pkgSetting.lastUpdateTime; - pkgChangeEvent.newInstalled = (pkgRemovedInfo == null || !pkgRemovedInfo.isUpdate); - pkgChangeEvent.dataRemoved = (pkgRemovedInfo != null && pkgRemovedInfo.dataRemoved); - pkgChangeEvent.isDeleted = false; - - notifyPackageChangeObservers(pkgChangeEvent); - } - private void notifyPackageChangeObserversOnDelete(String packageName, long version) { - PackageChangeEvent pkgChangeEvent = new PackageChangeEvent(); - pkgChangeEvent.packageName = packageName; - pkgChangeEvent.version = version; - pkgChangeEvent.lastUpdateTimeMillis = 0L; - pkgChangeEvent.newInstalled = false; - pkgChangeEvent.dataRemoved = false; - pkgChangeEvent.isDeleted = true; + PackageChangeEvent pkgChangeEvent = new PackageChangeEvent(); + pkgChangeEvent.packageName = packageName; + pkgChangeEvent.version = version; + pkgChangeEvent.lastUpdateTimeMillis = 0L; + pkgChangeEvent.newInstalled = false; + pkgChangeEvent.dataRemoved = false; + pkgChangeEvent.isDeleted = true; - notifyPackageChangeObservers(pkgChangeEvent); + notifyPackageChangeObservers(pkgChangeEvent); } - private void notifyPackageChangeObservers(PackageChangeEvent event) { - try { - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "notifyPackageChangeObservers"); - synchronized (mPackageChangeObservers) { - for(IPackageChangeObserver observer : mPackageChangeObservers) { - try { - observer.onPackageChanged(event); - } catch(RemoteException e) { - Log.wtf(TAG, e); - } - } - } - } finally { - Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); - } - } - - /** - * The set of data needed to successfully install the prepared package. This includes data that - * will be used to scan and reconcile the package. - */ - private static class PrepareResult { - public final boolean replace; - public final int scanFlags; - public final int parseFlags; - @Nullable /* The original Package if it is being replaced, otherwise {@code null} */ - public final AndroidPackage existingPackage; - public final ParsedPackage packageToScan; - public final boolean clearCodeCache; - public final boolean system; - public final PackageSetting originalPs; - public final PackageSetting disabledPs; - - private PrepareResult(boolean replace, int scanFlags, - int parseFlags, AndroidPackage existingPackage, - ParsedPackage packageToScan, boolean clearCodeCache, boolean system, - PackageSetting originalPs, PackageSetting disabledPs) { - this.replace = replace; - this.scanFlags = scanFlags; - this.parseFlags = parseFlags; - this.existingPackage = existingPackage; - this.packageToScan = packageToScan; - this.clearCodeCache = clearCodeCache; - this.system = system; - this.originalPs = originalPs; - this.disabledPs = disabledPs; - } - } - - private static class PrepareFailure extends PackageManagerException { - - public String conflictingPackage; - public String conflictingPermission; - - 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) { - this.conflictingPermission = conflictingPermission; - this.conflictingPackage = conflictingPackage; - return this; - } - } - - private boolean doesSignatureMatchForPermissions(@NonNull String sourcePackageName, - @NonNull ParsedPackage parsedPackage, int scanFlags) { - // If the defining package is signed with our cert, it's okay. This - // also includes the "updating the same package" case, of course. - // "updating same package" could also involve key-rotation. - - final PackageSetting sourcePackageSetting; - synchronized (mLock) { - sourcePackageSetting = mSettings.getPackageLPr(sourcePackageName); - } - - final SigningDetails sourceSigningDetails = (sourcePackageSetting == null - ? SigningDetails.UNKNOWN : sourcePackageSetting.getSigningDetails()); - final KeySetManagerService ksms = mSettings.getKeySetManagerService(); - if (sourcePackageName.equals(parsedPackage.getPackageName()) - && (ksms.shouldCheckUpgradeKeySetLocked( - sourcePackageSetting, scanFlags))) { - return ksms.checkUpgradeKeySetLocked(sourcePackageSetting, parsedPackage); - } else { - - // in the event of signing certificate rotation, we need to see if the - // package's certificate has rotated from the current one, or if it is an - // older certificate with which the current is ok with sharing permissions - if (sourceSigningDetails.checkCapability( - parsedPackage.getSigningDetails(), - SigningDetails.CertCapabilities.PERMISSION)) { - return true; - } else if (parsedPackage.getSigningDetails().checkCapability( - sourceSigningDetails, - SigningDetails.CertCapabilities.PERMISSION)) { - // the scanned package checks out, has signing certificate rotation - // history, and is newer; bring it over - synchronized (mLock) { - sourcePackageSetting.signatures.mSigningDetails = - parsedPackage.getSigningDetails(); + void notifyPackageChangeObservers(PackageChangeEvent event) { + try { + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "notifyPackageChangeObservers"); + synchronized (mPackageChangeObservers) { + for (IPackageChangeObserver observer : mPackageChangeObservers) { + try { + observer.onPackageChanged(event); + } catch (RemoteException e) { + Log.wtf(TAG, e); + } } - return true; - } else { - return false; } - } - } - - /* - * Cannot properly check CANNOT_INSTALL_WITH_BAD_PERMISSION_GROUPS using CompatChanges - * as this only works for packages that are installed - * - * TODO: Move logic for permission group compatibility into PermissionManagerService - */ - @SuppressWarnings("AndroidFrameworkCompatChange") - private static boolean cannotInstallWithBadPermissionGroups(ParsedPackage parsedPackage) { - return parsedPackage.getTargetSdkVersion() >= Build.VERSION_CODES.S; - } - - @GuardedBy("mInstallLock") - private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res) - throws PrepareFailure { - final int installFlags = args.installFlags; - final File tmpPackageFile = new File(args.getCodePath()); - final boolean onExternal = args.volumeUuid != null; - final boolean instantApp = ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0); - final boolean fullApp = ((installFlags & PackageManager.INSTALL_FULL_APP) != 0); - final boolean virtualPreload = - ((installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0); - final boolean isRollback = args.installReason == PackageManager.INSTALL_REASON_ROLLBACK; - @ScanFlags int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE; - if (args.move != null) { - // moving a complete application; perform an initial scan on the new install location - scanFlags |= SCAN_INITIAL; - } - if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) { - scanFlags |= SCAN_DONT_KILL_APP; - } - if (instantApp) { - scanFlags |= SCAN_AS_INSTANT_APP; - } - if (fullApp) { - scanFlags |= SCAN_AS_FULL_APP; - } - if (virtualPreload) { - scanFlags |= SCAN_AS_VIRTUAL_PRELOAD; - } - - if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile); - - // Validity check - if (instantApp && onExternal) { - Slog.i(TAG, "Incompatible ephemeral install; external=" + onExternal); - throw new PrepareFailure(PackageManager.INSTALL_FAILED_SESSION_INVALID); - } - - // Retrieve PackageSettings and parse package - @ParseFlags final int parseFlags = mDefParseFlags | ParsingPackageUtils.PARSE_CHATTY - | ParsingPackageUtils.PARSE_ENFORCE_CODE - | (onExternal ? ParsingPackageUtils.PARSE_EXTERNAL_STORAGE : 0); - - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage"); - final ParsedPackage parsedPackage; - try (PackageParser2 pp = mInjector.getPreparingPackageParser()) { - parsedPackage = pp.parsePackage(tmpPackageFile, parseFlags, false); - AndroidPackageUtils.validatePackageDexMetadata(parsedPackage); - } catch (PackageManagerException e) { - throw new PrepareFailure("Failed parse during installPackageLI", e); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } - - // Instant apps have several additional install-time checks. - if (instantApp) { - if (parsedPackage.getTargetSdkVersion() < Build.VERSION_CODES.O) { - Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName() - + " does not target at least O"); - throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID, - "Instant app package must target at least O"); - } - if (parsedPackage.getSharedUserId() != null) { - Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName() - + " may not declare sharedUserId."); - throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID, - "Instant app package may not declare a sharedUserId"); - } - } - - if (parsedPackage.isStaticSharedLibrary()) { - // Static shared libraries have synthetic package names - renameStaticSharedLibraryPackage(parsedPackage); - - // No static shared libs on external storage - if (onExternal) { - Slog.i(TAG, "Static shared libs can only be installed on internal storage."); - throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION, - "Packages declaring static-shared libs cannot be updated"); - } - } - - String pkgName = res.name = parsedPackage.getPackageName(); - if (parsedPackage.isTestOnly()) { - if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) { - throw new PrepareFailure(INSTALL_FAILED_TEST_ONLY, "installPackageLI"); - } - } - - // either use what we've been given or parse directly from the APK - if (args.signingDetails != SigningDetails.UNKNOWN) { - parsedPackage.setSigningDetails(args.signingDetails); - } else { - final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); - final ParseResult result = ParsingPackageUtils.getSigningDetails( - input, parsedPackage, false /*skipVerify*/); - if (result.isError()) { - throw new PrepareFailure("Failed collect during installPackageLI", - result.getException()); - } - parsedPackage.setSigningDetails(result.getResult()); - } - - if (instantApp && parsedPackage.getSigningDetails().getSignatureSchemeVersion() - < SignatureSchemeVersion.SIGNING_BLOCK_V2) { - Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName() - + " is not signed with at least APK Signature Scheme v2"); - throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID, - "Instant app package must be signed with APK Signature Scheme v2 or greater"); - } - - boolean systemApp = false; - boolean replace = false; - synchronized (mLock) { - // Check if installing already existing package - if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) { - String oldName = mSettings.getRenamedPackageLPr(pkgName); - if (parsedPackage.getOriginalPackages().contains(oldName) - && mPackages.containsKey(oldName)) { - // This package is derived from an original package, - // and this device has been updating from that original - // name. We must continue using the original name, so - // rename the new package here. - parsedPackage.setPackageName(oldName); - pkgName = parsedPackage.getPackageName(); - replace = true; - if (DEBUG_INSTALL) { - Slog.d(TAG, "Replacing existing renamed package: oldName=" - + oldName + " pkgName=" + pkgName); - } - } else if (mPackages.containsKey(pkgName)) { - // This package, under its official name, already exists - // on the device; we should replace it. - replace = true; - if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName); - } - - if (replace) { - // Prevent apps opting out from runtime permissions - AndroidPackage oldPackage = mPackages.get(pkgName); - final int oldTargetSdk = oldPackage.getTargetSdkVersion(); - final int newTargetSdk = parsedPackage.getTargetSdkVersion(); - if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1 - && newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) { - throw new PrepareFailure( - PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE, - "Package " + parsedPackage.getPackageName() - + " new target SDK " + newTargetSdk - + " doesn't support runtime permissions but the old" - + " target SDK " + oldTargetSdk + " does."); - } - // Prevent persistent apps from being updated - if (oldPackage.isPersistent() - && ((installFlags & PackageManager.INSTALL_STAGED) == 0)) { - throw new PrepareFailure(PackageManager.INSTALL_FAILED_INVALID_APK, - "Package " + oldPackage.getPackageName() + " is a persistent app. " - + "Persistent apps are not updateable."); - } - } - } - - PackageSetting ps = mSettings.getPackageLPr(pkgName); - if (ps != null) { - if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps); - - // Static shared libs have same package with different versions where - // we internally use a synthetic package name to allow multiple versions - // of the same package, therefore we need to compare signatures against - // the package setting for the latest library version. - PackageSetting signatureCheckPs = ps; - if (parsedPackage.isStaticSharedLibrary()) { - SharedLibraryInfo libraryInfo = getLatestSharedLibraVersionLPr(parsedPackage); - if (libraryInfo != null) { - signatureCheckPs = mSettings.getPackageLPr(libraryInfo.getPackageName()); - } - } - - // Quick validity check that we're signed correctly if updating; - // we'll check this again later when scanning, but we want to - // bail early here before tripping over redefined permissions. - final KeySetManagerService ksms = mSettings.getKeySetManagerService(); - if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) { - if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, parsedPackage)) { - throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package " - + parsedPackage.getPackageName() + " upgrade keys do not match the " - + "previously installed version"); - } - } else { - try { - final boolean compareCompat = isCompatSignatureUpdateNeeded(parsedPackage); - final boolean compareRecover = isRecoverSignatureUpdateNeeded( - parsedPackage); - // We don't care about disabledPkgSetting on install for now. - final boolean compatMatch = verifySignatures(signatureCheckPs, null, - parsedPackage.getSigningDetails(), compareCompat, compareRecover, - isRollback); - // The new KeySets will be re-added later in the scanning process. - if (compatMatch) { - synchronized (mLock) { - ksms.removeAppKeySetDataLPw(parsedPackage.getPackageName()); - } - } - } catch (PackageManagerException e) { - throw new PrepareFailure(e.error, e.getMessage()); - } - } - - if (ps.pkg != null) { - systemApp = ps.pkg.isSystem(); - } - res.origUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true); - } - - final int numGroups = ArrayUtils.size(parsedPackage.getPermissionGroups()); - for (int groupNum = 0; groupNum < numGroups; groupNum++) { - final ParsedPermissionGroup group = - parsedPackage.getPermissionGroups().get(groupNum); - final PermissionGroupInfo sourceGroup = getPermissionGroupInfo(group.getName(), 0); - - if (sourceGroup != null - && cannotInstallWithBadPermissionGroups(parsedPackage)) { - final String sourcePackageName = sourceGroup.packageName; - - if ((replace || !parsedPackage.getPackageName().equals(sourcePackageName)) - && !doesSignatureMatchForPermissions(sourcePackageName, parsedPackage, - scanFlags)) { - EventLog.writeEvent(0x534e4554, "146211400", -1, - parsedPackage.getPackageName()); - - throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PERMISSION_GROUP, - "Package " - + parsedPackage.getPackageName() - + " attempting to redeclare permission group " - + group.getName() + " already owned by " - + sourcePackageName); - } - } - } - - // TODO: Move logic for checking permission compatibility into PermissionManagerService - final int N = ArrayUtils.size(parsedPackage.getPermissions()); - for (int i = N - 1; i >= 0; i--) { - final ParsedPermission perm = parsedPackage.getPermissions().get(i); - final Permission bp = mPermissionManager.getPermissionTEMP(perm.getName()); - - // Don't allow anyone but the system to define ephemeral permissions. - if ((perm.getProtectionLevel() & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0 - && !systemApp) { - Slog.w(TAG, "Non-System package " + parsedPackage.getPackageName() - + " attempting to delcare ephemeral permission " - + perm.getName() + "; Removing ephemeral."); - perm.setProtectionLevel(perm.getProtectionLevel() & ~PermissionInfo.PROTECTION_FLAG_INSTANT); - } - - // Check whether the newly-scanned package wants to define an already-defined perm - if (bp != null) { - final String sourcePackageName = bp.getPackageName(); - - if (!doesSignatureMatchForPermissions(sourcePackageName, parsedPackage, - scanFlags)) { - // If the owning package is the system itself, we log but allow - // install to proceed; we fail the install on all other permission - // redefinitions. - if (!sourcePackageName.equals("android")) { - throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package " - + parsedPackage.getPackageName() - + " attempting to redeclare permission " - + perm.getName() + " already owned by " - + sourcePackageName) - .conflictsWithExistingPermission(perm.getName(), - sourcePackageName); - } else { - Slog.w(TAG, "Package " + parsedPackage.getPackageName() - + " attempting to redeclare system permission " - + perm.getName() + "; ignoring new declaration"); - parsedPackage.removePermission(i); - } - } else if (!PLATFORM_PACKAGE_NAME.equals(parsedPackage.getPackageName())) { - // Prevent apps to change protection level to dangerous from any other - // type as this would allow a privilege escalation where an app adds a - // normal/signature permission in other app's group and later redefines - // it as dangerous leading to the group auto-grant. - if ((perm.getProtectionLevel() & PermissionInfo.PROTECTION_MASK_BASE) - == PermissionInfo.PROTECTION_DANGEROUS) { - if (bp != null && !bp.isRuntime()) { - Slog.w(TAG, "Package " + parsedPackage.getPackageName() - + " trying to change a non-runtime permission " - + perm.getName() - + " to runtime; keeping old protection level"); - perm.setProtectionLevel(bp.getProtectionLevel()); - } - } - } - } - - if (perm.getGroup() != null - && cannotInstallWithBadPermissionGroups(parsedPackage)) { - boolean isPermGroupDefinedByPackage = false; - for (int groupNum = 0; groupNum < numGroups; groupNum++) { - if (parsedPackage.getPermissionGroups().get(groupNum).getName() - .equals(perm.getGroup())) { - isPermGroupDefinedByPackage = true; - break; - } - } - - if (!isPermGroupDefinedByPackage) { - final PermissionGroupInfo sourceGroup = - getPermissionGroupInfo(perm.getGroup(), 0); - - if (sourceGroup == null) { - EventLog.writeEvent(0x534e4554, "146211400", -1, - parsedPackage.getPackageName()); - - throw new PrepareFailure(INSTALL_FAILED_BAD_PERMISSION_GROUP, - "Package " - + parsedPackage.getPackageName() - + " attempting to declare permission " - + perm.getName() + " in non-existing group " - + perm.getGroup()); - } else { - String groupSourcePackageName = sourceGroup.packageName; - - if (!PLATFORM_PACKAGE_NAME.equals(groupSourcePackageName) - && !doesSignatureMatchForPermissions(groupSourcePackageName, - parsedPackage, scanFlags)) { - EventLog.writeEvent(0x534e4554, "146211400", -1, - parsedPackage.getPackageName()); - - throw new PrepareFailure(INSTALL_FAILED_BAD_PERMISSION_GROUP, - "Package " - + parsedPackage.getPackageName() - + " attempting to declare permission " - + perm.getName() + " in group " - + perm.getGroup() + " owned by package " - + groupSourcePackageName - + " with incompatible certificate"); - } - } - } - } - } - } - - if (systemApp) { - if (onExternal) { - // Abort update; system app can't be replaced with app on sdcard - throw new PrepareFailure(INSTALL_FAILED_INVALID_INSTALL_LOCATION, - "Cannot install updates to system apps on sdcard"); - } else if (instantApp) { - // Abort update; system app can't be replaced with an instant app - throw new PrepareFailure(INSTALL_FAILED_SESSION_INVALID, - "Cannot update a system app with an instant app"); - } - } - - if (args.move != null) { - // We did an in-place move, so dex is ready to roll - scanFlags |= SCAN_NO_DEX; - scanFlags |= SCAN_MOVE; - - synchronized (mLock) { - final PackageSetting ps = mSettings.getPackageLPr(pkgName); - if (ps == null) { - res.setError(INSTALL_FAILED_INTERNAL_ERROR, - "Missing settings for moved package " + pkgName); - } - - // We moved the entire application as-is, so bring over the - // previously derived ABI information. - parsedPackage.setPrimaryCpuAbi(ps.primaryCpuAbiString) - .setSecondaryCpuAbi(ps.secondaryCpuAbiString); - } - - } else { - // Enable SCAN_NO_DEX flag to skip dexopt at a later stage - scanFlags |= SCAN_NO_DEX; - - try { - PackageSetting pkgSetting; - synchronized (mLock) { - pkgSetting = mSettings.getPackageLPr(pkgName); - } - boolean isUpdatedSystemAppFromExistingSetting = pkgSetting != null - && pkgSetting.getPkgState().isUpdatedSystemApp(); - final String abiOverride = deriveAbiOverride(args.abiOverride); - AndroidPackage oldPackage = mPackages.get(pkgName); - boolean isUpdatedSystemAppInferred = oldPackage != null && oldPackage.isSystem(); - final Pair - derivedAbi = mInjector.getAbiHelper().derivePackageAbi(parsedPackage, - isUpdatedSystemAppFromExistingSetting || isUpdatedSystemAppInferred, - abiOverride, mAppLib32InstallDir); - derivedAbi.first.applyTo(parsedPackage); - derivedAbi.second.applyTo(parsedPackage); - } catch (PackageManagerException pme) { - Slog.e(TAG, "Error deriving application ABI", pme); - throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR, - "Error deriving application ABI: " + pme.getMessage()); - } - } - - if (!args.doRename(res.returnCode, parsedPackage)) { - throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename"); - } - - try { - setUpFsVerityIfPossible(parsedPackage); - } catch (InstallerException | IOException | DigestException | NoSuchAlgorithmException e) { - throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR, - "Failed to set up verity: " + e); - } - - final PackageFreezer freezer = - freezePackageForInstall(pkgName, installFlags, "installPackageLI"); - boolean shouldCloseFreezerBeforeReturn = true; - try { - final AndroidPackage existingPackage; - String renamedPackage = null; - boolean sysPkg = false; - int targetScanFlags = scanFlags; - int targetParseFlags = parseFlags; - final PackageSetting ps; - final PackageSetting disabledPs; - if (replace) { - if (parsedPackage.isStaticSharedLibrary()) { - // Static libs have a synthetic package name containing the version - // and cannot be updated as an update would get a new package name, - // unless this is installed from adb which is useful for development. - AndroidPackage existingPkg = mPackages.get(parsedPackage.getPackageName()); - if (existingPkg != null - && (installFlags & PackageManager.INSTALL_FROM_ADB) == 0) { - throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PACKAGE, - "Packages declaring " - + "static-shared libs cannot be updated"); - } - } - - final boolean isInstantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0; - - final AndroidPackage oldPackage; - final String pkgName11 = parsedPackage.getPackageName(); - final int[] allUsers; - final int[] installedUsers; - final int[] uninstalledUsers; - - synchronized (mLock) { - oldPackage = mPackages.get(pkgName11); - existingPackage = oldPackage; - if (DEBUG_INSTALL) { - Slog.d(TAG, - "replacePackageLI: new=" + parsedPackage + ", old=" + oldPackage); - } - - ps = mSettings.getPackageLPr(pkgName11); - disabledPs = mSettings.getDisabledSystemPkgLPr(ps); - - // verify signatures are valid - final KeySetManagerService ksms = mSettings.getKeySetManagerService(); - if (ksms.shouldCheckUpgradeKeySetLocked(ps, scanFlags)) { - if (!ksms.checkUpgradeKeySetLocked(ps, parsedPackage)) { - throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, - "New package not signed by keys specified by upgrade-keysets: " - + pkgName11); - } - } else { - SigningDetails parsedPkgSigningDetails = parsedPackage.getSigningDetails(); - SigningDetails oldPkgSigningDetails = oldPackage.getSigningDetails(); - // default to original signature matching - if (!parsedPkgSigningDetails.checkCapability(oldPkgSigningDetails, - SigningDetails.CertCapabilities.INSTALLED_DATA) - && !oldPkgSigningDetails.checkCapability(parsedPkgSigningDetails, - SigningDetails.CertCapabilities.ROLLBACK)) { - // Allow the update to proceed if this is a rollback and the parsed - // package's current signing key is the current signer or in the lineage - // of the old package; this allows a rollback to a previously installed - // version after an app's signing key has been rotated without requiring - // the rollback capability on the previous signing key. - if (!isRollback || !oldPkgSigningDetails.hasAncestorOrSelf( - parsedPkgSigningDetails)) { - throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, - "New package has a different signature: " + pkgName11); - } - } - } - - // don't allow a system upgrade unless the upgrade hash matches - if (oldPackage.getRestrictUpdateHash() != null && oldPackage.isSystem()) { - final byte[] digestBytes; - try { - final MessageDigest digest = MessageDigest.getInstance("SHA-512"); - updateDigest(digest, new File(parsedPackage.getBaseApkPath())); - if (!ArrayUtils.isEmpty(parsedPackage.getSplitCodePaths())) { - for (String path : parsedPackage.getSplitCodePaths()) { - updateDigest(digest, new File(path)); - } - } - digestBytes = digest.digest(); - } catch (NoSuchAlgorithmException | IOException e) { - throw new PrepareFailure(INSTALL_FAILED_INVALID_APK, - "Could not compute hash: " + pkgName11); - } - if (!Arrays.equals(oldPackage.getRestrictUpdateHash(), digestBytes)) { - throw new PrepareFailure(INSTALL_FAILED_INVALID_APK, - "New package fails restrict-update check: " + pkgName11); - } - // retain upgrade restriction - parsedPackage.setRestrictUpdateHash(oldPackage.getRestrictUpdateHash()); - } - - // Check for shared user id changes - String invalidPackageName = null; - if (!Objects.equals(oldPackage.getSharedUserId(), - parsedPackage.getSharedUserId())) { - invalidPackageName = parsedPackage.getPackageName(); - } - - if (invalidPackageName != null) { - throw new PrepareFailure(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE, - "Package " + invalidPackageName + " tried to change user " - + oldPackage.getSharedUserId()); - } - - // In case of rollback, remember per-user/profile install state - allUsers = mUserManager.getUserIds(); - installedUsers = ps.queryInstalledUsers(allUsers, true); - uninstalledUsers = ps.queryInstalledUsers(allUsers, false); - - - // don't allow an upgrade from full to ephemeral - if (isInstantApp) { - if (args.user == null || args.user.getIdentifier() == UserHandle.USER_ALL) { - for (int currentUser : allUsers) { - if (!ps.getInstantApp(currentUser)) { - // can't downgrade from full to instant - Slog.w(TAG, - "Can't replace full app with instant app: " + pkgName11 - + " for user: " + currentUser); - throw new PrepareFailure( - PackageManager.INSTALL_FAILED_SESSION_INVALID); - } - } - } else if (!ps.getInstantApp(args.user.getIdentifier())) { - // can't downgrade from full to instant - Slog.w(TAG, "Can't replace full app with instant app: " + pkgName11 - + " for user: " + args.user.getIdentifier()); - throw new PrepareFailure( - PackageManager.INSTALL_FAILED_SESSION_INVALID); - } - } - } - - // Update what is removed - res.removedInfo = new PackageRemovedInfo(this); - res.removedInfo.uid = oldPackage.getUid(); - res.removedInfo.removedPackage = oldPackage.getPackageName(); - res.removedInfo.installerPackageName = ps.installSource.installerPackageName; - res.removedInfo.isStaticSharedLib = parsedPackage.getStaticSharedLibName() != null; - res.removedInfo.isUpdate = true; - res.removedInfo.origUsers = installedUsers; - res.removedInfo.installReasons = new SparseArray<>(installedUsers.length); - for (int i = 0; i < installedUsers.length; i++) { - final int userId = installedUsers[i]; - res.removedInfo.installReasons.put(userId, ps.getInstallReason(userId)); - } - res.removedInfo.uninstallReasons = new SparseArray<>(uninstalledUsers.length); - for (int i = 0; i < uninstalledUsers.length; i++) { - final int userId = uninstalledUsers[i]; - res.removedInfo.uninstallReasons.put(userId, ps.getUninstallReason(userId)); - } - - sysPkg = oldPackage.isSystem(); - if (sysPkg) { - // Set the system/privileged/oem/vendor/product flags as needed - final boolean privileged = oldPackage.isPrivileged(); - final boolean oem = oldPackage.isOem(); - final boolean vendor = oldPackage.isVendor(); - final boolean product = oldPackage.isProduct(); - final boolean odm = oldPackage.isOdm(); - final boolean systemExt = oldPackage.isSystemExt(); - final @ParseFlags int systemParseFlags = parseFlags; - final @ScanFlags int systemScanFlags = scanFlags - | SCAN_AS_SYSTEM - | (privileged ? SCAN_AS_PRIVILEGED : 0) - | (oem ? SCAN_AS_OEM : 0) - | (vendor ? SCAN_AS_VENDOR : 0) - | (product ? SCAN_AS_PRODUCT : 0) - | (odm ? SCAN_AS_ODM : 0) - | (systemExt ? SCAN_AS_SYSTEM_EXT : 0); - - if (DEBUG_INSTALL) { - Slog.d(TAG, "replaceSystemPackageLI: new=" + parsedPackage - + ", old=" + oldPackage); - } - res.setReturnCode(PackageManager.INSTALL_SUCCEEDED); - targetParseFlags = systemParseFlags; - targetScanFlags = systemScanFlags; - } else { // non system replace - replace = true; - if (DEBUG_INSTALL) { - Slog.d(TAG, - "replaceNonSystemPackageLI: new=" + parsedPackage + ", old=" - + oldPackage); - } - } - } else { // new package install - ps = null; - disabledPs = null; - replace = false; - existingPackage = null; - // Remember this for later, in case we need to rollback this install - String pkgName1 = parsedPackage.getPackageName(); - - if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + parsedPackage); - - // TODO(patb): MOVE TO RECONCILE - synchronized (mLock) { - renamedPackage = mSettings.getRenamedPackageLPr(pkgName1); - if (renamedPackage != null) { - // A package with the same name is already installed, though - // it has been renamed to an older name. The package we - // are trying to install should be installed as an update to - // the existing one, but that has not been requested, so bail. - throw new PrepareFailure(INSTALL_FAILED_ALREADY_EXISTS, - "Attempt to re-install " + pkgName1 - + " without first uninstalling package running as " - + renamedPackage); - } - if (mPackages.containsKey(pkgName1)) { - // Don't allow installation over an existing package with the same name. - throw new PrepareFailure(INSTALL_FAILED_ALREADY_EXISTS, - "Attempt to re-install " + pkgName1 - + " without first uninstalling."); - } - } - } - // we're passing the freezer back to be closed in a later phase of install - shouldCloseFreezerBeforeReturn = false; - - return new PrepareResult(replace, targetScanFlags, targetParseFlags, - existingPackage, parsedPackage, replace /* clearCodeCache */, sysPkg, - ps, disabledPs); - } finally { - res.freezer = freezer; - if (shouldCloseFreezerBeforeReturn) { - freezer.close(); - } - } - } - - /** - * Set up fs-verity for the given package if possible. This requires a feature flag of system - * property to be enabled only if the kernel supports fs-verity. - * - *

When the feature flag is set to legacy mode, only APK is supported (with some experimental - * kernel patches). In normal mode, all file format can be supported. - */ - private void setUpFsVerityIfPossible(AndroidPackage pkg) throws InstallerException, - PrepareFailure, IOException, DigestException, NoSuchAlgorithmException { - final boolean standardMode = PackageManagerServiceUtils.isApkVerityEnabled(); - final boolean legacyMode = PackageManagerServiceUtils.isLegacyApkVerityEnabled(); - if (!standardMode && !legacyMode) { - return; - } - - if (isIncrementalPath(pkg.getPath()) && IncrementalManager.getVersion() - < IncrementalManager.MIN_VERSION_TO_SUPPORT_FSVERITY) { - return; - } - - // Collect files we care for fs-verity setup. - ArrayMap fsverityCandidates = new ArrayMap<>(); - if (legacyMode) { - synchronized (mLock) { - final PackageSetting ps = mSettings.getPackageLPr(pkg.getPackageName()); - if (ps != null && ps.isPrivileged()) { - fsverityCandidates.put(pkg.getBaseApkPath(), null); - if (pkg.getSplitCodePaths() != null) { - for (String splitPath : pkg.getSplitCodePaths()) { - fsverityCandidates.put(splitPath, null); - } - } - } - } - } else { - // NB: These files will become only accessible if the signing key is loaded in kernel's - // .fs-verity keyring. - fsverityCandidates.put(pkg.getBaseApkPath(), - VerityUtils.getFsveritySignatureFilePath(pkg.getBaseApkPath())); - - final String dmPath = DexMetadataHelper.buildDexMetadataPathForApk( - pkg.getBaseApkPath()); - if (new File(dmPath).exists()) { - fsverityCandidates.put(dmPath, VerityUtils.getFsveritySignatureFilePath(dmPath)); - } - - if (pkg.getSplitCodePaths() != null) { - for (String path : pkg.getSplitCodePaths()) { - fsverityCandidates.put(path, VerityUtils.getFsveritySignatureFilePath(path)); - - final String splitDmPath = DexMetadataHelper.buildDexMetadataPathForApk(path); - if (new File(splitDmPath).exists()) { - fsverityCandidates.put(splitDmPath, - VerityUtils.getFsveritySignatureFilePath(splitDmPath)); - } - } - } - } - - for (Map.Entry entry : fsverityCandidates.entrySet()) { - final String filePath = entry.getKey(); - final String signaturePath = entry.getValue(); - - if (!legacyMode) { - // fs-verity is optional for now. Only set up if signature is provided. - if (new File(signaturePath).exists() && !VerityUtils.hasFsverity(filePath)) { - try { - VerityUtils.setUpFsverity(filePath, signaturePath); - } catch (IOException e) { - throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE, - "Failed to enable fs-verity: " + e); - } - } - continue; - } - - // In legacy mode, fs-verity can only be enabled by process with CAP_SYS_ADMIN. - final VerityUtils.SetupResult result = VerityUtils.generateApkVeritySetupData(filePath); - if (result.isOk()) { - if (Build.IS_DEBUGGABLE) Slog.i(TAG, "Enabling verity to " + filePath); - final FileDescriptor fd = result.getUnownedFileDescriptor(); - try { - final byte[] rootHash = VerityUtils.generateApkVerityRootHash(filePath); - try { - // A file may already have fs-verity, e.g. when reused during a split - // install. If the measurement succeeds, no need to attempt to set up. - mInstaller.assertFsverityRootHashMatches(filePath, rootHash); - } catch (InstallerException e) { - mInstaller.installApkVerity(filePath, fd, result.getContentSize()); - mInstaller.assertFsverityRootHashMatches(filePath, rootHash); - } - } finally { - IoUtils.closeQuietly(fd); - } - } else if (result.isFailed()) { - throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE, - "Failed to generate verity"); - } - } - } - - private static boolean isExternal(PackageSetting ps) { - return (ps.pkgFlags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0; } private static boolean isSystemApp(PackageSetting ps) { @@ -21196,7 +17378,7 @@ public class PackageManagerService extends IPackageManager.Stub return (ps.pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; } - private VersionInfo getSettingsVersionForPackage(AndroidPackage pkg) { + VersionInfo getSettingsVersionForPackage(AndroidPackage pkg) { if (pkg.isExternalStorage()) { if (TextUtils.isEmpty(pkg.getVolumeUuid())) { return mSettings.getExternalVersion(); @@ -21436,12 +17618,8 @@ public class PackageManagerService extends IPackageManager.Stub // Allow caller having MANAGE_PROFILE_AND_DEVICE_OWNERS permission to silently // uninstall for device owner provisioning. - if (checkUidPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS, callingUid) - == PERMISSION_GRANTED) { - return true; - } - - return false; + return checkUidPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS, callingUid) + == PERMISSION_GRANTED; } private int[] getBlockUninstallForUsers(String packageName, int[] userIds) { @@ -21599,7 +17777,7 @@ public class PackageManagerService extends IPackageManager.Stub } } - info.origUsers = uninstalledPs.queryInstalledUsers(allUsers, true); + info.mOrigUsers = uninstalledPs.queryInstalledUsers(allUsers, true); if (isUpdatedSystemApp(uninstalledPs) && ((deleteFlags & PackageManager.DELETE_SYSTEM_APP) == 0)) { @@ -21624,15 +17802,15 @@ public class PackageManagerService extends IPackageManager.Stub try (PackageFreezer freezer = freezePackageForDelete(packageName, freezeUser, deleteFlags, "deletePackageX")) { res = deletePackageLIF(packageName, UserHandle.of(removeUser), true, allUsers, - deleteFlags | PackageManager.DELETE_CHATTY, info, true, null); + deleteFlags | PackageManager.DELETE_CHATTY, info, true); } synchronized (mLock) { if (res) { if (pkg != null) { mInstantAppRegistry.onPackageUninstalledLPw(pkg, uninstalledPs, - info.removedUsers); + info.mRemovedUsers); } - updateSequenceNumberLP(uninstalledPs, info.removedUsers); + updateSequenceNumberLP(uninstalledPs, info.mRemovedUsers); updateInstantAppInstallerLocked(packageName); } } @@ -21649,8 +17827,8 @@ public class PackageManagerService extends IPackageManager.Stub // Delete the resources here after sending the broadcast to let // other processes clean up before deleting resources. synchronized (mInstallLock) { - if (info.args != null) { - info.args.doPostDeleteLI(true); + if (info.mArgs != null) { + info.mArgs.doPostDeleteLI(true); } boolean reEnableStub = false; @@ -21702,135 +17880,6 @@ public class PackageManagerService extends IPackageManager.Stub return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR; } - static class PackageRemovedInfo { - final PackageSender packageSender; - String removedPackage; - String installerPackageName; - int uid = -1; - int removedAppId = -1; - int[] origUsers; - int[] removedUsers = null; - int[] broadcastUsers = null; - int[] instantUserIds = null; - SparseArray installReasons; - SparseArray uninstallReasons; - boolean isRemovedPackageSystemUpdate = false; - boolean isUpdate; - boolean dataRemoved; - boolean removedForAllUsers; - boolean isStaticSharedLib; - // a two dimensional array mapping userId to the set of appIds that can receive notice - // of package changes - SparseArray broadcastAllowList; - // Clean up resources deleted packages. - InstallArgs args = null; - - PackageRemovedInfo(PackageSender packageSender) { - this.packageSender = packageSender; - } - - void sendPackageRemovedBroadcasts(boolean killApp, boolean removedBySystem) { - sendPackageRemovedBroadcastInternal(killApp, removedBySystem); - } - - void sendSystemPackageUpdatedBroadcasts() { - if (isRemovedPackageSystemUpdate) { - sendSystemPackageUpdatedBroadcastsInternal(); - } - } - - private void sendSystemPackageUpdatedBroadcastsInternal() { - Bundle extras = new Bundle(2); - extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid); - extras.putBoolean(Intent.EXTRA_REPLACING, true); - packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, removedPackage, extras, - 0, null /*targetPackage*/, null, null, null, broadcastAllowList, null); - packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, removedPackage, - extras, 0, null /*targetPackage*/, null, null, null, broadcastAllowList, null); - packageSender.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, null, 0, - removedPackage, null, null, null, null /* broadcastAllowList */, - getTemporaryAppAllowlistBroadcastOptions(REASON_PACKAGE_REPLACED).toBundle()); - if (installerPackageName != null) { - packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, - removedPackage, extras, 0 /*flags*/, - installerPackageName, null, null, null, null /* broadcastAllowList */, - null); - packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, - removedPackage, extras, 0 /*flags*/, - installerPackageName, null, null, null, null /* broadcastAllowList */, - null); - } - } - - private void sendPackageRemovedBroadcastInternal(boolean killApp, boolean removedBySystem) { - // Don't send static shared library removal broadcasts as these - // libs are visible only the the apps that depend on them an one - // cannot remove the library if it has a dependency. - if (isStaticSharedLib) { - return; - } - Bundle extras = new Bundle(2); - final int removedUid = removedAppId >= 0 ? removedAppId : uid; - extras.putInt(Intent.EXTRA_UID, removedUid); - extras.putBoolean(Intent.EXTRA_DATA_REMOVED, dataRemoved); - extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, !killApp); - extras.putBoolean(Intent.EXTRA_USER_INITIATED, !removedBySystem); - if (isUpdate || isRemovedPackageSystemUpdate) { - extras.putBoolean(Intent.EXTRA_REPLACING, true); - } - extras.putBoolean(Intent.EXTRA_REMOVED_FOR_ALL_USERS, removedForAllUsers); - if (removedPackage != null) { - packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, - removedPackage, extras, 0, null /*targetPackage*/, null, - broadcastUsers, instantUserIds, broadcastAllowList, null); - if (installerPackageName != null) { - packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, - removedPackage, extras, 0 /*flags*/, - installerPackageName, null, broadcastUsers, instantUserIds, null, null); - } - packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED_INTERNAL, - removedPackage, extras, 0 /*flags*/, PLATFORM_PACKAGE_NAME, - null /*finishedReceiver*/, broadcastUsers, instantUserIds, - broadcastAllowList, null /*bOptions*/); - if (dataRemoved && !isRemovedPackageSystemUpdate) { - packageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED, - removedPackage, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, null, - null, broadcastUsers, instantUserIds, broadcastAllowList, null); - packageSender.notifyPackageRemoved(removedPackage, removedUid); - } - } - if (removedAppId >= 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, removedPackage); - } - - packageSender.sendPackageBroadcast(Intent.ACTION_UID_REMOVED, - null, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, - null, null, broadcastUsers, instantUserIds, broadcastAllowList, null); - } - } - - void populateUsers(int[] userIds, PackageSetting deletedPackageSetting) { - removedUsers = userIds; - if (removedUsers == null) { - broadcastUsers = null; - return; - } - - broadcastUsers = EMPTY_INT_ARRAY; - instantUserIds = EMPTY_INT_ARRAY; - for (int i = userIds.length - 1; i >= 0; --i) { - final int userId = userIds[i]; - if (deletedPackageSetting.getInstantApp(userId)) { - instantUserIds = ArrayUtils.appendInt(instantUserIds, userId); - } else { - broadcastUsers = ArrayUtils.appendInt(broadcastUsers, userId); - } - } - } - } /* * This method deletes the package from internal data structures. If the DELETE_KEEP_DATA @@ -21845,9 +17894,9 @@ public class PackageManagerService extends IPackageManager.Stub // Retrieve object to delete permissions for shared user later on final AndroidPackage deletedPkg = deletedPs.pkg; if (outInfo != null) { - outInfo.removedPackage = packageName; - outInfo.installerPackageName = deletedPs.installSource.installerPackageName; - outInfo.isStaticSharedLib = deletedPkg != null + outInfo.mRemovedPackage = packageName; + outInfo.mInstallerPackageName = deletedPs.installSource.installerPackageName; + outInfo.mIsStaticSharedLib = deletedPkg != null && deletedPkg.getStaticSharedLibName() != null; outInfo.populateUsers(deletedPs == null ? null : deletedPs.queryInstalledUsers(mUserManager.getUserIds(), true), deletedPs); @@ -21869,7 +17918,7 @@ public class PackageManagerService extends IPackageManager.Stub FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL); destroyAppProfilesLIF(resolvedPkg); if (outInfo != null) { - outInfo.dataRemoved = true; + outInfo.mDataRemoved = true; } } @@ -21886,7 +17935,7 @@ public class PackageManagerService extends IPackageManager.Stub mAppsFilter.removePackage(getPackageSetting(packageName)); removedAppId = mSettings.removePackageLPw(packageName); if (outInfo != null) { - outInfo.removedAppId = removedAppId; + outInfo.mRemovedAppId = removedAppId; } if (!mSettings.isDisabledSystemPackageLPr(packageName)) { // If we don't have a disabled system package to reinstall, the package is @@ -21912,12 +17961,12 @@ public class PackageManagerService extends IPackageManager.Stub } // make sure to preserve per-user disabled state if this removal was just // a downgrade of a system app to the factory package - if (outInfo != null && outInfo.origUsers != null) { + if (outInfo != null && outInfo.mOrigUsers != null) { if (DEBUG_REMOVE) { Slog.d(TAG, "Propagating install state across downgrade"); } for (int userId : allUserHandles) { - final boolean installed = ArrayUtils.contains(outInfo.origUsers, userId); + final boolean installed = ArrayUtils.contains(outInfo.mOrigUsers, userId); if (DEBUG_REMOVE) { Slog.d(TAG, " user " + userId + " => " + installed); } @@ -21968,13 +18017,13 @@ public class PackageManagerService extends IPackageManager.Stub @NonNull int[] allUserHandles, int flags, @Nullable PackageRemovedInfo outInfo, boolean writeSettings) throws SystemDeleteException { - final boolean applyUserRestrictions = outInfo != null && (outInfo.origUsers != null); + final boolean applyUserRestrictions = outInfo != null && (outInfo.mOrigUsers != null); final AndroidPackage deletedPkg = deletedPs.pkg; // Confirm if the system package has been updated // An updated system app can be deleted. This will also have to restore // the system pkg from system partition // reader - final PackageSetting disabledPs = action.disabledPs; + final PackageSetting disabledPs = action.mDisabledPs; if (DEBUG_REMOVE) Slog.d(TAG, "deleteSystemPackageLI: newPs=" + deletedPkg.getPackageName() + " disabledPs=" + disabledPs); Slog.d(TAG, "Deleting system pkg from data partition"); @@ -21983,7 +18032,7 @@ public class PackageManagerService extends IPackageManager.Stub if (applyUserRestrictions) { Slog.d(TAG, "Remembering install states:"); for (int userId : allUserHandles) { - final boolean finstalled = ArrayUtils.contains(outInfo.origUsers, userId); + final boolean finstalled = ArrayUtils.contains(outInfo.mOrigUsers, userId); Slog.d(TAG, " u=" + userId + " inst=" + finstalled); } } @@ -21991,7 +18040,7 @@ public class PackageManagerService extends IPackageManager.Stub if (outInfo != null) { // Delete the updated package - outInfo.isRemovedPackageSystemUpdate = true; + outInfo.mIsRemovedPackageSystemUpdate = true; } if (disabledPs.versionCode < deletedPs.versionCode) { @@ -22021,7 +18070,7 @@ public class PackageManagerService extends IPackageManager.Stub if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs); try { installPackageFromSystemLIF(disabledPs.getPathString(), allUserHandles, - outInfo == null ? null : outInfo.origUsers, writeSettings); + outInfo == null ? null : outInfo.mOrigUsers, writeSettings); } catch (PackageManagerException e) { Slog.w(TAG, "Failed to restore system package:" + deletedPkg.getPackageName() + ": " + e.getMessage()); @@ -22034,8 +18083,8 @@ public class PackageManagerService extends IPackageManager.Stub // and re-enable it afterward. final PackageSetting stubPs = mSettings.getPackageLPr(deletedPkg.getPackageName()); if (stubPs != null) { - int userId = action.user == null - ? UserHandle.USER_ALL : action.user.getIdentifier(); + int userId = action.mUser == null + ? UserHandle.USER_ALL : action.mUser.getIdentifier(); if (userId == UserHandle.USER_ALL) { for (int aUserId : allUserHandles) { stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, aUserId, "android"); @@ -22051,7 +18100,7 @@ public class PackageManagerService extends IPackageManager.Stub /** * Installs a package that's already on the system partition. */ - private AndroidPackage installPackageFromSystemLIF(@NonNull String codePathString, + private void installPackageFromSystemLIF(@NonNull String codePathString, @NonNull int[] allUserHandles, @Nullable int[] origUserHandles, boolean writeSettings) throws PackageManagerException { final File codePath = new File(codePathString); @@ -22133,7 +18182,6 @@ public class PackageManagerService extends IPackageManager.Stub writeSettingsLPrTEMP(); } } - return pkg; } private void deleteInstalledPackageLIF(PackageSetting ps, @@ -22141,8 +18189,8 @@ public class PackageManagerService extends IPackageManager.Stub PackageRemovedInfo outInfo, boolean writeSettings) { synchronized (mLock) { if (outInfo != null) { - outInfo.uid = ps.appId; - outInfo.broadcastAllowList = mAppsFilter.getVisibilityAllowList(ps, + outInfo.mUid = ps.appId; + outInfo.mBroadcastAllowList = mAppsFilter.getVisibilityAllowList(ps, allUserHandles, mSettings.getPackagesLocked()); } } @@ -22152,10 +18200,10 @@ public class PackageManagerService extends IPackageManager.Stub // Delete application code and resources only for parent packages if (deleteCodeAndResources && (outInfo != null)) { - outInfo.args = createInstallArgsForExisting( + outInfo.mArgs = createInstallArgsForExisting( ps.getPathString(), getAppDexInstructionSets( ps.primaryCpuAbiString, ps.secondaryCpuAbiString)); - if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args); + if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.mArgs); } } @@ -22211,23 +18259,6 @@ public class PackageManagerService extends IPackageManager.Stub return true; } - private static class DeletePackageAction { - public final PackageSetting deletingPs; - public final PackageSetting disabledPs; - public final PackageRemovedInfo outInfo; - public final int flags; - public final UserHandle user; - - private DeletePackageAction(PackageSetting deletingPs, PackageSetting disabledPs, - PackageRemovedInfo outInfo, int flags, UserHandle user) { - this.deletingPs = deletingPs; - this.disabledPs = disabledPs; - this.outInfo = outInfo; - this.flags = flags; - this.user = user; - } - } - /** * @return a {@link DeletePackageAction} if the provided package and related state may be * deleted, {@code null} otherwise. @@ -22260,8 +18291,7 @@ public class PackageManagerService extends IPackageManager.Stub */ private boolean deletePackageLIF(@NonNull String packageName, UserHandle user, boolean deleteCodeAndResources, @NonNull int[] allUserHandles, int flags, - PackageRemovedInfo outInfo, boolean writeSettings, - ParsedPackage replacingPackage) { + PackageRemovedInfo outInfo, boolean writeSettings) { final DeletePackageAction action; synchronized (mLock) { final PackageSetting ps = mSettings.getPackageLPr(packageName); @@ -22277,7 +18307,7 @@ public class PackageManagerService extends IPackageManager.Stub try { executeDeletePackageLIF(action, packageName, deleteCodeAndResources, - allUserHandles, writeSettings, replacingPackage); + allUserHandles, writeSettings); } catch (SystemDeleteException e) { if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: system deletion failure", e); return false; @@ -22285,23 +18315,14 @@ public class PackageManagerService extends IPackageManager.Stub return true; } - private static class SystemDeleteException extends Exception { - public final PackageManagerException reason; - - private SystemDeleteException(PackageManagerException reason) { - this.reason = reason; - } - } - /** Deletes a package. Only throws when install of a disabled package fails. */ - private void executeDeletePackageLIF(DeletePackageAction action, + void executeDeletePackageLIF(DeletePackageAction action, String packageName, boolean deleteCodeAndResources, - @NonNull int[] allUserHandles, boolean writeSettings, - ParsedPackage replacingPackage) throws SystemDeleteException { - final PackageSetting ps = action.deletingPs; - final PackageRemovedInfo outInfo = action.outInfo; - final UserHandle user = action.user; - final int flags = action.flags; + @NonNull int[] allUserHandles, boolean writeSettings) throws SystemDeleteException { + final PackageSetting ps = action.mDeletingPs; + final PackageRemovedInfo outInfo = action.mRemovedInfo; + final UserHandle user = action.mUser; + final int flags = action.mFlags; final boolean systemApp = isSystemApp(ps); // We need to get the permission state before package state is (potentially) destroyed. @@ -22372,7 +18393,7 @@ public class PackageManagerService extends IPackageManager.Stub // If the package removed had SUSPEND_APPS, unset any restrictions that might have been in // place for all affected users. - int[] affectedUserIds = (outInfo != null) ? outInfo.removedUsers : null; + int[] affectedUserIds = (outInfo != null) ? outInfo.mRemovedUsers : null; if (affectedUserIds == null) { affectedUserIds = resolveUserIds(userId); } @@ -22385,7 +18406,7 @@ public class PackageManagerService extends IPackageManager.Stub // Take a note whether we deleted the package for all users if (outInfo != null) { - outInfo.removedForAllUsers = mPackages.get(ps.name) == null; + outInfo.mRemovedForAllUsers = mPackages.get(ps.name) == null; } } @@ -22451,14 +18472,14 @@ public class PackageManagerService extends IPackageManager.Stub if (outInfo != null) { if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) { - outInfo.dataRemoved = true; + outInfo.mDataRemoved = true; } - outInfo.removedPackage = ps.name; - outInfo.installerPackageName = ps.installSource.installerPackageName; - outInfo.isStaticSharedLib = pkg != null && pkg.getStaticSharedLibName() != null; - outInfo.removedAppId = ps.appId; - outInfo.removedUsers = userIds; - outInfo.broadcastUsers = userIds; + outInfo.mRemovedPackage = ps.name; + outInfo.mInstallerPackageName = ps.installSource.installerPackageName; + outInfo.mIsStaticSharedLib = pkg != null && pkg.getStaticSharedLibName() != null; + outInfo.mRemovedAppId = ps.appId; + outInfo.mRemovedUsers = userIds; + outInfo.mBroadcastUsers = userIds; } } @@ -22473,7 +18494,7 @@ public class PackageManagerService extends IPackageManager.Stub try (PackageFreezer freezer = freezePackage(packageName, "clearApplicationProfileData")) { synchronized (mInstallLock) { - clearAppProfilesLIF(pkg, UserHandle.USER_ALL); + clearAppProfilesLIF(pkg); } } } @@ -22972,7 +18993,7 @@ public class PackageManagerService extends IPackageManager.Stub } private void restorePermissionsAndUpdateRolesForNewUserInstall(String packageName, - int installReason, @UserIdInt int userId) { + @UserIdInt int userId) { // We may also need to apply pending (restored) runtime permission grants // within these users. mPermissionManager.restoreDelayedRuntimePermissions(packageName, userId); @@ -23513,7 +19534,7 @@ public class PackageManagerService extends IPackageManager.Stub final List resolveInfos = queryIntentActivitiesInternal(intent, null, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId); final ResolveInfo preferredResolveInfo = findPreferredActivityNotLocked( - intent, null, 0, resolveInfos, 0, true, false, false, userId); + intent, null, 0, resolveInfos, true, false, false, userId); final String packageName = preferredResolveInfo != null && preferredResolveInfo.activityInfo != null ? preferredResolveInfo.activityInfo.packageName : null; @@ -23756,18 +19777,6 @@ public class PackageManagerService extends IPackageManager.Stub return packageName; } - @Nullable - private String[] ensureSystemPackageNames(@Nullable String[] packageNames) { - if (packageNames == null) { - return null; - } - final int packageNamesLength = packageNames.length; - for (int i = 0; i < packageNamesLength; i++) { - packageNames[i] = ensureSystemPackageName(packageNames[i]); - } - return ArrayUtils.filterNotNull(packageNames, String[]::new); - } - @Override public void setApplicationEnabledSetting(String appPackageName, int newState, int flags, int userId, String callingPackage) { @@ -24133,7 +20142,7 @@ public class PackageManagerService extends IPackageManager.Stub + componentNames); Bundle extras = new Bundle(4); extras.putString(Intent.EXTRA_CHANGED_COMPONENT_NAME, componentNames.get(0)); - String nameList[] = new String[componentNames.size()]; + String[] nameList = new String[componentNames.size()]; componentNames.toArray(nameList); extras.putStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, nameList); extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, dontKillApp); @@ -24407,11 +20416,7 @@ public class PackageManagerService extends IPackageManager.Stub componentInfo.getComponentName(), userId); if (componentEnabledSetting == COMPONENT_ENABLED_STATE_DEFAULT) { return componentInfo.isEnabled(); - } else if (componentEnabledSetting != COMPONENT_ENABLED_STATE_ENABLED) { - return false; - } - - return true; + } else return componentEnabledSetting == COMPONENT_ENABLED_STATE_ENABLED; } catch (PackageManager.NameNotFoundException ignored) { return false; } @@ -24868,7 +20873,7 @@ public class PackageManagerService extends IPackageManager.Stub ipw.println("Known Packages:"); ipw.increaseIndent(); for (int i = 0; i <= LAST_KNOWN_PACKAGE; i++) { - final String knownPackage = mPmInternal.knownPackageToString(i); + final String knownPackage = PackageManagerInternal.knownPackageToString(i); ipw.print(knownPackage); ipw.println(":"); final String[] pkgNames = mPmInternal.getKnownPackageNames(i, @@ -25233,9 +21238,9 @@ public class PackageManagerService extends IPackageManager.Stub //TODO: b/111402650 private void disableSkuSpecificApps() { - String apkList[] = mContext.getResources().getStringArray( + String[] apkList = mContext.getResources().getStringArray( R.array.config_disableApksUnlessMatchedSku_apk_list); - String skuArray[] = mContext.getResources().getStringArray( + String[] skuArray = mContext.getResources().getStringArray( R.array.config_disableApkUnlessMatchedSku_skus_list); if (ArrayUtils.isEmpty(apkList)) { return; @@ -25334,32 +21339,6 @@ public class PackageManagerService extends IPackageManager.Stub private static final String SD_ENCRYPTION_KEYSTORE_NAME = "AppsOnSD"; - private static final String SD_ENCRYPTION_ALGORITHM = "AES"; - - private boolean mMediaMounted = false; - - static String getEncryptKey() { - try { - String sdEncKey = SystemKeyStore.getInstance().retrieveKeyHexString( - SD_ENCRYPTION_KEYSTORE_NAME); - if (sdEncKey == null) { - sdEncKey = SystemKeyStore.getInstance().generateNewKeyHexString(128, - SD_ENCRYPTION_ALGORITHM, SD_ENCRYPTION_KEYSTORE_NAME); - if (sdEncKey == null) { - Slog.e(TAG, "Failed to create encryption keys"); - return null; - } - } - return sdEncKey; - } catch (NoSuchAlgorithmException nsae) { - Slog.e(TAG, "Failed to create encryption keys with exception: " + nsae); - return null; - } catch (IOException ioe) { - Slog.e(TAG, "Failed to retrieve encryption keys with exception: " + ioe); - return null; - } - } - private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing, ArrayList packages, IIntentReceiver finishedReceiver) { final int size = packages.size(); @@ -25374,8 +21353,8 @@ public class PackageManagerService extends IPackageManager.Stub finishedReceiver); } - private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing, - ArrayList pkgList, int uidArr[], IIntentReceiver finishedReceiver) { + void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing, + ArrayList pkgList, int[] uidArr, IIntentReceiver finishedReceiver) { sendResourcesChangedBroadcast(mediaStatus, replacing, pkgList.toArray(new String[pkgList.size()]), uidArr, finishedReceiver); } @@ -25519,7 +21498,7 @@ public class PackageManagerService extends IPackageManager.Stub try (PackageFreezer freezer = freezePackageForDelete(ps.name, deleteFlags, "unloadPrivatePackagesInner")) { if (deletePackageLIF(ps.name, null, false, userIds, deleteFlags, outInfo, - false, null)) { + false)) { unloaded.add(pkg); } else { Slog.w(TAG, "Failed to unload " + ps.getPath()); @@ -25776,7 +21755,7 @@ public class PackageManagerService extends IPackageManager.Stub *

* Note: To avoid a deadlock, do not call this method with {@code mLock} lock held */ - private void prepareAppDataAfterInstallLIF(AndroidPackage pkg) { + void prepareAppDataAfterInstallLIF(AndroidPackage pkg) { final PackageSetting ps; synchronized (mLock) { ps = mSettings.getPackageLPr(pkg.getPackageName()); @@ -25831,9 +21810,9 @@ public class PackageManagerService extends IPackageManager.Stub return prepareAppDataLeaf(batch, pkg, userId, flags); } - private @NonNull CompletableFuture prepareAppDataAndMigrate(@NonNull Installer.Batch batch, + private void prepareAppDataAndMigrate(@NonNull Installer.Batch batch, @NonNull AndroidPackage pkg, int userId, int flags, boolean maybeMigrateAppData) { - return prepareAppData(batch, pkg, userId, flags).thenRun(() -> { + prepareAppData(batch, pkg, userId, flags).thenRun(() -> { // Note: this code block is executed with the Installer lock // already held, since it's invoked as a side-effect of // executeBatchLI() @@ -25886,8 +21865,8 @@ public class PackageManagerService extends IPackageManager.Stub } catch (InstallerException e2) { logCriticalInfo(Log.DEBUG, "Recovery failed!"); } - } else if (e != null) { - Slog.e(TAG, "Failed to create app data for " + packageName + ": " + e); + } else { + Slog.e(TAG, "Failed to create app data for " + packageName); } // Prepare the application profiles only for upgrades and @@ -25990,21 +21969,7 @@ public class PackageManagerService extends IPackageManager.Stub } public PackageFreezer freezePackage(String packageName, int userId, String killReason) { - return new PackageFreezer(packageName, userId, killReason); - } - - public PackageFreezer freezePackageForInstall(String packageName, int installFlags, - String killReason) { - return freezePackageForInstall(packageName, UserHandle.USER_ALL, installFlags, killReason); - } - - public PackageFreezer freezePackageForInstall(String packageName, int userId, int installFlags, - String killReason) { - if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) { - return new PackageFreezer(); - } else { - return freezePackage(packageName, userId, killReason); - } + return new PackageFreezer(packageName, userId, killReason, this); } public PackageFreezer freezePackageForDelete(String packageName, int deleteFlags, @@ -26015,73 +21980,12 @@ public class PackageManagerService extends IPackageManager.Stub public PackageFreezer freezePackageForDelete(String packageName, int userId, int deleteFlags, String killReason) { if ((deleteFlags & PackageManager.DELETE_DONT_KILL_APP) != 0) { - return new PackageFreezer(); + return new PackageFreezer(this); } else { return freezePackage(packageName, userId, killReason); } } - /** - * 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. - */ - private class PackageFreezer implements AutoCloseable { - private final String mPackageName; - - private final boolean mWeFroze; - - private final AtomicBoolean mClosed = new AtomicBoolean(); - private final CloseGuard mCloseGuard = CloseGuard.get(); - - /** - * 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}. - */ - public PackageFreezer() { - mPackageName = null; - mWeFroze = false; - mCloseGuard.open("close"); - } - - public PackageFreezer(String packageName, int userId, String killReason) { - synchronized (mLock) { - mPackageName = packageName; - mWeFroze = mFrozenPackages.add(mPackageName); - - final PackageSetting ps = mSettings.getPackageLPr(mPackageName); - if (ps != null) { - 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 (mLock) { - if (mWeFroze) { - mFrozenPackages.remove(mPackageName); - } - } - } - } - } - /** * Verify that given package is currently frozen. */ @@ -26324,23 +22228,14 @@ public class PackageManagerService extends IPackageManager.Stub installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; - final Message msg = mHandler.obtainMessage(INIT_COPY); final OriginInfo origin = OriginInfo.fromExistingFile(codeFile); final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); final ParseResult ret = ApkLiteParseUtils.parsePackageLite(input, - new File(origin.resolvedPath), /* flags */ 0); + new File(origin.mResolvedPath), /* flags */ 0); final PackageLite lite = ret.isSuccess() ? ret.getResult() : null; final InstallParams params = new InstallParams(origin, move, installObserver, installFlags, - installSource, volumeUuid, user, packageAbiOverride, lite); - params.setTraceMethod("movePackage").setTraceCookie(System.identityHashCode(params)); - msg.obj = params; - - Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "movePackage", - System.identityHashCode(msg.obj)); - Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall", - System.identityHashCode(msg.obj)); - - mHandler.sendMessage(msg); + installSource, volumeUuid, user, packageAbiOverride, lite, this); + params.movePackage(); } /** @@ -26356,7 +22251,7 @@ public class PackageManagerService extends IPackageManager.Stub return; } - final StorageManager storage = mInjector.getSystemService(StorageManager.class);; + final StorageManager storage = mInjector.getSystemService(StorageManager.class); VolumeInfo volume = storage.findVolumeByUuid(pkg.getStorageUuid().toString()); int packageExternalStorageType = getPackageExternalStorageType(volume, pkg.isExternalStorage()); @@ -26606,11 +22501,7 @@ public class PackageManagerService extends IPackageManager.Stub Binder.restoreCallingIdentity(token); } final boolean b; - if (userInfo != null && userInfo.isManagedProfile()) { - b = true; - } else { - b = false; - } + b = userInfo != null && userInfo.isManagedProfile(); mUserNeedsBadging.put(userId, b); return b; } @@ -26727,7 +22618,7 @@ public class PackageManagerService extends IPackageManager.Stub } } - private Pair verifyReplacingVersionCode(PackageInfoLite pkgLite, + Pair verifyReplacingVersionCode(PackageInfoLite pkgLite, long requiredInstalledVersionCode, int installFlags) { if ((installFlags & PackageManager.INSTALL_APEX) != 0) { return verifyReplacingVersionCodeForApex( @@ -26832,12 +22723,12 @@ public class PackageManagerService extends IPackageManager.Stub if (after.getLongVersionCode() < before.getLongVersionCode()) { throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE, "Update version code " + after.versionCode + " is older than current " - + before.getLongVersionCode()); + + before.getLongVersionCode()); } else if (after.getLongVersionCode() == before.getLongVersionCode()) { if (after.baseRevisionCode < before.getBaseRevisionCode()) { throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE, "Update base revision code " + after.baseRevisionCode - + " is older than current " + before.getBaseRevisionCode()); + + " is older than current " + before.getBaseRevisionCode()); } if (!ArrayUtils.isEmpty(after.splitNames)) { @@ -26848,8 +22739,9 @@ public class PackageManagerService extends IPackageManager.Stub if (after.splitRevisionCodes[i] < before.getSplitRevisionCodes()[j]) { throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE, "Update split " + splitName + " revision code " - + after.splitRevisionCodes[i] + " is older than current " - + before.getSplitRevisionCodes()[j]); + + after.splitRevisionCodes[i] + + " is older than current " + + before.getSplitRevisionCodes()[j]); } } } @@ -27068,7 +22960,7 @@ public class PackageManagerService extends IPackageManager.Stub boolean[] results = new boolean[packageNames.length]; for (int i = results.length - 1; i >= 0; --i) { ApplicationInfo appInfo = getApplicationInfo(packageNames[i], 0, callingUser); - results[i] = appInfo == null ? false : appInfo.isAudioPlaybackCaptureAllowed(); + results[i] = appInfo != null && appInfo.isAudioPlaybackCaptureAllowed(); } return results; } @@ -27287,7 +23179,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public @Nullable String getDisabledSystemPackageName(@NonNull String packageName) { - PackageSetting disabledPkgSetting = (PackageSetting) getDisabledSystemPackage( + PackageSetting disabledPkgSetting = getDisabledSystemPackage( packageName); AndroidPackage disabledPkg = disabledPkgSetting == null ? null : disabledPkgSetting.pkg; return disabledPkg == null ? null : disabledPkg.getPackageName(); @@ -27435,7 +23327,7 @@ public class PackageManagerService extends IPackageManager.Stub public boolean isPackageSuspended(String packageName, int userId) { synchronized (mLock) { final PackageSetting ps = mSettings.getPackageLPr(packageName); - return (ps != null) ? ps.getSuspended(userId) : false; + return ps != null && ps.getSuspended(userId); } } @@ -27616,7 +23508,7 @@ public class PackageManagerService extends IPackageManager.Stub public boolean isPackageEphemeral(int userId, String packageName) { synchronized (mLock) { final PackageSetting ps = mSettings.getPackageLPr(packageName); - return ps != null ? ps.getInstantApp(userId) : false; + return ps != null && ps.getInstantApp(userId); } } @@ -28481,10 +24373,6 @@ public class PackageManagerService extends IPackageManager.Stub processName, uid, seinfo, pid); } - public CompilerStats.PackageStats getCompilerPackageStats(String pkgName) { - return mCompilerStats.getPackageStats(pkgName); - } - public CompilerStats.PackageStats getOrCreateCompilerPackageStats(AndroidPackage pkg) { return getOrCreateCompilerPackageStats(pkg.getPackageName()); } @@ -28493,10 +24381,6 @@ public class PackageManagerService extends IPackageManager.Stub return mCompilerStats.getOrCreatePackageStats(pkgName); } - public void deleteCompilerPackageStats(String pkgName) { - mCompilerStats.deletePackageStats(pkgName); - } - @Override public boolean isAutoRevokeWhitelisted(String packageName) { int mode = mInjector.getSystemService(AppOpsManager.class).checkOpNoThrow( @@ -28821,7 +24705,7 @@ public class PackageManagerService extends IPackageManager.Stub * * TODO(zhanghai): This should be removed once we finish migration of permission storage. */ - private void writeSettingsLPrTEMP() { + void writeSettingsLPrTEMP() { mPermissionManager.writeLegacyPermissionsTEMP(mSettings.mPermissions); mSettings.writeLPr(); } @@ -28979,11 +24863,6 @@ public class PackageManagerService extends IPackageManager.Stub return bOptions; } - @NonNull - public DomainVerificationService.Connection getDomainVerificationConnection() { - return mDomainVerificationConnection; - } - @Override public void setKeepUninstalledPackages(List packageList) { mContext.enforceCallingPermission( @@ -29086,19 +24965,4 @@ public class PackageManagerService extends IPackageManager.Stub } } -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(final String action, final String pkg, - final Bundle extras, final int flags, final String targetPkg, - final IIntentReceiver finishedReceiver, final int[] userIds, int[] instantUserIds, - @Nullable SparseArray 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); -} + diff --git a/services/core/java/com/android/server/pm/PackageRemovedInfo.java b/services/core/java/com/android/server/pm/PackageRemovedInfo.java new file mode 100644 index 0000000000000..e3581db146742 --- /dev/null +++ b/services/core/java/com/android/server/pm/PackageRemovedInfo.java @@ -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 mInstallReasons; + SparseArray 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 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); + } + } + } +} diff --git a/services/core/java/com/android/server/pm/PackageSender.java b/services/core/java/com/android/server/pm/PackageSender.java new file mode 100644 index 0000000000000..d380098d44b3f --- /dev/null +++ b/services/core/java/com/android/server/pm/PackageSender.java @@ -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 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); +} diff --git a/services/core/java/com/android/server/pm/PackageVerificationState.java b/services/core/java/com/android/server/pm/PackageVerificationState.java index cb9c2e997e227..a652d1c843eb4 100644 --- a/services/core/java/com/android/server/pm/PackageVerificationState.java +++ b/services/core/java/com/android/server/pm/PackageVerificationState.java @@ -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 diff --git a/services/core/java/com/android/server/pm/PrepareFailure.java b/services/core/java/com/android/server/pm/PrepareFailure.java new file mode 100644 index 0000000000000..a54ffa3219bca --- /dev/null +++ b/services/core/java/com/android/server/pm/PrepareFailure.java @@ -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; + } +} diff --git a/services/core/java/com/android/server/pm/PrepareResult.java b/services/core/java/com/android/server/pm/PrepareResult.java new file mode 100644 index 0000000000000..4e08e166ff0bb --- /dev/null +++ b/services/core/java/com/android/server/pm/PrepareResult.java @@ -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; + } +} diff --git a/services/core/java/com/android/server/pm/ReconcileFailure.java b/services/core/java/com/android/server/pm/ReconcileFailure.java new file mode 100644 index 0000000000000..c9615ffc1690b --- /dev/null +++ b/services/core/java/com/android/server/pm/ReconcileFailure.java @@ -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()); + } +} diff --git a/services/core/java/com/android/server/pm/ReconcileRequest.java b/services/core/java/com/android/server/pm/ReconcileRequest.java new file mode 100644 index 0000000000000..31881388e6ec0 --- /dev/null +++ b/services/core/java/com/android/server/pm/ReconcileRequest.java @@ -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 mScannedPackages; + + public final Map mAllPackages; + public final Map> mSharedLibrarySource; + public final Map mInstallArgs; + public final Map mInstallResults; + public final Map mPreparedPackages; + public final Map mVersionInfos; + public final Map mLastStaticSharedLibSettings; + + ReconcileRequest(Map scannedPackages, + Map installArgs, + Map installResults, + Map preparedPackages, + Map> sharedLibrarySource, + Map allPackages, + Map versionInfos, + Map lastStaticSharedLibSettings) { + mScannedPackages = scannedPackages; + mInstallArgs = installArgs; + mInstallResults = installResults; + mPreparedPackages = preparedPackages; + mSharedLibrarySource = sharedLibrarySource; + mAllPackages = allPackages; + mVersionInfos = versionInfos; + mLastStaticSharedLibSettings = lastStaticSharedLibSettings; + } + + ReconcileRequest(Map scannedPackages, + Map> sharedLibrarySource, + Map allPackages, + Map versionInfos, + Map lastStaticSharedLibSettings) { + this(scannedPackages, Collections.emptyMap(), Collections.emptyMap(), + Collections.emptyMap(), sharedLibrarySource, allPackages, versionInfos, + lastStaticSharedLibSettings); + } +} diff --git a/services/core/java/com/android/server/pm/ReconciledPackage.java b/services/core/java/com/android/server/pm/ReconciledPackage.java new file mode 100644 index 0000000000000..f78249f0e757e --- /dev/null +++ b/services/core/java/com/android/server/pm/ReconciledPackage.java @@ -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 mAllowedSharedLibraryInfos; + public final SigningDetails mSigningDetails; + public final boolean mSharedUserSignaturesChanged; + public ArrayList mCollectedSharedLibraryInfos; + public final boolean mRemoveAppKeySetData; + + ReconciledPackage(ReconcileRequest request, + InstallArgs installArgs, + PackageSetting pkgSetting, + PackageInstalledInfo installResult, + PrepareResult prepareResult, + ScanResult scanResult, + DeletePackageAction deletePackageAction, + List 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 getCombinedAvailablePackages() { + final ArrayMap 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; + } +} diff --git a/services/core/java/com/android/server/pm/ScanRequest.java b/services/core/java/com/android/server/pm/ScanRequest.java new file mode 100644 index 0000000000000..482b79cf83787 --- /dev/null +++ b/services/core/java/com/android/server/pm/ScanRequest.java @@ -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. + *

IMPORTANT: 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; + } +} diff --git a/services/core/java/com/android/server/pm/ScanResult.java b/services/core/java/com/android/server/pm/ScanResult.java new file mode 100644 index 0000000000000..6915a500210c8 --- /dev/null +++ b/services/core/java/com/android/server/pm/ScanResult.java @@ -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 mChangedAbiCodePath; + + public final SharedLibraryInfo mStaticSharedLibraryInfo; + + public final List mDynamicSharedLibraryInfos; + + ScanResult( + ScanRequest request, boolean success, + @Nullable PackageSetting pkgSetting, + @Nullable List changedAbiCodePath, boolean existingSettingCopied, + SharedLibraryInfo staticSharedLibraryInfo, + List dynamicSharedLibraryInfos) { + mRequest = request; + mSuccess = success; + mPkgSetting = pkgSetting; + mChangedAbiCodePath = changedAbiCodePath; + mExistingSettingCopied = existingSettingCopied; + mStaticSharedLibraryInfo = staticSharedLibraryInfo; + mDynamicSharedLibraryInfos = dynamicSharedLibraryInfos; + } +} diff --git a/services/core/java/com/android/server/pm/SystemDeleteException.java b/services/core/java/com/android/server/pm/SystemDeleteException.java new file mode 100644 index 0000000000000..410876ff2a475 --- /dev/null +++ b/services/core/java/com/android/server/pm/SystemDeleteException.java @@ -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; + } +} diff --git a/services/core/java/com/android/server/pm/VerificationInfo.java b/services/core/java/com/android/server/pm/VerificationInfo.java new file mode 100644 index 0000000000000..3d4a42c16c1b1 --- /dev/null +++ b/services/core/java/com/android/server/pm/VerificationInfo.java @@ -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; + } +} diff --git a/services/core/java/com/android/server/pm/VerificationParams.java b/services/core/java/com/android/server/pm/VerificationParams.java new file mode 100644 index 0000000000000..3c499de9ea468 --- /dev/null +++ b/services/core/java/com/android/server/pm/VerificationParams.java @@ -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. + * + *

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 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 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 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 matchVerifiers(PackageInfoLite pkgInfo, + List receivers, final PackageVerificationState verificationState) { + if (pkgInfo.verifiers.length == 0) { + return null; + } + + final int n = pkgInfo.verifiers.length; + final List 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 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 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 mChildParams; + private final Map mVerificationState; + + MultiPackageVerificationParams(VerificationParams parent, List 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."); + } + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java index 976a588273a7e..f241fe1b86bd2 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java @@ -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 diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java index 12fb400cbdb72..54bfe01999756 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java +++ b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java @@ -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); diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java index 8153242949231..6c6cfd45c6c50 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java @@ -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 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"));