Merge changes I0ad349f2,I0f528cf1

* changes:
  fs_mgr: allow using legacy A/B suffix
  fs_mgr: adapt to new A/B support
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index 5ee07cd..325210d 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -77,7 +77,9 @@
     resetLogs();
     elf_set_fake_build_id("");
     siginfo_t si;
+    memset(&si, 0, sizeof(si));
     si.si_signo = SIGABRT;
+    si.si_code = SI_KERNEL;
     ptrace_set_fake_getsiginfo(si);
   }
 
@@ -292,7 +294,9 @@
   map_mock_->AddMap(map);
 
   siginfo_t si;
+  memset(&si, 0, sizeof(si));
   si.si_signo = SIGBUS;
+  si.si_code = SI_KERNEL;
   si.si_addr = reinterpret_cast<void*>(0x1000);
   ptrace_set_fake_getsiginfo(si);
   dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
@@ -348,7 +352,9 @@
   map_mock_->AddMap(map);
 
   siginfo_t si;
+  memset(&si, 0, sizeof(si));
   si.si_signo = SIGBUS;
+  si.si_code = SI_KERNEL;
   si.si_addr = reinterpret_cast<void*>(0xa533000);
   ptrace_set_fake_getsiginfo(si);
   dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
@@ -404,7 +410,9 @@
   map_mock_->AddMap(map);
 
   siginfo_t si;
+  memset(&si, 0, sizeof(si));
   si.si_signo = SIGBUS;
+  si.si_code = SI_KERNEL;
   si.si_addr = reinterpret_cast<void*>(0xa534040);
   ptrace_set_fake_getsiginfo(si);
   dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
@@ -458,7 +466,9 @@
   map_mock_->AddMap(map);
 
   siginfo_t si;
+  memset(&si, 0, sizeof(si));
   si.si_signo = SIGBUS;
+  si.si_code = SI_KERNEL;
 #if defined(__LP64__)
   si.si_addr = reinterpret_cast<void*>(0x12345a534040UL);
 #else
@@ -503,7 +513,7 @@
   map_mock_->AddMap(map);
 
   siginfo_t si;
-  si.si_signo = 0;
+  memset(&si, 0, sizeof(si));
   ptrace_set_fake_getsiginfo(si);
   dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
 
@@ -539,7 +549,9 @@
     ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
 
     siginfo_t si;
+    memset(&si, 0, sizeof(si));
     si.si_signo = i;
+    si.si_code = SI_KERNEL;
     si.si_addr = reinterpret_cast<void*>(0x1000);
     ptrace_set_fake_getsiginfo(si);
     dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
@@ -592,7 +604,7 @@
 
 TEST_F(TombstoneTest, dump_signal_info_error) {
   siginfo_t si;
-  si.si_signo = 0;
+  memset(&si, 0, sizeof(si));
   ptrace_set_fake_getsiginfo(si);
 
   dump_signal_info(&log_, 123);
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index c23da44..0c38449 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -283,7 +283,7 @@
     if (BacktraceMap::IsValid(map) && !map.name.empty()) {
       line += "  " + map.name;
       uintptr_t offset = 0;
-      std::string func_name(backtrace->GetFunctionName(stack_data[i], &offset));
+      std::string func_name(backtrace->GetFunctionName(stack_data[i], &offset, &map));
       if (!func_name.empty()) {
         line += " (" + func_name;
         if (offset) {
diff --git a/include/backtrace/Backtrace.h b/include/backtrace/Backtrace.h
index c896ab8..4f73a65 100644
--- a/include/backtrace/Backtrace.h
+++ b/include/backtrace/Backtrace.h
@@ -104,8 +104,10 @@
   virtual bool Unwind(size_t num_ignore_frames, ucontext_t* context = NULL) = 0;
 
   // Get the function name and offset into the function given the pc.
-  // If the string is empty, then no valid function name was found.
-  virtual std::string GetFunctionName(uintptr_t pc, uintptr_t* offset);
+  // If the string is empty, then no valid function name was found,
+  // or the pc is not in any valid map.
+  virtual std::string GetFunctionName(uintptr_t pc, uintptr_t* offset,
+                                      const backtrace_map_t* map = NULL);
 
   // Fill in the map data associated with the given pc.
   virtual void FillInMap(uintptr_t pc, backtrace_map_t* map);
diff --git a/include/backtrace/BacktraceMap.h b/include/backtrace/BacktraceMap.h
index df48dfe..8ab0dfa 100644
--- a/include/backtrace/BacktraceMap.h
+++ b/include/backtrace/BacktraceMap.h
@@ -33,6 +33,10 @@
 #include <string>
 #include <vector>
 
+// Special flag to indicate a map is in /dev/. However, a map in
+// /dev/ashmem/... does not set this flag.
+static constexpr int PROT_DEVICE_MAP = 0x8000;
+
 struct backtrace_map_t {
   uintptr_t start = 0;
   uintptr_t end = 0;
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index 0d2e11b..4354f0b 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -52,7 +52,16 @@
   }
 }
 
-std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) {
+std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset, const backtrace_map_t* map) {
+  backtrace_map_t map_value;
+  if (map == nullptr) {
+    FillInMap(pc, &map_value);
+    map = &map_value;
+  }
+  // If no map is found, or this map is backed by a device, then return nothing.
+  if (map->start == 0 || (map->flags & PROT_DEVICE_MAP)) {
+    return "";
+  }
   std::string func_name = GetFunctionNameRaw(pc, offset);
   return func_name;
 }
diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp
index 4862d9d..3c509e6 100644
--- a/libbacktrace/UnwindCurrent.cpp
+++ b/libbacktrace/UnwindCurrent.cpp
@@ -127,7 +127,7 @@
       if (num_ignore_frames == 0) {
         // GetFunctionName is an expensive call, only do it if we are
         // keeping the frame.
-        frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);
+        frame->func_name = GetFunctionName(frame->pc, &frame->func_offset, &frame->map);
         if (num_frames > 0) {
           // Set the stack size for the previous frame.
           backtrace_frame_data_t* prev = &frames_.at(num_frames-1);
@@ -143,6 +143,16 @@
         frames_.resize(0);
       }
     }
+    // If the pc is in a device map, then don't try to step.
+    if (frame->map.flags & PROT_DEVICE_MAP) {
+      break;
+    }
+    // Verify the sp is not in a device map too.
+    backtrace_map_t map;
+    FillInMap(frame->sp, &map);
+    if (map.flags & PROT_DEVICE_MAP) {
+      break;
+    }
     ret = unw_step (cursor.get());
   } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);
 
diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp
index 5c73bd6..42ac1bc 100644
--- a/libbacktrace/UnwindPtrace.cpp
+++ b/libbacktrace/UnwindPtrace.cpp
@@ -136,12 +136,28 @@
 
       FillInMap(frame->pc, &frame->map);
 
-      frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);
+      frame->func_name = GetFunctionName(frame->pc, &frame->func_offset, &frame->map);
 
       num_frames++;
+      // If the pc is in a device map, then don't try to step.
+      if (frame->map.flags & PROT_DEVICE_MAP) {
+        break;
+      }
     } else {
+      // If the pc is in a device map, then don't try to step.
+      backtrace_map_t map;
+      FillInMap(pc, &map);
+      if (map.flags & PROT_DEVICE_MAP) {
+        break;
+      }
       num_ignore_frames--;
     }
+    // Verify the sp is not in a device map.
+    backtrace_map_t map;
+    FillInMap(sp, &map);
+    if (map.flags & PROT_DEVICE_MAP) {
+      break;
+    }
     ret = unw_step (&cursor);
   } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);
 
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 9ca373a..24e48cd 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -42,6 +42,7 @@
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
 
+#include <android-base/macros.h>
 #include <android-base/stringprintf.h>
 #include <android-base/unique_fd.h>
 #include <cutils/atomic.h>
@@ -1436,6 +1437,171 @@
   FinishRemoteProcess(pid);
 }
 
+static void SetUcontextSp(uintptr_t sp, ucontext_t* ucontext) {
+#if defined(__arm__)
+  ucontext->uc_mcontext.arm_sp = sp;
+#elif defined(__aarch64__)
+  ucontext->uc_mcontext.sp = sp;
+#elif defined(__i386__)
+  ucontext->uc_mcontext.gregs[REG_ESP] = sp;
+#elif defined(__x86_64__)
+  ucontext->uc_mcontext.gregs[REG_RSP] = sp;
+#else
+  UNUSED(sp);
+  UNUSED(ucontext);
+  ASSERT_TRUE(false) << "Unsupported architecture";
+#endif
+}
+
+static void SetUcontextPc(uintptr_t pc, ucontext_t* ucontext) {
+#if defined(__arm__)
+  ucontext->uc_mcontext.arm_pc = pc;
+#elif defined(__aarch64__)
+  ucontext->uc_mcontext.pc = pc;
+#elif defined(__i386__)
+  ucontext->uc_mcontext.gregs[REG_EIP] = pc;
+#elif defined(__x86_64__)
+  ucontext->uc_mcontext.gregs[REG_RIP] = pc;
+#else
+  UNUSED(pc);
+  UNUSED(ucontext);
+  ASSERT_TRUE(false) << "Unsupported architecture";
+#endif
+}
+
+static void SetUcontextLr(uintptr_t lr, ucontext_t* ucontext) {
+#if defined(__arm__)
+  ucontext->uc_mcontext.arm_lr = lr;
+#elif defined(__aarch64__)
+  ucontext->uc_mcontext.regs[30] = lr;
+#elif defined(__i386__)
+  // The lr is on the stack.
+  ASSERT_TRUE(lr != 0);
+  ASSERT_TRUE(ucontext != nullptr);
+#elif defined(__x86_64__)
+  // The lr is on the stack.
+  ASSERT_TRUE(lr != 0);
+  ASSERT_TRUE(ucontext != nullptr);
+#else
+  UNUSED(lr);
+  UNUSED(ucontext);
+  ASSERT_TRUE(false) << "Unsupported architecture";
+#endif
+}
+
+static constexpr size_t DEVICE_MAP_SIZE = 1024;
+
+static void SetupDeviceMap(void** device_map) {
+  // Make sure that anything in a device map will result in fails
+  // to read.
+  android::base::unique_fd device_fd(open("/dev/zero", O_RDONLY | O_CLOEXEC));
+
+  *device_map = mmap(nullptr, 1024, PROT_READ, MAP_PRIVATE, device_fd, 0);
+  ASSERT_TRUE(*device_map != MAP_FAILED);
+
+  // Make sure the map is readable.
+  ASSERT_EQ(0, reinterpret_cast<int*>(*device_map)[0]);
+}
+
+static void UnwindFromDevice(Backtrace* backtrace, void* device_map) {
+  uintptr_t device_map_uint = reinterpret_cast<uintptr_t>(device_map);
+
+  backtrace_map_t map;
+  backtrace->FillInMap(device_map_uint, &map);
+  // Verify the flag is set.
+  ASSERT_EQ(PROT_DEVICE_MAP, map.flags & PROT_DEVICE_MAP);
+
+  // Quick sanity checks.
+  size_t offset;
+  ASSERT_EQ(std::string(""), backtrace->GetFunctionName(device_map_uint, &offset));
+  ASSERT_EQ(std::string(""), backtrace->GetFunctionName(device_map_uint, &offset, &map));
+  ASSERT_EQ(std::string(""), backtrace->GetFunctionName(0, &offset));
+
+  uintptr_t cur_func_offset = reinterpret_cast<uintptr_t>(&test_level_one) + 1;
+  // Now verify the device map flag actually causes the function name to be empty.
+  backtrace->FillInMap(cur_func_offset, &map);
+  ASSERT_TRUE((map.flags & PROT_DEVICE_MAP) == 0);
+  ASSERT_NE(std::string(""), backtrace->GetFunctionName(cur_func_offset, &offset, &map));
+  map.flags |= PROT_DEVICE_MAP;
+  ASSERT_EQ(std::string(""), backtrace->GetFunctionName(cur_func_offset, &offset, &map));
+
+  ucontext_t ucontext;
+
+  // Create a context that has the pc in the device map, but the sp
+  // in a non-device map.
+  memset(&ucontext, 0, sizeof(ucontext));
+  SetUcontextSp(reinterpret_cast<uintptr_t>(&ucontext), &ucontext);
+  SetUcontextPc(device_map_uint, &ucontext);
+  SetUcontextLr(cur_func_offset, &ucontext);
+
+  ASSERT_TRUE(backtrace->Unwind(0, &ucontext));
+
+  // The buffer should only be a single element.
+  ASSERT_EQ(1U, backtrace->NumFrames());
+  const backtrace_frame_data_t* frame = backtrace->GetFrame(0);
+  ASSERT_EQ(device_map_uint, frame->pc);
+  ASSERT_EQ(reinterpret_cast<uintptr_t>(&ucontext), frame->sp);
+
+  // Check what happens when skipping the first frame.
+  ASSERT_TRUE(backtrace->Unwind(1, &ucontext));
+  ASSERT_EQ(0U, backtrace->NumFrames());
+
+  // Create a context that has the sp in the device map, but the pc
+  // in a non-device map.
+  memset(&ucontext, 0, sizeof(ucontext));
+  SetUcontextSp(device_map_uint, &ucontext);
+  SetUcontextPc(cur_func_offset, &ucontext);
+  SetUcontextLr(cur_func_offset, &ucontext);
+
+  ASSERT_TRUE(backtrace->Unwind(0, &ucontext));
+
+  // The buffer should only be a single element.
+  ASSERT_EQ(1U, backtrace->NumFrames());
+  frame = backtrace->GetFrame(0);
+  ASSERT_EQ(cur_func_offset, frame->pc);
+  ASSERT_EQ(device_map_uint, frame->sp);
+
+  // Check what happens when skipping the first frame.
+  ASSERT_TRUE(backtrace->Unwind(1, &ucontext));
+  ASSERT_EQ(0U, backtrace->NumFrames());
+}
+
+TEST(libbacktrace, unwind_disallow_device_map_local) {
+  void* device_map;
+  SetupDeviceMap(&device_map);
+
+  // Now create an unwind object.
+  std::unique_ptr<Backtrace> backtrace(
+      Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
+  ASSERT_TRUE(backtrace);
+
+  UnwindFromDevice(backtrace.get(), device_map);
+
+  munmap(device_map, DEVICE_MAP_SIZE);
+}
+
+TEST(libbacktrace, unwind_disallow_device_map_remote) {
+  void* device_map;
+  SetupDeviceMap(&device_map);
+
+  // Fork a process to do a remote backtrace.
+  pid_t pid;
+  CreateRemoteProcess(&pid);
+
+  // Now create an unwind object.
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, pid));
+
+  // TODO: Currently unwind from context doesn't work on remote
+  // unwind. Keep this test because the new unwinder should support
+  // this eventually, or we can delete this test.
+  // properly with unwind from context.
+  // UnwindFromDevice(backtrace.get(), device_map);
+
+  FinishRemoteProcess(pid);
+
+  munmap(device_map, DEVICE_MAP_SIZE);
+}
+
 #if defined(ENABLE_PSS_TESTS)
 #include "GetPss.h"
 
diff --git a/logwrapper/Android.bp b/logwrapper/Android.bp
index 7ee0464..ccb1aa6 100644
--- a/logwrapper/Android.bp
+++ b/logwrapper/Android.bp
@@ -32,3 +32,22 @@
         "-Werror",
     ],
 }
+
+// ========================================================
+// Benchmark
+// ========================================================
+cc_benchmark {
+    name: "android_fork_execvp_ext_benchmark",
+    srcs: [
+        "android_fork_execvp_ext_benchmark.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "liblog",
+        "liblogwrap",
+    ],
+    cflags: [
+        "-Werror",
+    ]
+}
diff --git a/logwrapper/android_fork_execvp_ext_benchmark.cpp b/logwrapper/android_fork_execvp_ext_benchmark.cpp
new file mode 100644
index 0000000..1abd932
--- /dev/null
+++ b/logwrapper/android_fork_execvp_ext_benchmark.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "logwrap/logwrap.h"
+
+#include <android-base/logging.h>
+#include <benchmark/benchmark.h>
+
+static void BM_android_fork_execvp_ext(benchmark::State& state) {
+    const char* argv[] = {"/system/bin/echo", "hello", "world"};
+    const int argc = 3;
+    while (state.KeepRunning()) {
+        int rc = android_fork_execvp_ext(
+            argc, (char**)argv, NULL /* status */, false /* ignore_int_quit */, LOG_NONE,
+            false /* abbreviated */, NULL /* file_path */, NULL /* opts */, 0 /* opts_len */);
+        CHECK_EQ(0, rc);
+    }
+}
+BENCHMARK(BM_android_fork_execvp_ext);
+
+BENCHMARK_MAIN();
diff --git a/logwrapper/include/logwrap/logwrap.h b/logwrapper/include/logwrap/logwrap.h
index 89a8fdd..d3538b3 100644
--- a/logwrapper/include/logwrap/logwrap.h
+++ b/logwrapper/include/logwrap/logwrap.h
@@ -54,9 +54,8 @@
  *           the specified log until the child has exited.
  *   file_path: if log_target has the LOG_FILE bit set, then this parameter
  *           must be set to the pathname of the file to log to.
- *   opts: set to non-NULL if you want to use one or more of the
- *           FORK_EXECVP_OPTION_* features.
- *   opts_len: the length of the opts array. When opts is NULL, pass 0.
+ *   unused_opts: currently unused.
+ *   unused_opts_len: currently unused.
  *
  * Return value:
  *   0 when logwrap successfully run the child process and captured its status
@@ -72,30 +71,10 @@
 #define LOG_KLOG        2
 #define LOG_FILE        4
 
-/* Write data to child's stdin. */
-#define FORK_EXECVP_OPTION_INPUT             0
-/* Capture data from child's stdout and stderr. */
-#define FORK_EXECVP_OPTION_CAPTURE_OUTPUT    1
-
-struct AndroidForkExecvpOption {
-    int opt_type;
-    union {
-        struct {
-            const uint8_t* input;
-            size_t input_len;
-        } opt_input;
-        struct {
-            void (*on_output)(const uint8_t* /*output*/,
-                              size_t /*output_len*/,
-                              void* /* user_pointer */);
-            void* user_pointer;
-        } opt_capture_output;
-    };
-};
-
+// TODO: Remove unused_opts / unused_opts_len in a followup change.
 int android_fork_execvp_ext(int argc, char* argv[], int *status, bool ignore_int_quit,
-        int log_target, bool abbreviated, char *file_path,
-        const struct AndroidForkExecvpOption* opts, size_t opts_len);
+        int log_target, bool abbreviated, char *file_path, void* unused_opts,
+        int unused_opts_len);
 
 /* Similar to above, except abbreviated logging is not available, and if logwrap
  * is true, logging is to the Android system log, and if false, there is no
diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c
index 3ad0983..7076078 100644
--- a/logwrapper/logwrap.c
+++ b/logwrapper/logwrap.c
@@ -291,8 +291,7 @@
 }
 
 static int parent(const char *tag, int parent_read, pid_t pid,
-        int *chld_sts, int log_target, bool abbreviated, char *file_path,
-        const struct AndroidForkExecvpOption* opts, size_t opts_len) {
+        int *chld_sts, int log_target, bool abbreviated, char *file_path) {
     int status = 0;
     char buffer[4096];
     struct pollfd poll_fds[] = {
@@ -359,13 +358,6 @@
             sz = TEMP_FAILURE_RETRY(
                 read(parent_read, &buffer[b], sizeof(buffer) - 1 - b));
 
-            for (size_t i = 0; sz > 0 && i < opts_len; ++i) {
-                if (opts[i].opt_type == FORK_EXECVP_OPTION_CAPTURE_OUTPUT) {
-                  opts[i].opt_capture_output.on_output(
-                      (uint8_t*)&buffer[b], sz, opts[i].opt_capture_output.user_pointer);
-                }
-            }
-
             sz += b;
             // Log one line at a time
             for (b = 0; b < sz; b++) {
@@ -483,7 +475,7 @@
 
 int android_fork_execvp_ext(int argc, char* argv[], int *status, bool ignore_int_quit,
         int log_target, bool abbreviated, char *file_path,
-        const struct AndroidForkExecvpOption* opts, size_t opts_len) {
+        void *unused_opts, int unused_opts_len) {
     pid_t pid;
     int parent_ptty;
     int child_ptty;
@@ -493,6 +485,9 @@
     sigset_t oldset;
     int rc = 0;
 
+    LOG_ALWAYS_FATAL_IF(unused_opts != NULL);
+    LOG_ALWAYS_FATAL_IF(unused_opts_len != 0);
+
     rc = pthread_mutex_lock(&fd_mutex);
     if (rc) {
         ERROR("failed to lock signal_fd mutex\n");
@@ -538,13 +533,6 @@
         pthread_sigmask(SIG_SETMASK, &oldset, NULL);
         close(parent_ptty);
 
-        // redirect stdin, stdout and stderr
-        for (size_t i = 0; i < opts_len; ++i) {
-            if (opts[i].opt_type == FORK_EXECVP_OPTION_INPUT) {
-                dup2(child_ptty, 0);
-                break;
-            }
-        }
         dup2(child_ptty, 1);
         dup2(child_ptty, 2);
         close(child_ptty);
@@ -561,24 +549,8 @@
             sigaction(SIGQUIT, &ignact, &quitact);
         }
 
-        for (size_t i = 0; i < opts_len; ++i) {
-            if (opts[i].opt_type == FORK_EXECVP_OPTION_INPUT) {
-                size_t left = opts[i].opt_input.input_len;
-                const uint8_t* input = opts[i].opt_input.input;
-                while (left > 0) {
-                    ssize_t res =
-                        TEMP_FAILURE_RETRY(write(parent_ptty, input, left));
-                    if (res < 0) {
-                        break;
-                    }
-                    left -= res;
-                    input += res;
-                }
-            }
-        }
-
         rc = parent(argv[0], parent_ptty, pid, status, log_target,
-                    abbreviated, file_path, opts, opts_len);
+                    abbreviated, file_path);
     }
 
     if (ignore_int_quit) {
diff --git a/rootdir/init.rc b/rootdir/init.rc
index dcb3b25..06dc88b 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -346,6 +346,9 @@
     # create the lost+found directories, so as to enforce our permissions
     mkdir /cache/lost+found 0770 root root
 
+on late-fs
+    start hwservicemanager
+
 on post-fs-data
     # We chown/chmod /data again so because mount is run as root + defaults
     chown system system /data
@@ -586,8 +589,9 @@
     # Define default initial receive window size in segments.
     setprop net.tcp.default_init_rwnd 60
 
-    # Start all binderized HAL daemons
-    start hwservicemanager
+    # Start standard binderized HAL daemons
+    class_start hal
+
     class_start core
 
 on nonencrypted