diff options
author | Jin Qian <jinqian@google.com> | 2017-08-14 16:41:24 -0700 |
---|---|---|
committer | Jin Qian <jinqian@google.com> | 2017-08-15 17:00:19 -0700 |
commit | ebf031be986369ef4eb035eed32dbc3e85e76988 (patch) | |
tree | 70e9345082b40ffd9c77a2dd42c738e5d613bd2c /storaged | |
parent | e4f1ec315d7fb8835c3d29ebda283dd840ae1a1f (diff) | |
download | core-ebf031be986369ef4eb035eed32dbc3e85e76988.tar.gz core-ebf031be986369ef4eb035eed32dbc3e85e76988.tar.bz2 core-ebf031be986369ef4eb035eed32dbc3e85e76988.zip |
storaged: store io_history as protobuf file on userdata
Convert storaged internal io_history to protobuf format and serialize
it to userdata partition. Also load this file during storaged startup
to reconstruct io history.
Bug: 63740245
Change-Id: I0697525df1c31fdec20f5ed4e3e9363e2dde244f
Diffstat (limited to 'storaged')
-rw-r--r-- | storaged/Android.bp | 8 | ||||
-rw-r--r-- | storaged/include/storaged_uid_monitor.h | 8 | ||||
-rw-r--r-- | storaged/storaged.cpp | 2 | ||||
-rw-r--r-- | storaged/storaged.proto | 42 | ||||
-rw-r--r-- | storaged/storaged.rc | 6 | ||||
-rw-r--r-- | storaged/storaged_uid_monitor.cpp | 159 |
6 files changed, 210 insertions, 15 deletions
diff --git a/storaged/Android.bp b/storaged/Android.bp index f8b0333da..25b433c7e 100644 --- a/storaged/Android.bp +++ b/storaged/Android.bp @@ -23,8 +23,10 @@ cc_defaults { "libbinder", "libcutils", "liblog", + "libprotobuf-cpp-lite", "libsysutils", "libutils", + "libz", ], cflags: [ @@ -46,10 +48,16 @@ cc_library_static { "storaged_service.cpp", "storaged_utils.cpp", "storaged_uid_monitor.cpp", + "storaged.proto", ], logtags: ["EventLogTags.logtags"], + proto: { + type: "lite", + export_proto_headers: true, + }, + export_include_dirs: ["include"], } diff --git a/storaged/include/storaged_uid_monitor.h b/storaged/include/storaged_uid_monitor.h index 9bb428e9d..86d3c2875 100644 --- a/storaged/include/storaged_uid_monitor.h +++ b/storaged/include/storaged_uid_monitor.h @@ -92,13 +92,15 @@ private: // current io usage for next report, app name -> uid_io_usage std::unordered_map<std::string, struct uid_io_usage> curr_io_stats; // io usage records, end timestamp -> {start timestamp, vector of records} - std::map<uint64_t, struct uid_records> records; + std::map<uint64_t, struct uid_records> io_history; // charger ON/OFF charger_stat_t charger_stat; // protects curr_io_stats, last_uid_io_stats, records and charger_stat sem_t um_lock; // start time for IO records uint64_t start_ts; + // protobuf file for io_history + static const std::string io_history_proto_file; // reads from /proc/uid_io/stats std::unordered_map<uint32_t, struct uid_info> get_uid_io_stats_locked(); @@ -106,6 +108,10 @@ private: void add_records_locked(uint64_t curr_ts); // updates curr_io_stats and set last_uid_io_stats void update_curr_io_stats_locked(); + // restores io_history from protobuf file + void load_io_history_from_proto(); + // converts io_history to protobuf and writes to a file + void flush_io_history_to_proto(); public: uid_monitor(); diff --git a/storaged/storaged.cpp b/storaged/storaged.cpp index 06afea693..49592ebe2 100644 --- a/storaged/storaged.cpp +++ b/storaged/storaged.cpp @@ -243,7 +243,7 @@ void storaged_t::event(void) { if (mConfig.proc_uid_io_available && mTimer && (mTimer % mConfig.periodic_chores_interval_uid_io) == 0) { - mUidm.report(); + mUidm.report(); } mTimer += mConfig.periodic_chores_interval_unit; diff --git a/storaged/storaged.proto b/storaged/storaged.proto new file mode 100644 index 000000000..52228468f --- /dev/null +++ b/storaged/storaged.proto @@ -0,0 +1,42 @@ +syntax = "proto2"; +option optimize_for = LITE_RUNTIME; +package storaged_proto; +option java_package = "com.android.storaged.proto"; +option java_outer_classname = "Storaged"; + +message IOUsage { + optional uint64 rd_fg_chg_on = 1; + optional uint64 rd_fg_chg_off = 2; + optional uint64 rd_bg_chg_on = 3; + optional uint64 rd_bg_chg_off = 4; + optional uint64 wr_fg_chg_on = 5; + optional uint64 wr_fg_chg_off = 6; + optional uint64 wr_bg_chg_on = 7; + optional uint64 wr_bg_chg_off = 8; +} + +message TaskIOUsage { + optional string task_name = 1; + optional IOUsage ios = 2; +} + +message UidRecord { + optional string uid_name = 1; + optional IOUsage uid_io = 2; + repeated TaskIOUsage task_io = 3; +} + +message UidIORecords { + optional uint64 start_ts = 1; + repeated UidRecord entries = 2; +} + +message UidIOItem { + optional uint64 end_ts = 1; + optional UidIORecords records = 2; +} + +message UidIOHistoryProto { + optional uint32 crc = 1; + repeated UidIOItem items = 2; +} diff --git a/storaged/storaged.rc b/storaged/storaged.rc index a24c7fba8..bd4022b48 100644 --- a/storaged/storaged.rc +++ b/storaged/storaged.rc @@ -1,7 +1,11 @@ +on post-fs-data + mkdir /data/misc/storaged 0700 root root + restorecon /data/misc/storaged + service storaged /system/bin/storaged class main priority 10 file /d/mmc0/mmc0:0001/ext_csd r writepid /dev/cpuset/system-background/tasks user root - group package_info
\ No newline at end of file + group package_info diff --git a/storaged/storaged_uid_monitor.cpp b/storaged/storaged_uid_monitor.cpp index 2bbbfe0c9..1c98477d5 100644 --- a/storaged/storaged_uid_monitor.cpp +++ b/storaged/storaged_uid_monitor.cpp @@ -17,8 +17,11 @@ #define LOG_TAG "storaged" #include <stdint.h> +#include <stdio.h> #include <time.h> +#include <zlib.h> +#include <fstream> #include <string> #include <unordered_map> @@ -34,12 +37,19 @@ #include "storaged.h" #include "storaged_uid_monitor.h" +#include "system/core/storaged/storaged.pb.h" using namespace android; using namespace android::base; using namespace android::content::pm; +using namespace google::protobuf::io; +using namespace storaged_proto; static bool refresh_uid_names; +static const uint32_t crc_init = 0x5108A4ED; /* STORAGED */ + +const std::string uid_monitor::io_history_proto_file = + "/data/misc/storaged/io_history.proto"; std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats() { @@ -187,11 +197,11 @@ std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats_lock static const int MAX_UID_RECORDS_SIZE = 1000 * 48; // 1000 uids in 48 hours -static inline int records_size( - const std::map<uint64_t, struct uid_records>& curr_records) +static inline size_t history_size( + const std::map<uint64_t, struct uid_records>& history) { - int count = 0; - for (auto const& it : curr_records) { + size_t count = 0; + for (auto const& it : history) { count += it.second.entries.size(); } return count; @@ -201,8 +211,8 @@ void uid_monitor::add_records_locked(uint64_t curr_ts) { // remove records more than 5 days old if (curr_ts > 5 * DAY_TO_SEC) { - auto it = records.lower_bound(curr_ts - 5 * DAY_TO_SEC); - records.erase(records.begin(), it); + auto it = io_history.lower_bound(curr_ts - 5 * DAY_TO_SEC); + io_history.erase(io_history.begin(), it); } struct uid_records new_records; @@ -227,15 +237,15 @@ void uid_monitor::add_records_locked(uint64_t curr_ts) return; // make some room for new records - int overflow = records_size(records) + + ssize_t overflow = history_size(io_history) + new_records.entries.size() - MAX_UID_RECORDS_SIZE; - while (overflow > 0 && records.size() > 0) { - auto del_it = records.begin(); + while (overflow > 0 && io_history.size() > 0) { + auto del_it = io_history.begin(); overflow -= del_it->second.entries.size(); - records.erase(records.begin()); + io_history.erase(io_history.begin()); } - records[curr_ts] = new_records; + io_history[curr_ts] = new_records; } std::map<uint64_t, struct uid_records> uid_monitor::dump( @@ -254,7 +264,7 @@ std::map<uint64_t, struct uid_records> uid_monitor::dump( first_ts = time(NULL) - hours * HOUR_TO_SEC; } - for (auto it = records.lower_bound(first_ts); it != records.end(); ++it) { + for (auto it = io_history.lower_bound(first_ts); it != io_history.end(); ++it) { const std::vector<struct uid_record>& recs = it->second.entries; struct uid_records filtered; @@ -351,6 +361,128 @@ void uid_monitor::report() update_curr_io_stats_locked(); add_records_locked(time(NULL)); + + flush_io_history_to_proto(); +} + +static void set_io_usage_proto(IOUsage* usage_proto, const struct io_usage& usage) +{ + usage_proto->set_rd_fg_chg_on(usage.bytes[READ][FOREGROUND][CHARGER_ON]); + usage_proto->set_rd_fg_chg_off(usage.bytes[READ][FOREGROUND][CHARGER_OFF]); + usage_proto->set_rd_bg_chg_on(usage.bytes[READ][BACKGROUND][CHARGER_ON]); + usage_proto->set_rd_bg_chg_off(usage.bytes[READ][BACKGROUND][CHARGER_OFF]); + usage_proto->set_wr_fg_chg_on(usage.bytes[WRITE][FOREGROUND][CHARGER_ON]); + usage_proto->set_wr_fg_chg_off(usage.bytes[WRITE][FOREGROUND][CHARGER_OFF]); + usage_proto->set_wr_bg_chg_on(usage.bytes[WRITE][BACKGROUND][CHARGER_ON]); + usage_proto->set_wr_bg_chg_off(usage.bytes[WRITE][BACKGROUND][CHARGER_OFF]); +} + +static void get_io_usage_proto(struct io_usage* usage, const IOUsage& io_proto) +{ + usage->bytes[READ][FOREGROUND][CHARGER_ON] = io_proto.rd_fg_chg_on(); + usage->bytes[READ][FOREGROUND][CHARGER_OFF] = io_proto.rd_fg_chg_off(); + usage->bytes[READ][BACKGROUND][CHARGER_ON] = io_proto.rd_bg_chg_on(); + usage->bytes[READ][BACKGROUND][CHARGER_OFF] = io_proto.rd_bg_chg_off(); + usage->bytes[WRITE][FOREGROUND][CHARGER_ON] = io_proto.wr_fg_chg_on(); + usage->bytes[WRITE][FOREGROUND][CHARGER_OFF] = io_proto.wr_fg_chg_off(); + usage->bytes[WRITE][BACKGROUND][CHARGER_ON] = io_proto.wr_bg_chg_on(); + usage->bytes[WRITE][BACKGROUND][CHARGER_OFF] = io_proto.wr_bg_chg_off(); +} + +void uid_monitor::flush_io_history_to_proto() +{ + UidIOHistoryProto out_proto; + + for (const auto& item : io_history) { + const uint64_t& end_ts = item.first; + const struct uid_records& recs = item.second; + + UidIOItem* item_proto = out_proto.add_items(); + item_proto->set_end_ts(end_ts); + + UidIORecords* recs_proto = item_proto->mutable_records(); + recs_proto->set_start_ts(recs.start_ts); + + for (const auto& entry : recs.entries) { + UidRecord* rec_proto = recs_proto->add_entries(); + rec_proto->set_uid_name(entry.name); + + IOUsage* uid_io_proto = rec_proto->mutable_uid_io(); + const struct io_usage& uio_ios = entry.ios.uid_ios; + set_io_usage_proto(uid_io_proto, uio_ios); + + for (const auto& task_io : entry.ios.task_ios) { + const std::string& task_name = task_io.first; + const struct io_usage& task_ios = task_io.second; + + TaskIOUsage* task_io_proto = rec_proto->add_task_io(); + task_io_proto->set_task_name(task_name); + set_io_usage_proto(task_io_proto->mutable_ios(), task_ios); + } + } + } + + out_proto.set_crc(crc_init); + std::string out_proto_str = out_proto.SerializeAsString(); + out_proto.set_crc(crc32(crc_init, + reinterpret_cast<const Bytef*>(out_proto_str.c_str()), + out_proto_str.size())); + + std::string tmp_file = io_history_proto_file + "_tmp"; + std::ofstream out(tmp_file, + std::ofstream::out | std::ofstream::binary | std::ofstream::trunc); + out << out_proto.SerializeAsString(); + out.close(); + + /* Atomically replace existing proto file to reduce chance of data loss. */ + rename(tmp_file.c_str(), io_history_proto_file.c_str()); +} + +void uid_monitor::load_io_history_from_proto() +{ + std::ifstream in(io_history_proto_file, + std::ofstream::in | std::ofstream::binary); + + if (!in.good()) { + PLOG_TO(SYSTEM, INFO) << "Open " << io_history_proto_file << " failed"; + return; + } + + stringstream ss; + ss << in.rdbuf(); + UidIOHistoryProto in_proto; + in_proto.ParseFromString(ss.str()); + + uint32_t crc = in_proto.crc(); + in_proto.set_crc(crc_init); + std::string io_proto_str = in_proto.SerializeAsString(); + uint32_t computed_crc = crc32(crc_init, + reinterpret_cast<const Bytef*>(io_proto_str.c_str()), + io_proto_str.size()); + + if (crc != computed_crc) { + LOG_TO(SYSTEM, WARNING) << "CRC mismatch in " << io_history_proto_file; + return; + } + + for (const auto& item_proto : in_proto.items()) { + const UidIORecords& records_proto = item_proto.records(); + struct uid_records* recs = &io_history[item_proto.end_ts()]; + + recs->start_ts = records_proto.start_ts(); + for (const auto& rec_proto : records_proto.entries()) { + struct uid_record record; + record.name = rec_proto.uid_name(); + get_io_usage_proto(&record.ios.uid_ios, rec_proto.uid_io()); + + for (const auto& task_io_proto : rec_proto.task_io()) { + get_io_usage_proto( + &record.ios.task_ios[task_io_proto.task_name()], + task_io_proto.ios()); + } + recs->entries.push_back(record); + } + } } void uid_monitor::set_charger_state(charger_stat_t stat) @@ -368,6 +500,9 @@ void uid_monitor::set_charger_state(charger_stat_t stat) void uid_monitor::init(charger_stat_t stat) { charger_stat = stat; + + load_io_history_from_proto(); + start_ts = time(NULL); last_uid_io_stats = get_uid_io_stats(); } |