blob: f58fb95b1ec9a2ecc2930ebdfb59339c869168be [file] [log] [blame]
Tim Murray1cdbd1e2018-12-18 15:18:33 -08001/*
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
17package com.android.server.am;
18
Ben Murdochc26a5a82019-01-16 10:05:58 +000019import static android.os.Process.THREAD_PRIORITY_FOREGROUND;
Tim Murray1cdbd1e2018-12-18 15:18:33 -080020
21import android.app.ActivityManager;
Ben Murdochc26a5a82019-01-16 10:05:58 +000022import android.app.ActivityThread;
Ben Murdochfdc55932019-01-30 10:43:15 +000023import android.os.Debug;
Tim Murray1cdbd1e2018-12-18 15:18:33 -080024import android.os.Handler;
Tim Murray1cdbd1e2018-12-18 15:18:33 -080025import android.os.Message;
26import android.os.Process;
27import android.os.SystemClock;
28import android.os.Trace;
Ben Murdochc26a5a82019-01-16 10:05:58 +000029import android.provider.DeviceConfig;
30import android.provider.DeviceConfig.OnPropertyChangedListener;
31import android.text.TextUtils;
Tim Murray1cdbd1e2018-12-18 15:18:33 -080032import android.util.EventLog;
33import android.util.StatsLog;
34
Ben Murdochc26a5a82019-01-16 10:05:58 +000035import com.android.internal.annotations.GuardedBy;
36import com.android.internal.annotations.VisibleForTesting;
Tim Murray1cdbd1e2018-12-18 15:18:33 -080037import com.android.server.ServiceThread;
38
39import java.io.FileOutputStream;
Ben Murdochc26a5a82019-01-16 10:05:58 +000040import java.io.PrintWriter;
Tim Murray1cdbd1e2018-12-18 15:18:33 -080041import java.util.ArrayList;
Ben Murdoch2384df72019-01-28 16:13:55 +000042import java.util.Random;
Tim Murray1cdbd1e2018-12-18 15:18:33 -080043
44public final class AppCompactor {
Tim Murray1cdbd1e2018-12-18 15:18:33 -080045
Matt Pape40074da2019-02-12 13:53:26 -080046 // Flags stored in the DeviceConfig API.
47 @VisibleForTesting static final String KEY_USE_COMPACTION = "use_compaction";
48 @VisibleForTesting static final String KEY_COMPACT_ACTION_1 = "compact_action_1";
49 @VisibleForTesting static final String KEY_COMPACT_ACTION_2 = "compact_action_2";
50 @VisibleForTesting static final String KEY_COMPACT_THROTTLE_1 = "compact_throttle_1";
51 @VisibleForTesting static final String KEY_COMPACT_THROTTLE_2 = "compact_throttle_2";
52 @VisibleForTesting static final String KEY_COMPACT_THROTTLE_3 = "compact_throttle_3";
53 @VisibleForTesting static final String KEY_COMPACT_THROTTLE_4 = "compact_throttle_4";
Tim Murraybf3f3692019-02-19 14:29:39 -080054 @VisibleForTesting static final String KEY_COMPACT_THROTTLE_5 = "compact_throttle_5";
55 @VisibleForTesting static final String KEY_COMPACT_THROTTLE_6 = "compact_throttle_6";
Matt Pape40074da2019-02-12 13:53:26 -080056 @VisibleForTesting static final String KEY_COMPACT_STATSD_SAMPLE_RATE =
57 "compact_statsd_sample_rate";
58
Ben Murdochc26a5a82019-01-16 10:05:58 +000059 // Phenotype sends int configurations and we map them to the strings we'll use on device,
60 // preventing a weird string value entering the kernel.
61 private static final int COMPACT_ACTION_FILE_FLAG = 1;
62 private static final int COMPACT_ACTION_ANON_FLAG = 2;
63 private static final int COMPACT_ACTION_FULL_FLAG = 3;
Tim Murrayf96451b2019-01-30 18:36:48 -080064 private static final int COMPACT_ACTION_NONE_FLAG = 4;
65 private static final String COMPACT_ACTION_NONE = "";
Ben Murdochc26a5a82019-01-16 10:05:58 +000066 private static final String COMPACT_ACTION_FILE = "file";
67 private static final String COMPACT_ACTION_ANON = "anon";
68 private static final String COMPACT_ACTION_FULL = "all";
69
70 // Defaults for phenotype flags.
71 @VisibleForTesting static final Boolean DEFAULT_USE_COMPACTION = false;
72 @VisibleForTesting static final int DEFAULT_COMPACT_ACTION_1 = COMPACT_ACTION_FILE_FLAG;
73 @VisibleForTesting static final int DEFAULT_COMPACT_ACTION_2 = COMPACT_ACTION_FULL_FLAG;
74 @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_1 = 5_000;
75 @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_2 = 10_000;
76 @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_3 = 500;
77 @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_4 = 10_000;
Tim Murraybf3f3692019-02-19 14:29:39 -080078 @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_5 = 10 * 60 * 1000;
79 @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_6 = 10 * 60 * 1000;
Ben Murdoch2384df72019-01-28 16:13:55 +000080 // The sampling rate to push app compaction events into statsd for upload.
81 @VisibleForTesting static final float DEFAULT_STATSD_SAMPLE_RATE = 0.1f;
Ben Murdochc26a5a82019-01-16 10:05:58 +000082
83 @VisibleForTesting
84 interface PropertyChangedCallbackForTest {
85 void onPropertyChanged();
86 }
87 private PropertyChangedCallbackForTest mTestCallback;
88
89 // Handler constants.
Tim Murraybbcbc2c2018-12-20 13:30:59 -080090 static final int COMPACT_PROCESS_SOME = 1;
91 static final int COMPACT_PROCESS_FULL = 2;
Tim Murraybf3f3692019-02-19 14:29:39 -080092 static final int COMPACT_PROCESS_PERSISTENT = 3;
93 static final int COMPACT_PROCESS_BFGS = 4;
Tim Murraybbcbc2c2018-12-20 13:30:59 -080094 static final int COMPACT_PROCESS_MSG = 1;
Tim Murray31faf3f2019-03-01 20:25:07 -080095 static final int COMPACT_SYSTEM_MSG = 2;
Tim Murraybbcbc2c2018-12-20 13:30:59 -080096
97 /**
Tim Murray1cdbd1e2018-12-18 15:18:33 -080098 * This thread must be moved to the system background cpuset.
99 * If that doesn't happen, it's probably going to draw a lot of power.
100 * However, this has to happen after the first updateOomAdjLocked, because
101 * that will wipe out the cpuset assignment for system_server threads.
102 * Accordingly, this is in the AMS constructor.
103 */
104 final ServiceThread mCompactionThread;
105
Ben Murdochc26a5a82019-01-16 10:05:58 +0000106 private final ArrayList<ProcessRecord> mPendingCompactionProcesses =
107 new ArrayList<ProcessRecord>();
108 private final ActivityManagerService mAm;
109 private final OnPropertyChangedListener mOnFlagsChangedListener =
110 new OnPropertyChangedListener() {
111 @Override
112 public void onPropertyChanged(String namespace, String name, String value) {
113 synchronized (mPhenotypeFlagLock) {
114 if (KEY_USE_COMPACTION.equals(name)) {
115 updateUseCompaction();
116 } else if (KEY_COMPACT_ACTION_1.equals(name)
117 || KEY_COMPACT_ACTION_2.equals(name)) {
118 updateCompactionActions();
119 } else if (KEY_COMPACT_THROTTLE_1.equals(name)
120 || KEY_COMPACT_THROTTLE_2.equals(name)
121 || KEY_COMPACT_THROTTLE_3.equals(name)
122 || KEY_COMPACT_THROTTLE_4.equals(name)) {
123 updateCompactionThrottles();
Ben Murdoch2384df72019-01-28 16:13:55 +0000124 } else if (KEY_COMPACT_STATSD_SAMPLE_RATE.equals(name)) {
125 updateStatsdSampleRate();
Ben Murdochc26a5a82019-01-16 10:05:58 +0000126 }
127 }
128 if (mTestCallback != null) {
129 mTestCallback.onPropertyChanged();
130 }
131 }
132 };
Tim Murray1cdbd1e2018-12-18 15:18:33 -0800133
Ben Murdochc26a5a82019-01-16 10:05:58 +0000134 private final Object mPhenotypeFlagLock = new Object();
Tim Murraybbcbc2c2018-12-20 13:30:59 -0800135
Ben Murdochc26a5a82019-01-16 10:05:58 +0000136 // Configured by phenotype. Updates from the server take effect immediately.
137 @GuardedBy("mPhenotypeFlagLock")
Ben Murdoch2384df72019-01-28 16:13:55 +0000138 @VisibleForTesting volatile String mCompactActionSome =
Ben Murdochc26a5a82019-01-16 10:05:58 +0000139 compactActionIntToString(DEFAULT_COMPACT_ACTION_1);
140 @GuardedBy("mPhenotypeFlagLock")
Ben Murdoch2384df72019-01-28 16:13:55 +0000141 @VisibleForTesting volatile String mCompactActionFull =
Ben Murdochc26a5a82019-01-16 10:05:58 +0000142 compactActionIntToString(DEFAULT_COMPACT_ACTION_2);
143 @GuardedBy("mPhenotypeFlagLock")
Ben Murdoch2384df72019-01-28 16:13:55 +0000144 @VisibleForTesting volatile long mCompactThrottleSomeSome = DEFAULT_COMPACT_THROTTLE_1;
Ben Murdochc26a5a82019-01-16 10:05:58 +0000145 @GuardedBy("mPhenotypeFlagLock")
Ben Murdoch2384df72019-01-28 16:13:55 +0000146 @VisibleForTesting volatile long mCompactThrottleSomeFull = DEFAULT_COMPACT_THROTTLE_2;
Ben Murdochc26a5a82019-01-16 10:05:58 +0000147 @GuardedBy("mPhenotypeFlagLock")
Ben Murdoch2384df72019-01-28 16:13:55 +0000148 @VisibleForTesting volatile long mCompactThrottleFullSome = DEFAULT_COMPACT_THROTTLE_3;
Ben Murdochc26a5a82019-01-16 10:05:58 +0000149 @GuardedBy("mPhenotypeFlagLock")
Ben Murdoch2384df72019-01-28 16:13:55 +0000150 @VisibleForTesting volatile long mCompactThrottleFullFull = DEFAULT_COMPACT_THROTTLE_4;
Ben Murdochc26a5a82019-01-16 10:05:58 +0000151 @GuardedBy("mPhenotypeFlagLock")
Tim Murraybf3f3692019-02-19 14:29:39 -0800152 @VisibleForTesting volatile long mCompactThrottleBFGS = DEFAULT_COMPACT_THROTTLE_5;
153 @GuardedBy("mPhenotypeFlagLock")
154 @VisibleForTesting volatile long mCompactThrottlePersistent = DEFAULT_COMPACT_THROTTLE_6;
155 @GuardedBy("mPhenotypeFlagLock")
Ben Murdoch2384df72019-01-28 16:13:55 +0000156 private volatile boolean mUseCompaction = DEFAULT_USE_COMPACTION;
157
158 private final Random mRandom = new Random();
159 @GuardedBy("mPhenotypeFlagLock")
160 @VisibleForTesting volatile float mStatsdSampleRate = DEFAULT_STATSD_SAMPLE_RATE;
Tim Murraybbcbc2c2018-12-20 13:30:59 -0800161
Ben Murdochc26a5a82019-01-16 10:05:58 +0000162 // Handler on which compaction runs.
163 private Handler mCompactionHandler;
Tim Murray1cdbd1e2018-12-18 15:18:33 -0800164
165 public AppCompactor(ActivityManagerService am) {
166 mAm = am;
Tim Murray1cdbd1e2018-12-18 15:18:33 -0800167 mCompactionThread = new ServiceThread("CompactionThread",
168 THREAD_PRIORITY_FOREGROUND, true);
Tim Murray1cdbd1e2018-12-18 15:18:33 -0800169 }
170
Ben Murdochc26a5a82019-01-16 10:05:58 +0000171 @VisibleForTesting
172 AppCompactor(ActivityManagerService am, PropertyChangedCallbackForTest callback) {
173 this(am);
174 mTestCallback = callback;
175 }
176
177 /**
178 * Reads phenotype config to determine whether app compaction is enabled or not and
179 * starts the background thread if necessary.
180 */
181 public void init() {
Matt Pape40074da2019-02-12 13:53:26 -0800182 DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
Ben Murdochc26a5a82019-01-16 10:05:58 +0000183 ActivityThread.currentApplication().getMainExecutor(), mOnFlagsChangedListener);
184 synchronized (mPhenotypeFlagLock) {
185 updateUseCompaction();
186 updateCompactionActions();
187 updateCompactionThrottles();
Ben Murdoch2384df72019-01-28 16:13:55 +0000188 updateStatsdSampleRate();
Ben Murdochc26a5a82019-01-16 10:05:58 +0000189 }
Tim Murray0a796c12019-02-05 13:03:16 -0800190 Process.setThreadGroupAndCpuset(mCompactionThread.getThreadId(),
191 Process.THREAD_GROUP_SYSTEM);
192
Ben Murdochc26a5a82019-01-16 10:05:58 +0000193 }
194
195 /**
196 * Returns whether compaction is enabled.
197 */
198 public boolean useCompaction() {
199 synchronized (mPhenotypeFlagLock) {
200 return mUseCompaction;
201 }
202 }
203
204 @GuardedBy("mAm")
205 void dump(PrintWriter pw) {
206 pw.println("AppCompactor settings");
207 synchronized (mPhenotypeFlagLock) {
208 pw.println(" " + KEY_USE_COMPACTION + "=" + mUseCompaction);
209 pw.println(" " + KEY_COMPACT_ACTION_1 + "=" + mCompactActionSome);
210 pw.println(" " + KEY_COMPACT_ACTION_2 + "=" + mCompactActionFull);
211 pw.println(" " + KEY_COMPACT_THROTTLE_1 + "=" + mCompactThrottleSomeSome);
212 pw.println(" " + KEY_COMPACT_THROTTLE_2 + "=" + mCompactThrottleSomeFull);
213 pw.println(" " + KEY_COMPACT_THROTTLE_3 + "=" + mCompactThrottleFullSome);
214 pw.println(" " + KEY_COMPACT_THROTTLE_4 + "=" + mCompactThrottleFullFull);
Ben Murdoch2384df72019-01-28 16:13:55 +0000215 pw.println(" " + KEY_COMPACT_STATSD_SAMPLE_RATE + "=" + mStatsdSampleRate);
Ben Murdochc26a5a82019-01-16 10:05:58 +0000216 }
217 }
218
219 @GuardedBy("mAm")
220 void compactAppSome(ProcessRecord app) {
Tim Murray1cdbd1e2018-12-18 15:18:33 -0800221 app.reqCompactAction = COMPACT_PROCESS_SOME;
222 mPendingCompactionProcesses.add(app);
223 mCompactionHandler.sendMessage(
224 mCompactionHandler.obtainMessage(
Ben Murdoch885c21b2019-03-15 18:02:04 +0000225 COMPACT_PROCESS_MSG, app.setAdj, app.setProcState));
Tim Murray1cdbd1e2018-12-18 15:18:33 -0800226 }
227
Ben Murdochc26a5a82019-01-16 10:05:58 +0000228 @GuardedBy("mAm")
229 void compactAppFull(ProcessRecord app) {
Tim Murray1cdbd1e2018-12-18 15:18:33 -0800230 app.reqCompactAction = COMPACT_PROCESS_FULL;
231 mPendingCompactionProcesses.add(app);
232 mCompactionHandler.sendMessage(
233 mCompactionHandler.obtainMessage(
Ben Murdoch885c21b2019-03-15 18:02:04 +0000234 COMPACT_PROCESS_MSG, app.setAdj, app.setProcState));
Tim Murray1cdbd1e2018-12-18 15:18:33 -0800235
236 }
Tim Murray1cdbd1e2018-12-18 15:18:33 -0800237
Tim Murraybf3f3692019-02-19 14:29:39 -0800238 @GuardedBy("mAm")
239 void compactAppPersistent(ProcessRecord app) {
240 app.reqCompactAction = COMPACT_PROCESS_PERSISTENT;
241 mPendingCompactionProcesses.add(app);
242 mCompactionHandler.sendMessage(
243 mCompactionHandler.obtainMessage(
244 COMPACT_PROCESS_MSG, app.curAdj, app.setProcState));
245 }
246
247 @GuardedBy("mAm")
248 boolean shouldCompactPersistent(ProcessRecord app, long now) {
249 return (app.lastCompactTime == 0
250 || (now - app.lastCompactTime) > mCompactThrottlePersistent);
251 }
252
253 @GuardedBy("mAm")
254 void compactAppBfgs(ProcessRecord app) {
255 app.reqCompactAction = COMPACT_PROCESS_BFGS;
256 mPendingCompactionProcesses.add(app);
257 mCompactionHandler.sendMessage(
258 mCompactionHandler.obtainMessage(
259 COMPACT_PROCESS_MSG, app.curAdj, app.setProcState));
260 }
261
262 @GuardedBy("mAm")
263 boolean shouldCompactBFGS(ProcessRecord app, long now) {
264 return (app.lastCompactTime == 0
265 || (now - app.lastCompactTime) > mCompactThrottleBFGS);
266 }
267
Tim Murray31faf3f2019-03-01 20:25:07 -0800268 @GuardedBy("mAm")
269 void compactAllSystem() {
270 if (mUseCompaction) {
271 mCompactionHandler.sendMessage(mCompactionHandler.obtainMessage(
272 COMPACT_SYSTEM_MSG));
273 }
274 }
275
276 private native void compactSystem();
277
Ben Murdochc26a5a82019-01-16 10:05:58 +0000278 /**
279 * Reads the flag value from DeviceConfig to determine whether app compaction
280 * should be enabled, and starts/stops the compaction thread as needed.
281 */
282 @GuardedBy("mPhenotypeFlagLock")
283 private void updateUseCompaction() {
Stanislav Zholnin632c91522019-03-07 15:46:27 +0000284 mUseCompaction = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
285 KEY_USE_COMPACTION, DEFAULT_USE_COMPACTION);
Ben Murdochc26a5a82019-01-16 10:05:58 +0000286 if (mUseCompaction && !mCompactionThread.isAlive()) {
287 mCompactionThread.start();
288 mCompactionHandler = new MemCompactionHandler();
289 }
290 }
291
292 @GuardedBy("mPhenotypeFlagLock")
293 private void updateCompactionActions() {
Stanislav Zholnin632c91522019-03-07 15:46:27 +0000294 int compactAction1 = DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
295 KEY_COMPACT_ACTION_1, DEFAULT_COMPACT_ACTION_1);
Ben Murdochc26a5a82019-01-16 10:05:58 +0000296
Stanislav Zholnin632c91522019-03-07 15:46:27 +0000297 int compactAction2 = DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
298 KEY_COMPACT_ACTION_2, DEFAULT_COMPACT_ACTION_2);
Ben Murdochc26a5a82019-01-16 10:05:58 +0000299
300 mCompactActionSome = compactActionIntToString(compactAction1);
301 mCompactActionFull = compactActionIntToString(compactAction2);
302 }
303
304 @GuardedBy("mPhenotypeFlagLock")
305 private void updateCompactionThrottles() {
306 boolean useThrottleDefaults = false;
307 String throttleSomeSomeFlag =
Matt Pape40074da2019-02-12 13:53:26 -0800308 DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
Ben Murdochc26a5a82019-01-16 10:05:58 +0000309 KEY_COMPACT_THROTTLE_1);
310 String throttleSomeFullFlag =
Matt Pape40074da2019-02-12 13:53:26 -0800311 DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
Ben Murdochc26a5a82019-01-16 10:05:58 +0000312 KEY_COMPACT_THROTTLE_2);
313 String throttleFullSomeFlag =
Matt Pape40074da2019-02-12 13:53:26 -0800314 DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
Ben Murdochc26a5a82019-01-16 10:05:58 +0000315 KEY_COMPACT_THROTTLE_3);
316 String throttleFullFullFlag =
Matt Pape40074da2019-02-12 13:53:26 -0800317 DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
Ben Murdochc26a5a82019-01-16 10:05:58 +0000318 KEY_COMPACT_THROTTLE_4);
Tim Murraybf3f3692019-02-19 14:29:39 -0800319 String throttleBFGSFlag =
320 DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
321 KEY_COMPACT_THROTTLE_5);
322 String throttlePersistentFlag =
323 DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
324 KEY_COMPACT_THROTTLE_6);
Ben Murdochc26a5a82019-01-16 10:05:58 +0000325
326 if (TextUtils.isEmpty(throttleSomeSomeFlag) || TextUtils.isEmpty(throttleSomeFullFlag)
327 || TextUtils.isEmpty(throttleFullSomeFlag)
Tim Murraybf3f3692019-02-19 14:29:39 -0800328 || TextUtils.isEmpty(throttleFullFullFlag)
329 || TextUtils.isEmpty(throttleBFGSFlag)
330 || TextUtils.isEmpty(throttlePersistentFlag)) {
Ben Murdochc26a5a82019-01-16 10:05:58 +0000331 // Set defaults for all if any are not set.
332 useThrottleDefaults = true;
333 } else {
334 try {
335 mCompactThrottleSomeSome = Integer.parseInt(throttleSomeSomeFlag);
336 mCompactThrottleSomeFull = Integer.parseInt(throttleSomeFullFlag);
337 mCompactThrottleFullSome = Integer.parseInt(throttleFullSomeFlag);
338 mCompactThrottleFullFull = Integer.parseInt(throttleFullFullFlag);
Tim Murraybf3f3692019-02-19 14:29:39 -0800339 mCompactThrottleBFGS = Integer.parseInt(throttleBFGSFlag);
340 mCompactThrottlePersistent = Integer.parseInt(throttlePersistentFlag);
Ben Murdochc26a5a82019-01-16 10:05:58 +0000341 } catch (NumberFormatException e) {
342 useThrottleDefaults = true;
343 }
344 }
345
346 if (useThrottleDefaults) {
347 mCompactThrottleSomeSome = DEFAULT_COMPACT_THROTTLE_1;
348 mCompactThrottleSomeFull = DEFAULT_COMPACT_THROTTLE_2;
349 mCompactThrottleFullSome = DEFAULT_COMPACT_THROTTLE_3;
350 mCompactThrottleFullFull = DEFAULT_COMPACT_THROTTLE_4;
Tim Murraybf3f3692019-02-19 14:29:39 -0800351 mCompactThrottleBFGS = DEFAULT_COMPACT_THROTTLE_5;
352 mCompactThrottlePersistent = DEFAULT_COMPACT_THROTTLE_6;
Ben Murdochc26a5a82019-01-16 10:05:58 +0000353 }
354 }
355
Ben Murdoch2384df72019-01-28 16:13:55 +0000356 @GuardedBy("mPhenotypeFlagLock")
357 private void updateStatsdSampleRate() {
Stanislav Zholnin632c91522019-03-07 15:46:27 +0000358 mStatsdSampleRate = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
359 KEY_COMPACT_STATSD_SAMPLE_RATE, DEFAULT_STATSD_SAMPLE_RATE);
Ben Murdoch2384df72019-01-28 16:13:55 +0000360 mStatsdSampleRate = Math.min(1.0f, Math.max(0.0f, mStatsdSampleRate));
361 }
362
Ben Murdochc26a5a82019-01-16 10:05:58 +0000363 @VisibleForTesting
364 static String compactActionIntToString(int action) {
365 switch(action) {
Tim Murrayf96451b2019-01-30 18:36:48 -0800366 case COMPACT_ACTION_NONE_FLAG:
367 return COMPACT_ACTION_NONE;
Ben Murdochc26a5a82019-01-16 10:05:58 +0000368 case COMPACT_ACTION_FILE_FLAG:
369 return COMPACT_ACTION_FILE;
370 case COMPACT_ACTION_ANON_FLAG:
371 return COMPACT_ACTION_ANON;
372 case COMPACT_ACTION_FULL_FLAG:
373 return COMPACT_ACTION_FULL;
374 default:
Tim Murrayf96451b2019-01-30 18:36:48 -0800375 return COMPACT_ACTION_NONE;
Ben Murdochc26a5a82019-01-16 10:05:58 +0000376 }
377 }
378
379 private final class MemCompactionHandler extends Handler {
380 private MemCompactionHandler() {
381 super(mCompactionThread.getLooper());
Tim Murray1cdbd1e2018-12-18 15:18:33 -0800382 }
383
384 @Override
385 public void handleMessage(Message msg) {
386 switch (msg.what) {
Ben Murdochc26a5a82019-01-16 10:05:58 +0000387 case COMPACT_PROCESS_MSG: {
388 long start = SystemClock.uptimeMillis();
389 ProcessRecord proc;
390 int pid;
391 String action;
392 final String name;
393 int pendingAction, lastCompactAction;
394 long lastCompactTime;
395 synchronized (mAm) {
396 proc = mPendingCompactionProcesses.remove(0);
Tim Murray1cdbd1e2018-12-18 15:18:33 -0800397
Tim Murraybf3f3692019-02-19 14:29:39 -0800398 pendingAction = proc.reqCompactAction;
399
Ben Murdochc26a5a82019-01-16 10:05:58 +0000400 // don't compact if the process has returned to perceptible
Tim Murraybf3f3692019-02-19 14:29:39 -0800401 // and this is only a cached/home/prev compaction
402 if ((pendingAction == COMPACT_PROCESS_SOME
403 || pendingAction == COMPACT_PROCESS_FULL)
404 && (proc.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ)) {
Ben Murdochc26a5a82019-01-16 10:05:58 +0000405 return;
406 }
407
408 pid = proc.pid;
409 name = proc.processName;
Tim Murraybf3f3692019-02-19 14:29:39 -0800410
Ben Murdochc26a5a82019-01-16 10:05:58 +0000411 lastCompactAction = proc.lastCompactAction;
412 lastCompactTime = proc.lastCompactTime;
413 }
414
415 if (pid == 0) {
416 // not a real process, either one being launched or one being killed
Tim Murray1cdbd1e2018-12-18 15:18:33 -0800417 return;
418 }
419
Ben Murdochc26a5a82019-01-16 10:05:58 +0000420 // basic throttling
421 // use the Phenotype flag knobs to determine whether current/prevous
422 // compaction combo should be throtted or not
Tim Murray1cdbd1e2018-12-18 15:18:33 -0800423
Ben Murdochc26a5a82019-01-16 10:05:58 +0000424 // Note that we explicitly don't take mPhenotypeFlagLock here as the flags
425 // should very seldom change, and taking the risk of using the wrong action is
426 // preferable to taking the lock for every single compaction action.
Tim Murraybf3f3692019-02-19 14:29:39 -0800427 if (lastCompactTime != 0) {
428 if (pendingAction == COMPACT_PROCESS_SOME) {
429 if ((lastCompactAction == COMPACT_PROCESS_SOME
430 && (start - lastCompactTime < mCompactThrottleSomeSome))
431 || (lastCompactAction == COMPACT_PROCESS_FULL
432 && (start - lastCompactTime
433 < mCompactThrottleSomeFull))) {
434 return;
435 }
436 } else if (pendingAction == COMPACT_PROCESS_FULL) {
437 if ((lastCompactAction == COMPACT_PROCESS_SOME
438 && (start - lastCompactTime < mCompactThrottleFullSome))
439 || (lastCompactAction == COMPACT_PROCESS_FULL
440 && (start - lastCompactTime
441 < mCompactThrottleFullFull))) {
442 return;
443 }
444 } else if (pendingAction == COMPACT_PROCESS_PERSISTENT) {
445 if (start - lastCompactTime < mCompactThrottlePersistent) {
446 return;
447 }
448 } else if (pendingAction == COMPACT_PROCESS_BFGS) {
449 if (start - lastCompactTime < mCompactThrottleBFGS) {
450 return;
451 }
Ben Murdochc26a5a82019-01-16 10:05:58 +0000452 }
Tim Murray1cdbd1e2018-12-18 15:18:33 -0800453 }
Tim Murraybf3f3692019-02-19 14:29:39 -0800454 switch (pendingAction) {
455 case COMPACT_PROCESS_SOME:
456 action = mCompactActionSome;
457 break;
458 // For the time being, treat these as equivalent.
459 case COMPACT_PROCESS_FULL:
460 case COMPACT_PROCESS_PERSISTENT:
461 case COMPACT_PROCESS_BFGS:
462 action = mCompactActionFull;
463 break;
464 default:
465 action = COMPACT_ACTION_NONE;
466 break;
Tim Murray1cdbd1e2018-12-18 15:18:33 -0800467 }
Ben Murdochc26a5a82019-01-16 10:05:58 +0000468
Tim Murraybf3f3692019-02-19 14:29:39 -0800469 if (COMPACT_ACTION_NONE.equals(action)) {
Tim Murrayf96451b2019-01-30 18:36:48 -0800470 return;
471 }
472
Ben Murdochc26a5a82019-01-16 10:05:58 +0000473 try {
474 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Compact "
475 + ((pendingAction == COMPACT_PROCESS_SOME) ? "some" : "full")
476 + ": " + name);
Ben Murdochfdc55932019-01-30 10:43:15 +0000477 long zramFreeKbBefore = Debug.getZramFreeKb();
Ben Murdochc26a5a82019-01-16 10:05:58 +0000478 long[] rssBefore = Process.getRss(pid);
479 FileOutputStream fos = new FileOutputStream("/proc/" + pid + "/reclaim");
480 fos.write(action.getBytes());
481 fos.close();
482 long[] rssAfter = Process.getRss(pid);
483 long end = SystemClock.uptimeMillis();
484 long time = end - start;
Ben Murdochfdc55932019-01-30 10:43:15 +0000485 long zramFreeKbAfter = Debug.getZramFreeKb();
Ben Murdochc26a5a82019-01-16 10:05:58 +0000486 EventLog.writeEvent(EventLogTags.AM_COMPACT, pid, name, action,
487 rssBefore[0], rssBefore[1], rssBefore[2], rssBefore[3],
488 rssAfter[0], rssAfter[1], rssAfter[2], rssAfter[3], time,
Ben Murdochfdc55932019-01-30 10:43:15 +0000489 lastCompactAction, lastCompactTime, msg.arg1, msg.arg2,
490 zramFreeKbBefore, zramFreeKbAfter);
Ben Murdoch2384df72019-01-28 16:13:55 +0000491 // Note that as above not taking mPhenoTypeFlagLock here to avoid locking
492 // on every single compaction for a flag that will seldom change and the
493 // impact of reading the wrong value here is low.
494 if (mRandom.nextFloat() < mStatsdSampleRate) {
495 StatsLog.write(StatsLog.APP_COMPACTED, pid, name, pendingAction,
496 rssBefore[0], rssBefore[1], rssBefore[2], rssBefore[3],
497 rssAfter[0], rssAfter[1], rssAfter[2], rssAfter[3], time,
498 lastCompactAction, lastCompactTime, msg.arg1,
Ben Murdochfdc55932019-01-30 10:43:15 +0000499 ActivityManager.processStateAmToProto(msg.arg2),
500 zramFreeKbBefore, zramFreeKbAfter);
Ben Murdoch2384df72019-01-28 16:13:55 +0000501 }
Ben Murdochc26a5a82019-01-16 10:05:58 +0000502 synchronized (mAm) {
503 proc.lastCompactTime = end;
504 proc.lastCompactAction = pendingAction;
505 }
506 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
507 } catch (Exception e) {
508 // nothing to do, presumably the process died
509 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
510 }
Tim Murray31faf3f2019-03-01 20:25:07 -0800511 break;
512 }
513 case COMPACT_SYSTEM_MSG: {
514 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "compactSystem");
515 compactSystem();
516 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
517 break;
Tim Murray1cdbd1e2018-12-18 15:18:33 -0800518 }
519 }
Tim Murray1cdbd1e2018-12-18 15:18:33 -0800520 }
521 }
Tim Murray1cdbd1e2018-12-18 15:18:33 -0800522}