Freezer: improve file lock exemption
When a process becomes cached and holds file locks blocking other processes, check whether those blocked processes are also in cached mode. If they are also cached, freeze the current process. Otherwise, Skip the current process to avoid deadlock. Bug: 245994713 Bug: 253913470 Test: atest ProcLocksReaderTest Test: verify apps with deadlock can be frozen Change-Id: I8635bf877bbe4404cc66955f1946444265680246
This commit is contained in:
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.internal.os;
|
||||
|
||||
import android.util.IntArray;
|
||||
|
||||
import com.android.internal.util.ProcFileReader;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
@@ -35,6 +37,7 @@ import java.io.IOException;
|
||||
public class ProcLocksReader {
|
||||
private final String mPath;
|
||||
private ProcFileReader mReader = null;
|
||||
private IntArray mPids = new IntArray();
|
||||
|
||||
public ProcLocksReader() {
|
||||
mPath = "/proc/locks";
|
||||
@@ -51,9 +54,13 @@ public class ProcLocksReader {
|
||||
public interface ProcLocksReaderCallback {
|
||||
/**
|
||||
* Call the callback function of handleBlockingFileLocks().
|
||||
* @param pid Each process that hold file locks blocking other processes.
|
||||
* @param pids Each process that hold file locks blocking other processes.
|
||||
* pids[0] is the process blocking others
|
||||
* pids[1..n-1] are the processes being blocked
|
||||
* NOTE: pids are cleared immediately after onBlockingFileLock() returns. If the caller
|
||||
* needs to cache it, please make a copy, e.g. by calling pids.toArray().
|
||||
*/
|
||||
void onBlockingFileLock(int pid);
|
||||
void onBlockingFileLock(IntArray pids);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,8 +71,7 @@ public class ProcLocksReader {
|
||||
public void handleBlockingFileLocks(ProcLocksReaderCallback callback) throws IOException {
|
||||
long last = -1;
|
||||
long id; // ordinal position of the lock in the list
|
||||
int owner = -1; // the PID of the process that owns the lock
|
||||
int pid = -1; // the PID of the process blocking others
|
||||
int pid = -1; // the PID of the process being blocked
|
||||
|
||||
if (mReader == null) {
|
||||
mReader = new ProcFileReader(new FileInputStream(mPath));
|
||||
@@ -73,26 +79,49 @@ public class ProcLocksReader {
|
||||
mReader.rewind();
|
||||
}
|
||||
|
||||
mPids.clear();
|
||||
while (mReader.hasMoreData()) {
|
||||
id = mReader.nextLong(true); // lock id
|
||||
if (id == last) {
|
||||
mReader.finishLine(); // blocked lock
|
||||
if (pid < 0) {
|
||||
pid = owner; // get pid from the previous line
|
||||
callback.onBlockingFileLock(pid);
|
||||
// blocked lock found
|
||||
mReader.nextIgnored(); // ->
|
||||
mReader.nextIgnored(); // lock type: POSIX?
|
||||
mReader.nextIgnored(); // lock type: MANDATORY?
|
||||
mReader.nextIgnored(); // lock type: RW?
|
||||
|
||||
pid = mReader.nextInt(); // pid
|
||||
if (pid > 0) {
|
||||
mPids.add(pid);
|
||||
}
|
||||
continue;
|
||||
|
||||
mReader.finishLine();
|
||||
} else {
|
||||
pid = -1; // a new lock
|
||||
// process blocking lock and move on to a new lock
|
||||
if (mPids.size() > 1) {
|
||||
callback.onBlockingFileLock(mPids);
|
||||
mPids.clear();
|
||||
}
|
||||
|
||||
// new lock found
|
||||
mReader.nextIgnored(); // lock type: POSIX?
|
||||
mReader.nextIgnored(); // lock type: MANDATORY?
|
||||
mReader.nextIgnored(); // lock type: RW?
|
||||
|
||||
pid = mReader.nextInt(); // pid
|
||||
if (pid > 0) {
|
||||
if (mPids.size() == 0) {
|
||||
mPids.add(pid);
|
||||
} else {
|
||||
mPids.set(0, pid);
|
||||
}
|
||||
}
|
||||
mReader.finishLine();
|
||||
last = id;
|
||||
}
|
||||
|
||||
mReader.nextIgnored(); // lock type: POSIX?
|
||||
mReader.nextIgnored(); // lock type: MANDATORY?
|
||||
mReader.nextIgnored(); // lock type: RW?
|
||||
|
||||
owner = mReader.nextInt(); // pid
|
||||
mReader.finishLine();
|
||||
last = id;
|
||||
}
|
||||
// The last unprocessed blocking lock immediately before EOF
|
||||
if (mPids.size() > 1) {
|
||||
callback.onBlockingFileLock(mPids);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.FileUtils;
|
||||
import android.util.IntArray;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
@@ -33,13 +34,15 @@ import org.junit.runner.RunWith;
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ProcLocksReaderTest implements
|
||||
ProcLocksReader.ProcLocksReaderCallback {
|
||||
private File mProcDirectory;
|
||||
private ArrayList<Integer> mPids = new ArrayList<>();
|
||||
|
||||
private ArrayList<int[]> mPids = new ArrayList<>();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@@ -54,41 +57,51 @@ public class ProcLocksReaderTest implements
|
||||
|
||||
@Test
|
||||
public void testRunSimpleLocks() throws Exception {
|
||||
String simpleLocks =
|
||||
"1: POSIX ADVISORY READ 18403 fd:09:9070 1073741826 1073742335\n" +
|
||||
"2: POSIX ADVISORY WRITE 18292 fd:09:34062 0 EOF\n";
|
||||
String simpleLocks = "1: POSIX ADVISORY READ 18403 fd:09:9070 1073741826 1073742335\n"
|
||||
+ "2: POSIX ADVISORY WRITE 18292 fd:09:34062 0 EOF\n";
|
||||
runHandleBlockingFileLocks(simpleLocks);
|
||||
assertTrue(mPids.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRunBlockingLocks() throws Exception {
|
||||
String blockedLocks =
|
||||
"1: POSIX ADVISORY READ 18403 fd:09:9070 1073741826 1073742335\n" +
|
||||
"2: POSIX ADVISORY WRITE 18292 fd:09:34062 0 EOF\n" +
|
||||
"2: -> POSIX ADVISORY WRITE 18291 fd:09:34062 0 EOF\n" +
|
||||
"2: -> POSIX ADVISORY WRITE 18293 fd:09:34062 0 EOF\n" +
|
||||
"3: POSIX ADVISORY READ 3888 fd:09:13992 128 128\n" +
|
||||
"4: POSIX ADVISORY READ 3888 fd:09:14230 1073741826 1073742335\n";
|
||||
String blockedLocks = "1: POSIX ADVISORY READ 18403 fd:09:9070 1073741826 1073742335\n"
|
||||
+ "2: POSIX ADVISORY WRITE 18292 fd:09:34062 0 EOF\n"
|
||||
+ "2: -> POSIX ADVISORY WRITE 18291 fd:09:34062 0 EOF\n"
|
||||
+ "2: -> POSIX ADVISORY WRITE 18293 fd:09:34062 0 EOF\n"
|
||||
+ "3: POSIX ADVISORY READ 3888 fd:09:13992 128 128\n"
|
||||
+ "4: POSIX ADVISORY READ 3888 fd:09:14230 1073741826 1073742335\n";
|
||||
runHandleBlockingFileLocks(blockedLocks);
|
||||
assertTrue(mPids.remove(0).equals(18292));
|
||||
assertTrue(Arrays.equals(mPids.remove(0), new int[]{18292, 18291, 18293}));
|
||||
assertTrue(mPids.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRunLastBlockingLocks() throws Exception {
|
||||
String blockedLocks = "1: POSIX ADVISORY READ 18403 fd:09:9070 1073741826 1073742335\n"
|
||||
+ "2: POSIX ADVISORY WRITE 18292 fd:09:34062 0 EOF\n"
|
||||
+ "2: -> POSIX ADVISORY WRITE 18291 fd:09:34062 0 EOF\n"
|
||||
+ "2: -> POSIX ADVISORY WRITE 18293 fd:09:34062 0 EOF\n";
|
||||
runHandleBlockingFileLocks(blockedLocks);
|
||||
assertTrue(Arrays.equals(mPids.remove(0), new int[]{18292, 18291, 18293}));
|
||||
assertTrue(mPids.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRunMultipleBlockingLocks() throws Exception {
|
||||
String blockedLocks =
|
||||
"1: POSIX ADVISORY READ 18403 fd:09:9070 1073741826 1073742335\n" +
|
||||
"2: POSIX ADVISORY WRITE 18292 fd:09:34062 0 EOF\n" +
|
||||
"2: -> POSIX ADVISORY WRITE 18291 fd:09:34062 0 EOF\n" +
|
||||
"2: -> POSIX ADVISORY WRITE 18293 fd:09:34062 0 EOF\n" +
|
||||
"3: POSIX ADVISORY READ 3888 fd:09:13992 128 128\n" +
|
||||
"4: FLOCK ADVISORY WRITE 3840 fe:01:5111809 0 EOF\n" +
|
||||
"4: -> FLOCK ADVISORY WRITE 3841 fe:01:5111809 0 EOF\n" +
|
||||
"5: POSIX ADVISORY READ 3888 fd:09:14230 1073741826 1073742335\n";
|
||||
String blockedLocks = "1: POSIX ADVISORY READ 18403 fd:09:9070 1073741826 1073742335\n"
|
||||
+ "2: POSIX ADVISORY WRITE 18292 fd:09:34062 0 EOF\n"
|
||||
+ "2: -> POSIX ADVISORY WRITE 18291 fd:09:34062 0 EOF\n"
|
||||
+ "2: -> POSIX ADVISORY WRITE 18293 fd:09:34062 0 EOF\n"
|
||||
+ "3: POSIX ADVISORY READ 3888 fd:09:13992 128 128\n"
|
||||
+ "4: FLOCK ADVISORY WRITE 3840 fe:01:5111809 0 EOF\n"
|
||||
+ "4: -> FLOCK ADVISORY WRITE 3841 fe:01:5111809 0 EOF\n"
|
||||
+ "5: FLOCK ADVISORY READ 3888 fd:09:14230 0 EOF\n"
|
||||
+ "5: -> FLOCK ADVISORY READ 3887 fd:09:14230 0 EOF\n";
|
||||
runHandleBlockingFileLocks(blockedLocks);
|
||||
assertTrue(mPids.remove(0).equals(18292));
|
||||
assertTrue(mPids.remove(0).equals(3840));
|
||||
assertTrue(Arrays.equals(mPids.remove(0), new int[]{18292, 18291, 18293}));
|
||||
assertTrue(Arrays.equals(mPids.remove(0), new int[]{3840, 3841}));
|
||||
assertTrue(Arrays.equals(mPids.remove(0), new int[]{3888, 3887}));
|
||||
assertTrue(mPids.isEmpty());
|
||||
}
|
||||
|
||||
@@ -102,11 +115,12 @@ public class ProcLocksReaderTest implements
|
||||
|
||||
/**
|
||||
* Call the callback function of handleBlockingFileLocks().
|
||||
*
|
||||
* @param pid Each process that hold file locks blocking other processes.
|
||||
* @param pids Each process that hold file locks blocking other processes.
|
||||
* pids[0] is the process blocking others
|
||||
* pids[1..n-1] are the processes being blocked
|
||||
*/
|
||||
@Override
|
||||
public void onBlockingFileLock(int pid) {
|
||||
mPids.add(pid);
|
||||
public void onBlockingFileLock(IntArray pids) {
|
||||
mPids.add(pids.toArray());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import android.provider.DeviceConfig.Properties;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.util.EventLog;
|
||||
import android.util.IntArray;
|
||||
import android.util.Pair;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
@@ -2110,15 +2111,28 @@ public final class CachedAppOptimizer {
|
||||
|
||||
@GuardedBy({"mAm"})
|
||||
@Override
|
||||
public void onBlockingFileLock(int pid) {
|
||||
public void onBlockingFileLock(IntArray pids) {
|
||||
if (DEBUG_FREEZER) {
|
||||
Slog.d(TAG_AM, "Process (pid=" + pid + ") holds blocking file lock");
|
||||
Slog.d(TAG_AM, "Blocking file lock found: " + pids);
|
||||
}
|
||||
synchronized (mProcLock) {
|
||||
int pid = pids.get(0);
|
||||
ProcessRecord app = mFrozenProcesses.get(pid);
|
||||
ProcessRecord pr;
|
||||
if (app != null) {
|
||||
Slog.i(TAG_AM, app.processName + " (" + pid + ") holds blocking file lock");
|
||||
unfreezeAppLSP(app, OomAdjuster.OOM_ADJ_REASON_NONE);
|
||||
for (int i = 1; i < pids.size(); i++) {
|
||||
int blocked = pids.get(i);
|
||||
synchronized (mAm.mPidsSelfLocked) {
|
||||
pr = mAm.mPidsSelfLocked.get(blocked);
|
||||
}
|
||||
if (pr != null && pr.mState.getCurAdj() < ProcessList.CACHED_APP_MIN_ADJ) {
|
||||
Slog.d(TAG_AM, app.processName + " (" + pid + ") blocks "
|
||||
+ pr.processName + " (" + blocked + ")");
|
||||
// Found at least one blocked non-cached process
|
||||
unfreezeAppLSP(app, OomAdjuster.OOM_ADJ_REASON_NONE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user