1 /* 2 * Copyright (C) 2018 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.UidFrozenStateChangedCallback.UID_FROZEN_STATE_FROZEN; 20 import static android.app.ActivityManager.UidFrozenStateChangedCallback.UID_FROZEN_STATE_UNFROZEN; 21 import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_ACTIVITY; 22 import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_ALLOWLIST; 23 import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_BACKUP; 24 import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_BIND_SERVICE; 25 import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_COMPONENT_DISABLED; 26 import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_EXECUTING_SERVICE; 27 import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_FINISH_RECEIVER; 28 import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_GET_PROVIDER; 29 import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_PROCESS_BEGIN; 30 import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_PROCESS_END; 31 import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_REMOVE_PROVIDER; 32 import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_REMOVE_TASK; 33 import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_RESTRICTION_CHANGE; 34 import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_SHELL; 35 import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_SHORT_FGS_TIMEOUT; 36 import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_START_RECEIVER; 37 import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_START_SERVICE; 38 import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_STOP_SERVICE; 39 import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_SYSTEM_INIT; 40 import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_UID_IDLE; 41 import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_UI_VISIBILITY; 42 import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_UNBIND_SERVICE; 43 import static android.content.ComponentCallbacks2.TRIM_MEMORY_BACKGROUND; 44 45 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_COMPACTION; 46 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FREEZER; 47 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; 48 49 import android.annotation.IntDef; 50 import android.annotation.UptimeMillisLong; 51 import android.app.ActivityManager; 52 import android.app.ActivityManagerInternal.OomAdjReason; 53 import android.app.ActivityThread; 54 import android.app.ApplicationExitInfo; 55 import android.app.ApplicationExitInfo.Reason; 56 import android.app.ApplicationExitInfo.SubReason; 57 import android.app.IApplicationThread; 58 import android.database.ContentObserver; 59 import android.net.Uri; 60 import android.os.Handler; 61 import android.os.Message; 62 import android.os.PowerManagerInternal; 63 import android.os.Process; 64 import android.os.RemoteException; 65 import android.os.SystemClock; 66 import android.os.Trace; 67 import android.provider.DeviceConfig; 68 import android.provider.DeviceConfig.OnPropertiesChangedListener; 69 import android.provider.DeviceConfig.Properties; 70 import android.provider.Settings; 71 import android.text.TextUtils; 72 import android.util.ArraySet; 73 import android.util.EventLog; 74 import android.util.IntArray; 75 import android.util.Pair; 76 import android.util.Slog; 77 import android.util.SparseArray; 78 79 import com.android.internal.annotations.GuardedBy; 80 import com.android.internal.annotations.VisibleForTesting; 81 import com.android.internal.os.BinderfsStatsReader; 82 import com.android.internal.os.ProcLocksReader; 83 import com.android.internal.util.FrameworkStatsLog; 84 import com.android.server.ServiceThread; 85 86 import java.io.FileReader; 87 import java.io.IOException; 88 import java.io.PrintWriter; 89 import java.lang.annotation.Retention; 90 import java.lang.annotation.RetentionPolicy; 91 import java.util.ArrayList; 92 import java.util.Arrays; 93 import java.util.EnumMap; 94 import java.util.HashSet; 95 import java.util.LinkedHashMap; 96 import java.util.LinkedList; 97 import java.util.Map; 98 import java.util.Random; 99 import java.util.Set; 100 101 public final class CachedAppOptimizer { 102 103 // Flags stored in the DeviceConfig API. 104 @VisibleForTesting static final String KEY_USE_COMPACTION = "use_compaction"; 105 @VisibleForTesting static final String KEY_USE_FREEZER = "use_freezer"; 106 @VisibleForTesting static final String KEY_COMPACT_THROTTLE_1 = "compact_throttle_1"; 107 @VisibleForTesting static final String KEY_COMPACT_THROTTLE_2 = "compact_throttle_2"; 108 @VisibleForTesting static final String KEY_COMPACT_THROTTLE_3 = "compact_throttle_3"; 109 @VisibleForTesting static final String KEY_COMPACT_THROTTLE_4 = "compact_throttle_4"; 110 @VisibleForTesting static final String KEY_COMPACT_THROTTLE_5 = "compact_throttle_5"; 111 @VisibleForTesting static final String KEY_COMPACT_THROTTLE_6 = "compact_throttle_6"; 112 @VisibleForTesting static final String KEY_COMPACT_THROTTLE_MIN_OOM_ADJ = 113 "compact_throttle_min_oom_adj"; 114 @VisibleForTesting static final String KEY_COMPACT_THROTTLE_MAX_OOM_ADJ = 115 "compact_throttle_max_oom_adj"; 116 @VisibleForTesting static final String KEY_COMPACT_STATSD_SAMPLE_RATE = 117 "compact_statsd_sample_rate"; 118 @VisibleForTesting static final String KEY_FREEZER_STATSD_SAMPLE_RATE = 119 "freeze_statsd_sample_rate"; 120 @VisibleForTesting static final String KEY_COMPACT_FULL_RSS_THROTTLE_KB = 121 "compact_full_rss_throttle_kb"; 122 @VisibleForTesting static final String KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB = 123 "compact_full_delta_rss_throttle_kb"; 124 @VisibleForTesting static final String KEY_COMPACT_PROC_STATE_THROTTLE = 125 "compact_proc_state_throttle"; 126 @VisibleForTesting static final String KEY_FREEZER_DEBOUNCE_TIMEOUT = 127 "freeze_debounce_timeout"; 128 @VisibleForTesting static final String KEY_FREEZER_EXEMPT_INST_PKG = 129 "freeze_exempt_inst_pkg"; 130 @VisibleForTesting static final String KEY_FREEZER_BINDER_ENABLED = 131 "freeze_binder_enabled"; 132 @VisibleForTesting static final String KEY_FREEZER_BINDER_DIVISOR = 133 "freeze_binder_divisor"; 134 @VisibleForTesting static final String KEY_FREEZER_BINDER_OFFSET = 135 "freeze_binder_offset"; 136 @VisibleForTesting static final String KEY_FREEZER_BINDER_THRESHOLD = 137 "freeze_binder_threshold"; 138 @VisibleForTesting static final String KEY_FREEZER_BINDER_CALLBACK_ENABLED = 139 "freeze_binder_callback_enabled"; 140 @VisibleForTesting static final String KEY_FREEZER_BINDER_CALLBACK_THROTTLE = 141 "freeze_binder_callback_throttle"; 142 @VisibleForTesting static final String KEY_FREEZER_BINDER_ASYNC_THRESHOLD = 143 "freeze_binder_async_threshold"; 144 145 static final int UNFREEZE_REASON_NONE = 146 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_NONE; 147 static final int UNFREEZE_REASON_ACTIVITY = 148 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_ACTIVITY; 149 static final int UNFREEZE_REASON_FINISH_RECEIVER = 150 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_FINISH_RECEIVER; 151 static final int UNFREEZE_REASON_START_RECEIVER = 152 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_START_RECEIVER; 153 static final int UNFREEZE_REASON_BIND_SERVICE = 154 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_BIND_SERVICE; 155 static final int UNFREEZE_REASON_UNBIND_SERVICE = 156 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_UNBIND_SERVICE; 157 static final int UNFREEZE_REASON_START_SERVICE = 158 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_START_SERVICE; 159 static final int UNFREEZE_REASON_GET_PROVIDER = 160 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_GET_PROVIDER; 161 static final int UNFREEZE_REASON_REMOVE_PROVIDER = 162 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_REMOVE_PROVIDER; 163 static final int UNFREEZE_REASON_UI_VISIBILITY = 164 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_UI_VISIBILITY; 165 static final int UNFREEZE_REASON_ALLOWLIST = 166 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_ALLOWLIST; 167 static final int UNFREEZE_REASON_PROCESS_BEGIN = 168 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_PROCESS_BEGIN; 169 static final int UNFREEZE_REASON_PROCESS_END = 170 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_PROCESS_END; 171 static final int UNFREEZE_REASON_TRIM_MEMORY = 172 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_TRIM_MEMORY; 173 static final int UNFREEZE_REASON_PING = 174 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_PING; 175 static final int UNFREEZE_REASON_FILE_LOCKS = 176 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_FILE_LOCKS; 177 static final int UNFREEZE_REASON_FILE_LOCK_CHECK_FAILURE = 178 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_FILE_LOCK_CHECK_FAILURE; 179 static final int UNFREEZE_REASON_BINDER_TXNS = 180 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_BINDER_TXNS; 181 static final int UNFREEZE_REASON_FEATURE_FLAGS = 182 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_FEATURE_FLAGS; 183 static final int UNFREEZE_REASON_SHORT_FGS_TIMEOUT = 184 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_SHORT_FGS_TIMEOUT; 185 static final int UNFREEZE_REASON_SYSTEM_INIT = 186 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_SYSTEM_INIT; 187 static final int UNFREEZE_REASON_BACKUP = 188 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_BACKUP; 189 static final int UNFREEZE_REASON_SHELL = 190 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_SHELL; 191 static final int UNFREEZE_REASON_REMOVE_TASK = 192 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_REMOVE_TASK; 193 static final int UNFREEZE_REASON_UID_IDLE = 194 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_UID_IDLE; 195 static final int UNFREEZE_REASON_STOP_SERVICE = 196 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_STOP_SERVICE; 197 static final int UNFREEZE_REASON_EXECUTING_SERVICE = 198 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_EXECUTING_SERVICE; 199 static final int UNFREEZE_REASON_RESTRICTION_CHANGE = 200 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_RESTRICTION_CHANGE; 201 static final int UNFREEZE_REASON_COMPONENT_DISABLED = 202 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON_V2__UFR_COMPONENT_DISABLED; 203 204 @IntDef(prefix = {"UNFREEZE_REASON_"}, value = { 205 UNFREEZE_REASON_NONE, 206 UNFREEZE_REASON_ACTIVITY, 207 UNFREEZE_REASON_FINISH_RECEIVER, 208 UNFREEZE_REASON_START_RECEIVER, 209 UNFREEZE_REASON_BIND_SERVICE, 210 UNFREEZE_REASON_UNBIND_SERVICE, 211 UNFREEZE_REASON_START_SERVICE, 212 UNFREEZE_REASON_GET_PROVIDER, 213 UNFREEZE_REASON_REMOVE_PROVIDER, 214 UNFREEZE_REASON_UI_VISIBILITY, 215 UNFREEZE_REASON_ALLOWLIST, 216 UNFREEZE_REASON_PROCESS_BEGIN, 217 UNFREEZE_REASON_PROCESS_END, 218 UNFREEZE_REASON_TRIM_MEMORY, 219 UNFREEZE_REASON_PING, 220 UNFREEZE_REASON_FILE_LOCKS, 221 UNFREEZE_REASON_FILE_LOCK_CHECK_FAILURE, 222 UNFREEZE_REASON_BINDER_TXNS, 223 UNFREEZE_REASON_FEATURE_FLAGS, 224 UNFREEZE_REASON_SHORT_FGS_TIMEOUT, 225 UNFREEZE_REASON_SYSTEM_INIT, 226 UNFREEZE_REASON_BACKUP, 227 UNFREEZE_REASON_SHELL, 228 UNFREEZE_REASON_REMOVE_TASK, 229 UNFREEZE_REASON_UID_IDLE, 230 UNFREEZE_REASON_STOP_SERVICE, 231 UNFREEZE_REASON_EXECUTING_SERVICE, 232 UNFREEZE_REASON_RESTRICTION_CHANGE, 233 UNFREEZE_REASON_COMPONENT_DISABLED, 234 }) 235 @Retention(RetentionPolicy.SOURCE) 236 public @interface UnfreezeReason {} 237 238 // RSS Indices 239 private static final int RSS_TOTAL_INDEX = 0; 240 private static final int RSS_FILE_INDEX = 1; 241 private static final int RSS_ANON_INDEX = 2; 242 private static final int RSS_SWAP_INDEX = 3; 243 244 // Keeps these flags in sync with services/core/jni/com_android_server_am_CachedAppOptimizer.cpp 245 private static final int COMPACT_ACTION_FILE_FLAG = 1; 246 private static final int COMPACT_ACTION_ANON_FLAG = 2; 247 248 private static final String ATRACE_COMPACTION_TRACK = "Compaction"; 249 private static final String ATRACE_FREEZER_TRACK = "Freezer"; 250 251 private static final int FREEZE_BINDER_TIMEOUT_MS = 0; 252 private static final int FREEZE_DEADLOCK_TIMEOUT_MS = 1000; 253 254 @VisibleForTesting static final boolean ENABLE_FILE_COMPACT = false; 255 256 // Defaults for phenotype flags. 257 @VisibleForTesting static final boolean DEFAULT_USE_COMPACTION = true; 258 @VisibleForTesting static final boolean DEFAULT_USE_FREEZER = true; 259 @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_1 = 5_000; 260 @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_2 = 10_000; 261 @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_3 = 500; 262 @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_4 = 10_000; 263 @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_5 = 10 * 60 * 1000; 264 @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_6 = 10 * 60 * 1000; 265 @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ = 266 ProcessList.CACHED_APP_MIN_ADJ; 267 @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ = 268 ProcessList.CACHED_APP_MAX_ADJ; 269 // The sampling rate to push app compaction events into statsd for upload. 270 @VisibleForTesting static final float DEFAULT_STATSD_SAMPLE_RATE = 0.1f; 271 @VisibleForTesting static final long DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB = 12_000L; 272 @VisibleForTesting static final long DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB = 8_000L; 273 // Format of this string should be a comma separated list of integers. 274 @VisibleForTesting static final String DEFAULT_COMPACT_PROC_STATE_THROTTLE = 275 String.valueOf(ActivityManager.PROCESS_STATE_RECEIVER); 276 @VisibleForTesting static final long DEFAULT_FREEZER_DEBOUNCE_TIMEOUT = 10_000L; 277 @VisibleForTesting static final boolean DEFAULT_FREEZER_EXEMPT_INST_PKG = true; 278 @VisibleForTesting static final boolean DEFAULT_FREEZER_BINDER_ENABLED = true; 279 @VisibleForTesting static final long DEFAULT_FREEZER_BINDER_DIVISOR = 4; 280 @VisibleForTesting static final int DEFAULT_FREEZER_BINDER_OFFSET = 500; 281 @VisibleForTesting static final long DEFAULT_FREEZER_BINDER_THRESHOLD = 1_000; 282 @VisibleForTesting static final boolean DEFAULT_FREEZER_BINDER_CALLBACK_ENABLED = true; 283 @VisibleForTesting static final long DEFAULT_FREEZER_BINDER_CALLBACK_THROTTLE = 10_000L; 284 @VisibleForTesting static final int DEFAULT_FREEZER_BINDER_ASYNC_THRESHOLD = 1_024; 285 286 @VisibleForTesting static final Uri CACHED_APP_FREEZER_ENABLED_URI = Settings.Global.getUriFor( 287 Settings.Global.CACHED_APPS_FREEZER_ENABLED); 288 289 @VisibleForTesting 290 interface PropertyChangedCallbackForTest { onPropertyChanged()291 void onPropertyChanged(); 292 } 293 private PropertyChangedCallbackForTest mTestCallback; 294 295 // This interface is for functions related to the Process object that need a different 296 // implementation in the tests as we are not creating real processes when testing compaction. 297 @VisibleForTesting 298 interface ProcessDependencies { getRss(int pid)299 long[] getRss(int pid); performCompaction(CompactProfile action, int pid)300 void performCompaction(CompactProfile action, int pid) throws IOException; 301 } 302 303 // This indicates the compaction we want to perform 304 public enum CompactProfile { 305 NONE, // No compaction 306 SOME, // File compaction 307 ANON, // Anon compaction 308 FULL // File+anon compaction 309 } 310 311 // This indicates who initiated the compaction request 312 public enum CompactSource { APP, SHELL } 313 314 public enum CancelCompactReason { 315 SCREEN_ON, // screen was turned on which cancels all compactions. 316 OOM_IMPROVEMENT // process moved out of cached state and into a more perceptible state. 317 } 318 319 // Handler constants. 320 static final int COMPACT_PROCESS_MSG = 1; 321 static final int COMPACT_SYSTEM_MSG = 2; 322 static final int SET_FROZEN_PROCESS_MSG = 3; 323 static final int REPORT_UNFREEZE_MSG = 4; 324 static final int COMPACT_NATIVE_MSG = 5; 325 static final int UID_FROZEN_STATE_CHANGED_MSG = 6; 326 static final int DEADLOCK_WATCHDOG_MSG = 7; 327 static final int BINDER_ERROR_MSG = 8; 328 329 // When free swap falls below this percentage threshold any full (file + anon) 330 // compactions will be downgraded to file only compactions to reduce pressure 331 // on swap resources as file. 332 static final double COMPACT_DOWNGRADE_FREE_SWAP_THRESHOLD = 0.2; 333 334 // Size of history for the last 20 compactions for any process 335 static final int LAST_COMPACTED_ANY_PROCESS_STATS_HISTORY_SIZE = 20; 336 337 // Amount of processes supported to record for their last compaction. 338 static final int LAST_COMPACTION_FOR_PROCESS_STATS_SIZE = 256; 339 340 static final int DO_FREEZE = 1; 341 static final int REPORT_UNFREEZE = 2; 342 343 // Bitfield values for sync/async transactions reveived by frozen processes 344 static final int SYNC_RECEIVED_WHILE_FROZEN = 1; 345 static final int ASYNC_RECEIVED_WHILE_FROZEN = 2; 346 347 // Bitfield values for sync transactions received by frozen binder threads 348 static final int TXNS_PENDING_WHILE_FROZEN = 4; 349 350 /** 351 * This thread must be moved to the system background cpuset. 352 * If that doesn't happen, it's probably going to draw a lot of power. 353 * However, this has to happen after the first updateOomAdjLocked, because 354 * that will wipe out the cpuset assignment for system_server threads. 355 * Accordingly, this is in the AMS constructor. 356 */ 357 final ServiceThread mCachedAppOptimizerThread; 358 359 @GuardedBy("mProcLock") 360 private final ArrayList<ProcessRecord> mPendingCompactionProcesses = 361 new ArrayList<ProcessRecord>(); 362 363 @GuardedBy("mProcLock") 364 private final SparseArray<ProcessRecord> mFrozenProcesses = 365 new SparseArray<>(); 366 367 private final ActivityManagerService mAm; 368 369 private final ActivityManagerGlobalLock mProcLock; 370 371 public final Object mFreezerLock = new Object(); 372 373 private final OnPropertiesChangedListener mOnFlagsChangedListener = 374 new OnPropertiesChangedListener() { 375 @Override 376 public void onPropertiesChanged(Properties properties) { 377 synchronized (mPhenotypeFlagLock) { 378 for (String name : properties.getKeyset()) { 379 if (KEY_USE_COMPACTION.equals(name)) { 380 updateUseCompaction(); 381 } else if (KEY_COMPACT_THROTTLE_1.equals(name) 382 || KEY_COMPACT_THROTTLE_2.equals(name) 383 || KEY_COMPACT_THROTTLE_3.equals(name) 384 || KEY_COMPACT_THROTTLE_4.equals(name) 385 || KEY_COMPACT_THROTTLE_5.equals(name) 386 || KEY_COMPACT_THROTTLE_6.equals(name)) { 387 updateCompactionThrottles(); 388 } else if (KEY_COMPACT_STATSD_SAMPLE_RATE.equals(name)) { 389 updateCompactStatsdSampleRate(); 390 } else if (KEY_FREEZER_STATSD_SAMPLE_RATE.equals(name)) { 391 updateFreezerStatsdSampleRate(); 392 } else if (KEY_COMPACT_FULL_RSS_THROTTLE_KB.equals(name)) { 393 updateFullRssThrottle(); 394 } else if (KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB.equals(name)) { 395 updateFullDeltaRssThrottle(); 396 } else if (KEY_COMPACT_PROC_STATE_THROTTLE.equals(name)) { 397 updateProcStateThrottle(); 398 } else if (KEY_COMPACT_THROTTLE_MIN_OOM_ADJ.equals(name)) { 399 updateMinOomAdjThrottle(); 400 } else if (KEY_COMPACT_THROTTLE_MAX_OOM_ADJ.equals(name)) { 401 updateMaxOomAdjThrottle(); 402 } 403 } 404 } 405 if (mTestCallback != null) { 406 mTestCallback.onPropertyChanged(); 407 } 408 } 409 }; 410 411 private final OnPropertiesChangedListener mOnNativeBootFlagsChangedListener = 412 new OnPropertiesChangedListener() { 413 @Override 414 public void onPropertiesChanged(Properties properties) { 415 synchronized (mPhenotypeFlagLock) { 416 for (String name : properties.getKeyset()) { 417 if (KEY_FREEZER_DEBOUNCE_TIMEOUT.equals(name)) { 418 updateFreezerDebounceTimeout(); 419 } else if (KEY_FREEZER_EXEMPT_INST_PKG.equals(name)) { 420 updateFreezerExemptInstPkg(); 421 } else if (KEY_FREEZER_BINDER_ENABLED.equals(name) 422 || KEY_FREEZER_BINDER_DIVISOR.equals(name) 423 || KEY_FREEZER_BINDER_THRESHOLD.equals(name) 424 || KEY_FREEZER_BINDER_OFFSET.equals(name) 425 || KEY_FREEZER_BINDER_CALLBACK_ENABLED.equals(name) 426 || KEY_FREEZER_BINDER_CALLBACK_THROTTLE.equals(name) 427 || KEY_FREEZER_BINDER_ASYNC_THRESHOLD.equals(name)) { 428 updateFreezerBinderState(); 429 } 430 } 431 } 432 if (mTestCallback != null) { 433 mTestCallback.onPropertyChanged(); 434 } 435 } 436 }; 437 438 private final class SettingsContentObserver extends ContentObserver { SettingsContentObserver()439 SettingsContentObserver() { 440 super(mAm.mHandler); 441 } 442 443 @Override onChange(boolean selfChange, Uri uri)444 public void onChange(boolean selfChange, Uri uri) { 445 if (CACHED_APP_FREEZER_ENABLED_URI.equals(uri)) { 446 synchronized (mPhenotypeFlagLock) { 447 updateUseFreezer(); 448 } 449 } 450 } 451 } 452 453 private final SettingsContentObserver mSettingsObserver; 454 455 @VisibleForTesting 456 final Object mPhenotypeFlagLock = new Object(); 457 458 // Configured by phenotype. Updates from the server take effect immediately. 459 @GuardedBy("mPhenotypeFlagLock") 460 @VisibleForTesting volatile long mCompactThrottleSomeSome = DEFAULT_COMPACT_THROTTLE_1; 461 @GuardedBy("mPhenotypeFlagLock") 462 @VisibleForTesting volatile long mCompactThrottleSomeFull = DEFAULT_COMPACT_THROTTLE_2; 463 @GuardedBy("mPhenotypeFlagLock") 464 @VisibleForTesting volatile long mCompactThrottleFullSome = DEFAULT_COMPACT_THROTTLE_3; 465 @GuardedBy("mPhenotypeFlagLock") 466 @VisibleForTesting volatile long mCompactThrottleFullFull = DEFAULT_COMPACT_THROTTLE_4; 467 @GuardedBy("mPhenotypeFlagLock") 468 @VisibleForTesting volatile long mCompactThrottleMinOomAdj = 469 DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ; 470 @GuardedBy("mPhenotypeFlagLock") 471 @VisibleForTesting volatile long mCompactThrottleMaxOomAdj = 472 DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ; 473 @GuardedBy("mPhenotypeFlagLock") 474 private volatile boolean mUseCompaction = DEFAULT_USE_COMPACTION; 475 private volatile boolean mUseFreezer = false; // set to DEFAULT in init() 476 @GuardedBy("this") 477 private int mFreezerDisableCount = 1; // Freezer is initially disabled, until enabled 478 private final Random mRandom = new Random(); 479 @GuardedBy("mPhenotypeFlagLock") 480 @VisibleForTesting volatile float mCompactStatsdSampleRate = DEFAULT_STATSD_SAMPLE_RATE; 481 @VisibleForTesting volatile float mFreezerStatsdSampleRate = DEFAULT_STATSD_SAMPLE_RATE; 482 @GuardedBy("mPhenotypeFlagLock") 483 @VisibleForTesting volatile long mFullAnonRssThrottleKb = 484 DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB; 485 @GuardedBy("mPhenotypeFlagLock") 486 @VisibleForTesting volatile long mFullDeltaRssThrottleKb = 487 DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB; 488 @GuardedBy("mPhenotypeFlagLock") 489 @VisibleForTesting final Set<Integer> mProcStateThrottle; 490 491 @GuardedBy("mPhenotypeFlagLock") 492 @VisibleForTesting volatile boolean mFreezerBinderEnabled = DEFAULT_FREEZER_BINDER_ENABLED; 493 @GuardedBy("mPhenotypeFlagLock") 494 @VisibleForTesting volatile long mFreezerBinderDivisor = DEFAULT_FREEZER_BINDER_DIVISOR; 495 @GuardedBy("mPhenotypeFlagLock") 496 @VisibleForTesting volatile int mFreezerBinderOffset = DEFAULT_FREEZER_BINDER_OFFSET; 497 @GuardedBy("mPhenotypeFlagLock") 498 @VisibleForTesting volatile long mFreezerBinderThreshold = DEFAULT_FREEZER_BINDER_THRESHOLD; 499 @GuardedBy("mPhenotypeFlagLock") 500 @VisibleForTesting volatile boolean mFreezerBinderCallbackEnabled = 501 DEFAULT_FREEZER_BINDER_CALLBACK_ENABLED; 502 @GuardedBy("mPhenotypeFlagLock") 503 @VisibleForTesting volatile long mFreezerBinderCallbackThrottle = 504 DEFAULT_FREEZER_BINDER_CALLBACK_THROTTLE; 505 @GuardedBy("mPhenotypeFlagLock") 506 @VisibleForTesting volatile int mFreezerBinderAsyncThreshold = 507 DEFAULT_FREEZER_BINDER_ASYNC_THRESHOLD; 508 509 // Handler on which compaction runs. 510 @VisibleForTesting 511 Handler mCompactionHandler; 512 private Handler mFreezeHandler; 513 @GuardedBy("mProcLock") 514 private boolean mFreezerOverride = false; 515 private long mFreezerBinderCallbackLast = -1; 516 517 @VisibleForTesting volatile long mFreezerDebounceTimeout = DEFAULT_FREEZER_DEBOUNCE_TIMEOUT; 518 @VisibleForTesting volatile boolean mFreezerExemptInstPkg = DEFAULT_FREEZER_EXEMPT_INST_PKG; 519 520 // Maps process ID to last compaction statistics for processes that we've fully compacted. Used 521 // when evaluating throttles that we only consider for "full" compaction, so we don't store 522 // data for "some" compactions. Uses LinkedHashMap to ensure insertion order is kept and 523 // facilitate removal of the oldest entry. 524 @VisibleForTesting 525 @GuardedBy("mProcLock") 526 LinkedHashMap<Integer, SingleCompactionStats> mLastCompactionStats = 527 new LinkedHashMap<Integer, SingleCompactionStats>() { 528 @Override 529 protected boolean removeEldestEntry(Map.Entry eldest) { 530 return size() > LAST_COMPACTION_FOR_PROCESS_STATS_SIZE; 531 } 532 }; 533 534 LinkedList<SingleCompactionStats> mCompactionStatsHistory = 535 new LinkedList<SingleCompactionStats>() { 536 @Override 537 public boolean add(SingleCompactionStats e) { 538 if (size() >= LAST_COMPACTED_ANY_PROCESS_STATS_HISTORY_SIZE) { 539 this.remove(); 540 } 541 return super.add(e); 542 } 543 }; 544 545 class AggregatedCompactionStats { 546 // Throttling stats 547 public long mFullCompactRequested; 548 public long mSomeCompactRequested; 549 public long mFullCompactPerformed; 550 public long mSomeCompactPerformed; 551 public long mProcCompactionsNoPidThrottled; 552 public long mProcCompactionsOomAdjThrottled; 553 public long mProcCompactionsTimeThrottled; 554 public long mProcCompactionsRSSThrottled; 555 public long mProcCompactionsMiscThrottled; 556 557 // Memory stats 558 public long mTotalDeltaAnonRssKBs; 559 public long mTotalZramConsumedKBs; 560 public long mTotalAnonMemFreedKBs; 561 public long mSumOrigAnonRss; 562 public double mMaxCompactEfficiency; 563 564 // Cpu time 565 public long mTotalCpuTimeMillis; 566 getThrottledSome()567 public long getThrottledSome() { return mSomeCompactRequested - mSomeCompactPerformed; } 568 getThrottledFull()569 public long getThrottledFull() { return mFullCompactRequested - mFullCompactPerformed; } 570 addMemStats(long anonRssSaved, long zramConsumed, long memFreed, long origAnonRss, long totalCpuTimeMillis)571 public void addMemStats(long anonRssSaved, long zramConsumed, long memFreed, 572 long origAnonRss, long totalCpuTimeMillis) { 573 final double compactEfficiency = memFreed / (double) origAnonRss; 574 if (compactEfficiency > mMaxCompactEfficiency) { 575 mMaxCompactEfficiency = compactEfficiency; 576 } 577 mTotalDeltaAnonRssKBs += anonRssSaved; 578 mTotalZramConsumedKBs += zramConsumed; 579 mTotalAnonMemFreedKBs += memFreed; 580 mSumOrigAnonRss += origAnonRss; 581 mTotalCpuTimeMillis += totalCpuTimeMillis; 582 } 583 dump(PrintWriter pw)584 public void dump(PrintWriter pw) { 585 long totalCompactRequested = mSomeCompactRequested + mFullCompactRequested; 586 long totalCompactPerformed = mSomeCompactPerformed + mFullCompactPerformed; 587 pw.println(" Performed / Requested:"); 588 pw.println(" Some: (" + mSomeCompactPerformed + "/" + mSomeCompactRequested + ")"); 589 pw.println(" Full: (" + mFullCompactPerformed + "/" + mFullCompactRequested + ")"); 590 591 long throttledSome = getThrottledSome(); 592 long throttledFull = getThrottledFull(); 593 594 if (throttledSome > 0 || throttledFull > 0) { 595 pw.println(" Throttled:"); 596 pw.println(" Some: " + throttledSome + " Full: " + throttledFull); 597 pw.println(" Throttled by Type:"); 598 final long compactionsThrottled = totalCompactRequested - totalCompactPerformed; 599 // Any throttle that was not part of the previous categories 600 final long unaccountedThrottled = compactionsThrottled 601 - mProcCompactionsNoPidThrottled - mProcCompactionsOomAdjThrottled 602 - mProcCompactionsTimeThrottled - mProcCompactionsRSSThrottled 603 - mProcCompactionsMiscThrottled; 604 pw.println(" NoPid: " + mProcCompactionsNoPidThrottled 605 + " OomAdj: " + mProcCompactionsOomAdjThrottled + " Time: " 606 + mProcCompactionsTimeThrottled + " RSS: " + mProcCompactionsRSSThrottled 607 + " Misc: " + mProcCompactionsMiscThrottled 608 + " Unaccounted: " + unaccountedThrottled); 609 final double compactThrottlePercentage = 610 (compactionsThrottled / (double) totalCompactRequested) * 100.0; 611 pw.println(" Throttle Percentage: " + compactThrottlePercentage); 612 } 613 614 if (mFullCompactPerformed > 0) { 615 pw.println(" -----Memory Stats----"); 616 pw.println(" Total Delta Anon RSS (KB) : " + mTotalDeltaAnonRssKBs); 617 pw.println(" Total Physical ZRAM Consumed (KB): " + mTotalZramConsumedKBs); 618 pw.println(" Total Anon Memory Freed (KB): " + mTotalAnonMemFreedKBs); 619 // This tells us how much anon memory we were able to free thanks to running 620 // compaction 621 pw.println(" Avg Compaction Efficiency (Anon Freed/Anon RSS): " 622 + (mTotalAnonMemFreedKBs / (double) mSumOrigAnonRss)); 623 pw.println(" Max Compaction Efficiency: " + mMaxCompactEfficiency); 624 // This tells us how effective is the compression algorithm in physical memory 625 pw.println(" Avg Compression Ratio (1 - ZRAM Consumed/DeltaAnonRSS): " 626 + (1.0 - mTotalZramConsumedKBs / (double) mTotalDeltaAnonRssKBs)); 627 long avgKBsPerProcCompact = mFullCompactPerformed > 0 628 ? (mTotalAnonMemFreedKBs / mFullCompactPerformed) 629 : 0; 630 pw.println(" Avg Anon Mem Freed/Compaction (KB) : " + avgKBsPerProcCompact); 631 double compactionCost = 632 mTotalCpuTimeMillis / (mTotalAnonMemFreedKBs / 1024.0); // ms/MB 633 pw.println(" Compaction Cost (ms/MB): " + compactionCost); 634 } 635 } 636 } 637 638 class AggregatedProcessCompactionStats extends AggregatedCompactionStats { 639 public final String processName; 640 AggregatedProcessCompactionStats(String processName)641 AggregatedProcessCompactionStats(String processName) { this.processName = processName; } 642 } 643 644 class AggregatedSourceCompactionStats extends AggregatedCompactionStats { 645 public final CompactSource sourceType; 646 AggregatedSourceCompactionStats(CompactSource sourceType)647 AggregatedSourceCompactionStats(CompactSource sourceType) { this.sourceType = sourceType; } 648 } 649 650 private final LinkedHashMap<String, AggregatedProcessCompactionStats> mPerProcessCompactStats = 651 new LinkedHashMap<>(256); 652 private final EnumMap<CompactSource, AggregatedSourceCompactionStats> mPerSourceCompactStats = 653 new EnumMap<>(CompactSource.class); 654 private long mTotalCompactionDowngrades; 655 private long mSystemCompactionsPerformed; 656 private long mSystemTotalMemFreed; 657 private EnumMap<CancelCompactReason, Integer> mTotalCompactionsCancelled = 658 new EnumMap<>(CancelCompactReason.class); 659 660 private final ProcessDependencies mProcessDependencies; 661 private final ProcLocksReader mProcLocksReader; 662 CachedAppOptimizer(ActivityManagerService am)663 public CachedAppOptimizer(ActivityManagerService am) { 664 this(am, null, new DefaultProcessDependencies()); 665 } 666 667 @VisibleForTesting CachedAppOptimizer(ActivityManagerService am, PropertyChangedCallbackForTest callback, ProcessDependencies processDependencies)668 CachedAppOptimizer(ActivityManagerService am, PropertyChangedCallbackForTest callback, 669 ProcessDependencies processDependencies) { 670 mAm = am; 671 mProcLock = am.mProcLock; 672 mCachedAppOptimizerThread = new ServiceThread("CachedAppOptimizerThread", 673 Process.THREAD_GROUP_SYSTEM, true); 674 mProcStateThrottle = new HashSet<>(); 675 mProcessDependencies = processDependencies; 676 mTestCallback = callback; 677 mSettingsObserver = new SettingsContentObserver(); 678 mProcLocksReader = new ProcLocksReader(); 679 } 680 681 /** 682 * Reads phenotype config to determine whether app compaction is enabled or not and 683 * starts the background thread if necessary. 684 */ init()685 public void init() { 686 // TODO: initialize flags to default and only update them if values are set in DeviceConfig 687 DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 688 ActivityThread.currentApplication().getMainExecutor(), mOnFlagsChangedListener); 689 DeviceConfig.addOnPropertiesChangedListener( 690 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, 691 ActivityThread.currentApplication().getMainExecutor(), 692 mOnNativeBootFlagsChangedListener); 693 mAm.mContext.getContentResolver().registerContentObserver( 694 CACHED_APP_FREEZER_ENABLED_URI, false, mSettingsObserver); 695 synchronized (mPhenotypeFlagLock) { 696 updateUseCompaction(); 697 updateCompactionThrottles(); 698 updateCompactStatsdSampleRate(); 699 updateFreezerStatsdSampleRate(); 700 updateFullRssThrottle(); 701 updateFullDeltaRssThrottle(); 702 updateProcStateThrottle(); 703 updateUseFreezer(); 704 updateMinOomAdjThrottle(); 705 updateMaxOomAdjThrottle(); 706 } 707 } 708 709 /** 710 * Returns whether compaction is enabled. 711 */ useCompaction()712 public boolean useCompaction() { 713 synchronized (mPhenotypeFlagLock) { 714 return mUseCompaction; 715 } 716 } 717 718 /** 719 * Returns whether freezer is enabled. 720 */ useFreezer()721 public boolean useFreezer() { 722 synchronized (mPhenotypeFlagLock) { 723 return mUseFreezer; 724 } 725 } 726 727 /** 728 * Returns whether freezer exempts INSTALL_PACKAGES. 729 */ freezerExemptInstPkg()730 public boolean freezerExemptInstPkg() { 731 synchronized (mPhenotypeFlagLock) { 732 return mUseFreezer && mFreezerExemptInstPkg; 733 } 734 } 735 736 @GuardedBy("mProcLock") dump(PrintWriter pw)737 void dump(PrintWriter pw) { 738 pw.println("CachedAppOptimizer settings"); 739 synchronized (mPhenotypeFlagLock) { 740 pw.println(" " + KEY_USE_COMPACTION + "=" + mUseCompaction); 741 pw.println(" " + KEY_COMPACT_THROTTLE_1 + "=" + mCompactThrottleSomeSome); 742 pw.println(" " + KEY_COMPACT_THROTTLE_2 + "=" + mCompactThrottleSomeFull); 743 pw.println(" " + KEY_COMPACT_THROTTLE_3 + "=" + mCompactThrottleFullSome); 744 pw.println(" " + KEY_COMPACT_THROTTLE_4 + "=" + mCompactThrottleFullFull); 745 pw.println(" " + KEY_COMPACT_THROTTLE_MIN_OOM_ADJ + "=" + mCompactThrottleMinOomAdj); 746 pw.println(" " + KEY_COMPACT_THROTTLE_MAX_OOM_ADJ + "=" + mCompactThrottleMaxOomAdj); 747 pw.println(" " + KEY_COMPACT_STATSD_SAMPLE_RATE + "=" + mCompactStatsdSampleRate); 748 pw.println(" " + KEY_COMPACT_FULL_RSS_THROTTLE_KB + "=" 749 + mFullAnonRssThrottleKb); 750 pw.println(" " + KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB + "=" 751 + mFullDeltaRssThrottleKb); 752 pw.println(" " + KEY_COMPACT_PROC_STATE_THROTTLE + "=" 753 + Arrays.toString(mProcStateThrottle.toArray(new Integer[0]))); 754 755 pw.println(" Per-Process Compaction Stats"); 756 long totalCompactPerformedSome = 0; 757 long totalCompactPerformedFull = 0; 758 for (AggregatedProcessCompactionStats stats : mPerProcessCompactStats.values()) { 759 pw.println("-----" + stats.processName + "-----"); 760 totalCompactPerformedSome += stats.mSomeCompactPerformed; 761 totalCompactPerformedFull += stats.mFullCompactPerformed; 762 stats.dump(pw); 763 pw.println(); 764 } 765 pw.println(); 766 pw.println(" Per-Source Compaction Stats"); 767 for (AggregatedSourceCompactionStats stats : mPerSourceCompactStats.values()) { 768 pw.println("-----" + stats.sourceType + "-----"); 769 stats.dump(pw); 770 pw.println(); 771 } 772 pw.println(); 773 774 pw.println("Total Compactions Performed by profile: " + totalCompactPerformedSome 775 + " some, " + totalCompactPerformedFull + " full"); 776 pw.println("Total compactions downgraded: " + mTotalCompactionDowngrades); 777 pw.println("Total compactions cancelled by reason: "); 778 for (CancelCompactReason reason : mTotalCompactionsCancelled.keySet()) { 779 pw.println(" " + reason + ": " + mTotalCompactionsCancelled.get(reason)); 780 } 781 pw.println(); 782 783 pw.println(" System Compaction Memory Stats"); 784 pw.println(" Compactions Performed: " + mSystemCompactionsPerformed); 785 pw.println(" Total Memory Freed (KB): " + mSystemTotalMemFreed); 786 double avgKBsPerSystemCompact = mSystemCompactionsPerformed > 0 787 ? mSystemTotalMemFreed / mSystemCompactionsPerformed 788 : 0; 789 pw.println(" Avg Mem Freed per Compact (KB): " + avgKBsPerSystemCompact); 790 pw.println(); 791 pw.println(" Tracking last compaction stats for " + mLastCompactionStats.size() 792 + " processes."); 793 pw.println("Last Compaction per process stats:"); 794 pw.println(" (ProcessName,Source,DeltaAnonRssKBs,ZramConsumedKBs,AnonMemFreedKBs," 795 + "CompactEfficiency,CompactCost(ms/MB),procState,oomAdj,oomAdjReason)"); 796 for (Map.Entry<Integer, SingleCompactionStats> entry : 797 mLastCompactionStats.entrySet()) { 798 SingleCompactionStats stats = entry.getValue(); 799 stats.dump(pw); 800 } 801 pw.println(); 802 pw.println("Last 20 Compactions Stats:"); 803 pw.println(" (ProcessName,Source,DeltaAnonRssKBs,ZramConsumedKBs,AnonMemFreedKBs," 804 + "CompactEfficiency,CompactCost(ms/MB),procState,oomAdj,oomAdjReason)"); 805 for (SingleCompactionStats stats : mCompactionStatsHistory) { 806 stats.dump(pw); 807 } 808 pw.println(); 809 810 pw.println(" " + KEY_USE_FREEZER + "=" + mUseFreezer); 811 pw.println(" " + KEY_FREEZER_STATSD_SAMPLE_RATE + "=" + mFreezerStatsdSampleRate); 812 pw.println(" " + KEY_FREEZER_DEBOUNCE_TIMEOUT + "=" + mFreezerDebounceTimeout); 813 pw.println(" " + KEY_FREEZER_EXEMPT_INST_PKG + "=" + mFreezerExemptInstPkg); 814 pw.println(" " + KEY_FREEZER_BINDER_ENABLED + "=" + mFreezerBinderEnabled); 815 pw.println(" " + KEY_FREEZER_BINDER_THRESHOLD + "=" + mFreezerBinderThreshold); 816 pw.println(" " + KEY_FREEZER_BINDER_DIVISOR + "=" + mFreezerBinderDivisor); 817 pw.println(" " + KEY_FREEZER_BINDER_OFFSET + "=" + mFreezerBinderOffset); 818 pw.println(" " + KEY_FREEZER_BINDER_CALLBACK_ENABLED + "=" 819 + mFreezerBinderCallbackEnabled); 820 pw.println(" " + KEY_FREEZER_BINDER_CALLBACK_THROTTLE + "=" 821 + mFreezerBinderCallbackThrottle); 822 pw.println(" " + KEY_FREEZER_BINDER_ASYNC_THRESHOLD + "=" 823 + mFreezerBinderAsyncThreshold); 824 synchronized (mProcLock) { 825 int size = mFrozenProcesses.size(); 826 pw.println(" Apps frozen: " + size); 827 for (int i = 0; i < size; i++) { 828 ProcessRecord app = mFrozenProcesses.valueAt(i); 829 pw.println(" " + app.mOptRecord.getFreezeUnfreezeTime() + ": " + app.getPid() 830 + " " + app.processName 831 + (app.mOptRecord.isFreezeSticky() ? " (sticky)" : "")); 832 } 833 834 if (!mPendingCompactionProcesses.isEmpty()) { 835 pw.println(" Pending compactions:"); 836 size = mPendingCompactionProcesses.size(); 837 for (int i = 0; i < size; i++) { 838 ProcessRecord app = mPendingCompactionProcesses.get(i); 839 pw.println(" pid: " + app.getPid() + ". name: " + app.processName 840 + ". hasPendingCompact: " + app.mOptRecord.hasPendingCompact()); 841 } 842 } 843 } 844 } 845 } 846 847 @GuardedBy("mProcLock") compactApp( ProcessRecord app, CompactProfile compactProfile, CompactSource source, boolean force)848 boolean compactApp( 849 ProcessRecord app, CompactProfile compactProfile, CompactSource source, boolean force) { 850 app.mOptRecord.setReqCompactSource(source); 851 app.mOptRecord.setReqCompactProfile(compactProfile); 852 AggregatedSourceCompactionStats perSourceStats = getPerSourceAggregatedCompactStat(source); 853 AggregatedCompactionStats perProcStats = 854 getPerProcessAggregatedCompactStat(app.processName); 855 switch (compactProfile) { 856 case SOME: 857 ++perProcStats.mSomeCompactRequested; 858 ++perSourceStats.mSomeCompactRequested; 859 break; 860 case FULL: 861 ++perProcStats.mFullCompactRequested; 862 ++perSourceStats.mFullCompactRequested; 863 break; 864 default: 865 Slog.e(TAG_AM, 866 "Unimplemented compaction type, consider adding it."); 867 return false; 868 } 869 870 if (!app.mOptRecord.hasPendingCompact()) { 871 final String processName = (app.processName != null ? app.processName : ""); 872 if (DEBUG_COMPACTION) { 873 Slog.d(TAG_AM, 874 "compactApp " + app.mOptRecord.getReqCompactSource().name() + " " 875 + app.mOptRecord.getReqCompactProfile().name() + " " + processName); 876 } 877 app.mOptRecord.setHasPendingCompact(true); 878 app.mOptRecord.setForceCompact(force); 879 mPendingCompactionProcesses.add(app); 880 mCompactionHandler.sendMessage(mCompactionHandler.obtainMessage( 881 COMPACT_PROCESS_MSG, app.mState.getCurAdj(), app.mState.getSetProcState())); 882 return true; 883 } 884 885 if (DEBUG_COMPACTION) { 886 Slog.d(TAG_AM, 887 " compactApp Skipped for " + app.processName + " pendingCompact= " 888 + app.mOptRecord.hasPendingCompact() + ". Requested compact profile: " 889 + app.mOptRecord.getReqCompactProfile().name() + ". Compact source " 890 + app.mOptRecord.getReqCompactSource().name()); 891 } 892 return false; 893 } 894 compactNative(CompactProfile compactProfile, int pid)895 void compactNative(CompactProfile compactProfile, int pid) { 896 mCompactionHandler.sendMessage(mCompactionHandler.obtainMessage( 897 COMPACT_NATIVE_MSG, pid, compactProfile.ordinal())); 898 } 899 getPerProcessAggregatedCompactStat( String processName)900 private AggregatedProcessCompactionStats getPerProcessAggregatedCompactStat( 901 String processName) { 902 if (processName == null) { 903 processName = ""; 904 } 905 AggregatedProcessCompactionStats stats = mPerProcessCompactStats.get(processName); 906 if (stats == null) { 907 stats = new AggregatedProcessCompactionStats(processName); 908 mPerProcessCompactStats.put(processName, stats); 909 } 910 return stats; 911 } 912 getPerSourceAggregatedCompactStat( CompactSource source)913 private AggregatedSourceCompactionStats getPerSourceAggregatedCompactStat( 914 CompactSource source) { 915 AggregatedSourceCompactionStats stats = mPerSourceCompactStats.get(source); 916 if (stats == null) { 917 stats = new AggregatedSourceCompactionStats(source); 918 mPerSourceCompactStats.put(source, stats); 919 } 920 return stats; 921 } 922 compactAllSystem()923 void compactAllSystem() { 924 if (useCompaction()) { 925 if (DEBUG_COMPACTION) { 926 Slog.d(TAG_AM, "compactAllSystem"); 927 } 928 Trace.instantForTrack( 929 Trace.TRACE_TAG_ACTIVITY_MANAGER, ATRACE_COMPACTION_TRACK, "compactAllSystem"); 930 mCompactionHandler.sendMessage(mCompactionHandler.obtainMessage( 931 COMPACT_SYSTEM_MSG)); 932 } 933 } 934 compactSystem()935 private native void compactSystem(); 936 937 /** 938 * Compacts a process or app 939 * @param pid pid of process to compact 940 * @param compactionFlags selects the compaction type as defined by COMPACT_ACTION_{TYPE}_FLAG 941 * constants 942 */ compactProcess(int pid, int compactionFlags)943 static private native void compactProcess(int pid, int compactionFlags); 944 cancelCompaction()945 static private native void cancelCompaction(); 946 947 /** 948 * Returns the cpu time for the current thread 949 */ threadCpuTimeNs()950 static private native long threadCpuTimeNs(); 951 952 /** 953 * Retrieves the free swap percentage. 954 */ getFreeSwapPercent()955 static native double getFreeSwapPercent(); 956 957 /** 958 * Retrieves the total used physical ZRAM 959 */ getUsedZramMemory()960 static private native long getUsedZramMemory(); 961 962 /** 963 * Amount of memory that has been made free due to compaction. 964 * It represents uncompressed memory size - compressed memory size. 965 */ getMemoryFreedCompaction()966 static private native long getMemoryFreedCompaction(); 967 968 /** 969 * Reads the flag value from DeviceConfig to determine whether app compaction 970 * should be enabled, and starts the freeze/compaction thread if needed. 971 */ 972 @GuardedBy("mPhenotypeFlagLock") updateUseCompaction()973 private void updateUseCompaction() { 974 mUseCompaction = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 975 KEY_USE_COMPACTION, DEFAULT_USE_COMPACTION); 976 977 if (mUseCompaction && mCompactionHandler == null) { 978 if (!mCachedAppOptimizerThread.isAlive()) { 979 mCachedAppOptimizerThread.start(); 980 } 981 982 mCompactionHandler = new MemCompactionHandler(); 983 984 Process.setThreadGroupAndCpuset(mCachedAppOptimizerThread.getThreadId(), 985 Process.THREAD_GROUP_SYSTEM); 986 } 987 } 988 989 /** 990 * Enables or disabled the app freezer. 991 * @param enable Enables the freezer if true, disables it if false. 992 * @return true if the operation completed successfully, false otherwise. 993 */ enableFreezer(boolean enable)994 public synchronized boolean enableFreezer(boolean enable) { 995 if (!mUseFreezer) { 996 return false; 997 } 998 999 if (enable) { 1000 mFreezerDisableCount--; 1001 1002 if (mFreezerDisableCount > 0) { 1003 return true; 1004 } else if (mFreezerDisableCount < 0) { 1005 Slog.e(TAG_AM, "unbalanced call to enableFreezer, ignoring"); 1006 mFreezerDisableCount = 0; 1007 return false; 1008 } 1009 } else { 1010 mFreezerDisableCount++; 1011 1012 if (mFreezerDisableCount > 1) { 1013 return true; 1014 } 1015 } 1016 1017 // Override is applied immediately, restore is delayed 1018 synchronized (mAm) { 1019 synchronized (mProcLock) { 1020 mFreezerOverride = !enable; 1021 Slog.d(TAG_AM, "freezer override set to " + mFreezerOverride); 1022 1023 mAm.mProcessList.forEachLruProcessesLOSP(true, process -> { 1024 if (process == null) { 1025 return; 1026 } 1027 1028 final ProcessCachedOptimizerRecord opt = process.mOptRecord; 1029 if (enable && opt.hasFreezerOverride()) { 1030 freezeAppAsyncLSP(process); 1031 opt.setFreezerOverride(false); 1032 } 1033 1034 if (!enable && opt.isFrozen()) { 1035 unfreezeAppLSP(process, UNFREEZE_REASON_FEATURE_FLAGS); 1036 1037 // Set freezerOverride *after* calling unfreezeAppLSP (it resets the flag) 1038 opt.setFreezerOverride(true); 1039 } 1040 }); 1041 } 1042 } 1043 1044 return true; 1045 } 1046 1047 /** 1048 * Informs binder that a process is about to be frozen. If freezer is enabled on a process via 1049 * this method, this method will synchronously dispatch all pending transactions to the 1050 * specified pid. This method will not add significant latencies when unfreezing. 1051 * After freezing binder calls, binder will block all transaction to the frozen pid, and return 1052 * an error to the sending process. 1053 * 1054 * @param pid the target pid for which binder transactions are to be frozen 1055 * @param freeze specifies whether to flush transactions and then freeze (true) or unfreeze 1056 * binder for the specificed pid. 1057 * @param timeoutMs the timeout in milliseconds to wait for the binder interface to freeze 1058 * before giving up. 1059 * 1060 * @throws RuntimeException in case a flush/freeze operation could not complete successfully. 1061 * @return 0 if success, or -EAGAIN indicating there's pending transaction. 1062 */ freezeBinder(int pid, boolean freeze, int timeoutMs)1063 public static native int freezeBinder(int pid, boolean freeze, int timeoutMs); 1064 1065 /** 1066 * Retrieves binder freeze info about a process. 1067 * @param pid the pid for which binder freeze info is to be retrieved. 1068 * 1069 * @throws RuntimeException if the operation could not complete successfully. 1070 * @return a bit field reporting the binder freeze info for the process. 1071 */ getBinderFreezeInfo(int pid)1072 private static native int getBinderFreezeInfo(int pid); 1073 1074 /** 1075 * Returns the path to be checked to verify whether the freezer is supported by this system. 1076 * @return absolute path to the file 1077 */ getFreezerCheckPath()1078 private static native String getFreezerCheckPath(); 1079 1080 /** 1081 * Check if task_profiles.json includes valid freezer profiles and actions 1082 * @return false if there are invalid profiles or actions 1083 */ isFreezerProfileValid()1084 private static native boolean isFreezerProfileValid(); 1085 1086 /** 1087 * Determines whether the freezer is supported by this system 1088 */ isFreezerSupported()1089 public static boolean isFreezerSupported() { 1090 boolean supported = false; 1091 FileReader fr = null; 1092 1093 try { 1094 String path = getFreezerCheckPath(); 1095 Slog.d(TAG_AM, "Checking cgroup freezer: " + path); 1096 fr = new FileReader(path); 1097 char state = (char) fr.read(); 1098 1099 if (state == '1' || state == '0') { 1100 // Also check freezer binder ioctl 1101 Slog.d(TAG_AM, "Checking binder freezer ioctl"); 1102 getBinderFreezeInfo(Process.myPid()); 1103 1104 // Check if task_profiles.json contains invalid profiles 1105 Slog.d(TAG_AM, "Checking freezer profiles"); 1106 supported = isFreezerProfileValid(); 1107 } else { 1108 Slog.e(TAG_AM, "Unexpected value in cgroup.freeze"); 1109 } 1110 } catch (java.io.FileNotFoundException e) { 1111 Slog.w(TAG_AM, "File cgroup.freeze not present"); 1112 } catch (RuntimeException e) { 1113 Slog.w(TAG_AM, "Unable to read freezer info"); 1114 } catch (Exception e) { 1115 Slog.w(TAG_AM, "Unable to read cgroup.freeze: " + e.toString()); 1116 } 1117 1118 if (fr != null) { 1119 try { 1120 fr.close(); 1121 } catch (java.io.IOException e) { 1122 Slog.e(TAG_AM, "Exception closing cgroup.freeze: " + e.toString()); 1123 } 1124 } 1125 1126 Slog.d(TAG_AM, "Freezer supported: " + supported); 1127 return supported; 1128 } 1129 1130 /** 1131 * Reads the flag value from DeviceConfig to determine whether app freezer 1132 * should be enabled, and starts the freeze/compaction thread if needed. 1133 */ 1134 @GuardedBy("mPhenotypeFlagLock") updateUseFreezer()1135 private void updateUseFreezer() { 1136 final String configOverride = Settings.Global.getString(mAm.mContext.getContentResolver(), 1137 Settings.Global.CACHED_APPS_FREEZER_ENABLED); 1138 1139 if ("disabled".equals(configOverride)) { 1140 mUseFreezer = false; 1141 } else if ("enabled".equals(configOverride) 1142 || DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, 1143 KEY_USE_FREEZER, DEFAULT_USE_FREEZER)) { 1144 mUseFreezer = isFreezerSupported(); 1145 updateFreezerDebounceTimeout(); 1146 updateFreezerExemptInstPkg(); 1147 } else { 1148 mUseFreezer = false; 1149 } 1150 1151 final boolean useFreezer = mUseFreezer; 1152 // enableFreezer() would need the global ActivityManagerService lock, post it. 1153 mAm.mHandler.post(() -> { 1154 if (useFreezer) { 1155 Slog.d(TAG_AM, "Freezer enabled"); 1156 enableFreezer(true); 1157 1158 if (!mCachedAppOptimizerThread.isAlive()) { 1159 mCachedAppOptimizerThread.start(); 1160 } 1161 1162 if (mFreezeHandler == null) { 1163 mFreezeHandler = new FreezeHandler(); 1164 } 1165 1166 Process.setThreadGroupAndCpuset(mCachedAppOptimizerThread.getThreadId(), 1167 Process.THREAD_GROUP_SYSTEM); 1168 } else { 1169 Slog.d(TAG_AM, "Freezer disabled"); 1170 enableFreezer(false); 1171 } 1172 }); 1173 } 1174 1175 @GuardedBy("mPhenotypeFlagLock") updateCompactionThrottles()1176 private void updateCompactionThrottles() { 1177 boolean useThrottleDefaults = false; 1178 // TODO: improve efficiency by calling DeviceConfig only once for all flags. 1179 String throttleSomeSomeFlag = 1180 DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1181 KEY_COMPACT_THROTTLE_1); 1182 String throttleSomeFullFlag = 1183 DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1184 KEY_COMPACT_THROTTLE_2); 1185 String throttleFullSomeFlag = 1186 DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1187 KEY_COMPACT_THROTTLE_3); 1188 String throttleFullFullFlag = 1189 DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1190 KEY_COMPACT_THROTTLE_4); 1191 String throttleBFGSFlag = 1192 DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1193 KEY_COMPACT_THROTTLE_5); 1194 String throttlePersistentFlag = 1195 DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1196 KEY_COMPACT_THROTTLE_6); 1197 String throttleMinOomAdjFlag = 1198 DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1199 KEY_COMPACT_THROTTLE_MIN_OOM_ADJ); 1200 String throttleMaxOomAdjFlag = 1201 DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1202 KEY_COMPACT_THROTTLE_MAX_OOM_ADJ); 1203 1204 if (TextUtils.isEmpty(throttleSomeSomeFlag) || TextUtils.isEmpty(throttleSomeFullFlag) 1205 || TextUtils.isEmpty(throttleFullSomeFlag) 1206 || TextUtils.isEmpty(throttleFullFullFlag) 1207 || TextUtils.isEmpty(throttleBFGSFlag) 1208 || TextUtils.isEmpty(throttlePersistentFlag) 1209 || TextUtils.isEmpty(throttleMinOomAdjFlag) 1210 || TextUtils.isEmpty(throttleMaxOomAdjFlag)) { 1211 // Set defaults for all if any are not set. 1212 useThrottleDefaults = true; 1213 } else { 1214 try { 1215 mCompactThrottleSomeSome = Integer.parseInt(throttleSomeSomeFlag); 1216 mCompactThrottleSomeFull = Integer.parseInt(throttleSomeFullFlag); 1217 mCompactThrottleFullSome = Integer.parseInt(throttleFullSomeFlag); 1218 mCompactThrottleFullFull = Integer.parseInt(throttleFullFullFlag); 1219 mCompactThrottleMinOomAdj = Long.parseLong(throttleMinOomAdjFlag); 1220 mCompactThrottleMaxOomAdj = Long.parseLong(throttleMaxOomAdjFlag); 1221 } catch (NumberFormatException e) { 1222 useThrottleDefaults = true; 1223 } 1224 } 1225 1226 if (useThrottleDefaults) { 1227 mCompactThrottleSomeSome = DEFAULT_COMPACT_THROTTLE_1; 1228 mCompactThrottleSomeFull = DEFAULT_COMPACT_THROTTLE_2; 1229 mCompactThrottleFullSome = DEFAULT_COMPACT_THROTTLE_3; 1230 mCompactThrottleFullFull = DEFAULT_COMPACT_THROTTLE_4; 1231 mCompactThrottleMinOomAdj = DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ; 1232 mCompactThrottleMaxOomAdj = DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ; 1233 } 1234 } 1235 1236 @GuardedBy("mPhenotypeFlagLock") updateCompactStatsdSampleRate()1237 private void updateCompactStatsdSampleRate() { 1238 mCompactStatsdSampleRate = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1239 KEY_COMPACT_STATSD_SAMPLE_RATE, DEFAULT_STATSD_SAMPLE_RATE); 1240 mCompactStatsdSampleRate = Math.min(1.0f, Math.max(0.0f, mCompactStatsdSampleRate)); 1241 } 1242 1243 @GuardedBy("mPhenotypeFlagLock") updateFreezerStatsdSampleRate()1244 private void updateFreezerStatsdSampleRate() { 1245 mFreezerStatsdSampleRate = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1246 KEY_FREEZER_STATSD_SAMPLE_RATE, DEFAULT_STATSD_SAMPLE_RATE); 1247 mFreezerStatsdSampleRate = Math.min(1.0f, Math.max(0.0f, mFreezerStatsdSampleRate)); 1248 } 1249 1250 @GuardedBy("mPhenotypeFlagLock") updateFullRssThrottle()1251 private void updateFullRssThrottle() { 1252 mFullAnonRssThrottleKb = DeviceConfig.getLong(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1253 KEY_COMPACT_FULL_RSS_THROTTLE_KB, DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB); 1254 1255 // Don't allow negative values. 0 means don't apply the throttle. 1256 if (mFullAnonRssThrottleKb < 0) { 1257 mFullAnonRssThrottleKb = DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB; 1258 } 1259 } 1260 1261 @GuardedBy("mPhenotypeFlagLock") updateFullDeltaRssThrottle()1262 private void updateFullDeltaRssThrottle() { 1263 mFullDeltaRssThrottleKb = DeviceConfig.getLong(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1264 KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB, DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB); 1265 1266 if (mFullDeltaRssThrottleKb < 0) { 1267 mFullDeltaRssThrottleKb = DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB; 1268 } 1269 } 1270 1271 @GuardedBy("mPhenotypeFlagLock") updateProcStateThrottle()1272 private void updateProcStateThrottle() { 1273 String procStateThrottleString = DeviceConfig.getString( 1274 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_COMPACT_PROC_STATE_THROTTLE, 1275 DEFAULT_COMPACT_PROC_STATE_THROTTLE); 1276 if (!parseProcStateThrottle(procStateThrottleString)) { 1277 Slog.w(TAG_AM, "Unable to parse app compact proc state throttle \"" 1278 + procStateThrottleString + "\" falling back to default."); 1279 if (!parseProcStateThrottle(DEFAULT_COMPACT_PROC_STATE_THROTTLE)) { 1280 Slog.wtf(TAG_AM, 1281 "Unable to parse default app compact proc state throttle " 1282 + DEFAULT_COMPACT_PROC_STATE_THROTTLE); 1283 } 1284 } 1285 } 1286 1287 @GuardedBy("mPhenotypeFlagLock") updateMinOomAdjThrottle()1288 private void updateMinOomAdjThrottle() { 1289 mCompactThrottleMinOomAdj = DeviceConfig.getLong(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1290 KEY_COMPACT_THROTTLE_MIN_OOM_ADJ, DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ); 1291 1292 // Should only compact cached processes. 1293 if (mCompactThrottleMinOomAdj < ProcessList.CACHED_APP_MIN_ADJ) { 1294 mCompactThrottleMinOomAdj = DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ; 1295 } 1296 } 1297 1298 @GuardedBy("mPhenotypeFlagLock") updateMaxOomAdjThrottle()1299 private void updateMaxOomAdjThrottle() { 1300 mCompactThrottleMaxOomAdj = DeviceConfig.getLong(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, 1301 KEY_COMPACT_THROTTLE_MAX_OOM_ADJ, DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ); 1302 1303 // Should only compact cached processes. 1304 if (mCompactThrottleMaxOomAdj > ProcessList.CACHED_APP_MAX_ADJ) { 1305 mCompactThrottleMaxOomAdj = DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ; 1306 } 1307 } 1308 1309 @GuardedBy("mPhenotypeFlagLock") updateFreezerDebounceTimeout()1310 private void updateFreezerDebounceTimeout() { 1311 mFreezerDebounceTimeout = DeviceConfig.getLong( 1312 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, 1313 KEY_FREEZER_DEBOUNCE_TIMEOUT, DEFAULT_FREEZER_DEBOUNCE_TIMEOUT); 1314 1315 if (mFreezerDebounceTimeout < 0) { 1316 mFreezerDebounceTimeout = DEFAULT_FREEZER_DEBOUNCE_TIMEOUT; 1317 } 1318 Slog.d(TAG_AM, "Freezer timeout set to " + mFreezerDebounceTimeout); 1319 } 1320 1321 @GuardedBy("mPhenotypeFlagLock") updateFreezerExemptInstPkg()1322 private void updateFreezerExemptInstPkg() { 1323 mFreezerExemptInstPkg = DeviceConfig.getBoolean( 1324 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, 1325 KEY_FREEZER_EXEMPT_INST_PKG, DEFAULT_FREEZER_EXEMPT_INST_PKG); 1326 Slog.d(TAG_AM, "Freezer exemption set to " + mFreezerExemptInstPkg); 1327 } 1328 1329 @GuardedBy("mPhenotypeFlagLock") updateFreezerBinderState()1330 private void updateFreezerBinderState() { 1331 mFreezerBinderEnabled = DeviceConfig.getBoolean( 1332 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, 1333 KEY_FREEZER_BINDER_ENABLED, DEFAULT_FREEZER_BINDER_ENABLED); 1334 mFreezerBinderDivisor = DeviceConfig.getLong( 1335 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, 1336 KEY_FREEZER_BINDER_DIVISOR, DEFAULT_FREEZER_BINDER_DIVISOR); 1337 mFreezerBinderOffset = DeviceConfig.getInt( 1338 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, 1339 KEY_FREEZER_BINDER_OFFSET, DEFAULT_FREEZER_BINDER_OFFSET); 1340 mFreezerBinderThreshold = DeviceConfig.getLong( 1341 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, 1342 KEY_FREEZER_BINDER_THRESHOLD, DEFAULT_FREEZER_BINDER_THRESHOLD); 1343 mFreezerBinderCallbackEnabled = DeviceConfig.getBoolean( 1344 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, 1345 KEY_FREEZER_BINDER_CALLBACK_ENABLED, DEFAULT_FREEZER_BINDER_CALLBACK_ENABLED); 1346 mFreezerBinderCallbackThrottle = DeviceConfig.getLong( 1347 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, 1348 KEY_FREEZER_BINDER_CALLBACK_THROTTLE, DEFAULT_FREEZER_BINDER_CALLBACK_THROTTLE); 1349 mFreezerBinderAsyncThreshold = DeviceConfig.getInt( 1350 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT, 1351 KEY_FREEZER_BINDER_ASYNC_THRESHOLD, DEFAULT_FREEZER_BINDER_ASYNC_THRESHOLD); 1352 Slog.d(TAG_AM, "Freezer binder state set to enabled=" + mFreezerBinderEnabled 1353 + ", divisor=" + mFreezerBinderDivisor 1354 + ", offset=" + mFreezerBinderOffset 1355 + ", threshold=" + mFreezerBinderThreshold 1356 + ", callback enabled=" + mFreezerBinderCallbackEnabled 1357 + ", callback throttle=" + mFreezerBinderCallbackThrottle 1358 + ", async threshold=" + mFreezerBinderAsyncThreshold); 1359 } 1360 parseProcStateThrottle(String procStateThrottleString)1361 private boolean parseProcStateThrottle(String procStateThrottleString) { 1362 String[] procStates = TextUtils.split(procStateThrottleString, ","); 1363 mProcStateThrottle.clear(); 1364 for (String procState : procStates) { 1365 try { 1366 mProcStateThrottle.add(Integer.parseInt(procState)); 1367 } catch (NumberFormatException e) { 1368 Slog.e(TAG_AM, "Failed to parse default app compaction proc state: " 1369 + procState); 1370 return false; 1371 } 1372 } 1373 return true; 1374 } 1375 1376 /** 1377 * Returns the earliest time (relative) from now that the app can be frozen. 1378 * @param app The app to update 1379 * @param delayMillis How much to delay freezing by 1380 */ 1381 @GuardedBy("mProcLock") updateEarliestFreezableTime(ProcessRecord app, long delayMillis)1382 private long updateEarliestFreezableTime(ProcessRecord app, long delayMillis) { 1383 final long now = SystemClock.uptimeMillis(); 1384 app.mOptRecord.setEarliestFreezableTime( 1385 Math.max(app.mOptRecord.getEarliestFreezableTime(), now + delayMillis)); 1386 return app.mOptRecord.getEarliestFreezableTime() - now; 1387 } 1388 1389 // This will ensure app will be out of the freezer for at least mFreezerDebounceTimeout. 1390 @GuardedBy("mAm") unfreezeTemporarily(ProcessRecord app, @UnfreezeReason int reason)1391 void unfreezeTemporarily(ProcessRecord app, @UnfreezeReason int reason) { 1392 unfreezeTemporarily(app, reason, mFreezerDebounceTimeout); 1393 } 1394 1395 // This will ensure app will be out of the freezer for at least mFreezerDebounceTimeout. 1396 @GuardedBy("mAm") unfreezeTemporarily(ProcessRecord app, @UnfreezeReason int reason, long delayMillis)1397 void unfreezeTemporarily(ProcessRecord app, @UnfreezeReason int reason, long delayMillis) { 1398 if (mUseFreezer) { 1399 synchronized (mProcLock) { 1400 // Move the earliest freezable time further, if necessary 1401 final long delay = updateEarliestFreezableTime(app, delayMillis); 1402 if (app.mOptRecord.isFrozen() || app.mOptRecord.isPendingFreeze()) { 1403 unfreezeAppLSP(app, reason); 1404 freezeAppAsyncLSP(app, delay); 1405 } 1406 } 1407 } 1408 } 1409 1410 @GuardedBy({"mAm", "mProcLock"}) freezeAppAsyncLSP(ProcessRecord app)1411 void freezeAppAsyncLSP(ProcessRecord app) { 1412 freezeAppAsyncLSP(app, updateEarliestFreezableTime(app, mFreezerDebounceTimeout)); 1413 } 1414 1415 @GuardedBy({"mAm", "mProcLock"}) freezeAppAsyncLSP(ProcessRecord app, @UptimeMillisLong long delayMillis)1416 private void freezeAppAsyncLSP(ProcessRecord app, @UptimeMillisLong long delayMillis) { 1417 freezeAppAsyncInternalLSP(app, delayMillis, false); 1418 } 1419 1420 @GuardedBy({"mAm", "mProcLock"}) freezeAppAsyncInternalLSP(ProcessRecord app, @UptimeMillisLong long delayMillis, boolean force)1421 void freezeAppAsyncInternalLSP(ProcessRecord app, @UptimeMillisLong long delayMillis, 1422 boolean force) { 1423 final ProcessCachedOptimizerRecord opt = app.mOptRecord; 1424 if (opt.isPendingFreeze()) { 1425 // Skip redundant DO_FREEZE message 1426 return; 1427 } 1428 1429 if (opt.isFreezeSticky() && !force) { 1430 if (DEBUG_FREEZER) { 1431 Slog.d(TAG_AM, 1432 "Skip freezing because unfrozen state is sticky pid=" + app.getPid() + " " 1433 + app.processName); 1434 } 1435 return; 1436 } 1437 1438 if (mAm.mConstants.USE_MODERN_TRIM 1439 && app.mState.getSetAdj() >= ProcessList.CACHED_APP_MIN_ADJ) { 1440 final IApplicationThread thread = app.getThread(); 1441 if (thread != null) { 1442 try { 1443 thread.scheduleTrimMemory(TRIM_MEMORY_BACKGROUND); 1444 } catch (RemoteException e) { 1445 // do nothing 1446 } 1447 } 1448 } 1449 reportProcessFreezableChangedLocked(app); 1450 app.mOptRecord.setLastUsedTimeout(delayMillis); 1451 mFreezeHandler.sendMessageDelayed( 1452 mFreezeHandler.obtainMessage(SET_FROZEN_PROCESS_MSG, DO_FREEZE, 0, app), 1453 delayMillis); 1454 opt.setPendingFreeze(true); 1455 if (DEBUG_FREEZER) { 1456 Slog.d(TAG_AM, "Async freezing " + app.getPid() + " " + app.processName); 1457 } 1458 } 1459 1460 @GuardedBy({"mAm", "mProcLock", "mFreezerLock"}) unfreezeAppInternalLSP(ProcessRecord app, @UnfreezeReason int reason, boolean force)1461 void unfreezeAppInternalLSP(ProcessRecord app, @UnfreezeReason int reason, boolean force) { 1462 final int pid = app.getPid(); 1463 final ProcessCachedOptimizerRecord opt = app.mOptRecord; 1464 boolean sticky = opt.isFreezeSticky(); 1465 if (sticky && !force) { 1466 // Sticky freezes will not change their state unless forced out of it. 1467 if (DEBUG_FREEZER) { 1468 Slog.d(TAG_AM, 1469 "Skip unfreezing because frozen state is sticky pid=" + pid + " " 1470 + app.processName); 1471 } 1472 return; 1473 } 1474 if (opt.isPendingFreeze()) { 1475 // Remove pending DO_FREEZE message 1476 mFreezeHandler.removeMessages(SET_FROZEN_PROCESS_MSG, app); 1477 opt.setPendingFreeze(false); 1478 if (DEBUG_FREEZER) { 1479 Slog.d(TAG_AM, "Cancel freezing " + pid + " " + app.processName); 1480 } 1481 } 1482 1483 UidRecord uidRec = app.getUidRecord(); 1484 if (uidRec != null && uidRec.isFrozen()) { 1485 uidRec.setFrozen(false); 1486 postUidFrozenMessage(uidRec.getUid(), false); 1487 } 1488 reportProcessFreezableChangedLocked(app); 1489 1490 opt.setFreezerOverride(false); 1491 if (pid == 0 || !opt.isFrozen()) { 1492 return; 1493 } 1494 1495 // Unfreeze the binder interface first, to avoid transactions triggered by timers fired 1496 // right after unfreezing the process to fail 1497 boolean processKilled = false; 1498 1499 try { 1500 int freezeInfo = getBinderFreezeInfo(pid); 1501 1502 if ((freezeInfo & SYNC_RECEIVED_WHILE_FROZEN) != 0) { 1503 Slog.d(TAG_AM, "pid " + pid + " " + app.processName 1504 + " received sync transactions while frozen, killing"); 1505 app.killLocked("Sync transaction while in frozen state", 1506 ApplicationExitInfo.REASON_FREEZER, 1507 ApplicationExitInfo.SUBREASON_FREEZER_BINDER_TRANSACTION, true); 1508 processKilled = true; 1509 } 1510 1511 if ((freezeInfo & ASYNC_RECEIVED_WHILE_FROZEN) != 0 && DEBUG_FREEZER) { 1512 Slog.d(TAG_AM, "pid " + pid + " " + app.processName 1513 + " received async transactions while frozen"); 1514 } 1515 } catch (Exception e) { 1516 Slog.d(TAG_AM, "Unable to query binder frozen info for pid " + pid + " " 1517 + app.processName + ". Killing it. Exception: " + e); 1518 app.killLocked("Unable to query binder frozen stats", 1519 ApplicationExitInfo.REASON_FREEZER, 1520 ApplicationExitInfo.SUBREASON_FREEZER_BINDER_IOCTL, true); 1521 processKilled = true; 1522 } 1523 1524 if (processKilled) { 1525 return; 1526 } 1527 1528 long freezeTime = opt.getFreezeUnfreezeTime(); 1529 1530 try { 1531 freezeBinder(pid, false, FREEZE_BINDER_TIMEOUT_MS); 1532 } catch (RuntimeException e) { 1533 Slog.e(TAG_AM, "Unable to unfreeze binder for " + pid + " " + app.processName 1534 + ". Killing it"); 1535 app.killLocked("Unable to unfreeze", 1536 ApplicationExitInfo.REASON_FREEZER, 1537 ApplicationExitInfo.SUBREASON_FREEZER_BINDER_IOCTL, true); 1538 return; 1539 } 1540 1541 try { 1542 traceAppFreeze(app.processName, pid, reason); 1543 Process.setProcessFrozen(pid, app.uid, false); 1544 1545 opt.setFreezeUnfreezeTime(SystemClock.uptimeMillis()); 1546 opt.setFrozen(false); 1547 mFrozenProcesses.delete(pid); 1548 } catch (Exception e) { 1549 Slog.e(TAG_AM, "Unable to unfreeze " + pid + " " + app.processName 1550 + ". This might cause inconsistency or UI hangs."); 1551 } 1552 1553 if (!opt.isFrozen()) { 1554 Slog.d(TAG_AM, "sync unfroze " + pid + " " + app.processName + " for " + reason); 1555 1556 mFreezeHandler.sendMessage( 1557 mFreezeHandler.obtainMessage(REPORT_UNFREEZE_MSG, 1558 pid, 1559 (int) Math.min(opt.getFreezeUnfreezeTime() - freezeTime, Integer.MAX_VALUE), 1560 new Pair<ProcessRecord, Integer>(app, reason))); 1561 } 1562 } 1563 1564 @GuardedBy({"mAm", "mProcLock"}) unfreezeAppLSP(ProcessRecord app, @UnfreezeReason int reason)1565 void unfreezeAppLSP(ProcessRecord app, @UnfreezeReason int reason) { 1566 synchronized (mFreezerLock) { 1567 unfreezeAppInternalLSP(app, reason, false); 1568 } 1569 } 1570 1571 /** 1572 * This quick function works around the race condition between WM/ATMS and AMS, allowing 1573 * the former to directly unfreeze a frozen process before the latter runs updateOomAdj. 1574 * After the race issue is solved, this workaround can be removed. (b/213288355) 1575 * The caller of this function should still trigger updateOomAdj for AMS to unfreeze the app. 1576 * @param pid pid of the process to be unfrozen 1577 */ unfreezeProcess(int pid, @OomAdjReason int reason)1578 void unfreezeProcess(int pid, @OomAdjReason int reason) { 1579 synchronized (mFreezerLock) { 1580 ProcessRecord app = mFrozenProcesses.get(pid); 1581 if (app == null) { 1582 return; 1583 } 1584 Slog.d(TAG_AM, "quick sync unfreeze " + pid + " for " + reason); 1585 try { 1586 freezeBinder(pid, false, FREEZE_BINDER_TIMEOUT_MS); 1587 } catch (RuntimeException e) { 1588 Slog.e(TAG_AM, "Unable to quick unfreeze binder for " + pid); 1589 return; 1590 } 1591 1592 try { 1593 traceAppFreeze(app.processName, pid, reason); 1594 Process.setProcessFrozen(pid, app.uid, false); 1595 } catch (Exception e) { 1596 Slog.e(TAG_AM, "Unable to quick unfreeze " + pid); 1597 } 1598 } 1599 } 1600 1601 /** 1602 * Trace app freeze status 1603 * @param processName The name of the target process 1604 * @param pid The pid of the target process 1605 * @param reason UNFREEZE_REASON_XXX (>=0) for unfreezing and -1 for freezing 1606 */ traceAppFreeze(String processName, int pid, int reason)1607 private static void traceAppFreeze(String processName, int pid, int reason) { 1608 Trace.instantForTrack(Trace.TRACE_TAG_ACTIVITY_MANAGER, ATRACE_FREEZER_TRACK, 1609 (reason < 0 ? "Freeze " : "Unfreeze ") + processName + ":" + pid + " " + reason); 1610 } 1611 1612 /** 1613 * To be called when the given app is killed. 1614 */ 1615 @GuardedBy({"mAm", "mProcLock"}) onCleanupApplicationRecordLocked(ProcessRecord app)1616 void onCleanupApplicationRecordLocked(ProcessRecord app) { 1617 if (mUseFreezer) { 1618 final ProcessCachedOptimizerRecord opt = app.mOptRecord; 1619 if (opt.isPendingFreeze()) { 1620 // Remove pending DO_FREEZE message 1621 mFreezeHandler.removeMessages(SET_FROZEN_PROCESS_MSG, app); 1622 opt.setPendingFreeze(false); 1623 } 1624 1625 final UidRecord uidRec = app.getUidRecord(); 1626 if (uidRec != null) { 1627 final boolean isFrozen = uidRec.getNumOfProcs() > 1 1628 && uidRec.areAllProcessesFrozen(app); 1629 if (isFrozen != uidRec.isFrozen()) { 1630 uidRec.setFrozen(isFrozen); 1631 postUidFrozenMessage(uidRec.getUid(), isFrozen); 1632 } 1633 } 1634 1635 mFrozenProcesses.delete(app.getPid()); 1636 } 1637 } 1638 onWakefulnessChanged(int wakefulness)1639 void onWakefulnessChanged(int wakefulness) { 1640 if(wakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE) { 1641 // Remove any pending compaction we may have scheduled to happen while screen was off 1642 Slog.e(TAG_AM, "Cancel pending or running compactions as system is awake"); 1643 cancelAllCompactions(CancelCompactReason.SCREEN_ON); 1644 } 1645 } 1646 cancelAllCompactions(CancelCompactReason reason)1647 void cancelAllCompactions(CancelCompactReason reason) { 1648 synchronized (mProcLock) { 1649 while(!mPendingCompactionProcesses.isEmpty()) { 1650 cancelCompactionForProcess(mPendingCompactionProcesses.get(0), reason); 1651 } 1652 mPendingCompactionProcesses.clear(); 1653 } 1654 } 1655 1656 @GuardedBy("mProcLock") cancelCompactionForProcess(ProcessRecord app, CancelCompactReason cancelReason)1657 void cancelCompactionForProcess(ProcessRecord app, CancelCompactReason cancelReason) { 1658 boolean cancelled = false; 1659 if (mPendingCompactionProcesses.contains(app)) { 1660 app.mOptRecord.setHasPendingCompact(false); 1661 mPendingCompactionProcesses.remove(app); 1662 cancelled = true; 1663 } 1664 if (DefaultProcessDependencies.mPidCompacting == app.mPid) { 1665 cancelCompaction(); 1666 cancelled = true; 1667 } 1668 if (cancelled) { 1669 if (mTotalCompactionsCancelled.containsKey(cancelReason)) { 1670 int count = mTotalCompactionsCancelled.get(cancelReason); 1671 mTotalCompactionsCancelled.put(cancelReason, count + 1); 1672 } else { 1673 mTotalCompactionsCancelled.put(cancelReason, 1); 1674 } 1675 if (DEBUG_COMPACTION) { 1676 Slog.d(TAG_AM, 1677 "Cancelled pending or running compactions for process: " + 1678 app.processName != null ? app.processName : "" + 1679 " reason: " + cancelReason.name()); 1680 } 1681 } 1682 } 1683 1684 @GuardedBy({"mService", "mProcLock"}) onOomAdjustChanged(int oldAdj, int newAdj, ProcessRecord app)1685 void onOomAdjustChanged(int oldAdj, int newAdj, ProcessRecord app) { 1686 if (useCompaction()) { 1687 // Cancel any currently executing compactions 1688 // if the process moved out of cached state 1689 if (newAdj < oldAdj && newAdj < ProcessList.CACHED_APP_MIN_ADJ) { 1690 cancelCompactionForProcess(app, CancelCompactReason.OOM_IMPROVEMENT); 1691 } 1692 } 1693 } 1694 1695 /** 1696 * Callback received after a process has been frozen. 1697 */ onProcessFrozen(ProcessRecord frozenProc)1698 void onProcessFrozen(ProcessRecord frozenProc) { 1699 if (useCompaction()) { 1700 synchronized (mProcLock) { 1701 compactApp(frozenProc, CompactProfile.FULL, CompactSource.APP, false); 1702 } 1703 } 1704 } 1705 1706 /** 1707 * Computes the final compaction profile to be used which depends on compaction 1708 * features enabled and swap usage. 1709 */ resolveCompactionProfile(CompactProfile profile)1710 CompactProfile resolveCompactionProfile(CompactProfile profile) { 1711 if (profile == CompactProfile.FULL) { 1712 double swapFreePercent = getFreeSwapPercent(); 1713 // Downgrade compaction under swap memory pressure 1714 if (swapFreePercent < COMPACT_DOWNGRADE_FREE_SWAP_THRESHOLD) { 1715 profile = CompactProfile.SOME; 1716 1717 ++mTotalCompactionDowngrades; 1718 if (DEBUG_COMPACTION) { 1719 Slog.d(TAG_AM, 1720 "Downgraded compaction to "+ profile +" due to low swap." 1721 + " Swap Free% " + swapFreePercent); 1722 } 1723 } 1724 } 1725 1726 if (!ENABLE_FILE_COMPACT) { 1727 if (profile == CompactProfile.SOME) { 1728 profile = CompactProfile.NONE; 1729 } else if (profile == CompactProfile.FULL) { 1730 profile = CompactProfile.ANON; 1731 } 1732 if (DEBUG_COMPACTION) { 1733 Slog.d(TAG_AM, 1734 "Final compaction profile "+ profile +" due to file compact disabled"); 1735 } 1736 } 1737 1738 return profile; 1739 } 1740 isProcessFrozen(int pid)1741 boolean isProcessFrozen(int pid) { 1742 synchronized (mProcLock) { 1743 return mFrozenProcesses.contains(pid); 1744 } 1745 } 1746 1747 @VisibleForTesting 1748 static final class SingleCompactionStats { 1749 private static final float STATSD_SAMPLE_RATE = 0.1f; 1750 private static final Random mRandom = new Random(); 1751 private final long[] mRssAfterCompaction; 1752 public CompactSource mSourceType; 1753 public String mProcessName; 1754 public final int mUid; 1755 public long mDeltaAnonRssKBs; 1756 public long mZramConsumedKBs; 1757 public long mAnonMemFreedKBs; 1758 public float mCpuTimeMillis; 1759 public long mOrigAnonRss; 1760 public int mProcState; 1761 public int mOomAdj; 1762 public @OomAdjReason int mOomAdjReason; 1763 SingleCompactionStats(long[] rss, CompactSource source, String processName, long deltaAnonRss, long zramConsumed, long anonMemFreed, long origAnonRss, long cpuTimeMillis, int procState, int oomAdj, @OomAdjReason int oomAdjReason, int uid)1764 SingleCompactionStats(long[] rss, CompactSource source, String processName, 1765 long deltaAnonRss, long zramConsumed, long anonMemFreed, long origAnonRss, 1766 long cpuTimeMillis, int procState, int oomAdj, 1767 @OomAdjReason int oomAdjReason, int uid) { 1768 mRssAfterCompaction = rss; 1769 mSourceType = source; 1770 mProcessName = processName; 1771 mUid = uid; 1772 mDeltaAnonRssKBs = deltaAnonRss; 1773 mZramConsumedKBs = zramConsumed; 1774 mAnonMemFreedKBs = anonMemFreed; 1775 mCpuTimeMillis = cpuTimeMillis; 1776 mOrigAnonRss = origAnonRss; 1777 mProcState = procState; 1778 mOomAdj = oomAdj; 1779 mOomAdjReason = oomAdjReason; 1780 } 1781 getCompactEfficiency()1782 double getCompactEfficiency() { return mAnonMemFreedKBs / (double) mOrigAnonRss; } 1783 getCompactCost()1784 double getCompactCost() { 1785 // mCpuTimeMillis / (anonMemFreedKBs/1024) and metric is in (ms/MB) 1786 return mCpuTimeMillis / (double) mAnonMemFreedKBs * 1024; 1787 } 1788 getRssAfterCompaction()1789 long[] getRssAfterCompaction() { 1790 return mRssAfterCompaction; 1791 } 1792 dump(PrintWriter pw)1793 void dump(PrintWriter pw) { 1794 pw.println(" (" + mProcessName + "," + mSourceType.name() + "," + mDeltaAnonRssKBs 1795 + "," + mZramConsumedKBs + "," + mAnonMemFreedKBs + "," + getCompactEfficiency() 1796 + "," + getCompactCost() + "," + mProcState + "," + mOomAdj + "," 1797 + OomAdjuster.oomAdjReasonToString(mOomAdjReason) + ")"); 1798 } 1799 sendStat()1800 void sendStat() { 1801 if (mRandom.nextFloat() < STATSD_SAMPLE_RATE) { 1802 FrameworkStatsLog.write(FrameworkStatsLog.APP_COMPACTED_V2, mUid, mProcState, 1803 mOomAdj, mDeltaAnonRssKBs, mZramConsumedKBs, mCpuTimeMillis, mOrigAnonRss, 1804 mOomAdjReason); 1805 } 1806 } 1807 } 1808 1809 private final class MemCompactionHandler extends Handler { MemCompactionHandler()1810 private MemCompactionHandler() { 1811 super(mCachedAppOptimizerThread.getLooper()); 1812 } 1813 shouldOomAdjThrottleCompaction(ProcessRecord proc)1814 private boolean shouldOomAdjThrottleCompaction(ProcessRecord proc) { 1815 final String name = proc.processName; 1816 1817 // don't compact if the process has returned to perceptible 1818 // and this is only a cached/home/prev compaction 1819 if (proc.mState.getSetAdj() <= ProcessList.PERCEPTIBLE_APP_ADJ) { 1820 if (DEBUG_COMPACTION) { 1821 Slog.d(TAG_AM, 1822 "Skipping compaction as process " + name + " is " 1823 + "now perceptible."); 1824 } 1825 return true; 1826 } 1827 1828 return false; 1829 } 1830 shouldTimeThrottleCompaction(ProcessRecord proc, long start, CompactProfile pendingProfile, CompactSource source)1831 private boolean shouldTimeThrottleCompaction(ProcessRecord proc, long start, 1832 CompactProfile pendingProfile, CompactSource source) { 1833 final ProcessCachedOptimizerRecord opt = proc.mOptRecord; 1834 final String name = proc.processName; 1835 1836 CompactProfile lastCompactProfile = opt.getLastCompactProfile(); 1837 long lastCompactTime = opt.getLastCompactTime(); 1838 1839 // basic throttling 1840 // use the Phenotype flag knobs to determine whether current/previous 1841 // compaction combo should be throttled or not. 1842 // Note that we explicitly don't take mPhenotypeFlagLock here as the flags 1843 // should very seldom change, and taking the risk of using the wrong action is 1844 // preferable to taking the lock for every single compaction action. 1845 if (lastCompactTime != 0) { 1846 if (source == CompactSource.APP) { 1847 if (pendingProfile == CompactProfile.SOME) { 1848 if ((lastCompactProfile == CompactProfile.SOME 1849 && (start - lastCompactTime < mCompactThrottleSomeSome)) 1850 || (lastCompactProfile == CompactProfile.FULL 1851 && (start - lastCompactTime < mCompactThrottleSomeFull))) { 1852 if (DEBUG_COMPACTION) { 1853 Slog.d(TAG_AM, 1854 "Skipping some compaction for " + name 1855 + ": too soon. throttle=" + mCompactThrottleSomeSome 1856 + "/" + mCompactThrottleSomeFull 1857 + " last=" + (start - lastCompactTime) + "ms ago"); 1858 } 1859 return true; 1860 } 1861 } else if (pendingProfile == CompactProfile.FULL) { 1862 if ((lastCompactProfile == CompactProfile.SOME 1863 && (start - lastCompactTime < mCompactThrottleFullSome)) 1864 || (lastCompactProfile == CompactProfile.FULL 1865 && (start - lastCompactTime < mCompactThrottleFullFull))) { 1866 if (DEBUG_COMPACTION) { 1867 Slog.d(TAG_AM, 1868 "Skipping full compaction for " + name 1869 + ": too soon. throttle=" + mCompactThrottleFullSome 1870 + "/" + mCompactThrottleFullFull 1871 + " last=" + (start - lastCompactTime) + "ms ago"); 1872 } 1873 return true; 1874 } 1875 } 1876 } 1877 } 1878 1879 return false; 1880 } 1881 shouldThrottleMiscCompaction(ProcessRecord proc, int procState)1882 private boolean shouldThrottleMiscCompaction(ProcessRecord proc, int procState) { 1883 if (mProcStateThrottle.contains(procState)) { 1884 if (DEBUG_COMPACTION) { 1885 final String name = proc.processName; 1886 Slog.d(TAG_AM, 1887 "Skipping full compaction for process " + name + "; proc state is " 1888 + procState); 1889 } 1890 return true; 1891 } 1892 1893 return false; 1894 } 1895 shouldRssThrottleCompaction( CompactProfile profile, int pid, String name, long[] rssBefore)1896 private boolean shouldRssThrottleCompaction( 1897 CompactProfile profile, int pid, String name, long[] rssBefore) { 1898 long anonRssBefore = rssBefore[RSS_ANON_INDEX]; 1899 SingleCompactionStats lastCompactionStats = mLastCompactionStats.get(pid); 1900 1901 if (rssBefore[RSS_TOTAL_INDEX] == 0 && rssBefore[RSS_FILE_INDEX] == 0 1902 && rssBefore[RSS_ANON_INDEX] == 0 && rssBefore[RSS_SWAP_INDEX] == 0) { 1903 if (DEBUG_COMPACTION) { 1904 Slog.d(TAG_AM, 1905 "Skipping compaction for" 1906 + "process " + pid + " with no memory usage. Dead?"); 1907 } 1908 return true; 1909 } 1910 1911 if (profile == CompactProfile.FULL) { 1912 if (mFullAnonRssThrottleKb > 0L && anonRssBefore < mFullAnonRssThrottleKb) { 1913 if (DEBUG_COMPACTION) { 1914 Slog.d(TAG_AM, 1915 "Skipping full compaction for process " + name 1916 + "; anon RSS is too small: " + anonRssBefore + "KB."); 1917 } 1918 return true; 1919 } 1920 1921 if (lastCompactionStats != null && mFullDeltaRssThrottleKb > 0L) { 1922 long[] lastRss = lastCompactionStats.getRssAfterCompaction(); 1923 long absDelta = Math.abs(rssBefore[RSS_FILE_INDEX] - lastRss[RSS_FILE_INDEX]) 1924 + Math.abs(rssBefore[RSS_ANON_INDEX] - lastRss[RSS_ANON_INDEX]) 1925 + Math.abs(rssBefore[RSS_SWAP_INDEX] - lastRss[RSS_SWAP_INDEX]); 1926 if (absDelta <= mFullDeltaRssThrottleKb) { 1927 if (DEBUG_COMPACTION) { 1928 Slog.d(TAG_AM, 1929 "Skipping full compaction for process " + name 1930 + "; abs delta is too small: " + absDelta + "KB."); 1931 } 1932 return true; 1933 } 1934 } 1935 } 1936 1937 return false; 1938 } 1939 1940 @Override handleMessage(Message msg)1941 public void handleMessage(Message msg) { 1942 switch (msg.what) { 1943 case COMPACT_PROCESS_MSG: { 1944 long start = SystemClock.uptimeMillis(); 1945 ProcessRecord proc; 1946 final ProcessCachedOptimizerRecord opt; 1947 int pid; 1948 final String name; 1949 CompactProfile lastCompactProfile; 1950 long lastCompactTime; 1951 int newOomAdj = msg.arg1; 1952 int procState = msg.arg2; 1953 boolean forceCompaction; 1954 CompactSource compactSource; 1955 CompactProfile requestedProfile; 1956 int oomAdjReason; 1957 synchronized (mProcLock) { 1958 if (mPendingCompactionProcesses.isEmpty()) { 1959 if (DEBUG_COMPACTION) { 1960 Slog.d(TAG_AM, "No processes pending compaction, bail out"); 1961 } 1962 return; 1963 } 1964 proc = mPendingCompactionProcesses.remove(0); 1965 opt = proc.mOptRecord; 1966 forceCompaction = opt.isForceCompact(); 1967 opt.setForceCompact(false); // since this is a one-shot operation 1968 pid = proc.getPid(); 1969 name = proc.processName; 1970 opt.setHasPendingCompact(false); 1971 compactSource = opt.getReqCompactSource(); 1972 requestedProfile = opt.getReqCompactProfile(); 1973 lastCompactProfile = opt.getLastCompactProfile(); 1974 lastCompactTime = opt.getLastCompactTime(); 1975 oomAdjReason = opt.getLastOomAdjChangeReason(); 1976 } 1977 1978 AggregatedSourceCompactionStats perSourceStats = 1979 getPerSourceAggregatedCompactStat(opt.getReqCompactSource()); 1980 AggregatedProcessCompactionStats perProcessStats = 1981 getPerProcessAggregatedCompactStat(name); 1982 1983 long[] rssBefore; 1984 if (pid == 0) { 1985 // not a real process, either one being launched or one being killed 1986 if (DEBUG_COMPACTION) { 1987 Slog.d(TAG_AM, "Compaction failed, pid is 0"); 1988 } 1989 ++perSourceStats.mProcCompactionsNoPidThrottled; 1990 ++perProcessStats.mProcCompactionsNoPidThrottled; 1991 return; 1992 } 1993 1994 if (!forceCompaction) { 1995 if (shouldOomAdjThrottleCompaction(proc)) { 1996 ++perProcessStats.mProcCompactionsOomAdjThrottled; 1997 ++perSourceStats.mProcCompactionsOomAdjThrottled; 1998 return; 1999 } 2000 if (shouldTimeThrottleCompaction( 2001 proc, start, requestedProfile, compactSource)) { 2002 ++perProcessStats.mProcCompactionsTimeThrottled; 2003 ++perSourceStats.mProcCompactionsTimeThrottled; 2004 return; 2005 } 2006 if (shouldThrottleMiscCompaction(proc, procState)) { 2007 ++perProcessStats.mProcCompactionsMiscThrottled; 2008 ++perSourceStats.mProcCompactionsMiscThrottled; 2009 return; 2010 } 2011 rssBefore = mProcessDependencies.getRss(pid); 2012 if (shouldRssThrottleCompaction(requestedProfile, pid, name, rssBefore)) { 2013 ++perProcessStats.mProcCompactionsRSSThrottled; 2014 ++perSourceStats.mProcCompactionsRSSThrottled; 2015 return; 2016 } 2017 } else { 2018 rssBefore = mProcessDependencies.getRss(pid); 2019 if (DEBUG_COMPACTION) { 2020 Slog.d(TAG_AM, "Forcing compaction for " + name); 2021 } 2022 } 2023 2024 CompactProfile resolvedProfile = 2025 resolveCompactionProfile(requestedProfile); 2026 if (resolvedProfile == CompactProfile.NONE) { 2027 // No point on issuing compaction call as we don't want to compact. 2028 if (DEBUG_COMPACTION) { 2029 Slog.d(TAG_AM, "Resolved no compaction for "+ name + 2030 " requested profile="+requestedProfile); 2031 } 2032 return; 2033 } 2034 2035 try { 2036 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, 2037 "Compact " + resolvedProfile.name() + ": " + name 2038 + " lastOomAdjReason: " + oomAdjReason 2039 + " source: " + compactSource.name()); 2040 long zramUsedKbBefore = getUsedZramMemory(); 2041 long startCpuTime = threadCpuTimeNs(); 2042 mProcessDependencies.performCompaction(resolvedProfile, pid); 2043 long endCpuTime = threadCpuTimeNs(); 2044 long[] rssAfter = mProcessDependencies.getRss(pid); 2045 long end = SystemClock.uptimeMillis(); 2046 long time = end - start; 2047 long deltaCpuTimeNanos = endCpuTime - startCpuTime; 2048 long zramUsedKbAfter = getUsedZramMemory(); 2049 long deltaTotalRss = rssAfter[RSS_TOTAL_INDEX] - rssBefore[RSS_TOTAL_INDEX]; 2050 long deltaFileRss = rssAfter[RSS_FILE_INDEX] - rssBefore[RSS_FILE_INDEX]; 2051 long deltaAnonRss = rssAfter[RSS_ANON_INDEX] - rssBefore[RSS_ANON_INDEX]; 2052 long deltaSwapRss = rssAfter[RSS_SWAP_INDEX] - rssBefore[RSS_SWAP_INDEX]; 2053 switch (opt.getReqCompactProfile()) { 2054 case SOME: 2055 ++perSourceStats.mSomeCompactPerformed; 2056 ++perProcessStats.mSomeCompactPerformed; 2057 break; 2058 case FULL: 2059 ++perSourceStats.mFullCompactPerformed; 2060 ++perProcessStats.mFullCompactPerformed; 2061 long anonRssSavings = -deltaAnonRss; 2062 long zramConsumed = zramUsedKbAfter - zramUsedKbBefore; 2063 long memFreed = anonRssSavings - zramConsumed; 2064 long totalCpuTimeMillis = deltaCpuTimeNanos / 1000000; 2065 long origAnonRss = rssBefore[RSS_ANON_INDEX]; 2066 2067 // Negative stats would skew averages and will likely be due to 2068 // noise of system doing other things so we put a floor at 0 to 2069 // avoid negative values. 2070 anonRssSavings = anonRssSavings > 0 ? anonRssSavings : 0; 2071 zramConsumed = zramConsumed > 0 ? zramConsumed : 0; 2072 memFreed = memFreed > 0 ? memFreed : 0; 2073 2074 perProcessStats.addMemStats(anonRssSavings, zramConsumed, memFreed, 2075 origAnonRss, totalCpuTimeMillis); 2076 perSourceStats.addMemStats(anonRssSavings, zramConsumed, memFreed, 2077 origAnonRss, totalCpuTimeMillis); 2078 SingleCompactionStats memStats = new SingleCompactionStats(rssAfter, 2079 compactSource, name, anonRssSavings, zramConsumed, memFreed, 2080 origAnonRss, totalCpuTimeMillis, procState, newOomAdj, 2081 oomAdjReason, proc.uid); 2082 mLastCompactionStats.remove(pid); 2083 mLastCompactionStats.put(pid, memStats); 2084 mCompactionStatsHistory.add(memStats); 2085 if (!forceCompaction) { 2086 // Avoid polluting field metrics with forced compactions. 2087 memStats.sendStat(); 2088 } 2089 break; 2090 default: 2091 // We likely missed adding this category, it needs to be added 2092 // if we end up here. In the meantime, gracefully fallback to 2093 // attribute to app. 2094 Slog.wtf(TAG_AM, "Compaction: Unknown requested action"); 2095 return; 2096 } 2097 EventLog.writeEvent(EventLogTags.AM_COMPACT, pid, name, 2098 resolvedProfile.name(), rssBefore[RSS_TOTAL_INDEX], 2099 rssBefore[RSS_FILE_INDEX], rssBefore[RSS_ANON_INDEX], 2100 rssBefore[RSS_SWAP_INDEX], deltaTotalRss, deltaFileRss, 2101 deltaAnonRss, deltaSwapRss, time, lastCompactProfile.name(), 2102 lastCompactTime, newOomAdj, procState, zramUsedKbBefore, 2103 zramUsedKbBefore - zramUsedKbAfter); 2104 synchronized (mProcLock) { 2105 opt.setLastCompactTime(end); 2106 opt.setLastCompactProfile(requestedProfile); 2107 } 2108 } catch (Exception e) { 2109 // nothing to do, presumably the process died 2110 Slog.d(TAG_AM, 2111 "Exception occurred while compacting pid: " + name 2112 + ". Exception:" + e.getMessage()); 2113 } finally { 2114 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 2115 } 2116 break; 2117 } 2118 case COMPACT_SYSTEM_MSG: { 2119 ++mSystemCompactionsPerformed; 2120 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "compactSystem"); 2121 long memFreedBefore = getMemoryFreedCompaction(); 2122 compactSystem(); 2123 long memFreedAfter = getMemoryFreedCompaction(); 2124 mSystemTotalMemFreed += memFreedAfter - memFreedBefore; 2125 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 2126 break; 2127 } 2128 case COMPACT_NATIVE_MSG: { 2129 int pid = msg.arg1; 2130 CompactProfile compactProfile = CompactProfile.values()[msg.arg2]; 2131 Slog.d(TAG_AM, 2132 "Performing native compaction for pid=" + pid 2133 + " type=" + compactProfile.name()); 2134 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "compactSystem"); 2135 try { 2136 mProcessDependencies.performCompaction(compactProfile, pid); 2137 } catch (Exception e) { 2138 Slog.d(TAG_AM, "Failed compacting native pid= " + pid); 2139 } 2140 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 2141 break; 2142 } 2143 } 2144 } 2145 } 2146 reportOneUidFrozenStateChanged(int uid, boolean frozen)2147 private void reportOneUidFrozenStateChanged(int uid, boolean frozen) { 2148 final int[] uids = new int[1]; 2149 final int[] frozenStates = new int[1]; 2150 2151 uids[0] = uid; 2152 frozenStates[0] = frozen ? UID_FROZEN_STATE_FROZEN : UID_FROZEN_STATE_UNFROZEN; 2153 2154 if (DEBUG_FREEZER) { 2155 Slog.d(TAG_AM, "reportOneUidFrozenStateChanged uid " + uid + " frozen = " + frozen); 2156 } 2157 2158 mAm.reportUidFrozenStateChanged(uids, frozenStates); 2159 } 2160 postUidFrozenMessage(int uid, boolean frozen)2161 private void postUidFrozenMessage(int uid, boolean frozen) { 2162 final Integer uidObj = Integer.valueOf(uid); 2163 mFreezeHandler.removeEqualMessages(UID_FROZEN_STATE_CHANGED_MSG, uidObj); 2164 2165 final int op = frozen ? 1 : 0; 2166 mFreezeHandler.sendMessage(mFreezeHandler.obtainMessage(UID_FROZEN_STATE_CHANGED_MSG, op, 2167 0, uidObj)); 2168 } 2169 2170 @GuardedBy("mAm") reportProcessFreezableChangedLocked(ProcessRecord app)2171 private void reportProcessFreezableChangedLocked(ProcessRecord app) { 2172 mAm.onProcessFreezableChangedLocked(app); 2173 } 2174 2175 private final class FreezeHandler extends Handler implements 2176 ProcLocksReader.ProcLocksReaderCallback { FreezeHandler()2177 private FreezeHandler() { 2178 super(mCachedAppOptimizerThread.getLooper()); 2179 } 2180 2181 @Override handleMessage(Message msg)2182 public void handleMessage(Message msg) { 2183 switch (msg.what) { 2184 case SET_FROZEN_PROCESS_MSG: { 2185 ProcessRecord proc = (ProcessRecord) msg.obj; 2186 synchronized (mAm) { 2187 freezeProcess(proc); 2188 } 2189 if (proc.mOptRecord.isFrozen()) { 2190 onProcessFrozen(proc); 2191 removeMessages(DEADLOCK_WATCHDOG_MSG); 2192 sendEmptyMessageDelayed(DEADLOCK_WATCHDOG_MSG, FREEZE_DEADLOCK_TIMEOUT_MS); 2193 } 2194 } break; 2195 case REPORT_UNFREEZE_MSG: { 2196 int pid = msg.arg1; 2197 int frozenDuration = msg.arg2; 2198 Pair<ProcessRecord, Integer> obj = (Pair<ProcessRecord, Integer>) msg.obj; 2199 ProcessRecord app = obj.first; 2200 String processName = app.processName; 2201 int reason = obj.second; 2202 2203 reportUnfreeze(app, pid, frozenDuration, processName, reason); 2204 } break; 2205 case UID_FROZEN_STATE_CHANGED_MSG: { 2206 final boolean frozen = (msg.arg1 == 1); 2207 final int uid = (int) msg.obj; 2208 reportOneUidFrozenStateChanged(uid, frozen); 2209 } break; 2210 case DEADLOCK_WATCHDOG_MSG: { 2211 try { 2212 // post-check to prevent deadlock 2213 if (DEBUG_FREEZER) { 2214 Slog.d(TAG_AM, "Freezer deadlock watchdog"); 2215 } 2216 mProcLocksReader.handleBlockingFileLocks(this); 2217 } catch (IOException e) { 2218 Slog.w(TAG_AM, "Unable to check file locks"); 2219 } 2220 } break; 2221 case BINDER_ERROR_MSG: { 2222 IntArray pids = new IntArray(); 2223 // Copy the frozen pids to a local array to release mProcLock ASAP 2224 synchronized (mProcLock) { 2225 int size = mFrozenProcesses.size(); 2226 for (int i = 0; i < size; i++) { 2227 pids.add(mFrozenProcesses.keyAt(i)); 2228 } 2229 } 2230 2231 // Check binder errors to frozen processes with a local freezer lock 2232 synchronized (mFreezerLock) { 2233 binderErrorLocked(pids); 2234 } 2235 } break; 2236 default: 2237 return; 2238 } 2239 } 2240 2241 @GuardedBy({"mAm", "mProcLock"}) handleBinderFreezerFailure(final ProcessRecord proc, final String reason)2242 private void handleBinderFreezerFailure(final ProcessRecord proc, final String reason) { 2243 if (!mFreezerBinderEnabled) { 2244 // Just reschedule indefinitely. 2245 unfreezeAppLSP(proc, UNFREEZE_REASON_BINDER_TXNS); 2246 freezeAppAsyncLSP(proc); 2247 return; 2248 } 2249 /* 2250 * This handles the case where a process couldn't be frozen due to pending binder 2251 * transactions. In order to prevent apps from avoiding the freezer by spamming binder 2252 * transactions, there is an exponential decrease in freezer retry times plus a random 2253 * offset per attempt to avoid phase issues. Once the last-attempted timeout is below a 2254 * threshold, we assume that the app is spamming binder calls and can never be frozen, 2255 * and we will then crash the app. 2256 */ 2257 if (proc.mOptRecord.getLastUsedTimeout() <= mFreezerBinderThreshold) { 2258 // We've given the app plenty of chances, assume broken. Time to die. 2259 Slog.d(TAG_AM, "Kill app due to repeated failure to freeze binder: " 2260 + proc.getPid() + " " + proc.processName); 2261 mAm.mHandler.post(() -> { 2262 synchronized (mAm) { 2263 // Crash regardless of procstate in case the app has found another way 2264 // to abuse oom_adj 2265 if (proc.getThread() == null) { 2266 return; 2267 } 2268 proc.killLocked("excessive binder traffic during cached", 2269 ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE, 2270 ApplicationExitInfo.SUBREASON_EXCESSIVE_CPU, 2271 true); 2272 } 2273 }); 2274 return; 2275 } 2276 2277 long timeout = proc.mOptRecord.getLastUsedTimeout() / mFreezerBinderDivisor; 2278 // range is [-mFreezerBinderOffset, +mFreezerBinderOffset] 2279 int offset = mRandom.nextInt(mFreezerBinderOffset * 2) - mFreezerBinderOffset; 2280 timeout = Math.max(timeout + offset, mFreezerBinderThreshold); 2281 2282 Slog.d(TAG_AM, "Reschedule freeze for process " + proc.getPid() 2283 + " " + proc.processName + " (" + reason + "), timeout=" + timeout); 2284 Trace.instantForTrack(Trace.TRACE_TAG_ACTIVITY_MANAGER, ATRACE_FREEZER_TRACK, 2285 "Reschedule freeze " + proc.processName + ":" + proc.getPid() 2286 + " timeout=" + timeout + ", reason=" + reason); 2287 2288 unfreezeAppLSP(proc, UNFREEZE_REASON_BINDER_TXNS); 2289 freezeAppAsyncLSP(proc, timeout); 2290 } 2291 2292 /** 2293 * Freeze a process. 2294 * @param proc process to be frozen 2295 */ 2296 @GuardedBy({"mAm"}) freezeProcess(final ProcessRecord proc)2297 private void freezeProcess(final ProcessRecord proc) { 2298 int pid = proc.getPid(); // Unlocked intentionally 2299 final String name = proc.processName; 2300 final long unfrozenDuration; 2301 final boolean frozen; 2302 final ProcessCachedOptimizerRecord opt = proc.mOptRecord; 2303 2304 synchronized (mProcLock) { 2305 // someone has canceled this freeze 2306 if (!opt.isPendingFreeze()) { 2307 return; 2308 } 2309 opt.setPendingFreeze(false); 2310 pid = proc.getPid(); 2311 2312 if (mFreezerOverride) { 2313 opt.setFreezerOverride(true); 2314 Slog.d(TAG_AM, "Skipping freeze for process " + pid 2315 + " " + name + " curAdj = " + proc.mState.getCurAdj() 2316 + "(override)"); 2317 return; 2318 } 2319 2320 if (pid == 0 || opt.isFrozen()) { 2321 // Already frozen or not a real process, either one being 2322 // launched or one being killed 2323 if (DEBUG_FREEZER) { 2324 Slog.d(TAG_AM, "Skipping freeze for process " + pid 2325 + " " + name + ". Already frozen or not a real process"); 2326 } 2327 return; 2328 } 2329 2330 Slog.d(TAG_AM, "freezing " + pid + " " + name); 2331 2332 // Freeze binder interface before the process, to flush any 2333 // transactions that might be pending. 2334 try { 2335 if (freezeBinder(pid, true, FREEZE_BINDER_TIMEOUT_MS) != 0) { 2336 handleBinderFreezerFailure(proc, "outstanding txns"); 2337 return; 2338 } 2339 } catch (RuntimeException e) { 2340 Slog.e(TAG_AM, "Unable to freeze binder for " + pid + " " + name); 2341 mFreezeHandler.post(() -> { 2342 synchronized (mAm) { 2343 proc.killLocked("Unable to freeze binder interface", 2344 ApplicationExitInfo.REASON_FREEZER, 2345 ApplicationExitInfo.SUBREASON_FREEZER_BINDER_IOCTL, true); 2346 } 2347 }); 2348 } 2349 2350 long unfreezeTime = opt.getFreezeUnfreezeTime(); 2351 2352 try { 2353 traceAppFreeze(proc.processName, pid, -1); 2354 Process.setProcessFrozen(pid, proc.uid, true); 2355 opt.setFreezeUnfreezeTime(SystemClock.uptimeMillis()); 2356 opt.setFrozen(true); 2357 opt.setHasCollectedFrozenPSS(false); 2358 mFrozenProcesses.put(pid, proc); 2359 } catch (Exception e) { 2360 Slog.w(TAG_AM, "Unable to freeze " + pid + " " + name); 2361 } 2362 2363 unfrozenDuration = opt.getFreezeUnfreezeTime() - unfreezeTime; 2364 frozen = opt.isFrozen(); 2365 2366 final UidRecord uidRec = proc.getUidRecord(); 2367 if (frozen && uidRec != null && uidRec.areAllProcessesFrozen()) { 2368 uidRec.setFrozen(true); 2369 2370 postUidFrozenMessage(uidRec.getUid(), true); 2371 } 2372 } 2373 2374 if (!frozen) { 2375 return; 2376 } 2377 2378 EventLog.writeEvent(EventLogTags.AM_FREEZE, pid, name); 2379 2380 // See above for why we're not taking mPhenotypeFlagLock here 2381 if (mRandom.nextFloat() < mFreezerStatsdSampleRate) { 2382 FrameworkStatsLog.write(FrameworkStatsLog.APP_FREEZE_CHANGED, 2383 FrameworkStatsLog.APP_FREEZE_CHANGED__ACTION__FREEZE_APP, 2384 pid, 2385 name, 2386 unfrozenDuration, 2387 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__NONE, 2388 UNFREEZE_REASON_NONE); 2389 } 2390 2391 try { 2392 // post-check to prevent races 2393 int freezeInfo = getBinderFreezeInfo(pid); 2394 2395 if ((freezeInfo & TXNS_PENDING_WHILE_FROZEN) != 0) { 2396 synchronized (mProcLock) { 2397 handleBinderFreezerFailure(proc, "new pending txns"); 2398 } 2399 return; 2400 } 2401 } catch (RuntimeException e) { 2402 Slog.e(TAG_AM, "Unable to freeze binder for " + pid + " " + name); 2403 mFreezeHandler.post(() -> { 2404 synchronized (mAm) { 2405 proc.killLocked("Unable to freeze binder interface", 2406 ApplicationExitInfo.REASON_FREEZER, 2407 ApplicationExitInfo.SUBREASON_FREEZER_BINDER_IOCTL, true); 2408 } 2409 }); 2410 } 2411 } 2412 reportUnfreeze(ProcessRecord app, int pid, int frozenDuration, String processName, @UnfreezeReason int reason)2413 private void reportUnfreeze(ProcessRecord app, int pid, int frozenDuration, 2414 String processName, @UnfreezeReason int reason) { 2415 2416 EventLog.writeEvent(EventLogTags.AM_UNFREEZE, pid, processName, reason); 2417 app.onProcessUnfrozen(); 2418 2419 // See above for why we're not taking mPhenotypeFlagLock here 2420 if (mRandom.nextFloat() < mFreezerStatsdSampleRate) { 2421 FrameworkStatsLog.write( 2422 FrameworkStatsLog.APP_FREEZE_CHANGED, 2423 FrameworkStatsLog.APP_FREEZE_CHANGED__ACTION__UNFREEZE_APP, 2424 pid, 2425 processName, 2426 frozenDuration, 2427 FrameworkStatsLog.APP_FREEZE_CHANGED__UNFREEZE_REASON__NONE, // deprecated 2428 reason); 2429 } 2430 } 2431 2432 @GuardedBy({"mAm"}) 2433 @Override onBlockingFileLock(IntArray pids)2434 public void onBlockingFileLock(IntArray pids) { 2435 if (DEBUG_FREEZER) { 2436 Slog.d(TAG_AM, "Blocking file lock found: " + pids); 2437 } 2438 synchronized (mAm) { 2439 synchronized (mProcLock) { 2440 int pid = pids.get(0); 2441 ProcessRecord app = mFrozenProcesses.get(pid); 2442 ProcessRecord pr; 2443 if (app != null) { 2444 for (int i = 1; i < pids.size(); i++) { 2445 int blocked = pids.get(i); 2446 synchronized (mAm.mPidsSelfLocked) { 2447 pr = mAm.mPidsSelfLocked.get(blocked); 2448 } 2449 if (pr != null 2450 && pr.mState.getCurAdj() < ProcessList.CACHED_APP_MIN_ADJ) { 2451 Slog.d(TAG_AM, app.processName + " (" + pid + ") blocks " 2452 + pr.processName + " (" + blocked + ")"); 2453 // Found at least one blocked non-cached process 2454 unfreezeAppLSP(app, UNFREEZE_REASON_FILE_LOCKS); 2455 break; 2456 } 2457 } 2458 } 2459 } 2460 } 2461 } 2462 } 2463 2464 /** 2465 * Default implementation for ProcessDependencies, public vor visibility to OomAdjuster class. 2466 */ 2467 private static final class DefaultProcessDependencies implements ProcessDependencies { 2468 public static volatile int mPidCompacting = -1; 2469 2470 // Get memory RSS from process. 2471 @Override getRss(int pid)2472 public long[] getRss(int pid) { 2473 return Process.getRss(pid); 2474 } 2475 2476 // Compact process. 2477 @Override performCompaction(CompactProfile profile, int pid)2478 public void performCompaction(CompactProfile profile, int pid) throws IOException { 2479 mPidCompacting = pid; 2480 if (profile == CompactProfile.FULL) { 2481 compactProcess(pid, COMPACT_ACTION_FILE_FLAG | COMPACT_ACTION_ANON_FLAG); 2482 } else if (profile == CompactProfile.SOME) { 2483 compactProcess(pid, COMPACT_ACTION_FILE_FLAG); 2484 } else if (profile == CompactProfile.ANON) { 2485 compactProcess(pid, COMPACT_ACTION_ANON_FLAG); 2486 } 2487 mPidCompacting = -1; 2488 } 2489 } 2490 getUnfreezeReasonCodeFromOomAdjReason(@omAdjReason int oomAdjReason)2491 static int getUnfreezeReasonCodeFromOomAdjReason(@OomAdjReason int oomAdjReason) { 2492 switch (oomAdjReason) { 2493 case OOM_ADJ_REASON_ACTIVITY: 2494 return UNFREEZE_REASON_ACTIVITY; 2495 case OOM_ADJ_REASON_FINISH_RECEIVER: 2496 return UNFREEZE_REASON_FINISH_RECEIVER; 2497 case OOM_ADJ_REASON_START_RECEIVER: 2498 return UNFREEZE_REASON_START_RECEIVER; 2499 case OOM_ADJ_REASON_BIND_SERVICE: 2500 return UNFREEZE_REASON_BIND_SERVICE; 2501 case OOM_ADJ_REASON_UNBIND_SERVICE: 2502 return UNFREEZE_REASON_UNBIND_SERVICE; 2503 case OOM_ADJ_REASON_START_SERVICE: 2504 return UNFREEZE_REASON_START_SERVICE; 2505 case OOM_ADJ_REASON_GET_PROVIDER: 2506 return UNFREEZE_REASON_GET_PROVIDER; 2507 case OOM_ADJ_REASON_REMOVE_PROVIDER: 2508 return UNFREEZE_REASON_REMOVE_PROVIDER; 2509 case OOM_ADJ_REASON_UI_VISIBILITY: 2510 return UNFREEZE_REASON_UI_VISIBILITY; 2511 case OOM_ADJ_REASON_ALLOWLIST: 2512 return UNFREEZE_REASON_ALLOWLIST; 2513 case OOM_ADJ_REASON_PROCESS_BEGIN: 2514 return UNFREEZE_REASON_PROCESS_BEGIN; 2515 case OOM_ADJ_REASON_PROCESS_END: 2516 return UNFREEZE_REASON_PROCESS_END; 2517 case OOM_ADJ_REASON_SHORT_FGS_TIMEOUT: 2518 return UNFREEZE_REASON_SHORT_FGS_TIMEOUT; 2519 case OOM_ADJ_REASON_SYSTEM_INIT: 2520 return UNFREEZE_REASON_SYSTEM_INIT; 2521 case OOM_ADJ_REASON_BACKUP: 2522 return UNFREEZE_REASON_BACKUP; 2523 case OOM_ADJ_REASON_SHELL: 2524 return UNFREEZE_REASON_SHELL; 2525 case OOM_ADJ_REASON_REMOVE_TASK: 2526 return UNFREEZE_REASON_REMOVE_TASK; 2527 case OOM_ADJ_REASON_UID_IDLE: 2528 return UNFREEZE_REASON_UID_IDLE; 2529 case OOM_ADJ_REASON_STOP_SERVICE: 2530 return UNFREEZE_REASON_STOP_SERVICE; 2531 case OOM_ADJ_REASON_EXECUTING_SERVICE: 2532 return UNFREEZE_REASON_EXECUTING_SERVICE; 2533 case OOM_ADJ_REASON_RESTRICTION_CHANGE: 2534 return UNFREEZE_REASON_RESTRICTION_CHANGE; 2535 case OOM_ADJ_REASON_COMPONENT_DISABLED: 2536 return UNFREEZE_REASON_COMPONENT_DISABLED; 2537 default: 2538 return UNFREEZE_REASON_NONE; 2539 } 2540 } 2541 2542 /** 2543 * Kill a frozen process with a specified reason 2544 */ killProcess(int pid, String reason, @Reason int reasonCode, @SubReason int subReason)2545 public void killProcess(int pid, String reason, @Reason int reasonCode, 2546 @SubReason int subReason) { 2547 mAm.mHandler.post(() -> { 2548 synchronized (mAm) { 2549 synchronized (mProcLock) { 2550 ProcessRecord proc = mFrozenProcesses.get(pid); 2551 // The process might have been killed or unfrozen by others 2552 if (proc != null && proc.getThread() != null && !proc.isKilledByAm()) { 2553 proc.killLocked(reason, reasonCode, subReason, true); 2554 } 2555 } 2556 } 2557 }); 2558 } 2559 2560 /** 2561 * Sending binder transactions to frozen apps most likely indicates there's a bug. Log it and 2562 * kill the frozen apps if they 1) receive sync binder transactions while frozen, or 2) miss 2563 * async binder transactions due to kernel binder buffer running out. 2564 * 2565 * @param debugPid The binder transaction sender 2566 * @param app The ProcessRecord of the sender 2567 * @param code The binder transaction code 2568 * @param flags The binder transaction flags 2569 * @param err The binder transaction error 2570 */ binderError(int debugPid, ProcessRecord app, int code, int flags, int err)2571 public void binderError(int debugPid, ProcessRecord app, int code, int flags, int err) { 2572 Slog.w(TAG_AM, "pid " + debugPid + " " + (app == null ? "null" : app.processName) 2573 + " sent binder code " + code + " with flags " + flags 2574 + " to frozen apps and got error " + err); 2575 2576 // Do nothing if the binder error callback is not enabled. 2577 // That means the frozen apps in a wrong state will be killed when they are unfrozen later. 2578 if (!mUseFreezer || !mFreezerBinderCallbackEnabled) { 2579 return; 2580 } 2581 2582 final long now = SystemClock.uptimeMillis(); 2583 if (now < mFreezerBinderCallbackLast + mFreezerBinderCallbackThrottle) { 2584 Slog.d(TAG_AM, "Too many transaction errors, throttling freezer binder callback."); 2585 return; 2586 } 2587 mFreezerBinderCallbackLast = now; 2588 2589 // Check all frozen processes in Freezer handler 2590 mFreezeHandler.sendEmptyMessage(BINDER_ERROR_MSG); 2591 } 2592 binderErrorLocked(IntArray pids)2593 private void binderErrorLocked(IntArray pids) { 2594 // PIDs that run out of async binder buffer when being frozen 2595 ArraySet<Integer> pidsAsync = (mFreezerBinderAsyncThreshold < 0) ? null : new ArraySet<>(); 2596 2597 for (int i = 0; i < pids.size(); i++) { 2598 int current = pids.get(i); 2599 try { 2600 int freezeInfo = getBinderFreezeInfo(current); 2601 2602 if ((freezeInfo & SYNC_RECEIVED_WHILE_FROZEN) != 0) { 2603 killProcess(current, "Sync transaction while frozen", 2604 ApplicationExitInfo.REASON_FREEZER, 2605 ApplicationExitInfo.SUBREASON_FREEZER_BINDER_TRANSACTION); 2606 2607 // No need to check async transactions in this case 2608 continue; 2609 } 2610 2611 if ((freezeInfo & ASYNC_RECEIVED_WHILE_FROZEN) != 0) { 2612 if (pidsAsync != null) { 2613 pidsAsync.add(current); 2614 } 2615 if (DEBUG_FREEZER) { 2616 Slog.w(TAG_AM, "pid " + current 2617 + " received async transactions while frozen"); 2618 } 2619 } 2620 } catch (Exception e) { 2621 // The process has died. No need to kill it again. 2622 Slog.w(TAG_AM, "Unable to query binder frozen stats for pid " + current); 2623 } 2624 } 2625 2626 // TODO: when kernel binder driver supports, poll the binder status directly. 2627 // Binderfs stats, like other debugfs files, is not a reliable interface. But it's the 2628 // only true source for now. The following code checks all frozen PIDs. If any of them 2629 // is running out of async binder buffer, kill it. Otherwise it will be killed at a 2630 // later time when AMS unfreezes it, which causes race issues. 2631 if (pidsAsync == null || pidsAsync.size() == 0) { 2632 return; 2633 } 2634 new BinderfsStatsReader().handleFreeAsyncSpace( 2635 // Check if the frozen process has pending async calls 2636 pidsAsync::contains, 2637 2638 // Kill the current process if it's running out of async binder space 2639 (current, free) -> { 2640 if (free < mFreezerBinderAsyncThreshold) { 2641 Slog.w(TAG_AM, "pid " + current 2642 + " has " + free + " free async space, killing"); 2643 killProcess(current, "Async binder space running out while frozen", 2644 ApplicationExitInfo.REASON_FREEZER, 2645 ApplicationExitInfo.SUBREASON_FREEZER_BINDER_ASYNC_FULL); 2646 } 2647 }, 2648 2649 // Log the error if binderfs stats can't be accesses or correctly parsed 2650 exception -> Slog.e(TAG_AM, "Unable to parse binderfs stats")); 2651 } 2652 } 2653