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