From bcd6e3b9d92b2eea3b054372c9adf00a1e6235bc Mon Sep 17 00:00:00 2001 From: Jin Qian Date: Wed, 28 Dec 2016 15:43:51 -0800 Subject: [PATCH] storaged: monitor per-uid IO usage Add uid_monitor class to query /proc/uid_io/stats periodically. Add a log tag to record any UID that exceeds IO threshold. Test: adb shell storaged -u Bug: 34198239 Change-Id: I53568c30dbefe2f4bdb18054d3dedb30b4133d8b --- storaged/Android.mk | 4 +- storaged/EventLogTags.logtags | 2 + storaged/include/storaged.h | 20 +++- storaged/include/storaged_service.h | 4 + storaged/include/storaged_uid_monitor.h | 59 +++++++++ storaged/include/storaged_utils.h | 5 +- storaged/main.cpp | 43 ++++++- storaged/storaged.cpp | 8 ++ storaged/storaged_service.cpp | 42 ++++++- storaged/storaged_uid_monitor.cpp | 152 ++++++++++++++++++++++++ storaged/storaged_utils.cpp | 48 ++++++++ storaged/tests/Android.mk | 2 +- 12 files changed, 381 insertions(+), 8 deletions(-) create mode 100644 storaged/include/storaged_uid_monitor.h create mode 100644 storaged/storaged_uid_monitor.cpp diff --git a/storaged/Android.mk b/storaged/Android.mk index db97040dc..0e8b574e8 100644 --- a/storaged/Android.mk +++ b/storaged/Android.mk @@ -2,14 +2,16 @@ LOCAL_PATH := $(call my-dir) -LIBSTORAGED_SHARED_LIBRARIES := libbinder libbase libutils libcutils liblog libsysutils libcap +LIBSTORAGED_SHARED_LIBRARIES := libbinder libbase libutils libcutils liblog libsysutils libcap libpackagelistparser include $(CLEAR_VARS) LOCAL_SRC_FILES := storaged.cpp \ storaged_service.cpp \ storaged_utils.cpp \ + storaged_uid_monitor.cpp \ EventLogTags.logtags + LOCAL_MODULE := libstoraged LOCAL_CFLAGS := -Werror LOCAL_C_INCLUDES := $(LOCAL_PATH)/include external/googletest/googletest/include diff --git a/storaged/EventLogTags.logtags b/storaged/EventLogTags.logtags index ee92dd1b2..71fda25e5 100644 --- a/storaged/EventLogTags.logtags +++ b/storaged/EventLogTags.logtags @@ -37,3 +37,5 @@ 2732 storaged_disk_stats (type|3),(start_time|2|3),(end_time|2|3),(read_ios|2|1),(read_merges|2|1),(read_sectors|2|1),(read_ticks|2|3),(write_ios|2|1),(write_merges|2|1),(write_sectors|2|1),(write_ticks|2|3),(o_in_flight|2|1),(io_ticks|2|3),(io_in_queue|2|1) 2733 storaged_emmc_info (mmc_ver|3),(eol|1),(lifetime_a|1),(lifetime_b|1) + +2734 storaged_uid_io_alert (name|3),(read|2),(write|2),(interval|2) \ No newline at end of file diff --git a/storaged/include/storaged.h b/storaged/include/storaged.h index 521cc9e29..7fa9958bd 100644 --- a/storaged/include/storaged.h +++ b/storaged/include/storaged.h @@ -17,13 +17,17 @@ #ifndef _STORAGED_H_ #define _STORAGED_H_ -#include #include #include +#include + +#include #include #include #include +#include "storaged_uid_monitor.h" + #define FRIEND_TEST(test_case_name, test_name) \ friend class test_case_name##_##test_name##_Test @@ -165,6 +169,8 @@ public: #define MMC_DISK_STATS_PATH "/sys/block/mmcblk0/stat" #define SDA_DISK_STATS_PATH "/sys/block/sda/stat" #define EMMC_ECSD_PATH "/d/mmc0/mmc0:0001/ext_csd" +#define UID_IO_STATS_PATH "/proc/uid_io/stats" + class disk_stats_monitor { private: FRIEND_TEST(storaged_test, disk_stats_monitor); @@ -260,12 +266,15 @@ public: #define DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT ( 60 ) #define DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH ( 3600 ) #define DEFAULT_PERIODIC_CHORES_INTERVAL_EMMC_INFO_PUBLISH ( 86400 ) +#define DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO_ALERT ( 3600 ) struct storaged_config { int periodic_chores_interval_unit; int periodic_chores_interval_disk_stats_publish; int periodic_chores_interval_emmc_info_publish; + int periodic_chores_interval_uid_io; bool proc_taskio_readable; // are /proc/[pid]/{io, comm, cmdline, stat} all readable + bool proc_uid_io_available; // whether uid_io is accessible bool emmc_available; // whether eMMC est_csd file is readable bool diskstats_available; // whether diskstats is accessible }; @@ -278,6 +287,7 @@ private: disk_stats_monitor mDsm; emmc_info_t mEmmcInfo; tasks_t mTasks; + uid_monitor mUidm; time_t mStarttime; public: storaged_t(void); @@ -295,6 +305,9 @@ public: void set_emmc_interval(int emmc_info) { mConfig.periodic_chores_interval_emmc_info_publish = emmc_info; } + void set_uid_io_interval(int uid_io) { + mUidm.set_periodic_chores_interval(uid_io); + } std::vector get_tasks(void) { // There could be a race when get_tasks() and the main thread is updating at the same time // While update_running_tasks() is updating the critical sections at the end of the function @@ -312,11 +325,16 @@ public: time_t get_starttime(void) { return mStarttime; } + + std::unordered_map get_uids(void) { + return mUidm.get_uids(); + } }; // Eventlog tag // The content must match the definition in EventLogTags.logtags #define EVENTLOGTAG_DISKSTATS ( 2732 ) #define EVENTLOGTAG_EMMCINFO ( 2733 ) +#define EVENTLOGTAG_UID_IO_ALERT ( 2734 ) #endif /* _STORAGED_H_ */ diff --git a/storaged/include/storaged_service.h b/storaged/include/storaged_service.h index 64a9c81c5..220038c23 100644 --- a/storaged/include/storaged_service.h +++ b/storaged/include/storaged_service.h @@ -31,9 +31,11 @@ class IStoraged : public IInterface { public: enum { DUMPTASKS = IBinder::FIRST_CALL_TRANSACTION, + DUMPUIDS = IBinder::FIRST_CALL_TRANSACTION + 1, }; // Request the service to run the test function virtual std::vector dump_tasks(const char* option) = 0; + virtual std::vector dump_uids(const char* option) = 0; DECLARE_META_INTERFACE(Storaged); }; @@ -43,6 +45,7 @@ class BpStoraged : public BpInterface { public: BpStoraged(const sp& impl) : BpInterface(impl){}; virtual std::vector dump_tasks(const char* option); + virtual std::vector dump_uids(const char* option); }; // Server @@ -52,6 +55,7 @@ class BnStoraged : public BnInterface { class Storaged : public BnStoraged { virtual std::vector dump_tasks(const char* option); + virtual std::vector dump_uids(const char* option); }; sp get_storaged_service(); diff --git a/storaged/include/storaged_uid_monitor.h b/storaged/include/storaged_uid_monitor.h new file mode 100644 index 000000000..eceb7fd34 --- /dev/null +++ b/storaged/include/storaged_uid_monitor.h @@ -0,0 +1,59 @@ +/* + * 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 + +#include +#include + +enum { + UID_FOREGROUND = 0, + UID_BACKGROUND = 1, + UID_STATS_SIZE = 2 +}; + +struct uid_io_stats { + uint64_t rchar; // characters read + uint64_t wchar; // characters written + uint64_t read_bytes; // bytes read (from storage layer) + uint64_t write_bytes; // bytes written (to storage layer) +}; + +struct uid_info { + uint32_t uid; // user id + std::string name; // package name + struct uid_io_stats io[UID_STATS_SIZE]; // [0]:foreground [1]:background + +}; + +class uid_monitor { +private: + std::unordered_map last_uids; + void set_last_uids(std::unordered_map&& uids, uint64_t ts); + int interval; // monitor interval in seconds + uint64_t last_report_ts; // timestamp of last report in nsec +public: + uid_monitor(); + void set_periodic_chores_interval(int t) { interval = t; } + int get_periodic_chores_interval() { return interval; } + std::unordered_map get_uids(); + void report(); +}; + +#endif /* _STORAGED_UID_MONITOR_H_ */ diff --git a/storaged/include/storaged_utils.h b/storaged/include/storaged_utils.h index 83538c215..bb14708c5 100644 --- a/storaged/include/storaged_utils.h +++ b/storaged/include/storaged_utils.h @@ -34,12 +34,15 @@ bool parse_emmc_ecsd(int ext_csd_fd, struct emmc_info* info); // Task I/O bool parse_task_info(uint32_t pid, struct task_info* info); void sort_running_tasks_info(std::vector &tasks); +// UID I/O +void sort_running_uids_info(std::vector &uids); // Logging void log_console_running_tasks_info(std::vector tasks); +void log_console_running_uids_info(std::vector uids); void log_debug_disk_perf(struct disk_perf* perf, const char* type); void log_event_disk_stats(struct disk_stats* stats, const char* type); void log_event_emmc_info(struct emmc_info* info_); -#endif /* _STORAGED_UTILS_H_ */ \ No newline at end of file +#endif /* _STORAGED_UTILS_H_ */ diff --git a/storaged/main.cpp b/storaged/main.cpp index 0cb0f5f70..915157493 100644 --- a/storaged/main.cpp +++ b/storaged/main.cpp @@ -105,9 +105,11 @@ void* storaged_main(void* s) { static void help_message(void) { printf("usage: storaged [OPTION]\n"); printf(" -d --dump Dump task I/O usage to stdout\n"); + printf(" -u --uid Dump uid I/O usage to stdout\n"); printf(" -s --start Start storaged (default)\n"); printf(" --emmc=INTERVAL Set publish interval of emmc lifetime information (in days)\n"); printf(" --diskstats=INTERVAL Set publish interval of diskstats (in hours)\n"); + printf(" --uidio=INTERVAL Set publish interval of uid io (in hours)\n"); printf(" --unit=INTERVAL Set storaged's refresh interval (in seconds)\n"); fflush(stdout); } @@ -118,10 +120,12 @@ static void help_message(void) { int main(int argc, char** argv) { int flag_main_service = 0; int flag_dump_task = 0; + int flag_dump_uid = 0; int flag_config = 0; int unit_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT; int diskstats_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH; int emmc_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_EMMC_INFO_PUBLISH; + int uid_io_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO_ALERT; int fd_emmc = -1; int opt; @@ -131,12 +135,14 @@ int main(int argc, char** argv) { {"start", no_argument, 0, 's'}, {"kill", no_argument, 0, 'k'}, {"dump", no_argument, 0, 'd'}, + {"uid", no_argument, 0, 'u'}, {"help", no_argument, 0, 'h'}, {"unit", required_argument, 0, 0 }, {"diskstats", required_argument, 0, 0 }, - {"emmc", required_argument, 0, 0 } + {"emmc", required_argument, 0, 0 }, + {"uidio", required_argument, 0, 0 } }; - opt = getopt_long(argc, argv, ":skdh0", long_options, &opt_idx); + opt = getopt_long(argc, argv, ":skdhu0", long_options, &opt_idx); if (opt == -1) { break; } @@ -165,7 +171,15 @@ int main(int argc, char** argv) { } else if (strcmp(long_options[opt_idx].name, "emmc") == 0) { emmc_interval = atoi(optarg) * DAY_TO_SEC; - if (diskstats_interval == 0) { + if (emmc_interval == 0) { + fprintf(stderr, "Invalid argument. Option %s requires an integer argument greater than 0.\n", + long_options[opt_idx].name); + help_message(); + return -1; + } + } else if (strcmp(long_options[opt_idx].name, "uidio") == 0) { + uid_io_interval = atoi(optarg) * HOUR_TO_SEC; + if (uid_io_interval == 0) { fprintf(stderr, "Invalid argument. Option %s requires an integer argument greater than 0.\n", long_options[opt_idx].name); help_message(); @@ -187,6 +201,9 @@ int main(int argc, char** argv) { case 'd': flag_dump_task = 1; break; + case 'u': + flag_dump_uid = 1; + break; case 'h': help_message(); return 0; @@ -230,6 +247,7 @@ int main(int argc, char** argv) { storaged.set_unit_interval(unit_interval); storaged.set_diskstats_interval(diskstats_interval); storaged.set_emmc_interval(emmc_interval); + storaged.set_uid_io_interval(uid_io_interval); } // Start the main thread of storaged @@ -278,5 +296,24 @@ int main(int argc, char** argv) { return 0; } + if (flag_dump_uid) { + sp storaged_service = get_storaged_service(); + if (storaged_service == NULL) { + fprintf(stderr, "Cannot find storaged service.\nMaybe run storaged --start first?\n"); + return -1; + } + std::vector res = storaged_service->dump_uids(NULL); + + if (res.size() == 0) { + fprintf(stderr, "UID I/O is not readable in this version of kernel.\n"); + return 0; + } + + sort_running_uids_info(res); + log_console_running_uids_info(res); + + return 0; + } + return 0; } diff --git a/storaged/storaged.cpp b/storaged/storaged.cpp index e4d3e686e..0c53f4482 100644 --- a/storaged/storaged.cpp +++ b/storaged/storaged.cpp @@ -174,9 +174,12 @@ storaged_t::storaged_t(void) { } } + mConfig.proc_uid_io_available = (access(UID_IO_STATS_PATH, R_OK) == 0); + mConfig.periodic_chores_interval_unit = DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT; mConfig.periodic_chores_interval_disk_stats_publish = DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH; mConfig.periodic_chores_interval_emmc_info_publish = DEFAULT_PERIODIC_CHORES_INTERVAL_EMMC_INFO_PUBLISH; + mUidm.set_periodic_chores_interval(DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO_ALERT); mStarttime = time(NULL); } @@ -202,5 +205,10 @@ void storaged_t::event(void) { mEmmcInfo.publish(); } + if (mConfig.proc_uid_io_available && mTimer && + (mTimer % mUidm.get_periodic_chores_interval()) == 0) { + mUidm.report(); + } + mTimer += mConfig.periodic_chores_interval_unit; } diff --git a/storaged/storaged_service.cpp b/storaged/storaged_service.cpp index aa38ceb64..2a81aef65 100644 --- a/storaged/storaged_service.cpp +++ b/storaged/storaged_service.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include + #include #include @@ -41,6 +43,22 @@ std::vector BpStoraged::dump_tasks(const char* /*option*/) { return res; } +std::vector BpStoraged::dump_uids(const char* /*option*/) { + Parcel data, reply; + data.writeInterfaceToken(IStoraged::getInterfaceDescriptor()); + + remote()->transact(DUMPUIDS, data, &reply); + + uint32_t res_size = reply.readInt32(); + std::vector res(res_size); + for (auto&& uid : res) { + uid.uid = reply.readInt32(); + uid.name = reply.readCString(); + reply.read(&uid.io, sizeof(uid.io)); + } + return res; +} + IMPLEMENT_META_INTERFACE(Storaged, "Storaged"); status_t BnStoraged::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { @@ -57,14 +75,36 @@ status_t BnStoraged::onTransact(uint32_t code, const Parcel& data, Parcel* reply return NO_ERROR; } break; + case DUMPUIDS: { + std::vector res = dump_uids(NULL); + reply->writeInt32(res.size()); + for (auto uid : res) { + reply->writeInt32(uid.uid); + reply->writeCString(uid.name.c_str()); + reply->write(&uid.io, sizeof(uid.io)); + } + return NO_ERROR; + } + break; default: return BBinder::onTransact(code, data, reply, flags); } } + std::vector Storaged::dump_tasks(const char* /* option */) { return storaged.get_tasks(); } +std::vector Storaged::dump_uids(const char* /* option */) { + std::vector uids_v; + std::unordered_map uids_m = storaged.get_uids(); + + for (const auto& it : uids_m) { + uids_v.push_back(it.second); + } + return uids_v; +} + sp get_storaged_service() { sp sm = defaultServiceManager(); if (sm == NULL) return NULL; @@ -75,4 +115,4 @@ sp get_storaged_service() { sp storaged = interface_cast(binder); return storaged; -} \ No newline at end of file +} diff --git a/storaged/storaged_uid_monitor.cpp b/storaged/storaged_uid_monitor.cpp new file mode 100644 index 000000000..4105dae8f --- /dev/null +++ b/storaged/storaged_uid_monitor.cpp @@ -0,0 +1,152 @@ +/* + * 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. + */ + +#define LOG_TAG "storaged" + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "storaged.h" +#include "storaged_uid_monitor.h" + +static const uint64_t io_alert_threshold = 1024 * 1024 * 1024; // 1GB + +using namespace android; +using namespace android::base; + +static bool packagelist_parse_cb(pkg_info* info, void* userdata) +{ + std::unordered_map* uids = + reinterpret_cast*>(userdata); + + if (uids->find(info->uid) != uids->end()) { + (*uids)[info->uid].name = info->name; + } + + packagelist_free(info); + return true; +} + +void uid_monitor::set_last_uids(std::unordered_map&& uids, + uint64_t ts) +{ + last_uids = uids; + last_report_ts = ts; +} + +std::unordered_map uid_monitor::get_uids() +{ + std::unordered_map uids; + std::string buffer; + if (!android::base::ReadFileToString(UID_IO_STATS_PATH, &buffer)) { + PLOG_TO(SYSTEM, ERROR) << UID_IO_STATS_PATH << ": ReadFileToString failed"; + return uids; + } + + std::stringstream ss(buffer); + struct uid_info u; + bool refresh_uid = false; + + while (ss >> u.uid) { + ss >> u.io[UID_FOREGROUND].rchar >> u.io[UID_FOREGROUND].wchar + >> u.io[UID_FOREGROUND].read_bytes >> u.io[UID_FOREGROUND].write_bytes + >> u.io[UID_BACKGROUND].rchar >> u.io[UID_BACKGROUND].wchar + >> u.io[UID_BACKGROUND].read_bytes >> u.io[UID_BACKGROUND].write_bytes; + + if (!ss.good()) { + ss.clear(std::ios_base::badbit); + break; + } + + if (last_uids.find(u.uid) == last_uids.end()) { + refresh_uid = true; + u.name = std::to_string(u.uid); + } else { + u.name = last_uids[u.uid].name; + } + uids[u.uid] = u; + } + + if (!ss.eof() || ss.bad()) { + uids.clear(); + LOG_TO(SYSTEM, ERROR) << "read UID IO stats failed"; + } + + if (refresh_uid) { + packagelist_parse(packagelist_parse_cb, &uids); + } + + return uids; +} + +void uid_monitor::report() +{ + struct timespec ts; + + // Use monotonic to exclude suspend time so that we measure IO bytes/sec + // when system is running. + if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) { + PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed"; + return; + } + + uint64_t curr_ts = ts.tv_sec * NS_PER_SEC + ts.tv_nsec; + uint64_t ts_delta = curr_ts - last_report_ts; + uint64_t adjusted_threshold = io_alert_threshold * ((double)ts_delta / interval / NS_PER_SEC); + + std::unordered_map uids = get_uids(); + if (uids.empty()) { + return; + } + + for (const auto& it : uids) { + const struct uid_info& uid = it.second; + uint64_t bg_read_delta = uid.io[UID_BACKGROUND].read_bytes - + last_uids[uid.uid].io[UID_BACKGROUND].read_bytes; + uint64_t bg_write_delta = uid.io[UID_BACKGROUND].write_bytes - + last_uids[uid.uid].io[UID_BACKGROUND].write_bytes; + + if (bg_read_delta + bg_write_delta >= adjusted_threshold) { + android_log_event_list(EVENTLOGTAG_UID_IO_ALERT) + << uid.name << bg_read_delta << bg_write_delta + << uint64_t(ts_delta / NS_PER_SEC) << LOG_ID_EVENTS; + } + } + + set_last_uids(std::move(uids), curr_ts); +} + +uid_monitor::uid_monitor() +{ + struct timespec ts; + + if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) { + PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed"; + return; + } + last_report_ts = ts.tv_sec * NS_PER_SEC + ts.tv_nsec; +} diff --git a/storaged/storaged_utils.cpp b/storaged/storaged_utils.cpp index c845ac471..6e4ddb66c 100644 --- a/storaged/storaged_utils.cpp +++ b/storaged/storaged_utils.cpp @@ -435,6 +435,54 @@ void log_console_running_tasks_info(std::vector tasks) { fflush(stdout); } +static bool cmp_uid_info(struct uid_info l, struct uid_info r) { + // Compare background I/O first. + for (int i = UID_STATS_SIZE - 1; i >= 0; i--) { + uint64_t l_bytes = l.io[i].read_bytes + l.io[i].write_bytes; + uint64_t r_bytes = r.io[i].read_bytes + r.io[i].write_bytes; + uint64_t l_chars = l.io[i].rchar + l.io[i].wchar; + uint64_t r_chars = r.io[i].rchar + r.io[i].wchar; + + if (l_bytes != r_bytes) { + return l_bytes > r_bytes; + } + if (l_chars != r_chars) { + return l_chars > r_chars; + } + } + + return l.name < r.name; +} + +void sort_running_uids_info(std::vector &uids) { + std::sort(uids.begin(), uids.end(), cmp_uid_info); +} + +// Logging functions +void log_console_running_uids_info(std::vector uids) { +// Sample Output: +// Application FG Read FG Write FG Read FG Write BG Read BG Write BG Read BG Write +// NAME/UID Characters Characters Bytes Bytes Characters Characters Bytes Bytes +// ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- +// com.google.android.gsf.login 0 0 0 0 57195097 5137089 176386048 6512640 +// com.google.android.googlequicksearchbox 0 0 0 0 4196821 12123468 34295808 13225984 +// 1037 4572 537 0 0 131352 5145643 34263040 5144576 +// com.google.android.youtube 2182 70 0 0 63969383 482939 38731776 466944 + + // Title + printf("Per-UID I/O stats\n"); + printf(" Application FG Read FG Write FG Read FG Write BG Read BG Write BG Read BG Write\n" + " NAME/UID Characters Characters Bytes Bytes Characters Characters Bytes Bytes\n" + " ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------\n"); + + for (const auto& uid : uids) { + printf("%50s%15ju%15ju%15ju%15ju%15ju%15ju%15ju%15ju\n", uid.name.c_str(), + uid.io[0].rchar, uid.io[0].wchar, uid.io[0].read_bytes, uid.io[0].write_bytes, + uid.io[1].rchar, uid.io[1].wchar, uid.io[1].read_bytes, uid.io[1].write_bytes); + } + fflush(stdout); +} + #if DEBUG void log_debug_disk_perf(struct disk_perf* perf, const char* type) { // skip if the input structure are all zeros diff --git a/storaged/tests/Android.mk b/storaged/tests/Android.mk index 4a0e45c78..26d04b162 100644 --- a/storaged/tests/Android.mk +++ b/storaged/tests/Android.mk @@ -40,6 +40,6 @@ LOCAL_MODULE := $(test_module_prefix)unit-tests LOCAL_MODULE_TAGS := $(test_tags) LOCAL_CFLAGS += $(test_c_flags) LOCAL_STATIC_LIBRARIES := libstoraged -LOCAL_SHARED_LIBRARIES := libbase libcutils liblog +LOCAL_SHARED_LIBRARIES := libbase libcutils liblog libpackagelistparser LOCAL_SRC_FILES := $(test_src_files) include $(BUILD_NATIVE_TEST)