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
This commit is contained in:
Marco Ballesio
2021-01-06 15:25:50 -08:00
parent 565151c564
commit 770df97bef
2 changed files with 96 additions and 27 deletions

View File

@@ -31,9 +31,12 @@ import dalvik.system.VMRuntime;
import libcore.io.IoUtils; import libcore.io.IoUtils;
import java.io.BufferedReader;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.Map;
import java.util.StringTokenizer;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
/** /**
@@ -1430,4 +1433,38 @@ public class Process {
} }
private static native int nativePidFdOpen(int pid, int flags) throws ErrnoException; 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) { private void freezeProcess(ProcessRecord proc) {
final int pid; final int pid = proc.pid;
final String name; final String name = proc.processName;
final long unfrozenDuration; final long unfrozenDuration;
final boolean frozen; final boolean frozen;
synchronized (mAm) { try {
pid = proc.pid; // pre-check for locks to avoid unnecessary freeze/unfreeze operations
name = proc.processName; 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 if (proc.curAdj < ProcessList.CACHED_APP_MIN_ADJ
|| proc.shouldNotFreeze) { || proc.shouldNotFreeze) {
if (DEBUG_FREEZER) { if (DEBUG_FREEZER) {
@@ -1141,7 +1152,11 @@ public final class CachedAppOptimizer {
frozen = proc.frozen; frozen = proc.frozen;
} }
if (frozen) { if (!frozen) {
return;
}
if (DEBUG_FREEZER) { if (DEBUG_FREEZER) {
Slog.d(TAG_AM, "froze " + pid + " " + name); Slog.d(TAG_AM, "froze " + pid + " " + name);
} }
@@ -1165,6 +1180,23 @@ public final class CachedAppOptimizer {
name, name,
unfrozenDuration); 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);
}
}
} catch (IOException e) {
Slog.e(TAG_AM, "Unable to check file locks for " + name + "(" + pid + "): " + e);
synchronized (mAm) {
unfreezeAppLocked(proc);
}
} }
} }