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