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.UptimeMillisLong;
20 import android.app.ActivityManagerInternal.OomAdjReason;
21 import android.util.TimeUtils;
22 
23 import com.android.internal.annotations.GuardedBy;
24 import com.android.internal.annotations.VisibleForTesting;
25 
26 import java.io.PrintWriter;
27 
28 /**
29  * The state info of app when it's cached, used by the optimizer.
30  */
31 final class ProcessCachedOptimizerRecord {
32     private final ProcessRecord mApp;
33 
34     private final ActivityManagerGlobalLock mProcLock;
35 
36     @VisibleForTesting
37     static final String IS_FROZEN = "isFrozen";
38 
39     /**
40      * The last time that this process was compacted.
41      */
42     @GuardedBy("mProcLock")
43     private long mLastCompactTime;
44 
45     /**
46      * The most recent compaction profile requested for this app.
47      */
48     @GuardedBy("mProcLock") private CachedAppOptimizer.CompactProfile mReqCompactProfile;
49 
50     /**
51      * Source that requested the latest compaction for this app.
52      */
53     @GuardedBy("mProcLock") private CachedAppOptimizer.CompactSource mReqCompactSource;
54 
55     /**
56      * Last oom adjust change reason for this app.
57      */
58     @GuardedBy("mProcLock") private @OomAdjReason int mLastOomAdjChangeReason;
59 
60     /**
61      * The most recent compaction action performed for this app.
62      */
63     @GuardedBy("mProcLock") private CachedAppOptimizer.CompactProfile mLastCompactProfile;
64 
65     /**
66      * This process has been scheduled for a memory compaction.
67      */
68     @GuardedBy("mProcLock")
69     private boolean mPendingCompact;
70 
71     @GuardedBy("mProcLock") private boolean mForceCompact;
72 
73     /**
74      * True when the process is frozen.
75      */
76     @GuardedBy("mProcLock")
77     private boolean mFrozen;
78 
79     /**
80      * If set to true it will make the (un)freeze decision sticky which means that the freezer
81      * decision will remain the same unless a freeze is forced via {@link #mForceFreezeOps}.
82      * This property is usually set to true when external user wants to maintain a (un)frozen state
83      * after being applied.
84      */
85     @GuardedBy("mProcLock")
86     private boolean mFreezeSticky;
87 
88     /**
89      * Set to false after the process has been frozen.
90      * Set to true after we have collected PSS for the frozen process.
91      */
92     private boolean mHasCollectedFrozenPSS;
93 
94     /**
95      * An override on the freeze state is in progress.
96      */
97     @GuardedBy("mProcLock")
98     boolean mFreezerOverride;
99 
100     /**
101      * Last time the app was (un)frozen, 0 for never.
102      */
103     @GuardedBy("mProcLock")
104     private long mFreezeUnfreezeTime;
105 
106     /**
107      * True if a process has a WPRI binding from an unfrozen process.
108      */
109     @GuardedBy("mProcLock")
110     private boolean mShouldNotFreeze;
111 
112     /**
113      * Exempt from freezer (now for system apps with INSTALL_PACKAGES permission)
114      */
115     @GuardedBy("mProcLock")
116     private boolean mFreezeExempt;
117 
118     /**
119      * This process has been scheduled for freezing
120      */
121     @GuardedBy("mProcLock")
122     private boolean mPendingFreeze;
123 
124     /**
125      * This is the soonest the process can be allowed to freeze, in uptime millis
126      */
127     @GuardedBy("mProcLock")
128     private @UptimeMillisLong long mEarliestFreezableTimeMillis;
129 
130     /**
131      * This is the most recently used timeout for freezing the app in millis
132      */
133     @GuardedBy("mProcLock")
134     private long mLastUsedTimeout;
135 
136     @GuardedBy("mProcLock")
getLastCompactTime()137     long getLastCompactTime() {
138         return mLastCompactTime;
139     }
140 
141     @GuardedBy("mProcLock")
setLastCompactTime(long lastCompactTime)142     void setLastCompactTime(long lastCompactTime) {
143         mLastCompactTime = lastCompactTime;
144     }
145 
146     @GuardedBy("mProcLock")
getReqCompactProfile()147     CachedAppOptimizer.CompactProfile getReqCompactProfile() {
148         return mReqCompactProfile;
149     }
150 
151     @GuardedBy("mProcLock")
setReqCompactProfile(CachedAppOptimizer.CompactProfile reqCompactProfile)152     void setReqCompactProfile(CachedAppOptimizer.CompactProfile reqCompactProfile) {
153         mReqCompactProfile = reqCompactProfile;
154     }
155 
156     @GuardedBy("mProcLock")
getReqCompactSource()157     CachedAppOptimizer.CompactSource getReqCompactSource() {
158         return mReqCompactSource;
159     }
160 
161     @GuardedBy("mProcLock")
setReqCompactSource(CachedAppOptimizer.CompactSource stat)162     void setReqCompactSource(CachedAppOptimizer.CompactSource stat) {
163         mReqCompactSource = stat;
164     }
165 
166     @GuardedBy("mProcLock")
setLastOomAdjChangeReason(@omAdjReason int reason)167     void setLastOomAdjChangeReason(@OomAdjReason int reason) {
168         mLastOomAdjChangeReason = reason;
169     }
170 
171     @GuardedBy("mProcLock")
172     @OomAdjReason
getLastOomAdjChangeReason()173     int getLastOomAdjChangeReason() {
174         return mLastOomAdjChangeReason;
175     }
176 
177     @GuardedBy("mProcLock")
getLastCompactProfile()178     CachedAppOptimizer.CompactProfile getLastCompactProfile() {
179         if (mLastCompactProfile == null) {
180             // The first compaction won't have a previous one, so assign one to avoid crashing.
181             mLastCompactProfile = CachedAppOptimizer.CompactProfile.SOME;
182         }
183 
184         return mLastCompactProfile;
185     }
186 
187     @GuardedBy("mProcLock")
setLastCompactProfile(CachedAppOptimizer.CompactProfile lastCompactProfile)188     void setLastCompactProfile(CachedAppOptimizer.CompactProfile lastCompactProfile) {
189         mLastCompactProfile = lastCompactProfile;
190     }
191 
192     @GuardedBy("mProcLock")
hasPendingCompact()193     boolean hasPendingCompact() {
194         return mPendingCompact;
195     }
196 
197     @GuardedBy("mProcLock")
setHasPendingCompact(boolean pendingCompact)198     void setHasPendingCompact(boolean pendingCompact) {
199         mPendingCompact = pendingCompact;
200     }
201 
202     @GuardedBy("mProcLock")
isForceCompact()203     boolean isForceCompact() {
204         return mForceCompact;
205     }
206 
207     @GuardedBy("mProcLock")
setForceCompact(boolean forceCompact)208     void setForceCompact(boolean forceCompact) {
209         mForceCompact = forceCompact;
210     }
211 
212     @GuardedBy("mProcLock")
isFrozen()213     boolean isFrozen() {
214         return mFrozen;
215     }
216 
217     @GuardedBy("mProcLock")
setFrozen(boolean frozen)218     void setFrozen(boolean frozen) {
219         mFrozen = frozen;
220     }
221     @GuardedBy("mProcLock")
setFreezeSticky(boolean sticky)222     void setFreezeSticky(boolean sticky) {
223         mFreezeSticky = sticky;
224     }
225 
226     @GuardedBy("mProcLock")
isFreezeSticky()227     boolean isFreezeSticky() {
228         return mFreezeSticky;
229     }
230 
skipPSSCollectionBecauseFrozen()231     boolean skipPSSCollectionBecauseFrozen() {
232         boolean collected = mHasCollectedFrozenPSS;
233 
234         // This check is racy but it isn't critical to PSS collection that we have the most up to
235         // date idea of whether a task is frozen.
236         if (!mFrozen) {
237             // not frozen == always ask to collect PSS
238             return false;
239         }
240 
241         // We don't want to count PSS for a frozen process more than once.
242         mHasCollectedFrozenPSS = true;
243         return collected;
244     }
245 
setHasCollectedFrozenPSS(boolean collected)246     void setHasCollectedFrozenPSS(boolean collected) {
247         mHasCollectedFrozenPSS = collected;
248     }
249 
250     @GuardedBy("mProcLock")
hasFreezerOverride()251     boolean hasFreezerOverride() {
252         return mFreezerOverride;
253     }
254 
255     @GuardedBy("mProcLock")
setFreezerOverride(boolean freezerOverride)256     void setFreezerOverride(boolean freezerOverride) {
257         mFreezerOverride = freezerOverride;
258     }
259 
260     @GuardedBy("mProcLock")
getFreezeUnfreezeTime()261     long getFreezeUnfreezeTime() {
262         return mFreezeUnfreezeTime;
263     }
264 
265     @GuardedBy("mProcLock")
setFreezeUnfreezeTime(long freezeUnfreezeTime)266     void setFreezeUnfreezeTime(long freezeUnfreezeTime) {
267         mFreezeUnfreezeTime = freezeUnfreezeTime;
268     }
269 
270     @GuardedBy("mProcLock")
shouldNotFreeze()271     boolean shouldNotFreeze() {
272         return mShouldNotFreeze;
273     }
274 
275     @GuardedBy("mProcLock")
setShouldNotFreeze(boolean shouldNotFreeze)276     void setShouldNotFreeze(boolean shouldNotFreeze) {
277         mShouldNotFreeze = shouldNotFreeze;
278     }
279 
280     @GuardedBy("mProcLock")
getEarliestFreezableTime()281     @UptimeMillisLong long getEarliestFreezableTime() {
282         return mEarliestFreezableTimeMillis;
283     }
284 
285     @GuardedBy("mProcLock")
setEarliestFreezableTime(@ptimeMillisLong long earliestFreezableTimeMillis)286     void setEarliestFreezableTime(@UptimeMillisLong long earliestFreezableTimeMillis) {
287         mEarliestFreezableTimeMillis = earliestFreezableTimeMillis;
288     }
289 
290     @GuardedBy("mProcLock")
getLastUsedTimeout()291     long getLastUsedTimeout() {
292         return mLastUsedTimeout;
293     }
294 
295     @GuardedBy("mProcLock")
setLastUsedTimeout(long lastUsedTimeout)296     void setLastUsedTimeout(long lastUsedTimeout) {
297         mLastUsedTimeout = lastUsedTimeout;
298     }
299 
300     @GuardedBy("mProcLock")
isFreezeExempt()301     boolean isFreezeExempt() {
302         return mFreezeExempt;
303     }
304 
305     @GuardedBy("mProcLock")
setPendingFreeze(boolean freeze)306     void setPendingFreeze(boolean freeze) {
307         mPendingFreeze = freeze;
308     }
309 
310     @GuardedBy("mProcLock")
isPendingFreeze()311     boolean isPendingFreeze() {
312         return mPendingFreeze;
313     }
314 
315     @GuardedBy("mProcLock")
setFreezeExempt(boolean exempt)316     void setFreezeExempt(boolean exempt) {
317         mFreezeExempt = exempt;
318     }
319 
ProcessCachedOptimizerRecord(ProcessRecord app)320     ProcessCachedOptimizerRecord(ProcessRecord app) {
321         mApp = app;
322         mProcLock = app.mService.mProcLock;
323     }
324 
init(long nowUptime)325     void init(long nowUptime) {
326         mFreezeUnfreezeTime = nowUptime;
327     }
328 
329     @GuardedBy("mProcLock")
dump(PrintWriter pw, String prefix, long nowUptime)330     void dump(PrintWriter pw, String prefix, long nowUptime) {
331         pw.print(prefix); pw.print("lastCompactTime="); pw.print(mLastCompactTime);
332         pw.print(" lastCompactProfile=");
333         pw.println(mLastCompactProfile);
334         pw.print(prefix);
335         pw.print("hasPendingCompaction=");
336         pw.print(mPendingCompact);
337         pw.print(prefix); pw.print("isFreezeExempt="); pw.print(mFreezeExempt);
338         pw.print(" isPendingFreeze="); pw.print(mPendingFreeze);
339         pw.print(" " + IS_FROZEN + "="); pw.println(mFrozen);
340         pw.print(prefix); pw.print("earliestFreezableTimeMs=");
341         TimeUtils.formatDuration(mEarliestFreezableTimeMillis, nowUptime, pw);
342         pw.println();
343     }
344 }
345