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.server.stats.pull; 17 18 import static android.os.Process.PROC_OUT_STRING; 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 String[] STATUS_KEYS = new String[] { 27 "Uid:", 28 "VmHWM:", 29 "VmRSS:", 30 "RssAnon:", 31 "VmSwap:" 32 }; 33 private static final String[] VMSTAT_KEYS = new String[] { 34 "oom_kill" 35 }; 36 ProcfsMemoryUtil()37 private ProcfsMemoryUtil() {} 38 39 /** 40 * Reads memory stats of a process from procfs. Returns values of the VmHWM, VmRss, AnonRSS, 41 * VmSwap fields in /proc/pid/status in kilobytes or null if not available. 42 */ 43 @Nullable readMemorySnapshotFromProcfs(int pid)44 public static MemorySnapshot readMemorySnapshotFromProcfs(int pid) { 45 long[] output = new long[STATUS_KEYS.length]; 46 output[0] = -1; 47 output[3] = -1; 48 output[4] = -1; 49 Process.readProcLines("/proc/" + pid + "/status", STATUS_KEYS, output); 50 if (output[0] == -1 || output[3] == -1 || output[4] == -1) { 51 // Could not open or parse file. 52 return null; 53 } 54 final MemorySnapshot snapshot = new MemorySnapshot(); 55 snapshot.uid = (int) output[0]; 56 snapshot.rssHighWaterMarkInKilobytes = (int) output[1]; 57 snapshot.rssInKilobytes = (int) output[2]; 58 snapshot.anonRssInKilobytes = (int) output[3]; 59 snapshot.swapInKilobytes = (int) output[4]; 60 return snapshot; 61 } 62 63 /** 64 * Reads cmdline of a process from procfs. 65 * 66 * Returns content of /proc/pid/cmdline (e.g. /system/bin/statsd) or an empty string 67 * if the file is not available. 68 */ readCmdlineFromProcfs(int pid)69 public static String readCmdlineFromProcfs(int pid) { 70 String[] cmdline = new String[1]; 71 if (!Process.readProcFile("/proc/" + pid + "/cmdline", CMDLINE_OUT, cmdline, null, null)) { 72 return ""; 73 } 74 return cmdline[0]; 75 } 76 77 /** 78 * Scans all /proc/pid/cmdline entries and returns a mapping between pid and cmdline. 79 */ getProcessCmdlines()80 public static SparseArray<String> getProcessCmdlines() { 81 int[] pids = new int[1024]; 82 pids = Process.getPids("/proc", pids); 83 84 SparseArray<String> cmdlines = new SparseArray<>(pids.length); 85 for (int pid : pids) { 86 if (pid < 0) { 87 break; 88 } 89 String cmdline = readCmdlineFromProcfs(pid); 90 if (cmdline.isEmpty()) { 91 continue; 92 } 93 cmdlines.append(pid, cmdline); 94 } 95 return cmdlines; 96 } 97 98 public static final class MemorySnapshot { 99 public int uid; 100 public int rssHighWaterMarkInKilobytes; 101 public int rssInKilobytes; 102 public int anonRssInKilobytes; 103 public int swapInKilobytes; 104 } 105 106 /** Reads and parses selected entries of /proc/vmstat. */ 107 @Nullable readVmStat()108 static VmStat readVmStat() { 109 long[] vmstat = new long[VMSTAT_KEYS.length]; 110 vmstat[0] = -1; 111 Process.readProcLines("/proc/vmstat", VMSTAT_KEYS, vmstat); 112 if (vmstat[0] == -1) { 113 return null; 114 } 115 VmStat result = new VmStat(); 116 result.oomKillCount = (int) vmstat[0]; 117 return result; 118 } 119 120 static final class VmStat { 121 public int oomKillCount; 122 } 123 } 124