dbus API UnmountComponent

UnmountComponent takes a component name and unmount all mount points of
this component.

The user of this API is component updater and the API does exactly what
caller wants.

BUG=chromium:781992
TEST=unmount a component on device successfully. an autotest will be
added to cover this API.

Change-Id: Ie4238e4a361608fb92086b966a6f1b70f0855b93
Reviewed-on: https://chromium-review.googlesource.com/791858
Commit-Ready: Xiaochu Liu <xiaochu@chromium.org>
Tested-by: Xiaochu Liu <xiaochu@chromium.org>
Reviewed-by: Greg Kerr <kerrnel@chromium.org>
diff --git a/dbus_adaptors/org.chromium.ImageLoaderInterface.xml b/dbus_adaptors/org.chromium.ImageLoaderInterface.xml
index b8a2a63..0bd9d04 100644
--- a/dbus_adaptors/org.chromium.ImageLoaderInterface.xml
+++ b/dbus_adaptors/org.chromium.ImageLoaderInterface.xml
@@ -117,5 +117,20 @@
       </tp:docstring>
     </arg>
   </method>
+  <method name="UnmountComponent">
+    <tp:docstring>
+      Unmount all mount points of a component.
+    </tp:docstring>
+    <arg name="name" type="s" direction="in">
+      <tp:docstring>
+        The name of the component.
+      </tp:docstring>
+    </arg>
+    <arg name="success" type="b" direction="out">
+      <tp:docstring>
+        The result of the component unmount (success or failure).
+      </tp:docstring>
+    </arg>
+  </method>
 </interface>
 </node>
diff --git a/dbus_permissions/org.chromium.ImageLoader.conf b/dbus_permissions/org.chromium.ImageLoader.conf
index 9bc9484..e4ee27a 100644
--- a/dbus_permissions/org.chromium.ImageLoader.conf
+++ b/dbus_permissions/org.chromium.ImageLoader.conf
@@ -31,6 +31,9 @@
     <allow send_destination="org.chromium.ImageLoader"
       send_interface="org.chromium.ImageLoaderInterface"
       send_member="RemoveComponent" />
+    <allow send_destination="org.chromium.ImageLoader"
+      send_interface="org.chromium.ImageLoaderInterface"
+      send_member="UnmountComponent" />
   </policy>
   <policy context="default">
     <deny send_destination="org.chromium.ImageLoader"/>
diff --git a/helper_process.cc b/helper_process.cc
index de107fd..f36d4db 100644
--- a/helper_process.cc
+++ b/helper_process.cc
@@ -124,9 +124,11 @@
   std::unique_ptr<CommandResponse> response = SendCommand(image_command, &msg);
 
   // 3. Process return value.
-  for (int i = 0; i < response->paths_size(); i++) {
-    std::string path(response->paths(i));
-    paths->push_back(path);
+  if (paths) {
+    for (int i = 0; i < response->paths_size(); i++) {
+      std::string path(response->paths(i));
+      paths->push_back(path);
+    }
   }
   return response->success();
 }
diff --git a/imageloader.cc b/imageloader.cc
index 6a53c38..5e955e6 100644
--- a/imageloader.cc
+++ b/imageloader.cc
@@ -24,6 +24,7 @@
 const char ImageLoader::kImageLoaderGroupName[] = "imageloaderd";
 const char ImageLoader::kImageLoaderUserName[] = "imageloaderd";
 const int ImageLoader::kShutdownTimeoutMilliseconds = 20000;
+const char ImageLoader::kLoadedMountsBase[] = "/run/imageloader";
 
 ImageLoader::ImageLoader(ImageLoaderConfig config,
                          std::unique_ptr<HelperProcess> process)
@@ -144,4 +145,16 @@
   return true;
 }
 
+bool ImageLoader::UnmountComponent(
+    brillo::ErrorPtr* err,
+    const std::string& name,
+    bool* out_success) {
+  base::FilePath component_mount_root =
+      base::FilePath(imageloader::ImageLoader::kLoadedMountsBase).Append(name);
+  *out_success = impl_.CleanupAll(
+      false, component_mount_root, nullptr, helper_process_.get());
+  PostponeShutdown();
+  return true;
+}
+
 }  // namespace imageloader
diff --git a/imageloader.h b/imageloader.h
index df53c07..f24801d 100644
--- a/imageloader.h
+++ b/imageloader.h
@@ -31,6 +31,8 @@
   static const char kImageLoaderGroupName[];
   static const char kImageLoaderUserName[];
 
+  static const char kLoadedMountsBase[];
+
   ImageLoader(ImageLoaderConfig config, std::unique_ptr<HelperProcess> helper);
   ~ImageLoader();
 
@@ -57,14 +59,20 @@
                            const std::string& component_folder_abs_path,
                            std::string* out_mount_point) override;
 
+  // Remove a component given component |name|.
   bool RemoveComponent(brillo::ErrorPtr* err, const std::string& name,
                        bool* out_success) override;
 
+  // Get component metadata given component |name|.
   bool GetComponentMetadata(
       brillo::ErrorPtr* err,
       const std::string& name,
       std::map<std::string, std::string>* out_metadata) override;
 
+  // Unmount all mount points given component |name|.
+  bool UnmountComponent(brillo::ErrorPtr* err, const std::string& name,
+                        bool* out_success) override;
+
   // Sandboxes the runtime environment, using minijail. This is publicly exposed
   // so that imageloader_main.cc can sandbox when not running as a daemon.
   static void EnterSandbox();
diff --git a/imageloader_main.cc b/imageloader_main.cc
index d72c99c..2cd07f0 100644
--- a/imageloader_main.cc
+++ b/imageloader_main.cc
@@ -67,7 +67,7 @@
   DEFINE_string(mount_point, "",
                 "Specifies the mountpoint when using either --mount or "
                 "--unmount.");
-  DEFINE_string(loaded_mounts_base, "/run/imageloader",
+  DEFINE_string(loaded_mounts_base, imageloader::ImageLoader::kLoadedMountsBase,
                 "Base path where components are mounted (unless --mount_point "
                 "is used).");
   DEFINE_int32(mount_helper_fd, -1,