diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index 7dae4c64cfd8b..2a0b44d43bd7d 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -150,7 +150,6 @@ import android.util.SparseIntArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.content.F2fsUtils; -import com.android.internal.content.InstallLocationUtils; import com.android.internal.security.VerityUtils; import com.android.internal.util.ArrayUtils; import com.android.internal.util.CollectionUtils; @@ -875,7 +874,7 @@ final class InstallPackageHelper { } } - Map reconciledPackages; + List reconciledPackages; synchronized (mPm.mLock) { try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages"); @@ -1883,11 +1882,11 @@ final class InstallPackageHelper { } @GuardedBy("mPm.mLock") - private void commitPackagesLocked(Map reconciledPackages, + private void commitPackagesLocked(List reconciledPackages, @NonNull int[] allUsers) { // 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 : reconciledPackages.values()) { + for (ReconciledPackage reconciledPkg : reconciledPackages) { final InstallRequest installRequest = reconciledPkg.mInstallRequest; final ParsedPackage parsedPackage = installRequest.getParsedPackage(); final String packageName = parsedPackage.getPackageName(); @@ -2205,9 +2204,9 @@ final class InstallPackageHelper { * locks on {@link com.android.server.pm.PackageManagerService.mLock}. */ @GuardedBy("mPm.mInstallLock") - private void executePostCommitStepsLIF(Map reconciledPackages) { + private void executePostCommitStepsLIF(List reconciledPackages) { final ArraySet incrementalStorages = new ArraySet<>(); - for (ReconciledPackage reconciledPkg : reconciledPackages.values()) { + for (ReconciledPackage reconciledPkg : reconciledPackages) { final InstallRequest installRequest = reconciledPkg.mInstallRequest; final boolean instantApp = ((installRequest.getScanFlags() & SCAN_AS_INSTANT_APP) != 0); final boolean isApex = ((installRequest.getScanFlags() & SCAN_AS_APEX) != 0); @@ -2338,45 +2337,6 @@ final class InstallPackageHelper { incrementalStorages); } - public int installLocationPolicy(PackageInfoLite pkgLite, int installFlags) { - 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 ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) { - // Check for updated system application. - if (installedPkg.isSystem()) { - return InstallLocationUtils.RECOMMEND_INSTALL_INTERNAL; - } else { - // If current upgrade specifies particular preference - if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) { - // Application explicitly specified internal. - return InstallLocationUtils.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 InstallLocationUtils.RECOMMEND_INSTALL_EXTERNAL; - } - return InstallLocationUtils.RECOMMEND_INSTALL_INTERNAL; - } - } - } else { - // Invalid install. Return error code - return InstallLocationUtils.RECOMMEND_FAILED_ALREADY_EXISTS; - } - } - } - return pkgLite.recommendedInstallLocation; - } - Pair verifyReplacingVersionCode(PackageInfoLite pkgLite, long requiredInstalledVersionCode, int installFlags) { if ((installFlags & PackageManager.INSTALL_APEX) != 0) { @@ -3645,7 +3605,7 @@ final class InstallPackageHelper { boolean appIdCreated = false; try { final String pkgName = scanResult.mPkgSetting.getPackageName(); - final Map reconcileResult = + final List reconcileResult = ReconcilePackageUtils.reconcilePackages( Collections.singletonList(installRequest), mPm.mPackages, Collections.singletonMap(pkgName, @@ -3657,7 +3617,7 @@ final class InstallPackageHelper { } else { installRequest.setScannedPackageSettingAppId(Process.INVALID_UID); } - commitReconciledScanResultLocked(reconcileResult.get(pkgName), + commitReconciledScanResultLocked(reconcileResult.get(0), mPm.mUserManager.getUserIds()); } catch (PackageManagerException e) { if (appIdCreated) { diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java index 4443710dd08bc..01a8bd0a42253 100644 --- a/services/core/java/com/android/server/pm/InstallRequest.java +++ b/services/core/java/com/android/server/pm/InstallRequest.java @@ -59,8 +59,10 @@ final class InstallRequest { @Nullable private PackageRemovedInfo mRemovedInfo; - private @PackageManagerService.ScanFlags int mScanFlags; - private @ParsingPackageUtils.ParseFlags int mParseFlags; + @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} */ @@ -155,7 +157,7 @@ final class InstallRequest { mParseFlags = parseFlags; mScanFlags = scanFlags; mScanResult = scanResult; - mPackageMetrics = null; // No real logging from this code path + mPackageMetrics = null; // No logging from this code path } @Nullable @@ -393,11 +395,13 @@ final class InstallRequest { return mParsedPackage; } - public @ParsingPackageUtils.ParseFlags int getParseFlags() { + @ParsingPackageUtils.ParseFlags + public int getParseFlags() { return mParseFlags; } - public @PackageManagerService.ScanFlags int getScanFlags() { + @PackageManagerService.ScanFlags + public int getScanFlags() { return mScanFlags; } @@ -435,6 +439,11 @@ final class InstallRequest { return mIsInstallForUsers; } + public boolean isInstallFromAdb() { + return mInstallArgs != null + && (mInstallArgs.mInstallFlags & PackageManager.INSTALL_FROM_ADB) != 0; + } + @Nullable public PackageSetting getOriginalPackageSetting() { return mOriginalPs; @@ -731,10 +740,10 @@ final class InstallRequest { } } - public void onInstallCompleted() { + public void onInstallCompleted(Computer snapshot) { if (getReturnCode() == INSTALL_SUCCEEDED) { if (mPackageMetrics != null) { - mPackageMetrics.onInstallSucceed(); + mPackageMetrics.onInstallSucceed(snapshot); } } } diff --git a/services/core/java/com/android/server/pm/InstallingSession.java b/services/core/java/com/android/server/pm/InstallingSession.java index d13822a4d98c1..e4a0a3ab8dfa7 100644 --- a/services/core/java/com/android/server/pm/InstallingSession.java +++ b/services/core/java/com/android/server/pm/InstallingSession.java @@ -510,7 +510,7 @@ class InstallingSession { mInstallPackageHelper.installPackagesTraced(installRequests); for (InstallRequest request : installRequests) { - request.onInstallCompleted(); + request.onInstallCompleted(mPm.snapshotComputer()); doPostInstall(request); } } diff --git a/services/core/java/com/android/server/pm/PackageMetrics.java b/services/core/java/com/android/server/pm/PackageMetrics.java index b725325eaaa98..0391163856b2c 100644 --- a/services/core/java/com/android/server/pm/PackageMetrics.java +++ b/services/core/java/com/android/server/pm/PackageMetrics.java @@ -16,16 +16,26 @@ package com.android.server.pm; +import static android.os.Process.INVALID_UID; + import android.annotation.IntDef; +import android.content.pm.parsing.ApkLiteParseUtils; import android.os.UserManager; import android.util.Pair; import android.util.SparseArray; import com.android.internal.util.FrameworkStatsLog; +import com.android.server.pm.pkg.PackageStateInternal; +import java.io.File; +import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Stream; /** * Metrics class for reporting stats to logging infrastructures like Westworld @@ -43,7 +53,8 @@ final class PackageMetrics { STEP_COMMIT, }) @Retention(RetentionPolicy.SOURCE) - public @interface StepInt {} + public @interface StepInt { + } private final long mInstallStartTimestampMillis; private final SparseArray mInstallSteps = new SparseArray<>(); @@ -56,16 +67,30 @@ final class PackageMetrics { mInstallRequest = installRequest; } - public void onInstallSucceed() { + public void onInstallSucceed(Computer snapshot) { + // TODO(b/239722919): report to SecurityLog if on work profile or managed device + reportInstallationStats(snapshot, true /* success */); + } + + private void reportInstallationStats(Computer snapshot, boolean success) { + // TODO(b/249294752): do not log if adb final long installDurationMillis = System.currentTimeMillis() - mInstallStartTimestampMillis; // write to stats final Pair stepDurations = getInstallStepDurations(); final int[] newUsers = mInstallRequest.getNewUsers(); final int[] originalUsers = mInstallRequest.getOriginUsers(); + final String packageName = mInstallRequest.getName(); + final String installerPackageName = mInstallRequest.getInstallerPackageName(); + final int installerUid = installerPackageName == null ? INVALID_UID + : snapshot.getPackageUid(installerPackageName, 0, 0); + final PackageStateInternal ps = snapshot.getPackageStateInternal(packageName); + final long versionCode = success ? 0 : ps.getVersionCode(); + final long apksSize = getApksSize(ps.getPath()); + FrameworkStatsLog.write(FrameworkStatsLog.PACKAGE_INSTALLATION_SESSION_REPORTED, 0 /* session_id */, - null /* package_name */, + success ? null : packageName /* not report package_name on success */, mInstallRequest.getUid() /* uid */, newUsers /* user_ids */, getUserTypes(newUsers) /* user_types */, @@ -73,13 +98,13 @@ final class PackageMetrics { getUserTypes(originalUsers) /* original_user_types */, mInstallRequest.getReturnCode() /* public_return_code */, 0 /* internal_error_code */, - 0 /* apks_size_bytes */, - 0 /* version_code */, + apksSize /* apks_size_bytes */, + versionCode /* version_code */, stepDurations.first /* install_steps */, stepDurations.second /* step_duration_millis */, installDurationMillis /* total_duration_millis */, mInstallRequest.getInstallFlags() /* install_flags */, - -1 /* installer_package_uid */, + installerUid /* installer_package_uid */, -1 /* original_installer_package_uid */, mInstallRequest.getDataLoaderType() /* data_loader_type */, 0 /* user_action_required_type */, @@ -93,6 +118,19 @@ final class PackageMetrics { ); } + private long getApksSize(File apkDir) { + // TODO(b/249294752): also count apk sizes for failed installs + final AtomicLong apksSize = new AtomicLong(); + try (Stream walkStream = Files.walk(apkDir.toPath())) { + walkStream.filter(p -> p.toFile().isFile() + && ApkLiteParseUtils.isApkFile(p.toFile())).forEach( + f -> apksSize.addAndGet(f.toFile().length())); + } catch (IOException e) { + // ignore + } + return apksSize.get(); + } + public void onStepStarted(@StepInt int step) { mInstallSteps.put(step, new InstallStep()); } @@ -140,12 +178,15 @@ final class PackageMetrics { private static class InstallStep { private final long mStartTimestampMillis; private long mDurationMillis = -1; + InstallStep() { mStartTimestampMillis = System.currentTimeMillis(); } + void finish() { mDurationMillis = System.currentTimeMillis() - mStartTimestampMillis; } + long getDurationMillis() { return mDurationMillis; } diff --git a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java index 01d17f6444f51..99bcbc9f95e63 100644 --- a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java +++ b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java @@ -35,6 +35,7 @@ import com.android.server.pm.pkg.AndroidPackage; import com.android.server.pm.pkg.parsing.ParsingPackageUtils; import com.android.server.utils.WatchedLongSparseArray; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -48,14 +49,14 @@ import java.util.Map; * as install) led to the request. */ final class ReconcilePackageUtils { - public static Map reconcilePackages( + public static List reconcilePackages( List installRequests, Map allPackages, Map versionInfos, SharedLibrariesImpl sharedLibraries, KeySetManagerService ksms, Settings settings) throws ReconcileFailure { - final Map result = new ArrayMap<>(installRequests.size()); + final List result = new ArrayList<>(installRequests.size()); // make a copy of the existing set of packages so we can combine them with incoming packages final ArrayMap combinedPackages = @@ -88,7 +89,6 @@ final class ReconcilePackageUtils { } - final DeletePackageAction deletePackageAction; // we only want to try to delete for non system apps if (installRequest.isInstallReplace() && !installRequest.isInstallSystem()) { @@ -257,13 +257,11 @@ final class ReconcilePackageUtils { } } - result.put(installPackageName, + final ReconciledPackage reconciledPackage = new ReconciledPackage(installRequests, allPackages, installRequest, deletePackageAction, allowedSharedLibInfos, signingDetails, - sharedUserSignaturesChanged, removeAppKeySetData)); - } + sharedUserSignaturesChanged, removeAppKeySetData); - for (InstallRequest installRequest : installRequests) { // Check all shared libraries and map to their actual file path. // We only do this here for apps not on a system dir, because those // are the only ones that can fail an install due to this. We @@ -271,24 +269,21 @@ final class ReconcilePackageUtils { // library paths after the scan is done. Also during the initial // scan don't update any libs as we do this wholesale after all // apps are scanned to avoid dependency based scanning. - if ((installRequest.getScanFlags() & SCAN_BOOTING) != 0 - || (installRequest.getParseFlags() & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) - != 0) { - continue; + if ((installRequest.getScanFlags() & SCAN_BOOTING) == 0 + && (installRequest.getParseFlags() & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) + == 0) { + try { + reconciledPackage.mCollectedSharedLibraryInfos = + sharedLibraries.collectSharedLibraryInfos( + installRequest.getParsedPackage(), combinedPackages, + incomingSharedLibraries); + } catch (PackageManagerException e) { + throw new ReconcileFailure(e.error, e.getMessage()); + } } - final String installPackageName = installRequest.getParsedPackage().getPackageName(); - try { - result.get(installPackageName).mCollectedSharedLibraryInfos = - sharedLibraries.collectSharedLibraryInfos( - installRequest.getParsedPackage(), combinedPackages, - incomingSharedLibraries); - } catch (PackageManagerException e) { - throw new ReconcileFailure(e.error, e.getMessage()); - } - } - for (InstallRequest installRequest : installRequests) { installRequest.onReconcileFinished(); + result.add(reconciledPackage); } return result;