2 * Copyright (C) 2019 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.server.am;
19 import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
20 import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
21 import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
22 import static android.app.ActivityManager.PROCESS_STATE_CACHED_EMPTY;
23 import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
24 import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE_LOCATION;
25 import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
26 import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
27 import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
28 import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
29 import static android.app.ActivityManager.PROCESS_STATE_SERVICE;
30 import static android.app.ActivityManager.PROCESS_STATE_TOP;
31 import static android.app.ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
32 import static android.os.Process.SCHED_OTHER;
33 import static android.os.Process.THREAD_GROUP_BG_NONINTERACTIVE;
34 import static android.os.Process.THREAD_GROUP_DEFAULT;
35 import static android.os.Process.THREAD_GROUP_RESTRICTED;
36 import static android.os.Process.THREAD_GROUP_TOP_APP;
37 import static android.os.Process.THREAD_PRIORITY_DISPLAY;
38 import static android.os.Process.setProcessGroup;
39 import static android.os.Process.setThreadPriority;
40 import static android.os.Process.setThreadScheduler;
42 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
43 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKUP;
44 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LRU;
45 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
46 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ_REASON;
47 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESS_OBSERVERS;
48 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS;
49 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
50 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USAGE_STATS;
51 import static com.android.server.am.ActivityManagerService.DISPATCH_OOM_ADJ_OBSERVER_MSG;
52 import static com.android.server.am.ActivityManagerService.IDLE_UIDS_MSG;
53 import static com.android.server.am.ActivityManagerService.TAG_BACKUP;
54 import static com.android.server.am.ActivityManagerService.TAG_LRU;
55 import static com.android.server.am.ActivityManagerService.TAG_OOM_ADJ;
56 import static com.android.server.am.ActivityManagerService.TAG_PROCESS_OBSERVERS;
57 import static com.android.server.am.ActivityManagerService.TAG_PSS;
58 import static com.android.server.am.ActivityManagerService.TAG_UID_OBSERVERS;
59 import static com.android.server.am.ActivityManagerService.TOP_APP_PRIORITY_BOOST;
60 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
62 import android.app.ActivityManager;
63 import android.app.usage.UsageEvents;
64 import android.content.Context;
65 import android.os.Debug;
66 import android.os.Handler;
67 import android.os.IBinder;
68 import android.os.PowerManagerInternal;
69 import android.os.Process;
70 import android.os.RemoteException;
71 import android.os.SystemClock;
72 import android.os.Trace;
73 import android.os.UserHandle;
74 import android.util.ArrayMap;
75 import android.util.ArraySet;
76 import android.util.Slog;
77 import android.util.proto.ProtoOutputStream;
79 import com.android.internal.annotations.GuardedBy;
80 import com.android.internal.annotations.VisibleForTesting;
81 import com.android.internal.app.procstats.ProcessStats;
82 import com.android.server.LocalServices;
83 import com.android.server.ServiceThread;
84 import com.android.server.wm.ActivityServiceConnectionsHolder;
85 import com.android.server.wm.WindowProcessController;
87 import java.io.PrintWriter;
88 import java.util.ArrayList;
89 import java.util.Arrays;
92 * All of the code required to compute proc states and oom_adj values.
94 public final class OomAdjuster {
95 private static final String TAG = "OomAdjuster";
97 static final String OOM_ADJ_REASON_METHOD = "updateOomAdj";
98 static final String OOM_ADJ_REASON_NONE = OOM_ADJ_REASON_METHOD + "_meh";
99 static final String OOM_ADJ_REASON_ACTIVITY = OOM_ADJ_REASON_METHOD + "_activityChange";
100 static final String OOM_ADJ_REASON_FINISH_RECEIVER = OOM_ADJ_REASON_METHOD + "_finishReceiver";
101 static final String OOM_ADJ_REASON_START_RECEIVER = OOM_ADJ_REASON_METHOD + "_startReceiver";
102 static final String OOM_ADJ_REASON_BIND_SERVICE = OOM_ADJ_REASON_METHOD + "_bindService";
103 static final String OOM_ADJ_REASON_UNBIND_SERVICE = OOM_ADJ_REASON_METHOD + "_unbindService";
104 static final String OOM_ADJ_REASON_START_SERVICE = OOM_ADJ_REASON_METHOD + "_startService";
105 static final String OOM_ADJ_REASON_GET_PROVIDER = OOM_ADJ_REASON_METHOD + "_getProvider";
106 static final String OOM_ADJ_REASON_REMOVE_PROVIDER = OOM_ADJ_REASON_METHOD + "_removeProvider";
107 static final String OOM_ADJ_REASON_UI_VISIBILITY = OOM_ADJ_REASON_METHOD + "_uiVisibility";
108 static final String OOM_ADJ_REASON_WHITELIST = OOM_ADJ_REASON_METHOD + "_whitelistChange";
109 static final String OOM_ADJ_REASON_PROCESS_BEGIN = OOM_ADJ_REASON_METHOD + "_processBegin";
110 static final String OOM_ADJ_REASON_PROCESS_END = OOM_ADJ_REASON_METHOD + "_processEnd";
113 * For some direct access we need to power manager.
115 PowerManagerInternal mLocalPowerManager;
118 * Service for compacting background apps.
120 AppCompactor mAppCompact;
122 ActivityManagerConstants mConstants;
124 final long[] mTmpLong = new long[3];
127 * Current sequence id for oom_adj computation traversal.
132 * Keep track of the number of service processes we last found, to
133 * determine on the next iteration which should be B services.
135 int mNumServiceProcs = 0;
136 int mNewNumAServiceProcs = 0;
137 int mNewNumServiceProcs = 0;
140 * Keep track of the non-cached/empty process we last found, to help
141 * determine how to distribute cached/empty processes next time.
143 int mNumNonCachedProcs = 0;
146 * Keep track of the number of cached hidden procs, to balance oom adj
147 * distribution between those and empty procs.
149 int mNumCachedHiddenProcs = 0;
151 /** Track all uids that have actively running processes. */
152 ActiveUids mActiveUids;
155 * The handler to execute {@link #setProcessGroup} (it may be heavy if the process has many
156 * threads) for reducing the time spent in {@link #applyOomAdjLocked}.
158 private final Handler mProcessGroupHandler;
160 private final ArraySet<BroadcastQueue> mTmpBroadcastQueue = new ArraySet();
162 private final ActivityManagerService mService;
163 private final ProcessList mProcessList;
165 OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids) {
167 mProcessList = processList;
168 mActiveUids = activeUids;
170 mLocalPowerManager = LocalServices.getService(PowerManagerInternal.class);
171 mConstants = mService.mConstants;
172 mAppCompact = new AppCompactor(mService);
174 // The process group is usually critical to the response time of foreground app, so the
175 // setter should apply it as soon as possible.
176 final ServiceThread adjusterThread = new ServiceThread(TAG, TOP_APP_PRIORITY_BOOST,
177 false /* allowIo */);
178 adjusterThread.start();
179 Process.setThreadGroupAndCpuset(adjusterThread.getThreadId(), THREAD_GROUP_TOP_APP);
180 mProcessGroupHandler = new Handler(adjusterThread.getLooper(), msg -> {
181 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "setProcessGroup");
182 final int pid = msg.arg1;
183 final int group = msg.arg2;
185 setProcessGroup(pid, group);
186 } catch (Exception e) {
188 Slog.w(TAG, "Failed setting process group of " + pid + " to " + group, e);
191 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
197 void initSettings() {
202 * Update OomAdj for a specific process.
203 * @param app The process to update
204 * @param oomAdjAll If it's ok to call updateOomAdjLocked() for all running apps
205 * if necessary, or skip.
206 * @param oomAdjReason
207 * @return whether updateOomAdjLocked(app) was successful.
209 @GuardedBy("mService")
210 boolean updateOomAdjLocked(ProcessRecord app, boolean oomAdjAll,
211 String oomAdjReason) {
212 final ProcessRecord TOP_APP = mService.getTopAppLocked();
213 final boolean wasCached = app.cached;
217 // This is the desired cached adjusment we want to tell it to use.
218 // If our app is currently cached, we know it, and that is it. Otherwise,
219 // we don't know it yet, and it needs to now be cached we will then
220 // need to do a complete oom adj.
221 final int cachedAdj = app.getCurRawAdj() >= ProcessList.CACHED_APP_MIN_ADJ
222 ? app.getCurRawAdj() : ProcessList.UNKNOWN_ADJ;
223 boolean success = updateOomAdjLocked(app, cachedAdj, TOP_APP, false,
224 SystemClock.uptimeMillis());
226 && (wasCached != app.cached || app.getCurRawAdj() == ProcessList.UNKNOWN_ADJ)) {
227 // Changed to/from cached state, so apps after it in the LRU
228 // list may also be changed.
229 updateOomAdjLocked(oomAdjReason);
234 @GuardedBy("mService")
235 private final boolean updateOomAdjLocked(ProcessRecord app, int cachedAdj,
236 ProcessRecord TOP_APP, boolean doingAll, long now) {
237 if (app.thread == null) {
241 computeOomAdjLocked(app, cachedAdj, TOP_APP, doingAll, now, false);
243 return applyOomAdjLocked(app, doingAll, now, SystemClock.elapsedRealtime());
246 @GuardedBy("mService")
247 void updateOomAdjLocked(String oomAdjReason) {
248 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReason);
249 mService.mOomAdjProfiler.oomAdjStarted();
250 final ProcessRecord TOP_APP = mService.getTopAppLocked();
251 final long now = SystemClock.uptimeMillis();
252 final long nowElapsed = SystemClock.elapsedRealtime();
253 final long oldTime = now - ProcessList.MAX_EMPTY_TIME;
254 final int N = mProcessList.getLruSizeLocked();
256 // Reset state in all uid records.
257 for (int i = mActiveUids.size() - 1; i >= 0; i--) {
258 final UidRecord uidRec = mActiveUids.valueAt(i);
259 if (false && DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
260 "Starting update of " + uidRec);
264 if (mService.mAtmInternal != null) {
265 mService.mAtmInternal.rankTaskLayersIfNeeded();
269 mNewNumServiceProcs = 0;
270 mNewNumAServiceProcs = 0;
272 final int emptyProcessLimit = mConstants.CUR_MAX_EMPTY_PROCESSES;
273 final int cachedProcessLimit = mConstants.CUR_MAX_CACHED_PROCESSES
276 // Let's determine how many processes we have running vs.
277 // how many slots we have for background processes; we may want
278 // to put multiple processes in a slot of there are enough of
280 final int numSlots = (ProcessList.CACHED_APP_MAX_ADJ
281 - ProcessList.CACHED_APP_MIN_ADJ + 1) / 2
282 / ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
283 int numEmptyProcs = N - mNumNonCachedProcs - mNumCachedHiddenProcs;
284 if (numEmptyProcs > cachedProcessLimit) {
285 // If there are more empty processes than our limit on cached
286 // processes, then use the cached process limit for the factor.
287 // This ensures that the really old empty processes get pushed
288 // down to the bottom, so if we are running low on memory we will
289 // have a better chance at keeping around more cached processes
290 // instead of a gazillion empty processes.
291 numEmptyProcs = cachedProcessLimit;
293 int emptyFactor = (numEmptyProcs + numSlots - 1) / numSlots;
294 if (emptyFactor < 1) emptyFactor = 1;
295 int cachedFactor = (mNumCachedHiddenProcs > 0 ? (mNumCachedHiddenProcs + numSlots - 1) : 1)
297 if (cachedFactor < 1) cachedFactor = 1;
301 int numCachedExtraGroup = 0;
304 int lastCachedGroup = 0;
305 int lastCachedGroupImportance = 0;
306 int lastCachedGroupUid = 0;
308 mNumNonCachedProcs = 0;
309 mNumCachedHiddenProcs = 0;
311 // First update the OOM adjustment for each of the
312 // application processes based on their current state.
313 int curCachedAdj = ProcessList.CACHED_APP_MIN_ADJ;
314 int nextCachedAdj = curCachedAdj + (ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2);
315 int curCachedImpAdj = 0;
316 int curEmptyAdj = ProcessList.CACHED_APP_MIN_ADJ + ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
317 int nextEmptyAdj = curEmptyAdj + (ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2);
319 boolean retryCycles = false;
321 // need to reset cycle state before calling computeOomAdjLocked because of service conns
322 for (int i = N - 1; i >= 0; i--) {
323 ProcessRecord app = mProcessList.mLruProcesses.get(i);
324 app.containsCycle = false;
325 app.setCurRawProcState(PROCESS_STATE_CACHED_EMPTY);
326 app.setCurRawAdj(ProcessList.UNKNOWN_ADJ);
328 for (int i = N - 1; i >= 0; i--) {
329 ProcessRecord app = mProcessList.mLruProcesses.get(i);
330 if (!app.killedByAm && app.thread != null) {
331 app.procStateChanged = false;
332 computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now, false);
334 // if any app encountered a cycle, we need to perform an additional loop later
335 retryCycles |= app.containsCycle;
337 // If we haven't yet assigned the final cached adj
338 // to the process, do that now.
339 if (app.curAdj >= ProcessList.UNKNOWN_ADJ) {
340 switch (app.getCurProcState()) {
341 case PROCESS_STATE_CACHED_ACTIVITY:
342 case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
343 case ActivityManager.PROCESS_STATE_CACHED_RECENT:
344 // Figure out the next cached level, taking into account groups.
345 boolean inGroup = false;
346 if (app.connectionGroup != 0) {
347 if (lastCachedGroupUid == app.uid
348 && lastCachedGroup == app.connectionGroup) {
349 // This is in the same group as the last process, just tweak
350 // adjustment by importance.
351 if (app.connectionImportance > lastCachedGroupImportance) {
352 lastCachedGroupImportance = app.connectionImportance;
353 if (curCachedAdj < nextCachedAdj
354 && curCachedAdj < ProcessList.CACHED_APP_MAX_ADJ) {
360 lastCachedGroupUid = app.uid;
361 lastCachedGroup = app.connectionGroup;
362 lastCachedGroupImportance = app.connectionImportance;
365 if (!inGroup && curCachedAdj != nextCachedAdj) {
368 if (stepCached >= cachedFactor) {
370 curCachedAdj = nextCachedAdj;
371 nextCachedAdj += ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2;
372 if (nextCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {
373 nextCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;
377 // This process is a cached process holding activities...
378 // assign it the next cached value for that type, and then
379 // step that cached level.
380 app.setCurRawAdj(curCachedAdj + curCachedImpAdj);
381 app.curAdj = app.modifyRawOomAdj(curCachedAdj + curCachedImpAdj);
382 if (DEBUG_LRU && false) Slog.d(TAG_LRU, "Assigning activity LRU #" + i
383 + " adj: " + app.curAdj + " (curCachedAdj=" + curCachedAdj
384 + " curCachedImpAdj=" + curCachedImpAdj + ")");
387 // Figure out the next cached level.
388 if (curEmptyAdj != nextEmptyAdj) {
390 if (stepEmpty >= emptyFactor) {
392 curEmptyAdj = nextEmptyAdj;
393 nextEmptyAdj += ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2;
394 if (nextEmptyAdj > ProcessList.CACHED_APP_MAX_ADJ) {
395 nextEmptyAdj = ProcessList.CACHED_APP_MAX_ADJ;
399 // For everything else, assign next empty cached process
400 // level and bump that up. Note that this means that
401 // long-running services that have dropped down to the
402 // cached level will be treated as empty (since their process
403 // state is still as a service), which is what we want.
404 app.setCurRawAdj(curEmptyAdj);
405 app.curAdj = app.modifyRawOomAdj(curEmptyAdj);
406 if (DEBUG_LRU && false) Slog.d(TAG_LRU, "Assigning empty LRU #" + i
407 + " adj: " + app.curAdj + " (curEmptyAdj=" + curEmptyAdj
416 // - Retry computing any process that has encountered a cycle.
417 // - Continue retrying until no process was promoted.
418 // - Iterate from least important to most important.
420 while (retryCycles && cycleCount < 10) {
424 for (int i = 0; i < N; i++) {
425 ProcessRecord app = mProcessList.mLruProcesses.get(i);
426 if (!app.killedByAm && app.thread != null && app.containsCycle == true) {
428 app.completedAdjSeq--;
432 for (int i = 0; i < N; i++) {
433 ProcessRecord app = mProcessList.mLruProcesses.get(i);
434 if (!app.killedByAm && app.thread != null && app.containsCycle == true) {
435 if (computeOomAdjLocked(app, app.getCurRawAdj(), TOP_APP, true, now,
443 lastCachedGroup = lastCachedGroupUid = 0;
445 for (int i = N - 1; i >= 0; i--) {
446 ProcessRecord app = mProcessList.mLruProcesses.get(i);
447 if (!app.killedByAm && app.thread != null) {
448 applyOomAdjLocked(app, true, now, nowElapsed);
450 // Count the number of process types.
451 switch (app.getCurProcState()) {
452 case PROCESS_STATE_CACHED_ACTIVITY:
453 case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
454 mNumCachedHiddenProcs++;
456 if (app.connectionGroup != 0) {
457 if (lastCachedGroupUid == app.info.uid
458 && lastCachedGroup == app.connectionGroup) {
459 // If this process is the next in the same group, we don't
460 // want it to count against our limit of the number of cached
461 // processes, so bump up the group count to account for it.
462 numCachedExtraGroup++;
464 lastCachedGroupUid = app.info.uid;
465 lastCachedGroup = app.connectionGroup;
468 lastCachedGroupUid = lastCachedGroup = 0;
470 if ((numCached - numCachedExtraGroup) > cachedProcessLimit) {
471 app.kill("cached #" + numCached, true);
474 case PROCESS_STATE_CACHED_EMPTY:
475 if (numEmpty > mConstants.CUR_TRIM_EMPTY_PROCESSES
476 && app.lastActivityTime < oldTime) {
477 app.kill("empty for "
478 + ((oldTime + ProcessList.MAX_EMPTY_TIME - app.lastActivityTime)
479 / 1000) + "s", true);
482 if (numEmpty > emptyProcessLimit) {
483 app.kill("empty #" + numEmpty, true);
488 mNumNonCachedProcs++;
492 if (app.isolated && app.services.size() <= 0 && app.isolatedEntryPoint == null) {
493 // If this is an isolated process, there are no services
494 // running in it, and it's not a special process with a
495 // custom entry point, then the process is no longer
496 // needed. We agressively kill these because we can by
497 // definition not re-use the same process again, and it is
498 // good to avoid having whatever code was running in them
499 // left sitting around after no longer needed.
500 app.kill("isolated not needed", true);
502 // Keeping this process, update its uid.
503 final UidRecord uidRec = app.uidRecord;
504 if (uidRec != null) {
505 uidRec.ephemeral = app.info.isInstantApp();
506 if (uidRec.getCurProcState() > app.getCurProcState()) {
507 uidRec.setCurProcState(app.getCurProcState());
509 if (app.hasForegroundServices()) {
510 uidRec.foregroundServices = true;
515 if (app.getCurProcState() >= ActivityManager.PROCESS_STATE_HOME
516 && !app.killedByAm) {
522 mService.incrementProcStateSeqAndNotifyAppsLocked();
524 mNumServiceProcs = mNewNumServiceProcs;
526 boolean allChanged = mService.updateLowMemStateLocked(numCached, numEmpty, numTrimming);
528 if (mService.mAlwaysFinishActivities) {
529 // Need to do this on its own message because the stack may not
530 // be in a consistent state at this point.
531 mService.mAtmInternal.scheduleDestroyAllActivities("always-finish");
535 mService.requestPssAllProcsLocked(now, false,
536 mService.mProcessStats.isMemFactorLowered());
539 ArrayList<UidRecord> becameIdle = null;
541 // Update from any uid changes.
542 if (mLocalPowerManager != null) {
543 mLocalPowerManager.startUidChanges();
545 for (int i = mActiveUids.size() - 1; i >= 0; i--) {
546 final UidRecord uidRec = mActiveUids.valueAt(i);
547 int uidChange = UidRecord.CHANGE_PROCSTATE;
548 if (uidRec.getCurProcState() != PROCESS_STATE_NONEXISTENT
549 && (uidRec.setProcState != uidRec.getCurProcState()
550 || uidRec.setWhitelist != uidRec.curWhitelist)) {
551 if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, "Changes in " + uidRec
552 + ": proc state from " + uidRec.setProcState + " to "
553 + uidRec.getCurProcState() + ", whitelist from " + uidRec.setWhitelist
554 + " to " + uidRec.curWhitelist);
555 if (ActivityManager.isProcStateBackground(uidRec.getCurProcState())
556 && !uidRec.curWhitelist) {
557 // UID is now in the background (and not on the temp whitelist). Was it
558 // previously in the foreground (or on the temp whitelist)?
559 if (!ActivityManager.isProcStateBackground(uidRec.setProcState)
560 || uidRec.setWhitelist) {
561 uidRec.lastBackgroundTime = nowElapsed;
562 if (!mService.mHandler.hasMessages(IDLE_UIDS_MSG)) {
563 // Note: the background settle time is in elapsed realtime, while
564 // the handler time base is uptime. All this means is that we may
565 // stop background uids later than we had intended, but that only
566 // happens because the device was sleeping so we are okay anyway.
567 mService.mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG,
568 mConstants.BACKGROUND_SETTLE_TIME);
571 if (uidRec.idle && !uidRec.setIdle) {
572 uidChange = UidRecord.CHANGE_IDLE;
573 if (becameIdle == null) {
574 becameIdle = new ArrayList<>();
576 becameIdle.add(uidRec);
580 uidChange = UidRecord.CHANGE_ACTIVE;
581 EventLogTags.writeAmUidActive(uidRec.uid);
584 uidRec.lastBackgroundTime = 0;
586 final boolean wasCached = uidRec.setProcState
587 > ActivityManager.PROCESS_STATE_RECEIVER;
588 final boolean isCached = uidRec.getCurProcState()
589 > ActivityManager.PROCESS_STATE_RECEIVER;
590 if (wasCached != isCached || uidRec.setProcState == PROCESS_STATE_NONEXISTENT) {
591 uidChange |= isCached ? UidRecord.CHANGE_CACHED : UidRecord.CHANGE_UNCACHED;
593 uidRec.setProcState = uidRec.getCurProcState();
594 uidRec.setWhitelist = uidRec.curWhitelist;
595 uidRec.setIdle = uidRec.idle;
596 mService.mAtmInternal.onUidProcStateChanged(uidRec.uid, uidRec.setProcState);
597 mService.enqueueUidChangeLocked(uidRec, -1, uidChange);
598 mService.noteUidProcessState(uidRec.uid, uidRec.getCurProcState());
599 if (uidRec.foregroundServices) {
600 mService.mServices.foregroundServiceProcStateChangedLocked(uidRec);
604 if (mLocalPowerManager != null) {
605 mLocalPowerManager.finishUidChanges();
608 if (becameIdle != null) {
609 // If we have any new uids that became idle this time, we need to make sure
610 // they aren't left with running services.
611 for (int i = becameIdle.size() - 1; i >= 0; i--) {
612 mService.mServices.stopInBackgroundLocked(becameIdle.get(i).uid);
616 if (mService.mProcessStats.shouldWriteNowLocked(now)) {
617 mService.mHandler.post(new ActivityManagerService.ProcStatsRunnable(mService,
618 mService.mProcessStats));
621 // Run this after making sure all procstates are updated.
622 mService.mProcessStats.updateTrackingAssociationsLocked(mAdjSeq, now);
625 final long duration = SystemClock.uptimeMillis() - now;
627 Slog.d(TAG_OOM_ADJ, "Did OOM ADJ in " + duration + "ms",
628 new RuntimeException("here").fillInStackTrace());
630 Slog.d(TAG_OOM_ADJ, "Did OOM ADJ in " + duration + "ms");
633 mService.mOomAdjProfiler.oomAdjEnded();
634 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
637 private final ComputeOomAdjWindowCallback mTmpComputeOomAdjWindowCallback =
638 new ComputeOomAdjWindowCallback();
640 /** These methods are called inline during computeOomAdjLocked(), on the same thread */
641 private final class ComputeOomAdjWindowCallback
642 implements WindowProcessController.ComputeOomAdjCallback {
646 boolean foregroundActivities;
651 int processStateCurTop;
653 void initialize(ProcessRecord app, int adj, boolean foregroundActivities,
654 int procState, int schedGroup, int appUid, int logUid, int processStateCurTop) {
657 this.foregroundActivities = foregroundActivities;
658 this.procState = procState;
659 this.schedGroup = schedGroup;
660 this.appUid = appUid;
661 this.logUid = logUid;
662 this.processStateCurTop = processStateCurTop;
666 public void onVisibleActivity() {
667 // App has a visible activity; only upgrade adjustment.
668 if (adj > ProcessList.VISIBLE_APP_ADJ) {
669 adj = ProcessList.VISIBLE_APP_ADJ;
670 app.adjType = "vis-activity";
671 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
672 reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to vis-activity: " + app);
675 if (procState > processStateCurTop) {
676 procState = processStateCurTop;
677 app.adjType = "vis-activity";
678 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
679 reportOomAdjMessageLocked(TAG_OOM_ADJ,
680 "Raise procstate to vis-activity (top): " + app);
683 if (schedGroup < ProcessList.SCHED_GROUP_DEFAULT) {
684 schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
688 foregroundActivities = true;
692 public void onPausedActivity() {
693 if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
694 adj = ProcessList.PERCEPTIBLE_APP_ADJ;
695 app.adjType = "pause-activity";
696 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
697 reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to pause-activity: " + app);
700 if (procState > processStateCurTop) {
701 procState = processStateCurTop;
702 app.adjType = "pause-activity";
703 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
704 reportOomAdjMessageLocked(TAG_OOM_ADJ,
705 "Raise procstate to pause-activity (top): " + app);
708 if (schedGroup < ProcessList.SCHED_GROUP_DEFAULT) {
709 schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
713 foregroundActivities = true;
717 public void onStoppingActivity(boolean finishing) {
718 if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
719 adj = ProcessList.PERCEPTIBLE_APP_ADJ;
720 app.adjType = "stop-activity";
721 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
722 reportOomAdjMessageLocked(TAG_OOM_ADJ,
723 "Raise adj to stop-activity: " + app);
727 // For the process state, we will at this point consider the process to be cached. It
728 // will be cached either as an activity or empty depending on whether the activity is
729 // finishing. We do this so that we can treat the process as cached for purposes of
730 // memory trimming (determining current memory level, trim command to send to process)
731 // since there can be an arbitrary number of stopping processes and they should soon all
732 // go into the cached state.
734 if (procState > PROCESS_STATE_LAST_ACTIVITY) {
735 procState = PROCESS_STATE_LAST_ACTIVITY;
736 app.adjType = "stop-activity";
737 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
738 reportOomAdjMessageLocked(TAG_OOM_ADJ,
739 "Raise procstate to stop-activity: " + app);
745 foregroundActivities = true;
749 public void onOtherActivity() {
750 if (procState > PROCESS_STATE_CACHED_ACTIVITY) {
751 procState = PROCESS_STATE_CACHED_ACTIVITY;
752 app.adjType = "cch-act";
753 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
754 reportOomAdjMessageLocked(TAG_OOM_ADJ,
755 "Raise procstate to cached activity: " + app);
761 private final boolean computeOomAdjLocked(ProcessRecord app, int cachedAdj,
762 ProcessRecord TOP_APP, boolean doingAll, long now, boolean cycleReEval) {
763 if (mAdjSeq == app.adjSeq) {
764 if (app.adjSeq == app.completedAdjSeq) {
765 // This adjustment has already been computed successfully.
768 // The process is being computed, so there is a cycle. We cannot
769 // rely on this process's state.
770 app.containsCycle = true;
776 if (app.thread == null) {
777 app.adjSeq = mAdjSeq;
778 app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_BACKGROUND);
779 app.setCurProcState(PROCESS_STATE_CACHED_EMPTY);
780 app.curAdj = ProcessList.CACHED_APP_MAX_ADJ;
781 app.setCurRawAdj(ProcessList.CACHED_APP_MAX_ADJ);
782 app.completedAdjSeq = app.adjSeq;
786 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
787 app.adjSource = null;
788 app.adjTarget = null;
792 final WindowProcessController wpc = app.getWindowProcessController();
793 final int appUid = app.info.uid;
794 final int logUid = mService.mCurOomAdjUid;
796 int prevAppAdj = app.curAdj;
797 int prevProcState = app.getCurProcState();
799 if (app.maxAdj <= ProcessList.FOREGROUND_APP_ADJ) {
800 // The max adjustment doesn't allow this app to be anything
801 // below foreground, so it is not worth doing work for it.
802 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
803 mService.reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making fixed: " + app);
805 app.adjType = "fixed";
806 app.adjSeq = mAdjSeq;
807 app.setCurRawAdj(app.maxAdj);
808 app.setHasForegroundActivities(false);
809 app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT);
810 app.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT);
811 // System processes can do UI, and when they do we want to have
812 // them trim their memory after the user leaves the UI. To
813 // facilitate this, here we need to determine whether or not it
814 // is currently showing UI.
815 app.systemNoUi = true;
816 if (app == TOP_APP) {
817 app.systemNoUi = false;
818 app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);
819 app.adjType = "pers-top-activity";
820 } else if (app.hasTopUi()) {
821 // sched group/proc state adjustment is below
822 app.systemNoUi = false;
823 app.adjType = "pers-top-ui";
824 } else if (wpc.hasVisibleActivities()) {
825 app.systemNoUi = false;
827 if (!app.systemNoUi) {
828 if (mService.mWakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE) {
829 // screen on, promote UI
830 app.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT_UI);
831 app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);
833 // screen off, restrict UI scheduling
834 app.setCurProcState(PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
835 app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_RESTRICTED);
838 app.setCurRawProcState(app.getCurProcState());
839 app.curAdj = app.maxAdj;
840 app.completedAdjSeq = app.adjSeq;
841 // if curAdj is less than prevAppAdj, then this process was promoted
842 return app.curAdj < prevAppAdj || app.getCurProcState() < prevProcState;
845 app.systemNoUi = false;
847 final int PROCESS_STATE_CUR_TOP = mService.mAtmInternal.getTopProcessState();
849 // Determine the importance of the process, starting with most
850 // important to least, and assign an appropriate OOM adjustment.
856 boolean foregroundActivities = false;
857 mTmpBroadcastQueue.clear();
858 if (PROCESS_STATE_CUR_TOP == PROCESS_STATE_TOP && app == TOP_APP) {
859 // The last app on the list is the foreground app.
860 adj = ProcessList.FOREGROUND_APP_ADJ;
861 schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
862 app.adjType = "top-activity";
863 foregroundActivities = true;
864 procState = PROCESS_STATE_CUR_TOP;
865 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
866 reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making top: " + app);
868 } else if (app.runningRemoteAnimation) {
869 adj = ProcessList.VISIBLE_APP_ADJ;
870 schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
871 app.adjType = "running-remote-anim";
872 procState = PROCESS_STATE_CUR_TOP;
873 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
874 reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making running remote anim: " + app);
876 } else if (app.getActiveInstrumentation() != null) {
877 // Don't want to kill running instrumentation.
878 adj = ProcessList.FOREGROUND_APP_ADJ;
879 schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
880 app.adjType = "instrumentation";
881 procState = PROCESS_STATE_FOREGROUND_SERVICE;
882 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
883 reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making instrumentation: " + app);
885 } else if (mService.isReceivingBroadcastLocked(app, mTmpBroadcastQueue)) {
886 // An app that is currently receiving a broadcast also
887 // counts as being in the foreground for OOM killer purposes.
888 // It's placed in a sched group based on the nature of the
889 // broadcast as reflected by which queue it's active in.
890 adj = ProcessList.FOREGROUND_APP_ADJ;
891 schedGroup = (mTmpBroadcastQueue.contains(mService.mFgBroadcastQueue))
892 ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
893 app.adjType = "broadcast";
894 procState = ActivityManager.PROCESS_STATE_RECEIVER;
895 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
896 reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making broadcast: " + app);
898 } else if (app.executingServices.size() > 0) {
899 // An app that is currently executing a service callback also
900 // counts as being in the foreground.
901 adj = ProcessList.FOREGROUND_APP_ADJ;
902 schedGroup = app.execServicesFg ?
903 ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
904 app.adjType = "exec-service";
905 procState = PROCESS_STATE_SERVICE;
906 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
907 reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making exec-service: " + app);
909 //Slog.i(TAG, "EXEC " + (app.execServicesFg ? "FG" : "BG") + ": " + app);
910 } else if (app == TOP_APP) {
911 adj = ProcessList.FOREGROUND_APP_ADJ;
912 schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
913 app.adjType = "top-sleeping";
914 foregroundActivities = true;
915 procState = PROCESS_STATE_CUR_TOP;
916 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
917 reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making top (sleeping): " + app);
920 // As far as we know the process is empty. We may change our mind later.
921 schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
922 // At this point we don't actually know the adjustment. Use the cached adj
923 // value that the caller wants us to.
925 procState = PROCESS_STATE_CACHED_EMPTY;
928 app.adjType = "cch-empty";
929 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
930 reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making empty: " + app);
934 // Examine all activities if not already foreground.
935 if (!foregroundActivities && wpc.hasActivities()) {
936 mTmpComputeOomAdjWindowCallback.initialize(app, adj, foregroundActivities, procState,
937 schedGroup, appUid, logUid, PROCESS_STATE_CUR_TOP);
938 final int minLayer = wpc.computeOomAdjFromActivities(
939 ProcessList.VISIBLE_APP_LAYER_MAX, mTmpComputeOomAdjWindowCallback);
941 adj = mTmpComputeOomAdjWindowCallback.adj;
942 foregroundActivities = mTmpComputeOomAdjWindowCallback.foregroundActivities;
943 procState = mTmpComputeOomAdjWindowCallback.procState;
944 schedGroup = mTmpComputeOomAdjWindowCallback.schedGroup;
946 if (adj == ProcessList.VISIBLE_APP_ADJ) {
951 if (procState > ActivityManager.PROCESS_STATE_CACHED_RECENT && app.hasRecentTasks()) {
952 procState = ActivityManager.PROCESS_STATE_CACHED_RECENT;
953 app.adjType = "cch-rec";
954 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
955 reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to cached recent: " + app);
959 if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
960 || procState > PROCESS_STATE_FOREGROUND_SERVICE_LOCATION) {
961 if (app.hasForegroundServices()) {
962 // The user is aware of this app, so make it visible.
963 adj = ProcessList.PERCEPTIBLE_APP_ADJ;
964 if (app.hasLocationForegroundServices()) {
965 procState = PROCESS_STATE_FOREGROUND_SERVICE_LOCATION;
966 app.adjType = "fg-service-location";
969 procState = PROCESS_STATE_FOREGROUND_SERVICE;
970 app.adjType = "fg-service";
973 schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
974 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
975 reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + app.adjType + ": "
978 } else if (app.hasOverlayUi()) {
979 // The process is display an overlay UI.
980 adj = ProcessList.PERCEPTIBLE_APP_ADJ;
981 procState = PROCESS_STATE_IMPORTANT_FOREGROUND;
983 app.adjType = "has-overlay-ui";
984 schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
985 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
986 reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to overlay ui: " + app);
991 // If the app was recently in the foreground and moved to a foreground service status,
992 // allow it to get a higher rank in memory for some time, compared to other foreground
993 // services so that it can finish performing any persistence/processing of in-memory state.
994 if (app.hasForegroundServices() && adj > ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ
995 && (app.lastTopTime + mConstants.TOP_TO_FGS_GRACE_DURATION > now
996 || app.setProcState <= PROCESS_STATE_TOP)) {
997 adj = ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ;
998 app.adjType = "fg-service-act";
999 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
1000 reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to recent fg: " + app);
1004 if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
1005 || procState > PROCESS_STATE_TRANSIENT_BACKGROUND) {
1006 if (app.forcingToImportant != null) {
1007 // This is currently used for toasts... they are not interactive, and
1008 // we don't want them to cause the app to become fully foreground (and
1009 // thus out of background check), so we yes the best background level we can.
1010 adj = ProcessList.PERCEPTIBLE_APP_ADJ;
1011 procState = PROCESS_STATE_TRANSIENT_BACKGROUND;
1013 app.adjType = "force-imp";
1014 app.adjSource = app.forcingToImportant;
1015 schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
1016 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
1017 reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to force imp: " + app);
1022 if (mService.mAtmInternal.isHeavyWeightProcess(app.getWindowProcessController())) {
1023 if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ) {
1024 // We don't want to kill the current heavy-weight process.
1025 adj = ProcessList.HEAVY_WEIGHT_APP_ADJ;
1026 schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
1028 app.adjType = "heavy";
1029 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
1030 reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to heavy: " + app);
1033 if (procState > ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
1034 procState = ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
1035 app.adjType = "heavy";
1036 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
1037 reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to heavy: " + app);
1042 if (wpc.isHomeProcess()) {
1043 if (adj > ProcessList.HOME_APP_ADJ) {
1044 // This process is hosting what we currently consider to be the
1045 // home app, so we don't want to let it go into the background.
1046 adj = ProcessList.HOME_APP_ADJ;
1047 schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
1049 app.adjType = "home";
1050 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
1051 reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to home: " + app);
1054 if (procState > ActivityManager.PROCESS_STATE_HOME) {
1055 procState = ActivityManager.PROCESS_STATE_HOME;
1056 app.adjType = "home";
1057 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
1058 reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to home: " + app);
1063 if (wpc.isPreviousProcess() && app.hasActivities()) {
1064 if (adj > ProcessList.PREVIOUS_APP_ADJ) {
1065 // This was the previous process that showed UI to the user.
1066 // We want to try to keep it around more aggressively, to give
1067 // a good experience around switching between two apps.
1068 adj = ProcessList.PREVIOUS_APP_ADJ;
1069 schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
1071 app.adjType = "previous";
1072 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
1073 reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to prev: " + app);
1076 if (procState > PROCESS_STATE_LAST_ACTIVITY) {
1077 procState = PROCESS_STATE_LAST_ACTIVITY;
1078 app.adjType = "previous";
1079 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
1080 reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to prev: " + app);
1085 if (false) Slog.i(TAG, "OOM " + app + ": initial adj=" + adj
1086 + " reason=" + app.adjType);
1088 // By default, we use the computed adjustment. It may be changed if
1089 // there are applications dependent on our services or providers, but
1090 // this gives us a baseline and makes sure we don't get into an
1091 // infinite recursion. If we're re-evaluating due to cycles, use the previously computed
1093 app.setCurRawAdj(!cycleReEval ? adj : Math.min(adj, app.getCurRawAdj()));
1094 app.setCurRawProcState(!cycleReEval
1096 : Math.min(procState, app.getCurRawProcState()));
1098 app.hasStartedServices = false;
1099 app.adjSeq = mAdjSeq;
1101 final BackupRecord backupTarget = mService.mBackupTargets.get(app.userId);
1102 if (backupTarget != null && app == backupTarget.app) {
1103 // If possible we want to avoid killing apps while they're being backed up
1104 if (adj > ProcessList.BACKUP_APP_ADJ) {
1105 if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "oom BACKUP_APP_ADJ for " + app);
1106 adj = ProcessList.BACKUP_APP_ADJ;
1107 if (procState > PROCESS_STATE_TRANSIENT_BACKGROUND) {
1108 procState = PROCESS_STATE_TRANSIENT_BACKGROUND;
1110 app.adjType = "backup";
1111 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
1112 reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to backup: " + app);
1116 if (procState > ActivityManager.PROCESS_STATE_BACKUP) {
1117 procState = ActivityManager.PROCESS_STATE_BACKUP;
1118 app.adjType = "backup";
1119 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
1120 reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to backup: " + app);
1125 for (int is = app.services.size() - 1;
1126 is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
1127 || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
1128 || procState > PROCESS_STATE_TOP);
1130 ServiceRecord s = app.services.valueAt(is);
1131 if (s.startRequested) {
1132 app.hasStartedServices = true;
1133 if (procState > PROCESS_STATE_SERVICE) {
1134 procState = PROCESS_STATE_SERVICE;
1135 app.adjType = "started-services";
1136 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
1137 reportOomAdjMessageLocked(TAG_OOM_ADJ,
1138 "Raise procstate to started service: " + app);
1141 if (app.hasShownUi && !wpc.isHomeProcess()) {
1142 // If this process has shown some UI, let it immediately
1143 // go to the LRU list because it may be pretty heavy with
1144 // UI stuff. We'll tag it with a label just to help
1145 // debug and understand what is going on.
1146 if (adj > ProcessList.SERVICE_ADJ) {
1147 app.adjType = "cch-started-ui-services";
1150 if (now < (s.lastActivity + mConstants.MAX_SERVICE_INACTIVITY)) {
1151 // This service has seen some activity within
1152 // recent memory, so we will keep its process ahead
1153 // of the background processes.
1154 if (adj > ProcessList.SERVICE_ADJ) {
1155 adj = ProcessList.SERVICE_ADJ;
1156 app.adjType = "started-services";
1157 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
1158 reportOomAdjMessageLocked(TAG_OOM_ADJ,
1159 "Raise adj to started service: " + app);
1164 // If we have let the service slide into the background
1165 // state, still have some text describing what it is doing
1166 // even though the service no longer has an impact.
1167 if (adj > ProcessList.SERVICE_ADJ) {
1168 app.adjType = "cch-started-services";
1173 ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections = s.getConnections();
1174 for (int conni = serviceConnections.size() - 1;
1175 conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
1176 || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
1177 || procState > PROCESS_STATE_TOP);
1179 ArrayList<ConnectionRecord> clist = serviceConnections.valueAt(conni);
1181 i < clist.size() && (adj > ProcessList.FOREGROUND_APP_ADJ
1182 || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
1183 || procState > PROCESS_STATE_TOP);
1185 // XXX should compute this based on the max of
1186 // all connected clients.
1187 ConnectionRecord cr = clist.get(i);
1188 if (cr.binding.client == app) {
1189 // Binding to oneself is not interesting.
1193 boolean trackedProcState = false;
1194 if ((cr.flags& Context.BIND_WAIVE_PRIORITY) == 0) {
1195 ProcessRecord client = cr.binding.client;
1196 computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now, cycleReEval);
1198 if (shouldSkipDueToCycle(app, client, procState, adj, cycleReEval)) {
1202 int clientAdj = client.getCurRawAdj();
1203 int clientProcState = client.getCurRawProcState();
1205 if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
1206 // If the other app is cached for any reason, for purposes here
1207 // we are going to consider it empty. The specific cached state
1208 // doesn't propagate except under certain conditions.
1209 clientProcState = PROCESS_STATE_CACHED_EMPTY;
1211 String adjType = null;
1212 if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
1213 // Not doing bind OOM management, so treat
1214 // this guy more like a started service.
1215 if (app.hasShownUi && !wpc.isHomeProcess()) {
1216 // If this process has shown some UI, let it immediately
1217 // go to the LRU list because it may be pretty heavy with
1218 // UI stuff. We'll tag it with a label just to help
1219 // debug and understand what is going on.
1220 if (adj > clientAdj) {
1221 adjType = "cch-bound-ui-services";
1225 clientProcState = procState;
1227 if (now >= (s.lastActivity
1228 + mConstants.MAX_SERVICE_INACTIVITY)) {
1229 // This service has not seen activity within
1230 // recent memory, so allow it to drop to the
1231 // LRU list if there is no other reason to keep
1232 // it around. We'll also tag it with a label just
1233 // to help debug and undertand what is going on.
1234 if (adj > clientAdj) {
1235 adjType = "cch-bound-services";
1241 if (adj > clientAdj) {
1242 // If this process has recently shown UI, and
1243 // the process that is binding to it is less
1244 // important than being visible, then we don't
1245 // care about the binding as much as we care
1246 // about letting this process get into the LRU
1247 // list to be killed and restarted if needed for
1249 if (app.hasShownUi && !wpc.isHomeProcess()
1250 && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
1251 if (adj >= ProcessList.CACHED_APP_MIN_ADJ) {
1252 adjType = "cch-bound-ui-services";
1256 if ((cr.flags&(Context.BIND_ABOVE_CLIENT
1257 |Context.BIND_IMPORTANT)) != 0) {
1258 if (clientAdj >= ProcessList.PERSISTENT_SERVICE_ADJ) {
1261 // make this service persistent
1262 newAdj = ProcessList.PERSISTENT_SERVICE_ADJ;
1263 schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
1264 procState = ActivityManager.PROCESS_STATE_PERSISTENT;
1265 cr.trackProcState(procState, mAdjSeq, now);
1266 trackedProcState = true;
1268 } else if ((cr.flags & Context.BIND_NOT_PERCEPTIBLE) != 0
1269 && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
1270 && adj > ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
1271 newAdj = ProcessList.PERCEPTIBLE_LOW_APP_ADJ;
1272 } else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0
1273 && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
1274 && adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
1275 newAdj = ProcessList.PERCEPTIBLE_APP_ADJ;
1276 } else if (clientAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
1279 if (adj > ProcessList.VISIBLE_APP_ADJ) {
1280 // TODO: Is this too limiting for apps bound from TOP?
1281 newAdj = Math.max(clientAdj, ProcessList.VISIBLE_APP_ADJ);
1286 if (!client.cached) {
1291 app.setCurRawAdj(adj);
1292 adjType = "service";
1296 if ((cr.flags & (Context.BIND_NOT_FOREGROUND
1297 | Context.BIND_IMPORTANT_BACKGROUND)) == 0) {
1298 // This will treat important bound services identically to
1299 // the top app, which may behave differently than generic
1301 final int curSchedGroup = client.getCurrentSchedulingGroup();
1302 if (curSchedGroup > schedGroup) {
1303 if ((cr.flags&Context.BIND_IMPORTANT) != 0) {
1304 schedGroup = curSchedGroup;
1306 schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
1309 if (clientProcState < PROCESS_STATE_TOP) {
1310 // Special handling for above-top states (persistent
1311 // processes). These should not bring the current process
1312 // into the top state, since they are not on top. Instead
1313 // give them the best bound state after that.
1314 final int bestState = cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)
1315 ? PROCESS_STATE_FOREGROUND_SERVICE_LOCATION
1316 : PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
1317 if ((cr.flags & Context.BIND_FOREGROUND_SERVICE) != 0) {
1318 clientProcState = bestState;
1319 } else if (mService.mWakefulness
1320 == PowerManagerInternal.WAKEFULNESS_AWAKE
1321 && (cr.flags & Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE)
1323 clientProcState = bestState;
1326 PROCESS_STATE_IMPORTANT_FOREGROUND;
1328 } else if (clientProcState == PROCESS_STATE_TOP) {
1329 if (cr.notHasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
1330 // Go at most to BOUND_TOP, unless requested to elevate
1331 // to client's state.
1332 clientProcState = PROCESS_STATE_BOUND_TOP;
1334 } else if (clientProcState
1335 <= PROCESS_STATE_FOREGROUND_SERVICE) {
1336 if (cr.notHasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
1337 clientProcState = PROCESS_STATE_FOREGROUND_SERVICE;
1340 } else if ((cr.flags & Context.BIND_IMPORTANT_BACKGROUND) == 0) {
1341 if (clientProcState <
1342 PROCESS_STATE_TRANSIENT_BACKGROUND) {
1344 PROCESS_STATE_TRANSIENT_BACKGROUND;
1347 if (clientProcState <
1348 PROCESS_STATE_IMPORTANT_BACKGROUND) {
1350 PROCESS_STATE_IMPORTANT_BACKGROUND;
1354 if (schedGroup < ProcessList.SCHED_GROUP_TOP_APP
1355 && (cr.flags & Context.BIND_SCHEDULE_LIKE_TOP_APP) != 0) {
1356 schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
1359 if (!trackedProcState) {
1360 cr.trackProcState(clientProcState, mAdjSeq, now);
1363 if (procState > clientProcState) {
1364 procState = clientProcState;
1365 app.setCurRawProcState(procState);
1366 if (adjType == null) {
1367 adjType = "service";
1370 if (procState < PROCESS_STATE_IMPORTANT_BACKGROUND
1371 && (cr.flags & Context.BIND_SHOWING_UI) != 0) {
1372 app.setPendingUiClean(true);
1374 if (adjType != null) {
1375 app.adjType = adjType;
1376 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
1377 .REASON_SERVICE_IN_USE;
1378 app.adjSource = cr.binding.client;
1379 app.adjSourceProcState = clientProcState;
1380 app.adjTarget = s.instanceName;
1381 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
1382 reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType
1383 + ": " + app + ", due to " + cr.binding.client
1384 + " adj=" + adj + " procState="
1385 + ProcessList.makeProcStateString(procState));
1389 if ((cr.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
1390 app.treatLikeActivity = true;
1392 final ActivityServiceConnectionsHolder a = cr.activity;
1393 if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
1394 if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ
1395 && a.isActivityVisible()) {
1396 adj = ProcessList.FOREGROUND_APP_ADJ;
1397 app.setCurRawAdj(adj);
1398 if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
1399 if ((cr.flags&Context.BIND_IMPORTANT) != 0) {
1400 schedGroup = ProcessList.SCHED_GROUP_TOP_APP_BOUND;
1402 schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
1406 app.adjType = "service";
1407 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
1408 .REASON_SERVICE_IN_USE;
1410 app.adjSourceProcState = procState;
1411 app.adjTarget = s.instanceName;
1412 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
1413 reportOomAdjMessageLocked(TAG_OOM_ADJ,
1414 "Raise to service w/activity: " + app);
1422 for (int provi = app.pubProviders.size() - 1;
1423 provi >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
1424 || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
1425 || procState > PROCESS_STATE_TOP);
1427 ContentProviderRecord cpr = app.pubProviders.valueAt(provi);
1428 for (int i = cpr.connections.size() - 1;
1429 i >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
1430 || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
1431 || procState > PROCESS_STATE_TOP);
1433 ContentProviderConnection conn = cpr.connections.get(i);
1434 ProcessRecord client = conn.client;
1435 if (client == app) {
1436 // Being our own client is not interesting.
1439 computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now, cycleReEval);
1441 if (shouldSkipDueToCycle(app, client, procState, adj, cycleReEval)) {
1445 int clientAdj = client.getCurRawAdj();
1446 int clientProcState = client.getCurRawProcState();
1448 if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
1449 // If the other app is cached for any reason, for purposes here
1450 // we are going to consider it empty.
1451 clientProcState = PROCESS_STATE_CACHED_EMPTY;
1453 String adjType = null;
1454 if (adj > clientAdj) {
1455 if (app.hasShownUi && !wpc.isHomeProcess()
1456 && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
1457 adjType = "cch-ui-provider";
1459 adj = clientAdj > ProcessList.FOREGROUND_APP_ADJ
1460 ? clientAdj : ProcessList.FOREGROUND_APP_ADJ;
1461 app.setCurRawAdj(adj);
1462 adjType = "provider";
1464 app.cached &= client.cached;
1467 if (clientProcState <= PROCESS_STATE_FOREGROUND_SERVICE) {
1468 if (adjType == null) {
1469 adjType = "provider";
1471 if (clientProcState == PROCESS_STATE_TOP) {
1472 clientProcState = PROCESS_STATE_BOUND_TOP;
1474 clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
1478 conn.trackProcState(clientProcState, mAdjSeq, now);
1479 if (procState > clientProcState) {
1480 procState = clientProcState;
1481 app.setCurRawProcState(procState);
1483 if (client.getCurrentSchedulingGroup() > schedGroup) {
1484 schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
1486 if (adjType != null) {
1487 app.adjType = adjType;
1488 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
1489 .REASON_PROVIDER_IN_USE;
1490 app.adjSource = client;
1491 app.adjSourceProcState = clientProcState;
1492 app.adjTarget = cpr.name;
1493 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
1494 reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType
1495 + ": " + app + ", due to " + client
1496 + " adj=" + adj + " procState="
1497 + ProcessList.makeProcStateString(procState));
1501 // If the provider has external (non-framework) process
1502 // dependencies, ensure that its adjustment is at least
1503 // FOREGROUND_APP_ADJ.
1504 if (cpr.hasExternalProcessHandles()) {
1505 if (adj > ProcessList.FOREGROUND_APP_ADJ) {
1506 adj = ProcessList.FOREGROUND_APP_ADJ;
1507 app.setCurRawAdj(adj);
1508 schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
1510 app.adjType = "ext-provider";
1511 app.adjTarget = cpr.name;
1512 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
1513 reportOomAdjMessageLocked(TAG_OOM_ADJ,
1514 "Raise adj to external provider: " + app);
1517 if (procState > PROCESS_STATE_IMPORTANT_FOREGROUND) {
1518 procState = PROCESS_STATE_IMPORTANT_FOREGROUND;
1519 app.setCurRawProcState(procState);
1520 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
1521 reportOomAdjMessageLocked(TAG_OOM_ADJ,
1522 "Raise procstate to external provider: " + app);
1528 if (app.lastProviderTime > 0 &&
1529 (app.lastProviderTime + mConstants.CONTENT_PROVIDER_RETAIN_TIME) > now) {
1530 if (adj > ProcessList.PREVIOUS_APP_ADJ) {
1531 adj = ProcessList.PREVIOUS_APP_ADJ;
1532 schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
1534 app.adjType = "recent-provider";
1535 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
1536 reportOomAdjMessageLocked(TAG_OOM_ADJ,
1537 "Raise adj to recent provider: " + app);
1540 if (procState > PROCESS_STATE_LAST_ACTIVITY) {
1541 procState = PROCESS_STATE_LAST_ACTIVITY;
1542 app.adjType = "recent-provider";
1543 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
1544 reportOomAdjMessageLocked(TAG_OOM_ADJ,
1545 "Raise procstate to recent provider: " + app);
1550 if (procState >= PROCESS_STATE_CACHED_EMPTY) {
1551 if (app.hasClientActivities()) {
1552 // This is a cached process, but with client activities. Mark it so.
1553 procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
1554 app.adjType = "cch-client-act";
1555 } else if (app.treatLikeActivity) {
1556 // This is a cached process, but somebody wants us to treat it like it has
1557 // an activity, okay!
1558 procState = PROCESS_STATE_CACHED_ACTIVITY;
1559 app.adjType = "cch-as-act";
1563 if (adj == ProcessList.SERVICE_ADJ) {
1565 app.serviceb = mNewNumAServiceProcs > (mNumServiceProcs/3);
1566 mNewNumServiceProcs++;
1567 //Slog.i(TAG, "ADJ " + app + " serviceb=" + app.serviceb);
1568 if (!app.serviceb) {
1569 // This service isn't far enough down on the LRU list to
1570 // normally be a B service, but if we are low on RAM and it
1571 // is large we want to force it down since we would prefer to
1572 // keep launcher over it.
1573 if (mService.mLastMemoryLevel > ProcessStats.ADJ_MEM_FACTOR_NORMAL
1574 && app.lastPss >= mProcessList.getCachedRestoreThresholdKb()) {
1575 app.serviceHighRam = true;
1576 app.serviceb = true;
1577 //Slog.i(TAG, "ADJ " + app + " high ram!");
1579 mNewNumAServiceProcs++;
1580 //Slog.i(TAG, "ADJ " + app + " not high ram!");
1583 app.serviceHighRam = false;
1587 adj = ProcessList.SERVICE_B_ADJ;
1591 app.setCurRawAdj(adj);
1593 //Slog.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
1594 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
1595 if (adj > app.maxAdj) {
1597 if (app.maxAdj <= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
1598 schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
1602 // Put bound foreground services in a special sched group for additional
1603 // restrictions on screen off
1604 if (procState >= PROCESS_STATE_BOUND_FOREGROUND_SERVICE
1605 && mService.mWakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE) {
1606 if (schedGroup > ProcessList.SCHED_GROUP_RESTRICTED) {
1607 schedGroup = ProcessList.SCHED_GROUP_RESTRICTED;
1611 // Do final modification to adj. Everything we do between here and applying
1612 // the final setAdj must be done in this function, because we will also use
1613 // it when computing the final cached adj later. Note that we don't need to
1614 // worry about this for max adj above, since max adj will always be used to
1615 // keep it out of the cached vaues.
1616 app.curAdj = app.modifyRawOomAdj(adj);
1617 app.setCurrentSchedulingGroup(schedGroup);
1618 app.setCurProcState(procState);
1619 app.setCurRawProcState(procState);
1620 app.setHasForegroundActivities(foregroundActivities);
1621 app.completedAdjSeq = mAdjSeq;
1623 // if curAdj or curProcState improved, then this process was promoted
1624 return app.curAdj < prevAppAdj || app.getCurProcState() < prevProcState;
1628 * Checks if for the given app and client, there's a cycle that should skip over the client
1629 * for now or use partial values to evaluate the effect of the client binding.
1632 * @param procState procstate evaluated so far for this app
1633 * @param adj oom_adj evaluated so far for this app
1634 * @param cycleReEval whether we're currently re-evaluating due to a cycle, and not the first
1636 * @return whether to skip using the client connection at this time
1638 private boolean shouldSkipDueToCycle(ProcessRecord app, ProcessRecord client,
1639 int procState, int adj, boolean cycleReEval) {
1640 if (client.containsCycle) {
1641 // We've detected a cycle. We should retry computeOomAdjLocked later in
1642 // case a later-checked connection from a client would raise its
1643 // priority legitimately.
1644 app.containsCycle = true;
1645 // If the client has not been completely evaluated, check if it's worth
1646 // using the partial values.
1647 if (client.completedAdjSeq < mAdjSeq) {
1649 // If the partial values are no better, skip until the next
1651 if (client.getCurRawProcState() >= procState
1652 && client.getCurRawAdj() >= adj) {
1655 // Else use the client's partial procstate and adj to adjust the
1656 // effect of the binding
1665 /** Inform the oomadj observer of changes to oomadj. Used by tests. */
1666 @GuardedBy("mService")
1667 void reportOomAdjMessageLocked(String tag, String msg) {
1669 if (mService.mCurOomAdjObserver != null) {
1670 mService.mUiHandler.obtainMessage(DISPATCH_OOM_ADJ_OBSERVER_MSG, msg).sendToTarget();
1674 /** Applies the computed oomadj, procstate and sched group values and freezes them in set* */
1675 @GuardedBy("mService")
1676 private final boolean applyOomAdjLocked(ProcessRecord app, boolean doingAll, long now,
1678 boolean success = true;
1680 if (app.getCurRawAdj() != app.setRawAdj) {
1681 app.setRawAdj = app.getCurRawAdj();
1686 // don't compact during bootup
1687 if (mAppCompact.useCompaction() && mService.mBooted) {
1688 // Cached and prev/home compaction
1689 if (app.curAdj != app.setAdj) {
1690 // Perform a minor compaction when a perceptible app becomes the prev/home app
1691 // Perform a major compaction when any app enters cached
1692 // reminder: here, setAdj is previous state, curAdj is upcoming state
1693 if (app.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ &&
1694 (app.curAdj == ProcessList.PREVIOUS_APP_ADJ ||
1695 app.curAdj == ProcessList.HOME_APP_ADJ)) {
1696 mAppCompact.compactAppSome(app);
1697 } else if ((app.setAdj < ProcessList.CACHED_APP_MIN_ADJ
1698 || app.setAdj > ProcessList.CACHED_APP_MAX_ADJ)
1699 && app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ
1700 && app.curAdj <= ProcessList.CACHED_APP_MAX_ADJ) {
1701 mAppCompact.compactAppFull(app);
1703 } else if (mService.mWakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE
1704 && app.setAdj < ProcessList.FOREGROUND_APP_ADJ
1705 // Because these can fire independent of oom_adj/procstate changes, we need
1706 // to throttle the actual dispatch of these requests in addition to the
1707 // processing of the requests. As a result, there is throttling both here
1708 // and in AppCompactor.
1709 && mAppCompact.shouldCompactPersistent(app, now)) {
1710 mAppCompact.compactAppPersistent(app);
1711 } else if (mService.mWakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE
1712 && app.getCurProcState()
1713 == ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
1714 && mAppCompact.shouldCompactBFGS(app, now)) {
1715 mAppCompact.compactAppBfgs(app);
1719 if (app.curAdj != app.setAdj) {
1720 ProcessList.setOomAdj(app.pid, app.uid, app.curAdj);
1721 if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mService.mCurOomAdjUid == app.info.uid) {
1722 String msg = "Set " + app.pid + " " + app.processName + " adj "
1723 + app.curAdj + ": " + app.adjType;
1724 reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
1726 app.setAdj = app.curAdj;
1727 app.verifiedAdj = ProcessList.INVALID_ADJ;
1730 final int curSchedGroup = app.getCurrentSchedulingGroup();
1731 if (app.setSchedGroup != curSchedGroup) {
1732 int oldSchedGroup = app.setSchedGroup;
1733 app.setSchedGroup = curSchedGroup;
1734 if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mService.mCurOomAdjUid == app.uid) {
1735 String msg = "Setting sched group of " + app.processName
1736 + " to " + curSchedGroup + ": " + app.adjType;
1737 reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
1739 if (app.waitingToKill != null && app.curReceivers.isEmpty()
1740 && app.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND) {
1741 app.kill(app.waitingToKill, true);
1745 switch (curSchedGroup) {
1746 case ProcessList.SCHED_GROUP_BACKGROUND:
1747 processGroup = THREAD_GROUP_BG_NONINTERACTIVE;
1749 case ProcessList.SCHED_GROUP_TOP_APP:
1750 case ProcessList.SCHED_GROUP_TOP_APP_BOUND:
1751 processGroup = THREAD_GROUP_TOP_APP;
1753 case ProcessList.SCHED_GROUP_RESTRICTED:
1754 processGroup = THREAD_GROUP_RESTRICTED;
1757 processGroup = THREAD_GROUP_DEFAULT;
1760 mProcessGroupHandler.sendMessage(mProcessGroupHandler.obtainMessage(
1761 0 /* unused */, app.pid, processGroup));
1763 if (curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
1764 // do nothing if we already switched to RT
1765 if (oldSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
1766 app.getWindowProcessController().onTopProcChanged();
1767 if (mService.mUseFifoUiScheduling) {
1768 // Switch UI pipeline for app to SCHED_FIFO
1769 app.savedPriority = Process.getThreadPriority(app.pid);
1770 mService.scheduleAsFifoPriority(app.pid, /* suppressLogs */true);
1771 if (app.renderThreadTid != 0) {
1772 mService.scheduleAsFifoPriority(app.renderThreadTid,
1773 /* suppressLogs */true);
1774 if (DEBUG_OOM_ADJ) {
1775 Slog.d("UI_FIFO", "Set RenderThread (TID " +
1776 app.renderThreadTid + ") to FIFO");
1779 if (DEBUG_OOM_ADJ) {
1780 Slog.d("UI_FIFO", "Not setting RenderThread TID");
1784 // Boost priority for top app UI and render threads
1785 setThreadPriority(app.pid, TOP_APP_PRIORITY_BOOST);
1786 if (app.renderThreadTid != 0) {
1788 setThreadPriority(app.renderThreadTid,
1789 TOP_APP_PRIORITY_BOOST);
1790 } catch (IllegalArgumentException e) {
1791 // thread died, ignore
1796 } else if (oldSchedGroup == ProcessList.SCHED_GROUP_TOP_APP &&
1797 curSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
1798 app.getWindowProcessController().onTopProcChanged();
1799 if (mService.mUseFifoUiScheduling) {
1801 // Reset UI pipeline to SCHED_OTHER
1802 setThreadScheduler(app.pid, SCHED_OTHER, 0);
1803 setThreadPriority(app.pid, app.savedPriority);
1804 if (app.renderThreadTid != 0) {
1805 setThreadScheduler(app.renderThreadTid,
1808 } catch (IllegalArgumentException e) {
1810 "Failed to set scheduling policy, thread does not exist:\n"
1812 } catch (SecurityException e) {
1813 Slog.w(TAG, "Failed to set scheduling policy, not allowed:\n" + e);
1816 // Reset priority for top app UI and render threads
1817 setThreadPriority(app.pid, 0);
1820 if (app.renderThreadTid != 0) {
1821 setThreadPriority(app.renderThreadTid, THREAD_PRIORITY_DISPLAY);
1824 } catch (Exception e) {
1826 Slog.w(TAG, "Failed setting thread priority of " + app.pid, e);
1831 if (app.repForegroundActivities != app.hasForegroundActivities()) {
1832 app.repForegroundActivities = app.hasForegroundActivities();
1833 changes |= ActivityManagerService.ProcessChangeItem.CHANGE_ACTIVITIES;
1835 if (app.getReportedProcState() != app.getCurProcState()) {
1836 app.setReportedProcState(app.getCurProcState());
1837 if (app.thread != null) {
1840 //RuntimeException h = new RuntimeException("here");
1841 Slog.i(TAG, "Sending new process state " + app.getReportedProcState()
1842 + " to " + app /*, h*/);
1844 app.thread.setProcessState(app.getReportedProcState());
1845 } catch (RemoteException e) {
1849 if (app.setProcState == PROCESS_STATE_NONEXISTENT
1850 || ProcessList.procStatesDifferForMem(app.getCurProcState(), app.setProcState)) {
1851 if (false && mService.mTestPssMode
1852 && app.setProcState >= 0 && app.lastStateTime <= (now-200)) {
1853 // Experimental code to more aggressively collect pss while
1854 // running test... the problem is that this tends to collect
1855 // the data right when a process is transitioning between process
1856 // states, which will tend to give noisy data.
1857 long start = SystemClock.uptimeMillis();
1858 long startTime = SystemClock.currentThreadTimeMillis();
1859 long pss = Debug.getPss(app.pid, mTmpLong, null);
1860 long endTime = SystemClock.currentThreadTimeMillis();
1861 mService.recordPssSampleLocked(app, app.getCurProcState(), pss,
1862 mTmpLong[0], mTmpLong[1], mTmpLong[2],
1863 ProcessStats.ADD_PSS_INTERNAL_SINGLE, endTime-startTime, now);
1864 mService.mPendingPssProcesses.remove(app);
1865 Slog.i(TAG, "Recorded pss for " + app + " state " + app.setProcState
1866 + " to " + app.getCurProcState() + ": "
1867 + (SystemClock.uptimeMillis()-start) + "ms");
1869 app.lastStateTime = now;
1870 app.nextPssTime = ProcessList.computeNextPssTime(app.getCurProcState(),
1871 app.procStateMemTracker, mService.mTestPssMode,
1872 mService.mAtmInternal.isSleeping(), now);
1873 if (DEBUG_PSS) Slog.d(TAG_PSS, "Process state change from "
1874 + ProcessList.makeProcStateString(app.setProcState) + " to "
1875 + ProcessList.makeProcStateString(app.getCurProcState()) + " next pss in "
1876 + (app.nextPssTime-now) + ": " + app);
1878 if (now > app.nextPssTime || (now > (app.lastPssTime+ProcessList.PSS_MAX_INTERVAL)
1879 && now > (app.lastStateTime+ProcessList.minTimeFromStateChange(
1880 mService.mTestPssMode)))) {
1881 if (mService.requestPssLocked(app, app.setProcState)) {
1882 app.nextPssTime = ProcessList.computeNextPssTime(app.getCurProcState(),
1883 app.procStateMemTracker, mService.mTestPssMode,
1884 mService.mAtmInternal.isSleeping(), now);
1886 } else if (false && DEBUG_PSS) {
1888 "Not requesting pss of " + app + ": next=" + (app.nextPssTime-now));
1891 if (app.setProcState != app.getCurProcState()) {
1892 if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mService.mCurOomAdjUid == app.uid) {
1893 String msg = "Proc state change of " + app.processName
1894 + " to " + ProcessList.makeProcStateString(app.getCurProcState())
1895 + " (" + app.getCurProcState() + ")" + ": " + app.adjType;
1896 reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
1898 boolean setImportant = app.setProcState < PROCESS_STATE_SERVICE;
1899 boolean curImportant = app.getCurProcState() < PROCESS_STATE_SERVICE;
1900 if (setImportant && !curImportant) {
1901 // This app is no longer something we consider important enough to allow to use
1902 // arbitrary amounts of battery power. Note its current CPU time to later know to
1903 // kill it if it is not behaving well.
1904 app.setWhenUnimportant(now);
1905 app.lastCpuTime = 0;
1907 // Inform UsageStats of important process state change
1908 // Must be called before updating setProcState
1909 maybeUpdateUsageStatsLocked(app, nowElapsed);
1911 maybeUpdateLastTopTime(app, now);
1913 app.setProcState = app.getCurProcState();
1914 if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) {
1915 app.notCachedSinceIdle = false;
1918 mService.setProcessTrackerStateLocked(app,
1919 mService.mProcessStats.getMemFactorLocked(), now);
1921 app.procStateChanged = true;
1923 } else if (app.reportedInteraction && (nowElapsed - app.getInteractionEventTime())
1924 > mConstants.USAGE_STATS_INTERACTION_INTERVAL) {
1925 // For apps that sit around for a long time in the interactive state, we need
1926 // to report this at least once a day so they don't go idle.
1927 maybeUpdateUsageStatsLocked(app, nowElapsed);
1928 } else if (!app.reportedInteraction && (nowElapsed - app.getFgInteractionTime())
1929 > mConstants.SERVICE_USAGE_INTERACTION_TIME) {
1930 // For foreground services that sit around for a long time but are not interacted with.
1931 maybeUpdateUsageStatsLocked(app, nowElapsed);
1935 if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
1936 "Changes in " + app + ": " + changes);
1937 ActivityManagerService.ProcessChangeItem item =
1938 mService.enqueueProcessChangeItemLocked(app.pid, app.info.uid);
1939 item.changes = changes;
1940 item.foregroundActivities = app.repForegroundActivities;
1941 if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
1942 "Item " + Integer.toHexString(System.identityHashCode(item))
1943 + " " + app.toShortString() + ": changes=" + item.changes
1944 + " foreground=" + item.foregroundActivities
1945 + " type=" + app.adjType + " source=" + app.adjSource
1946 + " target=" + app.adjTarget);
1952 // ONLY used for unit testing in OomAdjusterTests.java
1954 void maybeUpdateUsageStats(ProcessRecord app, long nowElapsed) {
1955 synchronized (mService) {
1956 maybeUpdateUsageStatsLocked(app, nowElapsed);
1960 @GuardedBy("mService")
1961 private void maybeUpdateUsageStatsLocked(ProcessRecord app, long nowElapsed) {
1962 if (DEBUG_USAGE_STATS) {
1963 Slog.d(TAG, "Checking proc [" + Arrays.toString(app.getPackageList())
1964 + "] state changes: old = " + app.setProcState + ", new = "
1965 + app.getCurProcState());
1967 if (mService.mUsageStatsService == null) {
1970 boolean isInteraction;
1971 // To avoid some abuse patterns, we are going to be careful about what we consider
1972 // to be an app interaction. Being the top activity doesn't count while the display
1973 // is sleeping, nor do short foreground services.
1974 if (app.getCurProcState() <= PROCESS_STATE_TOP
1975 || app.getCurProcState() == PROCESS_STATE_BOUND_TOP) {
1976 isInteraction = true;
1977 app.setFgInteractionTime(0);
1978 } else if (app.getCurProcState() <= PROCESS_STATE_FOREGROUND_SERVICE) {
1979 if (app.getFgInteractionTime() == 0) {
1980 app.setFgInteractionTime(nowElapsed);
1981 isInteraction = false;
1983 isInteraction = nowElapsed > app.getFgInteractionTime()
1984 + mConstants.SERVICE_USAGE_INTERACTION_TIME;
1988 app.getCurProcState() <= PROCESS_STATE_IMPORTANT_FOREGROUND;
1989 app.setFgInteractionTime(0);
1992 && (!app.reportedInteraction || (nowElapsed - app.getInteractionEventTime())
1993 > mConstants.USAGE_STATS_INTERACTION_INTERVAL)) {
1994 app.setInteractionEventTime(nowElapsed);
1995 String[] packages = app.getPackageList();
1996 if (packages != null) {
1997 for (int i = 0; i < packages.length; i++) {
1998 mService.mUsageStatsService.reportEvent(packages[i], app.userId,
1999 UsageEvents.Event.SYSTEM_INTERACTION);
2003 app.reportedInteraction = isInteraction;
2004 if (!isInteraction) {
2005 app.setInteractionEventTime(0);
2009 private void maybeUpdateLastTopTime(ProcessRecord app, long nowUptime) {
2010 if (app.setProcState <= PROCESS_STATE_TOP
2011 && app.getCurProcState() > PROCESS_STATE_TOP) {
2012 app.lastTopTime = nowUptime;
2017 * Look for recently inactive apps and mark them idle after a grace period. If idled, stop
2018 * any background services and inform listeners.
2020 @GuardedBy("mService")
2021 void idleUidsLocked() {
2022 final int N = mActiveUids.size();
2026 final long nowElapsed = SystemClock.elapsedRealtime();
2027 final long maxBgTime = nowElapsed - mConstants.BACKGROUND_SETTLE_TIME;
2029 if (mLocalPowerManager != null) {
2030 mLocalPowerManager.startUidChanges();
2032 for (int i = N - 1; i >= 0; i--) {
2033 final UidRecord uidRec = mActiveUids.valueAt(i);
2034 final long bgTime = uidRec.lastBackgroundTime;
2035 if (bgTime > 0 && !uidRec.idle) {
2036 if (bgTime <= maxBgTime) {
2037 EventLogTags.writeAmUidIdle(uidRec.uid);
2039 uidRec.setIdle = true;
2040 mService.doStopUidLocked(uidRec.uid, uidRec);
2042 if (nextTime == 0 || nextTime > bgTime) {
2048 if (mLocalPowerManager != null) {
2049 mLocalPowerManager.finishUidChanges();
2052 mService.mHandler.removeMessages(IDLE_UIDS_MSG);
2053 mService.mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG,
2054 nextTime + mConstants.BACKGROUND_SETTLE_TIME - nowElapsed);
2058 @GuardedBy("mService")
2059 final void setAppIdTempWhitelistStateLocked(int appId, boolean onWhitelist) {
2060 boolean changed = false;
2061 for (int i = mActiveUids.size() - 1; i >= 0; i--) {
2062 final UidRecord uidRec = mActiveUids.valueAt(i);
2063 if (UserHandle.getAppId(uidRec.uid) == appId && uidRec.curWhitelist != onWhitelist) {
2064 uidRec.curWhitelist = onWhitelist;
2069 updateOomAdjLocked(OOM_ADJ_REASON_WHITELIST);
2073 @GuardedBy("mService")
2074 final void setUidTempWhitelistStateLocked(int uid, boolean onWhitelist) {
2075 boolean changed = false;
2076 final UidRecord uidRec = mActiveUids.get(uid);
2077 if (uidRec != null && uidRec.curWhitelist != onWhitelist) {
2078 uidRec.curWhitelist = onWhitelist;
2079 updateOomAdjLocked(OOM_ADJ_REASON_WHITELIST);
2083 @GuardedBy("mService")
2084 void dumpProcessListVariablesLocked(ProtoOutputStream proto) {
2085 proto.write(ActivityManagerServiceDumpProcessesProto.ADJ_SEQ, mAdjSeq);
2086 proto.write(ActivityManagerServiceDumpProcessesProto.LRU_SEQ, mProcessList.mLruSeq);
2087 proto.write(ActivityManagerServiceDumpProcessesProto.NUM_NON_CACHED_PROCS,
2088 mNumNonCachedProcs);
2089 proto.write(ActivityManagerServiceDumpProcessesProto.NUM_SERVICE_PROCS, mNumServiceProcs);
2090 proto.write(ActivityManagerServiceDumpProcessesProto.NEW_NUM_SERVICE_PROCS,
2091 mNewNumServiceProcs);
2095 @GuardedBy("mService")
2096 void dumpSequenceNumbersLocked(PrintWriter pw) {
2097 pw.println(" mAdjSeq=" + mAdjSeq + " mLruSeq=" + mProcessList.mLruSeq);
2100 @GuardedBy("mService")
2101 void dumpProcCountsLocked(PrintWriter pw) {
2102 pw.println(" mNumNonCachedProcs=" + mNumNonCachedProcs
2103 + " (" + mProcessList.getLruSizeLocked() + " total)"
2104 + " mNumCachedHiddenProcs=" + mNumCachedHiddenProcs
2105 + " mNumServiceProcs=" + mNumServiceProcs
2106 + " mNewNumServiceProcs=" + mNewNumServiceProcs);
2109 @GuardedBy("mService")
2110 void dumpAppCompactorSettings(PrintWriter pw) {
2111 mAppCompact.dump(pw);