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"));