Merge changes Iec369a50,I78959464,I3f9f8d56 into oc-dev

* changes:
  logd: instrument tests better for failure
  logd: iterator corruption paranoia
  liblog: log_time add explicit to some constructors.
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/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp
index 7c82bb1..83bf8a7 100644
--- a/fs_mgr/fs_mgr_avb.cpp
+++ b/fs_mgr/fs_mgr_avb.cpp
@@ -493,6 +493,10 @@
         return nullptr;
     }
 
+    // Sets the MAJOR.MINOR for init to set it into "ro.boot.avb_version".
+    avb_handle->avb_version_ =
+        android::base::StringPrintf("%d.%d", AVB_VERSION_MAJOR, AVB_VERSION_MINOR);
+
     // Verifies vbmeta images against the digest passed from bootloader.
     if (!avb_verifier->VerifyVbmetaImages(*avb_handle->avb_slot_data_)) {
         LERROR << "VerifyVbmetaImages failed";
diff --git a/fs_mgr/include/fs_mgr_avb.h b/fs_mgr/include/fs_mgr_avb.h
index 526a5ce..a66ff42 100644
--- a/fs_mgr/include/fs_mgr_avb.h
+++ b/fs_mgr/include/fs_mgr_avb.h
@@ -72,7 +72,8 @@
     // Otherwise, returns false.
     bool SetUpAvb(fstab_rec* fstab_entry, bool wait_for_verity_dev);
 
-    bool AvbHashtreeDisabled() { return status_ == kFsManagerAvbHandleHashtreeDisabled; }
+    bool hashtree_disabled() const { return status_ == kFsManagerAvbHandleHashtreeDisabled; }
+    const std::string& avb_version() const { return avb_version_; }
 
     FsManagerAvbHandle(const FsManagerAvbHandle&) = delete;             // no copy
     FsManagerAvbHandle& operator=(const FsManagerAvbHandle&) = delete;  // no assignment
@@ -92,6 +93,7 @@
   private:
     AvbSlotVerifyData* avb_slot_data_;
     FsManagerAvbHandleStatus status_;
+    std::string avb_version_;
 };
 
 #endif /* __CORE_FS_MGR_AVB_H */
diff --git a/init/README.md b/init/README.md
index 822d81e..8cb1e52 100644
--- a/init/README.md
+++ b/init/README.md
@@ -293,6 +293,11 @@
 `copy <src> <dst>`
 > Copies a file. Similar to write, but useful for binary/large
   amounts of data.
+  Regarding to the src file, copying from symbolic link file and world-writable
+  or group-writable files are not allowed.
+  Regarding to the dst file, the default mode created is 0600 if it does not
+  exist. And it will be truncated if dst file is a normal regular file and
+  already exists.
 
 `domainname <name>`
 > Set the domain name.
@@ -365,10 +370,6 @@
   _options_ include "barrier=1", "noauto\_da\_alloc", "discard", ... as
   a comma separated string, eg: barrier=1,noauto\_da\_alloc
 
-`powerctl`
-> Internal implementation detail used to respond to changes to the
-  "sys.powerctl" system property, used to implement rebooting.
-
 `restart <service>`
 > Stops and restarts a running service, does nothing if the service is currently
   restarting, otherwise, it just starts the service.
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 2be70bf..7ee02d0 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -155,7 +155,7 @@
 }
 
 static int do_domainname(const std::vector<std::string>& args) {
-    return write_file("/proc/sys/kernel/domainname", args[1].c_str()) ? 0 : 1;
+    return write_file("/proc/sys/kernel/domainname", args[1]) ? 0 : 1;
 }
 
 static int do_enable(const std::vector<std::string>& args) {
@@ -179,7 +179,7 @@
 }
 
 static int do_hostname(const std::vector<std::string>& args) {
-    return write_file("/proc/sys/kernel/hostname", args[1].c_str()) ? 0 : 1;
+    return write_file("/proc/sys/kernel/hostname", args[1]) ? 0 : 1;
 }
 
 static int do_ifup(const std::vector<std::string>& args) {
@@ -603,54 +603,6 @@
     return 0;
 }
 
-static int do_powerctl(const std::vector<std::string>& args) {
-    const std::string& command = args[1];
-    unsigned int cmd = 0;
-    std::vector<std::string> cmd_params = android::base::Split(command, ",");
-    std::string reason_string = cmd_params[0];
-    std::string reboot_target = "";
-    bool runFsck = false;
-    bool commandInvalid = false;
-
-    if (cmd_params.size() > 2) {
-        commandInvalid = true;
-    } else if (cmd_params[0] == "shutdown") {
-        cmd = ANDROID_RB_POWEROFF;
-        if (cmd_params.size() == 2 && cmd_params[1] == "userrequested") {
-            // The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED.
-            // Run fsck once the file system is remounted in read-only mode.
-            runFsck = true;
-            reason_string = cmd_params[1];
-        }
-    } else if (cmd_params[0] == "reboot") {
-        cmd = ANDROID_RB_RESTART2;
-        if (cmd_params.size() == 2) {
-            reboot_target = cmd_params[1];
-            // When rebooting to the bootloader notify the bootloader writing
-            // also the BCB.
-            if (reboot_target == "bootloader") {
-                std::string err;
-                if (!write_reboot_bootloader(&err)) {
-                    LOG(ERROR) << "reboot-bootloader: Error writing "
-                                  "bootloader_message: "
-                               << err;
-                }
-            }
-        }
-    } else if (command == "thermal-shutdown") {  // no additional parameter allowed
-        cmd = ANDROID_RB_THERMOFF;
-    } else {
-        commandInvalid = true;
-    }
-    if (commandInvalid) {
-        LOG(ERROR) << "powerctl: unrecognized command '" << command << "'";
-        return -EINVAL;
-    }
-
-    DoReboot(cmd, reason_string, reboot_target, runFsck);
-    return 0;
-}
-
 static int do_trigger(const std::vector<std::string>& args) {
     ActionManager::GetInstance().QueueEventTrigger(args[1]);
     return 0;
@@ -696,57 +648,15 @@
 }
 
 static int do_write(const std::vector<std::string>& args) {
-    const char* path = args[1].c_str();
-    const char* value = args[2].c_str();
-    return write_file(path, value) ? 0 : 1;
+    return write_file(args[1], args[2]) ? 0 : 1;
 }
 
 static int do_copy(const std::vector<std::string>& args) {
-    char* buffer = NULL;
-    int rc = 0;
-    int fd1 = -1, fd2 = -1;
-    struct stat info;
-    int brtw, brtr;
-    char* p;
-
-    if (stat(args[1].c_str(), &info) < 0) return -1;
-
-    if ((fd1 = open(args[1].c_str(), O_RDONLY | O_CLOEXEC)) < 0) goto out_err;
-
-    if ((fd2 = open(args[2].c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0660)) < 0)
-        goto out_err;
-
-    if (!(buffer = (char*)malloc(info.st_size))) goto out_err;
-
-    p = buffer;
-    brtr = info.st_size;
-    while (brtr) {
-        rc = read(fd1, p, brtr);
-        if (rc < 0) goto out_err;
-        if (rc == 0) break;
-        p += rc;
-        brtr -= rc;
+    std::string data;
+    if (read_file(args[1], &data)) {
+        return write_file(args[2], data) ? 0 : 1;
     }
-
-    p = buffer;
-    brtw = info.st_size;
-    while (brtw) {
-        rc = write(fd2, p, brtw);
-        if (rc < 0) goto out_err;
-        if (rc == 0) break;
-        p += rc;
-        brtw -= rc;
-    }
-
-    rc = 0;
-    goto out;
-out_err:
-    rc = -1;
-out:
-    if (buffer) free(buffer);
-    if (fd1 >= 0) close(fd1);
-    if (fd2 >= 0) close(fd2);
-    return rc;
+    return 1;
 }
 
 static int do_chown(const std::vector<std::string>& args) {
@@ -962,7 +872,6 @@
         {"mount_all",               {1,     kMax, do_mount_all}},
         {"mount",                   {3,     kMax, do_mount}},
         {"umount",                  {1,     1,    do_umount}},
-        {"powerctl",                {1,     1,    do_powerctl}},
         {"restart",                 {1,     1,    do_restart}},
         {"restorecon",              {1,     kMax, do_restorecon}},
         {"restorecon_recursive",    {1,     kMax, do_restorecon_recursive}},
diff --git a/init/init.cpp b/init/init.cpp
index b05311a..a75ced5 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -64,6 +64,7 @@
 #include "keychords.h"
 #include "log.h"
 #include "property_service.h"
+#include "reboot.h"
 #include "service.h"
 #include "signal_handler.h"
 #include "ueventd.h"
@@ -149,8 +150,13 @@
     return true;
 }
 
-void property_changed(const char *name, const char *value)
-{
+void property_changed(const std::string& name, const std::string& value) {
+    // If the property is sys.powerctl, we bypass the event queue and immediately handle it.
+    // This is to ensure that init will always and immediately shutdown/reboot, regardless of
+    // if there are other pending events to process or if init is waiting on an exec service or
+    // waiting on a property.
+    if (name == "sys.powerctl") HandlePowerctlMessage(value);
+
     if (property_triggers_enabled)
         ActionManager::GetInstance().QueuePropertyTrigger(name, value);
     if (waiting_for_prop) {
@@ -1034,10 +1040,11 @@
         return false;
     }
 
+    setenv("INIT_AVB_VERSION", avb_handle->avb_version().c_str(), 1);
     for (auto rec : fstab_recs) {
         bool need_create_dm_device = false;
         if (fs_mgr_is_avb(rec)) {
-            if (avb_handle->AvbHashtreeDisabled()) {
+            if (avb_handle->hashtree_disabled()) {
                 LOG(INFO) << "avb hashtree disabled for '" << rec->mount_point << "'";
             } else if (avb_handle->SetUpAvb(rec, false /* wait_for_verity_dev */)) {
                 need_create_dm_device = true;
@@ -1384,12 +1391,14 @@
     property_set("ro.boottime.init.selinux", getenv("INIT_SELINUX_TOOK"));
 
     // Set libavb version for Framework-only OTA match in Treble build.
-    property_set("ro.boot.init.avb_version", std::to_string(AVB_MAJOR_VERSION).c_str());
+    const char* avb_version = getenv("INIT_AVB_VERSION");
+    if (avb_version) property_set("ro.boot.avb_version", avb_version);
 
     // Clean up our environment.
     unsetenv("INIT_SECOND_STAGE");
     unsetenv("INIT_STARTED_AT");
     unsetenv("INIT_SELINUX_TOOK");
+    unsetenv("INIT_AVB_VERSION");
 
     // Now set up SELinux for second stage.
     selinux_initialize(false);
diff --git a/init/init.h b/init/init.h
index fe850ef..1da3350 100644
--- a/init/init.h
+++ b/init/init.h
@@ -26,7 +26,7 @@
 
 void handle_control_message(const std::string& msg, const std::string& arg);
 
-void property_changed(const char *name, const char *value);
+void property_changed(const std::string& name, const std::string& value);
 
 void register_epoll_handler(int fd, void (*fn)());
 
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index 326ebf2..a192862 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -96,7 +96,7 @@
     LOG(INFO) << "Parsing file " << path << "...";
     Timer t;
     std::string data;
-    if (!read_file(path.c_str(), &data)) {
+    if (!read_file(path, &data)) {
         return false;
     }
 
diff --git a/init/property_service.cpp b/init/property_service.cpp
index a4d8b5f..a44df42 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -206,7 +206,7 @@
     if (persistent_properties_loaded && android::base::StartsWith(name, "persist.")) {
         write_persistent_property(name.c_str(), value.c_str());
     }
-    property_changed(name.c_str(), value.c_str());
+    property_changed(name, value);
     return PROP_SUCCESS;
 }
 
diff --git a/init/reboot.cpp b/init/reboot.cpp
index e887677..e234f96 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -425,3 +425,54 @@
     RebootSystem(cmd, rebootTarget);
     abort();
 }
+
+bool HandlePowerctlMessage(const std::string& command) {
+    unsigned int cmd = 0;
+    std::vector<std::string> cmd_params = android::base::Split(command, ",");
+    std::string reason_string = cmd_params[0];
+    std::string reboot_target = "";
+    bool run_fsck = false;
+    bool command_invalid = false;
+
+    if (cmd_params.size() > 3) {
+        command_invalid = true;
+    } else if (cmd_params[0] == "shutdown") {
+        cmd = ANDROID_RB_POWEROFF;
+        if (cmd_params.size() == 2 && cmd_params[1] == "userrequested") {
+            // The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED.
+            // Run fsck once the file system is remounted in read-only mode.
+            run_fsck = true;
+            reason_string = cmd_params[1];
+        }
+    } else if (cmd_params[0] == "reboot") {
+        cmd = ANDROID_RB_RESTART2;
+        if (cmd_params.size() >= 2) {
+            reboot_target = cmd_params[1];
+            // When rebooting to the bootloader notify the bootloader writing
+            // also the BCB.
+            if (reboot_target == "bootloader") {
+                std::string err;
+                if (!write_reboot_bootloader(&err)) {
+                    LOG(ERROR) << "reboot-bootloader: Error writing "
+                                  "bootloader_message: "
+                               << err;
+                }
+            }
+            // If there is an additional bootloader parameter, pass it along
+            if (cmd_params.size() == 3) {
+                reboot_target += "," + cmd_params[2];
+            }
+        }
+    } else if (command == "thermal-shutdown") {  // no additional parameter allowed
+        cmd = ANDROID_RB_THERMOFF;
+    } else {
+        command_invalid = true;
+    }
+    if (command_invalid) {
+        LOG(ERROR) << "powerctl: unrecognized command '" << command << "'";
+        return false;
+    }
+
+    DoReboot(cmd, reason_string, reboot_target, run_fsck);
+    return true;
+}
diff --git a/init/reboot.h b/init/reboot.h
index 3956249..cd6be39 100644
--- a/init/reboot.h
+++ b/init/reboot.h
@@ -27,4 +27,7 @@
 void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget,
               bool runFsck) __attribute__((__noreturn__));
 
+// Parses and handles a setprop sys.powerctl message.
+bool HandlePowerctlMessage(const std::string& command);
+
 #endif
diff --git a/init/util.cpp b/init/util.cpp
index 73d97ed..895e78a 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -161,10 +161,11 @@
     return -1;
 }
 
-bool read_file(const char* path, std::string* content) {
+bool read_file(const std::string& path, std::string* content) {
     content->clear();
 
-    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
+    android::base::unique_fd fd(
+        TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
     if (fd == -1) {
         return false;
     }
@@ -184,9 +185,9 @@
     return android::base::ReadFdToString(fd, content);
 }
 
-bool write_file(const char* path, const char* content) {
-    android::base::unique_fd fd(
-        TEMP_FAILURE_RETRY(open(path, O_WRONLY | O_CREAT | O_NOFOLLOW | O_CLOEXEC, 0600)));
+bool write_file(const std::string& path, const std::string& content) {
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(
+        open(path.c_str(), O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC | O_CLOEXEC, 0600)));
     if (fd == -1) {
         PLOG(ERROR) << "write_file: Unable to open '" << path << "'";
         return false;
diff --git a/init/util.h b/init/util.h
index 81c64d7..90ec6bb 100644
--- a/init/util.h
+++ b/init/util.h
@@ -32,8 +32,8 @@
 int create_socket(const char *name, int type, mode_t perm,
                   uid_t uid, gid_t gid, const char *socketcon);
 
-bool read_file(const char* path, std::string* content);
-bool write_file(const char* path, const char* content);
+bool read_file(const std::string& path, std::string* content);
+bool write_file(const std::string& path, const std::string& content);
 
 // A std::chrono clock based on CLOCK_BOOTTIME.
 class boot_clock {
diff --git a/init/util_test.cpp b/init/util_test.cpp
index 24c75c4..0c0350a 100644
--- a/init/util_test.cpp
+++ b/init/util_test.cpp
@@ -17,7 +17,11 @@
 #include "util.h"
 
 #include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
 
+#include <android-base/stringprintf.h>
+#include <android-base/test_utils.h>
 #include <gtest/gtest.h>
 
 TEST(util, read_file_ENOENT) {
@@ -28,6 +32,35 @@
   EXPECT_EQ("", s); // s was cleared.
 }
 
+TEST(util, read_file_group_writeable) {
+    std::string s("hello");
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    EXPECT_TRUE(write_file(tf.path, s)) << strerror(errno);
+    EXPECT_NE(-1, fchmodat(AT_FDCWD, tf.path, 0620, AT_SYMLINK_NOFOLLOW)) << strerror(errno);
+    EXPECT_FALSE(read_file(tf.path, &s)) << strerror(errno);
+    EXPECT_EQ("", s);  // s was cleared.
+}
+
+TEST(util, read_file_world_writeable) {
+    std::string s("hello");
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    EXPECT_TRUE(write_file(tf.path, s.c_str())) << strerror(errno);
+    EXPECT_NE(-1, fchmodat(AT_FDCWD, tf.path, 0602, AT_SYMLINK_NOFOLLOW)) << strerror(errno);
+    EXPECT_FALSE(read_file(tf.path, &s)) << strerror(errno);
+    EXPECT_EQ("", s);  // s was cleared.
+}
+
+TEST(util, read_file_symbolic_link) {
+    std::string s("hello");
+    errno = 0;
+    // lrwxrwxrwx 1 root root 13 1970-01-01 00:00 charger -> /sbin/healthd
+    EXPECT_FALSE(read_file("/charger", &s));
+    EXPECT_EQ(ELOOP, errno);
+    EXPECT_EQ("", s);  // s was cleared.
+}
+
 TEST(util, read_file_success) {
   std::string s("hello");
   EXPECT_TRUE(read_file("/proc/version", &s));
@@ -37,6 +70,51 @@
   EXPECT_STREQ("Linux", s.c_str());
 }
 
+TEST(util, write_file_binary) {
+    std::string contents("abcd");
+    contents.push_back('\0');
+    contents.push_back('\0');
+    contents.append("dcba");
+    ASSERT_EQ(10u, contents.size());
+
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    EXPECT_TRUE(write_file(tf.path, contents)) << strerror(errno);
+
+    std::string read_back_contents;
+    EXPECT_TRUE(read_file(tf.path, &read_back_contents)) << strerror(errno);
+    EXPECT_EQ(contents, read_back_contents);
+    EXPECT_EQ(10u, read_back_contents.size());
+}
+
+TEST(util, write_file_not_exist) {
+    std::string s("hello");
+    std::string s2("hello");
+    TemporaryDir test_dir;
+    std::string path = android::base::StringPrintf("%s/does-not-exist", test_dir.path);
+    EXPECT_TRUE(write_file(path, s));
+    EXPECT_TRUE(read_file(path, &s2));
+    EXPECT_EQ(s, s2);
+    struct stat sb;
+    int fd = open(path.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
+    EXPECT_NE(-1, fd);
+    EXPECT_EQ(0, fstat(fd, &sb));
+    EXPECT_EQ((const unsigned int)(S_IRUSR | S_IWUSR), sb.st_mode & 0777);
+    EXPECT_EQ(0, unlink(path.c_str()));
+}
+
+TEST(util, write_file_exist) {
+    std::string s2("");
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    EXPECT_TRUE(write_file(tf.path, "1hello1")) << strerror(errno);
+    EXPECT_TRUE(read_file(tf.path, &s2));
+    EXPECT_STREQ("1hello1", s2.c_str());
+    EXPECT_TRUE(write_file(tf.path, "2ll2"));
+    EXPECT_TRUE(read_file(tf.path, &s2));
+    EXPECT_STREQ("2ll2", s2.c_str());
+}
+
 TEST(util, decode_uid) {
   EXPECT_EQ(0U, decode_uid("root"));
   EXPECT_EQ(UINT_MAX, decode_uid("toot"));
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/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/rootdir/init.rc b/rootdir/init.rc
index 15bbd32..fd82513 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -157,25 +157,25 @@
     # this ensures that the cpusets are present and usable, but the device's
     # init.rc must actually set the correct cpus
     mkdir /dev/cpuset/foreground
-    write /dev/cpuset/foreground/cpus 0
-    write /dev/cpuset/foreground/mems 0
+    copy /dev/cpuset/cpus /dev/cpuset/foreground/cpus
+    copy /dev/cpuset/mems /dev/cpuset/foreground/mems
     mkdir /dev/cpuset/foreground/boost
-    write /dev/cpuset/foreground/boost/cpus 0
-    write /dev/cpuset/foreground/boost/mems 0
+    copy /dev/cpuset/cpus /dev/cpuset/foreground/boost/cpus
+    copy /dev/cpuset/mems /dev/cpuset/foreground/boost/mems
     mkdir /dev/cpuset/background
-    write /dev/cpuset/background/cpus 0
-    write /dev/cpuset/background/mems 0
+    copy /dev/cpuset/cpus /dev/cpuset/background/cpus
+    copy /dev/cpuset/mems /dev/cpuset/background/mems
 
     # system-background is for system tasks that should only run on
     # little cores, not on bigs
     # to be used only by init, so don't change system-bg permissions
     mkdir /dev/cpuset/system-background
-    write /dev/cpuset/system-background/cpus 0
-    write /dev/cpuset/system-background/mems 0
+    copy /dev/cpuset/cpus /dev/cpuset/system-background/cpus
+    copy /dev/cpuset/mems /dev/cpuset/system-background/mems
 
     mkdir /dev/cpuset/top-app
-    write /dev/cpuset/top-app/cpus 0
-    write /dev/cpuset/top-app/mems 0
+    copy /dev/cpuset/cpus /dev/cpuset/top-app/cpus
+    copy /dev/cpuset/mems /dev/cpuset/top-app/mems
 
     # change permissions for all cpusets we'll touch at runtime
     chown system system /dev/cpuset
@@ -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 servicemanager
     start hwservicemanager
@@ -641,9 +639,6 @@
     class_reset late_start
     class_reset main
 
-on property:sys.powerctl=*
-    powerctl ${sys.powerctl}
-
 on property:sys.boot_completed=1
     bootchart stop