From 9a68bedca7ab3c21f7418f88a290f54e354d3e3f Mon Sep 17 00:00:00 2001 From: Samiul Islam Date: Thu, 22 Jul 2021 16:41:09 +0100 Subject: [PATCH] Open up new API in StagingManager to get information about staged APEX These APIs will be later used by PackageManagerNative service to open up the information to native clients. The current implementation is a bit wasteful since everytime the client makes a request, we ask the ApexManager to fetch us information about the staged sessions N times, where N is the number of staged sessions that are marked ready. We can optimize it by caching the result of getStagedApexInfos(session) method. This will be done in a separate CL. (Note: Unit tests have been removed to resolve cherry-pick conflict) Bug: 187444679 Test: atest StagedInstallInternalTests Change-Id: I76803382db26a029f6d9cabb0d9ce9a2bf9c8ea1 Merged-In: I76803382db26a029f6d9cabb0d9ce9a2bf9c8ea1 (cherry picked from commit c8132a943723f56fb4850b96779ac39d41fec336) --- .../com/android/server/pm/StagingManager.java | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 4038bf2901610..f1e300891eeb3 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -58,6 +58,7 @@ import android.os.UserManagerInternal; import android.os.storage.IStorageManager; import android.os.storage.StorageManager; import android.text.TextUtils; +import android.util.ArrayMap; import android.util.IntArray; import android.util.Slog; import android.util.SparseArray; @@ -66,8 +67,10 @@ import android.util.SparseIntArray; import android.util.apk.ApkSignatureVerifier; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.PackageHelper; import com.android.internal.os.BackgroundThread; +import com.android.internal.util.Preconditions; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.SystemServiceManager; @@ -84,7 +87,9 @@ import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; @@ -1299,6 +1304,86 @@ public class StagingManager { return session; } + /** + * Returns ApexInfo about APEX contained inside the session as a {@code Map}, + * where the key of the map is the module name of the ApexInfo. + * + * Returns an empty map if there is any error. + */ + @VisibleForTesting + @NonNull + Map getStagedApexInfos(@NonNull PackageInstallerSession session) { + Preconditions.checkArgument(session != null, "Session is null"); + Preconditions.checkArgument(!session.hasParentSessionId(), + session.sessionId + " session has parent session"); + Preconditions.checkArgument(sessionContainsApex(session), + session.sessionId + " session does not contain apex"); + + // Even if caller calls this method on ready session, the session could be abandoned + // right after this method is called. + if (!session.isStagedSessionReady() || session.isDestroyed()) { + return Collections.emptyMap(); + } + + ApexSessionParams params = new ApexSessionParams(); + params.sessionId = session.sessionId; + final IntArray childSessionIds = new IntArray(); + if (session.isMultiPackage()) { + for (int id : session.getChildSessionIds()) { + if (isApexSession(getStagedSession(id))) { + childSessionIds.add(id); + } + } + } + params.childSessionIds = childSessionIds.toArray(); + + ApexInfo[] infos = mApexManager.getStagedApexInfos(params); + Map result = new ArrayMap<>(); + for (ApexInfo info : infos) { + result.put(info.moduleName, info); + } + return result; + } + + /** + * Returns apex module names of all packages that are staged ready + */ + List getStagedApexModuleNames() { + List result = new ArrayList<>(); + synchronized (mStagedSessions) { + for (int i = 0; i < mStagedSessions.size(); i++) { + final PackageInstallerSession session = mStagedSessions.valueAt(i); + if (!session.isStagedSessionReady() || session.isDestroyed() + || session.hasParentSessionId() || !sessionContainsApex(session)) { + continue; + } + result.addAll(getStagedApexInfos(session).keySet()); + } + } + return result; + } + + /** + * Returns ApexInfo of the {@code moduleInfo} provided if it is staged, otherwise returns null. + */ + @Nullable + ApexInfo getStagedApexInfo(String moduleName) { + synchronized (mStagedSessions) { + for (int i = 0; i < mStagedSessions.size(); i++) { + final PackageInstallerSession session = mStagedSessions.valueAt(i); + if (!session.isStagedSessionReady() || session.isDestroyed() + || session.hasParentSessionId() || !sessionContainsApex(session)) { + continue; + } + ApexInfo result = getStagedApexInfos(session).get(moduleName); + if (result != null) { + return result; + } + } + } + return null; + } + private final class PreRebootVerificationHandler extends Handler { // Hold session ids before handler gets ready to do the verification. private IntArray mPendingSessionIds;