Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c9cca5c4 authored by Songchun Fan's avatar Songchun Fan
Browse files

[pm/metrics][2/n] pass snapshot to metrics when finish

Snapshot is needed to collect information about installer UID and
installed package version code.

+ minor improvements

BUG: 249294752
Test: atest com.android.cts.packagemanager.stats.host.PackageInstallationSessionReportedStatsTests
Change-Id: Ibaf94132f70bd7a8a74351a297dc92fe515258f3
parent 8e0eb90b
Loading
Loading
Loading
Loading
+7 −47
Original line number Diff line number Diff line
@@ -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<String, ReconciledPackage> reconciledPackages;
            List<ReconciledPackage> reconciledPackages;
            synchronized (mPm.mLock) {
                try {
                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
@@ -1881,11 +1880,11 @@ final class InstallPackageHelper {
    }

    @GuardedBy("mPm.mLock")
    private void commitPackagesLocked(Map<String, ReconciledPackage> reconciledPackages,
    private void commitPackagesLocked(List<ReconciledPackage> 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();
@@ -2203,9 +2202,9 @@ final class InstallPackageHelper {
     * locks on {@link com.android.server.pm.PackageManagerService.mLock}.
     */
    @GuardedBy("mPm.mInstallLock")
    private void executePostCommitStepsLIF(Map<String, ReconciledPackage> reconciledPackages) {
    private void executePostCommitStepsLIF(List<ReconciledPackage> reconciledPackages) {
        final ArraySet<IncrementalStorage> 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);
@@ -2336,45 +2335,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<Integer, String> verifyReplacingVersionCode(PackageInfoLite pkgLite,
            long requiredInstalledVersionCode, int installFlags) {
        if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
@@ -3643,7 +3603,7 @@ final class InstallPackageHelper {
            boolean appIdCreated = false;
            try {
                final String pkgName = scanResult.mPkgSetting.getPackageName();
                final Map<String, ReconciledPackage> reconcileResult =
                final List<ReconciledPackage> reconcileResult =
                        ReconcilePackageUtils.reconcilePackages(
                                Collections.singletonList(installRequest),
                                mPm.mPackages, Collections.singletonMap(pkgName,
@@ -3655,7 +3615,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) {
+16 −7
Original line number Diff line number Diff line
@@ -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);
            }
        }
    }
+1 −1
Original line number Diff line number Diff line
@@ -510,7 +510,7 @@ class InstallingSession {
            mInstallPackageHelper.installPackagesTraced(installRequests);

            for (InstallRequest request : installRequests) {
                request.onInstallCompleted();
                request.onInstallCompleted(mPm.snapshotComputer());
                doPostInstall(request);
            }
        }
+47 −6
Original line number Diff line number Diff line
@@ -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<InstallStep> 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<int[], long[]> 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<Path> 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;
        }
+17 −22
Original line number Diff line number Diff line
@@ -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<String, ReconciledPackage> reconcilePackages(
    public static List<ReconciledPackage> reconcilePackages(
            List<InstallRequest> installRequests,
            Map<String, AndroidPackage> allPackages,
            Map<String, Settings.VersionInfo> versionInfos,
            SharedLibrariesImpl sharedLibraries,
            KeySetManagerService ksms, Settings settings)
            throws ReconcileFailure {
        final Map<String, ReconciledPackage> result = new ArrayMap<>(installRequests.size());
        final List<ReconciledPackage> result = new ArrayList<>(installRequests.size());

        // make a copy of the existing set of packages so we can combine them with incoming packages
        final ArrayMap<String, AndroidPackage> 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,14 +269,11 @@ 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;
            }
            final String installPackageName = installRequest.getParsedPackage().getPackageName();
            if ((installRequest.getScanFlags() & SCAN_BOOTING) == 0
                    && (installRequest.getParseFlags() & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR)
                    == 0) {
                try {
                result.get(installPackageName).mCollectedSharedLibraryInfos =
                    reconciledPackage.mCollectedSharedLibraryInfos =
                            sharedLibraries.collectSharedLibraryInfos(
                                    installRequest.getParsedPackage(), combinedPackages,
                                    incomingSharedLibraries);
@@ -287,8 +282,8 @@ final class ReconcilePackageUtils {
                }
            }

        for (InstallRequest installRequest : installRequests) {
            installRequest.onReconcileFinished();
            result.add(reconciledPackage);
        }

        return result;