blob: fffb3d2c8191325264bd0a18cfb09fc4f632ca07 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _STORAGED_UID_MONITOR_H_
#define _STORAGED_UID_MONITOR_H_
#include <stdint.h>
#include <string>
#include <unordered_map>
#include <vector>
#include <cutils/multiuser.h>
#include <utils/Mutex.h>
#include "storaged.pb.h"
#include "uid_info.h"
#define FRIEND_TEST(test_case_name, test_name) \
friend class test_case_name##_##test_name##_Test
using namespace std;
using namespace storaged_proto;
using namespace android;
using namespace android::os::storaged;
class uid_info : public UidInfo {
public:
bool parse_uid_io_stats(string&& s);
};
class io_usage {
public:
io_usage() : bytes{{{0}}} {};
uint64_t bytes[IO_TYPES][UID_STATS][CHARGER_STATS];
bool is_zero() const;
io_usage& operator+= (const io_usage& stats) {
for (int i = 0; i < IO_TYPES; i++) {
for (int j = 0; j < UID_STATS; j++) {
for (int k = 0; k < CHARGER_STATS; k++) {
bytes[i][j][k] += stats.bytes[i][j][k];
}
}
}
return *this;
}
};
struct uid_io_usage {
userid_t user_id;
io_usage uid_ios;
// mapped from task comm to task io usage
map<string, io_usage> task_ios;
};
struct uid_record {
string name;
uid_io_usage ios;
};
struct uid_records {
uint64_t start_ts;
vector<uid_record> entries;
};
class uid_monitor {
private:
FRIEND_TEST(storaged_test, uid_monitor);
FRIEND_TEST(storaged_test, load_uid_io_proto);
// last dump from /proc/uid_io/stats, uid -> uid_info
unordered_map<uint32_t, uid_info> last_uid_io_stats_;
// current io usage for next report, app name -> uid_io_usage
unordered_map<string, uid_io_usage> curr_io_stats_;
// io usage records, end timestamp -> {start timestamp, vector of records}
map<uint64_t, uid_records> io_history_;
// charger ON/OFF
charger_stat_t charger_stat_;
// protects curr_io_stats, last_uid_io_stats, records and charger_stat
Mutex uidm_mutex_;
// start time for IO records
uint64_t start_ts_;
// true if UID_IO_STATS_PATH is accessible
const bool enabled_;
// reads from /proc/uid_io/stats
unordered_map<uint32_t, uid_info> get_uid_io_stats_locked();
// flushes curr_io_stats to records
void add_records_locked(uint64_t curr_ts);
// updates curr_io_stats and set last_uid_io_stats
void update_curr_io_stats_locked();
// writes io_history to protobuf
void update_uid_io_proto(unordered_map<int, StoragedProto>* protos);
// Ensure that io_history_ can append |n| items without exceeding
// MAX_UID_RECORDS_SIZE in size.
void maybe_shrink_history_for_items(size_t nitems);
public:
uid_monitor();
// called by storaged main thread
void init(charger_stat_t stat);
// called by storaged -u
unordered_map<uint32_t, uid_info> get_uid_io_stats();
// called by dumpsys
map<uint64_t, uid_records> dump(
double hours, uint64_t threshold, bool force_report);
// called by battery properties listener
void set_charger_state(charger_stat_t stat);
// called by storaged periodic_chore or dump with force_report
bool enabled() { return enabled_; };
void report(unordered_map<int, StoragedProto>* protos);
// restores io_history from protobuf
void load_uid_io_proto(userid_t user_id, const UidIOUsage& proto);
void clear_user_history(userid_t user_id);
map<uint64_t, uid_records>& io_history() { return io_history_; }
static constexpr int MAX_UID_RECORDS_SIZE = 1000 * 48; // 1000 uids in 48 hours
};
#endif /* _STORAGED_UID_MONITOR_H_ */