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