From 2a3daaa3b12fe428ec79ca8a201e829b6370073c Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Thu, 12 Jan 2023 10:51:48 +0000 Subject: [PATCH] OomAdjuster: Give SDK sandbox the priority of the app it belongs to. SDK sandbox processes are bound to by system_server, but system_server binds on behalf of a regular application process. An earlier changed stored this "attributed" process in the AppBindRecord; here, retrieve it, and use that to compute the priority of the sandbox instead. Additionally, keep track of started SDK sandboxes per UID, so that we can retrieve them when computing the downstream dependencies of applications in collectReachableProcessesLocked(). Bug: 253399592 Test: atest SdkSandboxLifecycleHostTest Test: evaluate OOM adj scores Change-Id: Ib0696c55e7c0c16c3ba2d19d861098bd2e3ebd21 --- .../com/android/server/am/OomAdjuster.java | 49 ++++++++++++++++++- .../com/android/server/am/ProcessList.java | 37 ++++++++++++++ 2 files changed, 84 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 81655cf33fa8d..114e2c1397943 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -143,6 +143,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; +import java.util.List; /** * All of the code required to compute proc states and oom_adj values. @@ -743,6 +744,45 @@ public class OomAdjuster { queue.offer(provider); provider.mState.setReachable(true); } + // See if this process has any corresponding SDK sandbox processes running, and if so + // scan them as well. + final List sdkSandboxes = + mProcessList.getSdkSandboxProcessesForAppLocked(pr.uid); + final int numSdkSandboxes = sdkSandboxes != null ? sdkSandboxes.size() : 0; + for (int i = numSdkSandboxes - 1; i >= 0; i--) { + ProcessRecord sdkSandbox = sdkSandboxes.get(i); + containsCycle |= sdkSandbox.mState.isReachable(); + if (sdkSandbox.mState.isReachable()) { + continue; + } + queue.offer(sdkSandbox); + sdkSandbox.mState.setReachable(true); + } + // If this process is a sandbox itself, also scan the app on whose behalf its running + if (pr.isSdkSandbox) { + for (int is = psr.numberOfRunningServices() - 1; is >= 0; is--) { + ServiceRecord s = psr.getRunningServiceAt(is); + ArrayMap> serviceConnections = + s.getConnections(); + for (int conni = serviceConnections.size() - 1; conni >= 0; conni--) { + ArrayList clist = serviceConnections.valueAt(conni); + for (int i = clist.size() - 1; i >= 0; i--) { + ConnectionRecord cr = clist.get(i); + ProcessRecord attributedApp = cr.binding.attributedClient; + if (attributedApp == null || attributedApp == pr + || ((attributedApp.mState.getMaxAdj() >= ProcessList.SYSTEM_ADJ) + && (attributedApp.mState.getMaxAdj() < FOREGROUND_APP_ADJ))) { + continue; + } + if (attributedApp.mState.isReachable()) { + continue; + } + queue.offer(attributedApp); + attributedApp.mState.setReachable(true); + } + } + } + } } int size = processes.size(); @@ -2131,6 +2171,11 @@ public class OomAdjuster { boolean trackedProcState = false; ProcessRecord client = cr.binding.client; + if (app.isSdkSandbox && cr.binding.attributedClient != null) { + // For SDK sandboxes, use the attributed client (eg the app that + // requested the sandbox) + client = cr.binding.attributedClient; + } final ProcessStateRecord cstate = client.mState; if (computeClients) { computeOomAdjLSP(client, cachedAdj, topApp, doingAll, now, @@ -2377,12 +2422,12 @@ public class OomAdjuster { state.setAdjType(adjType); state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo .REASON_SERVICE_IN_USE); - state.setAdjSource(cr.binding.client); + state.setAdjSource(client); state.setAdjSourceProcState(clientProcState); state.setAdjTarget(s.instanceName); if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType - + ": " + app + ", due to " + cr.binding.client + + ": " + app + ", due to " + client + " adj=" + adj + " procState=" + ProcessList.makeProcStateString(procState)); } diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 3a40fc7199f39..04c0d64e42a1c 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -484,6 +484,12 @@ public final class ProcessList { @GuardedBy("mService") final ProcessMap mAppZygotes = new ProcessMap(); + /** + * The currently running SDK sandbox processes for a uid. + */ + @GuardedBy("mService") + final SparseArray> mSdkSandboxes = new SparseArray<>(); + /** * Managees the {@link android.app.ApplicationExitInfo} records. */ @@ -2990,6 +2996,14 @@ public final class ProcessList { if (proc.isolated) { mIsolatedProcesses.put(proc.uid, proc); } + if (proc.isSdkSandbox) { + ArrayList sdkSandboxes = mSdkSandboxes.get(proc.uid); + if (sdkSandboxes == null) { + sdkSandboxes = new ArrayList<>(); + } + sdkSandboxes.add(proc); + mSdkSandboxes.put(Process.getAppUidForSdkSandboxUid(proc.uid), sdkSandboxes); + } } @GuardedBy("mService") @@ -3030,6 +3044,19 @@ public final class ProcessList { return ret; } + /** + * Returns the associated SDK sandbox processes for a UID. Note that this does + * NOT return a copy, so callers should not modify the result, or use it outside + * of the lock scope. + * + * @param uid UID to return sansdbox processes for + */ + @Nullable + @GuardedBy("mService") + List getSdkSandboxProcessesForAppLocked(int uid) { + return mSdkSandboxes.get(uid); + } + @GuardedBy("mService") ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess, boolean isolated, int isolatedUid, boolean isSdkSandbox, int sdkSandboxUid, @@ -3135,6 +3162,16 @@ public final class ProcessList { if (record != null && record.appZygote) { removeProcessFromAppZygoteLocked(record); } + if (record != null && record.isSdkSandbox) { + final int appUid = Process.getAppUidForSdkSandboxUid(uid); + final ArrayList sdkSandboxesForUid = mSdkSandboxes.get(appUid); + if (sdkSandboxesForUid != null) { + sdkSandboxesForUid.remove(record); + if (sdkSandboxesForUid.size() == 0) { + mSdkSandboxes.remove(appUid); + } + } + } mAppsInBackgroundRestricted.remove(record); return old;