diff options
-rwxr-xr-x | api/current.txt | 2 | ||||
-rw-r--r-- | core/java/android/app/ContextImpl.java | 18 | ||||
-rw-r--r-- | core/java/android/app/IActivityManager.aidl | 1 | ||||
-rw-r--r-- | core/java/android/content/Context.java | 34 | ||||
-rw-r--r-- | core/java/android/content/ContextWrapper.java | 5 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ActiveServices.java | 33 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ActivityManagerService.java | 149 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ActivityManagerShellCommand.java | 3 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ConnectionRecord.java | 4 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ProcessList.java | 130 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ProcessRecord.java | 8 | ||||
-rw-r--r-- | test-mock/api/current.txt | 1 | ||||
-rw-r--r-- | test-mock/src/android/test/mock/MockContext.java | 5 |
13 files changed, 345 insertions, 48 deletions
diff --git a/api/current.txt b/api/current.txt index ff78d481f4de..4c32d04bcbcb 100755 --- a/api/current.txt +++ b/api/current.txt @@ -9598,6 +9598,7 @@ package android.content { method public abstract void unbindService(android.content.ServiceConnection); method public void unregisterComponentCallbacks(android.content.ComponentCallbacks); method public abstract void unregisterReceiver(android.content.BroadcastReceiver); + method public abstract void updateServiceGroup(android.content.ServiceConnection, int, int); field public static final java.lang.String ACCESSIBILITY_SERVICE = "accessibility"; field public static final java.lang.String ACCOUNT_SERVICE = "account"; field public static final java.lang.String ACTIVITY_SERVICE = "activity"; @@ -9796,6 +9797,7 @@ package android.content { method public boolean stopService(android.content.Intent); method public void unbindService(android.content.ServiceConnection); method public void unregisterReceiver(android.content.BroadcastReceiver); + method public void updateServiceGroup(android.content.ServiceConnection, int, int); } public deprecated class CursorLoader extends android.content.AsyncTaskLoader { diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 9837deb6143c..28ecb27b53d2 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -1724,6 +1724,24 @@ class ContextImpl extends Context { } @Override + public void updateServiceGroup(@NonNull ServiceConnection conn, int group, int importance) { + if (conn == null) { + throw new IllegalArgumentException("connection is null"); + } + if (mPackageInfo != null) { + IServiceConnection sd = mPackageInfo.forgetServiceDispatcher( + getOuterContext(), conn); + try { + ActivityManager.getService().updateServiceGroup(sd, group, importance); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } else { + throw new RuntimeException("Not supported in system context"); + } + } + + @Override public void unbindService(ServiceConnection conn) { if (conn == null) { throw new IllegalArgumentException("connection is null"); diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index f27c6677ed22..e83bcd0e6647 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -140,6 +140,7 @@ interface IActivityManager { int bindIsolatedService(in IApplicationThread caller, in IBinder token, in Intent service, in String resolvedType, in IServiceConnection connection, int flags, in String instanceName, in String callingPackage, int userId); + void updateServiceGroup(in IServiceConnection connection, int group, int importance); boolean unbindService(in IServiceConnection connection); void publishService(in IBinder token, in Intent intent, in IBinder service); void setDebugApp(in String packageName, boolean waitForDebugger, boolean persistent); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 004417b80e26..cec8ef59b961 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -425,6 +425,15 @@ public abstract class Context { */ public static final int BIND_EXTERNAL_SERVICE = 0x80000000; + /** + * These bind flags reduce the strength of the binding such that we shouldn't + * consider it as pulling the process up to the level of the one that is bound to it. + * @hide + */ + public static final int BIND_REDUCTION_FLAGS = + Context.BIND_ALLOW_OOM_MANAGEMENT | Context.BIND_WAIVE_PRIORITY + | Context.BIND_ADJUST_BELOW_PERCEPTIBLE | Context.BIND_NOT_VISIBLE; + /** @hide */ @IntDef(flag = true, prefix = { "RECEIVER_VISIBLE_" }, value = { RECEIVER_VISIBLE_TO_INSTANT_APPS @@ -2982,6 +2991,31 @@ public abstract class Context { } /** + * For a service previously bound with {@link #bindService} or a related method, change + * how the system manages that service's process in relation to other processes. This + * doesn't modify the original bind flags that were passed in when binding, but adjusts + * how the process will be managed in some cases based on those flags. Currently only + * works on isolated processes (will be ignored for non-isolated processes). + * + * @param conn The connection interface previously supplied to bindService(). This + * parameter must not be null. + * @param group A group to put this connection's process in. Upon calling here, this + * will override any previous group that was set for that process. The group + * tells the system about processes that are logically grouped together, so + * should be managed as one unit of importance (such as when being considered + * a recently used app). All processes in the same app with the same group + * are considered to be related. Supplying 0 reverts to the default behavior + * of not grouping. + * @param importance Additional importance of the processes within a group. Upon calling + * here, this will override any previous group that was set for that + * process. This fine-tunes process killing of all processes within + * a related groups -- higher importance values will be killed before + * lower ones. + */ + public abstract void updateServiceGroup(@NonNull ServiceConnection conn, int group, + int importance); + + /** * Disconnect from an application service. You will no longer receive * calls as the service is restarted, and the service is now allowed to * stop at any time. diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index 88696b0e1e4d..2db44b44fd6c 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -726,6 +726,11 @@ public class ContextWrapper extends Context { } @Override + public void updateServiceGroup(ServiceConnection conn, int group, int importance) { + mBase.updateServiceGroup(conn, group, importance); + } + + @Override public void unbindService(ServiceConnection conn) { mBase.unbindService(conn); } diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index c660cc6c6f75..a19e9287aa6c 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -1702,8 +1702,11 @@ public final class ActiveServices { s.app.whitelistManager = true; } // This could have made the service more important. - mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities() - || s.app.treatLikeActivity, b.client); + mAm.updateLruProcessLocked(s.app, + (callerApp.hasActivitiesOrRecentTasks() && s.app.hasClientActivities()) + || (callerApp.getCurProcState() <= ActivityManager.PROCESS_STATE_TOP + && (flags & Context.BIND_TREAT_LIKE_ACTIVITY) != 0), + b.client); mAm.updateOomAdjLocked(s.app, true); } @@ -1787,6 +1790,32 @@ public final class ActiveServices { } } + void updateServiceGroupLocked(IServiceConnection connection, int group, int importance) { + final IBinder binder = connection.asBinder(); + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "updateServiceGroup: conn=" + binder); + final ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder); + if (clist == null) { + throw new IllegalArgumentException("Could not find connection for " + + connection.asBinder()); + } + for (int i = clist.size() - 1; i >= 0; i--) { + final ConnectionRecord crec = clist.get(i); + final ServiceRecord srec = crec.binding.service; + if (srec != null && srec.app != null + && (srec.serviceInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0) { + if (group > 0) { + srec.app.connectionService = srec; + srec.app.connectionGroup = group; + srec.app.connectionImportance = importance; + } else { + srec.app.connectionService = null; + srec.app.connectionGroup = 0; + srec.app.connectionImportance = 0; + } + } + } + } + boolean unbindServiceLocked(IServiceConnection connection) { IBinder binder = connection.asBinder(); if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "unbindService: conn=" + binder); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 4e417bab7d6a..7e9e83cf17d0 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -9207,26 +9207,33 @@ public class ActivityManagerService extends IActivityManager.Stub } dumpAssociationsLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage); } - pw.println(); - if (dumpAll) { - pw.println("-------------------------------------------------------------------------------"); - } - dumpProcessesLocked(fd, pw, args, opti, dumpAll, dumpPackage, dumpAppId); - pw.println(); - if (dumpAll) { - pw.println("-------------------------------------------------------------------------------"); + if (dumpPackage == null) { + pw.println(); + if (dumpAll) { + pw.println("-------------------------------------------------------------------------------"); + } + mOomAdjProfiler.dump(pw); + pw.println(); + if (dumpAll) { + pw.println("-------------------------------------------------------------------------------"); + } + dumpBinderProxies(pw); + pw.println(); + if (dumpAll) { + pw.println("-------------------------------------------------------------------------------"); + } + dumpLmkLocked(pw); } - mOomAdjProfiler.dump(pw); pw.println(); if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); } - dumpBinderProxies(pw); + dumpLruLocked(pw, dumpPackage); pw.println(); if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); } - dumpLmkLocked(pw); + dumpProcessesLocked(fd, pw, args, opti, dumpAll, dumpPackage, dumpAppId); } } @@ -9421,6 +9428,10 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (this) { dumpLmkLocked(pw); } + } else if ("lru".equals(cmd)) { + synchronized (this) { + dumpLruLocked(pw, null); + } } else if ("permissions".equals(cmd) || "perm".equals(cmd)) { synchronized (this) { dumpPermissionsLocked(fd, pw, args, opti, true, null); @@ -9698,17 +9709,102 @@ public class ActivityManagerService extends IActivityManager.Stub } pw.println(); } - pw.println(); return true; } return false; } void dumpBinderProxies(PrintWriter pw) { + pw.println("ACTIVITY MANAGER BINDER PROXY STATE (dumpsys activity binder-proxies)"); dumpBinderProxyInterfaceCounts(pw, - "Top proxy interface names held by SYSTEM"); + " Top proxy interface names held by SYSTEM"); dumpBinderProxiesCounts(pw, - "Counts of Binder Proxies held by SYSTEM"); + " Counts of Binder Proxies held by SYSTEM"); + } + + void dumpLruEntryLocked(PrintWriter pw, int index, ProcessRecord proc) { + pw.print(" #"); + pw.print(index); + pw.print(": "); + pw.print(ProcessList.makeOomAdjString(proc.setAdj)); + pw.print(" "); + pw.print(ProcessList.makeProcStateString(proc.getCurProcState())); + pw.print(" "); + pw.print(proc.toShortString()); + pw.print(" "); + if (proc.hasActivitiesOrRecentTasks() || proc.hasClientActivities() + || proc.treatLikeActivity) { + pw.print(" activity="); + boolean printed = false; + if (proc.hasActivities()) { + pw.print("activities"); + printed = true; + } + if (proc.hasRecentTasks()) { + if (printed) { + pw.print("|"); + } + pw.print("recents"); + printed = true; + } + if (proc.hasClientActivities()) { + if (printed) { + pw.print("|"); + } + pw.print("client"); + printed = true; + } + if (proc.treatLikeActivity) { + if (printed) { + pw.print("|"); + } + pw.print("treated"); + } + } + pw.println(); + } + + // TODO: Move to ProcessList? + void dumpLruLocked(PrintWriter pw, String dumpPackage) { + pw.println("ACTIVITY MANAGER LRU PROCESSES (dumpsys activity lru)"); + final int N = mProcessList.mLruProcesses.size(); + int i; + boolean first = true; + for (i = N - 1; i >= mProcessList.mLruProcessActivityStart; i--) { + final ProcessRecord r = mProcessList.mLruProcesses.get(i); + if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) { + continue; + } + if (first) { + pw.println(" Activities:"); + first = false; + } + dumpLruEntryLocked(pw, i, r); + } + first = true; + for (; i >= mProcessList.mLruProcessServiceStart; i--) { + final ProcessRecord r = mProcessList.mLruProcesses.get(i); + if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) { + continue; + } + if (first) { + pw.println(" Services:"); + first = false; + } + dumpLruEntryLocked(pw, i, r); + } + first = true; + for (; i >= 0; i--) { + final ProcessRecord r = mProcessList.mLruProcesses.get(i); + if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) { + continue; + } + if (first) { + pw.println(" Other:"); + first = false; + } + dumpLruEntryLocked(pw, i, r); + } } // TODO: Move to ProcessList? @@ -13214,6 +13310,12 @@ public class ActivityManagerService extends IActivityManager.Stub } } + public void updateServiceGroup(IServiceConnection connection, int group, int importance) { + synchronized (this) { + mServices.updateServiceGroupLocked(connection, group, importance); + } + } + public boolean unbindService(IServiceConnection connection) { synchronized (this) { return mServices.unbindServiceLocked(connection); @@ -17398,8 +17500,11 @@ public class ActivityManagerService extends IActivityManager.Stub int stepCached = 0; int stepEmpty = 0; int numCached = 0; + int numCachedExtraGroup = 0; int numEmpty = 0; int numTrimming = 0; + int lastCachedGroup = 0; + int lastCachedGroupUid = 0; mNumNonCachedProcs = 0; mNumCachedHiddenProcs = 0; @@ -17523,7 +17628,21 @@ public class ActivityManagerService extends IActivityManager.Stub case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT: mNumCachedHiddenProcs++; numCached++; - if (numCached > cachedProcessLimit) { + if (app.connectionGroup != 0) { + if (lastCachedGroupUid == app.uid + && lastCachedGroup == app.connectionGroup) { + // If this process is the next in the same group, we don't + // want it to count against our limit of the number of cached + // processes, so bump up the group count to account for it. + numCachedExtraGroup++; + } else { + lastCachedGroupUid = app.uid; + lastCachedGroup = app.connectionGroup; + } + } else { + lastCachedGroupUid = lastCachedGroup = 0; + } + if ((numCached - numCachedExtraGroup) > cachedProcessLimit) { app.kill("cached #" + numCached, true); } break; diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 8f8d5abca1d8..67a4d14a6edb 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -2853,6 +2853,9 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" provider [COMP_SPEC]: provider client-side state"); pw.println(" s[ervices] [COMP_SPEC ...]: service state"); pw.println(" as[sociations]: tracked app associations"); + pw.println(" lmk: stats on low memory killer"); + pw.println(" lru: raw LRU process list"); + pw.println(" binder-proxies: stats on binder objects and IPCs"); pw.println(" settings: currently applied config settings"); pw.println(" service [COMP_SPEC]: service client-side state"); pw.println(" package [PACKAGE_NAME]: all state related to given package"); diff --git a/services/core/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java index bfa3f66ce726..aa76b3d6b856 100644 --- a/services/core/java/com/android/server/am/ConnectionRecord.java +++ b/services/core/java/com/android/server/am/ConnectionRecord.java @@ -48,7 +48,7 @@ final class ConnectionRecord { boolean serviceDead; // Well is it? // Please keep the following two enum list synced. - private static int[] BIND_ORIG_ENUMS = new int[] { + private static final int[] BIND_ORIG_ENUMS = new int[] { Context.BIND_AUTO_CREATE, Context.BIND_DEBUG_UNBIND, Context.BIND_NOT_FOREGROUND, @@ -65,7 +65,7 @@ final class ConnectionRecord { Context.BIND_SHOWING_UI, Context.BIND_NOT_VISIBLE, }; - private static int[] BIND_PROTO_ENUMS = new int[] { + private static final int[] BIND_PROTO_ENUMS = new int[] { ConnectionRecordProto.AUTO_CREATE, ConnectionRecordProto.DEBUG_UNBIND, ConnectionRecordProto.NOT_FG, diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 84b364bd20a8..4b19398cc73d 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -50,6 +50,7 @@ import android.app.AppGlobals; import android.app.AppProtoEnums; import android.app.IApplicationThread; import android.content.ComponentName; +import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; @@ -2204,7 +2205,7 @@ public final class ProcessList { @GuardedBy("mService") int updateLruProcessInternalLocked(ProcessRecord app, long now, int index, - String what, Object obj, ProcessRecord srcApp) { + int lruSeq, String what, Object obj, ProcessRecord srcApp) { app.lastActivityTime = now; if (app.hasActivitiesOrRecentTasks()) { @@ -2225,7 +2226,7 @@ public final class ProcessList { return index; } - if (lrui >= mLruProcessActivityStart) { + if (lrui >= mLruProcessActivityStart && index < mLruProcessActivityStart) { // Don't want to touch dependent processes that are hosting activities. return index; } @@ -2237,6 +2238,7 @@ public final class ProcessList { if (DEBUG_LRU) Slog.d(TAG_LRU, "Moving dep from " + lrui + " to " + index + " in LRU list: " + app); mLruProcesses.add(index, app); + app.lruSeq = lruSeq; return index; } @@ -2345,9 +2347,11 @@ public final class ProcessList { */ int nextIndex; + int nextActivityIndex = -1; if (hasActivity) { final int N = mLruProcesses.size(); - if ((!app.hasActivities() || app.hasRecentTasks()) + nextIndex = mLruProcessServiceStart; + if (!app.hasActivitiesOrRecentTasks() && !app.treatLikeActivity && mLruProcessActivityStart < (N - 1)) { // Process doesn't have activities, but has clients with // activities... move it up, but one below the top (the top @@ -2355,36 +2359,92 @@ public final class ProcessList { if (DEBUG_LRU) Slog.d(TAG_LRU, "Adding to second-top of LRU activity list: " + app); mLruProcesses.add(N - 1, app); - // To keep it from spamming the LRU list (by making a bunch of clients), - // we will push down any other entries owned by the app. + // If this process is part of a group, need to pull up any other processes + // in that group to be with it. final int uid = app.info.uid; - for (int i = N - 2; i > mLruProcessActivityStart; i--) { - ProcessRecord subProc = mLruProcesses.get(i); - if (subProc.info.uid == uid) { - // We want to push this one down the list. If the process after - // it is for the same uid, however, don't do so, because we don't - // want them internally to be re-ordered. - if (mLruProcesses.get(i - 1).info.uid != uid) { - if (DEBUG_LRU) Slog.d(TAG_LRU, - "Pushing uid " + uid + " swapping at " + i + ": " - + mLruProcesses.get(i) + " : " - + mLruProcesses.get(i - 1)); - ProcessRecord tmp = mLruProcesses.get(i); - mLruProcesses.set(i, mLruProcesses.get(i - 1)); - mLruProcesses.set(i - 1, tmp); - i--; + int endIndex = N - 2; + nextActivityIndex = N - 2; + if (app.connectionGroup > 0) { + int endImportance = app.connectionImportance; + for (int i = endIndex; i >= mLruProcessActivityStart; i--) { + final ProcessRecord subProc = mLruProcesses.get(i); + if (subProc.info.uid == uid + && subProc.connectionGroup == subProc.connectionGroup) { + if (i == endIndex && subProc.connectionImportance >= endImportance) { + // This process is already in the group, and its importance + // is not as strong as the process before it, so it keep it + // correctly positioned in the group. + endIndex--; + endImportance = subProc.connectionImportance; + } else { + // We want to pull this up to be with the rest of the group, + // and order within the group by importance. + boolean moved = false; + for (int pos = N - 1; pos > endIndex; pos--) { + final ProcessRecord posProc = mLruProcesses.get(pos); + if (subProc.connectionImportance + <= posProc.connectionImportance) { + mLruProcesses.remove(i); + mLruProcesses.add(pos, subProc); + moved = true; + endIndex--; + break; + } + } + if (!moved) { + // Goes to the end of the group. + mLruProcesses.remove(i); + mLruProcesses.add(endIndex - 1, subProc); + endIndex--; + endImportance = subProc.connectionImportance; + } + } + } + } + + } + // To keep it from spamming the LRU list (by making a bunch of clients), + // we will distribute other entries owned by it to be in-between other apps. + for (int i = endIndex; i >= mLruProcessActivityStart; i--) { + final ProcessRecord subProc = mLruProcesses.get(i); + if (subProc.info.uid != uid) { + // This is a different app... if we have gone through some of the + // target app, pull this up to be before them. + if (i < endIndex) { + mLruProcesses.remove(i); + mLruProcesses.add(endIndex, subProc); + } + // Find the end of the next group of processes for target app. This + // is after any entries of different apps (so we don't change the existing + // relative order of apps) and then after the next last group of processes + // of the target app. + for (endIndex--; endIndex >= mLruProcessActivityStart; endIndex--) { + final ProcessRecord endProc = mLruProcesses.get(endIndex); + if (endProc.info.uid == uid) { + break; + } + } + if (endIndex >= mLruProcessActivityStart) { + final ProcessRecord endProc = mLruProcesses.get(endIndex); + for (endIndex--; endIndex >= mLruProcessActivityStart; endIndex--) { + final ProcessRecord nextEndProc = mLruProcesses.get(endIndex); + if (nextEndProc.info.uid != uid + || nextEndProc.connectionGroup != endProc.connectionGroup) { + break; + } + } + } + if (i > endIndex) { + i = endIndex; } - } else { - // A gap, we can stop here. - break; } } } else { // Process has activities, put it at the very tipsy-top. if (DEBUG_LRU) Slog.d(TAG_LRU, "Adding to top of LRU activity list: " + app); mLruProcesses.add(app); + nextActivityIndex = mLruProcesses.size() - 1; } - nextIndex = mLruProcessServiceStart; } else if (hasService) { // Process has services, put it at the top of the service list. if (DEBUG_LRU) Slog.d(TAG_LRU, "Adding to top of LRU service list: " + app); @@ -2416,6 +2476,8 @@ public final class ProcessList { mLruProcessServiceStart++; } + app.lruSeq = mLruSeq; + // If the app is currently using a content provider or service, // bump those processes as well. for (int j = app.connections.size() - 1; j >= 0; j--) { @@ -2423,17 +2485,27 @@ public final class ProcessList { if (cr.binding != null && !cr.serviceDead && cr.binding.service != null && cr.binding.service.app != null && cr.binding.service.app.lruSeq != mLruSeq + && (cr.flags & Context.BIND_REDUCTION_FLAGS) == 0 && !cr.binding.service.app.isPersistent()) { - nextIndex = updateLruProcessInternalLocked(cr.binding.service.app, - now, - nextIndex, - "service connection", cr, app); + if (cr.binding.service.app.hasClientActivities()) { + if (nextActivityIndex >= 0) { + nextActivityIndex = updateLruProcessInternalLocked(cr.binding.service.app, + now, + nextActivityIndex, mLruSeq, + "service connection", cr, app); + } + } else { + nextIndex = updateLruProcessInternalLocked(cr.binding.service.app, + now, + nextIndex, mLruSeq, + "service connection", cr, app); + } } } for (int j = app.conProviders.size() - 1; j >= 0; j--) { ContentProviderRecord cpr = app.conProviders.get(j).provider; if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq && !cpr.proc.isPersistent()) { - nextIndex = updateLruProcessInternalLocked(cpr.proc, now, nextIndex, + nextIndex = updateLruProcessInternalLocked(cpr.proc, now, nextIndex, mLruSeq, "provider reference", cpr, app); } } diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index faf85615eb0d..013de93c7f24 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -155,6 +155,9 @@ final class ProcessRecord implements WindowProcessListener { int pssStatType; // The type of stat collection that we are currently requesting int savedPriority; // Previous priority value if we're switching to non-SCHED_OTHER int renderThreadTid; // TID for RenderThread + ServiceRecord connectionService; // Service that applied current connectionGroup/Importance + int connectionGroup; // Last group set by a connection + int connectionImportance; // Last importance set by a connection boolean serviceb; // Process currently is on the service B list boolean serviceHighRam; // We are forcing to service B list due to its RAM use boolean notCachedSinceIdle; // Has this process not been in a cached state since last idle? @@ -396,6 +399,11 @@ final class ProcessRecord implements WindowProcessListener { pw.print(" hasAboveClient="); pw.print(hasAboveClient); pw.print(" treatLikeActivity="); pw.println(treatLikeActivity); } + if (connectionService != null || connectionGroup != 0) { + pw.print(prefix); pw.print("connectionGroup="); pw.print(connectionGroup); + pw.print(" Importance="); pw.print(connectionImportance); + pw.print(" Service="); pw.println(connectionService); + } if (hasTopUi() || hasOverlayUi() || runningRemoteAnimation) { pw.print(prefix); pw.print("hasTopUi="); pw.print(hasTopUi()); pw.print(" hasOverlayUi="); pw.print(hasOverlayUi()); diff --git a/test-mock/api/current.txt b/test-mock/api/current.txt index f91d74a30693..7842a1cd03b3 100644 --- a/test-mock/api/current.txt +++ b/test-mock/api/current.txt @@ -135,6 +135,7 @@ package android.test.mock { method public boolean stopService(android.content.Intent); method public void unbindService(android.content.ServiceConnection); method public void unregisterReceiver(android.content.BroadcastReceiver); + method public void updateServiceGroup(android.content.ServiceConnection, int, int); } public deprecated class MockCursor implements android.database.Cursor { diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java index 66be6d9d9840..ae6cd29fb2de 100644 --- a/test-mock/src/android/test/mock/MockContext.java +++ b/test-mock/src/android/test/mock/MockContext.java @@ -591,6 +591,11 @@ public class MockContext extends Context { } @Override + public void updateServiceGroup(ServiceConnection conn, int group, int importance) { + throw new UnsupportedOperationException(); + } + + @Override public void unbindService(ServiceConnection conn) { throw new UnsupportedOperationException(); } |