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