Merge "Fix various adb error reporting bugs."
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 4ddcc52..e3d4f87 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -128,18 +128,20 @@
     }
 }
 
+static bool should_force_check(int fs_stat) {
+    return fs_stat & (FS_STAT_E2FSCK_F_ALWAYS | FS_STAT_UNCLEAN_SHUTDOWN | FS_STAT_QUOTA_ENABLED |
+                      FS_STAT_TUNE2FS_FAILED | FS_STAT_RO_MOUNT_FAILED | FS_STAT_RO_UNMOUNT_FAILED |
+                      FS_STAT_FULL_MOUNT_FAILED | FS_STAT_E2FSCK_FAILED);
+}
+
 static void check_fs(const char *blk_device, char *fs_type, char *target, int *fs_stat)
 {
     int status;
     int ret;
     long tmpmnt_flags = MS_NOATIME | MS_NOEXEC | MS_NOSUID;
     char tmpmnt_opts[64] = "errors=remount-ro";
-    const char *e2fsck_argv[] = {
-        E2FSCK_BIN,
-        "-f",
-        "-y",
-        blk_device
-    };
+    const char* e2fsck_argv[] = {E2FSCK_BIN, "-y", blk_device};
+    const char* e2fsck_forced_argv[] = {E2FSCK_BIN, "-f", "-y", blk_device};
 
     /* Check for the types of filesystems we know how to check */
     if (!strcmp(fs_type, "ext2") || !strcmp(fs_type, "ext3") || !strcmp(fs_type, "ext4")) {
@@ -159,32 +161,35 @@
          * filesytsem due to an error, e2fsck is still run to do a full check
          * fix the filesystem.
          */
-        errno = 0;
-        if (!strcmp(fs_type, "ext4")) {
-            // This option is only valid with ext4
-            strlcat(tmpmnt_opts, ",nomblk_io_submit", sizeof(tmpmnt_opts));
-        }
-        ret = mount(blk_device, target, fs_type, tmpmnt_flags, tmpmnt_opts);
-        PINFO << __FUNCTION__ << "(): mount(" << blk_device <<  "," << target
-              << "," << fs_type << ")=" << ret;
-        if (!ret) {
-            int i;
-            for (i = 0; i < 5; i++) {
-                // Try to umount 5 times before continuing on.
-                // Should we try rebooting if all attempts fail?
-                int result = umount(target);
-                if (result == 0) {
-                    LINFO << __FUNCTION__ << "(): unmount(" << target
-                          << ") succeeded";
-                    break;
-                }
-                *fs_stat |= FS_STAT_RO_UNMOUNT_FAILED;
-                PERROR << __FUNCTION__ << "(): umount(" << target << ")="
-                       << result;
-                sleep(1);
+        if (!(*fs_stat & FS_STAT_FULL_MOUNT_FAILED)) {  // already tried if full mount failed
+            errno = 0;
+            if (!strcmp(fs_type, "ext4")) {
+                // This option is only valid with ext4
+                strlcat(tmpmnt_opts, ",nomblk_io_submit", sizeof(tmpmnt_opts));
             }
-        } else {
-            *fs_stat |= FS_STAT_RO_MOUNT_FAILED;
+            ret = mount(blk_device, target, fs_type, tmpmnt_flags, tmpmnt_opts);
+            PINFO << __FUNCTION__ << "(): mount(" << blk_device << "," << target << "," << fs_type
+                  << ")=" << ret;
+            if (!ret) {
+                bool umounted = false;
+                int retry_count = 5;
+                while (retry_count-- > 0) {
+                    umounted = umount(target) == 0;
+                    if (umounted) {
+                        LINFO << __FUNCTION__ << "(): unmount(" << target << ") succeeded";
+                        break;
+                    }
+                    PERROR << __FUNCTION__ << "(): umount(" << target << ") failed";
+                    if (retry_count) sleep(1);
+                }
+                if (!umounted) {
+                    // boot may fail but continue and leave it to later stage for now.
+                    PERROR << __FUNCTION__ << "(): umount(" << target << ") timed out";
+                    *fs_stat |= FS_STAT_RO_UNMOUNT_FAILED;
+                }
+            } else {
+                *fs_stat |= FS_STAT_RO_MOUNT_FAILED;
+            }
         }
 
         /*
@@ -196,14 +201,15 @@
                   << " (executable not in system image)";
         } else {
             LINFO << "Running " << E2FSCK_BIN << " on " << blk_device;
-
-            *fs_stat |= FS_STAT_E2FSCK_F_ALWAYS;
-            ret = android_fork_execvp_ext(ARRAY_SIZE(e2fsck_argv),
-                                          const_cast<char **>(e2fsck_argv),
-                                          &status, true, LOG_KLOG | LOG_FILE,
-                                          true,
-                                          const_cast<char *>(FSCK_LOG_FILE),
-                                          NULL, 0);
+            if (should_force_check(*fs_stat)) {
+                ret = android_fork_execvp_ext(
+                    ARRAY_SIZE(e2fsck_forced_argv), const_cast<char**>(e2fsck_forced_argv), &status,
+                    true, LOG_KLOG | LOG_FILE, true, const_cast<char*>(FSCK_LOG_FILE), NULL, 0);
+            } else {
+                ret = android_fork_execvp_ext(
+                    ARRAY_SIZE(e2fsck_argv), const_cast<char**>(e2fsck_argv), &status, true,
+                    LOG_KLOG | LOG_FILE, true, const_cast<char*>(FSCK_LOG_FILE), NULL, 0);
+            }
 
             if (ret < 0) {
                 /* No need to check for error in fork, we can't really handle it now */
@@ -574,21 +580,31 @@
                                  &fstab->recs[i], &fs_stat);
             }
 
-            if (!__mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point, &fstab->recs[i])) {
-                *attempted_idx = i;
-                mounted = 1;
-                if (i != start_idx) {
-                    LERROR << __FUNCTION__ << "(): Mounted "
-                           << fstab->recs[i].blk_device << " on "
-                           << fstab->recs[i].mount_point << " with fs_type="
-                           << fstab->recs[i].fs_type << " instead of "
-                           << fstab->recs[start_idx].fs_type;
-                }
-            } else {
-                fs_stat |= FS_STAT_FULL_MOUNT_FAILED;
-                /* back up the first errno for crypto decisions */
-                if (mount_errno == 0) {
-                    mount_errno = errno;
+            int retry_count = 2;
+            while (retry_count-- > 0) {
+                if (!__mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point,
+                             &fstab->recs[i])) {
+                    *attempted_idx = i;
+                    mounted = 1;
+                    if (i != start_idx) {
+                        LERROR << __FUNCTION__ << "(): Mounted " << fstab->recs[i].blk_device
+                               << " on " << fstab->recs[i].mount_point
+                               << " with fs_type=" << fstab->recs[i].fs_type << " instead of "
+                               << fstab->recs[start_idx].fs_type;
+                    }
+                    fs_stat &= ~FS_STAT_FULL_MOUNT_FAILED;
+                    mount_errno = 0;
+                    break;
+                } else {
+                    if (retry_count <= 0) break;  // run check_fs only once
+                    fs_stat |= FS_STAT_FULL_MOUNT_FAILED;
+                    /* back up the first errno for crypto decisions */
+                    if (mount_errno == 0) {
+                        mount_errno = errno;
+                    }
+                    // retry after fsck
+                    check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
+                             fstab->recs[i].mount_point, &fs_stat);
                 }
             }
             log_fs_stat(fstab->recs[i].blk_device, fs_stat);
@@ -1074,17 +1090,22 @@
         } else {
             m = fstab->recs[i].mount_point;
         }
-        if (__mount(n_blk_device, m, &fstab->recs[i])) {
-            if (!first_mount_errno) first_mount_errno = errno;
-            mount_errors++;
-            fs_stat |= FS_STAT_FULL_MOUNT_FAILED;
-            log_fs_stat(fstab->recs[i].blk_device, fs_stat);
-            continue;
-        } else {
-            ret = 0;
-            log_fs_stat(fstab->recs[i].blk_device, fs_stat);
-            goto out;
+        int retry_count = 2;
+        while (retry_count-- > 0) {
+            if (!__mount(n_blk_device, m, &fstab->recs[i])) {
+                ret = 0;
+                fs_stat &= ~FS_STAT_FULL_MOUNT_FAILED;
+                goto out;
+            } else {
+                if (retry_count <= 0) break;  // run check_fs only once
+                if (!first_mount_errno) first_mount_errno = errno;
+                mount_errors++;
+                fs_stat |= FS_STAT_FULL_MOUNT_FAILED;
+                // try again after fsck
+                check_fs(n_blk_device, fstab->recs[i].fs_type, fstab->recs[i].mount_point, &fs_stat);
+            }
         }
+        log_fs_stat(fstab->recs[i].blk_device, fs_stat);
     }
     if (mount_errors) {
         PERROR << "Cannot mount filesystem on " << n_blk_device
diff --git a/init/README.md b/init/README.md
index 8cb1e52..1eb42e0 100644
--- a/init/README.md
+++ b/init/README.md
@@ -16,9 +16,7 @@
 or options belong to the section most recently declared.  Commands
 or options before the first section are ignored.
 
-Actions and Services have unique names.  If a second Action is defined
-with the same name as an existing one, its commands are appended to
-the commands of the existing action.  If a second Service is defined
+Services have unique names.  If a second Service is defined
 with the same name as an existing one, it is ignored and an error
 message is logged.
 
@@ -31,13 +29,21 @@
 
 /init.rc is the primary .rc file and is loaded by the init executable
 at the beginning of its execution.  It is responsible for the initial
-set up of the system.  It imports /init.${ro.hardware}.rc which is the
-primary vendor supplied .rc file.
+set up of the system.
 
-During the mount\_all command, the init executable loads all of the
-files contained within the /{system,vendor,odm}/etc/init/ directories.
-These directories are intended for all Actions and Services used after
-file system mounting.
+Devices that mount /system, /vendor through the early mount mechanism
+load all of the files contained within the
+/{system,vendor,odm}/etc/init/ directories immediately after loading
+the primary /init.rc.  This is explained in more details in the
+Imports section of this file.
+
+Legacy devices without the early mount mechanism do the following:
+1. /init.rc imports /init.${ro.hardware}.rc which is the primary
+   vendor supplied .rc file.
+2. During the mount\_all command, the init executable loads all of the
+   files contained within the /{system,vendor,odm}/etc/init/ directories.
+   These directories are intended for all Actions and Services used after
+   file system mounting.
 
 One may specify paths in the mount\_all command line to have it import
 .rc files at the specified paths instead of the default ones listed above.
@@ -89,7 +95,7 @@
 Actions
 -------
 Actions are named sequences of commands.  Actions have a trigger which
-is used to determine when the action should occur.  When an event
+is used to determine when the action is executed.  When an event
 occurs which matches an action's trigger, that action is added to
 the tail of a to-be-executed queue (unless it is already on the
 queue).
@@ -106,6 +112,34 @@
        <command>
        <command>
 
+Actions are added to the queue and executed based on the order that
+the file that contains them was parsed (see the Imports section), then
+sequentially within an individual file.
+
+For example if a file contains:
+
+    on boot
+       setprop a 1
+       setprop b 2
+
+    on boot && property:true=true
+       setprop c 1
+       setprop d 2
+
+    on boot
+       setprop e 1
+       setprop f 2
+
+Then when the `boot` trigger occurs and assuming the property `true`
+equals `true`, then the order of the commands executed will be:
+
+    setprop a 1
+    setprop b 2
+    setprop c 1
+    setprop d 2
+    setprop e 1
+    setprop f 2
+
 
 Services
 --------
@@ -276,7 +310,8 @@
 
 `class_start <serviceclass>`
 > Start all services of the specified class if they are
-  not already running.
+  not already running.  See the start entry for more information on
+  starting services.
 
 `class_stop <serviceclass>`
 > Stop and disable all services of the specified class if they are
@@ -401,6 +436,16 @@
 
 `start <service>`
 > Start a service running if it is not already running.
+  Note that this is _not_ synchronous, and even if it were, there is
+  no guarantee that the operating system's scheduler will execute the
+  service sufficiently to guarantee anything about the service's status.
+
+> This creates an important consequence that if the service offers
+  functionality to other services, such as providing a
+  communication channel, simply starting this service before those
+  services is _not_ sufficient to guarantee that the channel has
+  been set up before those services ask for it.  There must be a
+  separate mechanism to make any such guarantees.
 
 `stop <service>`
 > Stop a service from running if it is currently running.
@@ -447,21 +492,54 @@
 
 Imports
 -------
-The import keyword is not a command, but rather its own section and is
-handled immediately after the .rc file that contains it has finished
-being parsed.  It takes the below form:
-
 `import <path>`
 > Parse an init config file, extending the current configuration.
   If _path_ is a directory, each file in the directory is parsed as
   a config file. It is not recursive, nested directories will
   not be parsed.
 
-There are only two times where the init executable imports .rc files:
+The import keyword is not a command, but rather its own section,
+meaning that it does not happen as part of an Action, but rather,
+imports are handled as a file is being parsed and follow the below logic.
 
-   1. When it imports /init.rc during initial boot
-   2. When it imports /{system,vendor,odm}/etc/init/ or .rc files at specified
-      paths during mount_all
+There are only three times where the init executable imports .rc files:
+
+   1. When it imports /init.rc or the script indicated by the property
+      `ro.boot.init_rc` during initial boot.
+   2. When it imports /{system,vendor,odm}/etc/init/ for early mount
+      devices immediately after importing /init.rc.
+   3. When it imports /{system,vendor,odm}/etc/init/ or .rc files at specified
+      paths during mount_all.
+
+The order that files are imported is a bit complex for legacy reasons
+and to keep backwards compatibility.  It is not strictly guaranteed.
+
+The only correct way to guarantee that a command has been run before a
+different command is to either 1) place it in an Action with an
+earlier executed trigger, or 2) place it in an Action with the same
+trigger within the same file at an earlier line.
+
+Nonetheless, the defacto order for early mount devices is:
+1. /init.rc is parsed then recursively each of its imports are
+   parsed.
+2. The contents of /system/etc/init/ are alphabetized and parsed
+   sequentially, with imports happening recursively after each file is
+   parsed.
+3. Step 2 is repeated for /vendor/etc/init then /odm/etc/init
+
+The below pseudocode may explain this more clearly:
+
+    fn Import(file)
+      Parse(file)
+      for (import : file.imports)
+        Import(import)
+
+    Import(/init.rc)
+    Directories = [/system/etc/init, /vendor/etc/init, /odm/etc/init]
+    for (directory : Directories)
+      files = <Alphabetical order of directory's contents>
+      for (file : files)
+        Import(file)
 
 
 Properties
diff --git a/init/action.cpp b/init/action.cpp
index 347edb0..c128968 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -26,10 +26,8 @@
 using android::base::Join;
 using android::base::StringPrintf;
 
-Command::Command(BuiltinFunction f, const std::vector<std::string>& args,
-                 const std::string& filename, int line)
-    : func_(f), args_(args), filename_(filename), line_(line) {
-}
+Command::Command(BuiltinFunction f, const std::vector<std::string>& args, int line)
+    : func_(f), args_(args), line_(line) {}
 
 int Command::InvokeFunc() const {
     std::vector<std::string> expanded_args;
@@ -49,21 +47,12 @@
     return Join(args_, ' ');
 }
 
-std::string Command::BuildSourceString() const {
-    if (!filename_.empty()) {
-        return StringPrintf(" (%s:%d)", filename_.c_str(), line_);
-    } else {
-        return std::string();
-    }
-}
-
-Action::Action(bool oneshot) : oneshot_(oneshot) {
-}
+Action::Action(bool oneshot, const std::string& filename, int line)
+    : oneshot_(oneshot), filename_(filename), line_(line) {}
 
 const KeywordMap<BuiltinFunction>* Action::function_map_ = nullptr;
 
-bool Action::AddCommand(const std::vector<std::string>& args,
-                        const std::string& filename, int line, std::string* err) {
+bool Action::AddCommand(const std::vector<std::string>& args, int line, std::string* err) {
     if (!function_map_) {
         *err = "no function map available";
         return false;
@@ -79,20 +68,12 @@
         return false;
     }
 
-    AddCommand(function, args, filename, line);
+    AddCommand(function, args, line);
     return true;
 }
 
-void Action::AddCommand(BuiltinFunction f,
-                        const std::vector<std::string>& args,
-                        const std::string& filename, int line) {
-    commands_.emplace_back(f, args, filename, line);
-}
-
-void Action::CombineAction(const Action& action) {
-    for (const auto& c : action.commands_) {
-        commands_.emplace_back(c);
-    }
+void Action::AddCommand(BuiltinFunction f, const std::vector<std::string>& args, int line) {
+    commands_.emplace_back(f, args, line);
 }
 
 std::size_t Action::NumCommands() const {
@@ -122,7 +103,7 @@
         android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
         std::string trigger_name = BuildTriggersString();
         std::string cmd_str = command.BuildCommandString();
-        std::string source = command.BuildSourceString();
+        std::string source = StringPrintf(" (%s:%d)", filename_.c_str(), command.line());
 
         LOG(INFO) << "Command '" << cmd_str << "' action=" << trigger_name << source
                   << " returned " << result << " took " << duration_ms << "ms.";
@@ -234,11 +215,6 @@
     return event_trigger_.empty() && CheckPropertyTriggers(name, value);
 }
 
-bool Action::TriggersEqual(const Action& other) const {
-    return property_triggers_ == other.property_triggers_ &&
-        event_trigger_ == other.event_trigger_;
-}
-
 std::string Action::BuildTriggersString() const {
     std::vector<std::string> triggers;
 
@@ -306,17 +282,7 @@
 }
 
 void ActionManager::AddAction(std::unique_ptr<Action> action) {
-    auto old_action_it =
-        std::find_if(actions_.begin(), actions_.end(),
-                     [&action] (std::unique_ptr<Action>& a) {
-                         return action->TriggersEqual(*a);
-                     });
-
-    if (old_action_it != actions_.end()) {
-        (*old_action_it)->CombineAction(*action);
-    } else {
-        actions_.emplace_back(std::move(action));
-    }
+    actions_.emplace_back(std::move(action));
 }
 
 void ActionManager::QueueEventTrigger(const std::string& trigger) {
@@ -332,16 +298,15 @@
     QueuePropertyTrigger("", "");
 }
 
-void ActionManager::QueueBuiltinAction(BuiltinFunction func,
-                                       const std::string& name) {
-    auto action = std::make_unique<Action>(true);
+void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) {
+    auto action = std::make_unique<Action>(true, "<Builtin Action>", 0);
     std::vector<std::string> name_vector{name};
 
     if (!action->InitSingleTrigger(name)) {
         return;
     }
 
-    action->AddCommand(func, name_vector);
+    action->AddCommand(func, name_vector, 0);
 
     trigger_queue_.push(std::make_unique<BuiltinTrigger>(action.get()));
     actions_.emplace_back(std::move(action));
@@ -366,7 +331,8 @@
 
     if (current_command_ == 0) {
         std::string trigger_name = action->BuildTriggersString();
-        LOG(INFO) << "processing action (" << trigger_name << ")";
+        LOG(INFO) << "processing action (" << trigger_name << ") from (" << action->filename()
+                  << ":" << action->line() << ")";
     }
 
     action->ExecuteOneCommand(current_command_);
@@ -397,15 +363,15 @@
     }
 }
 
-bool ActionParser::ParseSection(const std::vector<std::string>& args,
-                                std::string* err) {
+bool ActionParser::ParseSection(const std::vector<std::string>& args, const std::string& filename,
+                                int line, std::string* err) {
     std::vector<std::string> triggers(args.begin() + 1, args.end());
     if (triggers.size() < 1) {
         *err = "actions must have a trigger";
         return false;
     }
 
-    auto action = std::make_unique<Action>(false);
+    auto action = std::make_unique<Action>(false, filename, line);
     if (!action->InitTriggers(triggers, err)) {
         return false;
     }
@@ -414,10 +380,9 @@
     return true;
 }
 
-bool ActionParser::ParseLineSection(const std::vector<std::string>& args,
-                                    const std::string& filename, int line,
-                                    std::string* err) const {
-    return action_ ? action_->AddCommand(args, filename, line, err) : false;
+bool ActionParser::ParseLineSection(const std::vector<std::string>& args, int line,
+                                    std::string* err) {
+    return action_ ? action_->AddCommand(args, line, err) : false;
 }
 
 void ActionParser::EndSection() {
diff --git a/init/action.h b/init/action.h
index 0bae9f0..25e5a3e 100644
--- a/init/action.h
+++ b/init/action.h
@@ -27,31 +27,26 @@
 #include "keyword_map.h"
 
 class Command {
-public:
-    Command(BuiltinFunction f, const std::vector<std::string>& args,
-            const std::string& filename, int line);
+  public:
+    Command(BuiltinFunction f, const std::vector<std::string>& args, int line);
 
     int InvokeFunc() const;
     std::string BuildCommandString() const;
-    std::string BuildSourceString() const;
 
-private:
+    int line() const { return line_; }
+
+  private:
     BuiltinFunction func_;
     std::vector<std::string> args_;
-    std::string filename_;
     int line_;
 };
 
 class Action {
-public:
-    explicit Action(bool oneshot = false);
+  public:
+    explicit Action(bool oneshot, const std::string& filename, int line);
 
-    bool AddCommand(const std::vector<std::string>& args,
-                    const std::string& filename, int line, std::string* err);
-    void AddCommand(BuiltinFunction f,
-                    const std::vector<std::string>& args,
-                    const std::string& filename = "", int line = 0);
-    void CombineAction(const Action& action);
+    bool AddCommand(const std::vector<std::string>& args, int line, std::string* err);
+    void AddCommand(BuiltinFunction f, const std::vector<std::string>& args, int line);
     bool InitTriggers(const std::vector<std::string>& args, std::string* err);
     bool InitSingleTrigger(const std::string& trigger);
     std::size_t NumCommands() const;
@@ -60,11 +55,12 @@
     bool CheckEventTrigger(const std::string& trigger) const;
     bool CheckPropertyTrigger(const std::string& name,
                               const std::string& value) const;
-    bool TriggersEqual(const Action& other) const;
     std::string BuildTriggersString() const;
     void DumpState() const;
 
     bool oneshot() const { return oneshot_; }
+    const std::string& filename() const { return filename_; }
+    int line() const { return line_; }
     static void set_function_map(const KeywordMap<BuiltinFunction>* function_map) {
         function_map_ = function_map;
     }
@@ -80,6 +76,8 @@
     std::string event_trigger_;
     std::vector<Command> commands_;
     bool oneshot_;
+    std::string filename_;
+    int line_;
     static const KeywordMap<BuiltinFunction>* function_map_;
 };
 
@@ -115,18 +113,17 @@
 };
 
 class ActionParser : public SectionParser {
-public:
+  public:
     ActionParser() : action_(nullptr) {
     }
-    bool ParseSection(const std::vector<std::string>& args,
+    bool ParseSection(const std::vector<std::string>& args, const std::string& filename, int line,
                       std::string* err) override;
-    bool ParseLineSection(const std::vector<std::string>& args,
-                          const std::string& filename, int line,
-                          std::string* err) const override;
+    bool ParseLineSection(const std::vector<std::string>& args, int line, std::string* err) override;
     void EndSection() override;
     void EndFile(const std::string&) override {
     }
-private:
+
+  private:
     std::unique_ptr<Action> action_;
 };
 
diff --git a/init/import_parser.cpp b/init/import_parser.cpp
index 8a2bcc2..f66b2ba 100644
--- a/init/import_parser.cpp
+++ b/init/import_parser.cpp
@@ -20,8 +20,8 @@
 
 #include "util.h"
 
-bool ImportParser::ParseSection(const std::vector<std::string>& args,
-                                std::string* err) {
+bool ImportParser::ParseSection(const std::vector<std::string>& args, const std::string& filename,
+                                int line, std::string* err) {
     if (args.size() != 2) {
         *err = "single argument needed for import\n";
         return false;
diff --git a/init/import_parser.h b/init/import_parser.h
index 0e91025..e15d555 100644
--- a/init/import_parser.h
+++ b/init/import_parser.h
@@ -23,20 +23,20 @@
 #include <vector>
 
 class ImportParser : public SectionParser {
-public:
+  public:
     ImportParser()  {
     }
-    bool ParseSection(const std::vector<std::string>& args,
+    bool ParseSection(const std::vector<std::string>& args, const std::string& filename, int line,
                       std::string* err) override;
-    bool ParseLineSection(const std::vector<std::string>& args,
-                          const std::string& filename, int line,
-                          std::string* err) const override {
+    bool ParseLineSection(const std::vector<std::string>& args, int line,
+                          std::string* err) override {
         return true;
     }
     void EndSection() override {
     }
     void EndFile(const std::string& filename) override;
-private:
+
+  private:
     std::vector<std::string> imports_;
 };
 
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index 53e670b..b425497 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -71,14 +71,13 @@
                 }
                 section_parser = section_parsers_[args[0]].get();
                 std::string ret_err;
-                if (!section_parser->ParseSection(args, &ret_err)) {
+                if (!section_parser->ParseSection(args, state.filename, state.line, &ret_err)) {
                     parse_error(&state, "%s\n", ret_err.c_str());
                     section_parser = nullptr;
                 }
             } else if (section_parser) {
                 std::string ret_err;
-                if (!section_parser->ParseLineSection(args, state.filename,
-                                                      state.line, &ret_err)) {
+                if (!section_parser->ParseLineSection(args, state.line, &ret_err)) {
                     parse_error(&state, "%s\n", ret_err.c_str());
                 }
             }
diff --git a/init/init_parser.h b/init/init_parser.h
index 6935fdf..64f0cac 100644
--- a/init/init_parser.h
+++ b/init/init_parser.h
@@ -26,11 +26,10 @@
 public:
     virtual ~SectionParser() {
     }
-    virtual bool ParseSection(const std::vector<std::string>& args,
-                              std::string* err) = 0;
-    virtual bool ParseLineSection(const std::vector<std::string>& args,
-                                  const std::string& filename, int line,
-                                  std::string* err) const = 0;
+    virtual bool ParseSection(const std::vector<std::string>& args, const std::string& filename,
+                              int line, std::string* err) = 0;
+    virtual bool ParseLineSection(const std::vector<std::string>& args, int line,
+                                  std::string* err) = 0;
     virtual void EndSection() = 0;
     virtual void EndFile(const std::string& filename) = 0;
 };
diff --git a/init/service.cpp b/init/service.cpp
index 4adbbf0..caf5785 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -157,6 +157,7 @@
       gid_(0),
       namespace_flags_(0),
       seclabel_(""),
+      onrestart_(false, "<Service '" + name + "' onrestart>", 0),
       ioprio_class_(IoSchedClass_NONE),
       ioprio_pri_(0),
       priority_(0),
@@ -180,6 +181,7 @@
       capabilities_(capabilities),
       namespace_flags_(namespace_flags),
       seclabel_(seclabel),
+      onrestart_(false, "<Service '" + name + "' onrestart>", 0),
       ioprio_class_(IoSchedClass_NONE),
       ioprio_pri_(0),
       priority_(0),
@@ -438,7 +440,8 @@
 
 bool Service::ParseOnrestart(const std::vector<std::string>& args, std::string* err) {
     std::vector<std::string> str_args(args.begin() + 1, args.end());
-    onrestart_.AddCommand(str_args, "", 0, err);
+    int line = onrestart_.NumCommands() + 1;
+    onrestart_.AddCommand(str_args, line, err);
     return true;
 }
 
@@ -1092,8 +1095,8 @@
     }
 }
 
-bool ServiceParser::ParseSection(const std::vector<std::string>& args,
-                                 std::string* err) {
+bool ServiceParser::ParseSection(const std::vector<std::string>& args, const std::string& filename,
+                                 int line, std::string* err) {
     if (args.size() < 3) {
         *err = "services must have a name and a program";
         return false;
@@ -1110,9 +1113,8 @@
     return true;
 }
 
-bool ServiceParser::ParseLineSection(const std::vector<std::string>& args,
-                                     const std::string& filename, int line,
-                                     std::string* err) const {
+bool ServiceParser::ParseLineSection(const std::vector<std::string>& args, int line,
+                                     std::string* err) {
     return service_ ? service_->ParseLine(args, err) : false;
 }
 
diff --git a/init/service.h b/init/service.h
index 5e89b9f..6fe0258 100644
--- a/init/service.h
+++ b/init/service.h
@@ -212,18 +212,15 @@
 };
 
 class ServiceParser : public SectionParser {
-public:
-    ServiceParser() : service_(nullptr) {
-    }
-    bool ParseSection(const std::vector<std::string>& args,
+  public:
+    ServiceParser() : service_(nullptr) {}
+    bool ParseSection(const std::vector<std::string>& args, const std::string& filename, int line,
                       std::string* err) override;
-    bool ParseLineSection(const std::vector<std::string>& args,
-                          const std::string& filename, int line,
-                          std::string* err) const override;
+    bool ParseLineSection(const std::vector<std::string>& args, int line, std::string* err) override;
     void EndSection() override;
-    void EndFile(const std::string&) override {
-    }
-private:
+    void EndFile(const std::string&) override {}
+
+  private:
     bool IsValidName(const std::string& name) const;
 
     std::unique_ptr<Service> service_;
diff --git a/libcutils/include/cutils/multiuser.h b/libcutils/include/cutils/multiuser.h
index 5bd9c7b..9a2305c 100644
--- a/libcutils/include/cutils/multiuser.h
+++ b/libcutils/include/cutils/multiuser.h
@@ -33,6 +33,7 @@
 
 extern gid_t multiuser_get_cache_gid(userid_t user_id, appid_t app_id);
 extern gid_t multiuser_get_ext_gid(userid_t user_id, appid_t app_id);
+extern gid_t multiuser_get_ext_cache_gid(userid_t user_id, appid_t app_id);
 extern gid_t multiuser_get_shared_gid(userid_t user_id, appid_t app_id);
 
 /* TODO: switch callers over to multiuser_get_shared_gid() */
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index 0037f15..bbba853 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -171,6 +171,9 @@
 #define AID_EXT_GID_START 30000 /* start of gids for apps to mark external data */
 #define AID_EXT_GID_END 39999   /* end of gids for apps to mark external data */
 
+#define AID_EXT_CACHE_GID_START 40000 /* start of gids for apps to mark external cached data */
+#define AID_EXT_CACHE_GID_END 49999   /* end of gids for apps to mark external cached data */
+
 #define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */
 #define AID_SHARED_GID_END 59999   /* end of gids for apps in each user to share */
 
diff --git a/libcutils/multiuser.c b/libcutils/multiuser.c
index 08d4d6c..61403f4 100644
--- a/libcutils/multiuser.c
+++ b/libcutils/multiuser.c
@@ -45,6 +45,14 @@
     }
 }
 
+gid_t multiuser_get_ext_cache_gid(userid_t user_id, appid_t app_id) {
+    if (app_id >= AID_APP_START && app_id <= AID_APP_END) {
+        return multiuser_get_uid(user_id, (app_id - AID_APP_START) + AID_EXT_CACHE_GID_START);
+    } else {
+        return -1;
+    }
+}
+
 gid_t multiuser_get_shared_gid(userid_t user_id, appid_t app_id) {
     if (app_id >= AID_APP_START && app_id <= AID_APP_END) {
         return multiuser_get_uid(user_id, (app_id - AID_APP_START) + AID_SHARED_GID_START);
diff --git a/libcutils/tests/multiuser_test.cpp b/libcutils/tests/multiuser_test.cpp
index ae5c416..2f9d854 100644
--- a/libcutils/tests/multiuser_test.cpp
+++ b/libcutils/tests/multiuser_test.cpp
@@ -68,6 +68,14 @@
     EXPECT_EQ(1030000U, multiuser_get_ext_gid(10, 10000));
 }
 
+TEST(MultiuserTest, TestExtCache) {
+    EXPECT_EQ(ERR_GID, multiuser_get_ext_cache_gid(0, 0));
+    EXPECT_EQ(ERR_GID, multiuser_get_ext_cache_gid(0, 1000));
+    EXPECT_EQ(40000U, multiuser_get_ext_cache_gid(0, 10000));
+    EXPECT_EQ(ERR_GID, multiuser_get_ext_cache_gid(0, 50000));
+    EXPECT_EQ(1040000U, multiuser_get_ext_cache_gid(10, 10000));
+}
+
 TEST(MultiuserTest, TestShared) {
     EXPECT_EQ(ERR_GID, multiuser_get_shared_gid(0, 0));
     EXPECT_EQ(ERR_GID, multiuser_get_shared_gid(0, 1000));
diff --git a/liblog/include/log/log_time.h b/liblog/include/log/log_time.h
index 9ece0b3..3764faf 100644
--- a/liblog/include/log/log_time.h
+++ b/liblog/include/log/log_time.h
@@ -22,6 +22,8 @@
 
 /* struct log_time is a wire-format variant of struct timespec */
 #define NS_PER_SEC 1000000000ULL
+#define US_PER_SEC 1000000ULL
+#define MS_PER_SEC 1000ULL
 
 #ifndef __struct_log_time_defined
 #define __struct_log_time_defined
@@ -148,6 +150,14 @@
   uint64_t nsec() const {
     return static_cast<uint64_t>(tv_sec) * NS_PER_SEC + tv_nsec;
   }
+  uint64_t usec() const {
+    return static_cast<uint64_t>(tv_sec) * US_PER_SEC +
+           tv_nsec / (NS_PER_SEC / US_PER_SEC);
+  }
+  uint64_t msec() const {
+    return static_cast<uint64_t>(tv_sec) * MS_PER_SEC +
+           tv_nsec / (NS_PER_SEC / MS_PER_SEC);
+  }
 
 #ifdef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_LOGGER_H_
   static const char default_format[];
diff --git a/liblog/properties.c b/liblog/properties.c
index c71cbcf..11be827 100644
--- a/liblog/properties.c
+++ b/liblog/properties.c
@@ -459,6 +459,9 @@
   if (check_flag(property.property, "false")) {
     return false;
   }
+  if (property.property[0]) {
+    flag &= ~(BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE);
+  }
   if (check_flag(property.property, "eng")) {
     flag |= BOOL_DEFAULT_FLAG_ENG;
   }
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
new file mode 100644
index 0000000..37e4dbf
--- /dev/null
+++ b/libprocessgroup/Android.bp
@@ -0,0 +1,10 @@
+cc_library {
+    srcs: ["processgroup.cpp"],
+    name: "libprocessgroup",
+    shared_libs: ["libbase"],
+    export_include_dirs: ["include"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+}
diff --git a/libprocessgroup/Android.mk b/libprocessgroup/Android.mk
deleted file mode 100644
index 0bfc391..0000000
--- a/libprocessgroup/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := processgroup.cpp
-LOCAL_MODULE := libprocessgroup
-LOCAL_STATIC_LIBRARIES := libbase
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_CFLAGS := -Wall -Werror
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := processgroup.cpp
-LOCAL_MODULE := libprocessgroup
-LOCAL_SHARED_LIBRARIES := libbase
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_CFLAGS := -Wall -Werror
-include $(BUILD_SHARED_LIBRARY)
diff --git a/libsparse/Android.bp b/libsparse/Android.bp
index dd8b5fd..6ec0991 100644
--- a/libsparse/Android.bp
+++ b/libsparse/Android.bp
@@ -10,17 +10,23 @@
         "sparse.c",
         "sparse_crc32.c",
         "sparse_err.c",
-        "sparse_read.c",
+        "sparse_read.cpp",
     ],
     cflags: ["-Werror"],
     local_include_dirs: ["include"],
     export_include_dirs: ["include"],
     target: {
         host: {
-            shared_libs: ["libz-host"],
+            shared_libs: [
+                "libz-host",
+                "libbase",
+            ],
         },
         android: {
-            shared_libs: ["libz"],
+            shared_libs: [
+                "libz",
+                "libbase",
+            ],
         },
         windows: {
             enabled: true,
@@ -38,6 +44,7 @@
     static_libs: [
         "libsparse",
         "libz",
+        "libbase",
     ],
 
     cflags: ["-Werror"],
@@ -50,6 +57,7 @@
     static_libs: [
         "libsparse",
         "libz",
+        "libbase",
     ],
 
     cflags: ["-Werror"],
@@ -61,6 +69,7 @@
     static_libs: [
         "libsparse",
         "libz",
+        "libbase",
     ],
 
     cflags: ["-Werror"],
diff --git a/libsparse/output_file.c b/libsparse/output_file.c
index 2115998..51e60ef 100644
--- a/libsparse/output_file.c
+++ b/libsparse/output_file.c
@@ -584,7 +584,7 @@
 				.file_hdr_sz = SPARSE_HEADER_LEN,
 				.chunk_hdr_sz = CHUNK_HEADER_LEN,
 				.blk_sz = out->block_size,
-				.total_blks = out->len / out->block_size,
+				.total_blks = DIV_ROUND_UP(out->len, out->block_size),
 				.total_chunks = chunks,
 				.image_checksum = 0
 		};
diff --git a/libsparse/output_file.h b/libsparse/output_file.h
index 474c1fc..b67e94e 100644
--- a/libsparse/output_file.h
+++ b/libsparse/output_file.h
@@ -17,6 +17,10 @@
 #ifndef _OUTPUT_FILE_H_
 #define _OUTPUT_FILE_H_
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include <sparse/sparse.h>
 
 struct output_file;
@@ -38,4 +42,8 @@
 
 int read_all(int fd, void *buf, size_t len);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
diff --git a/libsparse/sparse_file.h b/libsparse/sparse_file.h
index 91a12e6..763f43f 100644
--- a/libsparse/sparse_file.h
+++ b/libsparse/sparse_file.h
@@ -17,6 +17,10 @@
 #ifndef _LIBSPARSE_SPARSE_FILE_H_
 #define _LIBSPARSE_SPARSE_FILE_H_
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include <sparse/sparse.h>
 
 struct sparse_file {
@@ -28,5 +32,8 @@
 	struct output_file *out;
 };
 
+#ifdef __cplusplus
+}
+#endif
 
 #endif /* _LIBSPARSE_SPARSE_FILE_H_ */
diff --git a/libsparse/sparse_format.h b/libsparse/sparse_format.h
index c41f12a..779e038 100644
--- a/libsparse/sparse_format.h
+++ b/libsparse/sparse_format.h
@@ -18,6 +18,10 @@
 #define _LIBSPARSE_SPARSE_FORMAT_H_
 #include "sparse_defs.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef struct sparse_header {
   __le32	magic;		/* 0xed26ff3a */
   __le16	major_version;	/* (0x1) - reject images with higher major versions */
@@ -52,4 +56,8 @@
  *  For a CRC32 chunk, it's 4 bytes of CRC32
  */
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
diff --git a/libsparse/sparse_read.c b/libsparse/sparse_read.cpp
similarity index 88%
rename from libsparse/sparse_read.c
rename to libsparse/sparse_read.cpp
index a188202..bd66873 100644
--- a/libsparse/sparse_read.c
+++ b/libsparse/sparse_read.cpp
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-#define _GNU_SOURCE
 #define _FILE_OFFSET_BITS 64
 #define _LARGEFILE64_SOURCE 1
 
+#include <algorithm>
 #include <inttypes.h>
 #include <fcntl.h>
 #include <stdarg.h>
@@ -25,17 +25,19 @@
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
+#include <string>
 #include <unistd.h>
 
 #include <sparse/sparse.h>
 
+#include "android-base/stringprintf.h"
 #include "defs.h"
 #include "output_file.h"
 #include "sparse_crc32.h"
 #include "sparse_file.h"
 #include "sparse_format.h"
 
+
 #if defined(__APPLE__) && defined(__MACH__)
 #define lseek64 lseek
 #define off64_t off_t
@@ -45,57 +47,30 @@
 #define SPARSE_HEADER_LEN       (sizeof(sparse_header_t))
 #define CHUNK_HEADER_LEN (sizeof(chunk_header_t))
 
-#define COPY_BUF_SIZE (1024U*1024U)
+static constexpr int64_t COPY_BUF_SIZE = 1024 * 1024;
 static char *copybuf;
 
-#define min(a, b) \
-	({ typeof(a) _a = (a); typeof(b) _b = (b); (_a < _b) ? _a : _b; })
+static std::string ErrorString(int err)
+{
+	if (err == -EOVERFLOW) return "EOF while reading file";
+	if (err == -EINVAL) return "Invalid sparse file format";
+	if (err == -ENOMEM) return "Failed allocation while reading file";
+	return android::base::StringPrintf("Unknown error %d", err);
+}
 
 static void verbose_error(bool verbose, int err, const char *fmt, ...)
 {
-	char *s = "";
-	char *at = "";
+	if (!verbose) return;
+
+	std::string msg = ErrorString(err);
 	if (fmt) {
+		msg += " at ";
 		va_list argp;
-		int size;
-
 		va_start(argp, fmt);
-		size = vsnprintf(NULL, 0, fmt, argp);
+		android::base::StringAppendV(&msg, fmt, argp);
 		va_end(argp);
-
-		if (size < 0) {
-			return;
-		}
-
-		at = malloc(size + 1);
-		if (at == NULL) {
-			return;
-		}
-
-		va_start(argp, fmt);
-		vsnprintf(at, size, fmt, argp);
-		va_end(argp);
-		at[size] = 0;
-		s = " at ";
 	}
-	if (verbose) {
-#ifndef _WIN32
-		if (err == -EOVERFLOW) {
-			sparse_print_verbose("EOF while reading file%s%s\n", s, at);
-		} else
-#endif
-		if (err == -EINVAL) {
-			sparse_print_verbose("Invalid sparse file format%s%s\n", s, at);
-		} else if (err == -ENOMEM) {
-			sparse_print_verbose("Failed allocation while reading file%s%s\n",
-					s, at);
-		} else {
-			sparse_print_verbose("Unknown error %d%s%s\n", err, s, at);
-		}
-	}
-	if (fmt) {
-		free(at);
-	}
+	sparse_print_verbose("%s\n", msg.c_str());
 }
 
 static int process_raw_chunk(struct sparse_file *s, unsigned int chunk_size,
@@ -104,7 +79,7 @@
 {
 	int ret;
 	int chunk;
-	unsigned int len = blocks * s->block_size;
+	int64_t len = blocks * s->block_size;
 
 	if (chunk_size % s->block_size != 0) {
 		return -EINVAL;
@@ -121,7 +96,7 @@
 
 	if (crc32) {
 		while (len) {
-			chunk = min(len, COPY_BUF_SIZE);
+			chunk = std::min(len, COPY_BUF_SIZE);
 			ret = read_all(fd, copybuf, chunk);
 			if (ret < 0) {
 				return ret;
@@ -168,7 +143,7 @@
 		}
 
 		while (len) {
-			chunk = min(len, COPY_BUF_SIZE);
+			chunk = std::min(len, COPY_BUF_SIZE);
 			*crc32 = sparse_crc32(*crc32, copybuf, chunk);
 			len -= chunk;
 		}
@@ -190,7 +165,7 @@
 		memset(copybuf, 0, COPY_BUF_SIZE);
 
 		while (len) {
-			int chunk = min(len, COPY_BUF_SIZE);
+			int chunk = std::min(len, COPY_BUF_SIZE);
 			*crc32 = sparse_crc32(*crc32, copybuf, chunk);
 			len -= chunk;
 		}
@@ -284,7 +259,7 @@
 	off64_t offset;
 
 	if (!copybuf) {
-		copybuf = malloc(COPY_BUF_SIZE);
+		copybuf = (char *)malloc(COPY_BUF_SIZE);
 	}
 
 	if (!copybuf) {
@@ -357,7 +332,7 @@
 static int sparse_file_read_normal(struct sparse_file *s, int fd)
 {
 	int ret;
-	uint32_t *buf = malloc(s->block_size);
+	uint32_t *buf = (uint32_t *)malloc(s->block_size);
 	unsigned int block = 0;
 	int64_t remain = s->len;
 	int64_t offset = 0;
@@ -370,7 +345,7 @@
 	}
 
 	while (remain > 0) {
-		to_read = min(remain, s->block_size);
+		to_read = std::min(remain, (int64_t)(s->block_size));
 		ret = read_all(fd, buf, to_read);
 		if (ret < 0) {
 			error("failed to read sparse file");
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index a6bea0c..ed46181 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -208,8 +208,7 @@
         if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
             // Log traffic received to total
             pthread_mutex_lock(&mLogElementsLock);
-            stats.add(elem);
-            stats.subtract(elem);
+            stats.addTotal(elem);
             pthread_mutex_unlock(&mLogElementsLock);
             delete elem;
             return -EACCES;
@@ -320,8 +319,7 @@
                         pthread_mutex_unlock(&mLogElementsLock);
                         return len;
                     }
-                    stats.add(currentLast);
-                    stats.subtract(currentLast);
+                    stats.addTotal(currentLast);
                     delete currentLast;
                     swab = total;
                     event->payload.data = htole32(swab);
@@ -337,8 +335,7 @@
                 }
             }
             if (count) {
-                stats.add(currentLast);
-                stats.subtract(currentLast);
+                stats.addTotal(currentLast);
                 currentLast->setDropped(count);
             }
             droppedElements[log_id] = currentLast;
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index af19279..feb105f 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <ctype.h>
+#include <inttypes.h>
 #include <poll.h>
 #include <sys/prctl.h>
 #include <sys/socket.h>
@@ -192,6 +193,12 @@
         }
     }
 
+    android::prdebug(
+        "logdr: UID=%d GID=%d PID=%d %c tail=%lu logMask=%x pid=%d "
+        "start=%" PRIu64 "ns timeout=%" PRIu64 "ns\n",
+        cli->getUid(), cli->getGid(), cli->getPid(), nonBlock ? 'n' : 'b', tail,
+        logMask, (int)pid, sequence.nsec(), timeout);
+
     FlushCommand command(*this, nonBlock, tail, logMask, pid, sequence, timeout);
 
     // Set acceptable upper limit to wait for slow reader processing b/27242723
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index d3167ad..b41aca5 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <fcntl.h>
+#include <inttypes.h>
 #include <pwd.h>
 #include <stdio.h>
 #include <string.h>
@@ -70,20 +71,30 @@
 }
 }
 
+void LogStatistics::addTotal(LogBufferElement* element) {
+    if (element->getDropped()) return;
+
+    log_id_t log_id = element->getLogId();
+    unsigned short size = element->getMsgLen();
+    mSizesTotal[log_id] += size;
+    SizesTotal += size;
+    ++mElementsTotal[log_id];
+}
+
 void LogStatistics::add(LogBufferElement* element) {
     log_id_t log_id = element->getLogId();
     unsigned short size = element->getMsgLen();
     mSizes[log_id] += size;
     ++mElements[log_id];
 
+    // When caller adding a chatty entry, they will have already
+    // called add() and subtract() for each entry as they are
+    // evaluated and trimmed, thus recording size and number of
+    // elements, but we must recognize the manufactured dropped
+    // entry as not contributing to the lifetime totals.
     if (element->getDropped()) {
         ++mDroppedElements[log_id];
     } else {
-        // When caller adding a chatty entry, they will have already
-        // called add() and subtract() for each entry as they are
-        // evaluated and trimmed, thus recording size and number of
-        // elements, but we must recognize the manufactured dropped
-        // entry as not contributing to the lifetime totals.
         mSizesTotal[log_id] += size;
         SizesTotal += size;
         ++mElementsTotal[log_id];
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 066b7de..e171e4a 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -576,6 +576,7 @@
         enable = true;
     }
 
+    void addTotal(LogBufferElement* entry);
     void add(LogBufferElement* entry);
     void subtract(LogBufferElement* entry);
     // entry->setDropped(1) must follow this call
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 56e736e..a94a717 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -245,10 +245,6 @@
     class_stop charger
     trigger late-init
 
-# Load properties from /system/ + /factory after fs mount.
-on load_system_props_action
-    load_system_props
-
 on load_persist_props_action
     load_persist_props
     start logd
@@ -269,11 +265,6 @@
     trigger fs
     trigger post-fs
 
-    # Load properties from /system/ + /factory after fs mount. Place
-    # this in another action so that the load will be scheduled after the prior
-    # issued fs triggers have completed.
-    trigger load_system_props_action
-
     # Mount fstab in init.{$device}.rc by mount_all with '--late' parameter
     # to only mount entries with 'latemount'. This is needed if '--early' is
     # specified in the previous mount_all command on the fs stage.
@@ -298,6 +289,13 @@
     trigger boot
 
 on post-fs
+    # Load properties from
+    #     /system/build.prop,
+    #     /odm/build.prop,
+    #     /vendor/build.prop and
+    #     /factory/factory.prop
+    load_system_props
+    # start essential services
     start logd
     start hwservicemanager