• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 
17 package com.android.server.am;
18 
19 import static android.app.ActivityManager.PROCESS_CAPABILITY_BFSL;
20 import static android.app.ActivityManager.PROCESS_STATE_BACKUP;
21 import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
22 import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
23 import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
24 import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
25 import static android.app.ActivityManager.PROCESS_STATE_CACHED_EMPTY;
26 import static android.app.ActivityManager.PROCESS_STATE_CACHED_RECENT;
27 import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
28 import static android.app.ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
29 import static android.app.ActivityManager.PROCESS_STATE_HOME;
30 import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
31 import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
32 import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
33 import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT;
34 import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI;
35 import static android.app.ActivityManager.PROCESS_STATE_RECEIVER;
36 import static android.app.ActivityManager.PROCESS_STATE_SERVICE;
37 import static android.app.ActivityManager.PROCESS_STATE_TOP;
38 import static android.app.ActivityManager.PROCESS_STATE_TOP_SLEEPING;
39 import static android.app.ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
40 import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
41 
42 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
43 import static com.android.server.am.ActivityManagerService.TAG_UID_OBSERVERS;
44 import static com.android.server.am.ProcessList.BACKUP_APP_ADJ;
45 import static com.android.server.am.ProcessList.CACHED_APP_MIN_ADJ;
46 import static com.android.server.am.ProcessList.FOREGROUND_APP_ADJ;
47 import static com.android.server.am.ProcessList.HEAVY_WEIGHT_APP_ADJ;
48 import static com.android.server.am.ProcessList.HOME_APP_ADJ;
49 import static com.android.server.am.ProcessList.NATIVE_ADJ;
50 import static com.android.server.am.ProcessList.PERCEPTIBLE_APP_ADJ;
51 import static com.android.server.am.ProcessList.PERCEPTIBLE_LOW_APP_ADJ;
52 import static com.android.server.am.ProcessList.PERCEPTIBLE_MEDIUM_APP_ADJ;
53 import static com.android.server.am.ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ;
54 import static com.android.server.am.ProcessList.PERSISTENT_PROC_ADJ;
55 import static com.android.server.am.ProcessList.PERSISTENT_SERVICE_ADJ;
56 import static com.android.server.am.ProcessList.PREVIOUS_APP_ADJ;
57 import static com.android.server.am.ProcessList.PREVIOUS_APP_MAX_ADJ;
58 import static com.android.server.am.ProcessList.SCHED_GROUP_BACKGROUND;
59 import static com.android.server.am.ProcessList.SERVICE_ADJ;
60 import static com.android.server.am.ProcessList.SERVICE_B_ADJ;
61 import static com.android.server.am.ProcessList.SYSTEM_ADJ;
62 import static com.android.server.am.ProcessList.UNKNOWN_ADJ;
63 import static com.android.server.am.ProcessList.VISIBLE_APP_ADJ;
64 
65 import android.annotation.IntDef;
66 import android.annotation.NonNull;
67 import android.annotation.Nullable;
68 import android.app.ActivityManager;
69 import android.app.ActivityManagerInternal.OomAdjReason;
70 import android.content.pm.ServiceInfo;
71 import android.os.IBinder;
72 import android.os.Trace;
73 import android.util.ArrayMap;
74 import android.util.ArraySet;
75 import android.util.Slog;
76 
77 import com.android.internal.annotations.GuardedBy;
78 import com.android.internal.annotations.VisibleForTesting;
79 import com.android.server.ServiceThread;
80 
81 import java.lang.annotation.Retention;
82 import java.lang.annotation.RetentionPolicy;
83 import java.util.ArrayList;
84 import java.util.Arrays;
85 import java.util.function.BiConsumer;
86 import java.util.function.Consumer;
87 import java.util.function.ToIntFunction;
88 
89 /**
90  * A modern implementation of the oom adjuster.
91  */
92 public class OomAdjusterModernImpl extends OomAdjuster {
93     static final String TAG = "OomAdjusterModernImpl";
94 
95     // The ADJ_SLOT_INVALID is NOT an actual slot.
96     static final int ADJ_SLOT_INVALID = -1;
97     static final int ADJ_SLOT_NATIVE = 0;
98     static final int ADJ_SLOT_SYSTEM = 1;
99     static final int ADJ_SLOT_PERSISTENT_PROC = 2;
100     static final int ADJ_SLOT_PERSISTENT_SERVICE = 3;
101     static final int ADJ_SLOT_FOREGROUND_APP = 4;
102     static final int ADJ_SLOT_PERCEPTIBLE_RECENT_FOREGROUND_APP = 5;
103     static final int ADJ_SLOT_VISIBLE_APP = 6;
104     static final int ADJ_SLOT_PERCEPTIBLE_APP = 7;
105     static final int ADJ_SLOT_PERCEPTIBLE_MEDIUM_APP = 8;
106     static final int ADJ_SLOT_PERCEPTIBLE_LOW_APP = 9;
107     static final int ADJ_SLOT_BACKUP_APP = 10;
108     static final int ADJ_SLOT_HEAVY_WEIGHT_APP = 11;
109     static final int ADJ_SLOT_SERVICE = 12;
110     static final int ADJ_SLOT_HOME_APP = 13;
111     static final int ADJ_SLOT_PREVIOUS_APP = 14;
112     static final int ADJ_SLOT_SERVICE_B = 15;
113     static final int ADJ_SLOT_CACHED_APP = 16;
114     static final int ADJ_SLOT_UNKNOWN = 17;
115 
116     @IntDef(prefix = { "ADJ_SLOT_" }, value = {
117         ADJ_SLOT_INVALID,
118         ADJ_SLOT_NATIVE,
119         ADJ_SLOT_SYSTEM,
120         ADJ_SLOT_PERSISTENT_PROC,
121         ADJ_SLOT_PERSISTENT_SERVICE,
122         ADJ_SLOT_FOREGROUND_APP,
123         ADJ_SLOT_PERCEPTIBLE_RECENT_FOREGROUND_APP,
124         ADJ_SLOT_VISIBLE_APP,
125         ADJ_SLOT_PERCEPTIBLE_APP,
126         ADJ_SLOT_PERCEPTIBLE_MEDIUM_APP,
127         ADJ_SLOT_PERCEPTIBLE_LOW_APP,
128         ADJ_SLOT_BACKUP_APP,
129         ADJ_SLOT_HEAVY_WEIGHT_APP,
130         ADJ_SLOT_SERVICE,
131         ADJ_SLOT_HOME_APP,
132         ADJ_SLOT_PREVIOUS_APP,
133         ADJ_SLOT_SERVICE_B,
134         ADJ_SLOT_CACHED_APP,
135         ADJ_SLOT_UNKNOWN,
136     })
137     @Retention(RetentionPolicy.SOURCE)
138     @interface AdjSlot{}
139 
140     static final int[] ADJ_SLOT_VALUES = new int[] {
141         NATIVE_ADJ,
142         SYSTEM_ADJ,
143         PERSISTENT_PROC_ADJ,
144         PERSISTENT_SERVICE_ADJ,
145         FOREGROUND_APP_ADJ,
146         PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ,
147         VISIBLE_APP_ADJ,
148         PERCEPTIBLE_APP_ADJ,
149         PERCEPTIBLE_MEDIUM_APP_ADJ,
150         PERCEPTIBLE_LOW_APP_ADJ,
151         BACKUP_APP_ADJ,
152         HEAVY_WEIGHT_APP_ADJ,
153         SERVICE_ADJ,
154         HOME_APP_ADJ,
155         PREVIOUS_APP_ADJ,
156         SERVICE_B_ADJ,
157         CACHED_APP_MIN_ADJ,
158         UNKNOWN_ADJ,
159     };
160 
161     /**
162      * Note: Always use the raw adj to call this API.
163      */
adjToSlot(int adj)164     static @AdjSlot int adjToSlot(int adj) {
165         if (adj >= ADJ_SLOT_VALUES[0] && adj <= ADJ_SLOT_VALUES[ADJ_SLOT_VALUES.length - 1]) {
166             // Conduct a binary search, in most of the cases it'll get a hit.
167             final int index = Arrays.binarySearch(ADJ_SLOT_VALUES, adj);
168             if (index >= 0) {
169                 return index;
170             }
171             // If not found, the returned index above should be (-(insertion point) - 1),
172             // let's return the first slot that's less than the adj value.
173             return -(index + 1) - 1;
174         }
175         return ADJ_SLOT_VALUES.length - 1;
176     }
177 
178     static final int[] PROC_STATE_SLOTS = new int[] {
179         PROCESS_STATE_PERSISTENT, // 0
180         PROCESS_STATE_PERSISTENT_UI,
181         PROCESS_STATE_TOP,
182         PROCESS_STATE_BOUND_TOP,
183         PROCESS_STATE_FOREGROUND_SERVICE,
184         PROCESS_STATE_BOUND_FOREGROUND_SERVICE,
185         PROCESS_STATE_IMPORTANT_FOREGROUND,
186         PROCESS_STATE_IMPORTANT_BACKGROUND,
187         PROCESS_STATE_TRANSIENT_BACKGROUND,
188         PROCESS_STATE_BACKUP,
189         PROCESS_STATE_SERVICE,
190         PROCESS_STATE_RECEIVER,
191         PROCESS_STATE_TOP_SLEEPING,
192         PROCESS_STATE_HEAVY_WEIGHT,
193         PROCESS_STATE_HOME,
194         PROCESS_STATE_LAST_ACTIVITY,
195         PROCESS_STATE_CACHED_ACTIVITY,
196         PROCESS_STATE_CACHED_ACTIVITY_CLIENT,
197         PROCESS_STATE_CACHED_RECENT,
198         PROCESS_STATE_CACHED_EMPTY,
199         PROCESS_STATE_UNKNOWN, // -1
200     };
201 
processStateToSlot(@ctivityManager.ProcessState int state)202     static int processStateToSlot(@ActivityManager.ProcessState int state) {
203         if (state >= PROCESS_STATE_PERSISTENT && state <= PROCESS_STATE_CACHED_EMPTY) {
204             return state;
205         }
206         return PROC_STATE_SLOTS.length - 1;
207     }
208 
209     /**
210      * A container node in the {@link LinkedProcessRecordList},
211      * holding the references to {@link ProcessRecord}.
212      */
213     static class ProcessRecordNode {
214         static final int NODE_TYPE_PROC_STATE = 0;
215         static final int NODE_TYPE_ADJ = 1;
216 
217         @IntDef(prefix = { "NODE_TYPE_" }, value = {
218             NODE_TYPE_PROC_STATE,
219             NODE_TYPE_ADJ,
220         })
221         @Retention(RetentionPolicy.SOURCE)
222         @interface NodeType {}
223 
224         static final int NUM_NODE_TYPE = NODE_TYPE_ADJ + 1;
225 
226         @Nullable ProcessRecordNode mPrev;
227         @Nullable ProcessRecordNode mNext;
228         final @Nullable ProcessRecord mApp;
229 
ProcessRecordNode(@ullable ProcessRecord app)230         ProcessRecordNode(@Nullable ProcessRecord app) {
231             mApp = app;
232         }
233 
unlink()234         void unlink() {
235             if (mPrev != null) {
236                 mPrev.mNext = mNext;
237             }
238             if (mNext != null) {
239                 mNext.mPrev = mPrev;
240             }
241             mPrev = mNext = null;
242         }
243 
isLinked()244         boolean isLinked() {
245             return mPrev != null && mNext != null;
246         }
247 
248         @Override
toString()249         public String toString() {
250             final StringBuilder sb = new StringBuilder();
251             sb.append("ProcessRecordNode{");
252             sb.append(Integer.toHexString(System.identityHashCode(this)));
253             sb.append(' ');
254             sb.append(mApp);
255             sb.append(' ');
256             sb.append(mApp != null ? mApp.mState.getCurProcState() : PROCESS_STATE_UNKNOWN);
257             sb.append(' ');
258             sb.append(mApp != null ? mApp.mState.getCurAdj() : UNKNOWN_ADJ);
259             sb.append(' ');
260             sb.append(Integer.toHexString(System.identityHashCode(mPrev)));
261             sb.append(' ');
262             sb.append(Integer.toHexString(System.identityHashCode(mNext)));
263             sb.append('}');
264             return sb.toString();
265         }
266     }
267 
268     private class ProcessRecordNodes {
269         private final @ProcessRecordNode.NodeType int mType;
270 
271         private final LinkedProcessRecordList[] mProcessRecordNodes;
272         // The last node besides the tail.
273         private final ProcessRecordNode[] mLastNode;
274 
275         private final ToIntFunction<ProcessRecord> mSlotFunction;
276         // Cache of the most important slot with a node in it.
277         private int mFirstPopulatedSlot = 0;
278 
ProcessRecordNodes(@rocessRecordNode.NodeType int type, int size)279         ProcessRecordNodes(@ProcessRecordNode.NodeType int type, int size) {
280             mType = type;
281             final ToIntFunction<ProcessRecord> valueFunction;
282             switch (mType) {
283                 case ProcessRecordNode.NODE_TYPE_PROC_STATE:
284                     valueFunction = (proc) -> proc.mState.getCurProcState();
285                     mSlotFunction = (proc) -> processStateToSlot(proc.mState.getCurProcState());
286                     break;
287                 case ProcessRecordNode.NODE_TYPE_ADJ:
288                     valueFunction = (proc) -> proc.mState.getCurRawAdj();
289                     mSlotFunction = (proc) -> adjToSlot(proc.mState.getCurRawAdj());
290                     break;
291                 default:
292                     valueFunction = (proc) -> 0;
293                     mSlotFunction = (proc) -> 0;
294                     break;
295             }
296 
297             mProcessRecordNodes = new LinkedProcessRecordList[size];
298             for (int i = 0; i < size; i++) {
299                 mProcessRecordNodes[i] = new LinkedProcessRecordList(valueFunction);
300             }
301             mLastNode = new ProcessRecordNode[size];
302             resetLastNodes();
303         }
304 
size()305         int size() {
306             return mProcessRecordNodes.length;
307         }
308 
309         @VisibleForTesting
reset()310         void reset() {
311             for (int i = 0; i < mProcessRecordNodes.length; i++) {
312                 mProcessRecordNodes[i].reset();
313                 setLastNodeToHead(i);
314             }
315         }
316 
resetLastNodes()317         void resetLastNodes() {
318             if (Flags.simplifyProcessTraversal()) {
319                 // Last nodes are no longer used. Just reset instead.
320                 reset();
321                 return;
322             }
323             for (int i = 0; i < mProcessRecordNodes.length; i++) {
324                 mLastNode[i] = mProcessRecordNodes[i].getLastNodeBeforeTail();
325             }
326         }
327 
setLastNodeToHead(int slot)328         void setLastNodeToHead(int slot) {
329             mLastNode[slot] = mProcessRecordNodes[slot].HEAD;
330         }
331 
forEachNewNode(int slot, @NonNull Consumer<OomAdjusterArgs> callback)332         void forEachNewNode(int slot, @NonNull Consumer<OomAdjusterArgs> callback) {
333             ProcessRecordNode node = mLastNode[slot].mNext;
334             final ProcessRecordNode tail = mProcessRecordNodes[slot].TAIL;
335             while (node != null && node != tail) {
336                 mTmpOomAdjusterArgs.mApp = node.mApp;
337                 if (node.mApp == null) {
338                     // TODO(b/336178916) - Temporary logging for root causing b/336178916.
339                     StringBuilder sb = new StringBuilder();
340                     sb.append("Iterating null process during OomAdjuster traversal!!!\n");
341                     sb.append("Type:");
342                     switch (mType) {
343                         case ProcessRecordNode.NODE_TYPE_PROC_STATE -> sb.append(
344                                 "NODE_TYPE_PROC_STATE");
345                         case ProcessRecordNode.NODE_TYPE_ADJ -> sb.append("NODE_TYPE_ADJ");
346                         default -> sb.append("UNKNOWN");
347                     }
348                     sb.append(", Slot:");
349                     sb.append(slot);
350                     sb.append("\nLAST:");
351                     ProcessRecordNode last = mLastNode[slot];
352                     if (last.mApp == null) {
353                         sb.append("null");
354                     } else {
355                         sb.append(last);
356                         sb.append("\nSetProcState:");
357                         sb.append(last.mApp.getSetProcState());
358                         sb.append(", CurProcState:");
359                         sb.append(last.mApp.mState.getCurProcState());
360                         sb.append(", SetAdj:");
361                         sb.append(last.mApp.getSetAdj());
362                         sb.append(", CurRawAdj:");
363                         sb.append(last.mApp.mState.getCurRawAdj());
364                     }
365                     Slog.wtfStack(TAG, sb.toString());
366                 }
367                 // Save the next before calling callback, since that may change the node.mNext.
368                 final ProcessRecordNode next = node.mNext;
369                 if (mTmpOomAdjusterArgs.mApp != null) {
370                     callback.accept(mTmpOomAdjusterArgs);
371                 }
372                 // There are couple of cases:
373                 // a) The current node is moved to another slot
374                 //    - for this case, we'd need to keep using the "next" node.
375                 // b) There are one or more new nodes being appended to this slot
376                 //    - for this case, we'd need to make sure we scan the new node too.
377                 // Based on the assumption that case a) is only possible with
378                 // the computeInitialOomAdjLSP(), where the movings are for single node only,
379                 // we may safely assume that, if the "next" used to be the "tail" here, and it's
380                 // now a new tail somewhere else, that's case a); otherwise, it's case b);
381                 node = next == tail && node.mNext != null && node.mNext.mNext != null
382                         ? node.mNext : next;
383             }
384         }
385 
poll()386         ProcessRecord poll() {
387             ProcessRecordNode node = null;
388             final int size = mProcessRecordNodes.length;
389             // Find the next node.
390             while (node == null && mFirstPopulatedSlot < size) {
391                 node = mProcessRecordNodes[mFirstPopulatedSlot].poll();
392                 if (node == null) {
393                     // This slot is now empty, move on to the next.
394                     mFirstPopulatedSlot++;
395                 }
396             }
397             if (node == null) return null;
398             return node.mApp;
399         }
400 
offer(ProcessRecord proc)401         void offer(ProcessRecord proc) {
402             ProcessRecordNode node = proc.mLinkedNodes[mType];
403             // Find which slot to add the node to.
404             final int newSlot = mSlotFunction.applyAsInt(proc);
405             if (newSlot < mFirstPopulatedSlot) {
406                 // node is being added to a more important slot.
407                 mFirstPopulatedSlot = newSlot;
408             }
409             node.unlink();
410             mProcessRecordNodes[newSlot].offer(node);
411         }
412 
getNumberOfSlots()413         int getNumberOfSlots() {
414             return mProcessRecordNodes.length;
415         }
416 
moveAppTo(@onNull ProcessRecord app, int prevSlot, int newSlot)417         void moveAppTo(@NonNull ProcessRecord app, int prevSlot, int newSlot) {
418             final ProcessRecordNode node = app.mLinkedNodes[mType];
419             if (prevSlot != ADJ_SLOT_INVALID) {
420                 if (mLastNode[prevSlot] == node) {
421                     mLastNode[prevSlot] = node.mPrev;
422                 }
423             }
424             // node will be firstly unlinked in the append.
425             append(node, newSlot);
426         }
427 
moveAllNodesTo(int fromSlot, int toSlot)428         void moveAllNodesTo(int fromSlot, int toSlot) {
429             final LinkedProcessRecordList fromList = mProcessRecordNodes[fromSlot];
430             final LinkedProcessRecordList toList = mProcessRecordNodes[toSlot];
431             if (fromSlot != toSlot && fromList.HEAD.mNext != fromList.TAIL) {
432                 fromList.moveTo(toList);
433                 mLastNode[fromSlot] = fromList.getLastNodeBeforeTail();
434             }
435         }
436 
moveAppToTail(ProcessRecord app)437         void moveAppToTail(ProcessRecord app) {
438             final ProcessRecordNode node = app.mLinkedNodes[mType];
439             int slot;
440             switch (mType) {
441                 case ProcessRecordNode.NODE_TYPE_PROC_STATE:
442                     slot = processStateToSlot(app.mState.getCurProcState());
443                     if (mLastNode[slot] == node) {
444                         mLastNode[slot] = node.mPrev;
445                     }
446                     mProcessRecordNodes[slot].moveNodeToTail(node);
447                     break;
448                 case ProcessRecordNode.NODE_TYPE_ADJ:
449                     slot = adjToSlot(app.mState.getCurRawAdj());
450                     if (mLastNode[slot] == node) {
451                         mLastNode[slot] = node.mPrev;
452                     }
453                     mProcessRecordNodes[slot].moveNodeToTail(node);
454                     break;
455                 default:
456                     return;
457             }
458 
459         }
460 
reset(int slot)461         void reset(int slot) {
462             mProcessRecordNodes[slot].reset();
463         }
464 
unlink(@onNull ProcessRecord app)465         void unlink(@NonNull ProcessRecord app) {
466             final ProcessRecordNode node = app.mLinkedNodes[mType];
467             final int slot = getCurrentSlot(app);
468             if (slot != ADJ_SLOT_INVALID) {
469                 if (mLastNode[slot] == node) {
470                     mLastNode[slot] = node.mPrev;
471                 }
472             }
473             node.unlink();
474         }
475 
append(@onNull ProcessRecord app)476         void append(@NonNull ProcessRecord app) {
477             append(app, getCurrentSlot(app));
478         }
479 
append(@onNull ProcessRecord app, int targetSlot)480         void append(@NonNull ProcessRecord app, int targetSlot) {
481             append(app.mLinkedNodes[mType], targetSlot);
482         }
483 
append(@onNull ProcessRecordNode node, int targetSlot)484         void append(@NonNull ProcessRecordNode node, int targetSlot) {
485             node.unlink();
486             mProcessRecordNodes[targetSlot].append(node);
487         }
488 
getCurrentSlot(@onNull ProcessRecord app)489         private int getCurrentSlot(@NonNull ProcessRecord app) {
490             switch (mType) {
491                 case ProcessRecordNode.NODE_TYPE_PROC_STATE:
492                     return processStateToSlot(app.mState.getCurProcState());
493                 case ProcessRecordNode.NODE_TYPE_ADJ:
494                     return adjToSlot(app.mState.getCurRawAdj());
495             }
496             return ADJ_SLOT_INVALID;
497         }
498 
toString(int slot, int logUid)499         String toString(int slot, int logUid) {
500             return "lastNode=" + mLastNode[slot] + " " + mProcessRecordNodes[slot].toString(logUid);
501         }
502 
503         /**
504          * A simple version of {@link java.util.LinkedList}, as here we don't allocate new node
505          * while adding an object to it.
506          */
507         private static class LinkedProcessRecordList {
508             // Sentinel head/tail, to make bookkeeping work easier.
509             final ProcessRecordNode HEAD = new ProcessRecordNode(null);
510             final ProcessRecordNode TAIL = new ProcessRecordNode(null);
511             final ToIntFunction<ProcessRecord> mValueFunction;
512 
LinkedProcessRecordList(ToIntFunction<ProcessRecord> valueFunction)513             LinkedProcessRecordList(ToIntFunction<ProcessRecord> valueFunction) {
514                 HEAD.mNext = TAIL;
515                 TAIL.mPrev = HEAD;
516                 mValueFunction = valueFunction;
517             }
518 
poll()519             ProcessRecordNode poll() {
520                 final ProcessRecordNode next = HEAD.mNext;
521                 if (next == TAIL) return null;
522                 next.unlink();
523                 return next;
524             }
525 
offer(@onNull ProcessRecordNode node)526             void offer(@NonNull ProcessRecordNode node) {
527                 final int newValue = mValueFunction.applyAsInt(node.mApp);
528 
529                 // Find the last node with less than or equal value to the new node.
530                 ProcessRecordNode curNode = TAIL.mPrev;
531                 while (curNode != HEAD && mValueFunction.applyAsInt(curNode.mApp) > newValue) {
532                     curNode = curNode.mPrev;
533                 }
534 
535                 // Insert the new node after the found node.
536                 node.mPrev = curNode;
537                 node.mNext = curNode.mNext;
538                 curNode.mNext.mPrev = node;
539                 curNode.mNext = node;
540             }
541 
append(@onNull ProcessRecordNode node)542             void append(@NonNull ProcessRecordNode node) {
543                 node.mNext = TAIL;
544                 node.mPrev = TAIL.mPrev;
545                 TAIL.mPrev.mNext = node;
546                 TAIL.mPrev = node;
547             }
548 
moveTo(@onNull LinkedProcessRecordList toList)549             void moveTo(@NonNull LinkedProcessRecordList toList) {
550                 if (HEAD.mNext != TAIL) {
551                     toList.TAIL.mPrev.mNext = HEAD.mNext;
552                     HEAD.mNext.mPrev = toList.TAIL.mPrev;
553                     toList.TAIL.mPrev = TAIL.mPrev;
554                     TAIL.mPrev.mNext = toList.TAIL;
555                     HEAD.mNext = TAIL;
556                     TAIL.mPrev = HEAD;
557                 }
558             }
559 
moveNodeToTail(@onNull ProcessRecordNode node)560             void moveNodeToTail(@NonNull ProcessRecordNode node) {
561                 node.unlink();
562                 append(node);
563             }
564 
getLastNodeBeforeTail()565             @NonNull ProcessRecordNode getLastNodeBeforeTail() {
566                 return TAIL.mPrev;
567             }
568 
569             @VisibleForTesting
reset()570             void reset() {
571                 if (HEAD.mNext != TAIL) {
572                     HEAD.mNext.mPrev = TAIL.mPrev.mNext = null;
573                 }
574                 HEAD.mNext = TAIL;
575                 TAIL.mPrev = HEAD;
576             }
577 
toString(int logUid)578             String toString(int logUid) {
579                 final StringBuilder sb = new StringBuilder();
580                 sb.append("LinkedProcessRecordList{");
581                 sb.append(HEAD);
582                 sb.append(' ');
583                 sb.append(TAIL);
584                 sb.append('[');
585                 ProcessRecordNode node = HEAD.mNext;
586                 while (node != TAIL) {
587                     if (node.mApp != null && node.mApp.uid == logUid) {
588                         sb.append(node);
589                         sb.append(',');
590                     }
591                     node = node.mNext;
592                 }
593                 sb.append(']');
594                 sb.append('}');
595                 return sb.toString();
596             }
597         }
598     }
599 
600     /**
601      * A data class for holding the parameters in computing oom adj.
602      */
603     private class OomAdjusterArgs {
604         ProcessRecord mApp;
605         ProcessRecord mTopApp;
606         long mNow;
607         int mCachedAdj;
608         @OomAdjReason int mOomAdjReason;
609         @NonNull ActiveUids mUids;
610         boolean mFullUpdate;
611 
update(ProcessRecord topApp, long now, int cachedAdj, @OomAdjReason int oomAdjReason, @NonNull ActiveUids uids, boolean fullUpdate)612         void update(ProcessRecord topApp, long now, int cachedAdj,
613                 @OomAdjReason int oomAdjReason, @NonNull ActiveUids uids, boolean fullUpdate) {
614             mTopApp = topApp;
615             mNow = now;
616             mCachedAdj = cachedAdj;
617             mOomAdjReason = oomAdjReason;
618             mUids = uids;
619             mFullUpdate = fullUpdate;
620         }
621     }
622 
623     /**
624      * A {@link Connection} represents any connection between two processes that can cause a
625      * change in importance in the host process based on the client process and connection state.
626      */
627     public interface Connection {
628         /**
629          * Compute the impact this connection has on the host's importance values.
630          */
computeHostOomAdjLSP(OomAdjuster oomAdjuster, ProcessRecord host, ProcessRecord client, long now, ProcessRecord topApp, boolean doingAll, int oomAdjReason, int cachedAdj)631         void computeHostOomAdjLSP(OomAdjuster oomAdjuster, ProcessRecord host, ProcessRecord client,
632                 long now, ProcessRecord topApp, boolean doingAll, int oomAdjReason, int cachedAdj);
633 
634         /**
635          * Returns true if this connection can propagate capabilities.
636          */
canAffectCapabilities()637         boolean canAffectCapabilities();
638 
639         /**
640          * Returns whether this connection transmits PROCESS_CAPABILITY_CPU_TIME to the host, if the
641          * client possesses it.
642          */
transmitsCpuTime()643         default boolean transmitsCpuTime() {
644             // Always lend this capability by default.
645             return true;
646         }
647     }
648 
649     /**
650      * A helper consumer for marking and collecting reachable processes.
651      */
652     private static class ReachableCollectingConsumer implements
653             BiConsumer<Connection, ProcessRecord> {
654         ArrayList<ProcessRecord> mReachables = null;
655 
init(ArrayList<ProcessRecord> reachables)656         public void init(ArrayList<ProcessRecord> reachables) {
657             mReachables = reachables;
658         }
659 
660         @Override
accept(Connection unused, ProcessRecord host)661         public void accept(Connection unused, ProcessRecord host) {
662             if (host.mState.isReachable()) {
663                 return;
664             }
665             host.mState.setReachable(true);
666             mReachables.add(host);
667         }
668     }
669 
670     private final ReachableCollectingConsumer mReachableCollectingConsumer =
671             new ReachableCollectingConsumer();
672 
673     /**
674      * A helper consumer for computing the importance of a connection from a client.
675      * Connections for clients marked reachable will be ignored.
676      */
677     private class ComputeConnectionIgnoringReachableClientsConsumer implements
678             BiConsumer<Connection, ProcessRecord> {
679         private OomAdjusterArgs mArgs = null;
680         public boolean hasReachableClient = false;
681 
init(OomAdjusterArgs args)682         public void init(OomAdjusterArgs args) {
683             mArgs = args;
684             hasReachableClient = false;
685         }
686 
687         @Override
accept(Connection conn, ProcessRecord client)688         public void accept(Connection conn, ProcessRecord client) {
689             final ProcessRecord host = mArgs.mApp;
690             final ProcessRecord topApp = mArgs.mTopApp;
691             final long now = mArgs.mNow;
692             final @OomAdjReason int oomAdjReason = mArgs.mOomAdjReason;
693 
694             if (client.mState.isReachable()) {
695                 hasReachableClient = true;
696                 return;
697             }
698 
699             if (unimportantConnectionLSP(conn, host, client)) {
700                 return;
701             }
702 
703             conn.computeHostOomAdjLSP(OomAdjusterModernImpl.this, host, client, now, topApp, false,
704                     oomAdjReason, UNKNOWN_ADJ);
705         }
706     }
707 
708     private final ComputeConnectionIgnoringReachableClientsConsumer
709             mComputeConnectionIgnoringReachableClientsConsumer =
710             new ComputeConnectionIgnoringReachableClientsConsumer();
711 
712     /**
713      * A helper consumer for computing host process importance from a connection from a client app.
714      */
715     private class ComputeHostConsumer implements BiConsumer<Connection, ProcessRecord> {
716         public OomAdjusterArgs args = null;
717 
718         @Override
accept(Connection conn, ProcessRecord host)719         public void accept(Connection conn, ProcessRecord host) {
720             final ProcessRecord client = args.mApp;
721             final int cachedAdj = args.mCachedAdj;
722             final ProcessRecord topApp = args.mTopApp;
723             final long now = args.mNow;
724             final @OomAdjReason int oomAdjReason = args.mOomAdjReason;
725             final boolean fullUpdate = args.mFullUpdate;
726 
727             final int prevProcState = host.mState.getCurProcState();
728             final int prevAdj = host.mState.getCurRawAdj();
729 
730             if (unimportantConnectionLSP(conn, host, client)) {
731                 return;
732             }
733 
734             conn.computeHostOomAdjLSP(OomAdjusterModernImpl.this, host, client, now, topApp,
735                     fullUpdate, oomAdjReason, cachedAdj);
736 
737             updateProcStateSlotIfNecessary(host, prevProcState);
738             updateAdjSlotIfNecessary(host, prevAdj);
739         }
740     }
741     private final ComputeHostConsumer mComputeHostConsumer = new ComputeHostConsumer();
742 
743     /**
744      * A helper consumer for computing all connections from an app.
745      */
746     private class ComputeConnectionsConsumer implements Consumer<OomAdjusterArgs> {
747         @Override
accept(OomAdjusterArgs args)748         public void accept(OomAdjusterArgs args) {
749             final ProcessRecord app = args.mApp;
750             final ActiveUids uids = args.mUids;
751 
752             // This process was updated in some way, mark that it was last calculated this sequence.
753             app.mState.setCompletedAdjSeq(mAdjSeq);
754             if (uids != null) {
755                 final UidRecord uidRec = app.getUidRecord();
756 
757                 if (uidRec != null) {
758                     uids.put(uidRec.getUid(), uidRec);
759                 }
760             }
761             mComputeHostConsumer.args = args;
762             forEachConnectionLSP(app, mComputeHostConsumer);
763         }
764     }
765     private final ComputeConnectionsConsumer mComputeConnectionsConsumer =
766             new ComputeConnectionsConsumer();
767 
OomAdjusterModernImpl(ActivityManagerService service, ProcessList processList, ActiveUids activeUids, ServiceThread adjusterThread, GlobalState globalState, CachedAppOptimizer cachedAppOptimizer, Injector injector)768     OomAdjusterModernImpl(ActivityManagerService service, ProcessList processList,
769             ActiveUids activeUids, ServiceThread adjusterThread, GlobalState globalState,
770             CachedAppOptimizer cachedAppOptimizer, Injector injector) {
771         super(service, processList, activeUids, adjusterThread, globalState, cachedAppOptimizer,
772                 injector);
773     }
774 
775     private final ProcessRecordNodes mProcessRecordProcStateNodes = new ProcessRecordNodes(
776             ProcessRecordNode.NODE_TYPE_PROC_STATE, PROC_STATE_SLOTS.length);
777     private final ProcessRecordNodes mProcessRecordAdjNodes = new ProcessRecordNodes(
778             ProcessRecordNode.NODE_TYPE_ADJ, ADJ_SLOT_VALUES.length);
779     private final OomAdjusterArgs mTmpOomAdjusterArgs = new OomAdjusterArgs();
780 
linkProcessRecordToList(@onNull ProcessRecord app)781     void linkProcessRecordToList(@NonNull ProcessRecord app) {
782         mProcessRecordProcStateNodes.append(app);
783         mProcessRecordAdjNodes.append(app);
784     }
785 
unlinkProcessRecordFromList(@onNull ProcessRecord app)786     void unlinkProcessRecordFromList(@NonNull ProcessRecord app) {
787         mProcessRecordProcStateNodes.unlink(app);
788         mProcessRecordAdjNodes.unlink(app);
789     }
790 
791     @Override
792     @VisibleForTesting
resetInternal()793     void resetInternal() {
794         mProcessRecordProcStateNodes.reset();
795         mProcessRecordAdjNodes.reset();
796     }
797 
798     @GuardedBy("mService")
799     @Override
onProcessEndLocked(@onNull ProcessRecord app)800     void onProcessEndLocked(@NonNull ProcessRecord app) {
801         if (app.mLinkedNodes[ProcessRecordNode.NODE_TYPE_PROC_STATE] != null
802                 && app.mLinkedNodes[ProcessRecordNode.NODE_TYPE_PROC_STATE].isLinked()) {
803             unlinkProcessRecordFromList(app);
804         }
805     }
806 
807     @GuardedBy("mService")
808     @Override
onProcessStateChanged(@onNull ProcessRecord app, int prevProcState)809     void onProcessStateChanged(@NonNull ProcessRecord app, int prevProcState) {
810         updateProcStateSlotIfNecessary(app, prevProcState);
811     }
812 
813     @GuardedBy("mService")
onProcessOomAdjChanged(@onNull ProcessRecord app, int prevAdj)814     void onProcessOomAdjChanged(@NonNull ProcessRecord app, int prevAdj) {
815         updateAdjSlotIfNecessary(app, prevAdj);
816     }
817 
818     @GuardedBy("mService")
819     @Override
getInitialAdj(@onNull ProcessRecord app)820     protected int getInitialAdj(@NonNull ProcessRecord app) {
821         return UNKNOWN_ADJ;
822     }
823 
824     @GuardedBy("mService")
825     @Override
getInitialProcState(@onNull ProcessRecord app)826     protected int getInitialProcState(@NonNull ProcessRecord app) {
827         return PROCESS_STATE_UNKNOWN;
828     }
829 
830     @GuardedBy("mService")
831     @Override
getInitialCapability(@onNull ProcessRecord app)832     protected int getInitialCapability(@NonNull ProcessRecord app) {
833         return 0;
834     }
835 
836     @GuardedBy("mService")
837     @Override
getInitialIsCurBoundByNonBgRestrictedApp(@onNull ProcessRecord app)838     protected boolean getInitialIsCurBoundByNonBgRestrictedApp(@NonNull ProcessRecord app) {
839         return false;
840     }
841 
updateAdjSlotIfNecessary(ProcessRecord app, int prevRawAdj)842     private void updateAdjSlotIfNecessary(ProcessRecord app, int prevRawAdj) {
843         if (app.mState.getCurRawAdj() != prevRawAdj) {
844             if (Flags.simplifyProcessTraversal()) {
845                 mProcessRecordAdjNodes.offer(app);
846             } else {
847                 final int slot = adjToSlot(app.mState.getCurRawAdj());
848                 final int prevSlot = adjToSlot(prevRawAdj);
849                 if (slot != prevSlot && slot != ADJ_SLOT_INVALID) {
850                     mProcessRecordAdjNodes.moveAppTo(app, prevSlot, slot);
851                 }
852             }
853         }
854     }
855 
updateAdjSlot(ProcessRecord app, int prevRawAdj)856     private void updateAdjSlot(ProcessRecord app, int prevRawAdj) {
857         if (Flags.simplifyProcessTraversal()) {
858             mProcessRecordAdjNodes.offer(app);
859         } else {
860             final int slot = adjToSlot(app.mState.getCurRawAdj());
861             final int prevSlot = adjToSlot(prevRawAdj);
862             mProcessRecordAdjNodes.moveAppTo(app, prevSlot, slot);
863         }
864     }
865 
updateProcStateSlotIfNecessary(ProcessRecord app, int prevProcState)866     private void updateProcStateSlotIfNecessary(ProcessRecord app, int prevProcState) {
867         if (app.mState.getCurProcState() != prevProcState) {
868             if (Flags.simplifyProcessTraversal()) {
869                 mProcessRecordProcStateNodes.offer(app);
870             } else {
871                 final int slot = processStateToSlot(app.mState.getCurProcState());
872                 final int prevSlot = processStateToSlot(prevProcState);
873                 if (slot != prevSlot) {
874                     mProcessRecordProcStateNodes.moveAppTo(app, prevSlot, slot);
875                 }
876             }
877         }
878     }
879 
updateProcStateSlot(ProcessRecord app, int prevProcState)880     private void updateProcStateSlot(ProcessRecord app, int prevProcState) {
881         if (Flags.simplifyProcessTraversal()) {
882             mProcessRecordProcStateNodes.offer(app);
883         } else {
884             final int slot = processStateToSlot(app.mState.getCurProcState());
885             final int prevSlot = processStateToSlot(prevProcState);
886             mProcessRecordProcStateNodes.moveAppTo(app, prevSlot, slot);
887         }
888     }
889 
890     @Override
performUpdateOomAdjLSP(@omAdjReason int oomAdjReason)891     protected void performUpdateOomAdjLSP(@OomAdjReason int oomAdjReason) {
892         final ProcessRecord topApp = mService.getTopApp();
893         mProcessStateCurTop = mService.mAtmInternal.getTopProcessState();
894         // Clear any pending ones because we are doing a full update now.
895         mPendingProcessSet.clear();
896         mService.mAppProfiler.mHasPreviousProcess = mService.mAppProfiler.mHasHomeProcess = false;
897 
898         mLastReason = oomAdjReason;
899         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReasonToString(oomAdjReason));
900 
901         fullUpdateLSP(oomAdjReason);
902 
903         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
904     }
905 
906     @GuardedBy({"mService", "mProcLock"})
907     @Override
performUpdateOomAdjLSP(ProcessRecord app, @OomAdjReason int oomAdjReason)908     protected boolean performUpdateOomAdjLSP(ProcessRecord app, @OomAdjReason int oomAdjReason) {
909         mPendingProcessSet.add(app);
910         performUpdateOomAdjPendingTargetsLocked(oomAdjReason);
911         return true;
912     }
913 
914     @GuardedBy("mService")
915     @Override
performUpdateOomAdjPendingTargetsLocked(@omAdjReason int oomAdjReason)916     protected void performUpdateOomAdjPendingTargetsLocked(@OomAdjReason int oomAdjReason) {
917         mLastReason = oomAdjReason;
918         mProcessStateCurTop = enqueuePendingTopAppIfNecessaryLSP();
919         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReasonToString(oomAdjReason));
920 
921         synchronized (mProcLock) {
922             partialUpdateLSP(oomAdjReason, mPendingProcessSet);
923         }
924         mPendingProcessSet.clear();
925 
926         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
927     }
928 
929     /**
930      * Perform a full update on the entire process list.
931      */
932     @GuardedBy({"mService", "mProcLock"})
fullUpdateLSP(@omAdjReason int oomAdjReason)933     private void fullUpdateLSP(@OomAdjReason int oomAdjReason) {
934         final ProcessRecord topApp = mService.getTopApp();
935         final long now = mInjector.getUptimeMillis();
936         final long nowElapsed = mInjector.getElapsedRealtimeMillis();
937         final long oldTime = now - mConstants.mMaxEmptyTimeMillis;
938 
939         mAdjSeq++;
940 
941         mNewNumServiceProcs = 0;
942         mNewNumAServiceProcs = 0;
943 
944         // Clear the priority queues.
945         mProcessRecordProcStateNodes.reset();
946         mProcessRecordAdjNodes.reset();
947 
948         final ArrayList<ProcessRecord> lru = mProcessList.getLruProcessesLOSP();
949         for (int i = lru.size() - 1; i >= 0; i--) {
950             final ProcessRecord app = lru.get(i);
951             final int prevProcState = app.mState.getCurProcState();
952             final int prevAdj = app.mState.getCurRawAdj();
953             app.mState.resetCachedInfo();
954             final UidRecord uidRec = app.getUidRecord();
955             if (uidRec != null) {
956                 if (DEBUG_UID_OBSERVERS) {
957                     Slog.i(TAG_UID_OBSERVERS, "Starting update of " + uidRec);
958                 }
959                 uidRec.reset();
960             }
961 
962             // Compute initial values, the procState and adj priority queues will be populated here.
963             computeOomAdjLSP(app, UNKNOWN_ADJ, topApp, true, now, false, false, oomAdjReason,
964                     false);
965 
966             if (Flags.simplifyProcessTraversal()) {
967                 // Just add to the procState priority queue. The adj priority queue should be
968                 // empty going into the traversal step.
969                 mProcessRecordProcStateNodes.offer(app);
970             } else {
971                 updateProcStateSlot(app, prevProcState);
972                 updateAdjSlot(app, prevAdj);
973             }
974         }
975 
976         // Set adj last nodes now, this way a process will only be reevaluated during the adj node
977         // iteration if they adj score changed during the procState node iteration.
978         mProcessRecordAdjNodes.resetLastNodes();
979         mTmpOomAdjusterArgs.update(topApp, now, UNKNOWN_ADJ, oomAdjReason, null, true);
980         computeConnectionsLSP();
981 
982         applyLruAdjust(mProcessList.getLruProcessesLOSP());
983         postUpdateOomAdjInnerLSP(oomAdjReason, mActiveUids, now, nowElapsed, oldTime, true);
984     }
985 
986     /**
987      * Traverse the process graph and update processes based on changes in connection importances.
988      */
989     @GuardedBy({"mService", "mProcLock"})
computeConnectionsLSP()990     private void computeConnectionsLSP() {
991         if (Flags.simplifyProcessTraversal()) {
992             // 1st pass, iterate all nodes in order of procState importance.
993             ProcessRecord proc = mProcessRecordProcStateNodes.poll();
994             while (proc != null) {
995                 mTmpOomAdjusterArgs.mApp = proc;
996                 mComputeConnectionsConsumer.accept(mTmpOomAdjusterArgs);
997                 proc = mProcessRecordProcStateNodes.poll();
998             }
999 
1000             // 2st pass, iterate all nodes in order of procState importance.
1001             proc = mProcessRecordAdjNodes.poll();
1002             while (proc != null) {
1003                 mTmpOomAdjusterArgs.mApp = proc;
1004                 mComputeConnectionsConsumer.accept(mTmpOomAdjusterArgs);
1005                 proc = mProcessRecordAdjNodes.poll();
1006             }
1007         } else {
1008             // 1st pass, scan each slot in the procstate node list.
1009             for (int i = 0, end = mProcessRecordProcStateNodes.size() - 1; i < end; i++) {
1010                 mProcessRecordProcStateNodes.forEachNewNode(i, mComputeConnectionsConsumer);
1011             }
1012 
1013             // 2nd pass, scan each slot in the adj node list.
1014             for (int i = 0, end = mProcessRecordAdjNodes.size() - 1; i < end; i++) {
1015                 mProcessRecordAdjNodes.forEachNewNode(i, mComputeConnectionsConsumer);
1016             }
1017         }
1018     }
1019 
1020     /**
1021      * Perform a partial update on the target processes and their reachable processes.
1022      */
1023     @GuardedBy({"mService", "mProcLock"})
partialUpdateLSP(@omAdjReason int oomAdjReason, ArraySet<ProcessRecord> targets)1024     private void partialUpdateLSP(@OomAdjReason int oomAdjReason, ArraySet<ProcessRecord> targets) {
1025         final ProcessRecord topApp = mService.getTopApp();
1026         final long now = mInjector.getUptimeMillis();
1027         final long nowElapsed = mInjector.getElapsedRealtimeMillis();
1028         final long oldTime = now - mConstants.mMaxEmptyTimeMillis;
1029 
1030         ActiveUids activeUids = mTmpUidRecords;
1031         activeUids.clear();
1032         mTmpOomAdjusterArgs.update(topApp, now, UNKNOWN_ADJ, oomAdjReason, activeUids, false);
1033 
1034         mAdjSeq++;
1035 
1036         final ArrayList<ProcessRecord> reachables = mTmpProcessList;
1037         reachables.clear();
1038 
1039         for (int i = 0, size = targets.size(); i < size; i++) {
1040             final ProcessRecord target = targets.valueAtUnchecked(i);
1041             target.mState.resetCachedInfo();
1042             target.mState.setReachable(true);
1043             reachables.add(target);
1044         }
1045 
1046         // Collect all processes that are reachable.
1047         // Any process not found in this step will not change in importance during this update.
1048         collectAndMarkReachableProcessesLSP(reachables);
1049 
1050         // Initialize the reachable processes based on their own values plus any
1051         // connections from processes not found in the previous step. Since those non-reachable
1052         // processes cannot change as a part of this update, their current values can be used
1053         // right now.
1054         mProcessRecordProcStateNodes.resetLastNodes();
1055         initReachableStatesLSP(reachables, targets.size(), mTmpOomAdjusterArgs);
1056 
1057         // Set adj last nodes now, this way a process will only be reevaluated during the adj node
1058         // iteration if they adj score changed during the procState node iteration.
1059         mProcessRecordAdjNodes.resetLastNodes();
1060         // Now traverse and compute the connections of processes with changed importance.
1061         computeConnectionsLSP();
1062 
1063         boolean needLruAdjust = false;
1064         for (int i = 0, size = reachables.size(); i < size; i++) {
1065             final ProcessStateRecord state = reachables.get(i).mState;
1066             state.setReachable(false);
1067             state.setCompletedAdjSeq(mAdjSeq);
1068             final int curAdj = state.getCurAdj();
1069             // Processes assigned the PREV oomscore will have a laddered oomscore with respect to
1070             // their positions in the LRU list. i.e. prev+0, prev+1, prev+2, etc.
1071             final boolean isPrevApp = PREVIOUS_APP_ADJ <= curAdj && curAdj <= PREVIOUS_APP_MAX_ADJ;
1072             if (curAdj >= UNKNOWN_ADJ || (Flags.oomadjusterPrevLaddering() && isPrevApp)) {
1073                 needLruAdjust = true;
1074             }
1075         }
1076 
1077         // If all processes have an assigned adj, no need to calculate and assign cached adjs.
1078         if (needLruAdjust) {
1079             // TODO: b/319163103 - optimize cache adj assignment to not require the whole lru list.
1080             applyLruAdjust(mProcessList.getLruProcessesLOSP());
1081         }
1082 
1083         // Repopulate any uid record that may have changed.
1084         for (int i = 0, size = activeUids.size(); i < size; i++) {
1085             final UidRecord ur = activeUids.valueAt(i);
1086             ur.reset();
1087             for (int j = ur.getNumOfProcs() - 1; j >= 0; j--) {
1088                 final ProcessRecord proc = ur.getProcessRecordByIndex(j);
1089                 updateAppUidRecIfNecessaryLSP(proc);
1090             }
1091         }
1092 
1093         postUpdateOomAdjInnerLSP(oomAdjReason, activeUids, now, nowElapsed, oldTime, false);
1094     }
1095 
1096     /**
1097      * Mark all processes reachable from the {@code reachables} processes and add them to the
1098      * provided {@code reachables} list (targets excluded).
1099      */
1100     @GuardedBy({"mService", "mProcLock"})
collectAndMarkReachableProcessesLSP(ArrayList<ProcessRecord> reachables)1101     private void collectAndMarkReachableProcessesLSP(ArrayList<ProcessRecord> reachables) {
1102         mReachableCollectingConsumer.init(reachables);
1103         for (int i = 0; i < reachables.size(); i++) {
1104             ProcessRecord pr = reachables.get(i);
1105             forEachConnectionLSP(pr, mReachableCollectingConsumer);
1106         }
1107     }
1108 
1109     /**
1110      * Calculate initial importance states for {@code reachables} and update their slot position
1111      * if necessary.
1112      */
initReachableStatesLSP(ArrayList<ProcessRecord> reachables, int targetCount, OomAdjusterArgs args)1113     private void initReachableStatesLSP(ArrayList<ProcessRecord> reachables, int targetCount,
1114             OomAdjusterArgs args) {
1115         int i = 0;
1116         boolean initReachables = !Flags.skipUnimportantConnections();
1117         for (; i < targetCount && !initReachables; i++) {
1118             final ProcessRecord target = reachables.get(i);
1119             final int prevProcState = target.mState.getCurProcState();
1120             final int prevAdj = target.mState.getCurRawAdj();
1121             final int prevCapability = target.mState.getCurCapability();
1122             final boolean prevShouldNotFreeze = target.mOptRecord.shouldNotFreeze();
1123 
1124             args.mApp = target;
1125             // If target client is a reachable, reachables need to be reinited in case this
1126             // client is important enough to change this target in the computeConnection step.
1127             initReachables |= computeOomAdjIgnoringReachablesLSP(args);
1128             // If target lowered in importance, reachables need to be reinited because this
1129             // target may have been the source of a reachable's current importance.
1130             initReachables |= selfImportanceLoweredLSP(target, prevProcState, prevAdj,
1131                     prevCapability, prevShouldNotFreeze);
1132 
1133             updateProcStateSlot(target, prevProcState);
1134             updateAdjSlot(target, prevAdj);
1135         }
1136 
1137         if (!initReachables) {
1138             return;
1139         }
1140 
1141         for (int size = reachables.size(); i < size; i++) {
1142             final ProcessRecord reachable = reachables.get(i);
1143             final int prevProcState = reachable.mState.getCurProcState();
1144             final int prevAdj = reachable.mState.getCurRawAdj();
1145 
1146             args.mApp = reachable;
1147             computeOomAdjIgnoringReachablesLSP(args);
1148 
1149             if (Flags.simplifyProcessTraversal()) {
1150                 // Just add to the procState priority queue. The adj priority queue should be
1151                 // empty going into the traversal step.
1152                 mProcessRecordProcStateNodes.offer(reachable);
1153             } else {
1154                 updateProcStateSlot(reachable, prevProcState);
1155                 updateAdjSlot(reachable, prevAdj);
1156             }
1157         }
1158     }
1159 
1160     /**
1161      * Calculate initial importance states for {@code app}.
1162      * Processes not marked reachable cannot change as a part of this update, so connections from
1163      * those process can be calculated now.
1164      *
1165      * Returns true if any client connection was skipped due to a reachablity cycle.
1166      */
1167     @GuardedBy({"mService", "mProcLock"})
computeOomAdjIgnoringReachablesLSP(OomAdjusterArgs args)1168     private boolean computeOomAdjIgnoringReachablesLSP(OomAdjusterArgs args) {
1169         final ProcessRecord app = args.mApp;
1170         final ProcessRecord topApp = args.mTopApp;
1171         final long now = args.mNow;
1172         final @OomAdjReason int oomAdjReason = args.mOomAdjReason;
1173 
1174         computeOomAdjLSP(app, UNKNOWN_ADJ, topApp, false, now, false, false, oomAdjReason, false);
1175 
1176         mComputeConnectionIgnoringReachableClientsConsumer.init(args);
1177         forEachClientConnectionLSP(app, mComputeConnectionIgnoringReachableClientsConsumer);
1178         return mComputeConnectionIgnoringReachableClientsConsumer.hasReachableClient;
1179     }
1180 
1181     /**
1182      * Stream the connections with {@code app} as a client to
1183      * {@code connectionConsumer}.
1184      */
1185     @GuardedBy({"mService", "mProcLock"})
forEachConnectionLSP(ProcessRecord app, BiConsumer<Connection, ProcessRecord> connectionConsumer)1186     private static void forEachConnectionLSP(ProcessRecord app,
1187             BiConsumer<Connection, ProcessRecord> connectionConsumer) {
1188         final ProcessServiceRecord psr = app.mServices;
1189         for (int i = psr.numberOfConnections() - 1; i >= 0; i--) {
1190             ConnectionRecord cr = psr.getConnectionAt(i);
1191             ProcessRecord service = cr.hasFlag(ServiceInfo.FLAG_ISOLATED_PROCESS)
1192                     ? cr.binding.service.isolationHostProc : cr.binding.service.app;
1193             if (service == null || service == app
1194                     || (service.mState.getMaxAdj() >= SYSTEM_ADJ
1195                     && service.mState.getMaxAdj() < FOREGROUND_APP_ADJ)
1196                     || (service.mState.getCurAdj() <= FOREGROUND_APP_ADJ
1197                     && service.mState.getCurrentSchedulingGroup() > SCHED_GROUP_BACKGROUND
1198                     && service.mState.getCurProcState() <= PROCESS_STATE_TOP)
1199                     || (service.isSdkSandbox && cr.binding.attributedClient != null)) {
1200                 continue;
1201             }
1202             connectionConsumer.accept(cr, service);
1203         }
1204 
1205         for (int i = psr.numberOfSdkSandboxConnections() - 1; i >= 0; i--) {
1206             final ConnectionRecord cr = psr.getSdkSandboxConnectionAt(i);
1207             final ProcessRecord service = cr.binding.service.app;
1208             if (service == null || service == app
1209                     || (service.mState.getMaxAdj() >= SYSTEM_ADJ
1210                     && service.mState.getMaxAdj() < FOREGROUND_APP_ADJ)
1211                     || (service.mState.getCurAdj() <= FOREGROUND_APP_ADJ
1212                     && service.mState.getCurrentSchedulingGroup() > SCHED_GROUP_BACKGROUND
1213                     && service.mState.getCurProcState() <= PROCESS_STATE_TOP)) {
1214                 continue;
1215             }
1216             connectionConsumer.accept(cr, service);
1217         }
1218 
1219         final ProcessProviderRecord ppr = app.mProviders;
1220         for (int i = ppr.numberOfProviderConnections() - 1; i >= 0; i--) {
1221             ContentProviderConnection cpc = ppr.getProviderConnectionAt(i);
1222             ProcessRecord provider = cpc.provider.proc;
1223             if (provider == null || provider == app
1224                     || (provider.mState.getMaxAdj() >= ProcessList.SYSTEM_ADJ
1225                     && provider.mState.getMaxAdj() < FOREGROUND_APP_ADJ)
1226                     || (provider.mState.getCurAdj() <= FOREGROUND_APP_ADJ
1227                     && provider.mState.getCurrentSchedulingGroup() > SCHED_GROUP_BACKGROUND
1228                     && provider.mState.getCurProcState() <= PROCESS_STATE_TOP)) {
1229                 continue;
1230             }
1231             connectionConsumer.accept(cpc, provider);
1232         }
1233     }
1234 
1235     /**
1236      * Stream the connections from clients with {@code app} as the host to {@code
1237      * connectionConsumer}.
1238      */
1239     @GuardedBy({"mService", "mProcLock"})
forEachClientConnectionLSP(ProcessRecord app, BiConsumer<Connection, ProcessRecord> connectionConsumer)1240     private static void forEachClientConnectionLSP(ProcessRecord app,
1241             BiConsumer<Connection, ProcessRecord> connectionConsumer) {
1242         final ProcessServiceRecord psr = app.mServices;
1243 
1244         for (int i = psr.numberOfRunningServices() - 1; i >= 0; i--) {
1245             final ServiceRecord s = psr.getRunningServiceAt(i);
1246             final ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections =
1247                     s.getConnections();
1248             for (int j = serviceConnections.size() - 1; j >= 0; j--) {
1249                 final ArrayList<ConnectionRecord> clist = serviceConnections.valueAt(j);
1250                 for (int k = clist.size() - 1; k >= 0; k--) {
1251                     final ConnectionRecord cr = clist.get(k);
1252                     final ProcessRecord client;
1253                     if (app.isSdkSandbox && cr.binding.attributedClient != null) {
1254                         client = cr.binding.attributedClient;
1255                     } else {
1256                         client = cr.binding.client;
1257                     }
1258                     if (client == null || client == app) continue;
1259                     connectionConsumer.accept(cr, client);
1260                 }
1261             }
1262         }
1263 
1264         final ProcessProviderRecord ppr = app.mProviders;
1265         for (int i = ppr.numberOfProviders() - 1; i >= 0; i--) {
1266             final ContentProviderRecord cpr = ppr.getProviderAt(i);
1267             for (int j = cpr.connections.size() - 1; j >= 0; j--) {
1268                 final ContentProviderConnection conn = cpr.connections.get(j);
1269                 connectionConsumer.accept(conn, conn.client);
1270             }
1271         }
1272     }
1273 
1274     /**
1275      * Returns true if at least one the provided values is more important than those in {@code app}.
1276      */
1277     @GuardedBy({"mService", "mProcLock"})
selfImportanceLoweredLSP(ProcessRecord app, int prevProcState, int prevAdj, int prevCapability, boolean prevShouldNotFreeze)1278     private static boolean selfImportanceLoweredLSP(ProcessRecord app, int prevProcState,
1279             int prevAdj, int prevCapability, boolean prevShouldNotFreeze) {
1280         if (app.mState.getCurProcState() > prevProcState) {
1281             return true;
1282         }
1283         if (app.mState.getCurRawAdj() > prevAdj)  {
1284             return true;
1285         }
1286         if ((app.mState.getCurCapability() & prevCapability) != prevCapability)  {
1287             return true;
1288         }
1289         if (!app.mOptRecord.shouldNotFreeze() && prevShouldNotFreeze) {
1290             // No long marked as should not freeze.
1291             return true;
1292         }
1293         return false;
1294     }
1295 
1296     /**
1297      * Returns whether a host connection evaluation can be skipped due to lack of importance.
1298      * Note: the client and host need to be provided as well for the isolated and sandbox
1299      * scenarios.
1300      */
1301     @GuardedBy({"mService", "mProcLock"})
unimportantConnectionLSP(Connection conn, ProcessRecord host, ProcessRecord client)1302     private static boolean unimportantConnectionLSP(Connection conn,
1303             ProcessRecord host, ProcessRecord client) {
1304         if (!Flags.skipUnimportantConnections()) {
1305             // Feature not enabled, just return false so the connection is evaluated.
1306             return false;
1307         }
1308         if (host.mState.getCurProcState() > client.mState.getCurProcState()) {
1309             return false;
1310         }
1311         if (host.mState.getCurRawAdj() > client.mState.getCurRawAdj())  {
1312             return false;
1313         }
1314         final int serviceCapability = host.mState.getCurCapability();
1315         final int clientCapability = client.mState.getCurCapability();
1316         if ((serviceCapability & clientCapability) != clientCapability) {
1317             // Client has a capability the host does not have.
1318             if ((clientCapability & PROCESS_CAPABILITY_BFSL) == PROCESS_CAPABILITY_BFSL
1319                     && (serviceCapability & PROCESS_CAPABILITY_BFSL) == 0) {
1320                 // The BFSL capability does not need a flag to propagate.
1321                 return false;
1322             }
1323             if (conn.canAffectCapabilities()) {
1324                 // One of these bind flags may propagate that capability.
1325                 return false;
1326             }
1327         }
1328 
1329         if (!host.mOptRecord.shouldNotFreeze() && client.mOptRecord.shouldNotFreeze()) {
1330             // If the client is marked as should not freeze, so should the host.
1331             return false;
1332         }
1333         return true;
1334     }
1335 }
1336