Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5b55587f authored by Li Li's avatar Li Li
Browse files

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
parent 00399566
Loading
Loading
Loading
Loading
+46 −17
Original line number Diff line number Diff line
@@ -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?

            owner = mReader.nextInt(); // pid
                pid = mReader.nextInt(); // pid
                if (pid > 0) {
                    if (mPids.size() == 0) {
                        mPids.add(pid);
                    } else {
                        mPids.set(0, pid);
                    }
                }
                mReader.finishLine();
                last = id;
            }
        }
        // The last unprocessed blocking lock immediately before EOF
        if (mPids.size() > 1) {
            callback.onBlockingFileLock(mPids);
        }
    }
}
+41 −27
Original line number Diff line number Diff line
@@ -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());
    }
}
+18 −4
Original line number Diff line number Diff line
@@ -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");
                    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;
                        }
                    }
                }
            }
        }