Merge "Define current ABI string in android-base/macros.h"
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 9f23473..d126f52 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -1588,9 +1588,13 @@
         } else {
             return 0;
         }
-    }
-    else if (!strcmp(argv[0], "tcpip") && argc > 1) {
-        return adb_connect_command(android::base::StringPrintf("tcpip:%s", argv[1]));
+    } else if (!strcmp(argv[0], "tcpip")) {
+        if (argc != 2) return syntax_error("tcpip requires an argument");
+        int port;
+        if (!android::base::ParseInt(argv[1], &port, 1, 65535)) {
+            return syntax_error("tcpip: invalid port: %s", argv[1]);
+        }
+        return adb_connect_command(android::base::StringPrintf("tcpip:%d", port));
     }
     else if (!strcmp(argv[0], "remount") ||
              !strcmp(argv[0], "reboot") ||
diff --git a/adb/test_adb.py b/adb/test_adb.py
index cb3e0d8..98c8a59 100644
--- a/adb/test_adb.py
+++ b/adb/test_adb.py
@@ -60,13 +60,13 @@
                              stderr=subprocess.STDOUT)
         out, _ = p.communicate()
         self.assertEqual(1, p.returncode)
-        self.assertIn('help message', out)
+        self.assertIn('requires an argument', out)
 
         p = subprocess.Popen(['adb', 'tcpip', 'foo'], stdout=subprocess.PIPE,
                              stderr=subprocess.STDOUT)
         out, _ = p.communicate()
         self.assertEqual(1, p.returncode)
-        self.assertIn('error', out)
+        self.assertIn('invalid port', out)
 
     # Helper method that reads a pipe until it is closed, then sets the event.
     def _read_pipe_and_set_event(self, pipe, event):
diff --git a/base/Android.bp b/base/Android.bp
index 1395756..82aee2a 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -40,6 +40,10 @@
     name: "libbase",
     vendor_available: true,
     host_supported: true,
+    vndk: {
+        enabled: true,
+        support_system_process: true,
+    },
     srcs: [
         "file.cpp",
         "logging.cpp",
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 49d9438..5f2267c 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -1463,7 +1463,7 @@
 
     if (fs_generator_generate(gen, output.path, size, initial_dir,
             eraseBlkSize, logicalBlkSize)) {
-        fprintf(stderr, "Cannot generate image: %s\n", strerror(errno));
+        die("Cannot generate image for %s\n", partition);
         return;
     }
 
diff --git a/init/Android.bp b/init/Android.bp
index b1f0279..efa5a02 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -54,6 +54,9 @@
                 "-DSHUTDOWN_ZERO_TIMEOUT=1",
             ],
         },
+        uml: {
+            cppflags: ["-DUSER_MODE_LINUX"],
+        }
     },
 }
 
diff --git a/init/Android.mk b/init/Android.mk
index 3886ed5..23ada73 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -30,10 +30,6 @@
 
 init_options += -DLOG_UEVENTS=0
 
-ifeq ($(TARGET_USER_MODE_LINUX), true)
-    init_cflags += -DUSER_MODE_LINUX
-endif
-
 init_cflags += \
     $(init_options) \
     -Wall -Wextra \
diff --git a/init/action.cpp b/init/action.cpp
index f687074..60204a8 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -91,14 +91,25 @@
     auto result = command.InvokeFunc();
     auto duration = t.duration();
 
+    // There are many legacy paths in rootdir/init.rc that will virtually never exist on a new
+    // device, such as '/sys/class/leds/jogball-backlight/brightness'.  As of this writing, there
+    // are 198 such failures on bullhead.  Instead of spamming the log reporting them, we do not
+    // report such failures unless we're running at the DEBUG log level.
+    bool report_failure = !result.has_value();
+    if (report_failure && android::base::GetMinimumLogSeverity() > android::base::DEBUG &&
+        result.error_errno() == ENOENT) {
+        report_failure = false;
+    }
+
     // Any action longer than 50ms will be warned to user as slow operation
-    if (duration > 50ms || android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
+    if (report_failure || duration > 50ms ||
+        android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
         std::string trigger_name = BuildTriggersString();
         std::string cmd_str = command.BuildCommandString();
 
         LOG(INFO) << "Command '" << cmd_str << "' action=" << trigger_name << " (" << filename_
                   << ":" << command.line() << ") took " << duration.count() << "ms and "
-                  << (result ? "succeeded" : "failed: " + result.error());
+                  << (result ? "succeeded" : "failed: " + result.error_string());
     }
 }
 
diff --git a/init/builtins.cpp b/init/builtins.cpp
index f807343..54ccf09 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -127,7 +127,9 @@
     Service* svc = ServiceList::GetInstance().FindService(args[1]);
     if (!svc) return Error() << "Could not find service";
 
-    if (!svc->Enable()) return Error() << "Could not enable service";
+    if (auto result = svc->Enable(); !result) {
+        return Error() << "Could not enable service: " << result.error();
+    }
 
     return Success();
 }
@@ -137,8 +139,8 @@
     if (!service) {
         return Error() << "Could not create exec service";
     }
-    if (!service->ExecStart()) {
-        return Error() << "Could not start exec service";
+    if (auto result = service->ExecStart(); !result) {
+        return Error() << "Could not start exec service: " << result.error();
     }
 
     ServiceList::GetInstance().AddService(std::move(service));
@@ -151,16 +153,16 @@
         return Error() << "Service not found";
     }
 
-    if (!service->ExecStart()) {
-        return Error() << "Could not start Service";
+    if (auto result = service->ExecStart(); !result) {
+        return Error() << "Could not start exec service: " << result.error();
     }
 
     return Success();
 }
 
 static Result<Success> do_export(const std::vector<std::string>& args) {
-    if (!add_environment(args[1].c_str(), args[2].c_str())) {
-        return Error();
+    if (setenv(args[1].c_str(), args[2].c_str(), 1) == -1) {
+        return ErrnoError() << "setenv() failed";
     }
     return Success();
 }
@@ -583,7 +585,9 @@
 static Result<Success> do_start(const std::vector<std::string>& args) {
     Service* svc = ServiceList::GetInstance().FindService(args[1]);
     if (!svc) return Error() << "service " << args[1] << " not found";
-    if (!svc->Start()) return Error() << "failed to start service";
+    if (auto result = svc->Start(); !result) {
+        return Error() << "Could not start service: " << result.error();
+    }
     return Success();
 }
 
@@ -608,6 +612,11 @@
 
 static Result<Success> do_symlink(const std::vector<std::string>& args) {
     if (symlink(args[1].c_str(), args[2].c_str()) < 0) {
+        // The symlink builtin is often used to create symlinks for older devices to be backwards
+        // compatible with new paths, therefore we skip reporting this error.
+        if (errno == EEXIST && android::base::GetMinimumLogSeverity() > android::base::DEBUG) {
+            return Success();
+        }
         return ErrnoError() << "symlink() failed";
     }
     return Success();
diff --git a/init/descriptors.cpp b/init/descriptors.cpp
index cc5b948..6265687 100644
--- a/init/descriptors.cpp
+++ b/init/descriptors.cpp
@@ -28,7 +28,6 @@
 #include <cutils/android_get_control_file.h>
 #include <cutils/sockets.h>
 
-#include "init.h"
 #include "util.h"
 
 namespace android {
@@ -62,7 +61,7 @@
                 [] (char& c) { c = isalnum(c) ? c : '_'; });
 
   std::string val = std::to_string(fd);
-  add_environment(publishedName.c_str(), val.c_str());
+  setenv(publishedName.c_str(), val.c_str(), 1);
 
   // make sure we don't close on exec
   fcntl(fd, F_SETFD, 0);
diff --git a/init/init.cpp b/init/init.cpp
index d0afac1..e1bd3a2 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -71,8 +71,6 @@
 
 std::string default_console = "/dev/console";
 
-const char *ENV[32];
-
 static int epoll_fd = -1;
 
 static std::unique_ptr<Timer> waiting_for_prop(nullptr);
@@ -126,38 +124,6 @@
     }
 }
 
-/* add_environment - add "key=value" to the current environment */
-int add_environment(const char *key, const char *val)
-{
-    size_t n;
-    size_t key_len = strlen(key);
-
-    /* The last environment entry is reserved to terminate the list */
-    for (n = 0; n < (arraysize(ENV) - 1); n++) {
-
-        /* Delete any existing entry for this key */
-        if (ENV[n] != NULL) {
-            size_t entry_key_len = strcspn(ENV[n], "=");
-            if ((entry_key_len == key_len) && (strncmp(ENV[n], key, entry_key_len) == 0)) {
-                free((char*)ENV[n]);
-                ENV[n] = NULL;
-            }
-        }
-
-        /* Add entry if a free slot is available */
-        if (ENV[n] == NULL) {
-            char* entry;
-            asprintf(&entry, "%s=%s", key, val);
-            ENV[n] = entry;
-            return 0;
-        }
-    }
-
-    LOG(ERROR) << "No env. room to store: '" << key << "':'" << val << "'";
-
-    return -1;
-}
-
 bool start_waiting_for_property(const char *name, const char *value)
 {
     if (waiting_for_prop) {
@@ -429,8 +395,6 @@
         install_reboot_signal_handlers();
     }
 
-    add_environment("PATH", _PATH_DEFPATH);
-
     bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
 
     if (is_first_stage) {
@@ -439,6 +403,8 @@
         // Clear the umask.
         umask(0);
 
+        clearenv();
+        setenv("PATH", _PATH_DEFPATH, 1);
         // Get the basic filesystem setup we need put together in the initramdisk
         // on / and then we'll let the rc file figure out the rest.
         mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
diff --git a/init/init.h b/init/init.h
index 50a7c83..b757c1d 100644
--- a/init/init.h
+++ b/init/init.h
@@ -30,9 +30,7 @@
 // Note: These globals are *only* valid in init, so they should not be used in ueventd,
 // watchdogd, or any files that may be included in those, such as devices.cpp and util.cpp.
 // TODO: Have an Init class and remove all globals.
-extern const char *ENV[32];
 extern std::string default_console;
-
 extern std::vector<std::string> late_import_paths;
 
 Parser CreateParser(ActionManager& action_manager, ServiceList& service_list);
@@ -43,8 +41,6 @@
 
 void register_epoll_handler(int fd, void (*fn)());
 
-int add_environment(const char* key, const char* val);
-
 bool start_waiting_for_property(const char *name, const char *value);
 
 void DumpState();
diff --git a/init/result.h b/init/result.h
index 64fa69f..36c3b83 100644
--- a/init/result.h
+++ b/init/result.h
@@ -21,9 +21,13 @@
 // There are 3 classes that implement this functionality and one additional helper type.
 //
 // Result<T> either contains a member of type T that can be accessed using similar semantics as
-// std::optional<T> or it contains a std::string describing an error, which can be accessed via
+// std::optional<T> or it contains a ResultError describing an error, which can be accessed via
 // Result<T>::error().
 //
+// ResultError is a type that contains both a std::string describing the error and a copy of errno
+// from when the error occurred.  ResultError can be used in an ostream directly to print its
+// string value.
+//
 // Success is a typedef that aids in creating Result<T> that do not contain a return value.
 // Result<Success> is the correct return type for a function that either returns successfully or
 // returns an error value.  Returning Success() from a function that returns Result<Success> is the
@@ -33,10 +37,20 @@
 // to T or from the constructor arguments for T.  This allows you to return a type T directly from
 // a function that returns Result<T>.
 //
-// Error and ErrnoError are used to construct a Result<T> that has failed.  Each of these classes
-// take an ostream as an input and are implicitly cast to a Result<T> containing that failure.
-// ErrnoError() additionally appends ": " + strerror(errno) to the end of the failure string to aid
-// in interacting with C APIs.
+// Error and ErrnoError are used to construct a Result<T> that has failed.  The Error class takes
+// an ostream as an input and are implicitly cast to a Result<T> containing that failure.
+// ErrnoError() is a helper function to create an Error class that appends ": " + strerror(errno)
+// to the end of the failure string to aid in interacting with C APIs.  Alternatively, an errno
+// value can be directly specified via the Error() constructor.
+//
+// ResultError can be used in the ostream when using Error to construct a Result<T>.  In this case,
+// the string that the ResultError takes is passed through the stream normally, but the errno is
+// passed to the Result<T>.  This can be used to pass errno from a failing C function up multiple
+// callers.
+//
+// ResultError can also directly construct a Result<T>.  This is particularly useful if you have a
+// function that return Result<T> but you have a Result<U> and want to return its error.  In this
+// case, you can return the .error() from the Result<U> to construct the Result<T>.
 
 // An example of how to use these is below:
 // Result<U> CalculateResult(const T& input) {
@@ -66,9 +80,29 @@
 namespace android {
 namespace init {
 
+struct ResultError {
+    template <typename T>
+    ResultError(T&& error_string, int error_errno)
+        : error_string(std::forward<T>(error_string)), error_errno(error_errno) {}
+
+    std::string error_string;
+    int error_errno;
+};
+
+inline std::ostream& operator<<(std::ostream& os, const ResultError& t) {
+    os << t.error_string;
+    return os;
+}
+
+inline std::ostream& operator<<(std::ostream& os, ResultError&& t) {
+    os << std::move(t.error_string);
+    return os;
+}
+
 class Error {
   public:
-    Error() : append_errno_(0) {}
+    Error() : errno_(0), append_errno_(false) {}
+    Error(int errno_to_append) : errno_(errno_to_append), append_errno_(true) {}
 
     template <typename T>
     Error&& operator<<(T&& t) {
@@ -76,30 +110,45 @@
         return std::move(*this);
     }
 
-    const std::string str() const {
-        if (append_errno_) {
-            return ss_.str() + ": " + strerror(append_errno_);
-        }
-        return ss_.str();
+    Error&& operator<<(const ResultError& result_error) {
+        ss_ << result_error.error_string;
+        errno_ = result_error.error_errno;
+        return std::move(*this);
     }
 
+    Error&& operator<<(ResultError&& result_error) {
+        ss_ << std::move(result_error.error_string);
+        errno_ = result_error.error_errno;
+        return std::move(*this);
+    }
+
+    const std::string str() const {
+        std::string str = ss_.str();
+        if (append_errno_) {
+            if (str.empty()) {
+                return strerror(errno_);
+            }
+            return str + ": " + strerror(errno_);
+        }
+        return str;
+    }
+
+    int get_errno() const { return errno_; }
+
     Error(const Error&) = delete;
     Error(Error&&) = delete;
     Error& operator=(const Error&) = delete;
     Error& operator=(Error&&) = delete;
 
-  protected:
-    Error(int append_errno) : append_errno_(append_errno) {}
-
   private:
     std::stringstream ss_;
-    int append_errno_;
+    int errno_;
+    bool append_errno_;
 };
 
-class ErrnoError : public Error {
-  public:
-    ErrnoError() : Error(errno) {}
-};
+inline Error ErrnoError() {
+    return Error(errno);
+}
 
 template <typename T>
 class Result {
@@ -107,7 +156,13 @@
     template <typename... U>
     Result(U&&... result) : contents_(std::in_place_index_t<0>(), std::forward<U>(result)...) {}
 
-    Result(Error&& fb) : contents_(std::in_place_index_t<1>(), fb.str()) {}
+    Result(Error&& error) : contents_(std::in_place_index_t<1>(), error.str(), error.get_errno()) {}
+    Result(const ResultError& result_error)
+        : contents_(std::in_place_index_t<1>(), result_error.error_string,
+                    result_error.error_errno) {}
+    Result(ResultError&& result_error)
+        : contents_(std::in_place_index_t<1>(), std::move(result_error.error_string),
+                    result_error.error_errno) {}
 
     bool has_value() const { return contents_.index() == 0; }
 
@@ -116,9 +171,17 @@
     T&& value() && { return std::get<0>(std::move(contents_)); }
     const T&& value() const && { return std::get<0>(std::move(contents_)); }
 
-    const std::string& error() const & { return std::get<1>(contents_); }
-    std::string&& error() && { return std::get<1>(std::move(contents_)); }
-    const std::string&& error() const && { return std::get<1>(std::move(contents_)); }
+    const ResultError& error() const & { return std::get<1>(contents_); }
+    ResultError&& error() && { return std::get<1>(std::move(contents_)); }
+    const ResultError&& error() const && { return std::get<1>(std::move(contents_)); }
+
+    const std::string& error_string() const & { return std::get<1>(contents_).error_string; }
+    std::string&& error_string() && { return std::get<1>(std::move(contents_)).error_string; }
+    const std::string&& error_string() const && {
+        return std::get<1>(std::move(contents_)).error_string;
+    }
+
+    int error_errno() const { return std::get<1>(contents_).error_errno; }
 
     explicit operator bool() const { return has_value(); }
 
@@ -131,7 +194,7 @@
     const T* operator->() const { return &value(); }
 
   private:
-    std::variant<T, std::string> contents_;
+    std::variant<T, ResultError> contents_;
 };
 
 using Success = std::monostate;
diff --git a/init/result_test.cpp b/init/result_test.cpp
index ca65013..19caaf5 100644
--- a/init/result_test.cpp
+++ b/init/result_test.cpp
@@ -74,7 +74,8 @@
     ASSERT_FALSE(result);
     ASSERT_FALSE(result.has_value());
 
-    EXPECT_EQ("failure1", result.error());
+    EXPECT_EQ(0, result.error_errno());
+    EXPECT_EQ("failure1", result.error_string());
 }
 
 TEST(result, result_error_empty) {
@@ -82,7 +83,8 @@
     ASSERT_FALSE(result);
     ASSERT_FALSE(result.has_value());
 
-    EXPECT_EQ("", result.error());
+    EXPECT_EQ(0, result.error_errno());
+    EXPECT_EQ("", result.error_string());
 }
 
 TEST(result, result_error_rvalue) {
@@ -96,7 +98,8 @@
     ASSERT_FALSE(MakeRvalueErrorResult());
     ASSERT_FALSE(MakeRvalueErrorResult().has_value());
 
-    EXPECT_EQ("failure1", MakeRvalueErrorResult().error());
+    EXPECT_EQ(0, MakeRvalueErrorResult().error_errno());
+    EXPECT_EQ("failure1", MakeRvalueErrorResult().error_string());
 }
 
 TEST(result, result_errno_error) {
@@ -107,7 +110,72 @@
     ASSERT_FALSE(result);
     ASSERT_FALSE(result.has_value());
 
-    EXPECT_EQ("failure1: "s + strerror(test_errno), result.error());
+    EXPECT_EQ(test_errno, result.error_errno());
+    EXPECT_EQ("failure1: "s + strerror(test_errno), result.error_string());
+}
+
+TEST(result, result_errno_error_no_text) {
+    constexpr int test_errno = 6;
+    errno = test_errno;
+    Result<Success> result = ErrnoError();
+
+    ASSERT_FALSE(result);
+    ASSERT_FALSE(result.has_value());
+
+    EXPECT_EQ(test_errno, result.error_errno());
+    EXPECT_EQ(strerror(test_errno), result.error_string());
+}
+
+TEST(result, result_error_from_other_result) {
+    auto error_text = "test error"s;
+    Result<Success> result = Error() << error_text;
+
+    ASSERT_FALSE(result);
+    ASSERT_FALSE(result.has_value());
+
+    Result<std::string> result2 = result.error();
+
+    ASSERT_FALSE(result2);
+    ASSERT_FALSE(result2.has_value());
+
+    EXPECT_EQ(0, result.error_errno());
+    EXPECT_EQ(error_text, result.error_string());
+}
+
+TEST(result, result_error_through_ostream) {
+    auto error_text = "test error"s;
+    Result<Success> result = Error() << error_text;
+
+    ASSERT_FALSE(result);
+    ASSERT_FALSE(result.has_value());
+
+    Result<std::string> result2 = Error() << result.error();
+
+    ASSERT_FALSE(result2);
+    ASSERT_FALSE(result2.has_value());
+
+    EXPECT_EQ(0, result.error_errno());
+    EXPECT_EQ(error_text, result.error_string());
+}
+
+TEST(result, result_errno_error_through_ostream) {
+    auto error_text = "test error"s;
+    constexpr int test_errno = 6;
+    errno = 6;
+    Result<Success> result = ErrnoError() << error_text;
+
+    errno = 0;
+
+    ASSERT_FALSE(result);
+    ASSERT_FALSE(result.has_value());
+
+    Result<std::string> result2 = Error() << result.error();
+
+    ASSERT_FALSE(result2);
+    ASSERT_FALSE(result2.has_value());
+
+    EXPECT_EQ(test_errno, result.error_errno());
+    EXPECT_EQ(error_text + ": " + strerror(test_errno), result.error_string());
 }
 
 TEST(result, constructor_forwarding) {
@@ -215,7 +283,7 @@
 
 TEST(result, die_on_get_error_succesful_result) {
     Result<std::string> result = "success";
-    ASSERT_DEATH(result.error(), "");
+    ASSERT_DEATH(result.error_string(), "");
 }
 
 }  // namespace init
diff --git a/init/selinux.cpp b/init/selinux.cpp
index c824028..ef59164 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -48,7 +48,6 @@
 #include "selinux.h"
 
 #include <fcntl.h>
-#include <paths.h>
 #include <stdlib.h>
 #include <sys/wait.h>
 #include <unistd.h>
@@ -126,8 +125,7 @@
         }
         TEMP_FAILURE_RETRY(close(pipe_fds[1]));
 
-        const char* envp[] = {_PATH_DEFPATH, nullptr};
-        if (execve(filename, argv, (char**)envp) == -1) {
+        if (execv(filename, argv) == -1) {
             PLOG(ERROR) << "Failed to execve " << filename;
             return false;
         }
diff --git a/init/service.cpp b/init/service.cpp
index 6ab60e3..d3c9f92 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -57,22 +57,20 @@
 namespace android {
 namespace init {
 
-static std::string ComputeContextFromExecutable(std::string& service_name,
-                                                const std::string& service_path) {
+static Result<std::string> ComputeContextFromExecutable(std::string& service_name,
+                                                        const std::string& service_path) {
     std::string computed_context;
 
     char* raw_con = nullptr;
     char* raw_filecon = nullptr;
 
     if (getcon(&raw_con) == -1) {
-        LOG(ERROR) << "could not get context while starting '" << service_name << "'";
-        return "";
+        return Error() << "Could not get security context";
     }
     std::unique_ptr<char> mycon(raw_con);
 
     if (getfilecon(service_path.c_str(), &raw_filecon) == -1) {
-        LOG(ERROR) << "could not get file context while starting '" << service_name << "'";
-        return "";
+        return Error() << "Could not get file context";
     }
     std::unique_ptr<char> filecon(raw_filecon);
 
@@ -84,12 +82,10 @@
         free(new_con);
     }
     if (rc == 0 && computed_context == mycon.get()) {
-        LOG(ERROR) << "service " << service_name << " does not have a SELinux domain defined";
-        return "";
+        return Error() << "Service does not have an SELinux domain defined";
     }
     if (rc < 0) {
-        LOG(ERROR) << "could not get context while starting '" << service_name << "'";
-        return "";
+        return Error() << "Could not get process context";
     }
     return computed_context;
 }
@@ -147,14 +143,6 @@
     strs->push_back(nullptr);
 }
 
-ServiceEnvironmentInfo::ServiceEnvironmentInfo() {
-}
-
-ServiceEnvironmentInfo::ServiceEnvironmentInfo(const std::string& name,
-                                               const std::string& value)
-    : name(name), value(value) {
-}
-
 unsigned long Service::next_start_order_ = 1;
 bool Service::is_exec_service_running_ = false;
 
@@ -507,7 +495,7 @@
 }
 
 Result<Success> Service::ParseSetenv(const std::vector<std::string>& args) {
-    envvars_.emplace_back(args[1], args[2]);
+    environment_vars_.emplace_back(args[1], args[2]);
     return Success();
 }
 
@@ -637,16 +625,16 @@
     static const OptionParserMap parser_map;
     auto parser = parser_map.FindFunction(args);
 
-    if (!parser) return Error() << parser.error();
+    if (!parser) return parser.error();
 
     return std::invoke(*parser, this, args);
 }
 
-bool Service::ExecStart() {
+Result<Success> Service::ExecStart() {
     flags_ |= SVC_ONESHOT;
 
-    if (!Start()) {
-        return false;
+    if (auto result = Start(); !result) {
+        return result;
     }
 
     flags_ |= SVC_EXEC;
@@ -656,10 +644,10 @@
               << supp_gids_.size() << " context " << (!seclabel_.empty() ? seclabel_ : "default")
               << ") started; waiting...";
 
-    return true;
+    return Success();
 }
 
-bool Service::Start() {
+Result<Success> 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.
     flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
@@ -668,7 +656,8 @@
     // process of exiting, we've ensured that they will immediately restart
     // on exit, unless they are ONESHOT.
     if (flags_ & SVC_RUNNING) {
-        return false;
+        // It is not an error to try to start a service that is already running.
+        return Success();
     }
 
     bool needs_console = (flags_ & SVC_CONSOLE);
@@ -681,28 +670,27 @@
         // properly registered for the device node
         int console_fd = open(console_.c_str(), O_RDWR | O_CLOEXEC);
         if (console_fd < 0) {
-            PLOG(ERROR) << "service '" << name_ << "' couldn't open console '" << console_ << "'";
             flags_ |= SVC_DISABLED;
-            return false;
+            return ErrnoError() << "Couldn't open console '" << console_ << "'";
         }
         close(console_fd);
     }
 
     struct stat sb;
     if (stat(args_[0].c_str(), &sb) == -1) {
-        PLOG(ERROR) << "cannot find '" << args_[0] << "', disabling '" << name_ << "'";
         flags_ |= SVC_DISABLED;
-        return false;
+        return ErrnoError() << "Cannot find '" << args_[0] << "'";
     }
 
     std::string scon;
     if (!seclabel_.empty()) {
         scon = seclabel_;
     } else {
-        scon = ComputeContextFromExecutable(name_, args_[0]);
-        if (scon == "") {
-            return false;
+        auto result = ComputeContextFromExecutable(name_, args_[0]);
+        if (!result) {
+            return result.error();
         }
+        scon = *result;
     }
 
     LOG(INFO) << "starting service '" << name_ << "'...";
@@ -723,8 +711,8 @@
             SetUpPidNamespace(name_);
         }
 
-        for (const auto& ei : envvars_) {
-            add_environment(ei.name.c_str(), ei.value.c_str());
+        for (const auto& [key, value] : environment_vars_) {
+            setenv(key.c_str(), value.c_str(), 1);
         }
 
         std::for_each(descriptors_.begin(), descriptors_.end(),
@@ -779,7 +767,7 @@
 
         std::vector<char*> strs;
         ExpandArgs(args_, &strs);
-        if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) {
+        if (execv(strs[0], (char**)&strs[0]) < 0) {
             PLOG(ERROR) << "cannot execve('" << strs[0] << "')";
         }
 
@@ -787,9 +775,8 @@
     }
 
     if (pid < 0) {
-        PLOG(ERROR) << "failed to fork for '" << name_ << "'";
         pid_ = 0;
-        return false;
+        return ErrnoError() << "Failed to fork";
     }
 
     if (oom_score_adjust_ != -1000) {
@@ -831,24 +818,24 @@
     }
 
     NotifyStateChange("running");
-    return true;
+    return Success();
 }
 
-bool Service::StartIfNotDisabled() {
+Result<Success> Service::StartIfNotDisabled() {
     if (!(flags_ & SVC_DISABLED)) {
         return Start();
     } else {
         flags_ |= SVC_DISABLED_START;
     }
-    return true;
+    return Success();
 }
 
-bool Service::Enable() {
+Result<Success> Service::Enable() {
     flags_ &= ~(SVC_DISABLED | SVC_RC_DISABLED);
     if (flags_ & SVC_DISABLED_START) {
         return Start();
     }
-    return true;
+    return Success();
 }
 
 void Service::Reset() {
@@ -874,7 +861,9 @@
         StopOrReset(SVC_RESTART);
     } else if (!(flags_ & SVC_RESTARTING)) {
         /* Just start the service since it's not running. */
-        Start();
+        if (auto result = Start(); !result) {
+            LOG(ERROR) << "Could not restart '" << name_ << "': " << result.error();
+        }
     } /* else: Service is restarting anyways. */
 }
 
diff --git a/init/service.h b/init/service.h
index fe85129..1f2c44f 100644
--- a/init/service.h
+++ b/init/service.h
@@ -57,13 +57,6 @@
 namespace android {
 namespace init {
 
-struct ServiceEnvironmentInfo {
-    ServiceEnvironmentInfo();
-    ServiceEnvironmentInfo(const std::string& name, const std::string& value);
-    std::string name;
-    std::string value;
-};
-
 class Service {
   public:
     Service(const std::string& name, const std::vector<std::string>& args);
@@ -77,10 +70,10 @@
 
     bool IsRunning() { return (flags_ & SVC_RUNNING) != 0; }
     Result<Success> ParseLine(const std::vector<std::string>& args);
-    bool ExecStart();
-    bool Start();
-    bool StartIfNotDisabled();
-    bool Enable();
+    Result<Success> ExecStart();
+    Result<Success> Start();
+    Result<Success> StartIfNotDisabled();
+    Result<Success> Enable();
     void Reset();
     void Stop();
     void Terminate();
@@ -178,7 +171,7 @@
     std::string seclabel_;
 
     std::vector<std::unique_ptr<DescriptorInfo>> descriptors_;
-    std::vector<ServiceEnvironmentInfo> envvars_;
+    std::vector<std::pair<std::string, std::string>> environment_vars_;
 
     Action onrestart_;  // Commands to execute on restart.
 
diff --git a/init/util_test.cpp b/init/util_test.cpp
index 007d10e..3ae53a4 100644
--- a/init/util_test.cpp
+++ b/init/util_test.cpp
@@ -34,7 +34,7 @@
     auto file_contents = ReadFile("/proc/does-not-exist");
     EXPECT_EQ(ENOENT, errno);
     ASSERT_FALSE(file_contents);
-    EXPECT_EQ("open() failed: No such file or directory", file_contents.error());
+    EXPECT_EQ("open() failed: No such file or directory", file_contents.error_string());
 }
 
 TEST(util, ReadFileGroupWriteable) {
@@ -45,7 +45,7 @@
     EXPECT_NE(-1, fchmodat(AT_FDCWD, tf.path, 0620, AT_SYMLINK_NOFOLLOW)) << strerror(errno);
     auto file_contents = ReadFile(tf.path);
     ASSERT_FALSE(file_contents) << strerror(errno);
-    EXPECT_EQ("Skipping insecure file", file_contents.error());
+    EXPECT_EQ("Skipping insecure file", file_contents.error_string());
 }
 
 TEST(util, ReadFileWorldWiteable) {
@@ -56,7 +56,7 @@
     EXPECT_NE(-1, fchmodat(AT_FDCWD, tf.path, 0602, AT_SYMLINK_NOFOLLOW)) << strerror(errno);
     auto file_contents = ReadFile(tf.path);
     ASSERT_FALSE(file_contents) << strerror(errno);
-    EXPECT_EQ("Skipping insecure file", file_contents.error());
+    EXPECT_EQ("Skipping insecure file", file_contents.error_string());
 }
 
 TEST(util, ReadFileSymbolicLink) {
@@ -65,7 +65,7 @@
     auto file_contents = ReadFile("/charger");
     EXPECT_EQ(ELOOP, errno);
     ASSERT_FALSE(file_contents);
-    EXPECT_EQ("open() failed: Too many symbolic links encountered", file_contents.error());
+    EXPECT_EQ("open() failed: Too many symbolic links encountered", file_contents.error_string());
 }
 
 TEST(util, ReadFileSuccess) {
@@ -130,7 +130,7 @@
 
     decoded_uid = DecodeUid("toot");
     EXPECT_FALSE(decoded_uid);
-    EXPECT_EQ("getpwnam failed: No such file or directory", decoded_uid.error());
+    EXPECT_EQ("getpwnam failed: No such file or directory", decoded_uid.error_string());
 
     decoded_uid = DecodeUid("123");
     EXPECT_TRUE(decoded_uid);
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index c58d777..02e0487 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -66,6 +66,10 @@
 cc_library {
     name: "libbacktrace",
     vendor_available: true,
+    vndk: {
+        enabled: true,
+        support_system_process: true,
+    },
     defaults: ["libbacktrace_common"],
     host_supported: true,
 
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 8528a4b..cfe8d29 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -50,6 +50,10 @@
 cc_library {
     name: "libcutils",
     vendor_available: true,
+    vndk: {
+        enabled: true,
+        support_system_process: true,
+    },
     host_supported: true,
     srcs: [
         "config_utils.c",
diff --git a/libion/Android.bp b/libion/Android.bp
index 6f267e4..6d9fae0 100644
--- a/libion/Android.bp
+++ b/libion/Android.bp
@@ -1,7 +1,11 @@
 
 cc_library {
     name: "libion",
-		vendor_available: true,
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+        support_system_process: true,
+    },
     srcs: ["ion.c"],
     shared_libs: ["liblog"],
     local_include_dirs: [
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 7d293ef..adcde81 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -44,6 +44,10 @@
 cc_library {
     name: "libutils",
     vendor_available: true,
+    vndk: {
+        enabled: true,
+        support_system_process: true,
+    },
     host_supported: true,
 
     srcs: [