1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.os; 18 19 import android.util.IntArray; 20 21 import com.android.internal.util.ProcFileReader; 22 23 import java.io.FileInputStream; 24 import java.io.IOException; 25 26 /** 27 * Reads and parses {@code locks} files in the {@code proc} filesystem. 28 * A typical example of /proc/locks 29 * 30 * 1: POSIX ADVISORY READ 18403 fd:09:9070 1073741826 1073742335 31 * 2: POSIX ADVISORY WRITE 18292 fd:09:34062 0 EOF 32 * 2: -> POSIX ADVISORY WRITE 18291 fd:09:34062 0 EOF 33 * 2: -> POSIX ADVISORY WRITE 18293 fd:09:34062 0 EOF 34 * 3: POSIX ADVISORY READ 3888 fd:09:13992 128 128 35 * 4: POSIX ADVISORY READ 3888 fd:09:14230 1073741826 1073742335 36 */ 37 public class ProcLocksReader { 38 private final String mPath; 39 private ProcFileReader mReader = null; 40 private IntArray mPids = new IntArray(); 41 ProcLocksReader()42 public ProcLocksReader() { 43 mPath = "/proc/locks"; 44 } 45 ProcLocksReader(String path)46 public ProcLocksReader(String path) { 47 mPath = path; 48 } 49 50 /** 51 * This interface is for AMS to run callback function on every processes one by one 52 * that hold file locks blocking other processes. 53 */ 54 public interface ProcLocksReaderCallback { 55 /** 56 * Call the callback function of handleBlockingFileLocks(). 57 * @param pids Each process that hold file locks blocking other processes. 58 * pids[0] is the process blocking others 59 * pids[1..n-1] are the processes being blocked 60 * NOTE: pids are cleared immediately after onBlockingFileLock() returns. If the caller 61 * needs to cache it, please make a copy, e.g. by calling pids.toArray(). 62 */ onBlockingFileLock(IntArray pids)63 void onBlockingFileLock(IntArray pids); 64 } 65 66 /** 67 * Checks if a process corresponding to a specific pid owns any file locks. 68 * @param callback Callback function, accepting pid as the input parameter. 69 * @throws IOException if /proc/locks can't be accessed or correctly parsed. 70 */ handleBlockingFileLocks(ProcLocksReaderCallback callback)71 public void handleBlockingFileLocks(ProcLocksReaderCallback callback) throws IOException { 72 long last = -1; 73 long id; // ordinal position of the lock in the list 74 int pid = -1; // the PID of the process being blocked 75 76 if (mReader == null) { 77 mReader = new ProcFileReader(new FileInputStream(mPath)); 78 } else { 79 mReader.rewind(); 80 } 81 82 mPids.clear(); 83 while (mReader.hasMoreData()) { 84 id = mReader.nextLong(true); // lock id 85 if (id == last) { 86 // blocked lock found 87 mReader.nextIgnored(); // -> 88 mReader.nextIgnored(); // lock type: POSIX? 89 mReader.nextIgnored(); // lock type: MANDATORY? 90 mReader.nextIgnored(); // lock type: RW? 91 92 pid = mReader.nextInt(); // pid 93 if (pid > 0) { 94 mPids.add(pid); 95 } 96 97 mReader.finishLine(); 98 } else { 99 // process blocking lock and move on to a new lock 100 if (mPids.size() > 1) { 101 callback.onBlockingFileLock(mPids); 102 mPids.clear(); 103 } 104 105 // new lock found 106 mReader.nextIgnored(); // lock type: POSIX? 107 mReader.nextIgnored(); // lock type: MANDATORY? 108 mReader.nextIgnored(); // lock type: RW? 109 110 pid = mReader.nextInt(); // pid 111 if (pid > 0) { 112 if (mPids.size() == 0) { 113 mPids.add(pid); 114 } else { 115 mPids.set(0, pid); 116 } 117 } 118 mReader.finishLine(); 119 last = id; 120 } 121 } 122 // The last unprocessed blocking lock immediately before EOF 123 if (mPids.size() > 1) { 124 callback.onBlockingFileLock(mPids); 125 } 126 } 127 } 128