Merge "fs_mgr: change the log level in fs_mgr_get_boot_config()" into oc-dev
diff --git a/init/README.md b/init/README.md
index 024d559..0d8f495 100644
--- a/init/README.md
+++ b/init/README.md
@@ -311,6 +311,12 @@
   groups can be provided. No other commands will be run until this one
   finishes. _seclabel_ can be a - to denote default. Properties are expanded
   within _argument_.
+  Init halts executing commands until the forked process exits.
+
+`exec_start <service>`
+> Start service a given service and halt processing of additional init commands
+  until it returns.  It functions similarly to the `exec` command, but uses an
+  existing service definition instead of providing them as arguments.
 
 `export <name> <value>`
 > Set the environment variable _name_ equal to _value_ in the
diff --git a/init/action.cpp b/init/action.cpp
index 1bba0f2..2ccf0bc 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -18,14 +18,14 @@
 
 #include <errno.h>
 
-#include <android-base/strings.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 
 #include "builtins.h"
 #include "error.h"
 #include "init_parser.h"
 #include "log.h"
-#include "property_service.h"
 #include "util.h"
 
 using android::base::Join;
@@ -219,9 +219,8 @@
                 found = true;
             }
         } else {
-            std::string prop_val = property_get(trigger_name.c_str());
-            if (prop_val.empty() || (trigger_value != "*" &&
-                                     trigger_value != prop_val)) {
+            std::string prop_val = android::base::GetProperty(trigger_name, "");
+            if (prop_val.empty() || (trigger_value != "*" && trigger_value != prop_val)) {
                 return false;
             }
         }
diff --git a/init/bootchart.cpp b/init/bootchart.cpp
index 4a9c32e..beabea1 100644
--- a/init/bootchart.cpp
+++ b/init/bootchart.cpp
@@ -16,8 +16,6 @@
 
 #include "bootchart.h"
 
-#include "property_service.h"
-
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -39,6 +37,7 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 
 using android::base::StringPrintf;
@@ -72,7 +71,7 @@
   utsname uts;
   if (uname(&uts) == -1) return;
 
-  std::string fingerprint = property_get("ro.build.fingerprint");
+  std::string fingerprint = android::base::GetProperty("ro.build.fingerprint", "");
   if (fingerprint.empty()) return;
 
   std::string kernel_cmdline;
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 95f1aa0..02e314f 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -45,16 +45,16 @@
 #include <selinux/selinux.h>
 #include <selinux/label.h>
 
-#include <fs_mgr.h>
 #include <android-base/file.h>
 #include <android-base/parseint.h>
-#include <android-base/strings.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <bootloader_message/bootloader_message.h>
-#include <cutils/partition_utils.h>
 #include <cutils/android_reboot.h>
 #include <ext4_utils/ext4_crypt.h>
 #include <ext4_utils/ext4_crypt_init_extensions.h>
+#include <fs_mgr.h>
 #include <logwrap/logwrap.h>
 
 #include "action.h"
@@ -167,19 +167,11 @@
 }
 
 static int do_exec(const std::vector<std::string>& args) {
-    Service* svc = ServiceManager::GetInstance().MakeExecOneshotService(args);
-    if (!svc) {
-        return -1;
-    }
-    if (!start_waiting_for_exec()) {
-        return -1;
-    }
-    if (!svc->Start()) {
-        stop_waiting_for_exec();
-        ServiceManager::GetInstance().RemoveService(*svc);
-        return -1;
-    }
-    return 0;
+    return ServiceManager::GetInstance().Exec(args) ? 0 : -1;
+}
+
+static int do_exec_start(const std::vector<std::string>& args) {
+    return ServiceManager::GetInstance().ExecStart(args[1]) ? 0 : -1;
 }
 
 static int do_export(const std::vector<std::string>& args) {
@@ -880,8 +872,7 @@
 }
 
 static bool is_file_crypto() {
-    std::string value = property_get("ro.crypto.type");
-    return value == "file";
+    return android::base::GetProperty("ro.crypto.type", "") == "file";
 }
 
 static int do_installkey(const std::vector<std::string>& args) {
@@ -898,6 +889,7 @@
 
 BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
     constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
+    // clang-format off
     static const Map builtin_functions = {
         {"bootchart",               {1,     1,    do_bootchart}},
         {"chmod",                   {2,     2,    do_chmod}},
@@ -910,6 +902,7 @@
         {"domainname",              {1,     1,    do_domainname}},
         {"enable",                  {1,     1,    do_enable}},
         {"exec",                    {1,     kMax, do_exec}},
+        {"exec_start",              {1,     1,    do_exec_start}},
         {"export",                  {2,     2,    do_export}},
         {"hostname",                {1,     1,    do_hostname}},
         {"ifup",                    {1,     1,    do_ifup}},
@@ -943,5 +936,6 @@
         {"wait_for_prop",           {2,     2,    do_wait_for_prop}},
         {"write",                   {2,     2,    do_write}},
     };
+    // clang-format on
     return builtin_functions;
 }
diff --git a/init/init.cpp b/init/init.cpp
index 23448d6..a1d9f1b 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -41,13 +41,10 @@
 #include <selinux/android.h>
 
 #include <android-base/file.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
-#include <cutils/fs.h>
-#include <cutils/iosched_policy.h>
-#include <cutils/list.h>
-#include <cutils/sockets.h>
 #include <libavb/libavb.h>
 #include <private/android_filesystem_config.h>
 
@@ -72,6 +69,7 @@
 #include "util.h"
 #include "watchdogd.h"
 
+using android::base::GetProperty;
 using android::base::StringPrintf;
 
 struct selabel_handle *sehandle;
@@ -86,8 +84,6 @@
 
 const char *ENV[32];
 
-static std::unique_ptr<Timer> waiting_for_exec(nullptr);
-
 static int epoll_fd = -1;
 
 static std::unique_ptr<Timer> waiting_for_prop(nullptr);
@@ -135,29 +131,12 @@
     return -1;
 }
 
-bool start_waiting_for_exec()
-{
-    if (waiting_for_exec) {
-        return false;
-    }
-    waiting_for_exec.reset(new Timer());
-    return true;
-}
-
-void stop_waiting_for_exec()
-{
-    if (waiting_for_exec) {
-        LOG(INFO) << "Wait for exec took " << *waiting_for_exec;
-        waiting_for_exec.reset();
-    }
-}
-
 bool start_waiting_for_property(const char *name, const char *value)
 {
     if (waiting_for_prop) {
         return false;
     }
-    if (property_get(name) != value) {
+    if (GetProperty(name, "") != value) {
         // Current property value is not equal to expected value
         wait_prop_name = name;
         wait_prop_value = value;
@@ -445,7 +424,7 @@
 
 static int console_init_action(const std::vector<std::string>& args)
 {
-    std::string console = property_get("ro.boot.console");
+    std::string console = GetProperty("ro.boot.console", "");
     if (!console.empty()) {
         default_console = "/dev/" + console;
     }
@@ -469,11 +448,11 @@
 }
 
 static void export_oem_lock_status() {
-    if (property_get("ro.oem_unlock_supported") != "1") {
+    if (!android::base::GetBoolProperty("ro.oem_unlock_supported", false)) {
         return;
     }
 
-    std::string value = property_get("ro.boot.verifiedbootstate");
+    std::string value = GetProperty("ro.boot.verifiedbootstate", "");
 
     if (!value.empty()) {
         property_set("ro.boot.flash.locked", value == "orange" ? "0" : "1");
@@ -494,7 +473,7 @@
         { "ro.boot.revision",   "ro.revision",   "0", },
     };
     for (size_t i = 0; i < arraysize(prop_map); i++) {
-        std::string value = property_get(prop_map[i].src_prop);
+        std::string value = GetProperty(prop_map[i].src_prop, "");
         property_set(prop_map[i].dst_prop, (!value.empty()) ? value.c_str() : prop_map[i].default_value);
     }
 }
@@ -896,6 +875,34 @@
     }
 }
 
+// The files and directories that were created before initial sepolicy load
+// need to have their security context restored to the proper value.
+// This must happen before /dev is populated by ueventd.
+static void selinux_restore_context() {
+    LOG(INFO) << "Running restorecon...";
+    restorecon("/dev");
+    restorecon("/dev/kmsg");
+    restorecon("/dev/socket");
+    restorecon("/dev/random");
+    restorecon("/dev/urandom");
+    restorecon("/dev/__properties__");
+
+    restorecon("/file_contexts.bin");
+    restorecon("/plat_file_contexts");
+    restorecon("/nonplat_file_contexts");
+    restorecon("/plat_property_contexts");
+    restorecon("/nonplat_property_contexts");
+    restorecon("/plat_seapp_contexts");
+    restorecon("/nonplat_seapp_contexts");
+    restorecon("/plat_service_contexts");
+    restorecon("/nonplat_service_contexts");
+    restorecon("/sepolicy");
+
+    restorecon("/sys", SELINUX_ANDROID_RESTORECON_RECURSE);
+    restorecon("/dev/block", SELINUX_ANDROID_RESTORECON_RECURSE);
+    restorecon("/dev/device-mapper");
+}
+
 // Set the UDC controller for the ConfigFS USB Gadgets.
 // Read the UDC controller in use from "/sys/class/udc".
 // In case of multiple UDC controllers select the first one.
@@ -1234,22 +1241,7 @@
 
     // Now set up SELinux for second stage.
     selinux_initialize(false);
-
-    // These directories were necessarily created before initial policy load
-    // and therefore need their security context restored to the proper value.
-    // This must happen before /dev is populated by ueventd.
-    LOG(INFO) << "Running restorecon...";
-    restorecon("/dev");
-    restorecon("/dev/kmsg");
-    restorecon("/dev/socket");
-    restorecon("/dev/random");
-    restorecon("/dev/urandom");
-    restorecon("/dev/__properties__");
-    restorecon("/plat_property_contexts");
-    restorecon("/nonplat_property_contexts");
-    restorecon("/sys", SELINUX_ANDROID_RESTORECON_RECURSE);
-    restorecon("/dev/block", SELINUX_ANDROID_RESTORECON_RECURSE);
-    restorecon("/dev/device-mapper");
+    selinux_restore_context();
 
     epoll_fd = epoll_create1(EPOLL_CLOEXEC);
     if (epoll_fd == -1) {
@@ -1271,7 +1263,7 @@
     parser.AddSectionParser("service",std::make_unique<ServiceParser>());
     parser.AddSectionParser("on", std::make_unique<ActionParser>());
     parser.AddSectionParser("import", std::make_unique<ImportParser>());
-    std::string bootscript = property_get("ro.boot.init_rc");
+    std::string bootscript = GetProperty("ro.boot.init_rc", "");
     if (bootscript.empty()) {
         parser.ParseConfig("/init.rc");
         parser.set_is_system_etc_init_loaded(
@@ -1311,7 +1303,7 @@
     am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
 
     // Don't mount filesystems or start core system services in charger mode.
-    std::string bootmode = property_get("ro.bootmode");
+    std::string bootmode = GetProperty("ro.bootmode", "");
     if (bootmode == "charger") {
         am.QueueEventTrigger("charger");
     } else {
@@ -1325,10 +1317,10 @@
         // By default, sleep until something happens.
         int epoll_timeout_ms = -1;
 
-        if (!(waiting_for_exec || waiting_for_prop)) {
+        if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
             am.ExecuteOneCommand();
         }
-        if (!(waiting_for_exec || waiting_for_prop)) {
+        if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
             restart_processes();
 
             // If there's a process that needs restarting, wake up in time for that.
diff --git a/init/init.h b/init/init.h
index b4d25fb..fe850ef 100644
--- a/init/init.h
+++ b/init/init.h
@@ -32,10 +32,6 @@
 
 int add_environment(const char* key, const char* val);
 
-bool start_waiting_for_exec();
-
-void stop_waiting_for_exec();
-
 bool start_waiting_for_property(const char *name, const char *value);
 
 #endif  /* _INIT_INIT_H */
diff --git a/init/keychords.cpp b/init/keychords.cpp
index 3dbb2f0..5801ea8 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -23,9 +23,10 @@
 #include <linux/keychord.h>
 #include <unistd.h>
 
+#include <android-base/properties.h>
+
 #include "init.h"
 #include "log.h"
-#include "property_service.h"
 #include "service.h"
 
 static struct input_keychord *keychords = 0;
@@ -74,7 +75,7 @@
     }
 
     // Only handle keychords if adb is enabled.
-    std::string adb_enabled = property_get("init.svc.adbd");
+    std::string adb_enabled = android::base::GetProperty("init.svc.adbd", "");
     if (adb_enabled == "running") {
         Service* svc = ServiceManager::GetInstance().FindServiceByKeychord(id);
         if (svc) {
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 983e684..a4d8b5f 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -30,10 +30,6 @@
 #include <memory>
 #include <vector>
 
-#include <cutils/misc.h>
-#include <cutils/sockets.h>
-#include <cutils/multiuser.h>
-
 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
 #include <sys/_system_properties.h>
 
@@ -118,12 +114,6 @@
     return check_mac_perms(ctl_name, sctx, cr);
 }
 
-std::string property_get(const char* name) {
-    char value[PROP_VALUE_MAX] = {0};
-    __system_property_get(name, value);
-    return value;
-}
-
 static void write_persistent_property(const char *name, const char *value)
 {
     char tempPath[PATH_MAX];
@@ -592,10 +582,7 @@
 
 static void load_override_properties() {
     if (ALLOW_LOCAL_PROP_OVERRIDE) {
-        std::string debuggable = property_get("ro.debuggable");
-        if (debuggable == "1") {
-            load_properties_from_file("/data/local.prop", NULL);
-        }
+        load_properties_from_file("/data/local.prop", NULL);
     }
 }
 
diff --git a/init/property_service.h b/init/property_service.h
index 5d59473..994da63 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -32,7 +32,6 @@
 void load_persist_props(void);
 void load_system_props(void);
 void start_property_service(void);
-std::string property_get(const char* name);
 uint32_t property_set(const std::string& name, const std::string& value);
 bool is_legal_property_name(const std::string& name);
 
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 261a437..2844d78 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -32,17 +32,15 @@
 
 #include <android-base/file.h>
 #include <android-base/macros.h>
-#include <android-base/parseint.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <bootloader_message/bootloader_message.h>
 #include <cutils/android_reboot.h>
-#include <cutils/partition_utils.h>
 #include <fs_mgr.h>
 #include <logwrap/logwrap.h>
 
 #include "log.h"
-#include "property_service.h"
 #include "reboot.h"
 #include "service.h"
 #include "util.h"
@@ -342,12 +340,9 @@
         abort();
     }
 
-    std::string timeout = property_get("ro.build.shutdown_timeout");
     /* TODO update default waiting time based on usage data */
-    unsigned int shutdownTimeout = 10;  // default value
-    if (android::base::ParseUint(timeout, &shutdownTimeout)) {
-        LOG(INFO) << "ro.build.shutdown_timeout set:" << shutdownTimeout;
-    }
+    unsigned int shutdownTimeout = android::base::GetUintProperty("ro.build.shutdown_timeout", 10u);
+    LOG(INFO) << "Shutdown timeout: " << shutdownTimeout;
 
     static const constexpr char* shutdown_critical_services[] = {"vold", "watchdogd"};
     for (const char* name : shutdown_critical_services) {
diff --git a/init/service.cpp b/init/service.cpp
index c6ef838..ede6364 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -34,6 +34,7 @@
 
 #include <android-base/file.h>
 #include <android-base/parseint.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <system/thread_defs.h>
@@ -191,8 +192,8 @@
 }
 
 void Service::NotifyStateChange(const std::string& new_state) const {
-    if ((flags_ & SVC_EXEC) != 0) {
-        // 'exec' commands don't have properties tracking their state.
+    if ((flags_ & SVC_TEMPORARY) != 0) {
+        // Services created by 'exec' are temporary and don't have properties tracking their state.
         return;
     }
 
@@ -259,7 +260,7 @@
     }
 }
 
-bool Service::Reap() {
+void Service::Reap() {
     if (!(flags_ & SVC_ONESHOT) || (flags_ & SVC_RESTART)) {
         KillProcessGroup(SIGKILL);
     }
@@ -270,7 +271,10 @@
 
     if (flags_ & SVC_EXEC) {
         LOG(INFO) << "SVC_EXEC pid " << pid_ << " finished...";
-        return true;
+    }
+
+    if (flags_ & SVC_TEMPORARY) {
+        return;
     }
 
     pid_ = 0;
@@ -285,7 +289,7 @@
     // Disabled and reset processes do not get restarted automatically.
     if (flags_ & (SVC_DISABLED | SVC_RESET))  {
         NotifyStateChange("stopped");
-        return false;
+        return;
     }
 
     // If we crash > 4 times in 4 minutes, reboot into recovery.
@@ -309,7 +313,7 @@
     onrestart_.ExecuteAllCommands();
 
     NotifyStateChange("restarting");
-    return false;
+    return;
 }
 
 void Service::DumpState() const {
@@ -577,6 +581,18 @@
     return (this->*parser)(args, err);
 }
 
+bool Service::ExecStart(std::unique_ptr<Timer>* exec_waiter) {
+    flags_ |= SVC_EXEC | SVC_ONESHOT;
+
+    exec_waiter->reset(new Timer);
+
+    if (!Start()) {
+        exec_waiter->reset();
+        return false;
+    }
+    return true;
+}
+
 bool Service::Start() {
     // Starting a service removes it from the disabled or reset state and
     // immediately takes it out of the restarting state if it was in there.
@@ -657,7 +673,7 @@
         if (iter == writepid_files_.end()) {
             // There were no "writepid" instructions for cpusets, check if the system default
             // cpuset is specified to be used for the process.
-            std::string default_cpuset = property_get("ro.cpuset.default");
+            std::string default_cpuset = android::base::GetProperty("ro.cpuset.default", "");
             if (!default_cpuset.empty()) {
                 // Make sure the cpuset name starts and ends with '/'.
                 // A single '/' means the 'root' cpuset.
@@ -863,6 +879,35 @@
     services_.emplace_back(std::move(service));
 }
 
+bool ServiceManager::Exec(const std::vector<std::string>& args) {
+    Service* svc = MakeExecOneshotService(args);
+    if (!svc) {
+        LOG(ERROR) << "Could not create exec service";
+        return false;
+    }
+    if (!svc->ExecStart(&exec_waiter_)) {
+        LOG(ERROR) << "Could not start exec service";
+        ServiceManager::GetInstance().RemoveService(*svc);
+        return false;
+    }
+    return true;
+}
+
+bool ServiceManager::ExecStart(const std::string& name) {
+    Service* svc = FindServiceByName(name);
+    if (!svc) {
+        LOG(ERROR) << "ExecStart(" << name << "): Service not found";
+        return false;
+    }
+    if (!svc->ExecStart(&exec_waiter_)) {
+        LOG(ERROR) << "ExecStart(" << name << "): Could not start Service";
+        return false;
+    }
+    return true;
+}
+
+bool ServiceManager::IsWaitingForExec() const { return exec_waiter_ != nullptr; }
+
 Service* ServiceManager::MakeExecOneshotService(const std::vector<std::string>& args) {
     // Parse the arguments: exec [SECLABEL [UID [GID]*] --] COMMAND ARGS...
     // SECLABEL can be a - to denote default
@@ -886,7 +931,7 @@
 
     exec_count_++;
     std::string name = StringPrintf("exec %d (%s)", exec_count_, str_args[0].c_str());
-    unsigned flags = SVC_EXEC | SVC_ONESHOT;
+    unsigned flags = SVC_EXEC | SVC_ONESHOT | SVC_TEMPORARY;
     CapSet no_capabilities;
     unsigned namespace_flags = 0;
 
@@ -1026,8 +1071,13 @@
         return true;
     }
 
-    if (svc->Reap()) {
-        stop_waiting_for_exec();
+    svc->Reap();
+
+    if (svc->flags() & SVC_EXEC) {
+        LOG(INFO) << "Wait for exec took " << *exec_waiter_;
+        exec_waiter_.reset();
+    }
+    if (svc->flags() & SVC_TEMPORARY) {
         RemoveService(*svc);
     }
 
diff --git a/init/service.h b/init/service.h
index 9a9046b..f08a03f 100644
--- a/init/service.h
+++ b/init/service.h
@@ -44,10 +44,13 @@
 #define SVC_RC_DISABLED 0x080     // Remember if the disabled flag was set in the rc script.
 #define SVC_RESTART 0x100         // Use to safely restart (stop, wait, start) a service.
 #define SVC_DISABLED_START 0x200  // A start was requested but it was disabled at the time.
-#define SVC_EXEC 0x400            // This synthetic service corresponds to an 'exec'.
+#define SVC_EXEC 0x400  // This service was started by either 'exec' or 'exec_start' and stops
+                        // init from processing more commands until it completes
 
 #define SVC_SHUTDOWN_CRITICAL 0x800  // This service is critical for shutdown and
                                      // should not be killed during shutdown
+#define SVC_TEMPORARY 0x1000  // This service was started by 'exec' and should be removed from the
+                              // service list once it is reaped.
 
 #define NR_SVC_SUPP_GIDS 12    // twelve supplementary groups
 
@@ -72,6 +75,7 @@
 
     bool IsRunning() { return (flags_ & SVC_RUNNING) != 0; }
     bool ParseLine(const std::vector<std::string>& args, std::string* err);
+    bool ExecStart(std::unique_ptr<Timer>* exec_waiter);
     bool Start();
     bool StartIfNotDisabled();
     bool Enable();
@@ -80,7 +84,7 @@
     void Terminate();
     void Restart();
     void RestartIfNeeded(time_t* process_needs_restart_at);
-    bool Reap();
+    void Reap();
     void DumpState() const;
     void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; }
     bool IsShutdownCritical() const { return (flags_ & SVC_SHUTDOWN_CRITICAL) != 0; }
@@ -178,6 +182,9 @@
 
     void AddService(std::unique_ptr<Service> service);
     Service* MakeExecOneshotService(const std::vector<std::string>& args);
+    bool Exec(const std::vector<std::string>& args);
+    bool ExecStart(const std::string& name);
+    bool IsWaitingForExec() const;
     Service* FindServiceByName(const std::string& name) const;
     Service* FindServiceByPid(pid_t pid) const;
     Service* FindServiceByKeychord(int keychord_id) const;
@@ -198,6 +205,8 @@
     bool ReapOneProcess();
 
     static int exec_count_; // Every service needs a unique name.
+    std::unique_ptr<Timer> exec_waiter_;
+
     std::vector<std::unique_ptr<Service>> services_;
 };
 
diff --git a/init/signal_handler.cpp b/init/signal_handler.cpp
index 1041b82..5e3acac 100644
--- a/init/signal_handler.cpp
+++ b/init/signal_handler.cpp
@@ -24,8 +24,6 @@
 #include <unistd.h>
 
 #include <android-base/stringprintf.h>
-#include <cutils/list.h>
-#include <cutils/sockets.h>
 
 #include "action.h"
 #include "init.h"
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index 915afbd..f27be64 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -26,6 +26,7 @@
 
 #include <sys/types.h>
 
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <selinux/selinux.h>
 
@@ -34,7 +35,6 @@
 #include "util.h"
 #include "devices.h"
 #include "ueventd_parser.h"
-#include "property_service.h"
 
 int ueventd_main(int argc, char **argv)
 {
@@ -71,7 +71,7 @@
      * TODO: cleanup platform ueventd.rc to remove vendor specific
      * device node entries (b/34968103)
      */
-    std::string hardware = property_get("ro.hardware");
+    std::string hardware = android::base::GetProperty("ro.hardware", "");
     ueventd_parse_config_file(android::base::StringPrintf("/ueventd.%s.rc", hardware.c_str()).c_str());
 
     device_init();
diff --git a/init/util.cpp b/init/util.cpp
index 0ba9800..8a19939 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -38,6 +38,7 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
@@ -48,7 +49,6 @@
 
 #include "init.h"
 #include "log.h"
-#include "property_service.h"
 #include "reboot.h"
 #include "util.h"
 
@@ -395,7 +395,7 @@
             return false;
         }
 
-        std::string prop_val = property_get(prop_name.c_str());
+        std::string prop_val = android::base::GetProperty(prop_name, "");
         if (prop_val.empty()) {
             if (def_val.empty()) {
                 LOG(ERROR) << "property '" << prop_name << "' doesn't exist while expanding '" << src << "'";
diff --git a/libappfuse/FuseAppLoop.cc b/libappfuse/FuseAppLoop.cc
index a31880e..b6bc191 100644
--- a/libappfuse/FuseAppLoop.cc
+++ b/libappfuse/FuseAppLoop.cc
@@ -16,205 +16,232 @@
 
 #include "libappfuse/FuseAppLoop.h"
 
+#include <sys/eventfd.h>
 #include <sys/stat.h>
 
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
 
+#include "libappfuse/EpollController.h"
+
 namespace android {
 namespace fuse {
 
 namespace {
 
-void HandleLookUp(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
-  // AppFuse does not support directory structure now.
-  // It can lookup only files under the mount point.
-  if (buffer->request.header.nodeid != FUSE_ROOT_ID) {
-    LOG(ERROR) << "Nodeid is not FUSE_ROOT_ID.";
-    buffer->response.Reset(0, -ENOENT, buffer->request.header.unique);
-    return;
-  }
-
-  // Ensure that the filename ends with 0.
-  const size_t filename_length =
-      buffer->request.header.len - sizeof(fuse_in_header);
-  if (buffer->request.lookup_name[filename_length - 1] != 0) {
-    LOG(ERROR) << "File name does not end with 0.";
-    buffer->response.Reset(0, -ENOENT, buffer->request.header.unique);
-    return;
-  }
-
-  const uint64_t inode =
-      static_cast<uint64_t>(atol(buffer->request.lookup_name));
-  if (inode == 0 || inode == LONG_MAX) {
-    LOG(ERROR) << "Invalid filename";
-    buffer->response.Reset(0, -ENOENT, buffer->request.header.unique);
-    return;
-  }
-
-  const int64_t size = callback->OnGetSize(inode);
-  if (size < 0) {
-    buffer->response.Reset(0, size, buffer->request.header.unique);
-    return;
-  }
-
-  buffer->response.Reset(sizeof(fuse_entry_out), 0,
-                         buffer->request.header.unique);
-  buffer->response.entry_out.nodeid = inode;
-  buffer->response.entry_out.attr_valid = 10;
-  buffer->response.entry_out.entry_valid = 10;
-  buffer->response.entry_out.attr.ino = inode;
-  buffer->response.entry_out.attr.mode = S_IFREG | 0777;
-  buffer->response.entry_out.attr.size = size;
-}
-
-void HandleGetAttr(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
-  const uint64_t nodeid = buffer->request.header.nodeid;
-  int64_t size;
-  uint32_t mode;
-  if (nodeid == FUSE_ROOT_ID) {
-    size = 0;
-    mode = S_IFDIR | 0777;
-  } else {
-    size = callback->OnGetSize(buffer->request.header.nodeid);
-    if (size < 0) {
-      buffer->response.Reset(0, size, buffer->request.header.unique);
-      return;
+bool HandleLookUp(FuseAppLoop* loop, FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+    // AppFuse does not support directory structure now.
+    // It can lookup only files under the mount point.
+    if (buffer->request.header.nodeid != FUSE_ROOT_ID) {
+        LOG(ERROR) << "Nodeid is not FUSE_ROOT_ID.";
+        return loop->ReplySimple(buffer->request.header.unique, -ENOENT);
     }
-    mode = S_IFREG | 0777;
-  }
 
-  buffer->response.Reset(sizeof(fuse_attr_out), 0,
-                         buffer->request.header.unique);
-  buffer->response.attr_out.attr_valid = 10;
-  buffer->response.attr_out.attr.ino = nodeid;
-  buffer->response.attr_out.attr.mode = mode;
-  buffer->response.attr_out.attr.size = size;
+    // Ensure that the filename ends with 0.
+    const size_t filename_length = buffer->request.header.len - sizeof(fuse_in_header);
+    if (buffer->request.lookup_name[filename_length - 1] != 0) {
+        LOG(ERROR) << "File name does not end with 0.";
+        return loop->ReplySimple(buffer->request.header.unique, -ENOENT);
+    }
+
+    const uint64_t inode = static_cast<uint64_t>(atol(buffer->request.lookup_name));
+    if (inode == 0 || inode == LONG_MAX) {
+        LOG(ERROR) << "Invalid filename";
+        return loop->ReplySimple(buffer->request.header.unique, -ENOENT);
+    }
+
+    callback->OnLookup(buffer->request.header.unique, inode);
+    return true;
 }
 
-void HandleOpen(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
-  const int32_t file_handle = callback->OnOpen(buffer->request.header.nodeid);
-  if (file_handle < 0) {
-    buffer->response.Reset(0, file_handle, buffer->request.header.unique);
-    return;
-  }
-  buffer->response.Reset(sizeof(fuse_open_out), kFuseSuccess,
-                         buffer->request.header.unique);
-  buffer->response.open_out.fh = file_handle;
+bool HandleGetAttr(FuseAppLoop* loop, FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+    if (buffer->request.header.nodeid == FUSE_ROOT_ID) {
+        return loop->ReplyGetAttr(buffer->request.header.unique, buffer->request.header.nodeid, 0,
+                                  S_IFDIR | 0777);
+    } else {
+        callback->OnGetAttr(buffer->request.header.unique, buffer->request.header.nodeid);
+        return true;
+    }
 }
 
-void HandleFsync(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
-  buffer->response.Reset(0, callback->OnFsync(buffer->request.header.nodeid),
-                         buffer->request.header.unique);
+bool HandleRead(FuseAppLoop* loop, FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+    if (buffer->request.read_in.size > kFuseMaxRead) {
+        return loop->ReplySimple(buffer->request.header.unique, -EINVAL);
+    }
+
+    callback->OnRead(buffer->request.header.unique, buffer->request.header.nodeid,
+                     buffer->request.read_in.offset, buffer->request.read_in.size);
+    return true;
 }
 
-void HandleRelease(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
-  buffer->response.Reset(0, callback->OnRelease(buffer->request.header.nodeid),
-                         buffer->request.header.unique);
+bool HandleWrite(FuseAppLoop* loop, FuseBuffer* buffer, FuseAppLoopCallback* callback) {
+    if (buffer->request.write_in.size > kFuseMaxWrite) {
+        return loop->ReplySimple(buffer->request.header.unique, -EINVAL);
+    }
+
+    callback->OnWrite(buffer->request.header.unique, buffer->request.header.nodeid,
+                      buffer->request.write_in.offset, buffer->request.write_in.size,
+                      buffer->request.write_data);
+    return true;
 }
 
-void HandleRead(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
-  const uint64_t unique = buffer->request.header.unique;
-  const uint64_t nodeid = buffer->request.header.nodeid;
-  const uint64_t offset = buffer->request.read_in.offset;
-  const uint32_t size = buffer->request.read_in.size;
+bool HandleMessage(FuseAppLoop* loop, FuseBuffer* buffer, int fd, FuseAppLoopCallback* callback) {
+    if (!buffer->request.Read(fd)) {
+        return false;
+    }
 
-  if (size > kFuseMaxRead) {
-    buffer->response.Reset(0, -EINVAL, buffer->request.header.unique);
-    return;
-  }
+    const uint32_t opcode = buffer->request.header.opcode;
+    LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode;
+    switch (opcode) {
+        case FUSE_FORGET:
+            // Do not reply to FUSE_FORGET.
+            return true;
 
-  const int32_t read_size = callback->OnRead(nodeid, offset, size,
-                                             buffer->response.read_data);
-  if (read_size < 0) {
-    buffer->response.Reset(0, read_size, buffer->request.header.unique);
-    return;
-  }
+        case FUSE_LOOKUP:
+            return HandleLookUp(loop, buffer, callback);
 
-  buffer->response.ResetHeader(read_size, kFuseSuccess, unique);
-}
+        case FUSE_GETATTR:
+            return HandleGetAttr(loop, buffer, callback);
 
-void HandleWrite(FuseBuffer* buffer, FuseAppLoopCallback* callback) {
-  const uint64_t unique = buffer->request.header.unique;
-  const uint64_t nodeid = buffer->request.header.nodeid;
-  const uint64_t offset = buffer->request.write_in.offset;
-  const uint32_t size = buffer->request.write_in.size;
+        case FUSE_OPEN:
+            callback->OnOpen(buffer->request.header.unique, buffer->request.header.nodeid);
+            return true;
 
-  if (size > kFuseMaxWrite) {
-    buffer->response.Reset(0, -EINVAL, buffer->request.header.unique);
-    return;
-  }
+        case FUSE_READ:
+            return HandleRead(loop, buffer, callback);
 
-  const int32_t write_size = callback->OnWrite(nodeid, offset, size,
-                                               buffer->request.write_data);
-  if (write_size < 0) {
-    buffer->response.Reset(0, write_size, buffer->request.header.unique);
-    return;
-  }
+        case FUSE_WRITE:
+            return HandleWrite(loop, buffer, callback);
 
-  buffer->response.Reset(sizeof(fuse_write_out), kFuseSuccess, unique);
-  buffer->response.write_out.size = write_size;
+        case FUSE_RELEASE:
+            callback->OnRelease(buffer->request.header.unique, buffer->request.header.nodeid);
+            return true;
+
+        case FUSE_FSYNC:
+            callback->OnFsync(buffer->request.header.unique, buffer->request.header.nodeid);
+            return true;
+
+        default:
+            buffer->HandleNotImpl();
+            return buffer->response.Write(fd);
+    }
 }
 
 } // namespace
 
-bool StartFuseAppLoop(int raw_fd, FuseAppLoopCallback* callback) {
-  base::unique_fd fd(raw_fd);
-  FuseBuffer buffer;
+FuseAppLoopCallback::~FuseAppLoopCallback() = default;
 
-  LOG(DEBUG) << "Start fuse loop.";
-  while (callback->IsActive()) {
-    if (!buffer.request.Read(fd)) {
-      return false;
+FuseAppLoop::FuseAppLoop(base::unique_fd&& fd) : fd_(std::move(fd)) {}
+
+void FuseAppLoop::Break() {
+    const int64_t value = 1;
+    if (write(break_fd_, &value, sizeof(value)) == -1) {
+        PLOG(ERROR) << "Failed to send a break event";
+    }
+}
+
+bool FuseAppLoop::ReplySimple(uint64_t unique, int32_t result) {
+    if (result == -ENOSYS) {
+        // We should not return -ENOSYS because the kernel stops delivering FUSE
+        // command after receiving -ENOSYS as a result for the command.
+        result = -EBADF;
+    }
+    FuseSimpleResponse response;
+    response.Reset(0, result, unique);
+    return response.Write(fd_);
+}
+
+bool FuseAppLoop::ReplyLookup(uint64_t unique, uint64_t inode, int64_t size) {
+    FuseSimpleResponse response;
+    response.Reset(sizeof(fuse_entry_out), 0, unique);
+    response.entry_out.nodeid = inode;
+    response.entry_out.attr_valid = 10;
+    response.entry_out.entry_valid = 10;
+    response.entry_out.attr.ino = inode;
+    response.entry_out.attr.mode = S_IFREG | 0777;
+    response.entry_out.attr.size = size;
+    return response.Write(fd_);
+}
+
+bool FuseAppLoop::ReplyGetAttr(uint64_t unique, uint64_t inode, int64_t size, int mode) {
+    CHECK(mode == (S_IFREG | 0777) || mode == (S_IFDIR | 0777));
+    FuseSimpleResponse response;
+    response.Reset(sizeof(fuse_attr_out), 0, unique);
+    response.attr_out.attr_valid = 10;
+    response.attr_out.attr.ino = inode;
+    response.attr_out.attr.mode = mode;
+    response.attr_out.attr.size = size;
+    return response.Write(fd_);
+}
+
+bool FuseAppLoop::ReplyOpen(uint64_t unique, uint64_t fh) {
+    FuseSimpleResponse response;
+    response.Reset(sizeof(fuse_open_out), kFuseSuccess, unique);
+    response.open_out.fh = fh;
+    return response.Write(fd_);
+}
+
+bool FuseAppLoop::ReplyWrite(uint64_t unique, uint32_t size) {
+    CHECK(size <= kFuseMaxWrite);
+    FuseSimpleResponse response;
+    response.Reset(sizeof(fuse_write_out), kFuseSuccess, unique);
+    response.write_out.size = size;
+    return response.Write(fd_);
+}
+
+bool FuseAppLoop::ReplyRead(uint64_t unique, uint32_t size, const void* data) {
+    CHECK(size <= kFuseMaxRead);
+    FuseSimpleResponse response;
+    response.ResetHeader(size, kFuseSuccess, unique);
+    return response.WriteWithBody(fd_, sizeof(FuseResponse), data);
+}
+
+void FuseAppLoop::Start(FuseAppLoopCallback* callback) {
+    break_fd_.reset(eventfd(/* initval */ 0, EFD_CLOEXEC));
+    if (break_fd_.get() == -1) {
+        PLOG(ERROR) << "Failed to open FD for break event";
+        return;
     }
 
-    const uint32_t opcode = buffer.request.header.opcode;
-    LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode;
-    switch (opcode) {
-      case FUSE_FORGET:
-        // Do not reply to FUSE_FORGET.
-        continue;
-
-      case FUSE_LOOKUP:
-        HandleLookUp(&buffer, callback);
-        break;
-
-      case FUSE_GETATTR:
-        HandleGetAttr(&buffer, callback);
-        break;
-
-      case FUSE_OPEN:
-        HandleOpen(&buffer, callback);
-        break;
-
-      case FUSE_READ:
-        HandleRead(&buffer, callback);
-        break;
-
-      case FUSE_WRITE:
-        HandleWrite(&buffer, callback);
-        break;
-
-      case FUSE_RELEASE:
-        HandleRelease(&buffer, callback);
-        break;
-
-      case FUSE_FSYNC:
-        HandleFsync(&buffer, callback);
-        break;
-
-      default:
-        buffer.HandleNotImpl();
-        break;
+    base::unique_fd epoll_fd(epoll_create1(EPOLL_CLOEXEC));
+    if (epoll_fd.get() == -1) {
+        PLOG(ERROR) << "Failed to open FD for epoll";
+        return;
     }
 
-    if (!buffer.response.Write(fd)) {
-      LOG(ERROR) << "Failed to write a response to the device.";
-      return false;
-    }
-  }
+    int last_event;
+    int break_event;
 
-  return true;
+    std::unique_ptr<EpollController> epoll_controller(new EpollController(std::move(epoll_fd)));
+    if (!epoll_controller->AddFd(fd_, EPOLLIN, &last_event)) {
+        return;
+    }
+    if (!epoll_controller->AddFd(break_fd_, EPOLLIN, &break_event)) {
+        return;
+    }
+
+    last_event = 0;
+    break_event = 0;
+
+    FuseBuffer buffer;
+    while (true) {
+        if (!epoll_controller->Wait(1)) {
+            break;
+        }
+        last_event = 0;
+        *reinterpret_cast<int*>(epoll_controller->events()[0].data.ptr) =
+            epoll_controller->events()[0].events;
+
+        if (break_event != 0 || (last_event & ~EPOLLIN) != 0) {
+            break;
+        }
+
+        if (!HandleMessage(this, &buffer, fd_, callback)) {
+            break;
+        }
+    }
+
+    LOG(VERBOSE) << "FuseAppLoop exit";
 }
 
 }  // namespace fuse
diff --git a/libappfuse/include/libappfuse/FuseAppLoop.h b/libappfuse/include/libappfuse/FuseAppLoop.h
index c3edfcc..f2ef2b5 100644
--- a/libappfuse/include/libappfuse/FuseAppLoop.h
+++ b/libappfuse/include/libappfuse/FuseAppLoop.h
@@ -17,23 +17,51 @@
 #ifndef ANDROID_LIBAPPFUSE_FUSEAPPLOOP_H_
 #define ANDROID_LIBAPPFUSE_FUSEAPPLOOP_H_
 
+#include <memory>
+#include <mutex>
+
+#include <android-base/unique_fd.h>
+
 #include "libappfuse/FuseBuffer.h"
 
 namespace android {
 namespace fuse {
 
+class EpollController;
+
 class FuseAppLoopCallback {
  public:
-  virtual bool IsActive() = 0;
-  virtual int64_t OnGetSize(uint64_t inode) = 0;
-  virtual int32_t OnFsync(uint64_t inode) = 0;
-  virtual int32_t OnWrite(
-      uint64_t inode, uint64_t offset, uint32_t size, const void* data) = 0;
-  virtual int32_t OnRead(
-      uint64_t inode, uint64_t offset, uint32_t size, void* data) = 0;
-  virtual int32_t OnOpen(uint64_t inode) = 0;
-  virtual int32_t OnRelease(uint64_t inode) = 0;
-  virtual ~FuseAppLoopCallback() = default;
+   virtual void OnLookup(uint64_t unique, uint64_t inode) = 0;
+   virtual void OnGetAttr(uint64_t unique, uint64_t inode) = 0;
+   virtual void OnFsync(uint64_t unique, uint64_t inode) = 0;
+   virtual void OnWrite(uint64_t unique, uint64_t inode, uint64_t offset, uint32_t size,
+                        const void* data) = 0;
+   virtual void OnRead(uint64_t unique, uint64_t inode, uint64_t offset, uint32_t size) = 0;
+   virtual void OnOpen(uint64_t unique, uint64_t inode) = 0;
+   virtual void OnRelease(uint64_t unique, uint64_t inode) = 0;
+   virtual ~FuseAppLoopCallback();
+};
+
+class FuseAppLoop final {
+  public:
+    FuseAppLoop(base::unique_fd&& fd);
+
+    void Start(FuseAppLoopCallback* callback);
+    void Break();
+
+    bool ReplySimple(uint64_t unique, int32_t result);
+    bool ReplyLookup(uint64_t unique, uint64_t inode, int64_t size);
+    bool ReplyGetAttr(uint64_t unique, uint64_t inode, int64_t size, int mode);
+    bool ReplyOpen(uint64_t unique, uint64_t fh);
+    bool ReplyWrite(uint64_t unique, uint32_t size);
+    bool ReplyRead(uint64_t unique, uint32_t size, const void* data);
+
+  private:
+    base::unique_fd fd_;
+    base::unique_fd break_fd_;
+
+    // Lock for multi-threading.
+    std::mutex mutex_;
 };
 
 bool StartFuseAppLoop(int fd, FuseAppLoopCallback* callback);
diff --git a/libappfuse/tests/FuseAppLoopTest.cc b/libappfuse/tests/FuseAppLoopTest.cc
index 64dd813..98e3665 100644
--- a/libappfuse/tests/FuseAppLoopTest.cc
+++ b/libappfuse/tests/FuseAppLoopTest.cc
@@ -23,6 +23,9 @@
 #include <gtest/gtest.h>
 #include <thread>
 
+#include "libappfuse/EpollController.h"
+#include "libappfuse/FuseBridgeLoop.h"
+
 namespace android {
 namespace fuse {
 namespace {
@@ -37,82 +40,61 @@
 class Callback : public FuseAppLoopCallback {
  public:
   std::vector<CallbackRequest> requests;
+  FuseAppLoop* loop;
 
-  bool IsActive() override {
-    return true;
+  void OnGetAttr(uint64_t seq, uint64_t inode) override {
+      EXPECT_NE(FUSE_ROOT_ID, static_cast<int>(inode));
+      EXPECT_TRUE(loop->ReplyGetAttr(seq, inode, kTestFileSize, S_IFREG | 0777));
   }
 
-  int64_t OnGetSize(uint64_t inode) override {
-    if (inode == FUSE_ROOT_ID) {
-      return 0;
-    } else {
-      return kTestFileSize;
-    }
+  void OnLookup(uint64_t unique, uint64_t inode) override {
+      EXPECT_NE(FUSE_ROOT_ID, static_cast<int>(inode));
+      EXPECT_TRUE(loop->ReplyLookup(unique, inode, kTestFileSize));
   }
 
-  int32_t OnFsync(uint64_t inode) override {
-    requests.push_back({
-      .code = FUSE_FSYNC,
-      .inode = inode
-    });
-    return 0;
+  void OnFsync(uint64_t seq, uint64_t inode) override {
+      requests.push_back({.code = FUSE_FSYNC, .inode = inode});
+      loop->ReplySimple(seq, 0);
   }
 
-  int32_t OnWrite(uint64_t inode,
-                  uint64_t offset ATTRIBUTE_UNUSED,
-                  uint32_t size ATTRIBUTE_UNUSED,
-                  const void* data ATTRIBUTE_UNUSED) override {
-    requests.push_back({
-      .code = FUSE_WRITE,
-      .inode = inode
-    });
-    return 0;
+  void OnWrite(uint64_t seq, uint64_t inode, uint64_t offset ATTRIBUTE_UNUSED,
+               uint32_t size ATTRIBUTE_UNUSED, const void* data ATTRIBUTE_UNUSED) override {
+      requests.push_back({.code = FUSE_WRITE, .inode = inode});
+      loop->ReplyWrite(seq, 0);
   }
 
-  int32_t OnRead(uint64_t inode,
-                 uint64_t offset ATTRIBUTE_UNUSED,
-                 uint32_t size ATTRIBUTE_UNUSED,
-                 void* data ATTRIBUTE_UNUSED) override {
-    requests.push_back({
-      .code = FUSE_READ,
-      .inode = inode
-    });
-    return 0;
+  void OnRead(uint64_t seq, uint64_t inode, uint64_t offset ATTRIBUTE_UNUSED,
+              uint32_t size ATTRIBUTE_UNUSED) override {
+      requests.push_back({.code = FUSE_READ, .inode = inode});
+      loop->ReplySimple(seq, 0);
   }
 
-  int32_t OnOpen(uint64_t inode) override {
-    requests.push_back({
-      .code = FUSE_OPEN,
-      .inode = inode
-    });
-    return 0;
+  void OnOpen(uint64_t seq, uint64_t inode) override {
+      requests.push_back({.code = FUSE_OPEN, .inode = inode});
+      loop->ReplyOpen(seq, inode);
   }
 
-  int32_t OnRelease(uint64_t inode) override {
-    requests.push_back({
-      .code = FUSE_RELEASE,
-      .inode = inode
-    });
-    return 0;
+  void OnRelease(uint64_t seq, uint64_t inode) override {
+      requests.push_back({.code = FUSE_RELEASE, .inode = inode});
+      loop->ReplySimple(seq, 0);
   }
 };
 
 class FuseAppLoopTest : public ::testing::Test {
- private:
-  std::thread thread_;
-
  protected:
-  base::unique_fd sockets_[2];
-  Callback callback_;
-  FuseRequest request_;
-  FuseResponse response_;
+   std::thread thread_;
+   base::unique_fd sockets_[2];
+   Callback callback_;
+   FuseRequest request_;
+   FuseResponse response_;
+   std::unique_ptr<FuseAppLoop> loop_;
 
-  void SetUp() override {
-    base::SetMinimumLogSeverity(base::VERBOSE);
-    ASSERT_TRUE(SetupMessageSockets(&sockets_));
-    thread_ = std::thread([this] {
-      StartFuseAppLoop(sockets_[1].release(), &callback_);
-    });
+   void SetUp() override {
+       base::SetMinimumLogSeverity(base::VERBOSE);
+       ASSERT_TRUE(SetupMessageSockets(&sockets_));
+       loop_.reset(new FuseAppLoop(std::move(sockets_[1])));
+       callback_.loop = loop_.get();
+       thread_ = std::thread([this] { loop_->Start(&callback_); });
   }
 
   void CheckCallback(
@@ -300,5 +282,18 @@
   CheckCallback(sizeof(fuse_write_in), FUSE_WRITE, sizeof(fuse_write_out));
 }
 
+TEST_F(FuseAppLoopTest, Break) {
+    // Ensure that the loop started.
+    request_.Reset(sizeof(fuse_open_in), FUSE_OPEN, 1);
+    request_.header.nodeid = 10;
+    ASSERT_TRUE(request_.Write(sockets_[0]));
+    ASSERT_TRUE(response_.Read(sockets_[0]));
+
+    loop_->Break();
+    if (thread_.joinable()) {
+        thread_.join();
+    }
+}
+
 }  // namespace fuse
 }  // namespace android
diff --git a/libcutils/sched_policy.cpp b/libcutils/sched_policy.cpp
index 0d459cc..73ca518 100644
--- a/libcutils/sched_policy.cpp
+++ b/libcutils/sched_policy.cpp
@@ -271,17 +271,9 @@
             return -1;
         }
     } else {
-        int rc = sched_getscheduler(tid);
-        if (rc < 0)
-            return -1;
-        else if (rc == SCHED_NORMAL)
-            *policy = SP_FOREGROUND;
-        else if (rc == SCHED_BATCH)
-            *policy = SP_BACKGROUND;
-        else {
-            errno = ERANGE;
-            return -1;
-        }
+        // In b/34193533, we removed bg_non_interactive cgroup, so now
+        // all threads are in FOREGROUND cgroup
+        *policy = SP_FOREGROUND;
     }
     return 0;
 }
@@ -428,14 +420,6 @@
                 return -errno;
         }
 
-    } else {
-        struct sched_param param;
-
-        param.sched_priority = 0;
-        sched_setscheduler(tid,
-                           (policy == SP_BACKGROUND) ?
-                           SCHED_BATCH : SCHED_NORMAL,
-                           &param);
     }
 
     if (__sys_supports_timerslack) {
diff --git a/libgrallocusage/Android.bp b/libgrallocusage/Android.bp
new file mode 100644
index 0000000..54bfee5
--- /dev/null
+++ b/libgrallocusage/Android.bp
@@ -0,0 +1,29 @@
+// Copyright 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_static {
+    name: "libgrallocusage",
+    cppflags: [
+        "-Weverything",
+        "-Werror",
+        "-Wno-c++98-compat-pedantic",
+        // Hide errors in headers we include
+        "-Wno-global-constructors",
+        "-Wno-exit-time-destructors",
+        "-Wno-padded",
+    ],
+    srcs: ["GrallocUsageConversion.cpp"],
+    export_include_dirs: ["include"],
+    shared_libs: ["android.hardware.graphics.allocator@2.0"],
+}
diff --git a/libgrallocusage/GrallocUsageConversion.cpp b/libgrallocusage/GrallocUsageConversion.cpp
new file mode 100644
index 0000000..8164beb
--- /dev/null
+++ b/libgrallocusage/GrallocUsageConversion.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <grallocusage/GrallocUsageConversion.h>
+
+#include <android/hardware/graphics/allocator/2.0/types.h>
+#include <hardware/gralloc.h>
+
+using android::hardware::graphics::allocator::V2_0::ProducerUsage;
+using android::hardware::graphics::allocator::V2_0::ConsumerUsage;
+
+void android_convertGralloc0To1Usage(int32_t usage, uint64_t* producerUsage,
+                                     uint64_t* consumerUsage) {
+    constexpr uint64_t PRODUCER_MASK = ProducerUsage::CPU_READ |
+                                       /* ProducerUsage::CPU_READ_OFTEN | */
+                                       ProducerUsage::CPU_WRITE |
+                                       /* ProducerUsage::CPU_WRITE_OFTEN | */
+                                       ProducerUsage::GPU_RENDER_TARGET | ProducerUsage::PROTECTED |
+                                       ProducerUsage::CAMERA | ProducerUsage::VIDEO_DECODER |
+                                       ProducerUsage::SENSOR_DIRECT_DATA;
+    constexpr uint64_t CONSUMER_MASK = ConsumerUsage::CPU_READ |
+                                       /* ConsumerUsage::CPU_READ_OFTEN | */
+                                       ConsumerUsage::GPU_TEXTURE | ConsumerUsage::HWCOMPOSER |
+                                       ConsumerUsage::CLIENT_TARGET | ConsumerUsage::CURSOR |
+                                       ConsumerUsage::VIDEO_ENCODER | ConsumerUsage::CAMERA |
+                                       ConsumerUsage::RENDERSCRIPT | ConsumerUsage::GPU_DATA_BUFFER;
+    *producerUsage = static_cast<uint64_t>(usage) & PRODUCER_MASK;
+    *consumerUsage = static_cast<uint64_t>(usage) & CONSUMER_MASK;
+    if ((static_cast<uint32_t>(usage) & GRALLOC_USAGE_SW_READ_OFTEN) == GRALLOC_USAGE_SW_READ_OFTEN) {
+        *producerUsage |= ProducerUsage::CPU_READ_OFTEN;
+        *consumerUsage |= ConsumerUsage::CPU_READ_OFTEN;
+    }
+    if ((static_cast<uint32_t>(usage) & GRALLOC_USAGE_SW_WRITE_OFTEN) ==
+        GRALLOC_USAGE_SW_WRITE_OFTEN) {
+        *producerUsage |= ProducerUsage::CPU_WRITE_OFTEN;
+    }
+}
+
+int32_t android_convertGralloc1To0Usage(uint64_t producerUsage, uint64_t consumerUsage) {
+    static_assert(uint64_t(ConsumerUsage::CPU_READ_OFTEN) == uint64_t(ProducerUsage::CPU_READ_OFTEN),
+                  "expected ConsumerUsage and ProducerUsage CPU_READ_OFTEN bits to match");
+    uint64_t merged = producerUsage | consumerUsage;
+    if ((merged & (ConsumerUsage::CPU_READ_OFTEN)) != 0) {
+        merged &= ~uint64_t(ConsumerUsage::CPU_READ_OFTEN);
+        merged |= GRALLOC_USAGE_SW_READ_OFTEN;
+    }
+    if ((merged & (ProducerUsage::CPU_WRITE_OFTEN)) != 0) {
+        merged &= ~uint64_t(ProducerUsage::CPU_WRITE_OFTEN);
+        merged |= GRALLOC_USAGE_SW_WRITE_OFTEN;
+    }
+    return static_cast<int32_t>(merged);
+}
diff --git a/libgrallocusage/MODULE_LICENSE_APACHE2 b/libgrallocusage/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libgrallocusage/MODULE_LICENSE_APACHE2
diff --git a/libgrallocusage/NOTICE b/libgrallocusage/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/libgrallocusage/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/libgrallocusage/include/grallocusage/GrallocUsageConversion.h b/libgrallocusage/include/grallocusage/GrallocUsageConversion.h
new file mode 100644
index 0000000..5c94343
--- /dev/null
+++ b/libgrallocusage/include/grallocusage/GrallocUsageConversion.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GRALLOCUSAGE_GRALLOC_USAGE_CONVERSION_H
+#define ANDROID_GRALLOCUSAGE_GRALLOC_USAGE_CONVERSION_H 1
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Conversion functions are out-of-line so that users don't have to be exposed to
+// android/hardware/graphics/allocator/2.0/types.h and link against
+// android.hardware.graphics.allocator@2.0 to get that in their search path.
+
+// Convert a 32-bit gralloc0 usage mask to a producer/consumer pair of 64-bit usage masks as used
+// by android.hardware.graphics.allocator@2.0 (and gralloc1). This conversion properly handles the
+// mismatch between a.h.g.allocator@2.0's CPU_{READ,WRITE}_OFTEN and gralloc0's
+// SW_{READ,WRITE}_OFTEN.
+void android_convertGralloc0To1Usage(int32_t usage, uint64_t* producerUsage,
+                                     uint64_t* consumerUsage);
+
+// Convert a producer/consumer pair of 64-bit usage masks as used by
+// android.hardware.graphics.allocator@2.0 (and gralloc1) to a 32-bit gralloc0 usage mask. This
+// conversion properly handles the mismatch between a.h.g.allocator@2.0's CPU_{READ,WRITE}_OFTEN
+// and gralloc0's SW_{READ,WRITE}_OFTEN.
+int32_t android_convertGralloc1To0Usage(uint64_t producerUsage, uint64_t consumerUsage);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // ANDROID_GRALLOCUSAGE_GRALLOC_USAGE_CONVERSION_H
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index 0d98db9..24737b9 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -760,6 +760,4 @@
     ref->mRefs->renameWeakRefId(old_id, new_id);
 }
 
-VirtualLightRefBase::~VirtualLightRefBase() {}
-
 }; // namespace android
diff --git a/libutils/include/utils/LightRefBase.h b/libutils/include/utils/LightRefBase.h
new file mode 100644
index 0000000..65257ed
--- /dev/null
+++ b/libutils/include/utils/LightRefBase.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+/*
+ * See documentation in RefBase.h
+ */
+
+#include <atomic>
+
+#include <sys/types.h>
+
+namespace android {
+
+class ReferenceRenamer;
+
+template <class T>
+class LightRefBase
+{
+public:
+    inline LightRefBase() : mCount(0) { }
+    inline void incStrong(__attribute__((unused)) const void* id) const {
+        mCount.fetch_add(1, std::memory_order_relaxed);
+    }
+    inline void decStrong(__attribute__((unused)) const void* id) const {
+        if (mCount.fetch_sub(1, std::memory_order_release) == 1) {
+            std::atomic_thread_fence(std::memory_order_acquire);
+            delete static_cast<const T*>(this);
+        }
+    }
+    //! DEBUGGING ONLY: Get current strong ref count.
+    inline int32_t getStrongCount() const {
+        return mCount.load(std::memory_order_relaxed);
+    }
+
+    typedef LightRefBase<T> basetype;
+
+protected:
+    inline ~LightRefBase() { }
+
+private:
+    friend class ReferenceMover;
+    inline static void renameRefs(size_t /*n*/, const ReferenceRenamer& /*renamer*/) { }
+    inline static void renameRefId(T* /*ref*/, const void* /*old_id*/ , const void* /*new_id*/) { }
+
+private:
+    mutable std::atomic<int32_t> mCount;
+};
+
+
+// This is a wrapper around LightRefBase that simply enforces a virtual
+// destructor to eliminate the template requirement of LightRefBase
+class VirtualLightRefBase : public LightRefBase<VirtualLightRefBase> {
+public:
+    virtual ~VirtualLightRefBase() = default;
+};
+
+}; // namespace android
diff --git a/libutils/include/utils/RefBase.h b/libutils/include/utils/RefBase.h
index a61ea58..223b666 100644
--- a/libutils/include/utils/RefBase.h
+++ b/libutils/include/utils/RefBase.h
@@ -177,6 +177,9 @@
 #include <stdlib.h>
 #include <string.h>
 
+// LightRefBase used to be declared in this header, so we have to include it
+#include <utils/LightRefBase.h>
+
 #include <utils/StrongPointer.h>
 #include <utils/TypeHelpers.h>
 
@@ -216,7 +219,7 @@
 
 class ReferenceRenamer {
 protected:
-    // destructor is purposedly not virtual so we avoid code overhead from
+    // destructor is purposely not virtual so we avoid code overhead from
     // subclasses; we have to make it protected to guarantee that it
     // cannot be called from this base class (and to make strict compilers
     // happy).
@@ -246,13 +249,13 @@
     {
     public:
         RefBase*            refBase() const;
-        
+
         void                incWeak(const void* id);
         void                decWeak(const void* id);
-        
+
         // acquires a strong reference if there is already one.
         bool                attemptIncStrong(const void* id);
-        
+
         // acquires a weak reference if there is already one.
         // This is not always safe. see ProcessState.cpp and BpBinder.cpp
         // for proper use.
@@ -268,12 +271,12 @@
         // enable -- enable/disable tracking
         // retain -- when tracking is enable, if true, then we save a stack trace
         //           for each reference and dereference; when retain == false, we
-        //           match up references and dereferences and keep only the 
+        //           match up references and dereferences and keep only the
         //           outstanding ones.
-        
+
         void                trackMe(bool enable, bool retain);
     };
-    
+
             weakref_type*   createWeak(const void* id) const;
             
             weakref_type*   getWeakRefs() const;
@@ -345,54 +348,12 @@
 
 // ---------------------------------------------------------------------------
 
-template <class T>
-class LightRefBase
-{
-public:
-    inline LightRefBase() : mCount(0) { }
-    inline void incStrong(__attribute__((unused)) const void* id) const {
-        mCount.fetch_add(1, std::memory_order_relaxed);
-    }
-    inline void decStrong(__attribute__((unused)) const void* id) const {
-        if (mCount.fetch_sub(1, std::memory_order_release) == 1) {
-            std::atomic_thread_fence(std::memory_order_acquire);
-            delete static_cast<const T*>(this);
-        }
-    }
-    //! DEBUGGING ONLY: Get current strong ref count.
-    inline int32_t getStrongCount() const {
-        return mCount.load(std::memory_order_relaxed);
-    }
-
-    typedef LightRefBase<T> basetype;
-
-protected:
-    inline ~LightRefBase() { }
-
-private:
-    friend class ReferenceMover;
-    inline static void renameRefs(size_t /*n*/, const ReferenceRenamer& /*renamer*/) { }
-    inline static void renameRefId(T* /*ref*/, const void* /*old_id*/ , const void* /*new_id*/) { }
-
-private:
-    mutable std::atomic<int32_t> mCount;
-};
-
-// This is a wrapper around LightRefBase that simply enforces a virtual
-// destructor to eliminate the template requirement of LightRefBase
-class VirtualLightRefBase : public LightRefBase<VirtualLightRefBase> {
-public:
-    virtual ~VirtualLightRefBase();
-};
-
-// ---------------------------------------------------------------------------
-
 template <typename T>
 class wp
 {
 public:
     typedef typename RefBase::weakref_type weakref_type;
-    
+
     inline wp() : m_ptr(0) { }
 
     wp(T* other);  // NOLINT(implicit)
@@ -403,31 +364,31 @@
     template<typename U> wp(const wp<U>& other);  // NOLINT(implicit)
 
     ~wp();
-    
+
     // Assignment
 
     wp& operator = (T* other);
     wp& operator = (const wp<T>& other);
     wp& operator = (const sp<T>& other);
-    
+
     template<typename U> wp& operator = (U* other);
     template<typename U> wp& operator = (const wp<U>& other);
     template<typename U> wp& operator = (const sp<U>& other);
-    
+
     void set_object_and_refs(T* other, weakref_type* refs);
 
     // promotion to sp
-    
+
     sp<T> promote() const;
 
     // Reset
-    
+
     void clear();
 
     // Accessors
-    
+
     inline  weakref_type* get_refs() const { return m_refs; }
-    
+
     inline  T* unsafe_get() const { return m_ptr; }
 
     // Operators
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 77b173d..28406c8 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -599,7 +599,7 @@
 
 on nonencrypted
     # A/B update verifier that marks a successful boot.
-    exec - root cache -- /system/bin/update_verifier nonencrypted
+    exec_start update_verifier_nonencrypted
     class_start main
     class_start late_start
 
@@ -622,12 +622,12 @@
 
 on property:vold.decrypt=trigger_restart_min_framework
     # A/B update verifier that marks a successful boot.
-    exec - root cache -- /system/bin/update_verifier trigger_restart_min_framework
+    exec_start update_verifier
     class_start main
 
 on property:vold.decrypt=trigger_restart_framework
     # A/B update verifier that marks a successful boot.
-    exec - root cache -- /system/bin/update_verifier trigger_restart_framework
+    exec_start update_verifier
     class_start main
     class_start late_start