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