| /* |
| * 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.pm.PackageInstaller.SessionParams.USER_ACTION_UNSPECIFIED; |
| import static android.content.pm.PackageManager.INSTALL_REASON_UNKNOWN; |
| import static android.content.pm.PackageManager.INSTALL_SCENARIO_DEFAULT; |
| import static android.content.pm.PackageManager.INSTALL_SUCCEEDED; |
| import static android.os.Process.INVALID_UID; |
| |
| import static com.android.server.pm.PackageManagerService.SCAN_AS_INSTANT_APP; |
| import static com.android.server.pm.PackageManagerService.TAG; |
| |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.apex.ApexInfo; |
| import android.app.AppOpsManager; |
| import android.content.pm.DataLoaderType; |
| import android.content.pm.IPackageInstallObserver2; |
| import android.content.pm.PackageInstaller; |
| import android.content.pm.PackageManager; |
| import android.content.pm.SharedLibraryInfo; |
| import android.content.pm.SigningDetails; |
| import android.net.Uri; |
| import android.os.Build; |
| import android.os.Process; |
| import android.os.UserHandle; |
| import android.util.ArrayMap; |
| import android.util.ExceptionUtils; |
| import android.util.Slog; |
| |
| import com.android.server.art.model.DexoptResult; |
| import com.android.server.pm.parsing.pkg.ParsedPackage; |
| import com.android.server.pm.pkg.AndroidPackage; |
| import com.android.server.pm.pkg.PackageState; |
| import com.android.server.pm.pkg.PackageStateInternal; |
| import com.android.server.pm.pkg.parsing.ParsingPackageUtils; |
| |
| import java.io.File; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| final class InstallRequest { |
| private final int mUserId; |
| @Nullable |
| private final InstallArgs mInstallArgs; |
| @Nullable |
| private Runnable mPostInstallRunnable; |
| @Nullable |
| private PackageRemovedInfo mRemovedInfo; |
| |
| @PackageManagerService.ScanFlags |
| private int mScanFlags; |
| @ParsingPackageUtils.ParseFlags |
| private int mParseFlags; |
| private boolean mReplace; |
| |
| @Nullable /* The original Package if it is being replaced, otherwise {@code null} */ |
| private AndroidPackage mExistingPackage; |
| /** parsed package to be scanned */ |
| @Nullable |
| private ParsedPackage mParsedPackage; |
| private boolean mClearCodeCache; |
| private boolean mSystem; |
| @Nullable |
| private PackageSetting mOriginalPs; |
| @Nullable |
| private PackageSetting mDisabledPs; |
| |
| /** Package Installed Info */ |
| @Nullable |
| private String mName; |
| private int mAppId = INVALID_UID; |
| // The set of users that originally had this package installed. |
| @Nullable |
| private int[] mOrigUsers; |
| // The set of users that now have this package installed. |
| @Nullable |
| private int[] mNewUsers; |
| @Nullable |
| private AndroidPackage mPkg; |
| private int mReturnCode; |
| private int mInternalErrorCode; |
| @Nullable |
| private String mReturnMsg; |
| // The set of packages consuming this shared library or null if no consumers exist. |
| @Nullable |
| private ArrayList<AndroidPackage> mLibraryConsumers; |
| @Nullable |
| private PackageFreezer mFreezer; |
| /** The package this package replaces */ |
| @Nullable |
| private String mOrigPackage; |
| @Nullable |
| private String mOrigPermission; |
| // The ApexInfo returned by ApexManager#installPackage, used by rebootless APEX install |
| @Nullable |
| private ApexInfo mApexInfo; |
| |
| /** |
| * For tracking {@link PackageState#getApexModuleName()}. |
| */ |
| @Nullable |
| private String mApexModuleName; |
| |
| @Nullable |
| private ScanResult mScanResult; |
| |
| private boolean mIsInstallInherit; |
| private boolean mIsInstallForUsers; |
| |
| @Nullable |
| private final PackageMetrics mPackageMetrics; |
| private final int mSessionId; |
| private final int mRequireUserAction; |
| |
| private int mDexoptStatus; |
| |
| // New install |
| InstallRequest(InstallingSession params) { |
| mUserId = params.getUser().getIdentifier(); |
| mInstallArgs = new InstallArgs(params.mOriginInfo, params.mMoveInfo, params.mObserver, |
| params.mInstallFlags, params.mInstallSource, params.mVolumeUuid, |
| params.getUser(), null /*instructionSets*/, params.mPackageAbiOverride, |
| params.mPermissionStates, params.mAllowlistedRestrictedPermissions, |
| params.mAutoRevokePermissionsMode, params.mTraceMethod, params.mTraceCookie, |
| params.mSigningDetails, params.mInstallReason, params.mInstallScenario, |
| params.mForceQueryableOverride, params.mDataLoaderType, params.mPackageSource, |
| params.mApplicationEnabledSettingPersistent); |
| mPackageMetrics = new PackageMetrics(this); |
| mIsInstallInherit = params.mIsInherit; |
| mSessionId = params.mSessionId; |
| mRequireUserAction = params.mRequireUserAction; |
| } |
| |
| // Install existing package as user |
| InstallRequest(int userId, int returnCode, AndroidPackage pkg, int[] newUsers, |
| Runnable runnable) { |
| mUserId = userId; |
| mInstallArgs = null; |
| mReturnCode = returnCode; |
| mPkg = pkg; |
| mNewUsers = newUsers; |
| mPostInstallRunnable = runnable; |
| mPackageMetrics = new PackageMetrics(this); |
| mIsInstallForUsers = true; |
| mSessionId = -1; |
| mRequireUserAction = USER_ACTION_UNSPECIFIED; |
| } |
| |
| // addForInit |
| InstallRequest(ParsedPackage parsedPackage, int parseFlags, int scanFlags, |
| @Nullable UserHandle user, ScanResult scanResult) { |
| if (user != null) { |
| mUserId = user.getIdentifier(); |
| } else { |
| // APEX |
| mUserId = UserHandle.USER_SYSTEM; |
| } |
| mInstallArgs = null; |
| mParsedPackage = parsedPackage; |
| mParseFlags = parseFlags; |
| mScanFlags = scanFlags; |
| mScanResult = scanResult; |
| mPackageMetrics = null; // No logging from this code path |
| mSessionId = -1; |
| mRequireUserAction = USER_ACTION_UNSPECIFIED; |
| } |
| |
| @Nullable |
| public String getName() { |
| return mName; |
| } |
| |
| @Nullable |
| public String getReturnMsg() { |
| return mReturnMsg; |
| } |
| |
| @Nullable |
| public OriginInfo getOriginInfo() { |
| return mInstallArgs == null ? null : mInstallArgs.mOriginInfo; |
| } |
| |
| @Nullable |
| public PackageRemovedInfo getRemovedInfo() { |
| return mRemovedInfo; |
| } |
| |
| @Nullable |
| public String getOrigPackage() { |
| return mOrigPackage; |
| } |
| |
| @Nullable |
| public String getOrigPermission() { |
| return mOrigPermission; |
| } |
| |
| @Nullable |
| public File getCodeFile() { |
| return mInstallArgs == null ? null : mInstallArgs.mCodeFile; |
| } |
| |
| @Nullable |
| public String getCodePath() { |
| return (mInstallArgs != null && mInstallArgs.mCodeFile != null) |
| ? mInstallArgs.mCodeFile.getAbsolutePath() : null; |
| } |
| |
| @Nullable |
| public String getAbiOverride() { |
| return mInstallArgs == null ? null : mInstallArgs.mAbiOverride; |
| } |
| |
| public int getReturnCode() { |
| return mReturnCode; |
| } |
| |
| public int getInternalErrorCode() { |
| return mInternalErrorCode; |
| } |
| |
| @Nullable |
| public IPackageInstallObserver2 getObserver() { |
| return mInstallArgs == null ? null : mInstallArgs.mObserver; |
| } |
| |
| public boolean isInstallMove() { |
| return mInstallArgs != null && mInstallArgs.mMoveInfo != null; |
| } |
| |
| @Nullable |
| public String getMoveToUuid() { |
| return (mInstallArgs != null && mInstallArgs.mMoveInfo != null) |
| ? mInstallArgs.mMoveInfo.mToUuid : null; |
| } |
| |
| @Nullable |
| public String getMovePackageName() { |
| return (mInstallArgs != null && mInstallArgs.mMoveInfo != null) |
| ? mInstallArgs.mMoveInfo.mPackageName : null; |
| } |
| |
| @Nullable |
| public String getMoveFromCodePath() { |
| return (mInstallArgs != null && mInstallArgs.mMoveInfo != null) |
| ? mInstallArgs.mMoveInfo.mFromCodePath : null; |
| } |
| |
| @Nullable |
| public File getOldCodeFile() { |
| return (mRemovedInfo != null && mRemovedInfo.mArgs != null) |
| ? mRemovedInfo.mArgs.mCodeFile : null; |
| } |
| |
| @Nullable |
| public String[] getOldInstructionSet() { |
| return (mRemovedInfo != null && mRemovedInfo.mArgs != null) |
| ? mRemovedInfo.mArgs.mInstructionSets : null; |
| } |
| |
| public UserHandle getUser() { |
| return new UserHandle(mUserId); |
| } |
| |
| public int getUserId() { |
| return mUserId; |
| } |
| |
| public int getInstallFlags() { |
| return mInstallArgs == null ? 0 : mInstallArgs.mInstallFlags; |
| } |
| |
| public int getInstallReason() { |
| return mInstallArgs == null ? INSTALL_REASON_UNKNOWN : mInstallArgs.mInstallReason; |
| } |
| |
| @Nullable |
| public String getVolumeUuid() { |
| return mInstallArgs == null ? null : mInstallArgs.mVolumeUuid; |
| } |
| |
| @Nullable |
| public AndroidPackage getPkg() { |
| return mPkg; |
| } |
| |
| @Nullable |
| public String getTraceMethod() { |
| return mInstallArgs == null ? null : mInstallArgs.mTraceMethod; |
| } |
| |
| public int getTraceCookie() { |
| return mInstallArgs == null ? 0 : mInstallArgs.mTraceCookie; |
| } |
| |
| public boolean isUpdate() { |
| return mRemovedInfo != null && mRemovedInfo.mRemovedPackage != null; |
| } |
| |
| @Nullable |
| public String getRemovedPackage() { |
| return mRemovedInfo != null ? mRemovedInfo.mRemovedPackage : null; |
| } |
| |
| public boolean isInstallExistingForUser() { |
| return mInstallArgs == null; |
| } |
| |
| @Nullable |
| public InstallSource getInstallSource() { |
| return mInstallArgs == null ? null : mInstallArgs.mInstallSource; |
| } |
| |
| @Nullable |
| public String getInstallerPackageName() { |
| return (mInstallArgs != null && mInstallArgs.mInstallSource != null) |
| ? mInstallArgs.mInstallSource.mInstallerPackageName : null; |
| } |
| |
| public int getInstallerPackageUid() { |
| return (mInstallArgs != null && mInstallArgs.mInstallSource != null) |
| ? mInstallArgs.mInstallSource.mInstallerPackageUid : INVALID_UID; |
| } |
| |
| public int getDataLoaderType() { |
| return mInstallArgs == null ? DataLoaderType.NONE : mInstallArgs.mDataLoaderType; |
| } |
| |
| public int getSignatureSchemeVersion() { |
| return mInstallArgs == null ? SigningDetails.SignatureSchemeVersion.UNKNOWN |
| : mInstallArgs.mSigningDetails.getSignatureSchemeVersion(); |
| } |
| |
| @NonNull |
| public SigningDetails getSigningDetails() { |
| return mInstallArgs == null ? SigningDetails.UNKNOWN : mInstallArgs.mSigningDetails; |
| } |
| |
| @Nullable |
| public Uri getOriginUri() { |
| return mInstallArgs == null ? null : Uri.fromFile(mInstallArgs.mOriginInfo.mResolvedFile); |
| } |
| |
| @Nullable |
| public ApexInfo getApexInfo() { |
| return mApexInfo; |
| } |
| |
| @Nullable |
| public String getApexModuleName() { |
| return mApexModuleName; |
| } |
| |
| @Nullable |
| public String getSourceInstallerPackageName() { |
| return mInstallArgs.mInstallSource.mInstallerPackageName; |
| } |
| |
| public boolean isRollback() { |
| return mInstallArgs != null |
| && mInstallArgs.mInstallReason == PackageManager.INSTALL_REASON_ROLLBACK; |
| } |
| |
| @Nullable |
| public int[] getNewUsers() { |
| return mNewUsers; |
| } |
| |
| @Nullable |
| public int[] getOriginUsers() { |
| return mOrigUsers; |
| } |
| |
| public int getAppId() { |
| return mAppId; |
| } |
| |
| @Nullable |
| public ArrayMap<String, Integer> getPermissionStates() { |
| return mInstallArgs == null ? null : mInstallArgs.mPermissionStates; |
| } |
| |
| @Nullable |
| public ArrayList<AndroidPackage> getLibraryConsumers() { |
| return mLibraryConsumers; |
| } |
| |
| @Nullable |
| public AndroidPackage getExistingPackage() { |
| return mExistingPackage; |
| } |
| |
| @Nullable |
| public List<String> getAllowlistedRestrictedPermissions() { |
| return mInstallArgs == null ? null : mInstallArgs.mAllowlistedRestrictedPermissions; |
| } |
| |
| public int getAutoRevokePermissionsMode() { |
| return mInstallArgs == null |
| ? AppOpsManager.MODE_DEFAULT : mInstallArgs.mAutoRevokePermissionsMode; |
| } |
| |
| public int getPackageSource() { |
| return mInstallArgs == null |
| ? PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED : mInstallArgs.mPackageSource; |
| } |
| |
| public int getInstallScenario() { |
| return mInstallArgs == null ? INSTALL_SCENARIO_DEFAULT : mInstallArgs.mInstallScenario; |
| } |
| |
| @Nullable |
| public ParsedPackage getParsedPackage() { |
| return mParsedPackage; |
| } |
| |
| @ParsingPackageUtils.ParseFlags |
| public int getParseFlags() { |
| return mParseFlags; |
| } |
| |
| @PackageManagerService.ScanFlags |
| public int getScanFlags() { |
| return mScanFlags; |
| } |
| |
| @Nullable |
| public String getExistingPackageName() { |
| if (mExistingPackage != null) { |
| return mExistingPackage.getPackageName(); |
| } |
| return null; |
| } |
| |
| @Nullable |
| public AndroidPackage getScanRequestOldPackage() { |
| assertScanResultExists(); |
| return mScanResult.mRequest.mOldPkg; |
| } |
| |
| public boolean isClearCodeCache() { |
| return mClearCodeCache; |
| } |
| |
| public boolean isInstallReplace() { |
| return mReplace; |
| } |
| |
| public boolean isInstallSystem() { |
| return mSystem; |
| } |
| |
| public boolean isInstallInherit() { |
| return mIsInstallInherit; |
| } |
| |
| public boolean isInstallForUsers() { |
| return mIsInstallForUsers; |
| } |
| |
| public boolean isInstallFromAdb() { |
| return mInstallArgs != null |
| && (mInstallArgs.mInstallFlags & PackageManager.INSTALL_FROM_ADB) != 0; |
| } |
| |
| @Nullable |
| public PackageSetting getOriginalPackageSetting() { |
| return mOriginalPs; |
| } |
| |
| @Nullable |
| public PackageSetting getDisabledPackageSetting() { |
| return mDisabledPs; |
| } |
| |
| @Nullable |
| public PackageSetting getScanRequestOldPackageSetting() { |
| assertScanResultExists(); |
| return mScanResult.mRequest.mOldPkgSetting; |
| } |
| |
| @Nullable |
| public PackageSetting getScanRequestOriginalPackageSetting() { |
| assertScanResultExists(); |
| return mScanResult.mRequest.mOriginalPkgSetting; |
| } |
| |
| @Nullable |
| public PackageSetting getScanRequestPackageSetting() { |
| assertScanResultExists(); |
| return mScanResult.mRequest.mPkgSetting; |
| } |
| |
| @Nullable |
| public String getRealPackageName() { |
| assertScanResultExists(); |
| return mScanResult.mRequest.mRealPkgName; |
| } |
| |
| @Nullable |
| public List<String> getChangedAbiCodePath() { |
| assertScanResultExists(); |
| return mScanResult.mChangedAbiCodePath; |
| } |
| |
| public boolean isApplicationEnabledSettingPersistent() { |
| return mInstallArgs == null ? false : mInstallArgs.mApplicationEnabledSettingPersistent; |
| } |
| |
| public boolean isForceQueryableOverride() { |
| return mInstallArgs != null && mInstallArgs.mForceQueryableOverride; |
| } |
| |
| @Nullable |
| public SharedLibraryInfo getSdkSharedLibraryInfo() { |
| assertScanResultExists(); |
| return mScanResult.mSdkSharedLibraryInfo; |
| } |
| |
| @Nullable |
| public SharedLibraryInfo getStaticSharedLibraryInfo() { |
| assertScanResultExists(); |
| return mScanResult.mStaticSharedLibraryInfo; |
| } |
| |
| @Nullable |
| public List<SharedLibraryInfo> getDynamicSharedLibraryInfos() { |
| assertScanResultExists(); |
| return mScanResult.mDynamicSharedLibraryInfos; |
| } |
| |
| @Nullable |
| public PackageSetting getScannedPackageSetting() { |
| assertScanResultExists(); |
| return mScanResult.mPkgSetting; |
| } |
| |
| @Nullable |
| public PackageSetting getRealPackageSetting() { |
| // 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 = isExistingSettingCopied() |
| ? getScanRequestPackageSetting() : getScannedPackageSetting(); |
| if (realPkgSetting == null) { |
| realPkgSetting = getScannedPackageSetting(); |
| } |
| return realPkgSetting; |
| } |
| |
| public boolean isExistingSettingCopied() { |
| assertScanResultExists(); |
| return mScanResult.mExistingSettingCopied; |
| } |
| |
| /** |
| * Whether the original PackageSetting needs to be updated with |
| * a new app ID. Useful when leaving a sharedUserId. |
| */ |
| public boolean needsNewAppId() { |
| assertScanResultExists(); |
| return mScanResult.mPreviousAppId != Process.INVALID_UID; |
| } |
| |
| public int getPreviousAppId() { |
| assertScanResultExists(); |
| return mScanResult.mPreviousAppId; |
| } |
| |
| public boolean isPlatformPackage() { |
| assertScanResultExists(); |
| return mScanResult.mRequest.mIsPlatformPackage; |
| } |
| |
| public boolean isInstantInstall() { |
| return (mScanFlags & SCAN_AS_INSTANT_APP) != 0; |
| } |
| |
| public void assertScanResultExists() { |
| if (mScanResult == null) { |
| // Should not happen. This indicates a bug in the installation code flow |
| if (Build.IS_USERDEBUG || Build.IS_ENG) { |
| throw new IllegalStateException("ScanResult cannot be null."); |
| } else { |
| Slog.e(TAG, "ScanResult is null and it should not happen"); |
| } |
| } |
| } |
| |
| public int getSessionId() { |
| return mSessionId; |
| } |
| |
| public int getRequireUserAction() { |
| return mRequireUserAction; |
| } |
| |
| public int getDexoptStatus() { |
| return mDexoptStatus; |
| } |
| |
| public void setScanFlags(int scanFlags) { |
| mScanFlags = scanFlags; |
| } |
| |
| public void closeFreezer() { |
| if (mFreezer != null) { |
| mFreezer.close(); |
| } |
| } |
| |
| public void runPostInstallRunnable() { |
| if (mPostInstallRunnable != null) { |
| mPostInstallRunnable.run(); |
| } |
| } |
| |
| public void setCodeFile(File codeFile) { |
| if (mInstallArgs != null) { |
| mInstallArgs.mCodeFile = codeFile; |
| } |
| } |
| |
| public void setError(int code, String msg) { |
| setReturnCode(code); |
| setReturnMessage(msg); |
| Slog.w(TAG, msg); |
| if (mPackageMetrics != null) { |
| mPackageMetrics.onInstallFailed(); |
| } |
| } |
| |
| public void setError(PackageManagerException e) { |
| setError(null, e); |
| } |
| |
| public void setError(String msg, PackageManagerException e) { |
| mInternalErrorCode = e.internalErrorCode; |
| mReturnCode = e.error; |
| setReturnMessage(ExceptionUtils.getCompleteMessage(msg, e)); |
| Slog.w(TAG, msg, e); |
| if (mPackageMetrics != null) { |
| mPackageMetrics.onInstallFailed(); |
| } |
| } |
| |
| public void setReturnCode(int returnCode) { |
| mReturnCode = returnCode; |
| } |
| |
| public void setReturnMessage(String returnMsg) { |
| mReturnMsg = returnMsg; |
| } |
| |
| public void setApexInfo(ApexInfo apexInfo) { |
| mApexInfo = apexInfo; |
| } |
| |
| public void setApexModuleName(@Nullable String apexModuleName) { |
| mApexModuleName = apexModuleName; |
| } |
| |
| public void setPkg(AndroidPackage pkg) { |
| mPkg = pkg; |
| } |
| |
| public void setAppId(int appId) { |
| mAppId = appId; |
| } |
| |
| public void setNewUsers(int[] newUsers) { |
| mNewUsers = newUsers; |
| } |
| |
| public void setOriginPackage(String originPackage) { |
| mOrigPackage = originPackage; |
| } |
| |
| public void setOriginPermission(String originPermission) { |
| mOrigPermission = originPermission; |
| } |
| |
| public void setName(String packageName) { |
| mName = packageName; |
| } |
| |
| public void setOriginUsers(int[] userIds) { |
| mOrigUsers = userIds; |
| } |
| |
| public void setFreezer(PackageFreezer freezer) { |
| mFreezer = freezer; |
| } |
| |
| public void setRemovedInfo(PackageRemovedInfo removedInfo) { |
| mRemovedInfo = removedInfo; |
| } |
| |
| public void setLibraryConsumers(ArrayList<AndroidPackage> libraryConsumers) { |
| mLibraryConsumers = libraryConsumers; |
| } |
| |
| public void setPrepareResult(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; |
| mParsedPackage = packageToScan; |
| mClearCodeCache = clearCodeCache; |
| mSystem = system; |
| mOriginalPs = originalPs; |
| mDisabledPs = disabledPs; |
| } |
| |
| public void setScanResult(@NonNull ScanResult scanResult) { |
| mScanResult = scanResult; |
| } |
| |
| public void setScannedPackageSettingAppId(int appId) { |
| assertScanResultExists(); |
| mScanResult.mPkgSetting.setAppId(appId); |
| } |
| |
| public void setScannedPackageSettingFirstInstallTimeFromReplaced( |
| @Nullable PackageStateInternal replacedPkgSetting, int[] userId) { |
| assertScanResultExists(); |
| mScanResult.mPkgSetting.setFirstInstallTimeFromReplaced(replacedPkgSetting, userId); |
| } |
| |
| public void setScannedPackageSettingLastUpdateTime(long lastUpdateTim) { |
| assertScanResultExists(); |
| mScanResult.mPkgSetting.setLastUpdateTime(lastUpdateTim); |
| } |
| |
| public void setRemovedAppId(int appId) { |
| if (mRemovedInfo != null) { |
| mRemovedInfo.mRemovedAppId = appId; |
| } |
| } |
| |
| public void onPrepareStarted() { |
| if (mPackageMetrics != null) { |
| mPackageMetrics.onStepStarted(PackageMetrics.STEP_PREPARE); |
| } |
| } |
| |
| public void onPrepareFinished() { |
| if (mPackageMetrics != null) { |
| mPackageMetrics.onStepFinished(PackageMetrics.STEP_PREPARE); |
| } |
| } |
| |
| public void onScanStarted() { |
| if (mPackageMetrics != null) { |
| mPackageMetrics.onStepStarted(PackageMetrics.STEP_SCAN); |
| } |
| } |
| |
| public void onScanFinished() { |
| if (mPackageMetrics != null) { |
| mPackageMetrics.onStepFinished(PackageMetrics.STEP_SCAN); |
| } |
| } |
| |
| public void onReconcileStarted() { |
| if (mPackageMetrics != null) { |
| mPackageMetrics.onStepStarted(PackageMetrics.STEP_RECONCILE); |
| } |
| } |
| |
| public void onReconcileFinished() { |
| if (mPackageMetrics != null) { |
| mPackageMetrics.onStepFinished(PackageMetrics.STEP_RECONCILE); |
| } |
| } |
| |
| public void onCommitStarted() { |
| if (mPackageMetrics != null) { |
| mPackageMetrics.onStepStarted(PackageMetrics.STEP_COMMIT); |
| } |
| } |
| |
| public void onCommitFinished() { |
| if (mPackageMetrics != null) { |
| mPackageMetrics.onStepFinished(PackageMetrics.STEP_COMMIT); |
| } |
| } |
| |
| public void onDexoptFinished(DexoptResult dexoptResult) { |
| if (mPackageMetrics == null) { |
| return; |
| } |
| mDexoptStatus = dexoptResult.getFinalStatus(); |
| if (mDexoptStatus != DexoptResult.DEXOPT_PERFORMED) { |
| return; |
| } |
| long durationMillis = 0; |
| for (DexoptResult.PackageDexoptResult packageResult : |
| dexoptResult.getPackageDexoptResults()) { |
| for (DexoptResult.DexContainerFileDexoptResult fileResult : |
| packageResult.getDexContainerFileDexoptResults()) { |
| durationMillis += fileResult.getDex2oatWallTimeMillis(); |
| } |
| } |
| mPackageMetrics.onStepFinished(PackageMetrics.STEP_DEXOPT, durationMillis); |
| } |
| |
| public void onInstallCompleted() { |
| if (getReturnCode() == INSTALL_SUCCEEDED) { |
| if (mPackageMetrics != null) { |
| mPackageMetrics.onInstallSucceed(); |
| } |
| } |
| } |
| } |