ActivityManager: don't freeze processes holding file locks

As a temporary measure waiting for the more robust b/176927978 to be
implemented, query the file lock status of processes prior freezing
them, and skip freeze if any locks are held.

Test: verified form the logs that processes holding file locks are not
frozen
Bug: 176928302

Change-Id: Ib7e1715effb63c1b304ce22a9451294fd9f7b10d
Merged-In: Ib7e1715effb63c1b304ce22a9451294fd9f7b10d
This commit is contained in:
Marco Ballesio
2021-01-06 15:25:50 -08:00
parent 2dd4e12e54
commit 80a05232a0
2 changed files with 97 additions and 27 deletions

View File

@@ -31,8 +31,12 @@ import dalvik.system.VMRuntime;
import libcore.io.IoUtils;
import java.io.BufferedReader;
import java.io.FileDescriptor;
import java.io.FileReader;
import java.io.IOException;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.concurrent.TimeoutException;
/**
@@ -1393,4 +1397,38 @@ public class Process {
}
private static native int nativePidFdOpen(int pid, int flags) throws ErrnoException;
/**
* Checks if a process corresponding to a specific pid owns any file locks.
* @param pid The process ID for which we want to know the existence of file locks.
* @return true If the process holds any file locks, false otherwise.
* @throws IOException if /proc/locks can't be accessed.
*
* @hide
*/
public static boolean hasFileLocks(int pid) throws IOException {
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("/proc/locks"));
String line;
while ((line = br.readLine()) != null) {
StringTokenizer st = new StringTokenizer(line);
for (int i = 0; i < 5 && st.hasMoreTokens(); i++) {
String str = st.nextToken();
if (i == 4 && Integer.parseInt(str) == pid) {
return true;
}
}
}
return false;
} finally {
if (br != null) {
br.close();
}
}
}
}

View File

@@ -1101,15 +1101,26 @@ public final class CachedAppOptimizer {
}
private void freezeProcess(ProcessRecord proc) {
final int pid;
final String name;
final int pid = proc.pid;
final String name = proc.processName;
final long unfrozenDuration;
final boolean frozen;
synchronized (mAm) {
pid = proc.pid;
name = proc.processName;
try {
// pre-check for locks to avoid unnecessary freeze/unfreeze operations
if (Process.hasFileLocks(pid)) {
if (DEBUG_FREEZER) {
Slog.d(TAG_AM, name + " (" + pid + ") holds file locks, not freezing");
}
return;
}
} catch (IOException e) {
Slog.e(TAG_AM, "Not freezing. Unable to check file locks for " + name + "(" + pid
+ "): " + e);
return;
}
synchronized (mAm) {
if (proc.curAdj < ProcessList.CACHED_APP_MIN_ADJ
|| proc.shouldNotFreeze) {
if (DEBUG_FREEZER) {
@@ -1141,29 +1152,50 @@ public final class CachedAppOptimizer {
frozen = proc.frozen;
}
if (frozen) {
if (DEBUG_FREEZER) {
Slog.d(TAG_AM, "froze " + pid + " " + name);
if (!frozen) {
return;
}
if (DEBUG_FREEZER) {
Slog.d(TAG_AM, "froze " + pid + " " + name);
}
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,
FrameworkStatsLog.APP_FREEZE_CHANGED__ACTION__FREEZE_APP,
pid,
name,
unfrozenDuration);
}
try {
// post-check to prevent races
if (Process.hasFileLocks(pid)) {
if (DEBUG_FREEZER) {
Slog.d(TAG_AM, name + " (" + pid + ") holds file locks, reverting freeze");
}
synchronized (mAm) {
unfreezeAppLocked(proc);
}
}
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,
FrameworkStatsLog.APP_FREEZE_CHANGED__ACTION__FREEZE_APP,
pid,
name,
unfrozenDuration);
} catch (IOException e) {
Slog.e(TAG_AM, "Unable to check file locks for " + name + "(" + pid + "): " + e);
synchronized (mAm) {
unfreezeAppLocked(proc);
}
}
}