Merge "Implements 'adb bugreport <ZIP_FILE>'." into nyc-dev
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index bc072bc..70acd38 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -626,11 +626,18 @@
             }
             encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
         } else {
-            ERROR("Failed to mount an un-encryptable or wiped partition on"
-                   "%s at %s options: %s error: %s\n",
-                   fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
-                   fstab->recs[attempted_idx].fs_options, strerror(mount_errno));
-            ++error_count;
+            if (fs_mgr_is_nofail(&fstab->recs[attempted_idx])) {
+                ERROR("Ignoring failure to mount an un-encryptable or wiped partition on"
+                       "%s at %s options: %s error: %s\n",
+                       fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
+                       fstab->recs[attempted_idx].fs_options, strerror(mount_errno));
+            } else {
+                ERROR("Failed to mount an un-encryptable or wiped partition on"
+                       "%s at %s options: %s error: %s\n",
+                       fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
+                       fstab->recs[attempted_idx].fs_options, strerror(mount_errno));
+                ++error_count;
+            }
             continue;
         }
     }
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index c8c624d..6d44e06 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -76,6 +76,7 @@
     { "notrim",       MF_NOTRIM },
     { "formattable", MF_FORMATTABLE },
     { "slotselect",  MF_SLOTSELECT },
+    { "nofail",      MF_NOFAIL },
     { "defaults",    0 },
     { 0,             0 },
 };
@@ -502,3 +503,8 @@
 {
     return fstab->fs_mgr_flags & MF_SLOTSELECT;
 }
+
+int fs_mgr_is_nofail(struct fstab_rec *fstab)
+{
+    return fstab->fs_mgr_flags & MF_NOFAIL;
+}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 181b6cd..46975f1 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -83,6 +83,7 @@
 #define MF_FORMATTABLE  0x4000
 #define MF_SLOTSELECT   0x8000
 #define MF_FORCEFDEORFBE 0x10000
+#define MF_NOFAIL       0x40000
 
 #define DM_BUF_SIZE 4096
 
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 0404dbd..6f4580e 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -106,6 +106,7 @@
 int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab);
 int fs_mgr_is_notrim(struct fstab_rec *fstab);
 int fs_mgr_is_formattable(struct fstab_rec *fstab);
+int fs_mgr_is_nofail(struct fstab_rec *fstab);
 int fs_mgr_swapon_all(struct fstab *fstab);
 
 int fs_mgr_do_format(struct fstab_rec *fstab);
diff --git a/init/init.cpp b/init/init.cpp
index 0ff55a5..84da2b9 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -141,59 +141,19 @@
             });
 }
 
-static void msg_start(const std::string& name)
-{
-    Service* svc = nullptr;
-    std::vector<std::string> vargs;
-
-    size_t colon_pos = name.find(':');
-    if (colon_pos == std::string::npos) {
-        svc = ServiceManager::GetInstance().FindServiceByName(name);
-    } else {
-        std::string service_name(name.substr(0, colon_pos));
-        std::string args(name.substr(colon_pos + 1));
-        vargs = android::base::Split(args, " ");
-
-        svc = ServiceManager::GetInstance().FindServiceByName(service_name);
-    }
-
-    if (svc) {
-        svc->Start(vargs);
-    } else {
-        ERROR("no such service '%s'\n", name.c_str());
-    }
-}
-
-static void msg_stop(const std::string& name)
-{
+void handle_control_message(const std::string& msg, const std::string& name) {
     Service* svc = ServiceManager::GetInstance().FindServiceByName(name);
-
-    if (svc) {
-        svc->Stop();
-    } else {
+    if (svc == nullptr) {
         ERROR("no such service '%s'\n", name.c_str());
+        return;
     }
-}
 
-static void msg_restart(const std::string& name)
-{
-    Service* svc = ServiceManager::GetInstance().FindServiceByName(name);
-
-    if (svc) {
-        svc->Restart();
-    } else {
-        ERROR("no such service '%s'\n", name.c_str());
-    }
-}
-
-void handle_control_message(const std::string& msg, const std::string& arg)
-{
     if (msg == "start") {
-        msg_start(arg);
+        svc->Start();
     } else if (msg == "stop") {
-        msg_stop(arg);
+        svc->Stop();
     } else if (msg == "restart") {
-        msg_restart(arg);
+        svc->Restart();
     } else {
         ERROR("unknown control msg '%s'\n", msg.c_str());
     }
diff --git a/init/service.cpp b/init/service.cpp
index bdecc32..f1ffa18 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -315,7 +315,7 @@
     return (this->*handler)(args, err);
 }
 
-bool Service::Start(const std::vector<std::string>& dynamic_args) {
+bool Service::Start() {
     // Starting a service removes it from the disabled or reset state and
     // immediately takes it out of the restarting state if it was in there.
     flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
@@ -343,13 +343,6 @@
         return false;
     }
 
-    if ((!(flags_ & SVC_ONESHOT)) && !dynamic_args.empty()) {
-        ERROR("service '%s' must be one-shot to use dynamic args, disabling\n",
-              args_[0].c_str());
-        flags_ |= SVC_DISABLED;
-        return false;
-    }
-
     std::string scon;
     if (!seclabel_.empty()) {
         scon = seclabel_;
@@ -471,9 +464,6 @@
         for (const auto& s : args_) {
             strs.push_back(const_cast<char*>(s.c_str()));
         }
-        for (const auto& s : dynamic_args) {
-            strs.push_back(const_cast<char*>(s.c_str()));
-        }
         strs.push_back(nullptr);
         if (execve(args_[0].c_str(), (char**) &strs[0], (char**) ENV) < 0) {
             ERROR("cannot execve('%s'): %s\n", args_[0].c_str(), strerror(errno));
@@ -502,11 +492,6 @@
     return true;
 }
 
-bool Service::Start() {
-    const std::vector<std::string> null_dynamic_args;
-    return Start(null_dynamic_args);
-}
-
 bool Service::StartIfNotDisabled() {
     if (!(flags_ & SVC_DISABLED)) {
         return Start();
diff --git a/init/service.h b/init/service.h
index 35abde9..d9d18ef 100644
--- a/init/service.h
+++ b/init/service.h
@@ -76,7 +76,6 @@
             const std::string& seclabel,  const std::vector<std::string>& args);
 
     bool HandleLine(const std::vector<std::string>& args, std::string* err);
-    bool Start(const std::vector<std::string>& dynamic_args);
     bool Start();
     bool StartIfNotDisabled();
     bool Enable();
diff --git a/rootdir/init.rc b/rootdir/init.rc
index a95eaa2..3e2f0a5 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -87,6 +87,7 @@
 
     # 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
 
     # root memory control cgroup, used by lmkd