AU: Provide a reboot_if_needed D-Bus API.
This will reboot if the current state is UPDATED_REBOOT_NEEDED.
Also add -reboot option to the update_engine_client.
BUG=4250
TEST=unit tests,gmerged on device and tried reboot requests
Review URL: http://codereview.chromium.org/3034026
diff --git a/UpdateEngine.conf b/UpdateEngine.conf
index 05f0056..94aa5a5 100644
--- a/UpdateEngine.conf
+++ b/UpdateEngine.conf
@@ -22,6 +22,9 @@
<allow send_destination="org.chromium.UpdateEngine"
send_interface="org.chromium.UpdateEngineInterface"
send_member="GetStatus"/>
+ <allow send_destination="org.chromium.UpdateEngine"
+ send_interface="org.chromium.UpdateEngineInterface"
+ send_member="RebootIfNeeded"/>
</policy>
<policy context="default">
<deny send_destination="org.chromium.UpdateEngine" />
diff --git a/dbus_service.cc b/dbus_service.cc
index 54dde41..4a05160 100644
--- a/dbus_service.cc
+++ b/dbus_service.cc
@@ -47,6 +47,24 @@
g_object_new(UPDATE_ENGINE_TYPE_SERVICE, NULL));
}
+gboolean update_engine_service_attempt_update(UpdateEngineService* self,
+ gchar* app_version,
+ gchar* omaha_url,
+ GError **error) {
+ const string update_app_version = app_version ? app_version : "";
+ const string update_omaha_url = omaha_url ? omaha_url : "";
+ LOG(INFO) << "Attempt update: app_version=\"" << update_app_version << "\" "
+ << "omaha_url=\"" << update_omaha_url << "\"";
+ self->update_attempter_->CheckForUpdate(app_version, omaha_url);
+ return TRUE;
+}
+
+gboolean update_engine_service_check_for_update(UpdateEngineService* self,
+ GError **error) {
+ self->update_attempter_->CheckForUpdate("", "");
+ return TRUE;
+}
+
gboolean update_engine_service_get_status(UpdateEngineService* self,
int64_t* last_checked_time,
double* progress,
@@ -68,21 +86,12 @@
return TRUE;
}
-gboolean update_engine_service_attempt_update(UpdateEngineService* self,
- gchar* app_version,
- gchar* omaha_url,
- GError **error) {
- const string update_app_version = app_version ? app_version : "";
- const string update_omaha_url = omaha_url ? omaha_url : "";
- LOG(INFO) << "Attempt update: app_version=\"" << update_app_version << "\" "
- << "omaha_url=\"" << update_omaha_url << "\"";
- self->update_attempter_->CheckForUpdate(app_version, omaha_url);
- return TRUE;
-}
-
-gboolean update_engine_service_check_for_update(UpdateEngineService* self,
+gboolean update_engine_service_reboot_if_needed(UpdateEngineService* self,
GError **error) {
- self->update_attempter_->CheckForUpdate("", "");
+ if (!self->update_attempter_->RebootIfNeeded()) {
+ *error = NULL;
+ return FALSE;
+ }
return TRUE;
}
diff --git a/dbus_service.h b/dbus_service.h
index 4b760ce..12c9ed1 100644
--- a/dbus_service.h
+++ b/dbus_service.h
@@ -46,6 +46,14 @@
// Methods
+gboolean update_engine_service_attempt_update(UpdateEngineService* self,
+ gchar* app_version,
+ gchar* omaha_url,
+ GError **error);
+
+gboolean update_engine_service_check_for_update(UpdateEngineService* self,
+ GError **error);
+
gboolean update_engine_service_get_status(UpdateEngineService* self,
int64_t* last_checked_time,
double* progress,
@@ -54,14 +62,9 @@
int64_t* new_size,
GError **error);
-gboolean update_engine_service_check_for_update(UpdateEngineService* self,
+gboolean update_engine_service_reboot_if_needed(UpdateEngineService* self,
GError **error);
-gboolean update_engine_service_attempt_update(UpdateEngineService* self,
- gchar* app_version,
- gchar* omaha_url,
- GError **error);
-
gboolean update_engine_service_emit_status_update(
UpdateEngineService* self,
gint64 last_checked_time,
diff --git a/update_attempter.cc b/update_attempter.cc
index 014f822..939e074 100644
--- a/update_attempter.cc
+++ b/update_attempter.cc
@@ -221,6 +221,16 @@
Update(app_version, omaha_url);
}
+bool UpdateAttempter::RebootIfNeeded() {
+ if (status_ != UPDATE_STATUS_UPDATED_NEED_REBOOT) {
+ LOG(INFO) << "Reboot requested, but status is "
+ << UpdateStatusToString(status_) << ", so not rebooting.";
+ return false;
+ }
+ TEST_AND_RETURN_FALSE(utils::Reboot());
+ return true;
+}
+
// Delegate methods:
void UpdateAttempter::ProcessingDone(const ActionProcessor* processor,
ActionExitCode code) {
diff --git a/update_attempter.h b/update_attempter.h
index 3e47969..cd7f480 100644
--- a/update_attempter.h
+++ b/update_attempter.h
@@ -86,6 +86,10 @@
void CheckForUpdate(const std::string& app_version,
const std::string& omaha_url);
+ // Initiates a reboot if the current state is
+ // UPDATED_NEED_REBOOT. Returns true on sucess, false otherwise.
+ bool RebootIfNeeded();
+
// DownloadActionDelegate method
void BytesReceived(uint64_t bytes_received, uint64_t total);
diff --git a/update_engine.xml b/update_engine.xml
index 9cd9d42..5f20751 100644
--- a/update_engine.xml
+++ b/update_engine.xml
@@ -7,6 +7,12 @@
<interface name="org.chromium.UpdateEngineInterface">
<annotation name="org.freedesktop.DBus.GLib.CSymbol"
value="update_engine_service"/>
+ <method name="AttemptUpdate">
+ <arg type="s" name="app_version" />
+ <arg type="s" name="omaha_url" />
+ </method>
+ <method name="CheckForUpdate">
+ </method>
<method name="GetStatus">
<arg type="x" name="last_checked_time" direction="out" />
<arg type="d" name="progress" direction="out" />
@@ -14,11 +20,7 @@
<arg type="s" name="new_version" direction="out" />
<arg type="x" name="new_size" direction="out" />
</method>
- <method name="CheckForUpdate">
- </method>
- <method name="AttemptUpdate">
- <arg type="s" name="app_version" />
- <arg type="s" name="omaha_url" />
+ <method name="RebootIfNeeded">
</method>
<signal name="StatusUpdate">
<arg type="x" name="last_checked_time" />
diff --git a/update_engine_client.cc b/update_engine_client.cc
index bb4beaa..c8dda07 100644
--- a/update_engine_client.cc
+++ b/update_engine_client.cc
@@ -22,14 +22,12 @@
using chromeos_update_engine::utils::GetGErrorMessage;
using std::string;
-DEFINE_string(app_version, "",
- "Force the current app version.");
-DEFINE_bool(check_for_update, false,
- "Initiate check for updates.");
+DEFINE_string(app_version, "", "Force the current app version.");
+DEFINE_bool(check_for_update, false, "Initiate check for updates.");
DEFINE_bool(force_update, false,
"Force an update, even over an expensive network.");
-DEFINE_string(omaha_url, "",
- "The URL of the Omaha update server.");
+DEFINE_string(omaha_url, "", "The URL of the Omaha update server.");
+DEFINE_bool(reboot, false, "Initiate a reboot if needed.");
DEFINE_bool(status, false, "Print the status to stdout.");
DEFINE_bool(watch_for_updates, false,
"Listen for status updates and print them to the screen.");
@@ -158,6 +156,21 @@
return true;
}
+bool RebootIfNeeded() {
+ DBusGProxy* proxy;
+ GError* error = NULL;
+
+ CHECK(GetProxy(&proxy));
+
+ gboolean rc =
+ org_chromium_UpdateEngineInterface_reboot_if_needed(proxy, &error);
+ // Reboot error code doesn't necessarily mean that a reboot
+ // failed. For example, D-Bus may be shutdown before we receive the
+ // result.
+ LOG_IF(INFO, !rc) << "Reboot error message: " << GetGErrorMessage(error);
+ return true;
+}
+
} // namespace {}
int main(int argc, char** argv) {
@@ -177,6 +190,7 @@
}
if (FLAGS_force_update || FLAGS_check_for_update ||
!FLAGS_app_version.empty() || !FLAGS_omaha_url.empty()) {
+ LOG_IF(WARNING, FLAGS_reboot) << "-reboot flag ignored.";
LOG(INFO) << "Initiating update check and install.";
if (FLAGS_force_update) {
LOG(INFO) << "Will not abort due to being on expensive network.";
@@ -187,10 +201,16 @@
return 0;
}
if (FLAGS_watch_for_updates) {
+ LOG_IF(WARNING, FLAGS_reboot) << "-reboot flag ignored.";
LOG(INFO) << "Watching for status updates.";
WatchForUpdates(); // Should never return.
return 1;
}
+ if (FLAGS_reboot) {
+ LOG(INFO) << "Requesting a reboot...";
+ CHECK(RebootIfNeeded());
+ return 0;
+ }
LOG(INFO) << "No flags specified. Exiting.";
return 0;
diff --git a/utils.cc b/utils.cc
index b19e6fc..4c5a195 100644
--- a/utils.cc
+++ b/utils.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -16,6 +16,7 @@
#include <algorithm>
#include "chromeos/obsolete_logging.h"
#include "update_engine/file_writer.h"
+#include "update_engine/subprocess.h"
using std::min;
using std::string;
@@ -73,7 +74,7 @@
}
*out_bytes_read = bytes_read;
return true;
-
+
}
bool ReadFile(const std::string& path, std::vector<char>* out) {
@@ -282,7 +283,7 @@
vector<char> buf(filename_template.size() + 1);
memcpy(&buf[0], filename_template.data(), filename_template.size());
buf[filename_template.size()] = '\0';
-
+
int mkstemp_fd = mkstemp(&buf[0]);
TEST_AND_RETURN_FALSE_ERRNO(mkstemp_fd >= 0);
if (filename) {
@@ -302,7 +303,7 @@
vector<char> buf(dirname_template.size() + 1);
memcpy(&buf[0], dirname_template.data(), dirname_template.size());
buf[dirname_template.size()] = '\0';
-
+
char* return_code = mkdtemp(&buf[0]);
TEST_AND_RETURN_FALSE_ERRNO(return_code != NULL);
*dirname = &buf[0];
@@ -393,9 +394,19 @@
return error->message;
}
+bool Reboot() {
+ vector<string> command;
+ command.push_back("/sbin/shutdown");
+ command.push_back("-r");
+ command.push_back("now");
+ int rc = 0;
+ Subprocess::SynchronousExec(command, &rc);
+ TEST_AND_RETURN_FALSE(rc == 0);
+ return true;
+}
+
const char* const kStatefulPartition = "/mnt/stateful_partition";
} // namespace utils
} // namespace chromeos_update_engine
-
diff --git a/utils.h b/utils.h
index 5a3efe9..9be2509 100644
--- a/utils.h
+++ b/utils.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -102,6 +102,9 @@
// Returns the error message, if any, from a GError pointer.
const char* GetGErrorMessage(const GError* error);
+// Initiates a system reboot. Returns true on success, false otherwise.
+bool Reboot();
+
// Log a string in hex to LOG(INFO). Useful for debugging.
void HexDumpArray(const unsigned char* const arr, const size_t length);
inline void HexDumpString(const std::string& str) {