[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
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -510,7 +510,7 @@ class InstallingSession {
|
||||
mInstallPackageHelper.installPackagesTraced(installRequests);
|
||||
|
||||
for (InstallRequest request : installRequests) {
|
||||
request.onInstallCompleted();
|
||||
request.onInstallCompleted(mPm.snapshotComputer());
|
||||
doPostInstall(request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,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;
|
||||
|
||||
Reference in New Issue
Block a user