Loading services/core/java/com/android/server/pm/InitAppScanMetrics.java 0 → 100644 +173 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.PackageManager; import android.content.pm.SigningDetails.SignatureSchemeVersion; import android.os.SystemClock; import com.android.internal.util.FrameworkStatsLog; /** * A helper class to collect and log metrics for the initial scan of a single package during system * boot. This class uses a builder pattern to gather metric data before logging. */ public final class InitAppScanMetrics { private boolean mIsFsiEnabled; private int mNumApkSplits; private int mSignatureSchemeVersion = FrameworkStatsLog.INIT_APP_SCAN_REPORTED__SIGNATURE_SCHEME_VERSION__UNKNOWN; private final long mTotalScanStartTimeMillis; private long mTotalScanDurationMillis; private int mInitAppScanOutcome = FrameworkStatsLog.INIT_APP_SCAN_REPORTED__INIT_APP_SCAN_OUTCOME__UNSPECIFIED; /** Starts the timer for the total scan duration. */ public InitAppScanMetrics() { this.mTotalScanStartTimeMillis = SystemClock.uptimeMillis(); } /** * Translates a package managers signature scheme version into the corresponding init app scan * metric signature scheme version. * * @param signatureSchemeVersion A package manager SigningDetails.SignatureScheme.* enum value. * @return The corresponding init app scan metric signature scheme enum value. */ private static int translateToSignatureSchemeVersion(int signatureSchemeVersion) { switch (signatureSchemeVersion) { case SignatureSchemeVersion.UNKNOWN: return FrameworkStatsLog.INIT_APP_SCAN_REPORTED__SIGNATURE_SCHEME_VERSION__UNKNOWN; case SignatureSchemeVersion.JAR: return FrameworkStatsLog .INIT_APP_SCAN_REPORTED__SIGNATURE_SCHEME_VERSION__JAR; case SignatureSchemeVersion.SIGNING_BLOCK_V2: return FrameworkStatsLog .INIT_APP_SCAN_REPORTED__SIGNATURE_SCHEME_VERSION__V2; case SignatureSchemeVersion.SIGNING_BLOCK_V3: return FrameworkStatsLog .INIT_APP_SCAN_REPORTED__SIGNATURE_SCHEME_VERSION__V3; case SignatureSchemeVersion.SIGNING_BLOCK_V4: return FrameworkStatsLog .INIT_APP_SCAN_REPORTED__SIGNATURE_SCHEME_VERSION__V4; default: return FrameworkStatsLog .INIT_APP_SCAN_REPORTED__SIGNATURE_SCHEME_VERSION__UNKNOWN; } } /** * Translates a package manager installation error code into the corresponding init app scan * outcome for metrics logging. * * @param returnCode A PackageManager.INSTALL_* error code. * @return The corresponding app scan outcome enum value. */ private static int translateToInitAppScanOutcome(int returnCode) { switch (returnCode) { case PackageManager.INSTALL_SUCCEEDED: return FrameworkStatsLog.INIT_APP_SCAN_REPORTED__INIT_APP_SCAN_OUTCOME__SUCCESS; case PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES: return FrameworkStatsLog .INIT_APP_SCAN_REPORTED__INIT_APP_SCAN_OUTCOME__FAILURE_NO_CERTIFICATES; case PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE: return FrameworkStatsLog .INIT_APP_SCAN_REPORTED__INIT_APP_SCAN_OUTCOME__FAILURE_VERIFICATION; case PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE: return FrameworkStatsLog .INIT_APP_SCAN_REPORTED__INIT_APP_SCAN_OUTCOME__FAILURE_UPDATE_INCOMPATIBLE; case PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: return FrameworkStatsLog .INIT_APP_SCAN_REPORTED__INIT_APP_SCAN_OUTCOME__FAILURE_INCONSISTENT_CERTIFICATES; case PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING: return FrameworkStatsLog .INIT_APP_SCAN_REPORTED__INIT_APP_SCAN_OUTCOME__FAILURE_CERTIFICATE_ENCODING; case PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE: case PackageManager.INSTALL_FAILED_INVALID_APK: case PackageManager.INSTALL_FAILED_PACKAGE_CHANGED: case PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION: return FrameworkStatsLog .INIT_APP_SCAN_REPORTED__INIT_APP_SCAN_OUTCOME__FAILURE_SCAN_VALIDATION; default: return FrameworkStatsLog .INIT_APP_SCAN_REPORTED__INIT_APP_SCAN_OUTCOME__FAILURE_OTHER; } } /** * Sets whether the scanned package is allow-listed for FSI check. * * @param isFsiEnabled True if the package has FSI enabled, false otherwise. * @return This {@link InitAppScanMetrics} instance for chaining. */ public InitAppScanMetrics setIsFsiEnabled(boolean isFsiEnabled) { this.mIsFsiEnabled = isFsiEnabled; return this; } /** * Sets the number of APK splits for the scanned package. * * @param numApkSplits number of APK splits. * @return This {@link InitAppScanMetrics} instance for chaining. */ public InitAppScanMetrics setNumApkSplits(int numApkSplits) { this.mNumApkSplits = numApkSplits; return this; } /** * Sets the signature scheme version used for package verification. * * @param signatureSchemeVersion The version of the signature scheme. * @return This {@link InitAppScanMetrics} instance for chaining. */ public InitAppScanMetrics setSignatureSchemeVersion(int signatureSchemeVersion) { this.mSignatureSchemeVersion = translateToSignatureSchemeVersion(signatureSchemeVersion); return this; } /** * Sets the final outcome of the APK scan. * * @param returnCode A PackageManager.INSTALL_* error code. * @return This {@link InitAppScanMetrics} instance for chaining. */ public InitAppScanMetrics setInitAppScanOutcome(int returnCode) { this.mInitAppScanOutcome = translateToInitAppScanOutcome(returnCode); return this; } /** Finalizes and logs the collected metrics to FrameworkStatsLog. */ public void log() { this.mTotalScanDurationMillis = SystemClock.uptimeMillis() - mTotalScanStartTimeMillis; FrameworkStatsLog.write( FrameworkStatsLog.INIT_APP_SCAN_REPORTED, mIsFsiEnabled, mNumApkSplits, mSignatureSchemeVersion, mTotalScanDurationMillis, mInitAppScanOutcome); } } services/core/java/com/android/server/pm/InstallPackageHelper.java +252 −226 Original line number Diff line number Diff line Loading @@ -4337,10 +4337,13 @@ final class InstallPackageHelper { @ParsingPackageUtils.ParseFlags int parseFlags, @PackageManagerService.ScanFlags int scanFlags, @Nullable UserHandle user) throws PackageManagerException { final InitAppScanMetrics metrics = new InitAppScanMetrics(); boolean shouldLogInitAppScanMetric = false; try { final boolean scanSystemPartition = (parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0; final ScanRequest initialScanRequest = prepareInitialScanRequest(parsedPackage, parseFlags, scanFlags, user, null); final ScanRequest initialScanRequest = prepareInitialScanRequest(parsedPackage, parseFlags, scanFlags, user, null); final PackageSetting installedPkgSetting = initialScanRequest.mPkgSetting; final PackageSetting originalPkgSetting = initialScanRequest.mOriginalPkgSetting; final PackageSetting pkgSetting = Loading Loading @@ -4391,6 +4394,7 @@ final class InstallPackageHelper { } } // End of mLock shouldLogInitAppScanMetric = !scanSystemPartition && isSystemPkgUpdated; final boolean newPkgChangedPaths = pkgAlreadyExists && !pkgSetting.getPathString().equals(parsedPackage.getPath()); final boolean newPkgVersionGreater = pkgAlreadyExists Loading Loading @@ -4436,8 +4440,8 @@ final class InstallPackageHelper { // For some updated system packages, during addForInit we want to ensure the // PackageSetting has the correct SigningDetails compares to the original version on // the system partition. For the check to happen later during the /data scan, update // the disabled package setting per the original APK on a system partition so that it // can be trusted during reconcile. // the disabled package setting per the original APK on a system partition so that // it can be trusted during reconcile. if (needSignatureMatchToSystem(parsedPackage.getPackageName())) { final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); final ParseResult<SigningDetails> result = Loading @@ -4450,22 +4454,23 @@ final class InstallPackageHelper { disabledPkgSetting.setSigningDetails(result.getResult()); } // In the case of a skipped package, commitReconciledScanResultLocked is not called to // add the object to the "live" data structures, so this is the final mutation step // 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. // In the case of a skipped package, commitReconciledScanResultLocked is not called // to add the object to the "live" data structures, so this is the final mutation // step 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.hideAsFinal(); throw PackageManagerException.ofInternalError( "Package " + parsedPackage.getPackageName() + " at " + parsedPackage.getPath() + " ignored: updated version " + (pkgAlreadyExists ? String.valueOf(pkgSetting.getVersionCode()) : "unknown") + (pkgAlreadyExists ? String.valueOf(pkgSetting.getVersionCode()) : "unknown") + " better than this " + parsedPackage.getLongVersionCode(), PackageManagerException.INTERNAL_ERROR_UPDATED_VERSION_BETTER_THAN_SYSTEM); } // Verify certificates against what was last scanned. Force re-collecting certificate in two // special cases: // Verify certificates against what was last scanned. Force re-collecting certificate in // two special cases: // 1) when scanning system, force re-collect only if system is upgrading. // 2) when scanning /data, force re-collect only if the package name is allowlisted. final boolean forceCollect = scanSystemPartition ? isUpgrade Loading @@ -4474,13 +4479,21 @@ final class InstallPackageHelper { Slog.d(TAG, "Force collect certificate of " + parsedPackage.getPackageName()); } // APK verification can be skipped during certificate collection, only if the file is in a // verified partition. // APK verification can be skipped during certificate collection, only if the file is in // a verified partition. final boolean skipVerify = scanSystemPartition; ScanPackageUtils.collectCertificatesLI(pkgSetting, parsedPackage, mPm.getSettingsVersionForPackage(parsedPackage), forceCollect, skipVerify, mPm.isPreNMR1Upgrade()); // Populate the InitAppScanMetrics object since all the variables are defined now. metrics.setIsFsiEnabled(forceCollect) .setNumApkSplits(parsedPackage.getSplitCodePaths() == null ? 0 : parsedPackage.getSplitCodePaths().length) .setSignatureSchemeVersion( parsedPackage.getSigningDetails().getSignatureSchemeVersion()); // Reset profile if the application version is changed maybeClearProfilesForUpgradesLI(pkgSetting, parsedPackage); Loading Loading @@ -4571,7 +4584,20 @@ final class InstallPackageHelper { final long firstInstallTime = System.currentTimeMillis(); final ScanResult scanResult = scanPackageNew(parsedPackage, parseFlags, scanFlags | SCAN_UPDATE_SIGNATURE, firstInstallTime, user, null); // Set scan outcome as successful for InitAppScanMetrics. metrics.setInitAppScanOutcome(PackageManager.INSTALL_SUCCEEDED); return new Pair<>(scanResult, shouldHideSystemApp); } catch (PackageManagerException e) { // Set scan outcome failure type for InitAppScanMetrics. metrics.setInitAppScanOutcome(e.error); throw e; } finally { // Finalizes the total scan duration and logs the InitAppScanMetrics metric. The metric // is only logged for updated system apps. if (shouldLogInitAppScanMetric) { metrics.log(); } } } private static boolean hasLauncherEntry(ParsedPackage parsedPackage) { Loading Loading
services/core/java/com/android/server/pm/InitAppScanMetrics.java 0 → 100644 +173 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.PackageManager; import android.content.pm.SigningDetails.SignatureSchemeVersion; import android.os.SystemClock; import com.android.internal.util.FrameworkStatsLog; /** * A helper class to collect and log metrics for the initial scan of a single package during system * boot. This class uses a builder pattern to gather metric data before logging. */ public final class InitAppScanMetrics { private boolean mIsFsiEnabled; private int mNumApkSplits; private int mSignatureSchemeVersion = FrameworkStatsLog.INIT_APP_SCAN_REPORTED__SIGNATURE_SCHEME_VERSION__UNKNOWN; private final long mTotalScanStartTimeMillis; private long mTotalScanDurationMillis; private int mInitAppScanOutcome = FrameworkStatsLog.INIT_APP_SCAN_REPORTED__INIT_APP_SCAN_OUTCOME__UNSPECIFIED; /** Starts the timer for the total scan duration. */ public InitAppScanMetrics() { this.mTotalScanStartTimeMillis = SystemClock.uptimeMillis(); } /** * Translates a package managers signature scheme version into the corresponding init app scan * metric signature scheme version. * * @param signatureSchemeVersion A package manager SigningDetails.SignatureScheme.* enum value. * @return The corresponding init app scan metric signature scheme enum value. */ private static int translateToSignatureSchemeVersion(int signatureSchemeVersion) { switch (signatureSchemeVersion) { case SignatureSchemeVersion.UNKNOWN: return FrameworkStatsLog.INIT_APP_SCAN_REPORTED__SIGNATURE_SCHEME_VERSION__UNKNOWN; case SignatureSchemeVersion.JAR: return FrameworkStatsLog .INIT_APP_SCAN_REPORTED__SIGNATURE_SCHEME_VERSION__JAR; case SignatureSchemeVersion.SIGNING_BLOCK_V2: return FrameworkStatsLog .INIT_APP_SCAN_REPORTED__SIGNATURE_SCHEME_VERSION__V2; case SignatureSchemeVersion.SIGNING_BLOCK_V3: return FrameworkStatsLog .INIT_APP_SCAN_REPORTED__SIGNATURE_SCHEME_VERSION__V3; case SignatureSchemeVersion.SIGNING_BLOCK_V4: return FrameworkStatsLog .INIT_APP_SCAN_REPORTED__SIGNATURE_SCHEME_VERSION__V4; default: return FrameworkStatsLog .INIT_APP_SCAN_REPORTED__SIGNATURE_SCHEME_VERSION__UNKNOWN; } } /** * Translates a package manager installation error code into the corresponding init app scan * outcome for metrics logging. * * @param returnCode A PackageManager.INSTALL_* error code. * @return The corresponding app scan outcome enum value. */ private static int translateToInitAppScanOutcome(int returnCode) { switch (returnCode) { case PackageManager.INSTALL_SUCCEEDED: return FrameworkStatsLog.INIT_APP_SCAN_REPORTED__INIT_APP_SCAN_OUTCOME__SUCCESS; case PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES: return FrameworkStatsLog .INIT_APP_SCAN_REPORTED__INIT_APP_SCAN_OUTCOME__FAILURE_NO_CERTIFICATES; case PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE: return FrameworkStatsLog .INIT_APP_SCAN_REPORTED__INIT_APP_SCAN_OUTCOME__FAILURE_VERIFICATION; case PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE: return FrameworkStatsLog .INIT_APP_SCAN_REPORTED__INIT_APP_SCAN_OUTCOME__FAILURE_UPDATE_INCOMPATIBLE; case PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: return FrameworkStatsLog .INIT_APP_SCAN_REPORTED__INIT_APP_SCAN_OUTCOME__FAILURE_INCONSISTENT_CERTIFICATES; case PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING: return FrameworkStatsLog .INIT_APP_SCAN_REPORTED__INIT_APP_SCAN_OUTCOME__FAILURE_CERTIFICATE_ENCODING; case PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE: case PackageManager.INSTALL_FAILED_INVALID_APK: case PackageManager.INSTALL_FAILED_PACKAGE_CHANGED: case PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION: return FrameworkStatsLog .INIT_APP_SCAN_REPORTED__INIT_APP_SCAN_OUTCOME__FAILURE_SCAN_VALIDATION; default: return FrameworkStatsLog .INIT_APP_SCAN_REPORTED__INIT_APP_SCAN_OUTCOME__FAILURE_OTHER; } } /** * Sets whether the scanned package is allow-listed for FSI check. * * @param isFsiEnabled True if the package has FSI enabled, false otherwise. * @return This {@link InitAppScanMetrics} instance for chaining. */ public InitAppScanMetrics setIsFsiEnabled(boolean isFsiEnabled) { this.mIsFsiEnabled = isFsiEnabled; return this; } /** * Sets the number of APK splits for the scanned package. * * @param numApkSplits number of APK splits. * @return This {@link InitAppScanMetrics} instance for chaining. */ public InitAppScanMetrics setNumApkSplits(int numApkSplits) { this.mNumApkSplits = numApkSplits; return this; } /** * Sets the signature scheme version used for package verification. * * @param signatureSchemeVersion The version of the signature scheme. * @return This {@link InitAppScanMetrics} instance for chaining. */ public InitAppScanMetrics setSignatureSchemeVersion(int signatureSchemeVersion) { this.mSignatureSchemeVersion = translateToSignatureSchemeVersion(signatureSchemeVersion); return this; } /** * Sets the final outcome of the APK scan. * * @param returnCode A PackageManager.INSTALL_* error code. * @return This {@link InitAppScanMetrics} instance for chaining. */ public InitAppScanMetrics setInitAppScanOutcome(int returnCode) { this.mInitAppScanOutcome = translateToInitAppScanOutcome(returnCode); return this; } /** Finalizes and logs the collected metrics to FrameworkStatsLog. */ public void log() { this.mTotalScanDurationMillis = SystemClock.uptimeMillis() - mTotalScanStartTimeMillis; FrameworkStatsLog.write( FrameworkStatsLog.INIT_APP_SCAN_REPORTED, mIsFsiEnabled, mNumApkSplits, mSignatureSchemeVersion, mTotalScanDurationMillis, mInitAppScanOutcome); } }
services/core/java/com/android/server/pm/InstallPackageHelper.java +252 −226 Original line number Diff line number Diff line Loading @@ -4337,10 +4337,13 @@ final class InstallPackageHelper { @ParsingPackageUtils.ParseFlags int parseFlags, @PackageManagerService.ScanFlags int scanFlags, @Nullable UserHandle user) throws PackageManagerException { final InitAppScanMetrics metrics = new InitAppScanMetrics(); boolean shouldLogInitAppScanMetric = false; try { final boolean scanSystemPartition = (parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0; final ScanRequest initialScanRequest = prepareInitialScanRequest(parsedPackage, parseFlags, scanFlags, user, null); final ScanRequest initialScanRequest = prepareInitialScanRequest(parsedPackage, parseFlags, scanFlags, user, null); final PackageSetting installedPkgSetting = initialScanRequest.mPkgSetting; final PackageSetting originalPkgSetting = initialScanRequest.mOriginalPkgSetting; final PackageSetting pkgSetting = Loading Loading @@ -4391,6 +4394,7 @@ final class InstallPackageHelper { } } // End of mLock shouldLogInitAppScanMetric = !scanSystemPartition && isSystemPkgUpdated; final boolean newPkgChangedPaths = pkgAlreadyExists && !pkgSetting.getPathString().equals(parsedPackage.getPath()); final boolean newPkgVersionGreater = pkgAlreadyExists Loading Loading @@ -4436,8 +4440,8 @@ final class InstallPackageHelper { // For some updated system packages, during addForInit we want to ensure the // PackageSetting has the correct SigningDetails compares to the original version on // the system partition. For the check to happen later during the /data scan, update // the disabled package setting per the original APK on a system partition so that it // can be trusted during reconcile. // the disabled package setting per the original APK on a system partition so that // it can be trusted during reconcile. if (needSignatureMatchToSystem(parsedPackage.getPackageName())) { final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); final ParseResult<SigningDetails> result = Loading @@ -4450,22 +4454,23 @@ final class InstallPackageHelper { disabledPkgSetting.setSigningDetails(result.getResult()); } // In the case of a skipped package, commitReconciledScanResultLocked is not called to // add the object to the "live" data structures, so this is the final mutation step // 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. // In the case of a skipped package, commitReconciledScanResultLocked is not called // to add the object to the "live" data structures, so this is the final mutation // step 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.hideAsFinal(); throw PackageManagerException.ofInternalError( "Package " + parsedPackage.getPackageName() + " at " + parsedPackage.getPath() + " ignored: updated version " + (pkgAlreadyExists ? String.valueOf(pkgSetting.getVersionCode()) : "unknown") + (pkgAlreadyExists ? String.valueOf(pkgSetting.getVersionCode()) : "unknown") + " better than this " + parsedPackage.getLongVersionCode(), PackageManagerException.INTERNAL_ERROR_UPDATED_VERSION_BETTER_THAN_SYSTEM); } // Verify certificates against what was last scanned. Force re-collecting certificate in two // special cases: // Verify certificates against what was last scanned. Force re-collecting certificate in // two special cases: // 1) when scanning system, force re-collect only if system is upgrading. // 2) when scanning /data, force re-collect only if the package name is allowlisted. final boolean forceCollect = scanSystemPartition ? isUpgrade Loading @@ -4474,13 +4479,21 @@ final class InstallPackageHelper { Slog.d(TAG, "Force collect certificate of " + parsedPackage.getPackageName()); } // APK verification can be skipped during certificate collection, only if the file is in a // verified partition. // APK verification can be skipped during certificate collection, only if the file is in // a verified partition. final boolean skipVerify = scanSystemPartition; ScanPackageUtils.collectCertificatesLI(pkgSetting, parsedPackage, mPm.getSettingsVersionForPackage(parsedPackage), forceCollect, skipVerify, mPm.isPreNMR1Upgrade()); // Populate the InitAppScanMetrics object since all the variables are defined now. metrics.setIsFsiEnabled(forceCollect) .setNumApkSplits(parsedPackage.getSplitCodePaths() == null ? 0 : parsedPackage.getSplitCodePaths().length) .setSignatureSchemeVersion( parsedPackage.getSigningDetails().getSignatureSchemeVersion()); // Reset profile if the application version is changed maybeClearProfilesForUpgradesLI(pkgSetting, parsedPackage); Loading Loading @@ -4571,7 +4584,20 @@ final class InstallPackageHelper { final long firstInstallTime = System.currentTimeMillis(); final ScanResult scanResult = scanPackageNew(parsedPackage, parseFlags, scanFlags | SCAN_UPDATE_SIGNATURE, firstInstallTime, user, null); // Set scan outcome as successful for InitAppScanMetrics. metrics.setInitAppScanOutcome(PackageManager.INSTALL_SUCCEEDED); return new Pair<>(scanResult, shouldHideSystemApp); } catch (PackageManagerException e) { // Set scan outcome failure type for InitAppScanMetrics. metrics.setInitAppScanOutcome(e.error); throw e; } finally { // Finalizes the total scan duration and logs the InitAppScanMetrics metric. The metric // is only logged for updated system apps. if (shouldLogInitAppScanMetric) { metrics.log(); } } } private static boolean hasLauncherEntry(ParsedPackage parsedPackage) { Loading