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 {
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     // Collects the per-UID I/O stats.
89     virtual android::base::Result<void> collect() = 0;
90     // Returns the latest per-uid I/O stats.
91     virtual const std::unordered_map<uid_t, UidIoStats> latestStats() const = 0;
92     // Returns the delta of per-uid I/O stats since the last before collection.
93     virtual const std::unordered_map<uid_t, UidIoStats> deltaStats() const = 0;
94     // Returns true only when the per-UID I/O stats file is accessible.
95     virtual bool enabled() const = 0;
96     // Returns the path for the per-UID I/O stats file.
97     virtual const std::string filePath() const = 0;
98 };
99 
100 class UidIoStatsCollector final : public UidIoStatsCollectorInterface {
101 public:
102     explicit UidIoStatsCollector(const std::string& path = kUidIoStatsPath) :
103           kEnabled(!access(path.c_str(), R_OK)), kPath(path) {}
104 
~UidIoStatsCollector()105     ~UidIoStatsCollector() {}
106 
107     android::base::Result<void> collect() override;
108 
latestStats()109     const std::unordered_map<uid_t, UidIoStats> latestStats() const override {
110         Mutex::Autolock lock(mMutex);
111         return mLatestStats;
112     }
113 
deltaStats()114     const std::unordered_map<uid_t, UidIoStats> deltaStats() const override {
115         Mutex::Autolock lock(mMutex);
116         return mDeltaStats;
117     }
118 
enabled()119     bool enabled() const override { return kEnabled; }
120 
filePath()121     const std::string filePath() const override { return kPath; }
122 
123 private:
124     // Reads the contents of |kPath|.
125     android::base::Result<std::unordered_map<uid_t, UidIoStats>> readUidIoStatsLocked() const;
126 
127     // Makes sure only one collection is running at any given time.
128     mutable Mutex mMutex;
129 
130     // Latest dump from the file at |kPath|.
131     std::unordered_map<uid_t, UidIoStats> mLatestStats GUARDED_BY(mMutex);
132 
133     // Delta of per-UID I/O stats since last before collection.
134     std::unordered_map<uid_t, UidIoStats> mDeltaStats GUARDED_BY(mMutex);
135 
136     // True if kPath is accessible.
137     const bool kEnabled;
138 
139     // Path to uid_io stats file. Default path is |kUidIoStatsPath|.
140     const std::string kPath;
141 };
142 
143 }  // namespace watchdog
144 }  // namespace automotive
145 }  // namespace android
146 
147 #endif  //  CPP_WATCHDOG_SERVER_SRC_UIDIOSTATSCOLLECTOR_H_
148