1 /* 2 * Copyright (C) 2017 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 package com.android.internal.os; 17 18 import static android.os.Process.*; 19 20 import android.annotation.Nullable; 21 import android.os.Process; 22 import android.util.SparseArray; 23 24 public final class ProcfsMemoryUtil { 25 private static final int[] CMDLINE_OUT = new int[] { PROC_OUT_STRING }; 26 private static final int[] OOM_SCORE_ADJ_OUT = new int[] { PROC_NEWLINE_TERM | PROC_OUT_LONG }; 27 private static final String[] STATUS_KEYS = new String[] { 28 "Uid:", 29 "VmHWM:", 30 "VmRSS:", 31 "RssAnon:", 32 "RssShmem:", 33 "VmSwap:", 34 }; 35 private static final String[] VMSTAT_KEYS = new String[] { 36 "oom_kill" 37 }; 38 ProcfsMemoryUtil()39 private ProcfsMemoryUtil() {} 40 41 /** 42 * Reads memory stats of a process from procfs. 43 * 44 * Returns values of the VmHWM, VmRss, AnonRSS, VmSwap, RssShmem fields in 45 * /proc/pid/status in kilobytes or null if not available. 46 */ 47 @Nullable readMemorySnapshotFromProcfs(int pid)48 public static MemorySnapshot readMemorySnapshotFromProcfs(int pid) { 49 return readMemorySnapshotFromProcfs("/proc/" + pid + "/status"); 50 } 51 52 /** 53 * Reads memory stats of the current process from procfs. 54 * 55 * Returns values of the VmHWM, VmRss, AnonRSS, VmSwap, RssShmem fields in 56 * /proc/self/status in kilobytes or null if not available. 57 */ 58 @Nullable readMemorySnapshotFromProcfs()59 public static MemorySnapshot readMemorySnapshotFromProcfs() { 60 return readMemorySnapshotFromProcfs("/proc/self/status"); 61 } 62 readMemorySnapshotFromProcfs(String path)63 private static MemorySnapshot readMemorySnapshotFromProcfs(String path) { 64 long[] output = new long[STATUS_KEYS.length]; 65 output[0] = -1; 66 output[3] = -1; 67 output[4] = -1; 68 output[5] = -1; 69 Process.readProcLines(path, STATUS_KEYS, output); 70 if (output[0] == -1 || output[3] == -1 || output[4] == -1 || output[5] == -1) { 71 // Could not open or parse file. 72 return null; 73 } 74 final MemorySnapshot snapshot = new MemorySnapshot(); 75 snapshot.uid = (int) output[0]; 76 snapshot.rssHighWaterMarkInKilobytes = (int) output[1]; 77 snapshot.rssInKilobytes = (int) output[2]; 78 snapshot.anonRssInKilobytes = (int) output[3]; 79 snapshot.rssShmemKilobytes = (int) output[4]; 80 snapshot.swapInKilobytes = (int) output[5]; 81 return snapshot; 82 } 83 84 /** 85 * Reads cmdline of a process from procfs. 86 * 87 * Returns content of /proc/pid/cmdline (e.g. /system/bin/statsd) or an empty string 88 * if the file is not available. 89 */ readCmdlineFromProcfs(int pid)90 public static String readCmdlineFromProcfs(int pid) { 91 return readCmdlineFromProcfs("/proc/" + pid + "/cmdline"); 92 } 93 94 /** 95 * Reads cmdline of the current process from procfs. 96 * 97 * Returns content of /proc/pid/cmdline (e.g. /system/bin/statsd) or an empty string 98 * if the file is not available. 99 */ readCmdlineFromProcfs()100 public static String readCmdlineFromProcfs() { 101 return readCmdlineFromProcfs("/proc/self/cmdline"); 102 } 103 readCmdlineFromProcfs(String path)104 private static String readCmdlineFromProcfs(String path) { 105 String[] cmdline = new String[1]; 106 if (!Process.readProcFile(path, CMDLINE_OUT, cmdline, null, null)) { 107 return ""; 108 } 109 return cmdline[0]; 110 } 111 112 /** 113 * Reads oom_score_adj of a process from procfs 114 * 115 * Returns content of /proc/pid/oom_score_adj. Defaults to 0 if reading fails. 116 */ readOomScoreAdjFromProcfs(int pid)117 public static int readOomScoreAdjFromProcfs(int pid) { 118 return readOomScoreAdjFromProcfs("/proc/" + pid + "/oom_score_adj"); 119 } 120 121 /** 122 * Reads oom_score_adj of the current process from procfs 123 * 124 * Returns content of /proc/pid/oom_score_adj. Defaults to 0 if reading fails. 125 */ readOomScoreAdjFromProcfs()126 public static int readOomScoreAdjFromProcfs() { 127 return readOomScoreAdjFromProcfs("/proc/self/oom_score_adj"); 128 } 129 readOomScoreAdjFromProcfs(String path)130 private static int readOomScoreAdjFromProcfs(String path) { 131 long[] oom_score_adj = new long[1]; 132 if (Process.readProcFile(path, OOM_SCORE_ADJ_OUT, null, oom_score_adj, null)) { 133 return (int)oom_score_adj[0]; 134 } 135 return 0; 136 } 137 138 /** 139 * Scans all /proc/pid/cmdline entries and returns a mapping between pid and cmdline. 140 */ getProcessCmdlines()141 public static SparseArray<String> getProcessCmdlines() { 142 int[] pids = new int[1024]; 143 pids = Process.getPids("/proc", pids); 144 145 SparseArray<String> cmdlines = new SparseArray<>(pids.length); 146 for (int pid : pids) { 147 if (pid < 0) { 148 break; 149 } 150 String cmdline = readCmdlineFromProcfs(pid); 151 if (cmdline.isEmpty()) { 152 continue; 153 } 154 cmdlines.append(pid, cmdline); 155 } 156 return cmdlines; 157 } 158 159 public static final class MemorySnapshot { 160 public int uid; 161 public int rssHighWaterMarkInKilobytes; 162 public int rssInKilobytes; 163 public int anonRssInKilobytes; 164 public int swapInKilobytes; 165 public int rssShmemKilobytes; 166 } 167 168 /** Reads and parses selected entries of /proc/vmstat. */ 169 @Nullable readVmStat()170 public static VmStat readVmStat() { 171 long[] vmstat = new long[VMSTAT_KEYS.length]; 172 vmstat[0] = -1; 173 Process.readProcLines("/proc/vmstat", VMSTAT_KEYS, vmstat); 174 if (vmstat[0] == -1) { 175 return null; 176 } 177 VmStat result = new VmStat(); 178 result.oomKillCount = (int) vmstat[0]; 179 return result; 180 } 181 182 public static final class VmStat { 183 public int oomKillCount; 184 } 185 } 186