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