Merge "Refine set_sched_policy behavior"
diff --git a/adb/Android.bp b/adb/Android.bp
index 7c5e3ea..675525c 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -160,6 +160,11 @@
     // libadbconnection_client doesn't need an embedded build number.
     use_version_lib: false,
 
+    target: {
+        linux: {
+            version_script: "adbconnection/libadbconnection_client.map.txt",
+        },
+    },
     stubs: {
         symbol_file: "adbconnection/libadbconnection_client.map.txt",
         versions: ["1"],
@@ -319,6 +324,7 @@
 cc_binary_host {
     name: "adb",
 
+    stl: "libc++_static",
     defaults: ["adb_defaults"],
 
     srcs: [
@@ -359,8 +365,6 @@
         "libz",
     ],
 
-    stl: "libc++_static",
-
     // Don't add anything here, we don't want additional shared dependencies
     // on the host adb tool, and shared libraries that link against libc++
     // will violate ODR
@@ -538,6 +542,7 @@
 cc_binary {
     name: "adbd",
     defaults: ["adbd_defaults", "host_adbd_supported"],
+    stl: "libc++_static",
     recovery_available: true,
 
     srcs: [
@@ -553,11 +558,9 @@
         keep_symbols: true,
     },
 
-    stl: "libc++_static",
     static_libs: [
         "libadbconnection_server",
         "libadbd",
-        "libadbd_auth",
         "libadbd_services",
         "libasyncio",
         "libbase",
@@ -572,15 +575,17 @@
     ],
 
     shared_libs: [
+        "libadbd_auth",
         "libcrypto",
     ],
+
+    required: ["libadbd_auth"],
 }
 
 phony {
     name: "adbd_system_binaries",
     required: [
         "abb",
-        "libadbd_auth",
         "reboot",
         "set-verity-state",
     ]
@@ -597,6 +602,7 @@
     name: "abb",
 
     defaults: ["adbd_defaults"],
+    stl: "libc++",
     recovery_available: false,
 
     srcs: [
@@ -629,7 +635,11 @@
 
 cc_test {
     name: "adbd_test",
+
     defaults: ["adbd_defaults"],
+    stl: "libc++_static",
+
+    recovery_available: false,
     srcs: libadb_test_srcs + [
         "daemon/services.cpp",
         "daemon/shell_service.cpp",
@@ -651,7 +661,7 @@
         "libmdnssd",
         "libselinux",
     ],
-    test_suites: ["device-tests"],
+    test_suites: ["device-tests", "mts"],
     require_root: true,
 }
 
@@ -686,10 +696,10 @@
     test_suites: ["general-tests"],
     version: {
         py2: {
-            enabled: true,
+            enabled: false,
         },
         py3: {
-            enabled: false,
+            enabled: true,
         },
     },
 }
@@ -734,7 +744,6 @@
         "libziparchive",
         "libz",
     ],
-    stl: "libc++_static",
     proto: {
         type: "lite",
         export_proto_headers: true,
diff --git a/adb/apex/Android.bp b/adb/apex/Android.bp
index 75c4ed9..a6b1e78 100644
--- a/adb/apex/Android.bp
+++ b/adb/apex/Android.bp
@@ -21,7 +21,7 @@
 }
 
 // adbd apex with INT_MAX version code, to allow for upgrade/rollback testing.
-apex {
+apex_test {
     name: "test_com.android.adbd",
     defaults: ["com.android.adbd-defaults"],
     manifest: "test_apex_manifest.json",
diff --git a/adb/apex/ld.config.txt b/adb/apex/ld.config.txt
index d1858a4..ca297fe 100644
--- a/adb/apex/ld.config.txt
+++ b/adb/apex/ld.config.txt
@@ -5,16 +5,24 @@
 dir.adbd = /apex/com.android.adbd/bin/
 
 [adbd]
-additional.namespaces = platform,art
+additional.namespaces = apex,platform,art
 
 namespace.default.isolated = true
-namespace.default.search.paths = /apex/com.android.adbd/${LIB}
-namespace.default.asan.search.paths = /apex/com.android.adbd/${LIB}
 namespace.default.permitted.paths = /system/${LIB}
 namespace.default.asan.permitted.paths = /system/${LIB}
-namespace.default.links = art,platform
+namespace.default.links = apex,art,platform
+namespace.default.link.apex.shared_libs = libcrypto.so
 namespace.default.link.art.shared_libs = libadbconnection_server.so
-namespace.default.link.platform.shared_libs = libc.so:libdl.so:libm.so:libclang_rt.hwasan-aarch64-android.so
+
+# libcrypto.so in the APEX might be a symlink to /system, for APEXes bundled with the system image.
+# The dynamic linker works off of realpath, so we need to permit loading libcrypto.so from /system.
+namespace.default.link.platform.shared_libs = libc.so:libdl.so:libm.so:libclang_rt.hwasan-aarch64-android.so:liblog.so:libadbd_auth.so:libcrypto.so
+
+namespace.apex.isolated = true
+namespace.apex.search.paths = /apex/com.android.adbd/${LIB}
+namespace.apex.asan.search.paths = /apex/com.android.adbd/${LIB}
+namespace.apex.links = platform
+namespace.apex.link.platform.allow_all_shared_libs = true
 
 ###############################################################################
 # "art" APEX namespace: used for libadbdconnection_server
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index 73dcde1..2bcd0a6 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -227,16 +227,20 @@
         return 1;
     }
 
-    copy_to_file(local_fd.get(), remote_fd.get());
+    if (!copy_to_file(local_fd.get(), remote_fd.get())) {
+        fprintf(stderr, "adb: failed to install: copy_to_file: %s: %s", file, strerror(errno));
+        return 1;
+    }
 
     char buf[BUFSIZ];
     read_status_line(remote_fd.get(), buf, sizeof(buf));
-    if (!strncmp("Success", buf, 7)) {
-        fputs(buf, stdout);
-        return 0;
+    if (strncmp("Success", buf, 7) != 0) {
+        fprintf(stderr, "adb: failed to install %s: %s", file, buf);
+        return 1;
     }
-    fprintf(stderr, "adb: failed to install %s: %s", file, buf);
-    return 1;
+
+    fputs(buf, stdout);
+    return 0;
 }
 
 static int install_app_legacy(int argc, const char** argv, bool use_fastdeploy) {
@@ -455,7 +459,12 @@
             goto finalize_session;
         }
 
-        copy_to_file(local_fd.get(), remote_fd.get());
+        if (!copy_to_file(local_fd.get(), remote_fd.get())) {
+            fprintf(stderr, "adb: failed to write \"%s\": %s\n", file, strerror(errno));
+            success = false;
+            goto finalize_session;
+        }
+
         read_status_line(remote_fd.get(), buf, sizeof(buf));
 
         if (strncmp("Success", buf, 7)) {
@@ -634,7 +643,11 @@
                 goto finalize_multi_package_session;
             }
 
-            copy_to_file(local_fd.get(), remote_fd.get());
+            if (!copy_to_file(local_fd.get(), remote_fd.get())) {
+                fprintf(stderr, "adb: failed to write %s: %s\n", split.c_str(), strerror(errno));
+                goto finalize_multi_package_session;
+            }
+
             read_status_line(remote_fd.get(), buf, sizeof(buf));
 
             if (strncmp("Success", buf, 7)) {
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index a6d7e31..c302965 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -352,7 +352,8 @@
 #endif
 }
 
-void copy_to_file(int inFd, int outFd) {
+bool copy_to_file(int inFd, int outFd) {
+    bool result = true;
     std::vector<char> buf(64 * 1024);
     int len;
     long total = 0;
@@ -375,6 +376,7 @@
         }
         if (len < 0) {
             D("copy_to_file(): read failed: %s", strerror(errno));
+            result = false;
             break;
         }
         if (outFd == STDOUT_FILENO) {
@@ -388,7 +390,8 @@
 
     stdinout_raw_epilogue(inFd, outFd, old_stdin_mode, old_stdout_mode);
 
-    D("copy_to_file() finished after %lu bytes", total);
+    D("copy_to_file() finished with %s after %lu bytes", result ? "success" : "failure", total);
+    return result;
 }
 
 static void send_window_size_change(int fd, std::unique_ptr<ShellProtocol>& shell) {
diff --git a/adb/client/commandline.h b/adb/client/commandline.h
index ab77b29..b9dee56 100644
--- a/adb/client/commandline.h
+++ b/adb/client/commandline.h
@@ -100,7 +100,7 @@
 
 int adb_commandline(int argc, const char** argv);
 
-void copy_to_file(int inFd, int outFd);
+bool copy_to_file(int inFd, int outFd);
 
 // Connects to the device "shell" service with |command| and prints the
 // resulting output.
diff --git a/adb/test_device.py b/adb/test_device.py
index 083adce..6a9ff89 100755
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 #
 # Copyright (C) 2015 The Android Open Source Project
@@ -81,6 +81,13 @@
         self.device = adb.get_device()
 
 
+class AbbTest(DeviceTest):
+    def test_smoke(self):
+        result = subprocess.run(['adb', 'abb'], capture_output=True)
+        self.assertEqual(1, result.returncode)
+        expected_output = b"cmd: No service specified; use -l to list all services\n"
+        self.assertEqual(expected_output, result.stderr)
+
 class ForwardReverseTest(DeviceTest):
     def _test_no_rebind(self, description, direction_list, direction,
                        direction_no_rebind, direction_remove_all):
@@ -246,7 +253,7 @@
                     # Accept the client connection.
                     accepted_connection, addr = listener.accept()
                     with contextlib.closing(accepted_connection) as server:
-                        data = 'hello'
+                        data = b'hello'
 
                         # Send data into the port setup by adb forward.
                         client.sendall(data)
@@ -254,7 +261,7 @@
                         client.close()
 
                         # Verify that the data came back via adb reverse.
-                        self.assertEqual(data, server.makefile().read())
+                        self.assertEqual(data, server.makefile().read().encode("utf8"))
         finally:
             if reverse_setup:
                 self.device.reverse_remove(forward_spec)
@@ -268,7 +275,7 @@
 
         Args:
           shell_args: List of string arguments to `adb shell`.
-          input: String input to send to the interactive shell.
+          input: bytes input to send to the interactive shell.
 
         Returns:
           The remote exit code.
@@ -286,7 +293,7 @@
         # Closing host-side stdin doesn't trigger a PTY shell to exit so we need
         # to explicitly add an exit command to close the session from the device
         # side, plus the necessary newline to complete the interactive command.
-        proc.communicate(input + '; exit\n')
+        proc.communicate(input + b'; exit\n')
         return proc.returncode
 
     def test_cat(self):
@@ -419,7 +426,7 @@
         self.assertEqual('foo' + self.device.linesep, result[1])
         self.assertEqual('bar' + self.device.linesep, result[2])
 
-        self.assertEqual(17, self._interactive_shell([], 'exit 17'))
+        self.assertEqual(17, self._interactive_shell([], b'exit 17'))
 
         # -x flag should disable shell protocol.
         result = self.device.shell_nocheck(
@@ -428,7 +435,7 @@
         self.assertEqual('foo{0}bar{0}'.format(self.device.linesep), result[1])
         self.assertEqual('', result[2])
 
-        self.assertEqual(0, self._interactive_shell(['-x'], 'exit 17'))
+        self.assertEqual(0, self._interactive_shell(['-x'], b'exit 17'))
 
     def test_non_interactive_sigint(self):
         """Tests that SIGINT in a non-interactive shell kills the process.
@@ -447,7 +454,7 @@
                 self.device.adb_cmd + shlex.split('shell echo $$; sleep 60'),
                 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
                 stderr=subprocess.STDOUT)
-        remote_pid = sleep_proc.stdout.readline().strip()
+        remote_pid = sleep_proc.stdout.readline().strip().decode("utf8")
         self.assertIsNone(sleep_proc.returncode, 'subprocess terminated early')
         proc_query = shlex.split('ps {0} | grep {0}'.format(remote_pid))
 
@@ -469,9 +476,10 @@
                                     'on this device')
 
         # Test both small and large inputs.
-        small_input = 'foo'
-        large_input = '\n'.join(c * 100 for c in (string.ascii_letters +
-                                                  string.digits))
+        small_input = b'foo'
+        characters = [c.encode("utf8") for c in string.ascii_letters + string.digits]
+        large_input = b'\n'.join(characters)
+
 
         for input in (small_input, large_input):
             proc = subprocess.Popen(self.device.adb_cmd + ['shell', 'cat'],
@@ -480,7 +488,7 @@
                                     stderr=subprocess.PIPE)
             stdout, stderr = proc.communicate(input)
             self.assertEqual(input.splitlines(), stdout.splitlines())
-            self.assertEqual('', stderr)
+            self.assertEqual(b'', stderr)
 
     def test_sighup(self):
         """Ensure that SIGHUP gets sent upon non-interactive ctrl-c"""
@@ -502,7 +510,7 @@
                                           stdin=subprocess.PIPE,
                                           stdout=subprocess.PIPE)
 
-        self.assertEqual("Waiting\n", process.stdout.readline())
+        self.assertEqual(b"Waiting\n", process.stdout.readline())
         process.send_signal(signal.SIGINT)
         process.wait()
 
@@ -533,7 +541,7 @@
             threads.append(thread)
         for thread in threads:
             thread.join()
-        for i, success in result.iteritems():
+        for i, success in result.items():
             self.assertTrue(success)
 
     def disabled_test_parallel(self):
@@ -546,24 +554,24 @@
 
         n_procs = 2048
         procs = dict()
-        for i in xrange(0, n_procs):
+        for i in range(0, n_procs):
             procs[i] = subprocess.Popen(
                 ['adb', 'shell', 'read foo; echo $foo; read rc; exit $rc'],
                 stdin=subprocess.PIPE,
                 stdout=subprocess.PIPE
             )
 
-        for i in xrange(0, n_procs):
+        for i in range(0, n_procs):
             procs[i].stdin.write("%d\n" % i)
 
-        for i in xrange(0, n_procs):
+        for i in range(0, n_procs):
             response = procs[i].stdout.readline()
             assert(response == "%d\n" % i)
 
-        for i in xrange(0, n_procs):
+        for i in range(0, n_procs):
             procs[i].stdin.write("%d\n" % (i % 256))
 
-        for i in xrange(0, n_procs):
+        for i in range(0, n_procs):
             assert(procs[i].wait() == i % 256)
 
 
@@ -602,14 +610,14 @@
     def test_install_argument_escaping(self):
         """Make sure that install argument escaping works."""
         # http://b/20323053, http://b/3090932.
-        for file_suffix in ('-text;ls;1.apk', "-Live Hold'em.apk"):
+        for file_suffix in (b'-text;ls;1.apk', b"-Live Hold'em.apk"):
             tf = tempfile.NamedTemporaryFile('wb', suffix=file_suffix,
                                              delete=False)
             tf.close()
 
             # Installing bogus .apks fails if the device supports exit codes.
             try:
-                output = self.device.install(tf.name)
+                output = self.device.install(tf.name.decode("utf8"))
             except subprocess.CalledProcessError as e:
                 output = e.output
 
@@ -712,7 +720,7 @@
     max_size = 16 * (1 << 10)
 
     files = []
-    for _ in xrange(num_files):
+    for _ in range(num_files):
         file_handle = tempfile.NamedTemporaryFile(dir=in_dir, delete=False)
 
         size = random.randrange(min_size, max_size, 1024)
@@ -731,7 +739,7 @@
     max_size = 16 * (1 << 10)
 
     files = []
-    for file_num in xrange(num_files):
+    for file_num in range(num_files):
         size = random.randrange(min_size, max_size, 1024)
 
         base_name = prefix + str(file_num)
@@ -878,7 +886,7 @@
             subdir_temp_files = make_random_host_files(in_dir=subdir,
                                                        num_files=4)
 
-            paths = map(lambda temp_file: temp_file.full_path, temp_files)
+            paths = [x.full_path for x in temp_files]
             paths.append(subdir)
             self.device._simple_call(['push'] + paths + [self.DEVICE_TEMP_DIR])
 
@@ -907,7 +915,7 @@
         Bug: http://b/26816782
         """
         with tempfile.NamedTemporaryFile() as tmp_file:
-            tmp_file.write('\0' * 1024 * 1024)
+            tmp_file.write(b'\0' * 1024 * 1024)
             tmp_file.flush()
             try:
                 self.device.push(local=tmp_file.name, remote='/system/')
@@ -915,8 +923,8 @@
             except subprocess.CalledProcessError as e:
                 output = e.output
 
-            self.assertTrue('Permission denied' in output or
-                            'Read-only file system' in output)
+            self.assertTrue(b'Permission denied' in output or
+                            b'Read-only file system' in output)
 
     @requires_non_root
     def test_push_directory_creation(self):
@@ -925,7 +933,7 @@
         Bug: http://b/110953234
         """
         with tempfile.NamedTemporaryFile() as tmp_file:
-            tmp_file.write('\0' * 1024 * 1024)
+            tmp_file.write(b'\0' * 1024 * 1024)
             tmp_file.flush()
             remote_path = self.DEVICE_TEMP_DIR + '/test_push_directory_creation'
             self.device.shell(['rm', '-rf', remote_path])
@@ -967,7 +975,7 @@
         except subprocess.CalledProcessError as e:
             output = e.output
 
-        self.assertIn('Permission denied', output)
+        self.assertIn(b'Permission denied', output)
 
         self.device.shell(['rm', '-f', self.DEVICE_TEMP_FILE])
 
@@ -1166,7 +1174,7 @@
             subdir_temp_files = make_random_device_files(
                 self.device, in_dir=subdir, num_files=4, prefix='subdir_')
 
-            paths = map(lambda temp_file: temp_file.full_path, temp_files)
+            paths = [x.full_path for x in temp_files]
             paths.append(subdir)
             self.device._simple_call(['pull'] + paths + [host_dir])
 
@@ -1355,7 +1363,7 @@
         """
         # The values that trigger things are 507 (512 - 5 bytes from shell protocol) + 1024*n
         # Probe some surrounding values as well, for the hell of it.
-        for base in [512] + range(1024, 1024 * 16, 1024):
+        for base in [512] + list(range(1024, 1024 * 16, 1024)):
             for offset in [-6, -5, -4]:
                 length = base + offset
                 cmd = ['dd', 'if=/dev/zero', 'bs={}'.format(length), 'count=1', '2>/dev/null;'
@@ -1390,10 +1398,10 @@
 
                 sock = socket.create_connection(("localhost", local_port))
                 with contextlib.closing(sock):
-                    bytesWritten = sock.send("a" * size)
+                    bytesWritten = sock.send(b"a" * size)
                     self.assertEqual(size, bytesWritten)
                     readBytes = sock.recv(4096)
-                    self.assertEqual("foo\n", readBytes)
+                    self.assertEqual(b"foo\n", readBytes)
 
                 thread.join()
         finally:
@@ -1424,13 +1432,13 @@
 
         s.sendall(adb_length_prefixed(transport_string))
         response = s.recv(4)
-        self.assertEquals(b"OKAY", response)
+        self.assertEqual(b"OKAY", response)
 
         shell_string = "shell:sleep 0.5; dd if=/dev/zero bs=1m count=1 status=none; echo foo"
         s.sendall(adb_length_prefixed(shell_string))
 
         response = s.recv(4)
-        self.assertEquals(b"OKAY", response)
+        self.assertEqual(b"OKAY", response)
 
         # Spawn a thread that dumps garbage into the socket until failure.
         def spam():
@@ -1453,7 +1461,7 @@
                 break
             received += read
 
-        self.assertEquals(1024 * 1024 + len("foo\n"), len(received))
+        self.assertEqual(1024 * 1024 + len("foo\n"), len(received))
         thread.join()
 
 
diff --git a/base/expected_test.cpp b/base/expected_test.cpp
index a74bc1d..47e396a 100644
--- a/base/expected_test.cpp
+++ b/base/expected_test.cpp
@@ -408,11 +408,11 @@
 
 TEST(Expected, testTest) {
   exp_int e = 10;
-  EXPECT_TRUE(e);
+  EXPECT_TRUE(e.ok());
   EXPECT_TRUE(e.has_value());
 
   exp_int e2 = unexpected(10);
-  EXPECT_FALSE(e2);
+  EXPECT_FALSE(e2.ok());
   EXPECT_FALSE(e2.has_value());
 }
 
@@ -499,24 +499,6 @@
   EXPECT_TRUE(e4 != e3);
 }
 
-TEST(Expected, testCompareWithSameValue) {
-  exp_int e = 10;
-  int value = 10;
-  EXPECT_TRUE(e == value);
-  EXPECT_TRUE(value == e);
-  EXPECT_FALSE(e != value);
-  EXPECT_FALSE(value != e);
-}
-
-TEST(Expected, testCompareWithDifferentValue) {
-  exp_int e = 10;
-  int value = 20;
-  EXPECT_FALSE(e == value);
-  EXPECT_FALSE(value == e);
-  EXPECT_TRUE(e != value);
-  EXPECT_TRUE(value != e);
-}
-
 TEST(Expected, testCompareWithSameError) {
   exp_int e = unexpected(10);
   exp_int::unexpected_type error = 10;
@@ -589,12 +571,12 @@
     }
   };
 
-  EXPECT_FALSE(divide(10, 0));
+  EXPECT_FALSE(divide(10, 0).ok());
   EXPECT_EQ("divide by zero", divide(10, 0).error().message);
   EXPECT_EQ(-1, divide(10, 0).error().cause);
 
-  EXPECT_TRUE(divide(10, 3));
-  EXPECT_EQ(QR(3, 1), divide(10, 3));
+  EXPECT_TRUE(divide(10, 3).ok());
+  EXPECT_EQ(QR(3, 1), *divide(10, 3));
 }
 
 TEST(Expected, testPair) {
@@ -607,7 +589,7 @@
   };
 
   auto r = test(true);
-  EXPECT_TRUE(r);
+  EXPECT_TRUE(r.ok());
   EXPECT_EQ("yes", r->first);
 }
 
@@ -621,9 +603,9 @@
   };
 
   auto r = test(true);
-  EXPECT_TRUE(r);
+  EXPECT_TRUE(r.ok());
   r = test(false);
-  EXPECT_FALSE(r);
+  EXPECT_FALSE(r.ok());
   EXPECT_EQ(10, r.error());
 }
 
@@ -772,7 +754,7 @@
 
   ConstructorTracker::Reset();
   auto result1 = test("");
-  ASSERT_TRUE(result1);
+  ASSERT_TRUE(result1.ok());
   EXPECT_EQ("literal string", result1->string);
   EXPECT_EQ(1U, ConstructorTracker::constructor_called);
   EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called);
@@ -782,7 +764,7 @@
 
   ConstructorTracker::Reset();
   auto result2 = test("test2");
-  ASSERT_TRUE(result2);
+  ASSERT_TRUE(result2.ok());
   EXPECT_EQ("test2test22", result2->string);
   EXPECT_EQ(1U, ConstructorTracker::constructor_called);
   EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called);
@@ -792,7 +774,7 @@
 
   ConstructorTracker::Reset();
   auto result3 = test("test3");
-  ASSERT_TRUE(result3);
+  ASSERT_TRUE(result3.ok());
   EXPECT_EQ("test3 test3", result3->string);
   EXPECT_EQ(1U, ConstructorTracker::constructor_called);
   EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called);
@@ -804,22 +786,22 @@
 TEST(Expected, testNested) {
   expected<exp_string, std::string> e = "hello";
 
+  EXPECT_TRUE(e.ok());
   EXPECT_TRUE(e.has_value());
   EXPECT_TRUE(e.value().has_value());
-  EXPECT_TRUE(e);
-  EXPECT_TRUE(*e);
+  EXPECT_TRUE(e->ok());
   EXPECT_EQ("hello", e.value().value());
 
   expected<exp_string, std::string> e2 = unexpected("world");
   EXPECT_FALSE(e2.has_value());
-  EXPECT_FALSE(e2);
+  EXPECT_FALSE(e2.ok());
   EXPECT_EQ("world", e2.error());
 
   expected<exp_string, std::string> e3 = exp_string(unexpected("world"));
   EXPECT_TRUE(e3.has_value());
   EXPECT_FALSE(e3.value().has_value());
-  EXPECT_TRUE(e3);
-  EXPECT_FALSE(*e3);
+  EXPECT_TRUE(e3.ok());
+  EXPECT_FALSE(e3->ok());
   EXPECT_EQ("world", e3.value().error());
 }
 
diff --git a/base/include/android-base/expected.h b/base/include/android-base/expected.h
index b3f5adb..9603bb1 100644
--- a/base/include/android-base/expected.h
+++ b/base/include/android-base/expected.h
@@ -331,6 +331,7 @@
 
   constexpr explicit operator bool() const noexcept { return has_value(); }
   constexpr bool has_value() const noexcept { return var_.index() == 0; }
+  constexpr bool ok() const noexcept { return has_value(); }
 
   constexpr const T& value() const& { return std::get<T>(var_); }
   constexpr T& value() & { return std::get<T>(var_); }
@@ -366,16 +367,6 @@
   template<class T1, class E1, class T2, class E2>
   friend constexpr bool operator!=(const expected<T1, E1>& x, const expected<T2, E2>& y);
 
-  // comparison with T
-  template<class T1, class E1, class T2>
-  friend constexpr bool operator==(const expected<T1, E1>&, const T2&);
-  template<class T1, class E1, class T2>
-  friend constexpr bool operator==(const T2&, const expected<T1, E1>&);
-  template<class T1, class E1, class T2>
-  friend constexpr bool operator!=(const expected<T1, E1>&, const T2&);
-  template<class T1, class E1, class T2>
-  friend constexpr bool operator!=(const T2&, const expected<T1, E1>&);
-
   // Comparison with unexpected<E>
   template<class T1, class E1, class E2>
   friend constexpr bool operator==(const expected<T1, E1>&, const unexpected<E2>&);
@@ -410,24 +401,6 @@
   return !(x == y);
 }
 
-// comparison with T
-template<class T1, class E1, class T2>
-constexpr bool operator==(const expected<T1, E1>& x, const T2& y) {
-  return x.has_value() && (*x == y);
-}
-template<class T1, class E1, class T2>
-constexpr bool operator==(const T2& x, const expected<T1, E1>& y) {
-  return y.has_value() && (x == *y);
-}
-template<class T1, class E1, class T2>
-constexpr bool operator!=(const expected<T1, E1>& x, const T2& y) {
-  return !x.has_value() || (*x != y);
-}
-template<class T1, class E1, class T2>
-constexpr bool operator!=(const T2& x, const expected<T1, E1>& y) {
-  return !y.has_value() || (x != *y);
-}
-
 // Comparison with unexpected<E>
 template<class T1, class E1, class E2>
 constexpr bool operator==(const expected<T1, E1>& x, const unexpected<E2>& y) {
@@ -585,6 +558,7 @@
   // observers
   constexpr explicit operator bool() const noexcept { return has_value(); }
   constexpr bool has_value() const noexcept { return var_.index() == 0; }
+  constexpr bool ok() const noexcept { return has_value(); }
 
   constexpr void value() const& { if (!has_value()) std::get<0>(var_); }
 
diff --git a/base/include/android-base/result.h b/base/include/android-base/result.h
index b6d26e7..4a59552 100644
--- a/base/include/android-base/result.h
+++ b/base/include/android-base/result.h
@@ -156,11 +156,11 @@
   Error& operator=(const Error&) = delete;
   Error& operator=(Error&&) = delete;
 
-  template <typename... Args>
-  friend Error Errorf(const char* fmt, const Args&... args);
+  template <typename T, typename... Args>
+  friend Error ErrorfImpl(const T&& fmt, const Args&... args);
 
-  template <typename... Args>
-  friend Error ErrnoErrorf(const char* fmt, const Args&... args);
+  template <typename T, typename... Args>
+  friend Error ErrnoErrorfImpl(const T&& fmt, const Args&... args);
 
  private:
   Error(bool append_errno, int errno_to_append, const std::string& message)
@@ -191,18 +191,49 @@
   return ErrorCode(code, args...);
 }
 
-template <typename... Args>
-inline Error Errorf(const char* fmt, const Args&... args) {
+// TODO(tomcherry): Remove this once we've removed all `using android::base::Errorf` and `using
+// android::base::ErrnoErrorf` lines.
+enum Errorf {};
+enum ErrnoErrorf {};
+
+template <typename T, typename... Args>
+inline Error ErrorfImpl(const T&& fmt, const Args&... args) {
   return Error(false, ErrorCode(0, args...), fmt::format(fmt, args...));
 }
 
-template <typename... Args>
-inline Error ErrnoErrorf(const char* fmt, const Args&... args) {
+template <typename T, typename... Args>
+inline Error ErrnoErrorfImpl(const T&& fmt, const Args&... args) {
   return Error(true, errno, fmt::format(fmt, args...));
 }
 
+#define Errorf(fmt, ...) android::base::ErrorfImpl(FMT_STRING(fmt), ##__VA_ARGS__)
+#define ErrnoErrorf(fmt, ...) android::base::ErrnoErrorfImpl(FMT_STRING(fmt), ##__VA_ARGS__)
+
 template <typename T>
 using Result = android::base::expected<T, ResultError>;
 
+// Macros for testing the results of functions that return android::base::Result.
+// These also work with base::android::expected.
+
+#define CHECK_RESULT_OK(stmt)       \
+  do {                              \
+    const auto& tmp = (stmt);       \
+    CHECK(tmp.ok()) << tmp.error(); \
+  } while (0)
+
+#define ASSERT_RESULT_OK(stmt)            \
+  do {                                    \
+    const auto& tmp = (stmt);             \
+    ASSERT_TRUE(tmp.ok()) << tmp.error(); \
+  } while (0)
+
+#define EXPECT_RESULT_OK(stmt)            \
+  do {                                    \
+    auto tmp = (stmt);                    \
+    EXPECT_TRUE(tmp.ok()) << tmp.error(); \
+  } while (0)
+
+// TODO: Maybe add RETURN_IF_ERROR() and ASSIGN_OR_RETURN()
+
 }  // namespace base
 }  // namespace android
diff --git a/base/result_test.cpp b/base/result_test.cpp
index 2ee4057..c0ac0fd 100644
--- a/base/result_test.cpp
+++ b/base/result_test.cpp
@@ -30,7 +30,7 @@
 
 TEST(result, result_accessors) {
   Result<std::string> result = "success";
-  ASSERT_TRUE(result);
+  ASSERT_RESULT_OK(result);
   ASSERT_TRUE(result.has_value());
 
   EXPECT_EQ("success", *result);
@@ -40,7 +40,7 @@
 }
 
 TEST(result, result_accessors_rvalue) {
-  ASSERT_TRUE(Result<std::string>("success"));
+  ASSERT_TRUE(Result<std::string>("success").ok());
   ASSERT_TRUE(Result<std::string>("success").has_value());
 
   EXPECT_EQ("success", *Result<std::string>("success"));
@@ -51,12 +51,12 @@
 
 TEST(result, result_void) {
   Result<void> ok = {};
-  EXPECT_TRUE(ok);
+  EXPECT_RESULT_OK(ok);
   ok.value();  // should not crash
   ASSERT_DEATH(ok.error(), "");
 
   Result<void> fail = Error() << "failure" << 1;
-  EXPECT_FALSE(fail);
+  EXPECT_FALSE(fail.ok());
   EXPECT_EQ("failure1", fail.error().message());
   EXPECT_EQ(0, fail.error().code());
   EXPECT_TRUE(ok != fail);
@@ -66,8 +66,8 @@
     if (ok) return {};
     else return Error() << "failure" << 1;
   };
-  EXPECT_TRUE(test(true));
-  EXPECT_FALSE(test(false));
+  EXPECT_TRUE(test(true).ok());
+  EXPECT_FALSE(test(false).ok());
   test(true).value();  // should not crash
   ASSERT_DEATH(test(true).error(), "");
   ASSERT_DEATH(test(false).value(), "");
@@ -76,7 +76,7 @@
 
 TEST(result, result_error) {
   Result<void> result = Error() << "failure" << 1;
-  ASSERT_FALSE(result);
+  ASSERT_FALSE(result.ok());
   ASSERT_FALSE(result.has_value());
 
   EXPECT_EQ(0, result.error().code());
@@ -85,7 +85,7 @@
 
 TEST(result, result_error_empty) {
   Result<void> result = Error();
-  ASSERT_FALSE(result);
+  ASSERT_FALSE(result.ok());
   ASSERT_FALSE(result.has_value());
 
   EXPECT_EQ(0, result.error().code());
@@ -100,7 +100,7 @@
   // create is.
 
   auto MakeRvalueErrorResult = []() -> Result<void> { return Error() << "failure" << 1; };
-  ASSERT_FALSE(MakeRvalueErrorResult());
+  ASSERT_FALSE(MakeRvalueErrorResult().ok());
   ASSERT_FALSE(MakeRvalueErrorResult().has_value());
 
   EXPECT_EQ(0, MakeRvalueErrorResult().error().code());
@@ -112,7 +112,7 @@
   errno = test_errno;
   Result<void> result = ErrnoError() << "failure" << 1;
 
-  ASSERT_FALSE(result);
+  ASSERT_FALSE(result.ok());
   ASSERT_FALSE(result.has_value());
 
   EXPECT_EQ(test_errno, result.error().code());
@@ -124,7 +124,7 @@
   errno = test_errno;
   Result<void> result = ErrnoError();
 
-  ASSERT_FALSE(result);
+  ASSERT_FALSE(result.ok());
   ASSERT_FALSE(result.has_value());
 
   EXPECT_EQ(test_errno, result.error().code());
@@ -135,12 +135,12 @@
   auto error_text = "test error"s;
   Result<void> result = Error() << error_text;
 
-  ASSERT_FALSE(result);
+  ASSERT_FALSE(result.ok());
   ASSERT_FALSE(result.has_value());
 
   Result<std::string> result2 = result.error();
 
-  ASSERT_FALSE(result2);
+  ASSERT_FALSE(result2.ok());
   ASSERT_FALSE(result2.has_value());
 
   EXPECT_EQ(0, result2.error().code());
@@ -151,12 +151,12 @@
   auto error_text = "test error"s;
   Result<void> result = Error() << error_text;
 
-  ASSERT_FALSE(result);
+  ASSERT_FALSE(result.ok());
   ASSERT_FALSE(result.has_value());
 
   Result<std::string> result2 = Error() << result.error();
 
-  ASSERT_FALSE(result2);
+  ASSERT_FALSE(result2.ok());
   ASSERT_FALSE(result2.has_value());
 
   EXPECT_EQ(0, result2.error().code());
@@ -171,12 +171,12 @@
 
   errno = 0;
 
-  ASSERT_FALSE(result);
+  ASSERT_FALSE(result.ok());
   ASSERT_FALSE(result.has_value());
 
   Result<std::string> result2 = Error() << result.error();
 
-  ASSERT_FALSE(result2);
+  ASSERT_FALSE(result2.ok());
   ASSERT_FALSE(result2.has_value());
 
   EXPECT_EQ(test_errno, result2.error().code());
@@ -186,7 +186,7 @@
 TEST(result, constructor_forwarding) {
   auto result = Result<std::string>(std::in_place, 5, 'a');
 
-  ASSERT_TRUE(result);
+  ASSERT_RESULT_OK(result);
   ASSERT_TRUE(result.has_value());
 
   EXPECT_EQ("aaaaa", *result);
@@ -254,7 +254,7 @@
   // are called.
 
   auto result1 = ReturnConstructorTracker("");
-  ASSERT_TRUE(result1);
+  ASSERT_RESULT_OK(result1);
   EXPECT_EQ("literal string", result1->string);
   EXPECT_EQ(1U, ConstructorTracker::constructor_called);
   EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called);
@@ -263,7 +263,7 @@
   EXPECT_EQ(0U, ConstructorTracker::move_assignment_called);
 
   auto result2 = ReturnConstructorTracker("test2");
-  ASSERT_TRUE(result2);
+  ASSERT_RESULT_OK(result2);
   EXPECT_EQ("test2test22", result2->string);
   EXPECT_EQ(2U, ConstructorTracker::constructor_called);
   EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called);
@@ -272,7 +272,7 @@
   EXPECT_EQ(0U, ConstructorTracker::move_assignment_called);
 
   auto result3 = ReturnConstructorTracker("test3");
-  ASSERT_TRUE(result3);
+  ASSERT_RESULT_OK(result3);
   EXPECT_EQ("test3 test3", result3->string);
   EXPECT_EQ(3U, ConstructorTracker::constructor_called);
   EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called);
@@ -287,11 +287,11 @@
 TEST(result, result_result_with_success) {
   auto return_result_result_with_success = []() -> Result<Result<void>> { return Result<void>(); };
   auto result = return_result_result_with_success();
-  ASSERT_TRUE(result);
-  ASSERT_TRUE(*result);
+  ASSERT_RESULT_OK(result);
+  ASSERT_RESULT_OK(*result);
 
   auto inner_result = result.value();
-  ASSERT_TRUE(inner_result);
+  ASSERT_RESULT_OK(inner_result);
 }
 
 TEST(result, result_result_with_failure) {
@@ -299,8 +299,8 @@
     return Result<void>(ResultError("failure string", 6));
   };
   auto result = return_result_result_with_error();
-  ASSERT_TRUE(result);
-  ASSERT_FALSE(*result);
+  ASSERT_RESULT_OK(result);
+  ASSERT_FALSE(result->ok());
   EXPECT_EQ("failure string", (*result).error().message());
   EXPECT_EQ(6, (*result).error().code());
 }
@@ -320,7 +320,7 @@
   };
 
   auto result = return_test_struct();
-  ASSERT_TRUE(result);
+  ASSERT_RESULT_OK(result);
   EXPECT_EQ(36, result->value_);
 }
 
@@ -344,13 +344,13 @@
   errno = 1;
   int old_errno = errno;
   Result<int> result = Error() << "Failed" << SetErrnoToTwo<char>;
-  ASSERT_FALSE(result);
+  ASSERT_FALSE(result.ok());
   EXPECT_EQ(old_errno, errno);
 
   errno = 1;
   old_errno = errno;
   Result<int> result2 = ErrnoError() << "Failed" << SetErrnoToTwo<char>;
-  ASSERT_FALSE(result2);
+  ASSERT_FALSE(result2.ok());
   EXPECT_EQ(old_errno, errno);
   EXPECT_EQ(old_errno, result2.error().code());
 }
@@ -362,7 +362,7 @@
   result = Errorf("{} {}!", std::string("hello"), std::string("world"));
   EXPECT_EQ("hello world!", result.error().message());
 
-  result = Errorf("{h} {w}!", fmt::arg("w", "world"), fmt::arg("h", "hello"));
+  result = Errorf("{1} {0}!", "world", "hello");
   EXPECT_EQ("hello world!", result.error().message());
 
   result = Errorf("hello world!");
diff --git a/bootstat/boot_reason_test.sh b/bootstat/boot_reason_test.sh
index f379d76..2f2919f 100755
--- a/bootstat/boot_reason_test.sh
+++ b/bootstat/boot_reason_test.sh
@@ -7,7 +7,7 @@
 # - watch adb logcat -b all -d -s bootstat
 # - watch adb logcat -b all -d | audit2allow
 # - wait until screen is up, boot has completed, can mean wait for
-#   sys.boot_completed=1 and sys.logbootcomplete=1 to be true
+#   sys.boot_completed=1 and sys.bootstat.first_boot_completed=1 to be true
 #
 # All test frames, and nothing else, must be function names prefixed and
 # specifiged with the pattern 'test_<test>() {' as this is also how the
@@ -230,16 +230,16 @@
       if [ -n "`get_property sys.boot.reason`" ]
       then
         vals=`get_property |
-              sed -n 's/[[]sys[.]\(boot_completed\|logbootcomplete\)[]]: [[]\([01]\)[]]$/\1=\2/p'`
-        if [ "${vals}" = "`echo boot_completed=1 ; echo logbootcomplete=1`" ]
-        then
-          sleep 1
-          break
-        fi
-        if [ "${vals}" = "`echo logbootcomplete=1 ; echo boot_completed=1`" ]
-        then
-          sleep 1
-          break
+              sed -n 's/[[]sys[.]\(boot_completed\|logbootcomplete\|bootstat[.]first_boot_completed\)[]]: [[]\([01]\)[]]$/\1=\2/p'`
+        if [ X"${vals}" != X"${vals##*boot_completed=1}" ]; then
+          if [ X"${vals}" != X"${vals##*logbootcomple=1}" ]; then
+            sleep 1
+            break
+          fi
+          if [ X"${vals}" != X"${vals##*bootstat.first_boot_completed=1}" ]; then
+            sleep 1
+            break
+          fi
         fi
       fi
     fi
@@ -384,15 +384,15 @@
 init    : processing action (boot) from (/system/etc/init/bootstat.rc
 init    : processing action (ro.boot.bootreason=*) from (/system/etc/init/bootstat.rc
 init    : processing action (ro.boot.bootreason=* && post-fs) from (/system/etc/init/bootstat.rc
-init    : processing action (zygote-start) from (/system/etc/init/bootstat.rc
-init    : processing action (sys.boot_completed=1 && sys.logbootcomplete=1) from (/system/etc/init/bootstat.rc
+init    : processing action (sys.bootstat.first_zygote_start=0 && zygote-start) from (/system/etc/init/bootstat.rc
+init    : processing action (sys.boot_completed=1 && sys.bootstat.first_boot_completed=0) from (/system/etc/init/bootstat.rc
  (/system/bin/bootstat --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l)'
  (/system/bin/bootstat --set_system_boot_reason --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l)'
  (/system/bin/bootstat -r post_decrypt_time_elapsed)'
-init    : Command 'exec - system log -- /system/bin/bootstat --record_boot_complete' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc:
-init    : Command 'exec - system log -- /system/bin/bootstat --record_boot_reason' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc:
-init    : Command 'exec - system log -- /system/bin/bootstat --record_time_since_factory_reset' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc:
-init    : Command 'exec_background - system log -- /system/bin/bootstat --set_system_boot_reason --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc
+init    : Command 'exec - system log -- /system/bin/bootstat --record_boot_complete' action=sys.boot_completed=1 && sys.bootstat.first_boot_completed=0 (/system/etc/init/bootstat.rc:
+init    : Command 'exec - system log -- /system/bin/bootstat --record_boot_reason' action=sys.boot_completed=1 && sys.bootstat.first_boot_completed=0 (/system/etc/init/bootstat.rc:
+init    : Command 'exec - system log -- /system/bin/bootstat --record_time_since_factory_reset' action=sys.boot_completed=1 && sys.bootstat.first_boot_completed=0 (/system/etc/init/bootstat.rc:
+init    : Command 'exec_background - system log -- /system/bin/bootstat --set_system_boot_reason --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l' action=sys.boot_completed=1 && sys.bootstat.first_boot_completed=0 (/system/etc/init/bootstat.rc
  (/system/bin/bootstat --record_boot_complete)'...
  (/system/bin/bootstat --record_boot_complete)' (pid${SPACE}
  (/system/bin/bootstat --record_boot_reason)'...
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 6b8a09a..9ffe5dd 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -32,6 +32,8 @@
 #include <memory>
 #include <regex>
 #include <string>
+#include <string_view>
+#include <unordered_map>
 #include <utility>
 #include <vector>
 
@@ -50,16 +52,133 @@
 
 namespace {
 
+struct AtomInfo {
+  int32_t atom;
+  int32_t event;
+};
+
+// Maps BootEvent used inside bootstat into statsd atom defined in
+// frameworks/base/cmds/statsd/src/atoms.proto.
+const std::unordered_map<std::string_view, AtomInfo> kBootEventToAtomInfo = {
+    // ELAPSED_TIME
+    {"ro.boottime.init",
+     {android::util::BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
+      android::util::BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__ANDROID_INIT_STAGE_1}},
+    {"boot_complete",
+     {android::util::BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
+      android::util::BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__BOOT_COMPLETE}},
+    {"boot_decryption_complete",
+     {android::util::BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
+      android::util::BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__BOOT_COMPLETE_ENCRYPTION}},
+    {"boot_complete_no_encryption",
+     {android::util::BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
+      android::util::BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__BOOT_COMPLETE_NO_ENCRYPTION}},
+    {"boot_complete_post_decrypt",
+     {android::util::BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
+      android::util::BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__BOOT_COMPLETE_POST_DECRYPT}},
+    {"factory_reset_boot_complete",
+     {android::util::BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
+      android::util::BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__FACTORY_RESET_BOOT_COMPLETE}},
+    {"factory_reset_boot_complete_no_encryption",
+     {android::util::BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
+      android::util::
+          BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__FACTORY_RESET_BOOT_COMPLETE_NO_ENCRYPTION}},
+    {"factory_reset_boot_complete_post_decrypt",
+     {android::util::BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
+      android::util::
+          BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__FACTORY_RESET_BOOT_COMPLETE_POST_DECRYPT}},
+    {"ota_boot_complete",
+     {android::util::BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
+      android::util::BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__OTA_BOOT_COMPLETE}},
+    {"ota_boot_complete_no_encryption",
+     {android::util::BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
+      android::util::BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__OTA_BOOT_COMPLETE_NO_ENCRYPTION}},
+    {"ota_boot_complete_post_decrypt",
+     {android::util::BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
+      android::util::BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__OTA_BOOT_COMPLETE_POST_DECRYPT}},
+    {"post_decrypt_time_elapsed",
+     {android::util::BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
+      android::util::BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__POST_DECRYPT}},
+    // DURATION
+    {"absolute_boot_time",
+     {android::util::BOOT_TIME_EVENT_DURATION_REPORTED,
+      android::util::BOOT_TIME_EVENT_DURATION__EVENT__ABSOLUTE_BOOT_TIME}},
+    {"boottime.bootloader.1BLE",
+     {android::util::BOOT_TIME_EVENT_DURATION_REPORTED,
+      android::util::BOOT_TIME_EVENT_DURATION__EVENT__BOOTLOADER_FIRST_STAGE_EXEC}},
+    {"boottime.bootloader.1BLL",
+     {android::util::BOOT_TIME_EVENT_DURATION_REPORTED,
+      android::util::BOOT_TIME_EVENT_DURATION__EVENT__BOOTLOADER_FIRST_STAGE_LOAD}},
+    {"boottime.bootloader.KL",
+     {android::util::BOOT_TIME_EVENT_DURATION_REPORTED,
+      android::util::BOOT_TIME_EVENT_DURATION__EVENT__BOOTLOADER_KERNEL_LOAD}},
+    {"boottime.bootloader.2BLE",
+     {android::util::BOOT_TIME_EVENT_DURATION_REPORTED,
+      android::util::BOOT_TIME_EVENT_DURATION__EVENT__BOOTLOADER_SECOND_STAGE_EXEC}},
+    {"boottime.bootloader.2BLL",
+     {android::util::BOOT_TIME_EVENT_DURATION_REPORTED,
+      android::util::BOOT_TIME_EVENT_DURATION__EVENT__BOOTLOADER_SECOND_STAGE_LOAD}},
+    {"boottime.bootloader.SW",
+     {android::util::BOOT_TIME_EVENT_DURATION_REPORTED,
+      android::util::BOOT_TIME_EVENT_DURATION__EVENT__BOOTLOADER_UI_WAIT}},
+    {"boottime.bootloader.total",
+     {android::util::BOOT_TIME_EVENT_DURATION_REPORTED,
+      android::util::BOOT_TIME_EVENT_DURATION__EVENT__BOOTLOADER_TOTAL}},
+    {"boottime.init.cold_boot_wait",
+     {android::util::BOOT_TIME_EVENT_DURATION_REPORTED,
+      android::util::BOOT_TIME_EVENT_DURATION__EVENT__COLDBOOT_WAIT}},
+    {"time_since_factory_reset",
+     {android::util::BOOT_TIME_EVENT_DURATION_REPORTED,
+      android::util::BOOT_TIME_EVENT_DURATION__EVENT__FACTORY_RESET_TIME_SINCE_RESET}},
+    {"ro.boottime.init.first_stage",
+     {android::util::BOOT_TIME_EVENT_DURATION_REPORTED,
+      android::util::BOOT_TIME_EVENT_DURATION__EVENT__ANDROID_INIT_STAGE_1}},
+    {"ro.boottime.init.selinux",
+     {android::util::BOOT_TIME_EVENT_DURATION_REPORTED,
+      android::util::BOOT_TIME_EVENT_DURATION__EVENT__SELINUX_INIT}},
+    // UTC_TIME
+    {"factory_reset",
+     {android::util::BOOT_TIME_EVENT_UTC_TIME_REPORTED,
+      android::util::BOOT_TIME_EVENT_UTC_TIME__EVENT__FACTORY_RESET_RESET_TIME}},
+    {"factory_reset_current_time",
+     {android::util::BOOT_TIME_EVENT_UTC_TIME_REPORTED,
+      android::util::BOOT_TIME_EVENT_UTC_TIME__EVENT__FACTORY_RESET_CURRENT_TIME}},
+    {"factory_reset_record_value",
+     {android::util::BOOT_TIME_EVENT_UTC_TIME_REPORTED,
+      android::util::BOOT_TIME_EVENT_UTC_TIME__EVENT__FACTORY_RESET_RECORD_VALUE}},
+    // ERROR_CODE
+    {"factory_reset_current_time_failure",
+     {android::util::BOOT_TIME_EVENT_ERROR_CODE_REPORTED,
+      android::util::BOOT_TIME_EVENT_ERROR_CODE__EVENT__FACTORY_RESET_CURRENT_TIME_FAILURE}},
+};
+
 // Scans the boot event record store for record files and logs each boot event
 // via EventLog.
 void LogBootEvents() {
   BootEventRecordStore boot_event_store;
-
   auto events = boot_event_store.GetAllBootEvents();
-  // TODO(b/148575354): Replace with statsd.
-  // for (auto i = events.cbegin(); i != events.cend(); ++i) {
-  //   android::metricslogger::LogHistogram(i->first, i->second);
-  // }
+  std::vector<std::string_view> notSupportedEvents;
+  for (const auto& event : events) {
+    const auto& name = event.first;
+    const auto& info = kBootEventToAtomInfo.find(name);
+    if (info != kBootEventToAtomInfo.end()) {
+      if (info->second.atom == android::util::BOOT_TIME_EVENT_ERROR_CODE_REPORTED) {
+        android::util::stats_write(static_cast<int32_t>(info->second.atom),
+                                   static_cast<int32_t>(info->second.event),
+                                   static_cast<int32_t>(event.second));
+      } else {
+        android::util::stats_write(static_cast<int32_t>(info->second.atom),
+                                   static_cast<int32_t>(info->second.event),
+                                   static_cast<int64_t>(event.second));
+      }
+    } else {
+      notSupportedEvents.push_back(name);
+    }
+  }
+  if (!notSupportedEvents.empty()) {
+    LOG(WARNING) << "LogBootEvents, atomInfo not defined for events:"
+                 << android::base::Join(notSupportedEvents, ',');
+  }
 }
 
 // Records the named boot |event| to the record store. If |value| is non-empty
@@ -1250,10 +1369,13 @@
   time_t current_time_utc = time(nullptr);
 
   if (current_time_utc < 0) {
-    // TODO(b/148575354): Replace with statsd.
     // UMA does not display negative values in buckets, so convert to positive.
-    // android::metricslogger::LogHistogram("factory_reset_current_time_failure",
-    //                                      std::abs(current_time_utc));
+    // Logging via BootEventRecordStore.
+    android::util::stats_write(
+        static_cast<int32_t>(android::util::BOOT_TIME_EVENT_ERROR_CODE_REPORTED),
+        static_cast<int32_t>(
+            android::util::BOOT_TIME_EVENT_ERROR_CODE__EVENT__FACTORY_RESET_CURRENT_TIME_FAILURE),
+        static_cast<int32_t>(std::abs(current_time_utc)));
 
     // Logging via BootEventRecordStore to see if using android::metricslogger::LogHistogram
     // is losing records somehow.
@@ -1261,8 +1383,11 @@
                                            std::abs(current_time_utc));
     return;
   } else {
-    // TODO(b/148575354): Replace with statsd.
-    // android::metricslogger::LogHistogram("factory_reset_current_time", current_time_utc);
+    android::util::stats_write(
+        static_cast<int32_t>(android::util::BOOT_TIME_EVENT_UTC_TIME_REPORTED),
+        static_cast<int32_t>(
+            android::util::BOOT_TIME_EVENT_UTC_TIME__EVENT__FACTORY_RESET_CURRENT_TIME),
+        static_cast<int64_t>(current_time_utc));
 
     // Logging via BootEventRecordStore to see if using android::metricslogger::LogHistogram
     // is losing records somehow.
@@ -1282,8 +1407,11 @@
   // Calculate and record the difference in time between now and the
   // factory_reset time.
   time_t factory_reset_utc = record.second;
-  // TODO(b/148575354): Replace with statsd.
-  // android::metricslogger::LogHistogram("factory_reset_record_value", factory_reset_utc);
+  android::util::stats_write(
+      static_cast<int32_t>(android::util::BOOT_TIME_EVENT_UTC_TIME_REPORTED),
+      static_cast<int32_t>(
+          android::util::BOOT_TIME_EVENT_UTC_TIME__EVENT__FACTORY_RESET_RECORD_VALUE),
+      static_cast<int64_t>(factory_reset_utc));
 
   // Logging via BootEventRecordStore to see if using android::metricslogger::LogHistogram
   // is losing records somehow.
diff --git a/bootstat/bootstat.rc b/bootstat/bootstat.rc
index 85caf25..a350fe7 100644
--- a/bootstat/bootstat.rc
+++ b/bootstat/bootstat.rc
@@ -50,34 +50,34 @@
 on post-fs-data && property:init.svc.bootanim=running && property:ro.crypto.type=block
     exec_background - system log -- /system/bin/bootstat -r post_decrypt_time_elapsed
 
-# sys.logbootcomplete is a signal to enable the bootstat logging mechanism.
-# This signaling is necessary to prevent logging boot metrics after a runtime
-# restart (e.g., adb shell stop && adb shell start).  /proc/uptime is not reset
-# during a runtime restart, which leads to false boot time metrics being reported.
+# Initialize bootstat state machine.
 #
-# The 'on boot' event occurs once per hard boot (device power on), which
-# switches the flag on. If the device performs a runtime restart, the flag is
-# switched off and cannot be switched on until the device hard boots again.
-
-# Enable bootstat logging on boot.
-on boot
-    setprop sys.logbootcomplete 1
-
-# Disable further bootstat logging on a runtime restart. A runtime restart is
-# signaled by the zygote stopping.
-on property:init.svc.zygote=stopping
-    setprop sys.logbootcomplete 0
+# sys.bootstat.first_boot_completed: responsible for making sure that record_boot_complete happens
+# only once per device hard reboot. Possible values:
+#
+#   sys.bootstat.first_boot_completed=0 - first boot completed trigger wasn't processed yet.
+#   sys.bootstat.first_boot_completed=1 - first boot completed trigger was processed and
+#                                         record_boot_complete was called. Subsequent boot completed
+#                                         triggers (e.g. due to userspace reboot) won't retrigger
+#                                         record_boot_complete
+#
+# IMPORTANT, ro.persistent_properties.ready=1 trigger is used here to ensure that we initialize
+# state machine only once, which as result ensures that bootstat --set_system_boot_reason and
+# bootstat --record_boot_complete will be called only once per full reboot.
+on property:ro.persistent_properties.ready=true
+  setprop sys.bootstat.first_boot_completed 0
 
 # Set boot reason
-on zygote-start
+on property:ro.persistent_properties.ready=true
     # Converts bootloader boot reason and persist.sys.boot.reason to system boot reason
     # Need go after persist peroperties are loaded which is right before zygote-start trigger
     exec_background - system log -- /system/bin/bootstat --set_system_boot_reason
 
 # Record boot complete metrics.
-on property:sys.boot_completed=1 && property:sys.logbootcomplete=1
+on property:sys.boot_completed=1 && property:sys.bootstat.first_boot_completed=0
     # Record boot_complete and related stats (decryption, etc).
     # Record the boot reason.
     # Record time since factory reset.
     # Log all boot events.
     exec_background - system log -- /system/bin/bootstat --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l
+    setprop sys.bootstat.first_boot_completed 1
diff --git a/fastboot/constants.h b/fastboot/constants.h
index aefd448..ba43ca5 100644
--- a/fastboot/constants.h
+++ b/fastboot/constants.h
@@ -42,7 +42,7 @@
 #define RESPONSE_INFO "INFO"
 
 #define FB_COMMAND_SZ 64
-#define FB_RESPONSE_SZ 64
+#define FB_RESPONSE_SZ 256
 
 #define FB_VAR_VERSION "version"
 #define FB_VAR_VERSION_BOOTLOADER "version-bootloader"
diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp
index b9784fe..d9167e7 100644
--- a/fastboot/fuzzy_fastboot/main.cpp
+++ b/fastboot/fuzzy_fastboot/main.cpp
@@ -227,13 +227,6 @@
 
 TEST_F(LogicalPartitionCompliance, FastbootRebootTest) {
     ASSERT_TRUE(UserSpaceFastboot());
-    GTEST_LOG_(INFO) << "Rebooting to bootloader mode";
-    // Test 'fastboot reboot bootloader' from fastbootd
-    fb->RebootTo("bootloader");
-
-    // Test fastboot reboot fastboot from bootloader
-    ReconnectFastbootDevice();
-    ASSERT_FALSE(UserSpaceFastboot());
     GTEST_LOG_(INFO) << "Rebooting back to fastbootd mode";
     fb->RebootTo("fastboot");
 
@@ -268,23 +261,6 @@
     GTEST_LOG_(INFO) << "Flashing a logical partition..";
     EXPECT_EQ(fb->FlashPartition(test_partition_name, buf), SUCCESS)
             << "flash logical -partition failed";
-    GTEST_LOG_(INFO) << "Rebooting to bootloader mode";
-    // Reboot to bootloader mode and attempt to flash the logical partitions
-    fb->RebootTo("bootloader");
-
-    ReconnectFastbootDevice();
-    ASSERT_FALSE(UserSpaceFastboot());
-    GTEST_LOG_(INFO) << "Attempt to flash a logical partition..";
-    EXPECT_EQ(fb->FlashPartition(test_partition_name, buf), DEVICE_FAIL)
-            << "flash logical partition must fail in bootloader";
-    GTEST_LOG_(INFO) << "Rebooting back to fastbootd mode";
-    fb->RebootTo("fastboot");
-
-    ReconnectFastbootDevice();
-    ASSERT_TRUE(UserSpaceFastboot());
-    GTEST_LOG_(INFO) << "Testing 'fastboot delete-logical-partition' command";
-    EXPECT_EQ(fb->DeletePartition(test_partition_name), SUCCESS)
-            << "delete logical-partition failed";
 }
 
 // Conformance tests
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 7a88aa3..f5daf91 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -96,6 +96,10 @@
     export_header_lib_headers: [
         "libfiemap_headers",
     ],
+    required: [
+        "e2freefrag",
+        "e2fsdroid",
+    ],
 }
 
 // Two variants of libfs_mgr are provided: libfs_mgr and libfs_mgr_binder.
diff --git a/fs_mgr/TEST_MAPPING b/fs_mgr/TEST_MAPPING
new file mode 100644
index 0000000..705d4e3
--- /dev/null
+++ b/fs_mgr/TEST_MAPPING
@@ -0,0 +1,19 @@
+{
+  "presubmit": [
+    {
+      "name": "libdm_test"
+    },
+    {
+      "name": "liblp_test"
+    },
+    {
+      "name": "fiemap_image_test_presubmit"
+    },
+    {
+      "name": "fiemap_writer_test"
+    },
+    {
+      "name": "vts_libsnapshot_test_presubmit"
+    }
+  ]
+}
diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp
index acf4d7b..a8c2cc1 100644
--- a/fs_mgr/fs_mgr_format.cpp
+++ b/fs_mgr/fs_mgr_format.cpp
@@ -24,6 +24,7 @@
 #include <cutils/partition_utils.h>
 #include <sys/mount.h>
 
+#include <android-base/properties.h>
 #include <android-base/unique_fd.h>
 #include <ext4_utils/ext4.h>
 #include <ext4_utils/ext4_utils.h>
@@ -57,7 +58,7 @@
 }
 
 static int format_ext4(const std::string& fs_blkdev, const std::string& fs_mnt_point,
-                       bool crypt_footer) {
+                       bool crypt_footer, bool needs_projid) {
     uint64_t dev_sz;
     int rc = 0;
 
@@ -72,11 +73,20 @@
     }
 
     std::string size_str = std::to_string(dev_sz / 4096);
-    const char* const mke2fs_args[] = {
-            "/system/bin/mke2fs", "-t",   "ext4", "-b", "4096", fs_blkdev.c_str(),
-            size_str.c_str(),     nullptr};
 
-    rc = logwrap_fork_execvp(arraysize(mke2fs_args), mke2fs_args, nullptr, false, LOG_KLOG, true,
+    std::vector<const char*> mke2fs_args = {"/system/bin/mke2fs", "-t", "ext4", "-b", "4096"};
+
+    // Project ID's require wider inodes. The Quotas themselves are enabled by tune2fs during boot.
+    if (needs_projid) {
+        mke2fs_args.push_back("-I");
+        mke2fs_args.push_back("512");
+    }
+    // casefolding is enabled via tune2fs during boot.
+
+    mke2fs_args.push_back(fs_blkdev.c_str());
+    mke2fs_args.push_back(size_str.c_str());
+
+    rc = logwrap_fork_execvp(mke2fs_args.size(), mke2fs_args.data(), nullptr, false, LOG_KLOG, true,
                              nullptr);
     if (rc) {
         LERROR << "mke2fs returned " << rc;
@@ -95,7 +105,8 @@
     return rc;
 }
 
-static int format_f2fs(const std::string& fs_blkdev, uint64_t dev_sz, bool crypt_footer) {
+static int format_f2fs(const std::string& fs_blkdev, uint64_t dev_sz, bool crypt_footer,
+                       bool needs_projid, bool needs_casefold) {
     if (!dev_sz) {
         int rc = get_dev_sz(fs_blkdev, &dev_sz);
         if (rc) {
@@ -109,26 +120,40 @@
     }
 
     std::string size_str = std::to_string(dev_sz / 4096);
-    // clang-format off
-    const char* const args[] = {
-        "/system/bin/make_f2fs",
-        "-g", "android",
-        fs_blkdev.c_str(),
-        size_str.c_str(),
-        nullptr
-    };
-    // clang-format on
 
-    return logwrap_fork_execvp(arraysize(args), args, nullptr, false, LOG_KLOG, true, nullptr);
+    std::vector<const char*> args = {"/system/bin/make_f2fs", "-g", "android"};
+    if (needs_projid) {
+        args.push_back("-O");
+        args.push_back("project_quota,extra_attr");
+    }
+    if (needs_casefold) {
+        args.push_back("-O");
+        args.push_back("casefold");
+        args.push_back("-C");
+        args.push_back("utf8");
+    }
+    args.push_back(fs_blkdev.c_str());
+    args.push_back(size_str.c_str());
+
+    return logwrap_fork_execvp(args.size(), args.data(), nullptr, false, LOG_KLOG, true, nullptr);
 }
 
 int fs_mgr_do_format(const FstabEntry& entry, bool crypt_footer) {
     LERROR << __FUNCTION__ << ": Format " << entry.blk_device << " as '" << entry.fs_type << "'";
 
+    bool needs_casefold = false;
+    bool needs_projid = false;
+
+    if (entry.mount_point == "/data") {
+        needs_casefold = android::base::GetBoolProperty("ro.emulated_storage.casefold", false);
+        needs_projid = android::base::GetBoolProperty("ro.emulated_storage.projid", false);
+    }
+
     if (entry.fs_type == "f2fs") {
-        return format_f2fs(entry.blk_device, entry.length, crypt_footer);
+        return format_f2fs(entry.blk_device, entry.length, crypt_footer, needs_projid,
+                           needs_casefold);
     } else if (entry.fs_type == "ext4") {
-        return format_ext4(entry.blk_device, entry.mount_point, crypt_footer);
+        return format_ext4(entry.blk_device, entry.mount_point, crypt_footer, needs_projid);
     } else {
         LERROR << "File system type '" << entry.fs_type << "' is not supported";
         return -EINVAL;
diff --git a/fs_mgr/libdm/Android.bp b/fs_mgr/libdm/Android.bp
index 8a924d5..1c3427f 100644
--- a/fs_mgr/libdm/Android.bp
+++ b/fs_mgr/libdm/Android.bp
@@ -54,29 +54,32 @@
 }
 
 cc_defaults {
-    name: "libdm_defaults",
+    name: "libdm_test_defaults",
     defaults: ["fs_mgr_defaults"],
     static_libs: [
         "libdm",
+    ],
+    shared_libs: [
         "libbase",
         "libext2_uuid",
         "libfs_mgr",
         "liblog",
     ],
     srcs: [":libdm_test_srcs"],
+    auto_gen_config: true,
+    require_root: true,
 }
 
 cc_test {
     name: "libdm_test",
-    defaults: ["libdm_defaults"],
+    defaults: ["libdm_test_defaults"],
+    test_suites: ["device-tests"],
 }
 
 cc_test {
     name: "vts_libdm_test",
-    defaults: ["libdm_defaults"],
+    defaults: ["libdm_test_defaults"],
     test_suites: ["vts-core"],
-    auto_gen_config: true,
-    require_root: true,
     test_min_api_level: 29,
 }
 
diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp
index b296801..affdd29 100644
--- a/fs_mgr/libdm/dm_test.cpp
+++ b/fs_mgr/libdm/dm_test.cpp
@@ -533,7 +533,9 @@
     if (is_legacy) {
         ASSERT_EQ(target.GetParameterString(), "AES-256-XTS abcdef0123456789 /dev/loop0 0");
     } else {
-        ASSERT_EQ(target.GetParameterString(), "AES-256-XTS abcdef0123456789 0 /dev/loop0 0");
+        ASSERT_EQ(target.GetParameterString(),
+                  "AES-256-XTS abcdef0123456789 0 /dev/loop0 0 3 allow_discards sector_size:4096 "
+                  "iv_large_sectors");
     }
 }
 
diff --git a/fs_mgr/libfiemap/Android.bp b/fs_mgr/libfiemap/Android.bp
index 1bf457f..2fd463c 100644
--- a/fs_mgr/libfiemap/Android.bp
+++ b/fs_mgr/libfiemap/Android.bp
@@ -104,4 +104,34 @@
     srcs: [
         "image_test.cpp",
     ],
+    test_suites: ["device-tests"],
+    auto_gen_config: true,
+    require_root: true,
+}
+
+/* BUG(148874852) temporary test */
+cc_test {
+    name: "fiemap_image_test_presubmit",
+    cppflags: [
+        "-DSKIP_TEST_IN_PRESUBMIT",
+    ],
+    static_libs: [
+        "libdm",
+        "libext4_utils",
+        "libfs_mgr",
+        "liblp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcrypto",
+        "libcrypto_utils",
+        "libcutils",
+        "liblog",
+    ],
+    srcs: [
+        "image_test.cpp",
+    ],
+    test_suites: ["device-tests"],
+    auto_gen_config: true,
+    require_root: true,
 }
diff --git a/fs_mgr/libfiemap/fiemap_writer.cpp b/fs_mgr/libfiemap/fiemap_writer.cpp
index b911234..4dd4bcc 100644
--- a/fs_mgr/libfiemap/fiemap_writer.cpp
+++ b/fs_mgr/libfiemap/fiemap_writer.cpp
@@ -526,11 +526,7 @@
 }
 
 static bool IsLastExtent(const fiemap_extent* extent) {
-    if (!(extent->fe_flags & FIEMAP_EXTENT_LAST)) {
-        LOG(ERROR) << "Extents are being received out-of-order";
-        return false;
-    }
-    return true;
+    return !!(extent->fe_flags & FIEMAP_EXTENT_LAST);
 }
 
 static bool FiemapToExtents(struct fiemap* fiemap, std::vector<struct fiemap_extent>* extents,
@@ -552,7 +548,10 @@
         fiemap_extent* next = &fiemap->fm_extents[i];
 
         // Make sure extents are returned in order
-        if (next != last_extent && IsLastExtent(next)) return false;
+        if (next != last_extent && IsLastExtent(next)) {
+            LOG(ERROR) << "Extents are being received out-of-order";
+            return false;
+        }
 
         // Check if extent's flags are valid
         if (!IsValidExtent(next, file_path)) return false;
@@ -592,8 +591,7 @@
         return false;
     }
 
-    uint64_t fiemap_size =
-            sizeof(struct fiemap_extent) + num_extents * sizeof(struct fiemap_extent);
+    uint64_t fiemap_size = sizeof(struct fiemap) + num_extents * sizeof(struct fiemap_extent);
     auto buffer = std::unique_ptr<void, decltype(&free)>(calloc(1, fiemap_size), free);
     if (buffer == nullptr) {
         LOG(ERROR) << "Failed to allocate memory for fiemap";
diff --git a/fs_mgr/libfiemap/image_manager.cpp b/fs_mgr/libfiemap/image_manager.cpp
index 0195716..6717922 100644
--- a/fs_mgr/libfiemap/image_manager.cpp
+++ b/fs_mgr/libfiemap/image_manager.cpp
@@ -252,7 +252,7 @@
     // For dm-linear devices sitting on top of /data, we cannot risk deleting
     // the file. The underlying blocks could be reallocated by the filesystem.
     if (IsImageMapped(name)) {
-        LOG(ERROR) << "Backing image " << name << " is currently mapped to a block device";
+        LOG(ERROR) << "Cannot delete backing image " << name << " because mapped to a block device";
         return false;
     }
 
diff --git a/fs_mgr/libfiemap/image_test.cpp b/fs_mgr/libfiemap/image_test.cpp
index 80c340f..5388b44 100644
--- a/fs_mgr/libfiemap/image_test.cpp
+++ b/fs_mgr/libfiemap/image_test.cpp
@@ -212,6 +212,9 @@
 }
 
 TEST_F(ImageTest, IndirectMount) {
+#ifdef SKIP_TEST_IN_PRESUBMIT
+    GTEST_SKIP() << "WIP failure b/148874852";
+#endif
     // Create a simple wrapper around the base device that we'll mount from
     // instead. This will simulate the code paths for dm-crypt/default-key/bow
     // and force us to use device-mapper rather than loop devices.
diff --git a/fs_mgr/libfiemap/metadata.cpp b/fs_mgr/libfiemap/metadata.cpp
index ea1f508..b0dfb5c 100644
--- a/fs_mgr/libfiemap/metadata.cpp
+++ b/fs_mgr/libfiemap/metadata.cpp
@@ -39,7 +39,13 @@
 
 bool MetadataExists(const std::string& metadata_dir) {
     auto metadata_file = GetMetadataFile(metadata_dir);
-    return access(metadata_file.c_str(), F_OK) == 0;
+    if (access(metadata_file.c_str(), F_OK)) {
+        if (errno != ENOENT) {
+            PLOG(ERROR) << "Access " << metadata_file << " failed:";
+        }
+        return false;
+    }
+    return true;
 }
 
 std::unique_ptr<LpMetadata> OpenMetadata(const std::string& metadata_dir) {
@@ -61,7 +67,7 @@
     std::unique_ptr<MetadataBuilder> builder;
     if (access(metadata_file.c_str(), R_OK)) {
         if (errno != ENOENT) {
-            PLOG(ERROR) << "access " << metadata_file << " failed:";
+            PLOG(ERROR) << "Access " << metadata_file << " failed:";
             return nullptr;
         }
 
@@ -112,7 +118,12 @@
 
 bool RemoveAllMetadata(const std::string& dir) {
     auto metadata_file = GetMetadataFile(dir);
-    return android::base::RemoveFileIfExists(metadata_file);
+    std::string err;
+    if (!android::base::RemoveFileIfExists(metadata_file, &err)) {
+        LOG(ERROR) << "Could not remove metadata file: " << err;
+        return false;
+    }
+    return true;
 }
 
 bool FillPartitionExtents(MetadataBuilder* builder, Partition* partition, SplitFiemap* file,
diff --git a/fs_mgr/libfs_avb/fs_avb.cpp b/fs_mgr/libfs_avb/fs_avb.cpp
index 8770a6b..ed623bc 100644
--- a/fs_mgr/libfs_avb/fs_avb.cpp
+++ b/fs_mgr/libfs_avb/fs_avb.cpp
@@ -266,8 +266,10 @@
     return avb_handle;
 }
 
-AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta(const FstabEntry& fstab_entry) {
-    if (fstab_entry.avb_keys.empty()) {
+AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta(const FstabEntry& fstab_entry,
+                                            const std::vector<std::string>& preload_avb_key_blobs) {
+    // At least one of the following should be provided for public key matching.
+    if (preload_avb_key_blobs.empty() && fstab_entry.avb_keys.empty()) {
         LERROR << "avb_keys=/path/to/key(s) is missing for " << fstab_entry.mount_point;
         return nullptr;
     }
@@ -309,18 +311,36 @@
             return nullptr;
     }
 
-    // fstab_entry.avb_keys might be either a directory containing multiple keys,
-    // or a string indicating multiple keys separated by ':'.
-    std::vector<std::string> allowed_avb_keys;
-    auto list_avb_keys_in_dir = ListFiles(fstab_entry.avb_keys);
-    if (list_avb_keys_in_dir) {
-        std::sort(list_avb_keys_in_dir->begin(), list_avb_keys_in_dir->end());
-        allowed_avb_keys = *list_avb_keys_in_dir;
-    } else {
-        allowed_avb_keys = Split(fstab_entry.avb_keys, ":");
+    bool public_key_match = false;
+    // Performs key matching for preload_avb_key_blobs first, if it is present.
+    if (!public_key_data.empty() && !preload_avb_key_blobs.empty()) {
+        if (std::find(preload_avb_key_blobs.begin(), preload_avb_key_blobs.end(),
+                      public_key_data) != preload_avb_key_blobs.end()) {
+            public_key_match = true;
+        }
+    }
+    // Performs key matching for fstab_entry.avb_keys if necessary.
+    // Note that it is intentional to match both preload_avb_key_blobs and fstab_entry.avb_keys.
+    // Some keys might only be availble before init chroots into /system, e.g., /avb/key1
+    // in the first-stage ramdisk, while other keys might only be available after the chroot,
+    // e.g., /system/etc/avb/key2.
+    if (!public_key_data.empty() && !public_key_match) {
+        // fstab_entry.avb_keys might be either a directory containing multiple keys,
+        // or a string indicating multiple keys separated by ':'.
+        std::vector<std::string> allowed_avb_keys;
+        auto list_avb_keys_in_dir = ListFiles(fstab_entry.avb_keys);
+        if (list_avb_keys_in_dir.ok()) {
+            std::sort(list_avb_keys_in_dir->begin(), list_avb_keys_in_dir->end());
+            allowed_avb_keys = *list_avb_keys_in_dir;
+        } else {
+            allowed_avb_keys = Split(fstab_entry.avb_keys, ":");
+        }
+        if (ValidatePublicKeyBlob(public_key_data, allowed_avb_keys)) {
+            public_key_match = true;
+        }
     }
 
-    if (!ValidatePublicKeyBlob(public_key_data, allowed_avb_keys)) {
+    if (!public_key_match) {
         avb_handle->status_ = AvbHandleStatus::kVerificationError;
         LWARNING << "Found unknown public key used to sign " << fstab_entry.mount_point;
         if (!allow_verification_error) {
diff --git a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
index 521f2d5..4702e68 100644
--- a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
+++ b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
@@ -85,8 +85,15 @@
     // TODO(bowgotsai): remove Open() and switch to LoadAndVerifyVbmeta().
     static AvbUniquePtr Open();                 // loads inline vbmeta, via libavb.
     static AvbUniquePtr LoadAndVerifyVbmeta();  // loads inline vbmeta.
-    static AvbUniquePtr LoadAndVerifyVbmeta(
-            const FstabEntry& fstab_entry);     // loads offline vbmeta.
+
+    // The caller can specify optional preload_avb_key_blobs for public key matching.
+    // This is mostly for init to preload AVB keys before chroot into /system.
+    // Both preload_avb_key_blobs and fstab_entry.avb_keys (file paths) will be used
+    // for public key matching.
+    static AvbUniquePtr LoadAndVerifyVbmeta(  // loads offline vbmeta.
+            const FstabEntry& fstab_entry,
+            const std::vector<std::string>& preload_avb_key_blobs = {});
+
     static AvbUniquePtr LoadAndVerifyVbmeta(    // loads offline vbmeta.
             const std::string& partition_name, const std::string& ab_suffix,
             const std::string& ab_other_suffix, const std::string& expected_public_key,
diff --git a/fs_mgr/libfs_avb/tests/util_test.cpp b/fs_mgr/libfs_avb/tests/util_test.cpp
index e64282b..5c388aa 100644
--- a/fs_mgr/libfs_avb/tests/util_test.cpp
+++ b/fs_mgr/libfs_avb/tests/util_test.cpp
@@ -232,8 +232,7 @@
 
     // List files for comparison.
     auto result = ListFiles(test_dir.value());
-    ASSERT_TRUE(result);
-    ASSERT_TRUE(result.has_value());
+    ASSERT_RESULT_OK(result);
     auto files = result.value();
     EXPECT_EQ(3UL, files.size());
     // Sort them offline for comparison.
@@ -266,8 +265,7 @@
 
     // List files for comparison.
     auto result = ListFiles(test_dir.value());
-    ASSERT_TRUE(result);
-    ASSERT_TRUE(result.has_value());
+    ASSERT_RESULT_OK(result);
     auto files = result.value();
     EXPECT_EQ(2UL, files.size());  // Should not include the symlink file.
     // Sort them offline for comparison.
@@ -287,7 +285,7 @@
     base::FilePath no_such_dir = tmp_dir.Append("not_such_dir");
 
     auto fail = ListFiles(no_such_dir.value());
-    ASSERT_FALSE(fail);
+    ASSERT_FALSE(fail.ok());
     EXPECT_EQ(ENOENT, fail.error().code());
     EXPECT_TRUE(android::base::StartsWith(fail.error().message(), "Failed to opendir: "));
 }
@@ -303,8 +301,7 @@
 
     // List files without sorting.
     auto result = ListFiles(test_dir.value());
-    ASSERT_TRUE(result);
-    ASSERT_TRUE(result.has_value());
+    ASSERT_RESULT_OK(result);
     auto files = result.value();
     EXPECT_EQ(0UL, files.size());
 
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index ad48b82..adfee1d 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -95,6 +95,16 @@
     static_libs: [
         "libfs_mgr_binder"
     ],
+
+    shared_libs: [
+        // TODO(b/148818798): remove when parent bug is fixed
+        "libutilscallstack",
+    ],
+    cflags: [
+        "-g",
+        "-O0",
+        "-DLIBSNAPSHOT_USE_CALLSTACK",
+    ],
 }
 
 cc_library_static {
@@ -150,8 +160,8 @@
     ],
 }
 
-cc_test {
-    name: "libsnapshot_test",
+cc_defaults {
+    name: "libsnapshot_test_defaults",
     defaults: ["libsnapshot_defaults"],
     srcs: [
         "partition_cow_creator_test.cpp",
@@ -163,26 +173,48 @@
         "android.hardware.boot@1.1",
         "libbinder",
         "libcrypto",
-        "libfs_mgr",
-        "libgsi",
         "libhidlbase",
-        "liblp",
         "libprotobuf-cpp-lite",
         "libsparse",
         "libutils",
         "libz",
+
+        // TODO(b/148818798): remove when parent bug is fixed
+        "libutilscallstack",
     ],
     static_libs: [
+        "libfs_mgr",
+        "libgsi",
         "libgmock",
+        "liblp",
         "libsnapshot",
         "libsnapshot_test_helpers",
     ],
     header_libs: [
         "libstorage_literals_headers",
     ],
+    test_suites: [
+        "vts-core",
+        "device-tests"
+    ],
+    test_min_api_level: 29,
+    auto_gen_config: true,
     require_root: true,
 }
 
+cc_test {
+    name: "vts_libsnapshot_test",
+    defaults: ["libsnapshot_test_defaults"],
+}
+
+cc_test {
+    name: "vts_libsnapshot_test_presubmit",
+    defaults: ["libsnapshot_test_defaults"],
+    cppflags: [
+        "-DSKIP_TEST_IN_PRESUBMIT",
+    ],
+}
+
 cc_binary {
     name: "snapshotctl",
     srcs: [
@@ -198,7 +230,6 @@
         "android.hardware.boot@1.1",
         "libbase",
         "libbinder",
-        "libbinderthreadstate",
         "libext2_uuid",
         "libext4_utils",
         "libfs_mgr_binder",
@@ -207,6 +238,9 @@
         "liblp",
         "libprotobuf-cpp-lite",
         "libutils",
+
+        // TODO(b/148818798): remove when parent bug is fixed.
+        "libutilscallstack",
     ],
     init_rc: [
         "snapshotctl.rc",
diff --git a/fs_mgr/libsnapshot/device_info.cpp b/fs_mgr/libsnapshot/device_info.cpp
index bacb41c..0e90100 100644
--- a/fs_mgr/libsnapshot/device_info.cpp
+++ b/fs_mgr/libsnapshot/device_info.cpp
@@ -22,6 +22,7 @@
 namespace snapshot {
 
 #ifdef LIBSNAPSHOT_USE_HAL
+using android::hardware::boot::V1_0::BoolResult;
 using android::hardware::boot::V1_0::CommandResult;
 #endif
 
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index e786bc9..ed92dd7 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -174,6 +174,7 @@
     // See InitiateMerge() and ProcessUpdateState() for details.
     // Returns:
     //   - None if no merge to initiate
+    //   - Unverified if called on the source slot
     //   - MergeCompleted if merge is completed
     //   - other states indicating an error has occurred
     UpdateState InitiateMergeAndWait();
@@ -273,6 +274,7 @@
     FRIEND_TEST(SnapshotTest, UpdateBootControlHal);
     FRIEND_TEST(SnapshotUpdateTest, DataWipeAfterRollback);
     FRIEND_TEST(SnapshotUpdateTest, DataWipeRollbackInRecovery);
+    FRIEND_TEST(SnapshotUpdateTest, FullUpdateFlow);
     FRIEND_TEST(SnapshotUpdateTest, MergeCannotRemoveCow);
     FRIEND_TEST(SnapshotUpdateTest, MergeInRecovery);
     FRIEND_TEST(SnapshotUpdateTest, SnapshotStatusFileWithoutCow);
@@ -374,7 +376,7 @@
     bool HandleCancelledUpdate(LockedFile* lock);
 
     // Helper for HandleCancelledUpdate. Assumes booting from new slot.
-    bool HandleCancelledUpdateOnNewSlot(LockedFile* lock);
+    bool AreAllSnapshotsCancelled(LockedFile* lock);
 
     // Remove artifacts created by the update process, such as snapshots, and
     // set the update state to None.
@@ -439,7 +441,7 @@
     std::string GetSnapshotStatusFilePath(const std::string& name);
 
     std::string GetSnapshotBootIndicatorPath();
-    void RemoveSnapshotBootIndicator();
+    std::string GetRollbackIndicatorPath();
 
     // Return the name of the device holding the "snapshot" or "snapshot-merge"
     // target. This may not be the final device presented via MapSnapshot(), if
@@ -503,6 +505,8 @@
     friend std::ostream& operator<<(std::ostream& os, SnapshotManager::Slot slot);
     Slot GetCurrentSlot();
 
+    std::string ReadUpdateSourceSlotSuffix();
+
     std::string gsid_dir_;
     std::string metadata_dir_;
     std::unique_ptr<IDeviceInfo> device_;
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 785882a..a937b43 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -21,6 +21,7 @@
 #include <sys/unistd.h>
 
 #include <optional>
+#include <sstream>
 #include <thread>
 #include <unordered_set>
 
@@ -37,6 +38,10 @@
 #include <libfiemap/image_manager.h>
 #include <liblp/liblp.h>
 
+#ifdef LIBSNAPSHOT_USE_CALLSTACK
+#include <utils/CallStack.h>
+#endif
+
 #include <android/snapshot/snapshot.pb.h>
 #include "device_info.h"
 #include "partition_cow_creator.h"
@@ -183,11 +188,19 @@
     return true;
 }
 
-SnapshotManager::Slot SnapshotManager::GetCurrentSlot() {
+std::string SnapshotManager::ReadUpdateSourceSlotSuffix() {
     auto boot_file = GetSnapshotBootIndicatorPath();
     std::string contents;
     if (!android::base::ReadFileToString(boot_file, &contents)) {
         PLOG(WARNING) << "Cannot read " << boot_file;
+        return {};
+    }
+    return contents;
+}
+
+SnapshotManager::Slot SnapshotManager::GetCurrentSlot() {
+    auto contents = ReadUpdateSourceSlotSuffix();
+    if (contents.empty()) {
         return Slot::Unknown;
     }
     if (device_->GetSlotSuffix() == contents) {
@@ -196,13 +209,44 @@
     return Slot::Target;
 }
 
+static bool RemoveFileIfExists(const std::string& path) {
+    std::string message;
+    if (!android::base::RemoveFileIfExists(path, &message)) {
+        LOG(ERROR) << "Remove failed: " << path << ": " << message;
+        return false;
+    }
+    return true;
+}
+
 bool SnapshotManager::RemoveAllUpdateState(LockedFile* lock) {
+    LOG(INFO) << "Removing all update state.";
+
+#ifdef LIBSNAPSHOT_USE_CALLSTACK
+    LOG(WARNING) << "Logging stack; see b/148818798.";
+    // Do not use CallStack's log functions because snapshotctl relies on
+    // android-base/logging to save log to files.
+    // TODO(b/148818798): remove this before we ship.
+    CallStack callstack;
+    callstack.update();
+    auto callstack_str = callstack.toString();
+    LOG(WARNING) << callstack_str.c_str();
+    std::stringstream path;
+    path << "/data/misc/snapshotctl_log/libsnapshot." << Now() << ".log";
+    android::base::WriteStringToFile(callstack_str.c_str(), path.str());
+#endif
+
     if (!RemoveAllSnapshots(lock)) {
         LOG(ERROR) << "Could not remove all snapshots";
         return false;
     }
 
-    RemoveSnapshotBootIndicator();
+    // It's okay if these fail - first-stage init performs a deeper check after
+    // reading the indicator file, so it's not a problem if it still exists
+    // after the update completes.
+    std::vector<std::string> files = {GetSnapshotBootIndicatorPath(), GetRollbackIndicatorPath()};
+    for (const auto& file : files) {
+        RemoveFileIfExists(file);
+    }
 
     // If this fails, we'll keep trying to remove the update state (as the
     // device reboots or starts a new update) until it finally succeeds.
@@ -229,6 +273,13 @@
         return false;
     }
 
+    // This file is written on boot to detect whether a rollback occurred. It
+    // MUST NOT exist before rebooting, otherwise, we're at risk of deleting
+    // snapshots too early.
+    if (!RemoveFileIfExists(GetRollbackIndicatorPath())) {
+        return false;
+    }
+
     // This file acts as both a quick indicator for init (it can use access(2)
     // to decide how to do first-stage mounts), and it stores the old slot, so
     // we can tell whether or not we performed a rollback.
@@ -945,14 +996,8 @@
     return metadata_dir_ + "/" + android::base::Basename(kBootIndicatorPath);
 }
 
-void SnapshotManager::RemoveSnapshotBootIndicator() {
-    // It's okay if this fails - first-stage init performs a deeper check after
-    // reading the indicator file, so it's not a problem if it still exists
-    // after the update completes.
-    auto boot_file = GetSnapshotBootIndicatorPath();
-    if (unlink(boot_file.c_str()) == -1 && errno != ENOENT) {
-        PLOG(ERROR) << "unlink " << boot_file;
-    }
+std::string SnapshotManager::GetRollbackIndicatorPath() {
+    return metadata_dir_ + "/rollback-indicator";
 }
 
 void SnapshotManager::AcknowledgeMergeSuccess(LockedFile* lock) {
@@ -1123,25 +1168,18 @@
     if (slot == Slot::Unknown) {
         return false;
     }
-    if (slot == Slot::Target) {
-        // We're booted into the target slot, which means we just rebooted
-        // after applying the update.
-        if (!HandleCancelledUpdateOnNewSlot(lock)) {
-            return false;
-        }
+
+    // If all snapshots were reflashed, then cancel the entire update.
+    if (AreAllSnapshotsCancelled(lock)) {
+        RemoveAllUpdateState(lock);
+        return true;
     }
 
-    // The only way we can get here is if:
-    //  (1) The device rolled back to the previous slot.
-    //  (2) This function was called prematurely before rebooting the device.
-    //  (3) fastboot set_active was used.
-    //  (4) The device updates to the new slot but re-flashed *all* partitions
-    //      in the new slot.
-    //
-    // In any case, delete the snapshots. It may be worth using the boot_control
-    // HAL to differentiate case (2).
-    RemoveAllUpdateState(lock);
-    return true;
+    // This unverified update might be rolled back, or it might not (b/147347110
+    // comment #77). Take no action, as update_engine is responsible for deciding
+    // whether to cancel.
+    LOG(ERROR) << "Update state is being processed before reboot, taking no action.";
+    return false;
 }
 
 std::unique_ptr<LpMetadata> SnapshotManager::ReadCurrentMetadata() {
@@ -1166,7 +1204,7 @@
     return MetadataPartitionState::Flashed;
 }
 
-bool SnapshotManager::HandleCancelledUpdateOnNewSlot(LockedFile* lock) {
+bool SnapshotManager::AreAllSnapshotsCancelled(LockedFile* lock) {
     std::vector<std::string> snapshots;
     if (!ListSnapshots(lock, &snapshots)) {
         LOG(WARNING) << "Failed to list snapshots to determine whether device has been flashed "
@@ -1175,35 +1213,45 @@
         return true;
     }
 
+    auto source_slot_suffix = ReadUpdateSourceSlotSuffix();
+    if (source_slot_suffix.empty()) {
+        return false;
+    }
+    uint32_t source_slot = SlotNumberForSlotSuffix(source_slot_suffix);
+    uint32_t target_slot = (source_slot == 0) ? 1 : 0;
+
     // Attempt to detect re-flashing on each partition.
     // - If all partitions are re-flashed, we can proceed to cancel the whole update.
     // - If only some of the partitions are re-flashed, snapshots for re-flashed partitions are
     //   deleted. Caller is responsible for merging the rest of the snapshots.
     // - If none of the partitions are re-flashed, caller is responsible for merging the snapshots.
-    auto metadata = ReadCurrentMetadata();
-    if (!metadata) return false;
-    bool all_snapshot_cancelled = true;
+    //
+    // Note that we use target slot metadata, since if an OTA has been applied
+    // to the target slot, we can detect the UPDATED flag. Any kind of flash
+    // operation against dynamic partitions ensures that all copies of the
+    // metadata are in sync, so flashing all partitions on the source slot will
+    // remove the UPDATED flag on the target slot as well.
+    const auto& opener = device_->GetPartitionOpener();
+    auto super_device = device_->GetSuperDevice(target_slot);
+    auto metadata = android::fs_mgr::ReadMetadata(opener, super_device, target_slot);
+    if (!metadata) {
+        return false;
+    }
+
+    bool all_snapshots_cancelled = true;
     for (const auto& snapshot_name : snapshots) {
         if (GetMetadataPartitionState(*metadata, snapshot_name) ==
             MetadataPartitionState::Updated) {
-            LOG(WARNING) << "Cannot cancel update because snapshot" << snapshot_name
-                         << " is in use.";
-            all_snapshot_cancelled = false;
+            all_snapshots_cancelled = false;
             continue;
         }
         // Delete snapshots for partitions that are re-flashed after the update.
-        LOG(INFO) << "Detected re-flashing of partition " << snapshot_name << ".";
-        if (!DeleteSnapshot(lock, snapshot_name)) {
-            // This is an error, but it is okay to leave the snapshot in the short term.
-            // However, if all_snapshot_cancelled == false after exiting the loop, caller may
-            // initiate merge for this unused snapshot, which is likely to fail.
-            LOG(WARNING) << "Failed to delete snapshot for re-flashed partition " << snapshot_name;
-        }
+        LOG(WARNING) << "Detected re-flashing of partition " << snapshot_name << ".";
     }
-    if (!all_snapshot_cancelled) return false;
-
-    LOG(INFO) << "All partitions are re-flashed after update, removing all update states.";
-    return true;
+    if (all_snapshots_cancelled) {
+        LOG(WARNING) << "All partitions are re-flashed after update, removing all update states.";
+    }
+    return all_snapshots_cancelled;
 }
 
 bool SnapshotManager::RemoveAllSnapshots(LockedFile* lock) {
@@ -1323,7 +1371,16 @@
     // the reason be clearer? Because the indicator file still exists, and
     // if this was FATAL, reverting to the old slot would be broken.
     auto slot = GetCurrentSlot();
+
     if (slot != Slot::Target) {
+        if (slot == Slot::Source && !device_->IsRecovery()) {
+            // Device is rebooting into the original slot, so mark this as a
+            // rollback.
+            auto path = GetRollbackIndicatorPath();
+            if (!android::base::WriteStringToFile("1", path)) {
+                PLOG(ERROR) << "Unable to write rollback indicator: " << path;
+            }
+        }
         LOG(INFO) << "Not booting from new slot. Will not mount snapshots.";
         return false;
     }
@@ -1709,6 +1766,8 @@
         return UpdateState::MergeNeedsReboot;
     } else if (contents == "merge-failed") {
         return UpdateState::MergeFailed;
+    } else if (contents == "cancelled") {
+        return UpdateState::Cancelled;
     } else {
         LOG(ERROR) << "Unknown merge state in update state file: \"" << contents << "\"";
         return UpdateState::None;
@@ -1731,6 +1790,8 @@
             return os << "merge-needs-reboot";
         case UpdateState::MergeFailed:
             return os << "merge-failed";
+        case UpdateState::Cancelled:
+            return os << "cancelled";
         default:
             LOG(ERROR) << "Unknown update state: " << static_cast<uint32_t>(state);
             return os;
@@ -2345,6 +2406,10 @@
         return state;
     }
     if (state == UpdateState::Unverified) {
+        if (GetCurrentSlot() != Slot::Target) {
+            LOG(INFO) << "Cannot merge until device reboots.";
+            return state;
+        }
         if (!InitiateMerge()) {
             LOG(ERROR) << "Failed to initiate merge.";
             return state;
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index c49c49e..d87274d 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -335,6 +335,7 @@
         return AssertionSuccess();
     }
 
+    static constexpr std::chrono::milliseconds snapshot_timeout_ = 5s;
     bool is_virtual_ab_;
     DeviceMapper& dm_;
     std::unique_ptr<SnapshotManager::LockedFile> lock_;
@@ -446,6 +447,9 @@
     auto sm = SnapshotManager::NewForFirstStageMount(info);
     ASSERT_NE(sm, nullptr);
     ASSERT_FALSE(sm->NeedSnapshotsInFirstStageMount());
+
+    auto indicator = sm->GetRollbackIndicatorPath();
+    ASSERT_EQ(access(indicator.c_str(), R_OK), 0);
 }
 
 TEST_F(SnapshotTest, Merge) {
@@ -502,6 +506,9 @@
 }
 
 TEST_F(SnapshotTest, FirstStageMountAndMerge) {
+#ifdef SKIP_TEST_IN_PRESUBMIT
+    GTEST_SKIP() << "WIP failure b/148889015";
+#endif
     ASSERT_TRUE(AcquireLock());
 
     static const uint64_t kDeviceSize = 1024 * 1024;
@@ -511,7 +518,7 @@
     auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
     ASSERT_NE(init, nullptr);
     ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
-    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
 
     ASSERT_TRUE(AcquireLock());
 
@@ -540,7 +547,7 @@
     auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
     ASSERT_NE(init, nullptr);
     ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
-    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
 
     ASSERT_TRUE(AcquireLock());
 
@@ -558,6 +565,9 @@
 }
 
 TEST_F(SnapshotTest, FlashSuperDuringMerge) {
+#ifdef SKIP_TEST_IN_PRESUBMIT
+    GTEST_SKIP() << "WIP failure b/148889015";
+#endif
     ASSERT_TRUE(AcquireLock());
 
     static const uint64_t kDeviceSize = 1024 * 1024;
@@ -567,7 +577,7 @@
     auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
     ASSERT_NE(init, nullptr);
     ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
-    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
     ASSERT_TRUE(init->InitiateMerge());
 
     // Now, reflash super. Note that we haven't called ProcessUpdateState, so the
@@ -577,7 +587,7 @@
     FormatFakeSuper();
     ASSERT_TRUE(CreatePartition("test_partition_b", kDeviceSize));
     ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
-    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
 
     // Because the status is Merging, we must call ProcessUpdateState, which should
     // detect a cancelled update.
@@ -969,6 +979,9 @@
 // Also test UnmapUpdateSnapshot unmaps everything.
 // Also test first stage mount and merge after this.
 TEST_F(SnapshotUpdateTest, FullUpdateFlow) {
+#ifdef SKIP_TEST_IN_PRESUBMIT
+    GTEST_SKIP() << "WIP failure b/148889015";
+#endif
     // OTA client blindly unmaps all partitions that are possibly mapped.
     for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
         ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
@@ -1012,7 +1025,10 @@
     auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
     ASSERT_NE(init, nullptr);
     ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
-    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", 1s));
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
+
+    auto indicator = sm->GetRollbackIndicatorPath();
+    ASSERT_NE(access(indicator.c_str(), R_OK), 0);
 
     // Check that the target partitions have the same content.
     for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
@@ -1113,6 +1129,9 @@
 
 // Test that the old partitions are not modified.
 TEST_F(SnapshotUpdateTest, TestRollback) {
+#ifdef SKIP_TEST_IN_PRESUBMIT
+    GTEST_SKIP() << "WIP failure b/148889015";
+#endif
     // Execute the update.
     ASSERT_TRUE(sm->BeginUpdate());
     ASSERT_TRUE(sm->UnmapUpdateSnapshot("sys_b"));
@@ -1140,7 +1159,7 @@
     auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
     ASSERT_NE(init, nullptr);
     ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
-    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", 1s));
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
 
     // Check that the target partitions have the same content.
     for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
@@ -1152,7 +1171,7 @@
     init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_a"));
     ASSERT_NE(init, nullptr);
     ASSERT_FALSE(init->NeedSnapshotsInFirstStageMount());
-    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", 1s));
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
 
     // Assert that the source partitions aren't affected.
     for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
@@ -1189,7 +1208,7 @@
     auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
     ASSERT_NE(init, nullptr);
     ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
-    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
     init = nullptr;
 
     // Initiate the merge and wait for it to be completed.
@@ -1290,6 +1309,9 @@
 }
 
 TEST_F(SnapshotUpdateTest, MergeCannotRemoveCow) {
+#ifdef SKIP_TEST_IN_PRESUBMIT
+    GTEST_SKIP() << "WIP failure b/148889015";
+#endif
     // Make source partitions as big as possible to force COW image to be created.
     SetSize(sys_, 5_MiB);
     SetSize(vnd_, 5_MiB);
@@ -1325,7 +1347,7 @@
     // won't be set.
     auto init = SnapshotManager::New(new TestDeviceInfo(fake_super, "_b"));
     ASSERT_NE(init, nullptr);
-    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
 
     // Keep an open handle to the cow device. This should cause the merge to
     // be incomplete.
@@ -1341,7 +1363,7 @@
     ASSERT_TRUE(UnmapAll());
 
     // init does first stage mount again.
-    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
 
     // sys_b should be mapped as a dm-linear device directly.
     ASSERT_FALSE(sm->IsSnapshotDevice("sys_b", nullptr));
@@ -1427,7 +1449,7 @@
     auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
     ASSERT_NE(init, nullptr);
     ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
-    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
     init = nullptr;
 
     // Initiate the merge and then immediately stop it to simulate a reboot.
@@ -1532,7 +1554,7 @@
     auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
     ASSERT_NE(init, nullptr);
     ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
-    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", 1s));
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
 
     // Check that the target partition have the same content. Hashtree and FEC extents
     // should be accounted for.
@@ -1564,6 +1586,9 @@
 }
 
 TEST_F(SnapshotUpdateTest, WaitForMerge) {
+#ifdef SKIP_TEST_IN_PRESUBMIT
+    GTEST_SKIP() << "WIP failure b/148889015";
+#endif
     AddOperationForPartitions();
 
     // Execute the update.
@@ -1584,7 +1609,7 @@
     {
         auto init = SnapshotManager::NewForFirstStageMount(new TestDeviceInfo(fake_super, "_b"));
         ASSERT_NE(nullptr, init);
-        ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
+        ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
     }
 
     auto new_sm = SnapshotManager::New(new TestDeviceInfo(fake_super, "_b"));
@@ -1630,7 +1655,7 @@
   public:
     AssertionResult InitiateMerge(const std::string& slot_suffix) {
         auto sm = SnapshotManager::New(new TestDeviceInfo(fake_super, slot_suffix));
-        if (!sm->CreateLogicalAndSnapshotPartitions("super")) {
+        if (!sm->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_)) {
             return AssertionFailure() << "Cannot CreateLogicalAndSnapshotPartitions";
         }
         if (!sm->InitiateMerge()) {
@@ -1680,9 +1705,11 @@
     ASSERT_NE(nullptr, flashed_builder->FindPartition("prd" + flashed_slot_suffix));
     flashed_builder->RemovePartition("prd" + flashed_slot_suffix);
 
+    // Note that fastbootd always updates the partition table of both slots.
     auto flashed_metadata = flashed_builder->Export();
     ASSERT_NE(nullptr, flashed_metadata);
-    ASSERT_TRUE(UpdatePartitionTable(*opener_, "super", *flashed_metadata, flashed_slot));
+    ASSERT_TRUE(UpdatePartitionTable(*opener_, "super", *flashed_metadata, 0));
+    ASSERT_TRUE(UpdatePartitionTable(*opener_, "super", *flashed_metadata, 1));
 
     std::string path;
     for (const auto& name : {"sys", "vnd"}) {
@@ -1712,7 +1739,7 @@
     if (flashed_slot && after_merge) {
         ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
     }
-    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", 1s));
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
 
     // Check that the target partitions have the same content.
     for (const auto& name : {"sys", "vnd"}) {
@@ -1781,6 +1808,10 @@
     std::vector<uint64_t> ret;
     for (uint64_t size = 1_MiB; size <= 512_MiB; size *= 2) {
         ret.push_back(size);
+#ifdef SKIP_TEST_IN_PRESUBMIT
+        // BUG(148889015);
+        break;
+#endif
     }
     return ret;
 }
diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp
index 1bc0357..d724be3 100644
--- a/fs_mgr/libsnapshot/snapshotctl.cpp
+++ b/fs_mgr/libsnapshot/snapshotctl.cpp
@@ -19,9 +19,15 @@
 #include <chrono>
 #include <iostream>
 #include <map>
+#include <sstream>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/unique_fd.h>
 #include <libsnapshot/snapshot.h>
+#include "utility.h"
+
+#include "utility.h"
 
 using namespace std::string_literals;
 
@@ -31,9 +37,11 @@
                  "Actions:\n"
                  "  dump\n"
                  "    Print snapshot states.\n"
-                 "  merge [--logcat]\n"
+                 "  merge [--logcat] [--log-to-file]\n"
                  "    Initialize merge and wait for it to be completed.\n"
-                 "    If --logcat is specified, log to logcat. Otherwise, log to stdout.\n";
+                 "    If --logcat is specified, log to logcat.\n"
+                 "    If --log-to-file is specified, log to /data/misc/snapshotctl_log/.\n"
+                 "    If both specified, log to both. If none specified, log to stdout.\n";
     return EX_USAGE;
 }
 
@@ -45,24 +53,68 @@
     return SnapshotManager::New()->Dump(std::cout);
 }
 
+class FileLogger {
+  public:
+    FileLogger() {
+        static constexpr const char* kLogFilePath = "/data/misc/snapshotctl_log/";
+        std::stringstream ss;
+        ss << kLogFilePath << "snapshotctl." << Now() << ".log";
+        fd_.reset(TEMP_FAILURE_RETRY(
+                open(ss.str().c_str(),
+                     O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_SYNC, 0660)));
+    }
+    // Copy-contuctor needed to be converted to std::function.
+    FileLogger(const FileLogger& other) { fd_.reset(dup(other.fd_)); }
+    void operator()(android::base::LogId, android::base::LogSeverity, const char* /*tag*/,
+                    const char* /*file*/, unsigned int /*line*/, const char* message) {
+        if (fd_ == -1) return;
+        std::stringstream ss;
+        ss << Now() << ":" << message << "\n";
+        (void)android::base::WriteStringToFd(ss.str(), fd_);
+    }
+
+  private:
+    android::base::unique_fd fd_;
+};
+
+class MergeCmdLogger {
+  public:
+    MergeCmdLogger(int argc, char** argv) {
+        for (int i = 0; i < argc; ++i) {
+            if (argv[i] == "--logcat"s) {
+                loggers_.push_back(android::base::LogdLogger());
+            }
+            if (argv[i] == "--log-to-file"s) {
+                loggers_.push_back(std::move(FileLogger()));
+            }
+        }
+        if (loggers_.empty()) {
+            loggers_.push_back(&android::base::StdioLogger);
+        }
+    }
+    void operator()(android::base::LogId id, android::base::LogSeverity severity, const char* tag,
+                    const char* file, unsigned int line, const char* message) {
+        for (auto&& logger : loggers_) {
+            logger(id, severity, tag, file, line, message);
+        }
+    }
+
+  private:
+    std::vector<android::base::LogFunction> loggers_;
+};
+
 bool MergeCmdHandler(int argc, char** argv) {
     auto begin = std::chrono::steady_clock::now();
 
-    bool log_to_logcat = false;
-    for (int i = 2; i < argc; ++i) {
-        if (argv[i] == "--logcat"s) {
-            log_to_logcat = true;
-        }
-    }
-    if (log_to_logcat) {
-        android::base::InitLogging(argv);
-    } else {
-        android::base::InitLogging(argv, &android::base::StdioLogger);
-    }
+    // 'snapshotctl merge' is stripped away from arguments to
+    // Logger.
+    android::base::InitLogging(argv, MergeCmdLogger(argc - 2, argv + 2));
 
     auto state = SnapshotManager::New()->InitiateMergeAndWait();
 
-    if (state == UpdateState::None) {
+    // We could wind up in the Unverified state if the device rolled back or
+    // hasn't fully rebooted. Ignore this.
+    if (state == UpdateState::None || state == UpdateState::Unverified) {
         return true;
     }
     if (state == UpdateState::MergeCompleted) {
diff --git a/fs_mgr/libsnapshot/snapshotctl.rc b/fs_mgr/libsnapshot/snapshotctl.rc
index 3ab0645..5dbe352 100644
--- a/fs_mgr/libsnapshot/snapshotctl.rc
+++ b/fs_mgr/libsnapshot/snapshotctl.rc
@@ -1,2 +1,2 @@
 on property:sys.boot_completed=1
-    exec_background - root root -- /system/bin/snapshotctl merge --logcat
+    exec_background - root root -- /system/bin/snapshotctl merge --logcat --log-to-file
diff --git a/fs_mgr/libsnapshot/utility.cpp b/fs_mgr/libsnapshot/utility.cpp
index 3a64448..3318b33 100644
--- a/fs_mgr/libsnapshot/utility.cpp
+++ b/fs_mgr/libsnapshot/utility.cpp
@@ -15,6 +15,10 @@
 #include "utility.h"
 
 #include <errno.h>
+#include <time.h>
+
+#include <iomanip>
+#include <sstream>
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
@@ -155,5 +159,12 @@
     return true;
 }
 
+std::ostream& operator<<(std::ostream& os, const Now&) {
+    struct tm now;
+    time_t t = time(nullptr);
+    localtime_r(&t, &now);
+    return os << std::put_time(&now, "%Y%m%d-%H%M%S");
+}
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/utility.h b/fs_mgr/libsnapshot/utility.h
index ad46090..90ad0fe 100644
--- a/fs_mgr/libsnapshot/utility.h
+++ b/fs_mgr/libsnapshot/utility.h
@@ -15,6 +15,7 @@
 #pragma once
 
 #include <functional>
+#include <iostream>
 #include <string>
 
 #include <android-base/macros.h>
@@ -120,5 +121,9 @@
 // is an open fd to |path|, because that fd has an old view of the file.
 bool WriteStringToFileAtomic(const std::string& content, const std::string& path);
 
+// Writes current time to a given stream.
+struct Now {};
+std::ostream& operator<<(std::ostream& os, const Now&);
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libvbmeta/builder.cpp b/fs_mgr/libvbmeta/builder.cpp
index a901a4f..e6576ce 100644
--- a/fs_mgr/libvbmeta/builder.cpp
+++ b/fs_mgr/libvbmeta/builder.cpp
@@ -40,18 +40,18 @@
 Result<void> SuperVBMetaBuilder::Build() {
     for (const auto& [vbmeta_name, file_path] : images_path_) {
         Result<std::string> content = ReadVBMetaImageFromFile(file_path);
-        if (!content) {
+        if (!content.ok()) {
             return content.error();
         }
 
         Result<uint8_t> vbmeta_index = AddVBMetaImage(vbmeta_name);
-        if (!vbmeta_index) {
+        if (!vbmeta_index.ok()) {
             return vbmeta_index.error();
         }
 
         Result<void> rv_export_vbmeta_image =
                 ExportVBMetaImageToFile(vbmeta_index.value(), content.value());
-        if (!rv_export_vbmeta_image) {
+        if (!rv_export_vbmeta_image.ok()) {
             return rv_export_vbmeta_image;
         }
     }
@@ -65,7 +65,7 @@
     }
 
     Result<uint64_t> file_size = GetFileSize(source_fd);
-    if (!file_size) {
+    if (!file_size.ok()) {
         return file_size.error();
     }
 
@@ -98,7 +98,7 @@
         slot_number = desc->vbmeta_index;
     } else {
         Result<uint8_t> new_slot = GetEmptySlot();
-        if (!new_slot) {
+        if (!new_slot.ok()) {
             return new_slot;
         }
         slot_number = new_slot.value();
@@ -162,7 +162,7 @@
 
     android::base::Result<void> rv_write_primary_vbmeta_table =
             WritePrimaryVBMetaTable(super_vbmeta_fd_, serialized_table);
-    if (!rv_write_primary_vbmeta_table) {
+    if (!rv_write_primary_vbmeta_table.ok()) {
         return rv_write_primary_vbmeta_table;
     }
 
@@ -175,7 +175,7 @@
                                                          const std::string& vbmeta_image) {
     Result<void> rv_write_vbmeta_image =
             WriteVBMetaImage(super_vbmeta_fd_, vbmeta_index, vbmeta_image);
-    if (!rv_write_vbmeta_image) {
+    if (!rv_write_vbmeta_image.ok()) {
         return rv_write_vbmeta_image;
     }
 
@@ -196,13 +196,13 @@
     SuperVBMetaBuilder builder(super_vbmeta_fd, images_path);
 
     Result<void> rv_build = builder.Build();
-    if (!rv_build) {
+    if (!rv_build.ok()) {
         LERROR << rv_build.error();
         return false;
     }
 
     Result<void> rv_export = builder.ExportVBMetaTableToFile();
-    if (!rv_export) {
+    if (!rv_export.ok()) {
         LERROR << rv_export.error();
         return false;
     }
@@ -211,4 +211,4 @@
 }
 
 }  // namespace fs_mgr
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/fs_mgr/libvbmeta/builder_test.cpp b/fs_mgr/libvbmeta/builder_test.cpp
index 9a015fd..487bece 100644
--- a/fs_mgr/libvbmeta/builder_test.cpp
+++ b/fs_mgr/libvbmeta/builder_test.cpp
@@ -26,24 +26,20 @@
     std::unique_ptr<SuperVBMetaBuilder> builder = std::make_unique<SuperVBMetaBuilder>();
     ASSERT_NE(builder, nullptr);
 
-    Result<uint8_t> vbmeta_index = builder->AddVBMetaImage("vbmeta" /* vbmeta_name */
-    );
-    EXPECT_TRUE(vbmeta_index);
+    Result<uint8_t> vbmeta_index = builder->AddVBMetaImage("vbmeta" /* vbmeta_name */);
+    EXPECT_RESULT_OK(vbmeta_index);
 
-    Result<uint8_t> vbmeta_system_slot = builder->AddVBMetaImage("vbmeta_system" /* vbmeta_name */
-    );
-    EXPECT_TRUE(vbmeta_system_slot);
+    Result<uint8_t> vbmeta_system_slot = builder->AddVBMetaImage("vbmeta_system" /* vbmeta_name */);
+    EXPECT_RESULT_OK(vbmeta_system_slot);
 
-    Result<uint8_t> vbmeta_vendor_slot = builder->AddVBMetaImage("vbmeta_vendor" /* vbmeta_name */
-    );
-    EXPECT_TRUE(vbmeta_vendor_slot);
+    Result<uint8_t> vbmeta_vendor_slot = builder->AddVBMetaImage("vbmeta_vendor" /* vbmeta_name */);
+    EXPECT_RESULT_OK(vbmeta_vendor_slot);
 
-    builder->DeleteVBMetaImage("vbmeta_system" /* vbmeta_name */
-    );
+    builder->DeleteVBMetaImage("vbmeta_system" /* vbmeta_name */);
 
-    Result<uint8_t> vbmeta_product_slot = builder->AddVBMetaImage("vbmeta_product" /* vbmeta_name */
-    );
-    EXPECT_TRUE(vbmeta_product_slot);
+    Result<uint8_t> vbmeta_product_slot =
+            builder->AddVBMetaImage("vbmeta_product" /* vbmeta_name */);
+    EXPECT_RESULT_OK(vbmeta_product_slot);
 
     std::unique_ptr<VBMetaTable> table = builder->ExportVBMetaTable();
     ASSERT_NE(table, nullptr);
@@ -77,4 +73,4 @@
     for (int i = 0; i < sizeof(table->descriptors[2].reserved); i++)
         EXPECT_EQ(table->descriptors[2].reserved[i], 0);
     EXPECT_EQ(table->descriptors[2].vbmeta_name, "vbmeta_product");
-}
\ No newline at end of file
+}
diff --git a/fs_mgr/libvbmeta/reader.cpp b/fs_mgr/libvbmeta/reader.cpp
index 212d186..7b5ed93 100644
--- a/fs_mgr/libvbmeta/reader.cpp
+++ b/fs_mgr/libvbmeta/reader.cpp
@@ -64,7 +64,7 @@
     }
 
     Result<void> rv_header = LoadAndVerifySuperVBMetaHeader(header_buffer.get(), &table->header);
-    if (!rv_header) {
+    if (!rv_header.ok()) {
         return rv_header;
     }
 
@@ -104,7 +104,7 @@
 Result<void> ValidateVBMetaImage(int super_vbmeta_fd, int vbmeta_index,
                                  const std::string& vbmeta_image) {
     Result<std::string> content = ReadVBMetaImage(super_vbmeta_fd, vbmeta_index);
-    if (!content) {
+    if (!content.ok()) {
         return content.error();
     }
 
diff --git a/fs_mgr/libvbmeta/super_vbmeta_test.cpp b/fs_mgr/libvbmeta/super_vbmeta_test.cpp
index 6b4fc5d..daed0d1 100644
--- a/fs_mgr/libvbmeta/super_vbmeta_test.cpp
+++ b/fs_mgr/libvbmeta/super_vbmeta_test.cpp
@@ -77,7 +77,7 @@
     android::base::unique_fd fd(open(file.c_str(), O_RDONLY | O_CLOEXEC));
     EXPECT_GT(fd, 0);
     Result<uint64_t> file_size = GetFileSize(fd);
-    EXPECT_TRUE(file_size);
+    EXPECT_RESULT_OK(file_size);
     std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(VBMETA_IMAGE_MAX_SIZE);
     EXPECT_TRUE(android::base::ReadFully(fd, buffer.get(), file_size.value()));
     return std::string(reinterpret_cast<char*>(buffer.get()), VBMETA_IMAGE_MAX_SIZE);
@@ -138,15 +138,15 @@
 
     // Check the size of vbmeta table
     Result<uint64_t> super_vbmeta_size = GetFileSize(fd);
-    EXPECT_TRUE(super_vbmeta_size);
+    EXPECT_RESULT_OK(super_vbmeta_size);
     EXPECT_EQ(super_vbmeta_size.value(),
               SUPER_VBMETA_TABLE_MAX_SIZE * 2 + VBMETA_IMAGE_MAX_SIZE * 3);
 
     // Check Primary vbmeta table is equal to Backup one
     VBMetaTable table;
-    EXPECT_TRUE(android::fs_mgr::ReadPrimaryVBMetaTable(fd, &table));
+    EXPECT_RESULT_OK(android::fs_mgr::ReadPrimaryVBMetaTable(fd, &table));
     VBMetaTable table_backup;
-    EXPECT_TRUE(android::fs_mgr::ReadBackupVBMetaTable(fd, &table_backup));
+    EXPECT_RESULT_OK(android::fs_mgr::ReadBackupVBMetaTable(fd, &table_backup));
     EXPECT_EQ(android::fs_mgr::SerializeVBMetaTable(table),
               android::fs_mgr::SerializeVBMetaTable(table_backup));
 
@@ -167,25 +167,25 @@
     EXPECT_EQ(table.descriptors[0].vbmeta_name_length, 14);
     EXPECT_EQ(table.descriptors[0].vbmeta_name, "vbmeta_product");
     Result<std::string> vbmeta_product_content = ReadVBMetaImage(fd, 0);
-    EXPECT_TRUE(vbmeta_product_content);
+    EXPECT_RESULT_OK(vbmeta_product_content);
     EXPECT_EQ(ReadVBMetaImageFromFile(vbmeta_product_path), vbmeta_product_content.value());
 
     EXPECT_EQ(table.descriptors[1].vbmeta_index, 1);
     EXPECT_EQ(table.descriptors[1].vbmeta_name_length, 13);
     EXPECT_EQ(table.descriptors[1].vbmeta_name, "vbmeta_system");
     Result<std::string> vbmeta_system_content = ReadVBMetaImage(fd, 1);
-    EXPECT_TRUE(vbmeta_system_content);
+    EXPECT_RESULT_OK(vbmeta_system_content);
     EXPECT_EQ(ReadVBMetaImageFromFile(vbmeta_system_path), vbmeta_system_content.value());
 
     EXPECT_EQ(table.descriptors[2].vbmeta_index, 2);
     EXPECT_EQ(table.descriptors[2].vbmeta_name_length, 13);
     EXPECT_EQ(table.descriptors[2].vbmeta_name, "vbmeta_vendor");
     Result<std::string> vbmeta_vendor_content = ReadVBMetaImage(fd, 2);
-    EXPECT_TRUE(vbmeta_vendor_content);
+    EXPECT_RESULT_OK(vbmeta_vendor_content);
     EXPECT_EQ(ReadVBMetaImageFromFile(vbmeta_vendor_path), vbmeta_vendor_content.value());
 }
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
     return RUN_ALL_TESTS();
-}
\ No newline at end of file
+}
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index c66f307..e364436 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -474,20 +474,9 @@
       if [ 0 != ${counter} ]; then
         adb_wait
       fi
-      if [ -n "`get_property sys.boot.reason`" ]
-      then
-        vals=`get_property |
-              sed -n 's/[[]sys[.]\(boot_completed\|logbootcomplete\)[]]: [[]\([01]\)[]]$/\1=\2/p'`
-        if [ "${vals}" = "`echo boot_completed=1 ; echo logbootcomplete=1`" ]
-        then
-          sleep 1
-          break
-        fi
-        if [ "${vals}" = "`echo logbootcomplete=1 ; echo boot_completed=1`" ]
-        then
-          sleep 1
-          break
-        fi
+      if [ "1" = "`get_property sys.boot_completed`" ]; then
+        sleep 1
+        break
       fi
     fi
     counter=`expr ${counter} + 1`
@@ -858,7 +847,7 @@
 USB_SERIAL=
 [ -z "${ANDROID_SERIAL}" ] || USB_SERIAL=`find /sys/devices -name serial |
                                           grep usb |
-                                          xargs grep -l ${ANDROID_SERIAL}`
+                                          xargs -r grep -l ${ANDROID_SERIAL}`
 USB_ADDRESS=
 if [ -n "${USB_SERIAL}" ]; then
   USB_ADDRESS=${USB_SERIAL%/serial}
diff --git a/healthd/charger.cpp b/healthd/charger.cpp
index 58ed416..d03978d 100644
--- a/healthd/charger.cpp
+++ b/healthd/charger.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <android-base/logging.h>
+
 #include "charger.sysprop.h"
 #include "healthd_mode_charger.h"
 #include "healthd_mode_charger_nops.h"
@@ -23,6 +25,7 @@
 #endif
 
 int main(int argc, char** argv) {
+    android::base::InitLogging(argv, &android::base::KernelLogger);
     if (CHARGER_FORCE_NO_UI || android::sysprop::ChargerProperties::no_ui().value_or(false)) {
         return healthd_charger_nops(argc, argv);
     } else {
diff --git a/healthd/charger_utils.cpp b/healthd/charger_utils.cpp
index 0cf9df5..8bbfb4e 100644
--- a/healthd/charger_utils.cpp
+++ b/healthd/charger_utils.cpp
@@ -17,50 +17,28 @@
 #include "charger_utils.h"
 
 #include <android-base/logging.h>
-#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <android/hardware/health/2.1/IHealth.h>
 #include <health/utils.h>
 #include <health2impl/Health.h>
-#include <hidl/ServiceManagement.h>
-
-using android::hardware::getPassthroughServiceManager;
-using android::hidl::base::V1_0::IBase;
-using android::hidl::manager::V1_0::IServiceManager;
 
 namespace android {
 namespace hardware {
 namespace health {
-sp<V2_1::IHealth> GetPassthroughHealthImpl() {
-    // Not using getService() because there is no hwservicemanager in charger mode.
-    sp<IServiceManager> pm = getPassthroughServiceManager();
-    if (pm == nullptr) {
-        LOG(WARNING) << "Cannot get passthrough service manager.";
-        return nullptr;
-    }
-    sp<IBase> base = pm->get(V2_0::IHealth::descriptor, "default");
-    if (base == nullptr) {
-        LOG(WARNING) << "Cannot find passthrough implementation of health 2.0 HAL for instance "
-                        "'default' on the device.";
-        return nullptr;
-    }
-    sp<V2_1::IHealth> service = V2_1::IHealth::castFrom(base);
-    if (service == nullptr) {
-        LOG(WARNING)
-                << "Cannot cast passthrough implementation of health 2.0 HAL to 2.1 for instance "
-                   "'default' on the device.";
-        return nullptr;
-    }
-    return service;
-}
 
-sp<V2_1::IHealth> GetPassthroughHealth() {
-    auto impl = GetPassthroughHealthImpl();
-    if (impl == nullptr) {
+sp<V2_1::IHealth> GetHealthServiceOrDefault() {
+    // No need to use get_health_service from libhealthhalutils that
+    // checks for "backup" instance provided by healthd, since
+    // V2_1::implementation::Health does the same thing.
+    sp<V2_1::IHealth> service = V2_1::IHealth::getService();
+    if (service != nullptr) {
+        LOG(INFO) << "Charger uses health HAL service.";
+    } else {
         LOG(WARNING) << "Charger uses system defaults.";
         auto config = std::make_unique<healthd_config>();
         InitHealthdConfig(config.get());
-        impl = new V2_1::implementation::Health(std::move(config));
+        service = new V2_1::implementation::Health(std::move(config));
     }
-    return impl;
+    return service;
 }
 
 }  // namespace health
diff --git a/healthd/charger_utils.h b/healthd/charger_utils.h
index f96e827..39d8aab 100644
--- a/healthd/charger_utils.h
+++ b/healthd/charger_utils.h
@@ -21,7 +21,9 @@
 namespace android {
 namespace hardware {
 namespace health {
-sp<V2_1::IHealth> GetPassthroughHealth();
+// Return health HAL service. If it is not supported on the device (with
+// VINTF checks), return a default passthrough implementation.
+sp<V2_1::IHealth> GetHealthServiceOrDefault();
 }  // namespace health
 }  // namespace hardware
 }  // namespace android
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 7d844c9..386ba1a 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -60,7 +60,7 @@
 
 using namespace android;
 using android::hardware::Return;
-using android::hardware::health::GetPassthroughHealth;
+using android::hardware::health::GetHealthServiceOrDefault;
 using android::hardware::health::HealthLoop;
 using android::hardware::health::V1_0::BatteryStatus;
 using android::hardware::health::V2_0::Result;
@@ -742,6 +742,6 @@
         }
     }
 
-    Charger charger(GetPassthroughHealth());
+    Charger charger(GetHealthServiceOrDefault());
     return charger.StartLoop();
 }
diff --git a/healthd/healthd_mode_charger_nops.cpp b/healthd/healthd_mode_charger_nops.cpp
index 13e7348..9fe381e 100644
--- a/healthd/healthd_mode_charger_nops.cpp
+++ b/healthd/healthd_mode_charger_nops.cpp
@@ -20,10 +20,10 @@
 
 #include "charger_utils.h"
 
-using android::hardware::health::GetPassthroughHealth;
+using android::hardware::health::GetHealthServiceOrDefault;
 using android::hardware::health::V2_1::implementation::HalHealthLoop;
 
 int healthd_charger_nops(int /* argc */, char** /* argv */) {
-    HalHealthLoop charger("charger", GetPassthroughHealth());
+    HalHealthLoop charger("charger", GetHealthServiceOrDefault());
     return charger.StartLoop();
 }
diff --git a/init/Android.bp b/init/Android.bp
index 42d0b33..f28934e 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -14,6 +14,61 @@
 // limitations under the License.
 //
 
+init_common_sources = [
+    "action.cpp",
+    "action_manager.cpp",
+    "action_parser.cpp",
+    "capabilities.cpp",
+    "epoll.cpp",
+    "import_parser.cpp",
+    "interface_utils.cpp",
+    "keychords.cpp",
+    "parser.cpp",
+    "property_type.cpp",
+    "rlimit_parser.cpp",
+    "service.cpp",
+    "service_list.cpp",
+    "service_parser.cpp",
+    "service_utils.cpp",
+    "subcontext.cpp",
+    "subcontext.proto",
+    "tokenizer.cpp",
+    "util.cpp",
+]
+init_device_sources = [
+    "bootchart.cpp",
+    "builtins.cpp",
+    "devices.cpp",
+    "firmware_handler.cpp",
+    "first_stage_init.cpp",
+    "first_stage_mount.cpp",
+    "fscrypt_init_extensions.cpp",
+    "init.cpp",
+    "lmkd_service.cpp",
+    "modalias_handler.cpp",
+    "mount_handler.cpp",
+    "mount_namespace.cpp",
+    "persistent_properties.cpp",
+    "persistent_properties.proto",
+    "property_service.cpp",
+    "property_service.proto",
+    "reboot.cpp",
+    "reboot_utils.cpp",
+    "security.cpp",
+    "selabel.cpp",
+    "selinux.cpp",
+    "sigchld_handler.cpp",
+    "switch_root.cpp",
+    "uevent_listener.cpp",
+    "ueventd.cpp",
+    "ueventd_parser.cpp",
+]
+init_host_sources = [
+    "check_builtins.cpp",
+    "host_import_parser.cpp",
+    "host_init_verifier.cpp",
+]
+
 cc_defaults {
     name: "init_defaults",
     cpp_std: "experimental",
@@ -103,53 +158,7 @@
         "init_defaults",
         "selinux_policy_version",
     ],
-    srcs: [
-        "action.cpp",
-        "action_manager.cpp",
-        "action_parser.cpp",
-        "bootchart.cpp",
-        "builtins.cpp",
-        "capabilities.cpp",
-        "devices.cpp",
-        "epoll.cpp",
-        "firmware_handler.cpp",
-        "first_stage_init.cpp",
-        "first_stage_mount.cpp",
-        "fscrypt_init_extensions.cpp",
-        "import_parser.cpp",
-        "init.cpp",
-        "interface_utils.cpp",
-        "keychords.cpp",
-        "lmkd_service.cpp",
-        "modalias_handler.cpp",
-        "mount_handler.cpp",
-        "mount_namespace.cpp",
-        "parser.cpp",
-        "persistent_properties.cpp",
-        "persistent_properties.proto",
-        "property_service.cpp",
-        "property_service.proto",
-        "property_type.cpp",
-        "reboot.cpp",
-        "reboot_utils.cpp",
-        "security.cpp",
-        "selabel.cpp",
-        "selinux.cpp",
-        "service.cpp",
-        "service_list.cpp",
-        "service_parser.cpp",
-        "service_utils.cpp",
-        "sigchld_handler.cpp",
-        "subcontext.cpp",
-        "subcontext.proto",
-        "switch_root.cpp",
-        "rlimit_parser.cpp",
-        "tokenizer.cpp",
-        "uevent_listener.cpp",
-        "ueventd.cpp",
-        "ueventd_parser.cpp",
-        "util.cpp",
-    ],
+    srcs: init_common_sources + init_device_sources,
     whole_static_libs: [
         "libcap",
         "com.android.sysprop.apex",
@@ -297,30 +306,7 @@
         "libprocessgroup",
         "libprotobuf-cpp-lite",
     ],
-    srcs: [
-        "action.cpp",
-        "action_manager.cpp",
-        "action_parser.cpp",
-        "capabilities.cpp",
-        "check_builtins.cpp",
-        "epoll.cpp",
-        "keychords.cpp",
-        "import_parser.cpp",
-        "interface_utils.cpp",
-        "host_import_parser.cpp",
-        "host_init_verifier.cpp",
-        "parser.cpp",
-        "property_type.cpp",
-        "rlimit_parser.cpp",
-        "tokenizer.cpp",
-        "service.cpp",
-        "service_list.cpp",
-        "service_parser.cpp",
-        "service_utils.cpp",
-        "subcontext.cpp",
-        "subcontext.proto",
-        "util.cpp",
-    ],
+    srcs: init_common_sources + init_host_sources,
     proto: {
         type: "lite",
     },
diff --git a/init/action.cpp b/init/action.cpp
index f05fa7c..1e998ae 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -36,7 +36,7 @@
     builtin_arguments.args[0] = args[0];
     for (std::size_t i = 1; i < args.size(); ++i) {
         auto expanded_arg = ExpandProps(args[i]);
-        if (!expanded_arg) {
+        if (!expanded_arg.ok()) {
             return expanded_arg.error();
         }
         builtin_arguments.args[i] = std::move(*expanded_arg);
@@ -59,7 +59,7 @@
         }
 
         auto expanded_args = subcontext->ExpandArgs(args_);
-        if (!expanded_args) {
+        if (!expanded_args.ok()) {
             return expanded_args.error();
         }
         return RunBuiltinFunction(func_, *expanded_args, subcontext->context());
@@ -75,7 +75,7 @@
     builtin_arguments.args[0] = args_[0];
     for (size_t i = 1; i < args_.size(); ++i) {
         auto expanded_arg = ExpandProps(args_[i]);
-        if (!expanded_arg) {
+        if (!expanded_arg.ok()) {
             if (expanded_arg.error().message().find("doesn't exist while expanding") !=
                 std::string::npos) {
                 // If we failed because we won't have a property, use an empty string, which is
@@ -114,7 +114,7 @@
     }
 
     auto map_result = function_map_->Find(args);
-    if (!map_result) {
+    if (!map_result.ok()) {
         return Error() << map_result.error();
     }
 
@@ -134,7 +134,7 @@
 size_t Action::CheckAllCommands() const {
     size_t failures = 0;
     for (const auto& command : commands_) {
-        if (auto result = command.CheckCommand(); !result) {
+        if (auto result = command.CheckCommand(); !result.ok()) {
             LOG(ERROR) << "Command '" << command.BuildCommandString() << "' (" << filename_ << ":"
                        << command.line() << ") failed: " << result.error();
             ++failures;
@@ -169,7 +169,7 @@
 
         LOG(INFO) << "Command '" << cmd_str << "' action=" << trigger_name << " (" << filename_
                   << ":" << command.line() << ") took " << duration.count() << "ms and "
-                  << (result ? "succeeded" : "failed: " + result.error().message());
+                  << (result.ok() ? "succeeded" : "failed: " + result.error().message());
     }
 }
 
diff --git a/init/action_parser.cpp b/init/action_parser.cpp
index a8e1e09..f316871 100644
--- a/init/action_parser.cpp
+++ b/init/action_parser.cpp
@@ -110,14 +110,14 @@
 
         if (!args[i].compare(0, prop_str.length(), prop_str)) {
             if (auto result = ParsePropertyTrigger(args[i], subcontext, property_triggers);
-                !result) {
+                !result.ok()) {
                 return result;
             }
         } else {
             if (!event_trigger->empty()) {
                 return Error() << "multiple event triggers are not allowed";
             }
-            if (auto result = ValidateEventTrigger(args[i]); !result) {
+            if (auto result = ValidateEventTrigger(args[i]); !result.ok()) {
                 return result;
             }
 
@@ -145,8 +145,9 @@
     std::string event_trigger;
     std::map<std::string, std::string> property_triggers;
 
-    if (auto result = ParseTriggers(triggers, action_subcontext, &event_trigger, &property_triggers);
-        !result) {
+    if (auto result =
+                ParseTriggers(triggers, action_subcontext, &event_trigger, &property_triggers);
+        !result.ok()) {
         return Error() << "ParseTriggers() failed: " << result.error();
     }
 
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 742e089..200bfff 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -164,7 +164,7 @@
     // They must  be started individually.
     for (const auto& service : ServiceList::GetInstance()) {
         if (service->classnames().count(args[1])) {
-            if (auto result = service->StartIfNotDisabled(); !result) {
+            if (auto result = service->StartIfNotDisabled(); !result.ok()) {
                 LOG(ERROR) << "Could not start service '" << service->name()
                            << "' as part of class '" << args[1] << "': " << result.error();
             }
@@ -186,7 +186,7 @@
     }
     for (const auto& service : ServiceList::GetInstance()) {
         if (service->classnames().count(args[1])) {
-            if (auto result = service->StartIfPostData(); !result) {
+            if (auto result = service->StartIfPostData(); !result.ok()) {
                 LOG(ERROR) << "Could not start service '" << service->name()
                            << "' as part of class '" << args[1] << "': " << result.error();
             }
@@ -227,7 +227,7 @@
 }
 
 static Result<void> do_domainname(const BuiltinArguments& args) {
-    if (auto result = WriteFile("/proc/sys/kernel/domainname", args[1]); !result) {
+    if (auto result = WriteFile("/proc/sys/kernel/domainname", args[1]); !result.ok()) {
         return Error() << "Unable to write to /proc/sys/kernel/domainname: " << result.error();
     }
     return {};
@@ -237,7 +237,7 @@
     Service* svc = ServiceList::GetInstance().FindService(args[1]);
     if (!svc) return Error() << "Could not find service";
 
-    if (auto result = svc->Enable(); !result) {
+    if (auto result = svc->Enable(); !result.ok()) {
         return Error() << "Could not enable service: " << result.error();
     }
 
@@ -246,10 +246,10 @@
 
 static Result<void> do_exec(const BuiltinArguments& args) {
     auto service = Service::MakeTemporaryOneshotService(args.args);
-    if (!service) {
+    if (!service.ok()) {
         return Error() << "Could not create exec service: " << service.error();
     }
-    if (auto result = (*service)->ExecStart(); !result) {
+    if (auto result = (*service)->ExecStart(); !result.ok()) {
         return Error() << "Could not start exec service: " << result.error();
     }
 
@@ -259,10 +259,10 @@
 
 static Result<void> do_exec_background(const BuiltinArguments& args) {
     auto service = Service::MakeTemporaryOneshotService(args.args);
-    if (!service) {
+    if (!service.ok()) {
         return Error() << "Could not create exec background service: " << service.error();
     }
-    if (auto result = (*service)->Start(); !result) {
+    if (auto result = (*service)->Start(); !result.ok()) {
         return Error() << "Could not start exec background service: " << result.error();
     }
 
@@ -276,7 +276,7 @@
         return Error() << "Service not found";
     }
 
-    if (auto result = service->ExecStart(); !result) {
+    if (auto result = service->ExecStart(); !result.ok()) {
         return Error() << "Could not start exec service: " << result.error();
     }
 
@@ -291,7 +291,7 @@
 }
 
 static Result<void> do_hostname(const BuiltinArguments& args) {
-    if (auto result = WriteFile("/proc/sys/kernel/hostname", args[1]); !result) {
+    if (auto result = WriteFile("/proc/sys/kernel/hostname", args[1]); !result.ok()) {
         return Error() << "Unable to write to /proc/sys/kernel/hostname: " << result.error();
     }
     return {};
@@ -349,7 +349,7 @@
 static Result<void> do_interface_start(const BuiltinArguments& args) {
     Service* svc = ServiceList::GetInstance().FindInterface(args[1]);
     if (!svc) return Error() << "interface " << args[1] << " not found";
-    if (auto result = svc->Start(); !result) {
+    if (auto result = svc->Start(); !result.ok()) {
         return Error() << "Could not start interface: " << result.error();
     }
     return {};
@@ -413,7 +413,7 @@
 // mkdir <path> [mode] [owner] [group] [<option> ...]
 static Result<void> do_mkdir(const BuiltinArguments& args) {
     auto options = ParseMkdir(args.args);
-    if (!options) return options.error();
+    if (!options.ok()) return options.error();
     return make_dir_with_options(*options);
 }
 
@@ -681,7 +681,7 @@
          * and return processed return code*/
         initial_mount_fstab_return_code = mount_fstab_return_code;
         auto queue_fs_result = queue_fs_event(mount_fstab_return_code, false);
-        if (!queue_fs_result) {
+        if (!queue_fs_result.ok()) {
             return Error() << "queue_fs_event() failed: " << queue_fs_result.error();
         }
     }
@@ -731,7 +731,7 @@
 
 static Result<void> do_setrlimit(const BuiltinArguments& args) {
     auto rlimit = ParseRlimit(args.args);
-    if (!rlimit) return rlimit.error();
+    if (!rlimit.ok()) return rlimit.error();
 
     if (setrlimit(rlimit->first, &rlimit->second) == -1) {
         return ErrnoError() << "setrlimit failed";
@@ -742,7 +742,7 @@
 static Result<void> do_start(const BuiltinArguments& args) {
     Service* svc = ServiceList::GetInstance().FindService(args[1]);
     if (!svc) return Error() << "service " << args[1] << " not found";
-    if (auto result = svc->Start(); !result) {
+    if (auto result = svc->Start(); !result.ok()) {
         return ErrorIgnoreEnoent() << "Could not start service: " << result.error();
     }
     return {};
@@ -846,7 +846,7 @@
 }
 
 static Result<void> do_write(const BuiltinArguments& args) {
-    if (auto result = WriteFile(args[1], args[2]); !result) {
+    if (auto result = WriteFile(args[1], args[2]); !result.ok()) {
         return ErrorIgnoreEnoent()
                << "Unable to write to file '" << args[1] << "': " << result.error();
     }
@@ -904,7 +904,7 @@
         }
         android::base::Timer t;
         if (S_ISREG(sb.st_mode)) {
-            if (auto result = readahead_file(args[1], readfully); !result) {
+            if (auto result = readahead_file(args[1], readfully); !result.ok()) {
                 LOG(WARNING) << "Unable to readahead '" << args[1] << "': " << result.error();
                 _exit(EXIT_FAILURE);
             }
@@ -921,7 +921,7 @@
                  ftsent = fts_read(fts.get())) {
                 if (ftsent->fts_info & FTS_F) {
                     const std::string filename = ftsent->fts_accpath;
-                    if (auto result = readahead_file(filename, readfully); !result) {
+                    if (auto result = readahead_file(filename, readfully); !result.ok()) {
                         LOG(WARNING)
                             << "Unable to readahead '" << filename << "': " << result.error();
                     }
@@ -938,10 +938,10 @@
 
 static Result<void> do_copy(const BuiltinArguments& args) {
     auto file_contents = ReadFile(args[1]);
-    if (!file_contents) {
+    if (!file_contents.ok()) {
         return Error() << "Could not read input file '" << args[1] << "': " << file_contents.error();
     }
-    if (auto result = WriteFile(args[2], *file_contents); !result) {
+    if (auto result = WriteFile(args[2], *file_contents); !result.ok()) {
         return Error() << "Could not write to output file '" << args[2] << "': " << result.error();
     }
 
@@ -950,7 +950,7 @@
 
 static Result<void> do_chown(const BuiltinArguments& args) {
     auto uid = DecodeUid(args[1]);
-    if (!uid) {
+    if (!uid.ok()) {
         return Error() << "Unable to decode UID for '" << args[1] << "': " << uid.error();
     }
 
@@ -960,7 +960,7 @@
 
     if (args.size() == 4) {
         gid = DecodeUid(args[2]);
-        if (!gid) {
+        if (!gid.ok()) {
             return Error() << "Unable to decode GID for '" << args[2] << "': " << gid.error();
         }
     }
@@ -995,7 +995,7 @@
 
 static Result<void> do_restorecon(const BuiltinArguments& args) {
     auto restorecon_info = ParseRestorecon(args.args);
-    if (!restorecon_info) {
+    if (!restorecon_info.ok()) {
         return restorecon_info.error();
     }
 
@@ -1103,7 +1103,7 @@
 static Result<void> ExecWithFunctionOnFailure(const std::vector<std::string>& args,
                                               std::function<void(const std::string&)> function) {
     auto service = Service::MakeTemporaryOneshotService(args);
-    if (!service) {
+    if (!service.ok()) {
         function("MakeTemporaryOneshotService failed: " + service.error().message());
     }
     (*service)->AddReapCallback([function](const siginfo_t& siginfo) {
@@ -1111,7 +1111,7 @@
             function(StringPrintf("Exec service failed, status %d", siginfo.si_status));
         }
     });
-    if (auto result = (*service)->ExecStart(); !result) {
+    if (auto result = (*service)->ExecStart(); !result.ok()) {
         function("ExecStart failed: " + result.error().message());
     }
     ServiceList::GetInstance().AddService(std::move(*service));
@@ -1133,7 +1133,7 @@
                 LOG(ERROR) << message << ": Rebooting into recovery, reason: " << reboot_reason;
                 if (auto result = reboot_into_recovery(
                             {"--prompt_and_wipe_data", "--reason="s + reboot_reason});
-                    !result) {
+                    !result.ok()) {
                     LOG(FATAL) << "Could not reboot into recovery: " << result.error();
                 }
             } else {
@@ -1162,7 +1162,7 @@
     if (auto rc = fs_mgr_remount_userdata_into_checkpointing(&fstab); rc < 0) {
         trigger_shutdown("reboot,mount_userdata_failed");
     }
-    if (auto result = queue_fs_event(initial_mount_fstab_return_code, true); !result) {
+    if (auto result = queue_fs_event(initial_mount_fstab_return_code, true); !result.ok()) {
         return Error() << "queue_fs_event() failed: " << result.error();
     }
     return {};
@@ -1285,16 +1285,16 @@
 
 static Result<void> do_perform_apex_config(const BuiltinArguments& args) {
     auto create_dirs = create_apex_data_dirs();
-    if (!create_dirs) {
+    if (!create_dirs.ok()) {
         return create_dirs.error();
     }
     auto parse_configs = parse_apex_configs();
-    if (!parse_configs) {
+    if (!parse_configs.ok()) {
         return parse_configs.error();
     }
 
     auto update_linker_config = do_update_linker_config(args);
-    if (!update_linker_config) {
+    if (!update_linker_config.ok()) {
         return update_linker_config.error();
     }
 
@@ -1309,17 +1309,6 @@
     }
 }
 
-static Result<void> do_finish_userspace_reboot(const BuiltinArguments&) {
-    LOG(INFO) << "Userspace reboot successfully finished";
-    boot_clock::time_point now = boot_clock::now();
-    SetProperty("sys.init.userspace_reboot.last_finished",
-                std::to_string(now.time_since_epoch().count()));
-    if (!android::sysprop::InitProperties::userspace_reboot_in_progress(false)) {
-        return Error() << "Failed to set sys.init.userspace_reboot.in_progress property";
-    }
-    return {};
-}
-
 // Builtin-function-map start
 const BuiltinFunctionMap& GetBuiltinFunctionMap() {
     constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
@@ -1341,7 +1330,6 @@
         {"exec_background",         {1,     kMax, {false,  do_exec_background}}},
         {"exec_start",              {1,     1,    {false,  do_exec_start}}},
         {"export",                  {2,     2,    {false,  do_export}}},
-        {"finish_userspace_reboot", {0,     0,    {false,  do_finish_userspace_reboot}}},
         {"hostname",                {1,     1,    {true,   do_hostname}}},
         {"ifup",                    {1,     1,    {true,   do_ifup}}},
         {"init_user0",              {0,     0,    {false,  do_init_user0}}},
diff --git a/init/check_builtins.cpp b/init/check_builtins.cpp
index bef6966..d62ecb0 100644
--- a/init/check_builtins.cpp
+++ b/init/check_builtins.cpp
@@ -52,7 +52,7 @@
 Result<void> check_chown(const BuiltinArguments& args) {
     if (!args[1].empty()) {
         auto uid = DecodeUid(args[1]);
-        if (!uid) {
+        if (!uid.ok()) {
             return Error() << "Unable to decode UID for '" << args[1] << "': " << uid.error();
         }
     }
@@ -60,7 +60,7 @@
     // GID is optional and pushes the index of path out by one if specified.
     if (args.size() == 4 && !args[2].empty()) {
         auto gid = DecodeUid(args[2]);
-        if (!gid) {
+        if (!gid.ok()) {
             return Error() << "Unable to decode GID for '" << args[2] << "': " << gid.error();
         }
     }
@@ -72,7 +72,7 @@
     ReturnIfAnyArgsEmpty();
 
     auto result = Service::MakeTemporaryOneshotService(args.args);
-    if (!result) {
+    if (!result.ok()) {
         return result.error();
     }
 
@@ -93,7 +93,7 @@
 }
 
 Result<void> check_interface_restart(const BuiltinArguments& args) {
-    if (auto result = IsKnownInterface(args[1]); !result) {
+    if (auto result = IsKnownInterface(args[1]); !result.ok()) {
         return result.error();
     }
     return {};
@@ -124,7 +124,7 @@
 
 Result<void> check_mkdir(const BuiltinArguments& args) {
     auto options = ParseMkdir(args.args);
-    if (!options) {
+    if (!options.ok()) {
         return options.error();
     }
     return {};
@@ -134,7 +134,7 @@
     ReturnIfAnyArgsEmpty();
 
     auto restorecon_info = ParseRestorecon(args.args);
-    if (!restorecon_info) {
+    if (!restorecon_info.ok()) {
         return restorecon_info.error();
     }
 
@@ -157,7 +157,7 @@
     }
 
     if (!value.empty()) {
-        if (auto result = IsLegalPropertyValue(name, value); !result) {
+        if (auto result = IsLegalPropertyValue(name, value); !result.ok()) {
             return result.error();
         }
     }
@@ -189,7 +189,7 @@
     ReturnIfAnyArgsEmpty();
 
     auto rlimit = ParseRlimit(args.args);
-    if (!rlimit) return rlimit.error();
+    if (!rlimit.ok()) return rlimit.error();
     return {};
 }
 
diff --git a/init/firmware_handler.cpp b/init/firmware_handler.cpp
index 1dce2d5..dff7b69 100644
--- a/init/firmware_handler.cpp
+++ b/init/firmware_handler.cpp
@@ -165,7 +165,7 @@
 
             auto result =
                     RunExternalHandler(external_handler.handler_path, external_handler.uid, uevent);
-            if (!result) {
+            if (!result.ok()) {
                 LOG(ERROR) << "Using default firmware; External firmware handler failed: "
                            << result.error();
                 return uevent.firmware;
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index d8c4843..21663e6 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -21,6 +21,7 @@
 #include <unistd.h>
 
 #include <chrono>
+#include <map>
 #include <memory>
 #include <set>
 #include <string>
@@ -29,6 +30,7 @@
 #include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <fs_avb/fs_avb.h>
 #include <fs_mgr.h>
@@ -45,7 +47,9 @@
 #include "uevent_listener.h"
 #include "util.h"
 
+using android::base::ReadFileToString;
 using android::base::Split;
+using android::base::StringPrintf;
 using android::base::Timer;
 using android::fiemap::IImageManager;
 using android::fs_mgr::AvbHandle;
@@ -95,6 +99,7 @@
     void GetDmLinearMetadataDevice(std::set<std::string>* devices);
     bool InitDmLinearBackingDevices(const android::fs_mgr::LpMetadata& metadata);
     void UseDsuIfPresent();
+    void PreloadAvbKeys();
 
     ListenerAction UeventCallback(const Uevent& uevent, std::set<std::string>* required_devices);
 
@@ -110,6 +115,9 @@
     std::string super_partition_name_;
     std::unique_ptr<DeviceHandler> device_handler_;
     UeventListener uevent_listener_;
+    // Reads all AVB keys before chroot into /system, as they might be used
+    // later when mounting other partitions, e.g., /vendor and /product.
+    std::map<std::string, std::vector<std::string>> preload_avb_key_blobs_;
 };
 
 class FirstStageMountVBootV1 : public FirstStageMount {
@@ -508,11 +516,57 @@
     return mounted;
 }
 
+void FirstStageMount::PreloadAvbKeys() {
+    for (const auto& entry : fstab_) {
+        // No need to cache the key content if it's empty, or is already cached.
+        if (entry.avb_keys.empty() || preload_avb_key_blobs_.count(entry.avb_keys)) {
+            continue;
+        }
+
+        // Determines all key paths first.
+        std::vector<std::string> key_paths;
+        if (is_dir(entry.avb_keys.c_str())) {  // fstab_keys might be a dir, e.g., /avb.
+            const char* avb_key_dir = entry.avb_keys.c_str();
+            std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(avb_key_dir), closedir);
+            if (!dir) {
+                LOG(ERROR) << "Failed to opendir: " << dir;
+                continue;
+            }
+            // Gets all key pathes under the dir.
+            struct dirent* de;
+            while ((de = readdir(dir.get()))) {
+                if (de->d_type != DT_REG) continue;
+                std::string full_path = StringPrintf("%s/%s", avb_key_dir, de->d_name);
+                key_paths.emplace_back(std::move(full_path));
+            }
+            std::sort(key_paths.begin(), key_paths.end());
+        } else {
+            // avb_keys are key paths separated by ":", if it's not a dir.
+            key_paths = Split(entry.avb_keys, ":");
+        }
+
+        // Reads the key content then cache it.
+        std::vector<std::string> key_blobs;
+        for (const auto& path : key_paths) {
+            std::string key_value;
+            if (!ReadFileToString(path, &key_value)) {
+                continue;
+            }
+            key_blobs.emplace_back(std::move(key_value));
+        }
+
+        // Maps entry.avb_keys to actual key blobs.
+        preload_avb_key_blobs_[entry.avb_keys] = std::move(key_blobs);
+    }
+}
+
 // If system is in the fstab then we're not a system-as-root device, and in
 // this case, we mount system first then pivot to it.  From that point on,
 // we are effectively identical to a system-as-root device.
 bool FirstStageMount::TrySwitchSystemAsRoot() {
     UseDsuIfPresent();
+    // Preloading all AVB keys from the ramdisk before switching root to /system.
+    PreloadAvbKeys();
 
     auto system_partition = std::find_if(fstab_.begin(), fstab_.end(), [](const auto& entry) {
         return entry.mount_point == "/system";
@@ -776,7 +830,8 @@
                        << fstab_entry->mount_point;
             return true;  // Returns true to mount the partition directly.
         } else {
-            auto avb_standalone_handle = AvbHandle::LoadAndVerifyVbmeta(*fstab_entry);
+            auto avb_standalone_handle = AvbHandle::LoadAndVerifyVbmeta(
+                    *fstab_entry, preload_avb_key_blobs_[fstab_entry->avb_keys]);
             if (!avb_standalone_handle) {
                 LOG(ERROR) << "Failed to load offline vbmeta for " << fstab_entry->mount_point;
                 // Fallbacks to built-in hashtree if fs_mgr_flags.avb is set.
diff --git a/init/host_init_verifier.cpp b/init/host_init_verifier.cpp
index 22de846..0bd4df4 100644
--- a/init/host_init_verifier.cpp
+++ b/init/host_init_verifier.cpp
@@ -248,7 +248,7 @@
     }
 
     auto interface_inheritance_hierarchy_map = ReadInterfaceInheritanceHierarchy();
-    if (!interface_inheritance_hierarchy_map) {
+    if (!interface_inheritance_hierarchy_map.ok()) {
         LOG(ERROR) << interface_inheritance_hierarchy_map.error();
         return EXIT_FAILURE;
     }
diff --git a/init/import_parser.cpp b/init/import_parser.cpp
index 1a43508..e4b25ca 100644
--- a/init/import_parser.cpp
+++ b/init/import_parser.cpp
@@ -30,7 +30,7 @@
     }
 
     auto conf_file = ExpandProps(args[1]);
-    if (!conf_file) {
+    if (!conf_file.ok()) {
         return Error() << "Could not expand import: " << conf_file.error();
     }
 
diff --git a/init/init.cpp b/init/init.cpp
index a25bf6c..5bf1b36 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -237,7 +237,7 @@
 
         auto restart_time = s->time_started() + s->restart_period();
         if (boot_clock::now() > restart_time) {
-            if (auto result = s->Start(); !result) {
+            if (auto result = s->Start(); !result.ok()) {
                 LOG(ERROR) << "Could not restart process '" << s->name() << "': " << result.error();
             }
         } else {
@@ -333,7 +333,7 @@
         return false;
     }
 
-    if (auto result = function.action(svc); !result) {
+    if (auto result = function.action(svc); !result.ok()) {
         LOG(ERROR) << "Control message: Could not ctl." << msg << " for '" << name
                    << "' from pid: " << pid << " (" << process_cmdline << "): " << result.error();
         return false;
@@ -478,7 +478,7 @@
         PLOG(FATAL) << "failed to create signalfd";
     }
 
-    if (auto result = epoll->RegisterHandler(signal_fd, HandleSignalFd); !result) {
+    if (auto result = epoll->RegisterHandler(signal_fd, HandleSignalFd); !result.ok()) {
         LOG(FATAL) << result.error();
     }
 }
@@ -499,7 +499,7 @@
             found = true;
             LOG(INFO) << "Starting service '" << svc->name() << "' from keychord "
                       << android::base::Join(keycodes, ' ');
-            if (auto result = svc->Start(); !result) {
+            if (auto result = svc->Start(); !result.ok()) {
                 LOG(ERROR) << "Could not start service '" << svc->name() << "' from keychord "
                            << android::base::Join(keycodes, ' ') << ": " << result.error();
             }
@@ -558,7 +558,7 @@
 void SendLoadPersistentPropertiesMessage() {
     auto init_message = InitMessage{};
     init_message.set_load_persistent_properties(true);
-    if (auto result = SendMessage(property_fd, init_message); !result) {
+    if (auto result = SendMessage(property_fd, init_message); !result.ok()) {
         LOG(ERROR) << "Failed to send load persistent properties message: " << result.error();
     }
 }
@@ -566,7 +566,7 @@
 void SendStopSendingMessagesMessage() {
     auto init_message = InitMessage{};
     init_message.set_stop_sending_messages(true);
-    if (auto result = SendMessage(property_fd, init_message); !result) {
+    if (auto result = SendMessage(property_fd, init_message); !result.ok()) {
         LOG(ERROR) << "Failed to send 'stop sending messages' message: " << result.error();
     }
 }
@@ -574,14 +574,14 @@
 void SendStartSendingMessagesMessage() {
     auto init_message = InitMessage{};
     init_message.set_start_sending_messages(true);
-    if (auto result = SendMessage(property_fd, init_message); !result) {
+    if (auto result = SendMessage(property_fd, init_message); !result.ok()) {
         LOG(ERROR) << "Failed to send 'start sending messages' message: " << result.error();
     }
 }
 
 static void HandlePropertyFd() {
     auto message = ReadMessage(property_fd);
-    if (!message) {
+    if (!message.ok()) {
         LOG(ERROR) << "Could not read message from property service: " << message.error();
         return;
     }
@@ -636,7 +636,7 @@
     // Set init and its forked children's oom_adj.
     if (auto result =
                 WriteFile("/proc/1/oom_score_adj", StringPrintf("%d", DEFAULT_OOM_SCORE_ADJUST));
-        !result) {
+        !result.ok()) {
         LOG(ERROR) << "Unable to write " << DEFAULT_OOM_SCORE_ADJUST
                    << " to /proc/1/oom_score_adj: " << result.error();
     }
@@ -679,14 +679,14 @@
     SelinuxRestoreContext();
 
     Epoll epoll;
-    if (auto result = epoll.Open(); !result) {
+    if (auto result = epoll.Open(); !result.ok()) {
         PLOG(FATAL) << result.error();
     }
 
     InstallSignalFdHandler(&epoll);
 
     StartPropertyService(&property_fd);
-    if (auto result = epoll.RegisterHandler(property_fd, HandlePropertyFd); !result) {
+    if (auto result = epoll.RegisterHandler(property_fd, HandlePropertyFd); !result.ok()) {
         LOG(FATAL) << "Could not register epoll handler for property fd: " << result.error();
     }
 
@@ -780,24 +780,24 @@
         if (!(waiting_for_prop || Service::is_exec_service_running())) {
             am.ExecuteOneCommand();
         }
-        if (!(waiting_for_prop || Service::is_exec_service_running())) {
-            if (!IsShuttingDown()) {
-                auto next_process_action_time = HandleProcessActions();
+        if (!IsShuttingDown()) {
+            auto next_process_action_time = HandleProcessActions();
 
-                // If there's a process that needs restarting, wake up in time for that.
-                if (next_process_action_time) {
-                    epoll_timeout = std::chrono::ceil<std::chrono::milliseconds>(
-                            *next_process_action_time - boot_clock::now());
-                    if (*epoll_timeout < 0ms) epoll_timeout = 0ms;
-                }
+            // If there's a process that needs restarting, wake up in time for that.
+            if (next_process_action_time) {
+                epoll_timeout = std::chrono::ceil<std::chrono::milliseconds>(
+                        *next_process_action_time - boot_clock::now());
+                if (*epoll_timeout < 0ms) epoll_timeout = 0ms;
             }
+        }
 
+        if (!(waiting_for_prop || Service::is_exec_service_running())) {
             // If there's more work to do, wake up again immediately.
             if (am.HasMoreCommands()) epoll_timeout = 0ms;
         }
 
         auto pending_functions = epoll.Wait(epoll_timeout);
-        if (!pending_functions) {
+        if (!pending_functions.ok()) {
             LOG(ERROR) << pending_functions.error();
         } else if (!pending_functions->empty()) {
             // We always reap children before responding to the other pending functions. This is to
diff --git a/init/init_test.cpp b/init/init_test.cpp
index 9f63e4f..caf3e03 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -204,9 +204,9 @@
                                "execute 3";
     // clang-format on
     // WriteFile() ensures the right mode is set
-    ASSERT_TRUE(WriteFile(std::string(dir.path) + "/a.rc", dir_a_script));
+    ASSERT_RESULT_OK(WriteFile(std::string(dir.path) + "/a.rc", dir_a_script));
 
-    ASSERT_TRUE(WriteFile(std::string(dir.path) + "/b.rc", "on boot\nexecute 5"));
+    ASSERT_RESULT_OK(WriteFile(std::string(dir.path) + "/b.rc", "on boot\nexecute 5"));
 
     // clang-format off
     std::string start_script = "import " + std::string(first_import.path) + "\n"
diff --git a/init/keychords.cpp b/init/keychords.cpp
index 5f2682b..adec383 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -187,7 +187,7 @@
         LambdaCheck();
     }
     if (auto result = epoll_->RegisterHandler(fd, [this, fd]() { this->LambdaHandler(fd); });
-        !result) {
+        !result.ok()) {
         LOG(WARNING) << "Could not register keychord epoll handler: " << result.error();
         return false;
     }
@@ -272,7 +272,7 @@
     if (inotify_fd_ >= 0) {
         if (auto result =
                     epoll_->RegisterHandler(inotify_fd_, [this]() { this->InotifyHandler(); });
-            !result) {
+            !result.ok()) {
             LOG(WARNING) << "Could not register keychord epoll handler: " << result.error();
         }
     }
diff --git a/init/keychords_test.cpp b/init/keychords_test.cpp
index 6e9b337..8a333a2 100644
--- a/init/keychords_test.cpp
+++ b/init/keychords_test.cpp
@@ -204,7 +204,7 @@
 
 TestFrame::TestFrame(const std::vector<const std::vector<int>>& chords, EventHandler* ev)
     : ev_(ev) {
-    if (!epoll_.Open()) return;
+    if (!epoll_.Open().ok()) return;
     for (const auto& keycodes : chords) keychords_.Register(keycodes);
     keychords_.Start(&epoll_, [this](const std::vector<int>& keycodes) {
         this->keycodes_.emplace_back(keycodes);
@@ -213,7 +213,7 @@
 
 void TestFrame::RelaxForMs(std::chrono::milliseconds wait) {
     auto pending_functions = epoll_.Wait(wait);
-    ASSERT_TRUE(pending_functions) << pending_functions.error();
+    ASSERT_RESULT_OK(pending_functions);
     for (const auto& function : *pending_functions) {
         (*function)();
     }
diff --git a/init/mount_handler.cpp b/init/mount_handler.cpp
index 0e4e024..01abba8 100644
--- a/init/mount_handler.cpp
+++ b/init/mount_handler.cpp
@@ -116,7 +116,7 @@
     if (!fp_) PLOG(FATAL) << "Could not open /proc/mounts";
     auto result = epoll->RegisterHandler(
             fileno(fp_.get()), [this]() { this->MountHandlerFunction(); }, EPOLLERR | EPOLLPRI);
-    if (!result) LOG(FATAL) << result.error();
+    if (!result.ok()) LOG(FATAL) << result.error();
 }
 
 MountHandler::~MountHandler() {
diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp
index 1a474fb..0749fe3 100644
--- a/init/mount_namespace.cpp
+++ b/init/mount_namespace.cpp
@@ -141,12 +141,12 @@
         if (entry->d_type == DT_DIR) {
             const std::string apex_path = from_dir + "/" + entry->d_name;
             const auto apex_name = GetApexName(apex_path);
-            if (!apex_name) {
+            if (!apex_name.ok()) {
                 LOG(ERROR) << apex_path << " is not an APEX directory: " << apex_name.error();
                 continue;
             }
             const std::string mount_path = to_dir + "/" + (*apex_name);
-            if (auto result = MountDir(apex_path, mount_path); !result) {
+            if (auto result = MountDir(apex_path, mount_path); !result.ok()) {
                 return result;
             }
         }
@@ -168,7 +168,7 @@
     };
 
     for (const auto& dir : kBuiltinDirsForApexes) {
-        if (auto result = ActivateFlattenedApexesFrom(dir, kApexTop); !result) {
+        if (auto result = ActivateFlattenedApexesFrom(dir, kApexTop); !result.ok()) {
             LOG(ERROR) << result.error();
             return false;
         }
@@ -295,7 +295,7 @@
             return false;
         }
 
-        if (auto result = MountLinkerConfigForDefaultNamespace(); !result) {
+        if (auto result = MountLinkerConfigForDefaultNamespace(); !result.ok()) {
             LOG(ERROR) << result.error();
             return false;
         }
diff --git a/init/parser.cpp b/init/parser.cpp
index 6ab61cb..507ee4a 100644
--- a/init/parser.cpp
+++ b/init/parser.cpp
@@ -61,7 +61,7 @@
         bad_section_found = false;
         if (section_parser == nullptr) return;
 
-        if (auto result = section_parser->EndSection(); !result) {
+        if (auto result = section_parser->EndSection(); !result.ok()) {
             parse_error_count_++;
             LOG(ERROR) << filename << ": " << section_start_line << ": " << result.error();
         }
@@ -92,7 +92,7 @@
                 if (line_callback != line_callbacks_.end()) {
                     end_section();
 
-                    if (auto result = line_callback->second(std::move(args)); !result) {
+                    if (auto result = line_callback->second(std::move(args)); !result.ok()) {
                         parse_error_count_++;
                         LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
                     }
@@ -101,8 +101,8 @@
                     section_parser = section_parsers_[args[0]].get();
                     section_start_line = state.line;
                     if (auto result =
-                            section_parser->ParseSection(std::move(args), filename, state.line);
-                        !result) {
+                                section_parser->ParseSection(std::move(args), filename, state.line);
+                        !result.ok()) {
                         parse_error_count_++;
                         LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
                         section_parser = nullptr;
@@ -110,7 +110,7 @@
                     }
                 } else if (section_parser) {
                     if (auto result = section_parser->ParseLineSection(std::move(args), state.line);
-                        !result) {
+                        !result.ok()) {
                         parse_error_count_++;
                         LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
                     }
@@ -143,7 +143,7 @@
     LOG(INFO) << "Parsing file " << path << "...";
     android::base::Timer t;
     auto config_contents = ReadFile(path);
-    if (!config_contents) {
+    if (!config_contents.ok()) {
         LOG(INFO) << "Unable to read config file '" << path << "': " << config_contents.error();
         return false;
     }
diff --git a/init/persistent_properties.cpp b/init/persistent_properties.cpp
index 1758cfa..716f62e 100644
--- a/init/persistent_properties.cpp
+++ b/init/persistent_properties.cpp
@@ -149,7 +149,7 @@
         unlink(temp_filename.c_str());
     }
     auto file_contents = ReadFile(persistent_property_filename);
-    if (!file_contents) {
+    if (!file_contents.ok()) {
         return Error() << "Unable to read persistent property file: " << file_contents.error();
     }
     return *file_contents;
@@ -159,7 +159,7 @@
 
 Result<PersistentProperties> LoadPersistentPropertyFile() {
     auto file_contents = ReadPersistentPropertyFile();
-    if (!file_contents) return file_contents.error();
+    if (!file_contents.ok()) return file_contents.error();
 
     PersistentProperties persistent_properties;
     if (persistent_properties.ParseFromString(*file_contents)) return persistent_properties;
@@ -212,7 +212,7 @@
 void WritePersistentProperty(const std::string& name, const std::string& value) {
     auto persistent_properties = LoadPersistentPropertyFile();
 
-    if (!persistent_properties) {
+    if (!persistent_properties.ok()) {
         LOG(ERROR) << "Recovering persistent properties from memory: "
                    << persistent_properties.error();
         persistent_properties = LoadPersistentPropertiesFromMemory();
@@ -227,7 +227,7 @@
         AddPersistentProperty(name, value, &persistent_properties.value());
     }
 
-    if (auto result = WritePersistentPropertyFile(*persistent_properties); !result) {
+    if (auto result = WritePersistentPropertyFile(*persistent_properties); !result.ok()) {
         LOG(ERROR) << "Could not store persistent property: " << result.error();
     }
 }
@@ -235,16 +235,16 @@
 PersistentProperties LoadPersistentProperties() {
     auto persistent_properties = LoadPersistentPropertyFile();
 
-    if (!persistent_properties) {
+    if (!persistent_properties.ok()) {
         LOG(ERROR) << "Could not load single persistent property file, trying legacy directory: "
                    << persistent_properties.error();
         persistent_properties = LoadLegacyPersistentProperties();
-        if (!persistent_properties) {
+        if (!persistent_properties.ok()) {
             LOG(ERROR) << "Unable to load legacy persistent properties: "
                        << persistent_properties.error();
             return {};
         }
-        if (auto result = WritePersistentPropertyFile(*persistent_properties); result) {
+        if (auto result = WritePersistentPropertyFile(*persistent_properties); result.ok()) {
             RemoveLegacyPersistentPropertyFiles();
         } else {
             LOG(ERROR) << "Unable to write single persistent property file: " << result.error();
diff --git a/init/persistent_properties_test.cpp b/init/persistent_properties_test.cpp
index 13796a6..60cecde 100644
--- a/init/persistent_properties_test.cpp
+++ b/init/persistent_properties_test.cpp
@@ -83,7 +83,8 @@
         {"persist.\x00\x01\x02\xFF\xFE\xFD\x7F\x8F\x9F", "non-ascii-name"},
     };
 
-    ASSERT_TRUE(WritePersistentPropertyFile(VectorToPersistentProperties(persistent_properties)));
+    ASSERT_RESULT_OK(
+            WritePersistentPropertyFile(VectorToPersistentProperties(persistent_properties)));
 
     auto read_back_properties = LoadPersistentProperties();
     CheckPropertiesEqual(persistent_properties, read_back_properties);
@@ -97,7 +98,8 @@
     std::vector<std::pair<std::string, std::string>> persistent_properties = {
         {"persist.sys.timezone", "America/Los_Angeles"},
     };
-    ASSERT_TRUE(WritePersistentPropertyFile(VectorToPersistentProperties(persistent_properties)));
+    ASSERT_RESULT_OK(
+            WritePersistentPropertyFile(VectorToPersistentProperties(persistent_properties)));
 
     WritePersistentProperty("persist.sys.locale", "pt-BR");
 
@@ -119,7 +121,8 @@
         {"persist.sys.locale", "en-US"},
         {"persist.sys.timezone", "America/Los_Angeles"},
     };
-    ASSERT_TRUE(WritePersistentPropertyFile(VectorToPersistentProperties(persistent_properties)));
+    ASSERT_RESULT_OK(
+            WritePersistentPropertyFile(VectorToPersistentProperties(persistent_properties)));
 
     WritePersistentProperty("persist.sys.locale", "pt-BR");
 
@@ -137,7 +140,7 @@
     ASSERT_TRUE(tf.fd != -1);
     persistent_property_filename = tf.path;
 
-    ASSERT_TRUE(WriteFile(tf.path, "ab"));
+    ASSERT_RESULT_OK(WriteFile(tf.path, "ab"));
 
     WritePersistentProperty("persist.sys.locale", "pt-BR");
 
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 5b35ad2..84644e8 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -153,7 +153,7 @@
     changed_message->set_name(name);
     changed_message->set_value(value);
 
-    if (auto result = SendMessage(init_socket, property_msg); !result) {
+    if (auto result = SendMessage(init_socket, property_msg); !result.ok()) {
         LOG(ERROR) << "Failed to send property changed message: " << result.error();
     }
 }
@@ -166,7 +166,7 @@
         return PROP_ERROR_INVALID_NAME;
     }
 
-    if (auto result = IsLegalPropertyValue(name, value); !result) {
+    if (auto result = IsLegalPropertyValue(name, value); !result.ok()) {
         *error = result.error().message();
         return PROP_ERROR_INVALID_VALUE;
     }
@@ -392,7 +392,7 @@
         control_message->set_fd(fd);
     }
 
-    if (auto result = SendMessage(init_socket, property_msg); !result) {
+    if (auto result = SendMessage(init_socket, property_msg); !result.ok()) {
         // We've already released the fd above, so if we fail to send the message to init, we need
         // to manually free it here.
         if (fd != -1) {
@@ -670,7 +670,7 @@
             std::string raw_filename(fn);
             auto expanded_filename = ExpandProps(raw_filename);
 
-            if (!expanded_filename) {
+            if (!expanded_filename.ok()) {
                 LOG(ERROR) << "Could not expand filename ': " << expanded_filename.error();
                 continue;
             }
@@ -726,7 +726,7 @@
                                       std::map<std::string, std::string>* properties) {
     Timer t;
     auto file_contents = ReadFile(filename);
-    if (!file_contents) {
+    if (!file_contents.ok()) {
         PLOG(WARNING) << "Couldn't load property file '" << filename
                       << "': " << file_contents.error();
         return false;
@@ -1084,7 +1084,7 @@
 
 static void HandleInitSocket() {
     auto message = ReadMessage(init_socket);
-    if (!message) {
+    if (!message.ok()) {
         LOG(ERROR) << "Could not read message from init_dedicated_recv_socket: " << message.error();
         return;
     }
@@ -1123,21 +1123,22 @@
 
 static void PropertyServiceThread() {
     Epoll epoll;
-    if (auto result = epoll.Open(); !result) {
+    if (auto result = epoll.Open(); !result.ok()) {
         LOG(FATAL) << result.error();
     }
 
-    if (auto result = epoll.RegisterHandler(property_set_fd, handle_property_set_fd); !result) {
+    if (auto result = epoll.RegisterHandler(property_set_fd, handle_property_set_fd);
+        !result.ok()) {
         LOG(FATAL) << result.error();
     }
 
-    if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result) {
+    if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result.ok()) {
         LOG(FATAL) << result.error();
     }
 
     while (true) {
         auto pending_functions = epoll.Wait(std::nullopt);
-        if (!pending_functions) {
+        if (!pending_functions.ok()) {
             LOG(ERROR) << pending_functions.error();
         } else {
             for (const auto& function : *pending_functions) {
@@ -1159,7 +1160,8 @@
     accept_messages = true;
 
     if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
-                                   false, 0666, 0, 0, {})) {
+                                   false, 0666, 0, 0, {});
+        result.ok()) {
         property_set_fd = *result;
     } else {
         LOG(FATAL) << "start_property_service socket creation failed: " << result.error();
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 8b239fe..38e8227 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -180,7 +180,7 @@
         LOG(WARNING) << "cannot find blank_screen in TurnOffBacklight";
         return;
     }
-    if (auto result = service->Start(); !result) {
+    if (auto result = service->Start(); !result.ok()) {
         LOG(WARNING) << "Could not start blank_screen service: " << result.error();
     }
 }
@@ -591,14 +591,14 @@
             // keep debugging tools until non critical ones are all gone.
             s->SetShutdownCritical();
         } else if (to_starts.count(s->name())) {
-            if (auto result = s->Start(); !result) {
+            if (auto result = s->Start(); !result.ok()) {
                 LOG(ERROR) << "Could not start shutdown 'to_start' service '" << s->name()
                            << "': " << result.error();
             }
             s->SetShutdownCritical();
         } else if (s->IsShutdownCritical()) {
             // Start shutdown critical service if not started.
-            if (auto result = s->Start(); !result) {
+            if (auto result = s->Start(); !result.ok()) {
                 LOG(ERROR) << "Could not start shutdown critical service '" << s->name()
                            << "': " << result.error();
             }
@@ -731,9 +731,6 @@
 
 static Result<void> DoUserspaceReboot() {
     LOG(INFO) << "Userspace reboot initiated";
-    boot_clock::time_point now = boot_clock::now();
-    SetProperty("sys.init.userspace_reboot.last_started",
-                std::to_string(now.time_since_epoch().count()));
     auto guard = android::base::make_scope_guard([] {
         // Leave shutdown so that we can handle a full reboot.
         LeaveShutdown();
@@ -776,10 +773,10 @@
         // TODO(b/135984674): store information about offending services for debugging.
         return Error() << r << " post-data services are still running";
     }
-    if (auto result = KillZramBackingDevice(); !result) {
+    if (auto result = KillZramBackingDevice(); !result.ok()) {
         return result;
     }
-    if (auto result = CallVdc("volume", "reset"); !result) {
+    if (auto result = CallVdc("volume", "reset"); !result.ok()) {
         return result;
     }
     if (int r = StopServicesAndLogViolations(GetDebuggingServices(true /* only_post_data */), 5s,
@@ -794,7 +791,7 @@
         sync();
         LOG(INFO) << "sync() took " << sync_timer;
     }
-    if (auto result = UnmountAllApexes(); !result) {
+    if (auto result = UnmountAllApexes(); !result.ok()) {
         return result;
     }
     if (!SwitchToBootstrapMountNamespaceIfNeeded()) {
diff --git a/init/result.h b/init/result.h
index b70dd1b..8c1f91e 100644
--- a/init/result.h
+++ b/init/result.h
@@ -22,8 +22,6 @@
 #include <android-base/result.h>
 
 using android::base::ErrnoError;
-using android::base::ErrnoErrorf;
 using android::base::Error;
-using android::base::Errorf;
 using android::base::Result;
 using android::base::ResultError;
diff --git a/init/rlimit_parser_test.cpp b/init/rlimit_parser_test.cpp
index 6a16d3b..3c3f848 100644
--- a/init/rlimit_parser_test.cpp
+++ b/init/rlimit_parser_test.cpp
@@ -29,7 +29,7 @@
     ASSERT_EQ(4U, input.size());
     auto result = ParseRlimit(input);
 
-    ASSERT_TRUE(result) << "input: " << input[1];
+    ASSERT_TRUE(result.ok()) << "input: " << input[1];
     const auto& [resource, rlimit] = *result;
     const auto& [expected_resource, expected_rlimit] = expected_result;
     EXPECT_EQ(expected_resource, resource);
@@ -42,7 +42,7 @@
     ASSERT_EQ(4U, input.size());
     auto result = ParseRlimit(input);
 
-    ASSERT_FALSE(result) << "input: " << input[1];
+    ASSERT_FALSE(result.ok()) << "input: " << input[1];
     EXPECT_EQ(expected_result, result.error().message());
     EXPECT_EQ(0, result.error().code());
 }
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 852d6ca..41007c1 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -477,7 +477,7 @@
         }
     }
 
-    if (auto result = WriteFile("/sys/fs/selinux/checkreqprot", "0"); !result) {
+    if (auto result = WriteFile("/sys/fs/selinux/checkreqprot", "0"); !result.ok()) {
         LOG(FATAL) << "Unable to write to /sys/fs/selinux/checkreqprot: " << result.error();
     }
 }
diff --git a/init/service.cpp b/init/service.cpp
index 0e27ff1..665a1b0 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -106,7 +106,7 @@
     c_strings.push_back(const_cast<char*>(args[0].data()));
     for (std::size_t i = 1; i < args.size(); ++i) {
         auto expanded_arg = ExpandProps(args[i]);
-        if (!expanded_arg) {
+        if (!expanded_arg.ok()) {
             LOG(FATAL) << args[0] << ": cannot expand arguments': " << expanded_arg.error();
         }
         expanded_args[i] = *expanded_arg;
@@ -232,7 +232,7 @@
         }
     }
 
-    if (auto result = SetProcessAttributes(proc_attr_); !result) {
+    if (auto result = SetProcessAttributes(proc_attr_); !result.ok()) {
         LOG(FATAL) << "cannot set attribute for " << name_ << ": " << result.error();
     }
 
@@ -374,7 +374,7 @@
 
     flags_ |= SVC_ONESHOT;
 
-    if (auto result = Start(); !result) {
+    if (auto result = Start(); !result.ok()) {
         return result;
     }
 
@@ -449,7 +449,7 @@
         scon = seclabel_;
     } else {
         auto result = ComputeContextFromExecutable(args_[0]);
-        if (!result) {
+        if (!result.ok()) {
             return result.error();
         }
         scon = *result;
@@ -469,7 +469,7 @@
 
     std::vector<Descriptor> descriptors;
     for (const auto& socket : sockets_) {
-        if (auto result = socket.Create(scon)) {
+        if (auto result = socket.Create(scon); result.ok()) {
             descriptors.emplace_back(std::move(*result));
         } else {
             LOG(INFO) << "Could not create socket '" << socket.name << "': " << result.error();
@@ -477,7 +477,7 @@
     }
 
     for (const auto& file : files_) {
-        if (auto result = file.Create()) {
+        if (auto result = file.Create(); result.ok()) {
             descriptors.emplace_back(std::move(*result));
         } else {
             LOG(INFO) << "Could not open file '" << file.name << "': " << result.error();
@@ -494,7 +494,7 @@
     if (pid == 0) {
         umask(077);
 
-        if (auto result = EnterNamespaces(namespaces_, name_, pre_apexd_); !result) {
+        if (auto result = EnterNamespaces(namespaces_, name_, pre_apexd_); !result.ok()) {
             LOG(FATAL) << "Service '" << name_
                        << "' failed to set up namespaces: " << result.error();
         }
@@ -507,7 +507,7 @@
             descriptor.Publish();
         }
 
-        if (auto result = WritePidToFiles(&writepid_files_); !result) {
+        if (auto result = WritePidToFiles(&writepid_files_); !result.ok()) {
             LOG(ERROR) << "failed to write pid to files: " << result.error();
         }
 
@@ -669,7 +669,7 @@
         StopOrReset(SVC_RESTART);
     } else if (!(flags_ & SVC_RESTARTING)) {
         /* Just start the service since it's not running. */
-        if (auto result = Start(); !result) {
+        if (auto result = Start(); !result.ok()) {
             LOG(ERROR) << "Could not restart '" << name_ << "': " << result.error();
         }
     } /* else: Service is restarting anyways. */
@@ -742,7 +742,7 @@
     Result<uid_t> uid = 0;
     if (command_arg > 3) {
         uid = DecodeUid(args[2]);
-        if (!uid) {
+        if (!uid.ok()) {
             return Error() << "Unable to decode UID for '" << args[2] << "': " << uid.error();
         }
     }
@@ -750,13 +750,13 @@
     std::vector<gid_t> supp_gids;
     if (command_arg > 4) {
         gid = DecodeUid(args[3]);
-        if (!gid) {
+        if (!gid.ok()) {
             return Error() << "Unable to decode GID for '" << args[3] << "': " << gid.error();
         }
         std::size_t nr_supp_gids = command_arg - 1 /* -- */ - 4 /* exec SECLABEL UID GID */;
         for (size_t i = 0; i < nr_supp_gids; ++i) {
             auto supp_gid = DecodeUid(args[4 + i]);
-            if (!supp_gid) {
+            if (!supp_gid.ok()) {
                 return Error() << "Unable to decode GID for '" << args[4 + i]
                                << "': " << supp_gid.error();
             }
diff --git a/init/service_list.cpp b/init/service_list.cpp
index c51a9cf..3047821 100644
--- a/init/service_list.cpp
+++ b/init/service_list.cpp
@@ -86,7 +86,7 @@
             LOG(ERROR) << "delayed service '" << name << "' could not be found.";
             continue;
         }
-        if (auto result = service->Start(); !result) {
+        if (auto result = service->Start(); !result.ok()) {
             LOG(ERROR) << result.error().message();
         }
     }
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index 1d431e3..4b04ba0 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -119,14 +119,14 @@
 
 Result<void> ServiceParser::ParseGroup(std::vector<std::string>&& args) {
     auto gid = DecodeUid(args[1]);
-    if (!gid) {
+    if (!gid.ok()) {
         return Error() << "Unable to decode GID for '" << args[1] << "': " << gid.error();
     }
     service_->proc_attr_.gid = *gid;
 
     for (std::size_t n = 2; n < args.size(); n++) {
         gid = DecodeUid(args[n]);
-        if (!gid) {
+        if (!gid.ok()) {
             return Error() << "Unable to decode GID for '" << args[n] << "': " << gid.error();
         }
         service_->proc_attr_.supp_gids.emplace_back(*gid);
@@ -202,13 +202,13 @@
     auto it = args.begin() + 1;
     if (args.size() == 2 && StartsWith(args[1], "$")) {
         auto expanded = ExpandProps(args[1]);
-        if (!expanded) {
+        if (!expanded.ok()) {
             return expanded.error();
         }
 
         // If the property is not set, it defaults to none, in which case there are no keycodes
         // for this service.
-        if (expanded == "none") {
+        if (*expanded == "none") {
             return {};
         }
 
@@ -240,7 +240,7 @@
 Result<void> ServiceParser::ParseOnrestart(std::vector<std::string>&& args) {
     args.erase(args.begin());
     int line = service_->onrestart_.NumCommands() + 1;
-    if (auto result = service_->onrestart_.AddCommand(std::move(args), line); !result) {
+    if (auto result = service_->onrestart_.AddCommand(std::move(args), line); !result.ok()) {
         return Error() << "cannot add Onrestart command: " << result.error();
     }
     return {};
@@ -310,7 +310,7 @@
 
 Result<void> ServiceParser::ParseProcessRlimit(std::vector<std::string>&& args) {
     auto rlimit = ParseRlimit(args);
-    if (!rlimit) return rlimit.error();
+    if (!rlimit.ok()) return rlimit.error();
 
     service_->proc_attr_.rlimits.emplace_back(*rlimit);
     return {};
@@ -407,7 +407,7 @@
 
     if (args.size() > 4) {
         auto uid = DecodeUid(args[4]);
-        if (!uid) {
+        if (!uid.ok()) {
             return Error() << "Unable to find UID for '" << args[4] << "': " << uid.error();
         }
         socket.uid = *uid;
@@ -415,7 +415,7 @@
 
     if (args.size() > 5) {
         auto gid = DecodeUid(args[5]);
-        if (!gid) {
+        if (!gid.ok()) {
             return Error() << "Unable to find GID for '" << args[5] << "': " << gid.error();
         }
         socket.gid = *gid;
@@ -453,7 +453,7 @@
     file.type = args[2];
 
     auto file_name = ExpandProps(args[1]);
-    if (!file_name) {
+    if (!file_name.ok()) {
         return Error() << "Could not expand file path ': " << file_name.error();
     }
     file.name = *file_name;
@@ -475,7 +475,7 @@
 
 Result<void> ServiceParser::ParseUser(std::vector<std::string>&& args) {
     auto uid = DecodeUid(args[1]);
-    if (!uid) {
+    if (!uid.ok()) {
         return Error() << "Unable to find UID for '" << args[1] << "': " << uid.error();
     }
     service_->proc_attr_.uid = *uid;
@@ -580,7 +580,7 @@
 
     auto parser = GetParserMap().Find(args);
 
-    if (!parser) return parser.error();
+    if (!parser.ok()) return parser.error();
 
     return std::invoke(*parser, this, std::move(args));
 }
@@ -593,7 +593,7 @@
     if (interface_inheritance_hierarchy_) {
         if (const auto& check_hierarchy_result = CheckInterfaceInheritanceHierarchy(
                     service_->interfaces(), *interface_inheritance_hierarchy_);
-            !check_hierarchy_result) {
+            !check_hierarchy_result.ok()) {
             return Error() << check_hierarchy_result.error();
         }
     }
diff --git a/init/service_test.cpp b/init/service_test.cpp
index c158b0a..22ee844 100644
--- a/init/service_test.cpp
+++ b/init/service_test.cpp
@@ -76,15 +76,15 @@
 TEST(service, make_temporary_oneshot_service_invalid_syntax) {
     std::vector<std::string> args;
     // Nothing.
-    ASSERT_FALSE(Service::MakeTemporaryOneshotService(args));
+    ASSERT_FALSE(Service::MakeTemporaryOneshotService(args).ok());
 
     // No arguments to 'exec'.
     args.push_back("exec");
-    ASSERT_FALSE(Service::MakeTemporaryOneshotService(args));
+    ASSERT_FALSE(Service::MakeTemporaryOneshotService(args).ok());
 
     // No command in "exec --".
     args.push_back("--");
-    ASSERT_FALSE(Service::MakeTemporaryOneshotService(args));
+    ASSERT_FALSE(Service::MakeTemporaryOneshotService(args).ok());
 }
 
 TEST(service, make_temporary_oneshot_service_too_many_supplementary_gids) {
@@ -98,7 +98,7 @@
     }
     args.push_back("--");
     args.push_back("/system/bin/id");
-    ASSERT_FALSE(Service::MakeTemporaryOneshotService(args));
+    ASSERT_FALSE(Service::MakeTemporaryOneshotService(args).ok());
 }
 
 static void Test_make_temporary_oneshot_service(bool dash_dash, bool seclabel, bool uid, bool gid,
@@ -124,7 +124,7 @@
     args.push_back("/system/bin/toybox");
     args.push_back("id");
     auto service_ret = Service::MakeTemporaryOneshotService(args);
-    ASSERT_TRUE(service_ret);
+    ASSERT_RESULT_OK(service_ret);
     auto svc = std::move(*service_ret);
 
     if (seclabel) {
@@ -134,14 +134,14 @@
     }
     if (uid) {
         auto decoded_uid = DecodeUid("log");
-        ASSERT_TRUE(decoded_uid);
+        ASSERT_RESULT_OK(decoded_uid);
         ASSERT_EQ(*decoded_uid, svc->uid());
     } else {
         ASSERT_EQ(0U, svc->uid());
     }
     if (gid) {
         auto decoded_uid = DecodeUid("shell");
-        ASSERT_TRUE(decoded_uid);
+        ASSERT_RESULT_OK(decoded_uid);
         ASSERT_EQ(*decoded_uid, svc->gid());
     } else {
         ASSERT_EQ(0U, svc->gid());
@@ -150,11 +150,11 @@
         ASSERT_EQ(2U, svc->supp_gids().size());
 
         auto decoded_uid = DecodeUid("system");
-        ASSERT_TRUE(decoded_uid);
+        ASSERT_RESULT_OK(decoded_uid);
         ASSERT_EQ(*decoded_uid, svc->supp_gids()[0]);
 
         decoded_uid = DecodeUid("adb");
-        ASSERT_TRUE(decoded_uid);
+        ASSERT_RESULT_OK(decoded_uid);
         ASSERT_EQ(*decoded_uid, svc->supp_gids()[1]);
     } else {
         ASSERT_EQ(0U, svc->supp_gids().size());
diff --git a/init/service_utils.cpp b/init/service_utils.cpp
index 93cffd8..484c2c8 100644
--- a/init/service_utils.cpp
+++ b/init/service_utils.cpp
@@ -167,7 +167,7 @@
 Result<Descriptor> SocketDescriptor::Create(const std::string& global_context) const {
     const auto& socket_context = context.empty() ? global_context : context;
     auto result = CreateSocket(name, type | SOCK_CLOEXEC, passcred, perm, uid, gid, socket_context);
-    if (!result) {
+    if (!result.ok()) {
         return result.error();
     }
 
@@ -196,7 +196,7 @@
 
 Result<void> EnterNamespaces(const NamespaceInfo& info, const std::string& name, bool pre_apexd) {
     for (const auto& [nstype, path] : info.namespaces_to_enter) {
-        if (auto result = EnterNamespace(nstype, path.c_str()); !result) {
+        if (auto result = EnterNamespace(nstype, path.c_str()); !result.ok()) {
             return result;
         }
     }
@@ -214,14 +214,14 @@
         bool remount_sys =
                 std::any_of(info.namespaces_to_enter.begin(), info.namespaces_to_enter.end(),
                             [](const auto& entry) { return entry.first == CLONE_NEWNET; });
-        if (auto result = SetUpMountNamespace(remount_proc, remount_sys); !result) {
+        if (auto result = SetUpMountNamespace(remount_proc, remount_sys); !result.ok()) {
             return result;
         }
     }
 
     if (info.flags & CLONE_NEWPID) {
         // This will fork again to run an init process inside the PID namespace.
-        if (auto result = SetUpPidNamespace(name.c_str()); !result) {
+        if (auto result = SetUpPidNamespace(name.c_str()); !result.ok()) {
             return result;
         }
     }
@@ -249,9 +249,8 @@
 
     for (const auto& rlimit : attr.rlimits) {
         if (setrlimit(rlimit.first, &rlimit.second) == -1) {
-            return ErrnoError() << StringPrintf(
-                           "setrlimit(%d, {rlim_cur=%ld, rlim_max=%ld}) failed", rlimit.first,
-                           rlimit.second.rlim_cur, rlimit.second.rlim_max);
+            return ErrnoErrorf("setrlimit({}, {{rlim_cur={}, rlim_max={}}}) failed", rlimit.first,
+                               rlimit.second.rlim_cur, rlimit.second.rlim_max);
         }
     }
 
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index f3f759d..3260159 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -80,13 +80,13 @@
 
     auto map_result = function_map_->Find(args);
     Result<void> result;
-    if (!map_result) {
+    if (!map_result.ok()) {
         result = Error() << "Cannot find command: " << map_result.error();
     } else {
         result = RunBuiltinFunction(map_result->function, args, context_);
     }
 
-    if (result) {
+    if (result.ok()) {
         reply->set_success(true);
     } else {
         auto* failure = reply->mutable_failure();
@@ -99,7 +99,7 @@
                                    SubcontextReply* reply) const {
     for (const auto& arg : expand_args_command.args()) {
         auto expanded_arg = ExpandProps(arg);
-        if (!expanded_arg) {
+        if (!expanded_arg.ok()) {
             auto* failure = reply->mutable_failure();
             failure->set_error_string(expanded_arg.error().message());
             failure->set_error_errno(0);
@@ -125,7 +125,7 @@
         }
 
         auto init_message = ReadMessage(init_fd_);
-        if (!init_message) {
+        if (!init_message.ok()) {
             if (init_message.error().code() == 0) {
                 // If the init file descriptor was closed, let's exit quietly. If
                 // this was accidental, init will restart us. If init died, this
@@ -160,7 +160,7 @@
             shutdown_command.clear();
         }
 
-        if (auto result = SendMessage(init_fd_, reply); !result) {
+        if (auto result = SendMessage(init_fd_, reply); !result.ok()) {
             LOG(FATAL) << "Failed to send message to init: " << result.error();
         }
     }
@@ -246,13 +246,13 @@
 }
 
 Result<SubcontextReply> Subcontext::TransmitMessage(const SubcontextCommand& subcontext_command) {
-    if (auto result = SendMessage(socket_, subcontext_command); !result) {
+    if (auto result = SendMessage(socket_, subcontext_command); !result.ok()) {
         Restart();
         return ErrnoError() << "Failed to send message to subcontext";
     }
 
     auto subcontext_message = ReadMessage(socket_);
-    if (!subcontext_message) {
+    if (!subcontext_message.ok()) {
         Restart();
         return Error() << "Failed to receive result from subcontext: " << subcontext_message.error();
     }
@@ -277,7 +277,7 @@
         RepeatedPtrFieldBackInserter(subcontext_command.mutable_execute_command()->mutable_args()));
 
     auto subcontext_reply = TransmitMessage(subcontext_command);
-    if (!subcontext_reply) {
+    if (!subcontext_reply.ok()) {
         return subcontext_reply.error();
     }
 
@@ -301,7 +301,7 @@
                   subcontext_command.mutable_expand_args_command()->mutable_args()));
 
     auto subcontext_reply = TransmitMessage(subcontext_command);
-    if (!subcontext_reply) {
+    if (!subcontext_reply.ok()) {
         return subcontext_reply.error();
     }
 
diff --git a/init/subcontext_test.cpp b/init/subcontext_test.cpp
index 2e5a256..ee765a7 100644
--- a/init/subcontext_test.cpp
+++ b/init/subcontext_test.cpp
@@ -55,7 +55,7 @@
 TEST(subcontext, CheckDifferentPid) {
     RunTest([](auto& subcontext) {
         auto result = subcontext.Execute(std::vector<std::string>{"return_pids_as_error"});
-        ASSERT_FALSE(result);
+        ASSERT_FALSE(result.ok());
 
         auto pids = Split(result.error().message(), " ");
         ASSERT_EQ(2U, pids.size());
@@ -81,7 +81,7 @@
             "success",
         };
         auto result = subcontext.Execute(args);
-        ASSERT_TRUE(result) << result.error();
+        ASSERT_RESULT_OK(result);
 
         EXPECT_TRUE(WaitForProperty("init.test.subcontext", "success", 10s));
     });
@@ -104,11 +104,11 @@
                 word,
             };
             auto result = subcontext.Execute(args);
-            ASSERT_TRUE(result) << result.error();
+            ASSERT_RESULT_OK(result);
         }
 
         auto result = subcontext.Execute(std::vector<std::string>{"return_words_as_error"});
-        ASSERT_FALSE(result);
+        ASSERT_FALSE(result.ok());
         EXPECT_EQ(Join(expected_words, " "), result.error().message());
         EXPECT_EQ(first_pid, subcontext.pid());
     });
@@ -119,10 +119,10 @@
         auto first_pid = subcontext.pid();
 
         auto result = subcontext.Execute(std::vector<std::string>{"cause_log_fatal"});
-        ASSERT_FALSE(result);
+        ASSERT_FALSE(result.ok());
 
         auto result2 = subcontext.Execute(std::vector<std::string>{"generate_sane_error"});
-        ASSERT_FALSE(result2);
+        ASSERT_FALSE(result2.ok());
         EXPECT_EQ("Sane error!", result2.error().message());
         EXPECT_NE(subcontext.pid(), first_pid);
     });
@@ -131,7 +131,7 @@
 TEST(subcontext, ContextString) {
     RunTest([](auto& subcontext) {
         auto result = subcontext.Execute(std::vector<std::string>{"return_context_as_error"});
-        ASSERT_FALSE(result);
+        ASSERT_FALSE(result.ok());
         ASSERT_EQ(kTestContext, result.error().message());
     });
 }
@@ -143,7 +143,7 @@
     RunTest([](auto& subcontext) {
         auto result = subcontext.Execute(
                 std::vector<std::string>{"trigger_shutdown", kTestShutdownCommand});
-        ASSERT_TRUE(result);
+        ASSERT_RESULT_OK(result);
     });
     EXPECT_EQ(kTestShutdownCommand, trigger_shutdown_command);
 }
@@ -156,7 +156,7 @@
             "$$third",
         };
         auto result = subcontext.ExpandArgs(args);
-        ASSERT_TRUE(result) << result.error();
+        ASSERT_RESULT_OK(result);
         ASSERT_EQ(3U, result->size());
         EXPECT_EQ(args[0], result->at(0));
         EXPECT_EQ(GetProperty("ro.hardware", ""), result->at(1));
@@ -171,7 +171,7 @@
             "${",
         };
         auto result = subcontext.ExpandArgs(args);
-        ASSERT_FALSE(result);
+        ASSERT_FALSE(result.ok());
         EXPECT_EQ("unexpected end of string in '" + args[1] + "', looking for }",
                   result.error().message());
     });
diff --git a/init/test_utils/include/init-test-utils/service_utils.h b/init/test_utils/include/init-test-utils/service_utils.h
index 3ec61d4..f9366ea 100644
--- a/init/test_utils/include/init-test-utils/service_utils.h
+++ b/init/test_utils/include/init-test-utils/service_utils.h
@@ -20,12 +20,20 @@
 #include <set>
 
 #include <android-base/result.h>
-#include <hidl-util/FqInstance.h>
 
 namespace android {
 namespace init {
 
-using ServiceInterfacesMap = std::map<std::string, std::set<android::FqInstance>>;
+// this is service name -> interface declaration
+//
+// So, for:
+//     service foo ..
+//         interface aidl baz
+//         interface android.hardware.foo@1.0 IFoo
+//
+// We have:
+//     foo -> { aidl/baz, android.hardware.foo@1.0/IFoo }
+using ServiceInterfacesMap = std::map<std::string, std::set<std::string>>;
 android::base::Result<ServiceInterfacesMap> GetOnDeviceServiceInterfacesMap();
 
 }  // namespace init
diff --git a/init/test_utils/service_utils.cpp b/init/test_utils/service_utils.cpp
index bc00702..ae68679 100644
--- a/init/test_utils/service_utils.cpp
+++ b/init/test_utils/service_utils.cpp
@@ -47,14 +47,7 @@
     for (const auto& service : service_list.services()) {
         // Create an entry for all services, including services that may not
         // have any declared interfaces.
-        result[service->name()] = std::set<android::FqInstance>();
-        for (const auto& intf : service->interfaces()) {
-            android::FqInstance fqInstance;
-            if (!fqInstance.setTo(intf)) {
-                return android::base::Error() << "Unable to parse interface: '" << intf << "'";
-            }
-            result[service->name()].insert(fqInstance);
-        }
+        result[service->name()] = service->interfaces();
     }
     return result;
 }
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index a74b247..09dce44 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -209,7 +209,7 @@
 
     auto parser = parser_map.Find(args);
 
-    if (!parser) return Error() << parser.error();
+    if (!parser.ok()) return Error() << parser.error();
 
     return std::invoke(*parser, this, std::move(args));
 }
diff --git a/init/util.cpp b/init/util.cpp
index 0ca0da5..503c705 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -497,14 +497,14 @@
                 break;
             case 3:
                 uid = DecodeUid(args[3]);
-                if (!uid) {
+                if (!uid.ok()) {
                     return Error()
                            << "Unable to decode UID for '" << args[3] << "': " << uid.error();
                 }
                 break;
             case 4:
                 gid = DecodeUid(args[4]);
-                if (!gid) {
+                if (!gid.ok()) {
                     return Error()
                            << "Unable to decode GID for '" << args[4] << "': " << gid.error();
                 }
diff --git a/init/util_test.cpp b/init/util_test.cpp
index a8fcc87..96a5b55 100644
--- a/init/util_test.cpp
+++ b/init/util_test.cpp
@@ -33,7 +33,7 @@
     errno = 0;
     auto file_contents = ReadFile("/proc/does-not-exist");
     EXPECT_EQ(ENOENT, errno);
-    ASSERT_FALSE(file_contents);
+    ASSERT_FALSE(file_contents.ok());
     EXPECT_EQ("open() failed: No such file or directory", file_contents.error().message());
 }
 
@@ -41,10 +41,10 @@
     std::string s("hello");
     TemporaryFile tf;
     ASSERT_TRUE(tf.fd != -1);
-    EXPECT_TRUE(WriteFile(tf.path, s)) << strerror(errno);
+    EXPECT_RESULT_OK(WriteFile(tf.path, s));
     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);
+    ASSERT_FALSE(file_contents.ok()) << strerror(errno);
     EXPECT_EQ("Skipping insecure file", file_contents.error().message());
 }
 
@@ -52,10 +52,10 @@
     std::string s("hello");
     TemporaryFile tf;
     ASSERT_TRUE(tf.fd != -1);
-    EXPECT_TRUE(WriteFile(tf.path, s)) << strerror(errno);
+    EXPECT_RESULT_OK(WriteFile(tf.path, s));
     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);
+    ASSERT_FALSE(file_contents.ok());
     EXPECT_EQ("Skipping insecure file", file_contents.error().message());
 }
 
@@ -64,14 +64,14 @@
     // lrw------- 1 root root 23 2008-12-31 19:00 default.prop -> system/etc/prop.default
     auto file_contents = ReadFile("/default.prop");
     EXPECT_EQ(ELOOP, errno);
-    ASSERT_FALSE(file_contents);
+    ASSERT_FALSE(file_contents.ok());
     EXPECT_EQ("open() failed: Too many symbolic links encountered",
               file_contents.error().message());
 }
 
 TEST(util, ReadFileSuccess) {
     auto file_contents = ReadFile("/proc/version");
-    ASSERT_TRUE(file_contents);
+    ASSERT_TRUE(file_contents.ok());
     EXPECT_GT(file_contents->length(), 6U);
     EXPECT_EQ('\n', file_contents->at(file_contents->length() - 1));
     (*file_contents)[5] = 0;
@@ -87,10 +87,10 @@
 
     TemporaryFile tf;
     ASSERT_TRUE(tf.fd != -1);
-    EXPECT_TRUE(WriteFile(tf.path, contents)) << strerror(errno);
+    EXPECT_RESULT_OK(WriteFile(tf.path, contents));
 
     auto read_back_contents = ReadFile(tf.path);
-    ASSERT_TRUE(read_back_contents) << strerror(errno);
+    ASSERT_RESULT_OK(read_back_contents);
     EXPECT_EQ(contents, *read_back_contents);
     EXPECT_EQ(10u, read_back_contents->size());
 }
@@ -99,14 +99,15 @@
     std::string s("hello");
     TemporaryDir test_dir;
     std::string path = android::base::StringPrintf("%s/does-not-exist", test_dir.path);
-    EXPECT_TRUE(WriteFile(path, s));
+    EXPECT_RESULT_OK(WriteFile(path, s));
     auto file_contents = ReadFile(path);
-    ASSERT_TRUE(file_contents);
+    ASSERT_RESULT_OK(file_contents);
     EXPECT_EQ(s, *file_contents);
     struct stat sb;
     int fd = open(path.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
     EXPECT_NE(-1, fd);
     EXPECT_EQ(0, fstat(fd, &sb));
+    EXPECT_EQ(0, close(fd));
     EXPECT_EQ((const unsigned int)(S_IRUSR | S_IWUSR), sb.st_mode & 0777);
     EXPECT_EQ(0, unlink(path.c_str()));
 }
@@ -114,27 +115,27 @@
 TEST(util, WriteFileExist) {
     TemporaryFile tf;
     ASSERT_TRUE(tf.fd != -1);
-    EXPECT_TRUE(WriteFile(tf.path, "1hello1")) << strerror(errno);
+    EXPECT_RESULT_OK(WriteFile(tf.path, "1hello1"));
     auto file_contents = ReadFile(tf.path);
-    ASSERT_TRUE(file_contents);
+    ASSERT_RESULT_OK(file_contents);
     EXPECT_EQ("1hello1", *file_contents);
-    EXPECT_TRUE(WriteFile(tf.path, "2ll2"));
+    EXPECT_RESULT_OK(WriteFile(tf.path, "2ll2"));
     file_contents = ReadFile(tf.path);
-    ASSERT_TRUE(file_contents);
+    ASSERT_RESULT_OK(file_contents);
     EXPECT_EQ("2ll2", *file_contents);
 }
 
 TEST(util, DecodeUid) {
     auto decoded_uid = DecodeUid("root");
-    EXPECT_TRUE(decoded_uid);
+    EXPECT_TRUE(decoded_uid.ok());
     EXPECT_EQ(0U, *decoded_uid);
 
     decoded_uid = DecodeUid("toot");
-    EXPECT_FALSE(decoded_uid);
+    EXPECT_FALSE(decoded_uid.ok());
     EXPECT_EQ("getpwnam failed: No such file or directory", decoded_uid.error().message());
 
     decoded_uid = DecodeUid("123");
-    EXPECT_TRUE(decoded_uid);
+    EXPECT_RESULT_OK(decoded_uid);
     EXPECT_EQ(123U, *decoded_uid);
 }
 
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index fd9a3eb..c4e4f85 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -74,6 +74,8 @@
     { 00775, AID_MEDIA_RW,     AID_MEDIA_RW,     0, "data/media" },
     { 00750, AID_ROOT,         AID_SHELL,        0, "data/nativetest" },
     { 00750, AID_ROOT,         AID_SHELL,        0, "data/nativetest64" },
+    { 00750, AID_ROOT,         AID_SHELL,        0, "data/benchmarktest" },
+    { 00750, AID_ROOT,         AID_SHELL,        0, "data/benchmarktest64" },
     { 00775, AID_ROOT,         AID_ROOT,         0, "data/preloads" },
     { 00771, AID_SYSTEM,       AID_SYSTEM,       0, "data" },
     { 00755, AID_ROOT,         AID_SYSTEM,       0, "mnt" },
@@ -145,6 +147,8 @@
     { 00640, AID_ROOT,      AID_SHELL,     0, "data/nativetest64/tests.txt" },
     { 00750, AID_ROOT,      AID_SHELL,     0, "data/nativetest/*" },
     { 00750, AID_ROOT,      AID_SHELL,     0, "data/nativetest64/*" },
+    { 00750, AID_ROOT,      AID_SHELL,     0, "data/benchmarktest/*" },
+    { 00750, AID_ROOT,      AID_SHELL,     0, "data/benchmarktest64/*" },
     { 00600, AID_ROOT,      AID_ROOT,      0, "default.prop" }, // legacy
     { 00600, AID_ROOT,      AID_ROOT,      0, "system/etc/prop.default" },
     { 00600, AID_ROOT,      AID_ROOT,      0, "odm/build.prop" }, // legacy; only for P release
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index ff6b036..a2d36ff 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -131,6 +131,8 @@
 #define AID_FSVERITY_CERT 1075   /* fs-verity key ownership in keystore */
 #define AID_CREDSTORE 1076       /* identity credential manager service */
 #define AID_EXTERNAL_STORAGE 1077 /* Full external storage access including USB OTG volumes */
+#define AID_EXT_DATA_RW 1078      /* GID for app-private data directories on external storage */
+#define AID_EXT_OBB_RW 1079       /* GID for OBB directories on external storage */
 /* Changes to this file must be made in AOSP, *not* in internal branches. */
 
 #define AID_SHELL 2000 /* adb and debug shell user */
diff --git a/libcutils/trace-container.cpp b/libcutils/trace-container.cpp
index c23d5e2..f7eed48 100644
--- a/libcutils/trace-container.cpp
+++ b/libcutils/trace-container.cpp
@@ -87,24 +87,28 @@
 
 static void atrace_init_once()
 {
-    atrace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY | O_CLOEXEC);
+    atrace_marker_fd = open("/sys/kernel/tracing/trace_marker", O_WRONLY | O_CLOEXEC);
     if (atrace_marker_fd < 0) {
-        // We're in container, ftrace may be disabled. In such case, we use the
-        // socket to write trace event.
+        // try debugfs
+        atrace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY | O_CLOEXEC);
+        if (atrace_marker_fd < 0) {
+            // We're in container, ftrace may be disabled. In such case, we use the
+            // socket to write trace event.
 
-        // Protect the initialization of container socket from
-        // atrace_set_tracing_enabled.
-        pthread_mutex_lock(&atrace_enabling_mutex);
-        atrace_use_container_sock = true;
-        bool success = false;
-        if (atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) {
-            success = atrace_init_container_sock();
-        }
-        pthread_mutex_unlock(&atrace_enabling_mutex);
+            // Protect the initialization of container socket from
+            // atrace_set_tracing_enabled.
+            pthread_mutex_lock(&atrace_enabling_mutex);
+            atrace_use_container_sock = true;
+            bool success = false;
+            if (atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) {
+                success = atrace_init_container_sock();
+            }
+            pthread_mutex_unlock(&atrace_enabling_mutex);
 
-        if (!success) {
-            atrace_enabled_tags = 0;
-            goto done;
+            if (!success) {
+                atrace_enabled_tags = 0;
+                goto done;
+            }
         }
     }
     atrace_enabled_tags = atrace_get_property();
diff --git a/liblog/logger_read.cpp b/liblog/logger_read.cpp
index a0c526b..4937042 100644
--- a/liblog/logger_read.cpp
+++ b/liblog/logger_read.cpp
@@ -109,8 +109,8 @@
     return ret;
   }
 
-  if (ret > (int)sizeof(*log_msg)) {
-    ret = sizeof(*log_msg);
+  if (ret > LOGGER_ENTRY_MAX_LEN) {
+    ret = LOGGER_ENTRY_MAX_LEN;
   }
 
   if (ret < static_cast<int>(sizeof(log_msg->entry))) {
@@ -118,7 +118,7 @@
   }
 
   if (log_msg->entry.hdr_size < sizeof(log_msg->entry) ||
-      log_msg->entry.hdr_size >= sizeof(struct log_msg) - sizeof(log_msg->entry)) {
+      log_msg->entry.hdr_size >= LOGGER_ENTRY_MAX_LEN - sizeof(log_msg->entry)) {
     return -EINVAL;
   }
 
@@ -126,6 +126,8 @@
     return -EINVAL;
   }
 
+  log_msg->buf[log_msg->entry.len + log_msg->entry.hdr_size] = '\0';
+
   return ret;
 }
 
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index 3f3dbd7..3f08535 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -43,12 +43,12 @@
     {
       "Name": "UClampMin",
       "Controller": "cpu",
-      "File": "cpu.util.min"
+      "File": "cpu.uclamp.min"
     },
     {
       "Name": "UClampMax",
       "Controller": "cpu",
-      "File": "cpu.util.max"
+      "File": "cpu.uclamp.max"
     }
   ],
 
diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h
index adc3e7d..27eca0c 100644
--- a/libutils/include/utils/String16.h
+++ b/libutils/include/utils/String16.h
@@ -25,18 +25,10 @@
 
 // ---------------------------------------------------------------------------
 
-extern "C" {
-
-}
-
-// ---------------------------------------------------------------------------
-
 namespace android {
 
 // ---------------------------------------------------------------------------
 
-class String8;
-
 template <size_t N>
 class StaticString16;
 
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 20fb071..d6ce0d2 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -73,19 +73,6 @@
     mkdir /dev/boringssl 0755 root root
     mkdir /dev/boringssl/selftest 0755 root root
 
-    # Mount binderfs
-    mkdir /dev/binderfs
-    mount binder binder /dev/binderfs stats=global
-    chmod 0755 /dev/binderfs
-
-    symlink /dev/binderfs/binder /dev/binder
-    symlink /dev/binderfs/hwbinder /dev/hwbinder
-    symlink /dev/binderfs/vndbinder /dev/vndbinder
-
-    chmod 0666 /dev/binderfs/hwbinder
-    chmod 0666 /dev/binderfs/binder
-    chmod 0666 /dev/binderfs/vndbinder
-
 # Run boringssl self test for each ABI so that later processes can skip it. http://b/139348610
 on early-init && property:ro.product.cpu.abilist32=*
     exec_start boringssl_self_test32
@@ -127,15 +114,6 @@
     symlink /proc/self/fd/1 /dev/stdout
     symlink /proc/self/fd/2 /dev/stderr
 
-    symlink /system/bin /bin
-    symlink /system/etc /etc
-
-    # Backward compatibility.
-    symlink /sys/kernel/debug /d
-
-    # Link /vendor to /system/vendor for devices without a vendor partition.
-    symlink /system/vendor /vendor
-
     # Create energy-aware scheduler tuning nodes
     mkdir /dev/stune/foreground
     mkdir /dev/stune/background
@@ -157,6 +135,14 @@
     chmod 0664 /dev/stune/top-app/tasks
     chmod 0664 /dev/stune/rt/tasks
 
+    # Create an stune group for NNAPI HAL processes
+    mkdir /dev/stune/nnapi-hal
+    chown system system /dev/stune/nnapi-hal
+    chown system system /dev/stune/nnapi-hal/tasks
+    chmod 0664 /dev/stune/nnapi-hal/tasks
+    write /dev/stune/nnapi-hal/schedtune.boost 1
+    write /dev/stune/nnapi-hal/schedtune.prefer_idle 1
+
     # Create blkio group and apply initial settings.
     # This feature needs kernel to support it, and the
     # device's init.rc must actually set the correct values.
@@ -178,6 +164,19 @@
     chmod 0770 /config/sdcardfs
     chown system package_info /config/sdcardfs
 
+    # Mount binderfs
+    mkdir /dev/binderfs
+    mount binder binder /dev/binderfs stats=global
+    chmod 0755 /dev/binderfs
+
+    symlink /dev/binderfs/binder /dev/binder
+    symlink /dev/binderfs/hwbinder /dev/hwbinder
+    symlink /dev/binderfs/vndbinder /dev/vndbinder
+
+    chmod 0666 /dev/binderfs/hwbinder
+    chmod 0666 /dev/binderfs/binder
+    chmod 0666 /dev/binderfs/vndbinder
+
     mkdir /mnt/secure 0700 root root
     mkdir /mnt/secure/asec 0700 root root
     mkdir /mnt/asec 0755 root system
@@ -191,10 +190,10 @@
 
     # Prepare directories for pass through processes
     mkdir /mnt/pass_through 0700 root root
-    mkdir /mnt/pass_through/0 0755 root root
-    mkdir /mnt/pass_through/0/self 0755 root root
-    mkdir /mnt/pass_through/0/emulated 0755 root root
-    mkdir /mnt/pass_through/0/emulated/0 0755 root root
+    mkdir /mnt/pass_through/0 0710 root media_rw
+    mkdir /mnt/pass_through/0/self 0710 root media_rw
+    mkdir /mnt/pass_through/0/emulated 0710 root media_rw
+    mkdir /mnt/pass_through/0/emulated/0 0710 root media_rw
 
     mkdir /mnt/expand 0771 system system
     mkdir /mnt/appfuse 0711 root root
@@ -211,7 +210,6 @@
     mkdir /mnt/runtime/full/self 0755 root root
 
     # Symlink to keep legacy apps working in multi-user world
-    symlink /storage/self/primary /sdcard
     symlink /storage/self/primary /mnt/sdcard
     symlink /mnt/user/0/primary /mnt/runtime/default/self/primary
 
@@ -613,6 +611,9 @@
     mkdir /data/misc/installd 0700 root root
     mkdir /data/misc/apexdata 0711 root root
     mkdir /data/misc/apexrollback 0700 root root
+    mkdir /data/misc/snapshotctl_log 0770 root root
+    # create location to store pre-reboot information
+    mkdir /data/misc/prereboot 0700 system system
 
     mkdir /data/preloads 0775 system system encryption=None
 
@@ -693,10 +694,6 @@
     mkdir /data/user/0 0700 system system encryption=None
     mount none /data/data /data/user/0 bind rec
 
-    # Special-case /data/media/obb per b/64566063
-    mkdir /data/media 0770 media_rw media_rw encryption=None
-    mkdir /data/media/obb 0770 media_rw media_rw encryption=Attempt
-
     # A tmpfs directory, which will contain all apps CE DE data directory that
     # bind mount from the original source.
     chown root root /data_mirror
@@ -734,10 +731,21 @@
     wait_for_prop apexd.status ready
     perform_apex_config
 
+    # Special-case /data/media/obb per b/64566063
+    mkdir /data/media 0770 media_rw media_rw encryption=None
+    exec - media_rw media_rw -- /system/bin/chattr +F /data/media
+    mkdir /data/media/obb 0770 media_rw media_rw encryption=Attempt
+
     exec_start derive_sdk
 
     init_user0
 
+    # Allow apexd to snapshot and restore device encrypted apex data in the case
+    # of a rollback. This should be done immediately after DE_user data keys
+    # are loaded. APEXes should not access this data until this has been
+    # completed.
+    exec_start apexd-snapshotde
+
     # Set SELinux security contexts on upgrade or policy update.
     restorecon --recursive --skip-ce /data
 
@@ -1025,6 +1033,7 @@
 on userspace-reboot-requested
   # TODO(b/135984674): reset all necessary properties here.
   setprop sys.boot_completed ""
+  setprop dev.bootcomplete ""
   setprop sys.init.updatable_crashing ""
   setprop sys.init.updatable_crashing_process_name ""
   setprop apexd.status ""
@@ -1050,4 +1059,4 @@
   trigger boot
 
 on property:sys.boot_completed=1 && property:sys.init.userspace_reboot.in_progress=1
-  finish_userspace_reboot
+  setprop sys.init.userspace_reboot.in_progress ""
diff --git a/rootdir/init.usb.rc b/rootdir/init.usb.rc
index 02d34ba..27b05ec 100644
--- a/rootdir/init.usb.rc
+++ b/rootdir/init.usb.rc
@@ -138,5 +138,4 @@
 
 on userspace-reboot-requested
   setprop sys.usb.config ""
-  setprop sys.usb.configfs ""
   setprop sys.usb.state ""