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