• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 android.annotation.IntDef;
20 import android.annotation.UptimeMillisLong;
21 import android.app.ActivityManagerInternal.FrozenProcessListener;
22 import android.app.ActivityManagerInternal.OomAdjReason;
23 import android.util.Pair;
24 import android.util.TimeUtils;
25 
26 import com.android.internal.annotations.GuardedBy;
27 import com.android.internal.annotations.VisibleForTesting;
28 
29 import dalvik.annotation.optimization.NeverCompile;
30 
31 import java.io.PrintWriter;
32 import java.lang.annotation.Retention;
33 import java.lang.annotation.RetentionPolicy;
34 import java.util.concurrent.CopyOnWriteArrayList;
35 import java.util.concurrent.Executor;
36 
37 /**
38  * The state info of app when it's cached, used by the optimizer.
39  */
40 final class ProcessCachedOptimizerRecord {
41 
42     static final int SHOULD_NOT_FREEZE_REASON_NONE = 1;
43     static final int SHOULD_NOT_FREEZE_REASON_UID_ALLOWLISTED = 1 << 1;
44     static final int SHOULD_NOT_FREEZE_REASON_BINDER_ALLOW_OOM_MANAGEMENT = 1 << 2;
45     static final int SHOULD_NOT_FREEZE_REASON_BIND_WAIVE_PRIORITY = 1 << 3;
46 
47     @IntDef(flag = true, prefix = {"SHOULD_NOT_FREEZE_REASON_"}, value = {
48         SHOULD_NOT_FREEZE_REASON_NONE,
49         SHOULD_NOT_FREEZE_REASON_UID_ALLOWLISTED,
50         SHOULD_NOT_FREEZE_REASON_BINDER_ALLOW_OOM_MANAGEMENT,
51         SHOULD_NOT_FREEZE_REASON_BIND_WAIVE_PRIORITY,
52     })
53     @Retention(RetentionPolicy.SOURCE)
54     public @interface ShouldNotFreezeReason {}
55 
56     private final ProcessRecord mApp;
57 
58     private final ActivityManagerGlobalLock mProcLock;
59 
60     @VisibleForTesting
61     static final String IS_FROZEN = "isFrozen";
62 
63     /**
64      * The last time that this process was compacted.
65      */
66     @GuardedBy("mProcLock")
67     private long mLastCompactTime;
68 
69     /**
70      * The most recent compaction profile requested for this app.
71      */
72     @GuardedBy("mProcLock") private CachedAppOptimizer.CompactProfile mReqCompactProfile;
73 
74     /**
75      * Source that requested the latest compaction for this app.
76      */
77     @GuardedBy("mProcLock") private CachedAppOptimizer.CompactSource mReqCompactSource;
78 
79     /**
80      * Last oom adjust change reason for this app.
81      */
82     @GuardedBy("mProcLock") private @OomAdjReason int mLastOomAdjChangeReason;
83 
84     /**
85      * The most recent compaction action performed for this app.
86      */
87     @GuardedBy("mProcLock") private CachedAppOptimizer.CompactProfile mLastCompactProfile;
88 
89     /**
90      * This process has been scheduled for a memory compaction.
91      */
92     @GuardedBy("mProcLock")
93     private boolean mPendingCompact;
94 
95     @GuardedBy("mProcLock") private boolean mForceCompact;
96 
97     /**
98      * True when the process is frozen.
99      */
100     @GuardedBy("mProcLock")
101     private boolean mFrozen;
102 
103     /**
104      * If set to true it will make the (un)freeze decision sticky which means that the freezer
105      * decision will remain the same unless a freeze is forced via {@link #mForceFreezeOps}.
106      * This property is usually set to true when external user wants to maintain a (un)frozen state
107      * after being applied.
108      */
109     @GuardedBy("mProcLock")
110     private boolean mFreezeSticky;
111 
112     /**
113      * Set to false after the process has been frozen.
114      * Set to true after we have collected PSS for the frozen process.
115      */
116     private boolean mHasCollectedFrozenPSS;
117 
118     /**
119      * An override on the freeze state is in progress.
120      */
121     @GuardedBy("mProcLock")
122     boolean mFreezerOverride;
123 
124     /**
125      * Last time the app was (un)frozen, 0 for never.
126      */
127     @GuardedBy("mProcLock")
128     private long mFreezeUnfreezeTime;
129 
130     /**
131      * True if a process has a WPRI binding from an unfrozen process.
132      */
133     @GuardedBy("mProcLock")
134     private boolean mShouldNotFreeze;
135 
136     /**
137      * Reason for mShouldNotFreeze being set to a particular value.
138      */
139     @GuardedBy("mProcLock")
140     private @ShouldNotFreezeReason int mShouldNotFreezeReason;
141 
142     /**
143      * The value of adjSeq when last time mShouldNotFreeze was set.
144      */
145     @GuardedBy("mProcLock")
146     private int mShouldNotFreezeAdjSeq;
147 
148     /**
149      * Exempt from freezer (now for system apps with INSTALL_PACKAGES permission)
150      */
151     @GuardedBy("mProcLock")
152     private boolean mFreezeExempt;
153 
154     /**
155      * This process has been scheduled for freezing
156      */
157     @GuardedBy("mProcLock")
158     private boolean mPendingFreeze;
159 
160     /**
161      * This is the soonest the process can be allowed to freeze, in uptime millis
162      */
163     @GuardedBy("mProcLock")
164     private @UptimeMillisLong long mEarliestFreezableTimeMillis;
165 
166     /**
167      * This is the most recently used timeout for freezing the app in millis
168      */
169     @GuardedBy("mProcLock")
170     private long mLastUsedTimeout;
171 
172     /**
173      * The list of callbacks for this process whenever it is frozen or unfrozen.
174      */
175     final CopyOnWriteArrayList<Pair<Executor, FrozenProcessListener>> mFrozenProcessListeners =
176             new CopyOnWriteArrayList<>();
177 
178     @GuardedBy("mProcLock")
getLastCompactTime()179     long getLastCompactTime() {
180         return mLastCompactTime;
181     }
182 
183     @GuardedBy("mProcLock")
setLastCompactTime(long lastCompactTime)184     void setLastCompactTime(long lastCompactTime) {
185         mLastCompactTime = lastCompactTime;
186     }
187 
188     @GuardedBy("mProcLock")
getReqCompactProfile()189     CachedAppOptimizer.CompactProfile getReqCompactProfile() {
190         return mReqCompactProfile;
191     }
192 
193     @GuardedBy("mProcLock")
setReqCompactProfile(CachedAppOptimizer.CompactProfile reqCompactProfile)194     void setReqCompactProfile(CachedAppOptimizer.CompactProfile reqCompactProfile) {
195         mReqCompactProfile = reqCompactProfile;
196     }
197 
198     @GuardedBy("mProcLock")
getReqCompactSource()199     CachedAppOptimizer.CompactSource getReqCompactSource() {
200         return mReqCompactSource;
201     }
202 
203     @GuardedBy("mProcLock")
setReqCompactSource(CachedAppOptimizer.CompactSource stat)204     void setReqCompactSource(CachedAppOptimizer.CompactSource stat) {
205         mReqCompactSource = stat;
206     }
207 
208     @GuardedBy("mProcLock")
setLastOomAdjChangeReason(@omAdjReason int reason)209     void setLastOomAdjChangeReason(@OomAdjReason int reason) {
210         mLastOomAdjChangeReason = reason;
211     }
212 
213     @GuardedBy("mProcLock")
214     @OomAdjReason
getLastOomAdjChangeReason()215     int getLastOomAdjChangeReason() {
216         return mLastOomAdjChangeReason;
217     }
218 
219     @GuardedBy("mProcLock")
getLastCompactProfile()220     CachedAppOptimizer.CompactProfile getLastCompactProfile() {
221         if (mLastCompactProfile == null) {
222             // The first compaction won't have a previous one, so assign one to avoid crashing.
223             mLastCompactProfile = CachedAppOptimizer.CompactProfile.SOME;
224         }
225 
226         return mLastCompactProfile;
227     }
228 
229     @GuardedBy("mProcLock")
setLastCompactProfile(CachedAppOptimizer.CompactProfile lastCompactProfile)230     void setLastCompactProfile(CachedAppOptimizer.CompactProfile lastCompactProfile) {
231         mLastCompactProfile = lastCompactProfile;
232     }
233 
234     @GuardedBy("mProcLock")
hasPendingCompact()235     boolean hasPendingCompact() {
236         return mPendingCompact;
237     }
238 
239     @GuardedBy("mProcLock")
setHasPendingCompact(boolean pendingCompact)240     void setHasPendingCompact(boolean pendingCompact) {
241         mPendingCompact = pendingCompact;
242     }
243 
244     @GuardedBy("mProcLock")
isForceCompact()245     boolean isForceCompact() {
246         return mForceCompact;
247     }
248 
249     @GuardedBy("mProcLock")
setForceCompact(boolean forceCompact)250     void setForceCompact(boolean forceCompact) {
251         mForceCompact = forceCompact;
252     }
253 
254     @GuardedBy("mProcLock")
isFrozen()255     boolean isFrozen() {
256         return mFrozen;
257     }
258 
259     @GuardedBy("mProcLock")
setFrozen(boolean frozen)260     void setFrozen(boolean frozen) {
261         mFrozen = frozen;
262     }
263     @GuardedBy("mProcLock")
setFreezeSticky(boolean sticky)264     void setFreezeSticky(boolean sticky) {
265         mFreezeSticky = sticky;
266     }
267 
268     @GuardedBy("mProcLock")
isFreezeSticky()269     boolean isFreezeSticky() {
270         return mFreezeSticky;
271     }
272 
skipPSSCollectionBecauseFrozen()273     boolean skipPSSCollectionBecauseFrozen() {
274         boolean collected = mHasCollectedFrozenPSS;
275 
276         // This check is racy but it isn't critical to PSS collection that we have the most up to
277         // date idea of whether a task is frozen.
278         if (!mFrozen) {
279             // not frozen == always ask to collect PSS
280             return false;
281         }
282 
283         // We don't want to count PSS for a frozen process more than once.
284         mHasCollectedFrozenPSS = true;
285         return collected;
286     }
287 
setHasCollectedFrozenPSS(boolean collected)288     void setHasCollectedFrozenPSS(boolean collected) {
289         mHasCollectedFrozenPSS = collected;
290     }
291 
292     @GuardedBy("mProcLock")
hasFreezerOverride()293     boolean hasFreezerOverride() {
294         return mFreezerOverride;
295     }
296 
297     @GuardedBy("mProcLock")
setFreezerOverride(boolean freezerOverride)298     void setFreezerOverride(boolean freezerOverride) {
299         mFreezerOverride = freezerOverride;
300     }
301 
302     @GuardedBy("mProcLock")
getFreezeUnfreezeTime()303     long getFreezeUnfreezeTime() {
304         return mFreezeUnfreezeTime;
305     }
306 
307     @GuardedBy("mProcLock")
setFreezeUnfreezeTime(long freezeUnfreezeTime)308     void setFreezeUnfreezeTime(long freezeUnfreezeTime) {
309         mFreezeUnfreezeTime = freezeUnfreezeTime;
310     }
311 
312     @GuardedBy("mProcLock")
shouldNotFreeze()313     boolean shouldNotFreeze() {
314         return mShouldNotFreeze;
315     }
316 
317     @GuardedBy("mProcLock")
shouldNotFreezeReason()318     @ShouldNotFreezeReason int shouldNotFreezeReason() {
319         return mShouldNotFreezeReason;
320     }
321 
322     @GuardedBy("mProcLock")
shouldNotFreezeAdjSeq()323     int shouldNotFreezeAdjSeq() {
324         return mShouldNotFreezeAdjSeq;
325     }
326 
327     @GuardedBy("mProcLock")
setShouldNotFreeze(boolean shouldNotFreeze, @ShouldNotFreezeReason int reason, int adjSeq)328     void setShouldNotFreeze(boolean shouldNotFreeze, @ShouldNotFreezeReason int reason,
329             int adjSeq) {
330         setShouldNotFreeze(shouldNotFreeze, false, reason, adjSeq);
331     }
332 
333     /**
334      * @return {@code true} if it's a dry run and it's going to unfreeze the process
335      * if it was a real run.
336      */
337     @GuardedBy("mProcLock")
setShouldNotFreeze(boolean shouldNotFreeze, boolean dryRun, @ShouldNotFreezeReason int reason, int adjSeq)338     boolean setShouldNotFreeze(boolean shouldNotFreeze, boolean dryRun,
339             @ShouldNotFreezeReason int reason, int adjSeq) {
340         if (dryRun) {
341             if (Flags.unfreezeBindPolicyFix()) {
342                 return mShouldNotFreeze != shouldNotFreeze;
343             } else {
344                 return mFrozen && !shouldNotFreeze;
345             }
346         }
347         if (Flags.traceUpdateAppFreezeStateLsp()) {
348             if (shouldNotFreeze) {
349                 reason &= ~SHOULD_NOT_FREEZE_REASON_NONE;
350             } else {
351                 reason = SHOULD_NOT_FREEZE_REASON_NONE;
352             }
353 
354             if (reason != mShouldNotFreezeReason || shouldNotFreeze != mShouldNotFreeze) {
355                 mShouldNotFreezeAdjSeq = adjSeq;
356             }
357             mShouldNotFreezeReason = reason;
358         }
359         mShouldNotFreeze = shouldNotFreeze;
360         return false;
361     }
362 
363     @GuardedBy("mProcLock")
getEarliestFreezableTime()364     @UptimeMillisLong long getEarliestFreezableTime() {
365         return mEarliestFreezableTimeMillis;
366     }
367 
368     @GuardedBy("mProcLock")
setEarliestFreezableTime(@ptimeMillisLong long earliestFreezableTimeMillis)369     void setEarliestFreezableTime(@UptimeMillisLong long earliestFreezableTimeMillis) {
370         mEarliestFreezableTimeMillis = earliestFreezableTimeMillis;
371     }
372 
373     @GuardedBy("mProcLock")
getLastUsedTimeout()374     long getLastUsedTimeout() {
375         return mLastUsedTimeout;
376     }
377 
378     @GuardedBy("mProcLock")
setLastUsedTimeout(long lastUsedTimeout)379     void setLastUsedTimeout(long lastUsedTimeout) {
380         mLastUsedTimeout = lastUsedTimeout;
381     }
382 
383     @GuardedBy("mProcLock")
isFreezeExempt()384     boolean isFreezeExempt() {
385         return mFreezeExempt;
386     }
387 
388     @GuardedBy("mProcLock")
setPendingFreeze(boolean freeze)389     void setPendingFreeze(boolean freeze) {
390         mPendingFreeze = freeze;
391     }
392 
393     @GuardedBy("mProcLock")
isPendingFreeze()394     boolean isPendingFreeze() {
395         return mPendingFreeze;
396     }
397 
398     @GuardedBy("mProcLock")
setFreezeExempt(boolean exempt)399     void setFreezeExempt(boolean exempt) {
400         mFreezeExempt = exempt;
401     }
402 
addFrozenProcessListener(Executor executor, FrozenProcessListener listener)403     void addFrozenProcessListener(Executor executor, FrozenProcessListener listener) {
404         mFrozenProcessListeners.add(new Pair<Executor, FrozenProcessListener>(executor, listener));
405     }
406 
dispatchFrozenEvent()407     void dispatchFrozenEvent() {
408         mFrozenProcessListeners.forEach((pair) -> {
409             pair.first.execute(() -> pair.second.onProcessFrozen(mApp.mPid));
410         });
411     }
412 
dispatchUnfrozenEvent()413     void dispatchUnfrozenEvent() {
414         mFrozenProcessListeners.forEach((pair) -> {
415             pair.first.execute(() -> pair.second.onProcessUnfrozen(mApp.mPid));
416         });
417     }
418 
ProcessCachedOptimizerRecord(ProcessRecord app)419     ProcessCachedOptimizerRecord(ProcessRecord app) {
420         mApp = app;
421         mProcLock = app.mService.mProcLock;
422     }
423 
init(long nowUptime)424     void init(long nowUptime) {
425         mFreezeUnfreezeTime = nowUptime;
426     }
427 
428     @GuardedBy("mProcLock")
429     @NeverCompile
dump(PrintWriter pw, String prefix, long nowUptime)430     void dump(PrintWriter pw, String prefix, long nowUptime) {
431         pw.print(prefix); pw.print("lastCompactTime="); pw.print(mLastCompactTime);
432         pw.print(" lastCompactProfile=");
433         pw.println(mLastCompactProfile);
434         pw.print(prefix);
435         pw.print("hasPendingCompaction=");
436         pw.print(mPendingCompact);
437         pw.print(prefix); pw.print("isFreezeExempt="); pw.print(mFreezeExempt);
438         pw.print(" isPendingFreeze="); pw.print(mPendingFreeze);
439         pw.print(" " + IS_FROZEN + "="); pw.println(mFrozen);
440         pw.print(prefix); pw.print("earliestFreezableTimeMs=");
441         TimeUtils.formatDuration(mEarliestFreezableTimeMillis, nowUptime, pw);
442         if (!mFrozenProcessListeners.isEmpty()) {
443             pw.print(" mFrozenProcessListeners=");
444             mFrozenProcessListeners.forEach((pair) -> pw.print(pair.second + ", "));
445         }
446         pw.println();
447     }
448 }
449