1 /**
2  * Copyright (c) 2020, 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 
17 #ifndef WATCHDOG_SERVER_SRC_PROCPIDSTAT_H_
18 #define WATCHDOG_SERVER_SRC_PROCPIDSTAT_H_
19 
20 #include <android-base/result.h>
21 #include <android-base/stringprintf.h>
22 #include <gtest/gtest_prod.h>
23 #include <inttypes.h>
24 #include <stdint.h>
25 #include <utils/Mutex.h>
26 #include <utils/RefBase.h>
27 
28 #include <string>
29 #include <unordered_map>
30 #include <vector>
31 
32 namespace android {
33 namespace automotive {
34 namespace watchdog {
35 
36 using android::base::StringPrintf;
37 
38 #define PID_FOR_INIT 1
39 
40 constexpr const char* kProcDirPath = "/proc";
41 constexpr const char* kStatFileFormat = "/%" PRIu32 "/stat";
42 constexpr const char* kTaskDirFormat = "/%" PRIu32 "/task";
43 constexpr const char* kStatusFileFormat = "/%" PRIu32 "/status";
44 
45 struct PidStat {
46     uint32_t pid = 0;
47     std::string comm = "";
48     std::string state = "";
49     uint32_t ppid = 0;
50     uint64_t majorFaults = 0;
51     uint32_t numThreads = 0;
52     uint64_t startTime = 0;  // Useful when identifying PID/TID reuse
53 };
54 
55 struct ProcessStats {
56     int64_t tgid = -1;                              // -1 indicates a failure to read this value
57     int64_t uid = -1;                               // -1 indicates a failure to read this value
58     PidStat process = {};                           // Aggregated stats across all the threads
59     std::unordered_map<uint32_t, PidStat> threads;  // Per-thread stat including the main thread
60 };
61 
62 // Collector/parser for `/proc/[pid]/stat`, `/proc/[pid]/task/[tid]/stat` and /proc/[pid]/status`
63 // files.
64 class ProcPidStat : public RefBase {
65 public:
66     explicit ProcPidStat(const std::string& path = kProcDirPath) :
67           mLastProcessStats({}), mPath(path) {
68         std::string pidStatPath = StringPrintf((mPath + kStatFileFormat).c_str(), PID_FOR_INIT);
69         std::string tidStatPath = StringPrintf((mPath + kTaskDirFormat + kStatFileFormat).c_str(),
70                                                PID_FOR_INIT, PID_FOR_INIT);
71         std::string pidStatusPath = StringPrintf((mPath + kStatusFileFormat).c_str(), PID_FOR_INIT);
72 
73         mEnabled = !access(pidStatPath.c_str(), R_OK) && !access(tidStatPath.c_str(), R_OK) &&
74                 !access(pidStatusPath.c_str(), R_OK);
75     }
76 
~ProcPidStat()77     virtual ~ProcPidStat() {}
78 
79     // Collects pid info delta since the last collection.
80     virtual android::base::Result<std::vector<ProcessStats>> collect();
81 
82     // Called by IoPerfCollection and tests.
enabled()83     virtual bool enabled() { return mEnabled; }
84 
dirPath()85     virtual std::string dirPath() { return mPath; }
86 
87 private:
88     // Reads the contents of the below files:
89     // 1. Pid stat file at |mPath| + |kStatFileFormat|
90     // 2. Tid stat file at |mPath| + |kTaskDirFormat| + |kStatFileFormat|
91     android::base::Result<std::unordered_map<uint32_t, ProcessStats>> getProcessStatsLocked() const;
92 
93     // Reads the tgid and real UID for the given PID from |mPath| + |kStatusFileFormat|.
94     android::base::Result<void> getPidStatusLocked(ProcessStats* processStats) const;
95 
96     // Makes sure only one collection is running at any given time.
97     Mutex mMutex;
98 
99     // Last dump of per-process stats. Useful for calculating the delta and identifying PID/TID
100     // reuse.
101     std::unordered_map<uint32_t, ProcessStats> mLastProcessStats GUARDED_BY(mMutex);
102 
103     // True if the below files are accessible:
104     // 1. Pid stat file at |mPath| + |kTaskStatFileFormat|
105     // 2. Tid stat file at |mPath| + |kTaskDirFormat| + |kStatFileFormat|
106     // 3. Pid status file at |mPath| + |kStatusFileFormat|
107     // Otherwise, set to false.
108     bool mEnabled;
109 
110     // Proc directory path. Default value is |kProcDirPath|.
111     // Updated by tests to point to a different location when needed.
112     std::string mPath;
113 
114     FRIEND_TEST(IoPerfCollectionTest, TestValidProcPidContents);
115     FRIEND_TEST(ProcPidStatTest, TestValidStatFiles);
116     FRIEND_TEST(ProcPidStatTest, TestHandlesProcessTerminationBetweenScanningAndParsing);
117     FRIEND_TEST(ProcPidStatTest, TestHandlesPidTidReuse);
118 };
119 
120 }  // namespace watchdog
121 }  // namespace automotive
122 }  // namespace android
123 
124 #endif  //  WATCHDOG_SERVER_SRC_PROCPIDSTAT_H_
125