1 /* 2 * Copyright (C) 2018 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.os.StrictMode; 20 import android.text.TextUtils; 21 import android.util.Slog; 22 23 import com.android.internal.annotations.VisibleForTesting; 24 25 import java.io.BufferedReader; 26 import java.io.File; 27 import java.io.IOException; 28 import java.nio.file.Files; 29 30 31 /** 32 * Reads /proc/uid_io/stats which has the line format: 33 * 34 * uid: foreground_read_chars foreground_write_chars foreground_read_bytes foreground_write_bytes 35 * background_read_chars background_write_chars background_read_bytes background_write_bytes 36 * foreground_fsync background_fsync 37 * 38 * This provides the number of bytes/chars read/written in foreground/background for each uid. 39 * The file contains a monotonically increasing count of bytes/chars for a single boot. 40 */ 41 public class StoragedUidIoStatsReader { 42 43 private static final String TAG = StoragedUidIoStatsReader.class.getSimpleName(); 44 private static String sUidIoFile = "/proc/uid_io/stats"; 45 StoragedUidIoStatsReader()46 public StoragedUidIoStatsReader() { 47 } 48 49 @VisibleForTesting StoragedUidIoStatsReader(String file)50 public StoragedUidIoStatsReader(String file) { 51 sUidIoFile = file; 52 } 53 54 /** 55 * Notifies when new data is available. 56 */ 57 public interface Callback { 58 59 /** 60 * Provides data to the client. 61 * 62 * Note: Bytes are I/O events from a storage device. Chars are data requested by syscalls, 63 * and can be satisfied by caching. 64 */ onUidStorageStats(int uid, long fgCharsRead, long fgCharsWrite, long fgBytesRead, long fgBytesWrite, long bgCharsRead, long bgCharsWrite, long bgBytesRead, long bgBytesWrite, long fgFsync, long bgFsync)65 void onUidStorageStats(int uid, long fgCharsRead, long fgCharsWrite, long fgBytesRead, 66 long fgBytesWrite, long bgCharsRead, long bgCharsWrite, long bgBytesRead, 67 long bgBytesWrite, long fgFsync, long bgFsync); 68 } 69 70 /** 71 * Reads the proc file, calling into the callback with raw absolute value of I/O stats 72 * for each UID. 73 * 74 * @param callback The callback to invoke for each line of the proc file. 75 */ readAbsolute(Callback callback)76 public void readAbsolute(Callback callback) { 77 final int oldMask = StrictMode.allowThreadDiskReadsMask(); 78 File file = new File(sUidIoFile); 79 try (BufferedReader reader = Files.newBufferedReader(file.toPath())) { 80 String line; 81 while ((line = reader.readLine()) != null) { 82 String[] fields = TextUtils.split(line, " "); 83 if (fields.length != 11) { 84 Slog.e(TAG, "Malformed entry in " + sUidIoFile + ": " + line); 85 continue; 86 } 87 try { 88 final String uidStr = fields[0]; 89 final int uid = Integer.parseInt(fields[0], 10); 90 final long fgCharsRead = Long.parseLong(fields[1], 10); 91 final long fgCharsWrite = Long.parseLong(fields[2], 10); 92 final long fgBytesRead = Long.parseLong(fields[3], 10); 93 final long fgBytesWrite = Long.parseLong(fields[4], 10); 94 final long bgCharsRead = Long.parseLong(fields[5], 10); 95 final long bgCharsWrite = Long.parseLong(fields[6], 10); 96 final long bgBytesRead = Long.parseLong(fields[7], 10); 97 final long bgBytesWrite = Long.parseLong(fields[8], 10); 98 final long fgFsync = Long.parseLong(fields[9], 10); 99 final long bgFsync = Long.parseLong(fields[10], 10); 100 callback.onUidStorageStats(uid, fgCharsRead, fgCharsWrite, fgBytesRead, 101 fgBytesWrite, bgCharsRead, bgCharsWrite, bgBytesRead, bgBytesWrite, 102 fgFsync, bgFsync); 103 } catch (NumberFormatException e) { 104 Slog.e(TAG, "Could not parse entry in " + sUidIoFile + ": " + e.getMessage()); 105 } 106 } 107 } catch (IOException e) { 108 Slog.e(TAG, "Failed to read " + sUidIoFile + ": " + e.getMessage()); 109 } finally { 110 StrictMode.setThreadPolicyMask(oldMask); 111 } 112 } 113 } 114