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