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