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