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