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