AU: Execute postinst asynchronously so that the D-Bus service is not blocked.
This CL also cleans up Subprocess memory handling a bit and extends it to
capture the output of asynchronous subprocesses. Also adds a scoped temp mount
unmounter utility class.
BUG=8937
TEST=unit tests, tested on the device -- making sure no D-Bus calls timeou
during postinstall.
Change-Id: I219dda3dc98d875ff05050f1a32ffcc925db1d53
Review URL: http://codereview.chromium.org/4690006
diff --git a/postinstall_runner_action.cc b/postinstall_runner_action.cc
index 9a84563..c6320e1 100644
--- a/postinstall_runner_action.cc
+++ b/postinstall_runner_action.cc
@@ -15,7 +15,7 @@
using std::vector;
namespace {
-const string kPostinstallScript("/postinst");
+const char kPostinstallScript[] = "/postinst";
}
void PostinstallRunnerAction::PerformAction() {
@@ -24,53 +24,61 @@
const string install_device = install_plan.install_path;
ScopedActionCompleter completer(processor_, this);
- // Make mountpoint
- string temp_dir;
+ // Make mountpoint.
TEST_AND_RETURN(utils::MakeTempDirectory("/tmp/au_postint_mount.XXXXXX",
- &temp_dir));
- ScopedDirRemover temp_dir_remover(temp_dir);
+ &temp_rootfs_dir_));
+ ScopedDirRemover temp_dir_remover(temp_rootfs_dir_);
- {
- // Scope for the mount
- unsigned long mountflags = MS_RDONLY;
-
- int rc = mount(install_device.c_str(),
- temp_dir.c_str(),
- "ext4",
- mountflags,
- NULL);
- if (rc < 0) {
- LOG(INFO) << "Failed to mount install part as ext4. Trying ext3.";
- rc = mount(install_device.c_str(),
- temp_dir.c_str(),
- "ext3",
+ unsigned long mountflags = MS_RDONLY;
+ int rc = mount(install_device.c_str(),
+ temp_rootfs_dir_.c_str(),
+ "ext4",
mountflags,
NULL);
- }
- if (rc < 0) {
- LOG(ERROR) << "Unable to mount destination device " << install_device
- << " onto " << temp_dir;
- return;
- }
- ScopedFilesystemUnmounter unmounter(temp_dir);
-
- // run postinstall script
- vector<string> command;
- command.push_back(temp_dir + kPostinstallScript);
- command.push_back(install_device);
- rc = 0;
- TEST_AND_RETURN(Subprocess::SynchronousExec(command, &rc));
- bool success = (rc == 0);
- if (!success) {
- LOG(ERROR) << "Postinst command failed with code: " << rc;
- return;
- }
+ if (rc < 0) {
+ LOG(INFO) << "Failed to mount install part as ext4. Trying ext3.";
+ rc = mount(install_device.c_str(),
+ temp_rootfs_dir_.c_str(),
+ "ext3",
+ mountflags,
+ NULL);
+ }
+ if (rc < 0) {
+ LOG(ERROR) << "Unable to mount destination device " << install_device
+ << " onto " << temp_rootfs_dir_;
+ return;
}
+ temp_dir_remover.set_should_remove(false);
+ completer.set_should_complete(false);
+
+ // Runs the postinstall script asynchronously to free up the main loop while
+ // it's running.
+ vector<string> command;
+ command.push_back(temp_rootfs_dir_ + kPostinstallScript);
+ command.push_back(install_device);
+ Subprocess::Get().Exec(command, StaticCompletePostinstall, this);
+}
+
+void PostinstallRunnerAction::CompletePostinstall(int return_code) {
+ ScopedActionCompleter completer(processor_, this);
+ ScopedTempUnmounter temp_unmounter(temp_rootfs_dir_);
+ if (return_code != 0) {
+ LOG(ERROR) << "Postinst command failed with code: " << return_code;
+ return;
+ }
if (HasOutputPipe()) {
- SetOutputObject(install_plan);
+ CHECK(HasInputObject());
+ SetOutputObject(GetInputObject());
}
completer.set_code(kActionCodeSuccess);
}
+void PostinstallRunnerAction::StaticCompletePostinstall(int return_code,
+ const string& output,
+ void* p) {
+ reinterpret_cast<PostinstallRunnerAction*>(p)->CompletePostinstall(
+ return_code);
+}
+
} // namespace chromeos_update_engine