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 CPP_WATCHDOG_SERVER_SRC_UIDIOSTATSCOLLECTOR_H_
18 #define CPP_WATCHDOG_SERVER_SRC_UIDIOSTATSCOLLECTOR_H_
19 
20 #include <android-base/result.h>
21 #include <android-base/stringprintf.h>
22 #include <utils/Mutex.h>
23 #include <utils/RefBase.h>
24 
25 #include <stdint.h>
26 
27 #include <string>
28 #include <unordered_map>
29 
30 namespace android {
31 namespace automotive {
32 namespace watchdog {
33 
34 constexpr const char* kUidIoStatsPath = "/proc/uid_io/stats";
35 
36 enum UidState {
37     FOREGROUND = 0,
38     BACKGROUND,
39     UID_STATES,
40 };
41 
42 enum MetricType {
43     READ_BYTES = 0,  // bytes read (from storage layer)
44     WRITE_BYTES,     // bytes written (to storage layer)
45     FSYNC_COUNT,     // number of fsync syscalls
46     METRIC_TYPES,
47 };
48 
49 // Defines the per-UID I/O stats.
50 class UidIoStats final {
51 public:
UidIoStats()52     UidIoStats() : metrics{{0}} {};
UidIoStats(int64_t fgRdBytes,int64_t bgRdBytes,int64_t fgWrBytes,int64_t bgWrBytes,int64_t fgFsync,int64_t bgFsync)53     UidIoStats(int64_t fgRdBytes, int64_t bgRdBytes, int64_t fgWrBytes, int64_t bgWrBytes,
54                int64_t fgFsync, int64_t bgFsync) {
55         metrics[READ_BYTES][FOREGROUND] = fgRdBytes;
56         metrics[READ_BYTES][BACKGROUND] = bgRdBytes;
57         metrics[WRITE_BYTES][FOREGROUND] = fgWrBytes;
58         metrics[WRITE_BYTES][BACKGROUND] = bgWrBytes;
59         metrics[FSYNC_COUNT][FOREGROUND] = fgFsync;
60         metrics[FSYNC_COUNT][BACKGROUND] = bgFsync;
61     }
62     UidIoStats& operator-=(const UidIoStats& rhs);
63     bool operator==(const UidIoStats& stats) const {
64         return memcmp(&metrics, &stats.metrics, sizeof(metrics)) == 0;
65     }
sumReadBytes()66     int64_t sumReadBytes() const {
67         const auto& [fgBytes, bgBytes] =
68                 std::tuple(metrics[READ_BYTES][FOREGROUND], metrics[READ_BYTES][BACKGROUND]);
69         return (std::numeric_limits<int64_t>::max() - fgBytes) > bgBytes
70                 ? (fgBytes + bgBytes)
71                 : std::numeric_limits<int64_t>::max();
72     }
sumWriteBytes()73     int64_t sumWriteBytes() const {
74         const auto& [fgBytes, bgBytes] =
75                 std::tuple(metrics[WRITE_BYTES][FOREGROUND], metrics[WRITE_BYTES][BACKGROUND]);
76         return (std::numeric_limits<int64_t>::max() - fgBytes) > bgBytes
77                 ? (fgBytes + bgBytes)
78                 : std::numeric_limits<int64_t>::max();
79     }
80     bool isZero() const;
81     std::string toString() const;
82     int64_t metrics[METRIC_TYPES][UID_STATES];
83 };
84 
85 // Collector/Parser for `/proc/uid_io/stats`.
86 class UidIoStatsCollectorInterface : public RefBase {
87 public:
88     // Initializes the collector.
89     virtual void init() = 0;
90     // Collects the per-UID I/O stats.
91     virtual android::base::Result<void> collect() = 0;
92     // Returns the latest per-uid I/O stats.
93     virtual const std::unordered_map<uid_t, UidIoStats> latestStats() const = 0;
94     // Returns the delta of per-uid I/O stats since the last before collection.
95     virtual const std::unordered_map<uid_t, UidIoStats> deltaStats() const = 0;
96     // Returns true only when the per-UID I/O stats file is accessible.
97     virtual bool enabled() const = 0;
98     // Returns the path for the per-UID I/O stats file.
99     virtual const std::string filePath() const = 0;
100 };
101 
102 class UidIoStatsCollector final : public UidIoStatsCollectorInterface {
103 public:
kPath(path)104     explicit UidIoStatsCollector(const std::string& path = kUidIoStatsPath) : kPath(path) {}
105 
~UidIoStatsCollector()106     ~UidIoStatsCollector() {}
107 
init()108     void init() override {
109         Mutex::Autolock lock(mMutex);
110         // Note: Verify proc file access outside the constructor. Otherwise, the unittests of
111         // dependent classes would call the constructor before mocking and get killed due to
112         // sepolicy violation.
113         mEnabled = access(kPath.c_str(), R_OK) == 0;
114     }
115 
116     android::base::Result<void> collect() override;
117 
latestStats()118     const std::unordered_map<uid_t, UidIoStats> latestStats() const override {
119         Mutex::Autolock lock(mMutex);
120         return mLatestStats;
121     }
122 
deltaStats()123     const std::unordered_map<uid_t, UidIoStats> deltaStats() const override {
124         Mutex::Autolock lock(mMutex);
125         return mDeltaStats;
126     }
127 
enabled()128     bool enabled() const override {
129         Mutex::Autolock lock(mMutex);
130         return mEnabled;
131     }
132 
filePath()133     const std::string filePath() const override { return kPath; }
134 
135 private:
136     // Reads the contents of |kPath|.
137     android::base::Result<std::unordered_map<uid_t, UidIoStats>> readUidIoStatsLocked() const;
138 
139     // Path to uid_io stats file. Default path is |kUidIoStatsPath|.
140     const std::string kPath;
141 
142     // Makes sure only one collection is running at any given time.
143     mutable Mutex mMutex;
144 
145     // True if |kPath| is accessible.
146     bool mEnabled GUARDED_BY(mMutex);
147 
148     // Latest dump from the file at |kPath|.
149     std::unordered_map<uid_t, UidIoStats> mLatestStats GUARDED_BY(mMutex);
150 
151     // Delta of per-UID I/O stats since last before collection.
152     std::unordered_map<uid_t, UidIoStats> mDeltaStats GUARDED_BY(mMutex);
153 };
154 
155 }  // namespace watchdog
156 }  // namespace automotive
157 }  // namespace android
158 
159 #endif  //  CPP_WATCHDOG_SERVER_SRC_UIDIOSTATSCOLLECTOR_H_
160