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