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