概述:cached app freezer 是将原本需要不可见的随时可以被清理的Activity,进行冻结, 在下次使用时解冻, 从面提升系统保活能力.
开发者选项中开启的入口:
development_settings.xml
设置中开启cached app freezer 功能
CachedAppsFreezerPreferenceController.java
private DialogInterface.OnClickListener getRebootDialogOkListener(Object newValue) {
return (dialog, which) -> {
Settings.Global.putString(mContext.getContentResolver(),
Settings.Global.CACHED_APPS_FREEZER_ENABLED,
newValue.toString());
updateState(mPreference);
PowerManager pm = mContext.getSystemService(PowerManager.class);
pm.reboot(null);
};
}
App Freeze 启用流程
CachedAppOptimizer.java
mAm.mHandler.post(() -> {
if (useFreezer) {
Slog.d(TAG_AM, "Freezer enabled");
enableFreezer(true);
if (!mCachedAppOptimizerThread.isAlive()) {
mCachedAppOptimizerThread.start();
}
if (mFreezeHandler == null) {
mFreezeHandler = new FreezeHandler();
}
Process.setThreadGroupAndCpuset(mCachedAppOptimizerThread.getThreadId(),
Process.THREAD_GROUP_SYSTEM);
} else {
Slog.d(TAG_AM, "Freezer disabled");
enableFreezer(false);
}
});
}
冻结进程
private void freezeProcess(final ProcessRecord proc) {
int pid = proc.getPid(); // Unlocked intentionally
final String name = proc.processName;
final long unfrozenDuration;
final boolean frozen;
final ProcessCachedOptimizerRecord opt = proc.mOptRecord;
opt.setPendingFreeze(false);
try {
// pre-check for locks to avoid unnecessary freeze/unfreeze operations
if (mProcLocksReader.hasFileLocks(pid)) {
if (DEBUG_FREEZER) {
Slog.d(TAG_AM, name + " (" + pid + ") holds file locks, not freezing");
}
return;
}
} catch (Exception e) {
Slog.e(TAG_AM, "Not freezing. Unable to check file locks for " + name + "(" + pid
+ "): " + e);
return;
}
synchronized (mProcLock) {
pid = proc.getPid();
if (proc.mState.getCurAdj() < ProcessList.CACHED_APP_MIN_ADJ
|| opt.shouldNotFreeze()) {
if (DEBUG_FREEZER) {
Slog.d(TAG_AM, "Skipping freeze for process " + pid
+ " " + name + " curAdj = " + proc.mState.getCurAdj()
+ ", shouldNotFreeze = " + opt.shouldNotFreeze());
}
return;
}
if (mFreezerOverride) {
opt.setFreezerOverride(true);
Slog.d(TAG_AM, "Skipping freeze for process " + pid
+ " " + name + " curAdj = " + proc.mState.getCurAdj()
+ "(override)");
return;
}
if (pid == 0 || opt.isFrozen()) {
// Already frozen or not a real process, either one being
// launched or one being killed
return;
}
// Freeze binder interface before the process, to flush any
// transactions that might be pending.
try {
freezeBinder(pid, true);
} catch (RuntimeException e) {
Slog.e(TAG_AM, "Unable to freeze binder for " + pid + " " + name);
mFreezeHandler.post(() -> {
synchronized (mAm) {
proc.killLocked("Unable to freeze binder interface",
ApplicationExitInfo.REASON_OTHER,
ApplicationExitInfo.SUBREASON_FREEZER_BINDER_IOCTL, true);
}
});
}
long unfreezeTime = opt.getFreezeUnfreezeTime();
try {
Process.setProcessFrozen(pid, proc.uid, true);
opt.setFreezeUnfreezeTime(SystemClock.uptimeMillis());
opt.setFrozen(true);
} catch (Exception e) {
Slog.w(TAG_AM, "Unable to freeze " + pid + " " + name);
}
unfrozenDuration = opt.getFreezeUnfreezeTime() - unfreezeTime;
frozen = opt.isFrozen();
}
if (!frozen) {
return;
}
Slog.d(TAG_AM, "froze " + pid + " " + name);
EventLog.writeEvent(EventLogTags.AM_FREEZE, pid, name);
// See above for why we're not taking mPhenotypeFlagLock here
if (mRandom.nextFloat() < mFreezerStatsdSampleRate) {
FrameworkStatsLog.write(FrameworkStatsLog.APP_FREEZE_CHANGED,
FrameworkStatsLog.APP_FREEZE_CHANGED__ACTION__FREEZE_APP,
pid,
name,
unfrozenDuration);
}
try {
// post-check to prevent races
if (mProcLocksReader.hasFileLocks(pid)) {
if (DEBUG_FREEZER) {
Slog.d(TAG_AM, name + " (" + pid + ") holds file locks, reverting freeze");
}
synchronized (mAm) {
synchronized (mProcLock) {
unfreezeAppLSP(proc);
}
}
}
} catch (Exception e) {
Slog.e(TAG_AM, "Unable to check file locks for " + name + "(" + pid + "): " + e);
synchronized (mAm) {
synchronized (mProcLock) {
unfreezeAppLSP(proc);
}
}
}
}
通过 Process.setProcessFrozen(pid, proc.uid, true); 来冻结目标进程
//TODO
// native层冻结原理分析