CachedAppOptimizer: adapt freezer to uid/pid hiearchy.
The uid/pid hierarchy freezer is supported if the cgroup.freeze file is present under any uid cgroup. Check on uid_0 which is granted to exist. Also handle binder when enabling/disabling freezer. Freeze the binder interfaces for all froze processes after enabling the app freezer. Similarly, unfreeze the interfaces of frozen processes when the app freezer is enabled. Bug: 168907513 Bug: 173173405 Test: verified proper functioning of the freezer after boot on devices supporting the uid/pid hierarchy. Test: ran "adb shell am dumpsys meminfo -a", verified that no processes were killed by ActivityManager and that the command did not hang. Change-Id: Ia7fa25cb6c59da73d34460ead4833cec69f7f6bc
This commit is contained in:
@@ -232,6 +232,8 @@ public final class CachedAppOptimizer {
|
||||
@VisibleForTesting
|
||||
Handler mCompactionHandler;
|
||||
private Handler mFreezeHandler;
|
||||
@GuardedBy("mAm")
|
||||
private boolean mFreezerOverride = false;
|
||||
|
||||
// Maps process ID to last compaction statistics for processes that we've fully compacted. Used
|
||||
// when evaluating throttles that we only consider for "full" compaction, so we don't store
|
||||
@@ -454,21 +456,35 @@ public final class CachedAppOptimizer {
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
enableFreezerInternal(enable);
|
||||
return true;
|
||||
} catch (java.lang.RuntimeException e) {
|
||||
if (enable) {
|
||||
mFreezerDisableCount = 0;
|
||||
} else {
|
||||
mFreezerDisableCount = 1;
|
||||
}
|
||||
// Override is applied immediately, restore is delayed
|
||||
synchronized (mAm) {
|
||||
int processCount = mAm.mProcessList.mLruProcesses.size();
|
||||
|
||||
Slog.e(TAG_AM, "Exception handling freezer state (enable: " + enable + "): "
|
||||
+ e.toString());
|
||||
mFreezerOverride = !enable;
|
||||
Slog.d(TAG_AM, "freezer override set to " + mFreezerOverride);
|
||||
|
||||
for (int i = 0; i < processCount; i++) {
|
||||
ProcessRecord process = mAm.mProcessList.mLruProcesses.get(i);
|
||||
|
||||
if (process == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (enable && process.freezerOverride) {
|
||||
freezeAppAsync(process);
|
||||
process.freezerOverride = false;
|
||||
}
|
||||
|
||||
if (!enable && process.frozen) {
|
||||
unfreezeAppLocked(process);
|
||||
|
||||
// Set freezerOverride *after* calling unfreezeAppLocked (it resets the flag)
|
||||
process.freezerOverride = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -515,7 +531,7 @@ public final class CachedAppOptimizer {
|
||||
FileReader fr = null;
|
||||
|
||||
try {
|
||||
fr = new FileReader("/sys/fs/cgroup/freezer/cgroup.freeze");
|
||||
fr = new FileReader("/sys/fs/cgroup/uid_0/cgroup.freeze");
|
||||
char state = (char) fr.read();
|
||||
|
||||
if (state == '1' || state == '0') {
|
||||
@@ -744,6 +760,8 @@ public final class CachedAppOptimizer {
|
||||
void unfreezeAppLocked(ProcessRecord app) {
|
||||
mFreezeHandler.removeMessages(SET_FROZEN_PROCESS_MSG, app);
|
||||
|
||||
app.freezerOverride = false;
|
||||
|
||||
if (!app.frozen) {
|
||||
if (DEBUG_FREEZER) {
|
||||
Slog.d(TAG_AM,
|
||||
@@ -753,6 +771,8 @@ public final class CachedAppOptimizer {
|
||||
return;
|
||||
}
|
||||
|
||||
// Unfreeze the binder interface first, to avoid transactions triggered by timers fired
|
||||
// right after unfreezing the process to fail
|
||||
boolean processKilled = false;
|
||||
|
||||
try {
|
||||
@@ -1131,12 +1151,31 @@ public final class CachedAppOptimizer {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mFreezerOverride) {
|
||||
proc.freezerOverride = true;
|
||||
Slog.d(TAG_AM, "Skipping freeze for process " + pid
|
||||
+ " " + name + " curAdj = " + proc.curAdj
|
||||
+ "(override)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pid == 0 || proc.frozen) {
|
||||
// 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);
|
||||
proc.kill("Unable to freeze binder interface",
|
||||
ApplicationExitInfo.REASON_OTHER,
|
||||
ApplicationExitInfo.SUBREASON_INVALID_STATE, true);
|
||||
}
|
||||
|
||||
long unfreezeTime = proc.freezeUnfreezeTime;
|
||||
|
||||
try {
|
||||
@@ -1163,15 +1202,6 @@ public final class CachedAppOptimizer {
|
||||
|
||||
EventLog.writeEvent(EventLogTags.AM_FREEZE, pid, name);
|
||||
|
||||
try {
|
||||
freezeBinder(pid, true);
|
||||
} catch (RuntimeException e) {
|
||||
Slog.e(TAG_AM, "Unable to freeze binder for " + pid + " " + name);
|
||||
proc.kill("Unable to freeze binder interface",
|
||||
ApplicationExitInfo.REASON_OTHER,
|
||||
ApplicationExitInfo.SUBREASON_INVALID_STATE, true);
|
||||
}
|
||||
|
||||
// See above for why we're not taking mPhenotypeFlagLock here
|
||||
if (mRandom.nextFloat() < mFreezerStatsdSampleRate) {
|
||||
FrameworkStatsLog.write(FrameworkStatsLog.APP_FREEZE_CHANGED,
|
||||
|
||||
@@ -179,6 +179,7 @@ class ProcessRecord implements WindowProcessListener {
|
||||
int reqCompactAction; // The most recent compaction action requested for this app.
|
||||
int lastCompactAction; // The most recent compaction action performed for this app.
|
||||
boolean frozen; // True when the process is frozen.
|
||||
boolean freezerOverride; // An override on the freeze state is in progress.
|
||||
long freezeUnfreezeTime; // Last time the app was (un)frozen, 0 for never
|
||||
boolean shouldNotFreeze; // True if a process has a WPRI binding from an unfrozen process
|
||||
private int mCurSchedGroup; // Currently desired scheduling class
|
||||
|
||||
Reference in New Issue
Block a user