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