storaged: move proto file to /data/misc_ce/0/storaged

Use proto_stat to indicate status of CE area. Before user_0 unlocks,
storaged detects CE NOT_AVAILABLE when attempting to read the proto
file. It then skips reading/writting the proto.

When user_0 logs in, vold calls onUserStart in storaged, which sets
proto_stat to AVAILABLE. At next event, storaged tries to read the
proto. If it's a success, proto_stat is changed to LOADED. After that,
storaged reads and writes proto normally.

Test: adb shell storaged -u -p
Bug: 63740245
Change-Id: I1fdd42c430e91682f6cc07497fcad5be52489b4e
diff --git a/storaged/include/storaged.h b/storaged/include/storaged.h
index dead656..90850e9 100644
--- a/storaged/include/storaged.h
+++ b/storaged/include/storaged.h
@@ -84,6 +84,12 @@
     static const uint32_t crc_init;
     static const string proto_file;
     storaged_proto::StoragedProto proto;
+    enum stat {
+        NOT_AVAILABLE,
+        AVAILABLE,
+        LOADED,
+    };
+    stat proto_stat;
 public:
     storaged_t(void);
     ~storaged_t() {}
@@ -110,12 +116,23 @@
         return mUidm.dump(hours, threshold, force_report,
                           proto.mutable_uid_io_usage());
     }
+
     void update_uid_io_interval(int interval) {
         if (interval >= DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO_LIMIT) {
             mConfig.periodic_chores_interval_uid_io = interval;
         }
     }
 
+    void set_proto_stat_available(bool available) {
+        if (available) {
+            if (proto_stat != LOADED) {
+                proto_stat = AVAILABLE;
+            }
+        } else {
+            proto_stat = NOT_AVAILABLE;
+        }
+    };
+
     void init_battery_service();
     virtual void batteryPropertiesChanged(struct BatteryProperties props);
     void binderDied(const wp<IBinder>& who);
diff --git a/storaged/include/storaged_info.h b/storaged/include/storaged_info.h
index 125b5a8..93a1e6a 100644
--- a/storaged/include/storaged_info.h
+++ b/storaged/include/storaged_info.h
@@ -68,7 +68,7 @@
     static storage_info_t* get_storage_info();
     virtual ~storage_info_t() { sem_destroy(&si_lock); }
     virtual void report() {};
-    void init(const IOPerfHistory& perf_history);
+    void load_perf_history_proto(const IOPerfHistory& perf_history);
     void refresh(IOPerfHistory* perf_history);
     void update_perf_history(uint32_t bw,
                              const time_point<system_clock>& tp);
diff --git a/storaged/include/storaged_uid_monitor.h b/storaged/include/storaged_uid_monitor.h
index abf2475..9245ab4 100644
--- a/storaged/include/storaged_uid_monitor.h
+++ b/storaged/include/storaged_uid_monitor.h
@@ -90,8 +90,6 @@
     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
-    void load_uid_io_proto(const UidIOUsage& proto);
     // writes io_history to protobuf
     void update_uid_io_proto(UidIOUsage* proto);
 
@@ -99,7 +97,7 @@
     uid_monitor();
     ~uid_monitor();
     // called by storaged main thread
-    void init(charger_stat_t stat, const UidIOUsage& proto);
+    void init(charger_stat_t stat);
     // called by storaged -u
     std::unordered_map<uint32_t, uid_info> get_uid_io_stats();
     // called by dumpsys
@@ -111,6 +109,8 @@
     // called by storaged periodic_chore or dump with force_report
     bool enabled() { return enable; };
     void report(UidIOUsage* proto);
+    // restores io_history from protobuf
+    void load_uid_io_proto(const UidIOUsage& proto);
 };
 
 #endif /* _STORAGED_UID_MONITOR_H_ */
diff --git a/storaged/storaged.cpp b/storaged/storaged.cpp
index 1794fb5..1cd3450 100644
--- a/storaged/storaged.cpp
+++ b/storaged/storaged.cpp
@@ -51,7 +51,7 @@
 
 const uint32_t storaged_t::crc_init = 0x5108A4ED; /* STORAGED */
 const std::string storaged_t::proto_file =
-    "/data/misc/storaged/storaged.proto";
+    "/data/misc_ce/0/storaged/storaged.proto";
 
 sp<IBatteryPropertiesRegistrar> get_battery_properties_service() {
     sp<IServiceManager> sm = defaultServiceManager();
@@ -87,7 +87,7 @@
 
     struct BatteryProperty val;
     battery_properties->getProperty(BATTERY_PROP_BATTERY_STATUS, &val);
-    mUidm.init(is_charger_on(val.valueInt64), proto.uid_io_usage());
+    mUidm.init(is_charger_on(val.valueInt64));
 
     // register listener after init uid_monitor
     battery_properties->registerListener(this);
@@ -106,12 +106,11 @@
 }
 
 void storaged_t::report_storage_info() {
-    storage_info->init(proto.perf_history());
     storage_info->report();
 }
 
 /* storaged_t */
-storaged_t::storaged_t(void) {
+storaged_t::storaged_t(void) : proto_stat(NOT_AVAILABLE) {
     mConfig.periodic_chores_interval_unit =
         property_get_int32("ro.storaged.event.interval",
                            DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT);
@@ -143,11 +142,15 @@
 
     if (!in.good()) {
         PLOG_TO(SYSTEM, INFO) << "Open " << proto_file << " failed";
+        proto_stat = NOT_AVAILABLE;
         return;
     }
 
+    proto_stat = AVAILABLE;
+
     stringstream ss;
     ss << in.rdbuf();
+    proto.Clear();
     proto.ParseFromString(ss.str());
 
     uint32_t crc = proto.crc();
@@ -160,10 +163,18 @@
     if (crc != computed_crc) {
         LOG_TO(SYSTEM, WARNING) << "CRC mismatch in " << proto_file;
         proto.Clear();
+        return;
     }
+
+    proto_stat = LOADED;
+
+    storage_info->load_perf_history_proto(proto.perf_history());
+    mUidm.load_uid_io_proto(proto.uid_io_usage());
 }
 
 void storaged_t::flush_proto() {
+    if (proto_stat != LOADED) return;
+
     proto.set_version(1);
     proto.set_crc(crc_init);
     while (proto.ByteSize() < 128 * 1024) {
@@ -186,6 +197,7 @@
                  S_IRUSR | S_IWUSR)));
     if (fd == -1) {
         PLOG_TO(SYSTEM, ERROR) << "Faied to open tmp file: " << tmp_file;
+        proto_stat = NOT_AVAILABLE;
         return;
     }
 
@@ -222,6 +234,10 @@
 }
 
 void storaged_t::event(void) {
+    if (proto_stat == AVAILABLE) {
+        load_proto();
+    }
+
     if (mDsm.enabled()) {
         mDsm.update();
         if (!(mTimer % mConfig.periodic_chores_interval_disk_stats_publish)) {
@@ -229,13 +245,11 @@
         }
     }
 
-    if (mUidm.enabled() &&
-        !(mTimer % mConfig.periodic_chores_interval_uid_io)) {
+    if (!(mTimer % mConfig.periodic_chores_interval_uid_io)) {
         mUidm.report(proto.mutable_uid_io_usage());
     }
 
     storage_info->refresh(proto.mutable_perf_history());
-
     if (!(mTimer % mConfig.periodic_chores_interval_flush_proto)) {
         flush_proto();
     }
diff --git a/storaged/storaged.rc b/storaged/storaged.rc
index bd4022b..6e83e33 100644
--- a/storaged/storaged.rc
+++ b/storaged/storaged.rc
@@ -1,6 +1,6 @@
-on post-fs-data
-    mkdir /data/misc/storaged 0700 root root
-    restorecon /data/misc/storaged
+# remove this after vold can create directory for us.
+on property:sys.user.0.ce_available=true
+    mkdir /data/misc_ce/0/storaged
 
 service storaged /system/bin/storaged
     class main
diff --git a/storaged/storaged_info.cpp b/storaged/storaged_info.cpp
index 4243bd7..ae26f20 100644
--- a/storaged/storaged_info.cpp
+++ b/storaged/storaged_info.cpp
@@ -66,7 +66,7 @@
     return new storage_info_t;
 }
 
-void storage_info_t::init(const IOPerfHistory& perf_history)
+void storage_info_t::load_perf_history_proto(const IOPerfHistory& perf_history)
 {
     if (!perf_history.has_day_start_sec() ||
         perf_history.daily_perf_size() > (int)daily_perf.size() ||
diff --git a/storaged/storaged_service.cpp b/storaged/storaged_service.cpp
index abfecff..a5477e6 100644
--- a/storaged/storaged_service.cpp
+++ b/storaged/storaged_service.cpp
@@ -35,6 +35,13 @@
 using namespace std;
 using namespace android::base;
 
+/*
+ * The system user is the initial user that is implicitly created on first boot
+ * and hosts most of the system services. Keep this in sync with
+ * frameworks/base/core/java/android/os/UserManager.java
+ */
+const int USER_SYSTEM = 0;
+
 extern sp<storaged_t> storaged_sp;
 
 status_t StoragedService::start() {
@@ -140,10 +147,16 @@
 }
 
 binder::Status StoragedService::onUserStarted(int32_t userId) {
+    if (userId == USER_SYSTEM) {
+        storaged_sp->set_proto_stat_available(true);
+    }
     return binder::Status::ok();
 }
 
 binder::Status StoragedService::onUserStopped(int32_t userId) {
+    if (userId == USER_SYSTEM) {
+        storaged_sp->set_proto_stat_available(false);
+    }
     return binder::Status::ok();
 }
 
diff --git a/storaged/storaged_uid_monitor.cpp b/storaged/storaged_uid_monitor.cpp
index 06a0632..640de45 100644
--- a/storaged/storaged_uid_monitor.cpp
+++ b/storaged/storaged_uid_monitor.cpp
@@ -364,6 +364,8 @@
 
 void uid_monitor::report(UidIOUsage* proto)
 {
+    if (!enabled()) return;
+
     std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
 
     update_curr_io_stats_locked();
@@ -436,6 +438,8 @@
 
 void uid_monitor::load_uid_io_proto(const UidIOUsage& uid_io_proto)
 {
+    if (!enabled()) return;
+
     for (const auto& item_proto : uid_io_proto.uid_io_items()) {
         const UidIORecords& records_proto = item_proto.records();
         struct uid_records* recs = &io_history[item_proto.end_ts()];
@@ -468,12 +472,10 @@
     charger_stat = stat;
 }
 
-void uid_monitor::init(charger_stat_t stat, const UidIOUsage& proto)
+void uid_monitor::init(charger_stat_t stat)
 {
     charger_stat = stat;
 
-    load_uid_io_proto(proto);
-
     start_ts = time(NULL);
     last_uid_io_stats = get_uid_io_stats();
 }