Merge "Add permission bits to open with O_CREAT."
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 6bd5e83..8ab5e30 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -265,10 +265,14 @@
     if (!svc) {
         return -1;
     }
-    if (!svc->Start()) {
+    if (!start_waiting_for_exec()) {
         return -1;
     }
-    waiting_for_exec = true;
+    if (!svc->Start()) {
+        stop_waiting_for_exec();
+        ServiceManager::GetInstance().RemoveService(*svc);
+        return -1;
+    }
     return 0;
 }
 
@@ -1021,7 +1025,7 @@
                    << "\") failed: value too long";
         return -1;
     }
-    if (!wait_property(name, value)) {
+    if (!start_waiting_for_property(name, value)) {
         LOG(ERROR) << "do_wait_for_prop(\"" << name << "\", \"" << value
                    << "\") failed: init already in waiting";
         return -1;
diff --git a/init/init.cpp b/init/init.cpp
index c8c18d2..43f601f 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -82,7 +82,7 @@
 
 const char *ENV[32];
 
-bool waiting_for_exec = false;
+static std::unique_ptr<Timer> waiting_for_exec(nullptr);
 
 static int epoll_fd = -1;
 
@@ -131,7 +131,24 @@
     return -1;
 }
 
-bool wait_property(const char *name, const char *value)
+bool start_waiting_for_exec()
+{
+    if (waiting_for_exec) {
+        return false;
+    }
+    waiting_for_exec.reset(new Timer());
+    return true;
+}
+
+void stop_waiting_for_exec()
+{
+    if (waiting_for_exec) {
+        LOG(INFO) << "Wait for exec took " << *waiting_for_exec;
+        waiting_for_exec.reset();
+    }
+}
+
+bool start_waiting_for_property(const char *name, const char *value)
 {
     if (waiting_for_prop) {
         return false;
@@ -142,7 +159,8 @@
         wait_prop_value = value;
         waiting_for_prop.reset(new Timer());
     } else {
-        LOG(INFO) << "wait_property(\"" << name << "\", \"" << value << "\"): already set";
+        LOG(INFO) << "start_waiting_for_property(\""
+                  << name << "\", \"" << value << "\"): already set";
     }
     return true;
 }
diff --git a/init/init.h b/init/init.h
index 4e4da32..3768c02 100644
--- a/init/init.h
+++ b/init/init.h
@@ -23,7 +23,6 @@
 class Service;
 
 extern const char *ENV[32];
-extern bool waiting_for_exec;
 extern std::string default_console;
 extern struct selabel_handle *sehandle;
 extern struct selabel_handle *sehandle_prop;
@@ -36,6 +35,10 @@
 
 int add_environment(const char* key, const char* val);
 
-bool wait_property(const char *name, const char *value);
+bool start_waiting_for_exec();
+
+void stop_waiting_for_exec();
+
+bool start_waiting_for_property(const char *name, const char *value);
 
 #endif  /* _INIT_INIT_H */
diff --git a/init/service.cpp b/init/service.cpp
index 0f7f62f..e186f27 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -997,7 +997,7 @@
     }
 
     if (svc->Reap()) {
-        waiting_for_exec = false;
+        stop_waiting_for_exec();
         RemoveService(*svc);
     }
 
diff --git a/storaged/include/storaged.h b/storaged/include/storaged.h
index 41bdf97..ba78882 100644
--- a/storaged/include/storaged.h
+++ b/storaged/include/storaged.h
@@ -45,6 +45,8 @@
 #define MSEC_TO_USEC ( 1000 )
 #define USEC_TO_NSEC ( 1000 )
 #define SEC_TO_USEC ( 1000000 )
+#define HOUR_TO_SEC ( 3600 )
+#define DAY_TO_SEC ( 3600 * 24 )
 
 // number of attributes diskstats has
 #define DISK_STATS_SIZE ( 11 )
@@ -250,7 +252,7 @@
 #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 ( 86400 )
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO ( 3600 )
 
 // UID IO threshold in bytes
 #define DEFAULT_PERIODIC_CHORES_UID_IO_THRESHOLD ( 1024 * 1024 * 1024ULL )
@@ -294,8 +296,8 @@
     std::unordered_map<uint32_t, struct uid_info> get_uids(void) {
         return mUidm.get_uids();
     }
-    std::vector<struct uid_event> get_uid_events(void) {
-        return mUidm.dump_events();
+    std::vector<struct uid_event> get_uid_events(int hours) {
+        return mUidm.dump_events(hours);
     }
 };
 
diff --git a/storaged/include/storaged_uid_monitor.h b/storaged/include/storaged_uid_monitor.h
index 9101767..ac6a8bd 100644
--- a/storaged/include/storaged_uid_monitor.h
+++ b/storaged/include/storaged_uid_monitor.h
@@ -48,7 +48,10 @@
     uint64_t fg_write_bytes;
     uint64_t bg_read_bytes;
     uint64_t bg_write_bytes;
-    uint64_t interval;
+    uint64_t ts;
+    bool operator< (const struct uid_event& e) const {
+        return ts < e.ts;
+    }
 };
 
 class uid_monitor {
@@ -67,8 +70,8 @@
     int get_periodic_chores_interval() { return interval; }
     std::unordered_map<uint32_t, struct uid_info> get_uids();
     void report();
-    void add_event(const struct uid_event& event);
-    std::vector<struct uid_event> dump_events();
+    void add_events(const std::vector<struct uid_event>& new_events, uint64_t curr_ts);
+    std::vector<struct uid_event> dump_events(int hours);
 };
 
 #endif /* _STORAGED_UID_MONITOR_H_ */
diff --git a/storaged/main.cpp b/storaged/main.cpp
index 9ad420e..ee6a4c9 100644
--- a/storaged/main.cpp
+++ b/storaged/main.cpp
@@ -104,9 +104,6 @@
     fflush(stdout);
 }
 
-#define HOUR_TO_SEC ( 3600 )
-#define DAY_TO_SEC ( 3600 * 24 )
-
 int main(int argc, char** argv) {
     int flag_main_service = 0;
     int flag_dump_uid = 0;
diff --git a/storaged/storaged_service.cpp b/storaged/storaged_service.cpp
index 86a2b21..d81e0e5 100644
--- a/storaged/storaged_service.cpp
+++ b/storaged/storaged_service.cpp
@@ -78,7 +78,7 @@
     return uids_v;
 }
 
-status_t Storaged::dump(int fd, const Vector<String16>& /* args */) {
+status_t Storaged::dump(int fd, const Vector<String16>& args) {
     IPCThreadState* self = IPCThreadState::self();
     const int pid = self->getCallingPid();
     const int uid = self->getCallingUid();
@@ -88,14 +88,26 @@
         return PERMISSION_DENIED;
     }
 
-    const std::vector<struct uid_event>& events = storaged.get_uid_events();
+    int hours = 0;
+    for (size_t i = 0; i < args.size(); i++) {
+        const auto& arg = args[i];
+        if (arg == String16("--hours")) {
+            if (++i >= args.size())
+                break;
+            hours = stoi(String16::std_string(args[i]));
+            continue;
+        }
+    }
+
+    const std::vector<struct uid_event>& events = storaged.get_uid_events(hours);
     for (const auto& event : events) {
-        dprintf(fd, "%s %llu %llu %llu %llu %llu\n", event.name.c_str(),
+        dprintf(fd, "%llu %s %llu %llu %llu %llu\n",
+            (unsigned long long)event.ts,
+            event.name.c_str(),
             (unsigned long long)event.fg_read_bytes,
             (unsigned long long)event.fg_write_bytes,
             (unsigned long long)event.bg_read_bytes,
-            (unsigned long long)event.bg_write_bytes,
-            (unsigned long long)event.interval);
+            (unsigned long long)event.bg_write_bytes);
     }
     return NO_ERROR;
 }
diff --git a/storaged/storaged_uid_monitor.cpp b/storaged/storaged_uid_monitor.cpp
index 5f664e4..93c9df4 100644
--- a/storaged/storaged_uid_monitor.cpp
+++ b/storaged/storaged_uid_monitor.cpp
@@ -101,25 +101,48 @@
     return uids;
 }
 
-static const int MAX_UID_EVENTS = 1000;
+static const int MAX_UID_EVENTS_SIZE = 1000 * 48; // 1000 uids in 48 hours
 
-void uid_monitor::add_event(const struct uid_event& event)
+void uid_monitor::add_events(const std::vector<struct uid_event>& new_events,
+                             uint64_t curr_ts)
 {
     std::unique_ptr<lock_t> lock(new lock_t(&events_lock));
 
-    if (events.size() > MAX_UID_EVENTS) {
-        LOG_TO(SYSTEM, ERROR) << "event buffer full";
-        return;
-    }
-    events.push_back(event);
+    // remove events more than 5 days old
+    struct uid_event first_event;
+    first_event.ts = curr_ts / SEC_TO_USEC - 5 * DAY_TO_SEC;
+    auto it = std::upper_bound(events.begin(), events.end(), first_event);
+    events.erase(events.begin(), it);
+
+    // make some room for new events
+    int overflow = events.size() + new_events.size() - MAX_UID_EVENTS_SIZE;
+    if (overflow > 0)
+        events.erase(events.begin(), events.begin() + overflow);
+
+    events.insert(events.end(), new_events.begin(), new_events.end());
 }
 
-std::vector<struct uid_event> uid_monitor::dump_events()
+std::vector<struct uid_event> uid_monitor::dump_events(int hours)
 {
     std::unique_ptr<lock_t> lock(new lock_t(&events_lock));
-    std::vector<struct uid_event> dump_events = events;
+    std::vector<struct uid_event> dump_events;
+    struct timespec ts;
 
-    events.clear();
+    if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
+        PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
+        return dump_events;
+    }
+
+    struct uid_event first_event;
+    if (hours == 0) {
+        first_event.ts = 0; // dump all events
+    } else {
+        first_event.ts = ts.tv_sec - (uint64_t)hours * HOUR_TO_SEC;
+    }
+    auto it = std::upper_bound(events.begin(), events.end(), first_event);
+
+    dump_events.assign(it, events.end());
+
     return dump_events;
 }
 
@@ -143,10 +166,12 @@
         return;
     }
 
+    std::vector<struct uid_event> new_events;
     for (const auto& it : uids) {
         const struct uid_info& uid = it.second;
         struct uid_event event;
 
+        event.ts = ts.tv_sec;
         event.name = uid.name;
         event.fg_read_bytes = uid.io[UID_FOREGROUND].read_bytes -
             last_uids[uid.uid].io[UID_FOREGROUND].read_bytes;;
@@ -156,11 +181,16 @@
             last_uids[uid.uid].io[UID_BACKGROUND].read_bytes;;
         event.bg_write_bytes = uid.io[UID_BACKGROUND].write_bytes -
             last_uids[uid.uid].io[UID_BACKGROUND].write_bytes;;
-        event.interval = uint64_t(ts_delta / NS_PER_SEC);
 
-        add_event(event);
+        if (event.fg_read_bytes + event.fg_write_bytes +
+            event.bg_read_bytes + event.bg_write_bytes == 0) {
+            continue;
+        }
+
+        new_events.push_back(event);
     }
 
+    add_events(new_events, curr_ts);
     set_last_uids(std::move(uids), curr_ts);
 }