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 @android.ravenwood.annotation.RavenwoodKeepWholeClass 38 public class ProcLocksReader { 39 private final String mPath; 40 private ProcFileReader mReader = null; 41 private IntArray mPids = new IntArray(); 42 ProcLocksReader()43 public ProcLocksReader() { 44 mPath = "/proc/locks"; 45 } 46 ProcLocksReader(String path)47 public ProcLocksReader(String path) { 48 mPath = path; 49 } 50 51 /** 52 * This interface is for AMS to run callback function on every processes one by one 53 * that hold file locks blocking other processes. 54 */ 55 public interface ProcLocksReaderCallback { 56 /** 57 * Call the callback function of handleBlockingFileLocks(). 58 * @param pids Each process that hold file locks blocking other processes. 59 * pids[0] is the process blocking others 60 * pids[1..n-1] are the processes being blocked 61 * NOTE: pids are cleared immediately after onBlockingFileLock() returns. If the caller 62 * needs to cache it, please make a copy, e.g. by calling pids.toArray(). 63 */ onBlockingFileLock(IntArray pids)64 void onBlockingFileLock(IntArray pids); 65 } 66 67 /** 68 * Checks if a process corresponding to a specific pid owns any file locks. 69 * @param callback Callback function, accepting pid as the input parameter. 70 * @throws IOException if /proc/locks can't be accessed or correctly parsed. 71 */ handleBlockingFileLocks(ProcLocksReaderCallback callback)72 public void handleBlockingFileLocks(ProcLocksReaderCallback callback) throws IOException { 73 long last = -1; 74 long id; // ordinal position of the lock in the list 75 int pid = -1; // the PID of the process being blocked 76 77 if (mReader == null) { 78 mReader = new ProcFileReader(new FileInputStream(mPath)); 79 } else { 80 mReader.rewind(); 81 } 82 83 mPids.clear(); 84 while (mReader.hasMoreData()) { 85 id = mReader.nextLong(true); // lock id 86 if (id == last) { 87 // blocked lock found 88 mReader.nextIgnored(); // -> 89 mReader.nextIgnored(); // lock type: POSIX? 90 mReader.nextIgnored(); // lock type: MANDATORY? 91 mReader.nextIgnored(); // lock type: RW? 92 93 pid = mReader.nextInt(); // pid 94 if (pid > 0) { 95 mPids.add(pid); 96 } 97 98 mReader.finishLine(); 99 } else { 100 // process blocking lock and move on to a new lock 101 if (mPids.size() > 1) { 102 callback.onBlockingFileLock(mPids); 103 mPids.clear(); 104 } 105 106 // new lock found 107 mReader.nextIgnored(); // lock type: POSIX? 108 mReader.nextIgnored(); // lock type: MANDATORY? 109 mReader.nextIgnored(); // lock type: RW? 110 111 pid = mReader.nextInt(); // pid 112 if (pid > 0) { 113 if (mPids.size() == 0) { 114 mPids.add(pid); 115 } else { 116 mPids.set(0, pid); 117 } 118 } 119 mReader.finishLine(); 120 last = id; 121 } 122 } 123 // The last unprocessed blocking lock immediately before EOF 124 if (mPids.size() > 1) { 125 callback.onBlockingFileLock(mPids); 126 } 127 } 128 } 129