diff --git a/storaged/include/storaged.h b/storaged/include/storaged.h index 15d830c39..c6cdd81c7 100644 --- a/storaged/include/storaged.h +++ b/storaged/include/storaged.h @@ -283,7 +283,6 @@ public: void pause(void) { sleep(mConfig.periodic_chores_interval_unit); } - void set_privileged_fds(int fd_emmc) { mEmmcInfo.set_emmc_fd(fd_emmc); } @@ -295,6 +294,9 @@ public: std::unordered_map get_uids(void) { return mUidm.get_uids(); } + std::vector get_uid_events(void) { + return mUidm.dump_events(); + } }; // Eventlog tag diff --git a/storaged/include/storaged_service.h b/storaged/include/storaged_service.h index 0735f292d..a8ddf4c32 100644 --- a/storaged/include/storaged_service.h +++ b/storaged/include/storaged_service.h @@ -52,6 +52,7 @@ class BnStoraged : public BnInterface { class Storaged : public BnStoraged { virtual std::vector dump_uids(const char* option); + virtual status_t dump(int fd, const Vector& args); }; sp get_storaged_service(); diff --git a/storaged/include/storaged_uid_monitor.h b/storaged/include/storaged_uid_monitor.h index 9f95c5188..fffed6f19 100644 --- a/storaged/include/storaged_uid_monitor.h +++ b/storaged/include/storaged_uid_monitor.h @@ -21,6 +21,7 @@ #include #include +#include enum { UID_FOREGROUND = 0, @@ -39,22 +40,33 @@ 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 +}; +struct uid_event { + std::string name; + uint64_t read_bytes; + uint64_t write_bytes; + uint64_t interval; }; class uid_monitor { private: std::unordered_map last_uids; + std::vector events; + sem_t events_lock; void set_last_uids(std::unordered_map&& uids, uint64_t ts); int interval; // monitor interval in seconds int threshold; // monitor threshold in bytes uint64_t last_report_ts; // timestamp of last report in nsec public: uid_monitor(); + ~uid_monitor(); void set_periodic_chores_params(int intvl, int thold) { interval = intvl; threshold = thold; } int get_periodic_chores_interval() { return interval; } std::unordered_map get_uids(); void report(); + void add_event(const struct uid_event& event); + std::vector dump_events(); }; #endif /* _STORAGED_UID_MONITOR_H_ */ diff --git a/storaged/storaged_service.cpp b/storaged/storaged_service.cpp index 15185ec6f..2799c3933 100644 --- a/storaged/storaged_service.cpp +++ b/storaged/storaged_service.cpp @@ -23,6 +23,8 @@ #include #include +#include +#include #include #include @@ -44,14 +46,13 @@ std::vector BpStoraged::dump_uids(const char* /*option*/) { } return res; } - IMPLEMENT_META_INTERFACE(Storaged, "Storaged"); status_t BnStoraged::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { - data.checkInterface(this); - switch(code) { case DUMPUIDS: { + if (!data.checkInterface(this)) + return BAD_TYPE; std::vector res = dump_uids(NULL); reply->writeInt32(res.size()); for (auto uid : res) { @@ -77,6 +78,27 @@ std::vector Storaged::dump_uids(const char* /* option */) { return uids_v; } +status_t Storaged::dump(int fd, const Vector& /* args */) { + IPCThreadState* self = IPCThreadState::self(); + const int pid = self->getCallingPid(); + const int uid = self->getCallingUid(); + if ((uid != AID_SHELL) && + !PermissionCache::checkPermission( + String16("android.permission.DUMP"), pid, uid)) { + return PERMISSION_DENIED; + } + + const std::vector& events = storaged.get_uid_events(); + for (const auto& event : events) { + dprintf(fd, "%s %llu %llu %llu\n", event.name.c_str(), + (unsigned long long)event.read_bytes, + (unsigned long long)event.write_bytes, + (unsigned long long)event.interval); + } + return NO_ERROR; +} + + sp get_storaged_service() { sp sm = defaultServiceManager(); if (sm == NULL) return NULL; diff --git a/storaged/storaged_uid_monitor.cpp b/storaged/storaged_uid_monitor.cpp index 2a84a0c40..fd30f5f5b 100644 --- a/storaged/storaged_uid_monitor.cpp +++ b/storaged/storaged_uid_monitor.cpp @@ -101,6 +101,28 @@ std::unordered_map uid_monitor::get_uids() return uids; } +static const int MAX_UID_EVENTS = 1000; + +void uid_monitor::add_event(const struct uid_event& event) +{ + std::unique_ptr lock(new lock_t(&events_lock)); + + if (events.size() > MAX_UID_EVENTS) { + LOG_TO(SYSTEM, ERROR) << "event buffer full"; + return; + } + events.push_back(event); +} + +std::vector uid_monitor::dump_events() +{ + std::unique_ptr lock(new lock_t(&events_lock)); + std::vector dump_events = events; + + events.clear(); + return dump_events; +} + void uid_monitor::report() { struct timespec ts; @@ -129,6 +151,13 @@ void uid_monitor::report() last_uids[uid.uid].io[UID_BACKGROUND].write_bytes; if (bg_read_delta + bg_write_delta >= adjusted_threshold) { + struct uid_event event; + event.name = uid.name; + event.read_bytes = bg_read_delta; + event.write_bytes = bg_write_delta; + event.interval = uint64_t(ts_delta / NS_PER_SEC); + add_event(event); + 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; @@ -147,4 +176,11 @@ uid_monitor::uid_monitor() return; } last_report_ts = ts.tv_sec * NS_PER_SEC + ts.tv_nsec; + + sem_init(&events_lock, 0, 1); +} + +uid_monitor::~uid_monitor() +{ + sem_destroy(&events_lock); }