[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
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 84b8264..2c08248 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 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 @@
}
}
- Map<String, ReconciledPackage> reconciledPackages;
+ List<ReconciledPackage> reconciledPackages;
synchronized (mPm.mLock) {
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
@@ -1881,11 +1880,11 @@
}
@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 @@
* 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 @@
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 @@
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 @@
} 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 4443710..01a8bd0 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 @@
@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 @@
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 @@
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 @@
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 @@
}
}
- 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 d13822a..e4a0a3a 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 @@
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 b725325..0391163 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 @@
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 @@
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 @@
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 @@
);
}
+ 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 @@
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 01d17f6..99bcbc9 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.parsing.ParsingPackageUtils;
import com.android.server.utils.WatchedLongSparseArray;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -48,14 +49,14 @@
* 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 DeletePackageAction deletePackageAction;
// we only want to try to delete for non system apps
if (installRequest.isInstallReplace() && !installRequest.isInstallSystem()) {
@@ -257,13 +257,11 @@
}
}
- 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 @@
// 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;