diff options
| author | 2023-08-28 18:47:39 -0700 | |
|---|---|---|
| committer | 2023-09-01 12:47:50 -0700 | |
| commit | cfa9597688934fa8dd4a337a7fa97e7b70a58257 (patch) | |
| tree | 6cb4a302793dd38738472ee5b84851b859e8747e | |
| parent | c993acbf140b507064d36d2bfc64d9b72ccdaf13 (diff) | |
Add new getHistoricalSessions API to PMInternal
Sessions were written to strings to be stored as a historical session to
avoid keeping references on Bitmaps and other heavy-weight objects.
Since referenes to these heavy-weight object are all in SessionParams,
we just write the SessionParams to a string into a new
PackageInstallerHistoricalSession object.
Bug: 292091934
Test: manual install and check the dump
Change-Id: I839d67dff735a8e45ff206a0c9b08a1e72353042
5 files changed, 254 insertions, 7 deletions
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index 557e4ac843d2..838aae8a83c0 100644 --- a/services/core/java/android/content/pm/PackageManagerInternal.java +++ b/services/core/java/android/content/pm/PackageManagerInternal.java @@ -1409,4 +1409,10 @@ public abstract class PackageManagerInternal { */ public abstract boolean isPackageQuarantined(@NonNull String packageName, @UserIdInt int userId); + + /** + * Return a list of all historical install sessions for the given user. + */ + public abstract ParceledListSlice<PackageInstaller.SessionInfo> getHistoricalSessions( + int userId); } diff --git a/services/core/java/com/android/server/pm/PackageInstallerHistoricalSession.java b/services/core/java/com/android/server/pm/PackageInstallerHistoricalSession.java new file mode 100644 index 000000000000..d40a7157253b --- /dev/null +++ b/services/core/java/com/android/server/pm/PackageInstallerHistoricalSession.java @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2023 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.PackageInstaller.PreapprovalDetails; +import android.content.pm.PackageInstaller.SessionInfo; +import android.content.pm.PackageInstaller.SessionParams; + +import com.android.internal.util.IndentingPrintWriter; + +import java.io.CharArrayWriter; +import java.io.File; + +/** + * A historical session object that stores minimal session info. + */ +public final class PackageInstallerHistoricalSession { + public final int sessionId; + public final int userId; + private final String mParams; + private final long mCreatedMillis; + + private final File mStageDir; + private final String mStageCid; + + private final long mUpdatedMillis; + + private final long mCommittedMillis; + + private final int mOriginalInstallerUid; + + private final String mOriginalInstallerPackageName; + + private final int mInstallerUid; + + private final InstallSource mInstallSource; + + private final float mClientProgress; + + private final float mProgress; + private final boolean mSealed; + + private final boolean mPreapprovalRequested; + private final boolean mCommitted; + + private final boolean mStageDirInUse; + + private final boolean mPermissionsManuallyAccepted; + + private final int mFinalStatus; + private final String mFinalMessage; + + private final int mFds; + private final int mBridges; + + private final String mPreapprovalDetails; + private final int mParentSessionId; + private final boolean mDestroyed; + private final int[] mChildSessionIds; + private final boolean mSessionApplied; + private final boolean mSessionReady; + private final boolean mSessionFailed; + private final int mSessionErrorCode; + private final String mSessionErrorMessage; + + PackageInstallerHistoricalSession(int sessionId, int userId, int originalInstallerUid, + String originalInstallerPackageName, InstallSource installSource, int installerUid, + long createdMillis, long updatedMillis, long committedMillis, File stageDir, + String stageCid, float clientProgress, float progress, boolean committed, + boolean preapprovalRequested, boolean sealed, boolean permissionsManuallyAccepted, + boolean stageDirInUse, boolean destroyed, int fds, int bridges, int finalStatus, + String finalMessage, SessionParams params, int parentSessionId, + int[] childSessionIds, boolean sessionApplied, boolean sessionFailed, + boolean sessionReady, int sessionErrorCode, String sessionErrorMessage, + PreapprovalDetails preapprovalDetails) { + this.sessionId = sessionId; + this.userId = userId; + this.mOriginalInstallerUid = originalInstallerUid; + this.mOriginalInstallerPackageName = originalInstallerPackageName; + this.mInstallSource = installSource; + this.mInstallerUid = installerUid; + this.mCreatedMillis = createdMillis; + this.mUpdatedMillis = updatedMillis; + this.mCommittedMillis = committedMillis; + this.mStageDir = stageDir; + this.mStageCid = stageCid; + this.mClientProgress = clientProgress; + this.mProgress = progress; + this.mCommitted = committed; + this.mPreapprovalRequested = preapprovalRequested; + this.mSealed = sealed; + this.mPermissionsManuallyAccepted = permissionsManuallyAccepted; + this.mStageDirInUse = stageDirInUse; + this.mDestroyed = destroyed; + this.mFds = fds; + this.mBridges = bridges; + this.mFinalStatus = finalStatus; + this.mFinalMessage = finalMessage; + + CharArrayWriter writer = new CharArrayWriter(); + IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); + params.dump(pw); + this.mParams = writer.toString(); + + this.mParentSessionId = parentSessionId; + this.mChildSessionIds = childSessionIds; + this.mSessionApplied = sessionApplied; + this.mSessionFailed = sessionFailed; + this.mSessionReady = sessionReady; + this.mSessionErrorCode = sessionErrorCode; + this.mSessionErrorMessage = sessionErrorMessage; + if (preapprovalDetails != null) { + this.mPreapprovalDetails = preapprovalDetails.toString(); + } else { + this.mPreapprovalDetails = null; + } + } + + void dump(IndentingPrintWriter pw) { + pw.println("Session " + sessionId + ":"); + pw.increaseIndent(); + + pw.printPair("userId", userId); + pw.printPair("mOriginalInstallerUid", mOriginalInstallerUid); + pw.printPair("mOriginalInstallerPackageName", mOriginalInstallerPackageName); + pw.printPair("installerPackageName", mInstallSource.mInstallerPackageName); + pw.printPair("installInitiatingPackageName", mInstallSource.mInitiatingPackageName); + pw.printPair("installOriginatingPackageName", mInstallSource.mOriginatingPackageName); + pw.printPair("mInstallerUid", mInstallerUid); + pw.printPair("createdMillis", mCreatedMillis); + pw.printPair("updatedMillis", mUpdatedMillis); + pw.printPair("committedMillis", mCommittedMillis); + pw.printPair("stageDir", mStageDir); + pw.printPair("stageCid", mStageCid); + pw.println(); + + pw.print(mParams); + + pw.printPair("mClientProgress", mClientProgress); + pw.printPair("mProgress", mProgress); + pw.printPair("mCommitted", mCommitted); + pw.printPair("mPreapprovalRequested", mPreapprovalRequested); + pw.printPair("mSealed", mSealed); + pw.printPair("mPermissionsManuallyAccepted", mPermissionsManuallyAccepted); + pw.printPair("mStageDirInUse", mStageDirInUse); + pw.printPair("mDestroyed", mDestroyed); + pw.printPair("mFds", mFds); + pw.printPair("mBridges", mBridges); + pw.printPair("mFinalStatus", mFinalStatus); + pw.printPair("mFinalMessage", mFinalMessage); + pw.printPair("mParentSessionId", mParentSessionId); + pw.printPair("mChildSessionIds", mChildSessionIds); + pw.printPair("mSessionApplied", mSessionApplied); + pw.printPair("mSessionFailed", mSessionFailed); + pw.printPair("mSessionReady", mSessionReady); + pw.printPair("mSessionErrorCode", mSessionErrorCode); + pw.printPair("mSessionErrorMessage", mSessionErrorMessage); + pw.printPair("mPreapprovalDetails", mPreapprovalDetails); + pw.println(); + + pw.decreaseIndent(); + } + + /** + * Generates a {@link SessionInfo} object. + */ + public SessionInfo generateInfo() { + final SessionInfo info = new SessionInfo(); + info.sessionId = sessionId; + info.userId = userId; + info.installerPackageName = mInstallSource.mInstallerPackageName; + info.installerAttributionTag = mInstallSource.mInstallerAttributionTag; + info.progress = mProgress; + info.sealed = mSealed; + info.isCommitted = mCommitted; + info.isPreapprovalRequested = mPreapprovalRequested; + + info.parentSessionId = mParentSessionId; + info.childSessionIds = mChildSessionIds; + info.isSessionApplied = mSessionApplied; + info.isSessionReady = mSessionReady; + info.isSessionFailed = mSessionFailed; + info.setSessionErrorCode(mSessionErrorCode, mSessionErrorMessage); + info.createdMillis = mCreatedMillis; + info.updatedMillis = mUpdatedMillis; + info.installerUid = mInstallerUid; + return info; + } +} diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 10cd51a717cb..e3602565ef5b 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -111,7 +111,6 @@ import libcore.io.IoUtils; import org.xmlpull.v1.XmlPullParserException; -import java.io.CharArrayWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -230,7 +229,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements /** Historical sessions kept around for debugging purposes */ @GuardedBy("mSessions") - private final List<String> mHistoricalSessions = new ArrayList<>(); + private final List<PackageInstallerHistoricalSession> mHistoricalSessions = new ArrayList<>(); @GuardedBy("mSessions") private final SparseIntArray mHistoricalSessionsByInstaller = new SparseIntArray(); @@ -570,14 +569,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements @GuardedBy("mSessions") private void addHistoricalSessionLocked(PackageInstallerSession session) { - CharArrayWriter writer = new CharArrayWriter(); - IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); - session.dump(pw); if (mHistoricalSessions.size() > HISTORICAL_SESSIONS_THRESHOLD) { Slog.d(TAG, "Historical sessions size reaches threshold, clear the oldest"); mHistoricalSessions.subList(0, HISTORICAL_CLEAR_SIZE).clear(); } - mHistoricalSessions.add(writer.toString()); + mHistoricalSessions.add(session.createHistoricalSession()); int installerUid = session.getInstallerUid(); // Increment the number of sessions by this installerUid. @@ -1223,6 +1219,24 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements return new ParceledListSlice<>(result); } + ParceledListSlice<SessionInfo> getHistoricalSessions(int userId) { + final int callingUid = Binder.getCallingUid(); + final Computer snapshot = mPm.snapshotComputer(); + snapshot.enforceCrossUserPermission(callingUid, userId, true, false, "getAllSessions"); + + final List<SessionInfo> result = new ArrayList<>(); + synchronized (mSessions) { + for (int i = 0; i < mHistoricalSessions.size(); i++) { + final PackageInstallerHistoricalSession session = mHistoricalSessions.get(i); + if (userId == UserHandle.USER_ALL || session.userId == userId) { + result.add(session.generateInfo()); + } + } + } + result.removeIf(info -> shouldFilterSession(snapshot, callingUid, info)); + return new ParceledListSlice<>(result); + } + @Override public void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags, IntentSender statusReceiver, int userId) { @@ -1837,7 +1851,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements pw.increaseIndent(); N = mHistoricalSessions.size(); for (int i = 0; i < N; i++) { - pw.print(mHistoricalSessions.get(i)); + mHistoricalSessions.get(i).dump(pw); pw.println(); } pw.println(); diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 627065587825..b6079a64c0cd 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -1148,6 +1148,25 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } + PackageInstallerHistoricalSession createHistoricalSession() { + final float progress; + final float clientProgress; + synchronized (mProgressLock) { + progress = mProgress; + clientProgress = mClientProgress; + } + synchronized (mLock) { + return new PackageInstallerHistoricalSession(sessionId, userId, mOriginalInstallerUid, + mOriginalInstallerPackageName, mInstallSource, mInstallerUid, createdMillis, + updatedMillis, committedMillis, stageDir, stageCid, clientProgress, progress, + isCommitted(), isPreapprovalRequested(), mSealed, mPermissionsManuallyAccepted, + mStageDirInUse, mDestroyed, mFds.size(), mBridges.size(), mFinalStatus, + mFinalMessage, params, mParentSessionId, getChildSessionIdsLocked(), + mSessionApplied, mSessionFailed, mSessionReady, mSessionErrorCode, + mSessionErrorMessage, mPreapprovalDetails); + } + } + /** * Returns {@code true} if the {@link SessionInfo} object should be produced with potentially * sensitive data scrubbed from its fields. diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index c63d8be0e806..914f6d0b4be0 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -6933,6 +6933,11 @@ public class PackageManagerService implements PackageSender, TestUtilityService return mDistractingPackageHelper.getDistractingPackageRestrictionsAsUser(snapshot, packageNames, userId, callingUid); } + + @Override + public ParceledListSlice<PackageInstaller.SessionInfo> getHistoricalSessions(int userId) { + return mInstallerService.getHistoricalSessions(userId); + } } private void setEnabledOverlayPackages(@UserIdInt int userId, |