summaryrefslogtreecommitdiff
path: root/aosp/update_engine_client_android.cc
diff options
context:
space:
mode:
Diffstat (limited to 'aosp/update_engine_client_android.cc')
-rw-r--r--aosp/update_engine_client_android.cc314
1 files changed, 314 insertions, 0 deletions
diff --git a/aosp/update_engine_client_android.cc b/aosp/update_engine_client_android.cc
new file mode 100644
index 00000000..1a68cf49
--- /dev/null
+++ b/aosp/update_engine_client_android.cc
@@ -0,0 +1,314 @@
+//
+// Copyright (C) 2016 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 <sysexits.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include <base/bind.h>
+#include <base/callback.h>
+#include <base/command_line.h>
+#include <base/logging.h>
+#include <base/strings/string_split.h>
+#include <binder/IServiceManager.h>
+#include <binderwrapper/binder_wrapper.h>
+#include <brillo/binder_watcher.h>
+#include <brillo/daemons/daemon.h>
+#include <brillo/flag_helper.h>
+#include <brillo/message_loops/message_loop.h>
+#include <brillo/syslog_logging.h>
+#include <utils/String16.h>
+#include <utils/StrongPointer.h>
+
+#include "android/os/BnUpdateEngineCallback.h"
+#include "android/os/IUpdateEngine.h"
+#include "update_engine/client_library/include/update_engine/update_status.h"
+#include "update_engine/common/error_code.h"
+#include "update_engine/common/error_code_utils.h"
+#include "update_engine/update_status_utils.h"
+
+using android::binder::Status;
+
+namespace chromeos_update_engine {
+namespace internal {
+
+class UpdateEngineClientAndroid : public brillo::Daemon {
+ public:
+ UpdateEngineClientAndroid(int argc, char** argv) : argc_(argc), argv_(argv) {}
+
+ int ExitWhenIdle(const Status& status);
+ int ExitWhenIdle(int return_code);
+
+ private:
+ class UECallback : public android::os::BnUpdateEngineCallback {
+ public:
+ explicit UECallback(UpdateEngineClientAndroid* client) : client_(client) {}
+
+ // android::os::BnUpdateEngineCallback overrides.
+ Status onStatusUpdate(int status_code, float progress) override;
+ Status onPayloadApplicationComplete(int error_code) override;
+
+ private:
+ UpdateEngineClientAndroid* client_;
+ };
+
+ int OnInit() override;
+
+ // Called whenever the UpdateEngine daemon dies.
+ void UpdateEngineServiceDied();
+
+ static std::vector<android::String16> ParseHeaders(const std::string& arg);
+
+ // Copy of argc and argv passed to main().
+ int argc_;
+ char** argv_;
+
+ android::sp<android::os::IUpdateEngine> service_;
+ android::sp<android::os::BnUpdateEngineCallback> callback_;
+ android::sp<android::os::BnUpdateEngineCallback> cleanup_callback_;
+
+ brillo::BinderWatcher binder_watcher_;
+};
+
+Status UpdateEngineClientAndroid::UECallback::onStatusUpdate(int status_code,
+ float progress) {
+ update_engine::UpdateStatus status =
+ static_cast<update_engine::UpdateStatus>(status_code);
+ LOG(INFO) << "onStatusUpdate(" << UpdateStatusToString(status) << " ("
+ << status_code << "), " << progress << ")";
+ return Status::ok();
+}
+
+Status UpdateEngineClientAndroid::UECallback::onPayloadApplicationComplete(
+ int error_code) {
+ ErrorCode code = static_cast<ErrorCode>(error_code);
+ LOG(INFO) << "onPayloadApplicationComplete(" << utils::ErrorCodeToString(code)
+ << " (" << error_code << "))";
+ client_->ExitWhenIdle(
+ (code == ErrorCode::kSuccess || code == ErrorCode::kUpdatedButNotActive)
+ ? EX_OK
+ : 1);
+ return Status::ok();
+}
+
+int UpdateEngineClientAndroid::OnInit() {
+ int ret = Daemon::OnInit();
+ if (ret != EX_OK)
+ return ret;
+
+ DEFINE_bool(update, false, "Start a new update, if no update in progress.");
+ DEFINE_string(payload,
+ "http://127.0.0.1:8080/payload",
+ "The URI to the update payload to use.");
+ DEFINE_int64(offset,
+ 0,
+ "The offset in the payload where the CrAU update starts. "
+ "Used when --update is passed.");
+ DEFINE_int64(size,
+ 0,
+ "The size of the CrAU part of the payload. If 0 is passed, it "
+ "will be autodetected. Used when --update is passed.");
+ DEFINE_string(headers,
+ "",
+ "A list of key-value pairs, one element of the list per line. "
+ "Used when --update or --allocate is passed.");
+
+ DEFINE_bool(verify,
+ false,
+ "Given payload metadata, verify if the payload is applicable.");
+ DEFINE_bool(allocate, false, "Given payload metadata, allocate space.");
+ DEFINE_string(metadata,
+ "/data/ota_package/metadata",
+ "The path to the update payload metadata. "
+ "Used when --verify or --allocate is passed.");
+
+ DEFINE_bool(suspend, false, "Suspend an ongoing update and exit.");
+ DEFINE_bool(resume, false, "Resume a suspended update.");
+ DEFINE_bool(cancel, false, "Cancel the ongoing update and exit.");
+ DEFINE_bool(reset_status, false, "Reset an already applied update and exit.");
+ DEFINE_bool(follow,
+ false,
+ "Follow status update changes until a final state is reached. "
+ "Exit status is 0 if the update succeeded, and 1 otherwise.");
+ DEFINE_bool(merge,
+ false,
+ "Wait for previous update to merge. "
+ "Only available after rebooting to new slot.");
+ // Boilerplate init commands.
+ base::CommandLine::Init(argc_, argv_);
+ brillo::FlagHelper::Init(argc_, argv_, "Android Update Engine Client");
+ if (argc_ == 1) {
+ LOG(ERROR) << "Nothing to do. Run with --help for help.";
+ return 1;
+ }
+
+ // Ensure there are no positional arguments.
+ const std::vector<std::string> positional_args =
+ base::CommandLine::ForCurrentProcess()->GetArgs();
+ if (!positional_args.empty()) {
+ LOG(ERROR) << "Found a positional argument '" << positional_args.front()
+ << "'. If you want to pass a value to a flag, pass it as "
+ "--flag=value.";
+ return 1;
+ }
+
+ bool keep_running = false;
+ brillo::InitLog(brillo::kLogToStderr);
+
+ // Initialize a binder watcher early in the process before any interaction
+ // with the binder driver.
+ binder_watcher_.Init();
+
+ android::status_t status = android::getService(
+ android::String16("android.os.UpdateEngineService"), &service_);
+ if (status != android::OK) {
+ LOG(ERROR) << "Failed to get IUpdateEngine binder from service manager: "
+ << Status::fromStatusT(status).toString8();
+ return ExitWhenIdle(1);
+ }
+
+ if (FLAGS_suspend) {
+ return ExitWhenIdle(service_->suspend());
+ }
+
+ if (FLAGS_resume) {
+ return ExitWhenIdle(service_->resume());
+ }
+
+ if (FLAGS_cancel) {
+ return ExitWhenIdle(service_->cancel());
+ }
+
+ if (FLAGS_reset_status) {
+ return ExitWhenIdle(service_->resetStatus());
+ }
+
+ if (FLAGS_verify) {
+ bool applicable = false;
+ Status status = service_->verifyPayloadApplicable(
+ android::String16{FLAGS_metadata.data(), FLAGS_metadata.size()},
+ &applicable);
+ LOG(INFO) << "Payload is " << (applicable ? "" : "not ") << "applicable.";
+ return ExitWhenIdle(status);
+ }
+
+ if (FLAGS_allocate) {
+ auto headers = ParseHeaders(FLAGS_headers);
+ int64_t ret = 0;
+ Status status = service_->allocateSpaceForPayload(
+ android::String16{FLAGS_metadata.data(), FLAGS_metadata.size()},
+ headers,
+ &ret);
+ if (status.isOk()) {
+ if (ret == 0) {
+ LOG(INFO) << "Successfully allocated space for payload.";
+ } else {
+ LOG(INFO) << "Insufficient space; required " << ret << " bytes.";
+ }
+ } else {
+ LOG(INFO) << "Allocation failed.";
+ }
+ return ExitWhenIdle(status);
+ }
+
+ if (FLAGS_merge) {
+ // Register a callback object with the service.
+ cleanup_callback_ = new UECallback(this);
+ Status status = service_->cleanupSuccessfulUpdate(cleanup_callback_);
+ if (!status.isOk()) {
+ LOG(ERROR) << "Failed to call cleanupSuccessfulUpdate.";
+ return ExitWhenIdle(status);
+ }
+ keep_running = true;
+ }
+
+ if (FLAGS_follow) {
+ // Register a callback object with the service.
+ callback_ = new UECallback(this);
+ bool bound;
+ if (!service_->bind(callback_, &bound).isOk() || !bound) {
+ LOG(ERROR) << "Failed to bind() the UpdateEngine daemon.";
+ return 1;
+ }
+ keep_running = true;
+ }
+
+ if (FLAGS_update) {
+ auto and_headers = ParseHeaders(FLAGS_headers);
+ Status status = service_->applyPayload(
+ android::String16{FLAGS_payload.data(), FLAGS_payload.size()},
+ FLAGS_offset,
+ FLAGS_size,
+ and_headers);
+ if (!status.isOk())
+ return ExitWhenIdle(status);
+ }
+
+ if (!keep_running)
+ return ExitWhenIdle(EX_OK);
+
+ // When following updates status changes, exit if the update_engine daemon
+ // dies.
+ android::BinderWrapper::Create();
+ android::BinderWrapper::Get()->RegisterForDeathNotifications(
+ android::os::IUpdateEngine::asBinder(service_),
+ base::Bind(&UpdateEngineClientAndroid::UpdateEngineServiceDied,
+ base::Unretained(this)));
+
+ return EX_OK;
+}
+
+int UpdateEngineClientAndroid::ExitWhenIdle(const Status& status) {
+ if (status.isOk())
+ return ExitWhenIdle(EX_OK);
+ LOG(ERROR) << status.toString8();
+ return ExitWhenIdle(status.exceptionCode());
+}
+
+int UpdateEngineClientAndroid::ExitWhenIdle(int return_code) {
+ auto delayed_exit = base::Bind(
+ &Daemon::QuitWithExitCode, base::Unretained(this), return_code);
+ if (!brillo::MessageLoop::current()->PostTask(delayed_exit))
+ return 1;
+ return EX_OK;
+}
+
+void UpdateEngineClientAndroid::UpdateEngineServiceDied() {
+ LOG(ERROR) << "UpdateEngineService died.";
+ QuitWithExitCode(1);
+}
+
+std::vector<android::String16> UpdateEngineClientAndroid::ParseHeaders(
+ const std::string& arg) {
+ std::vector<std::string> headers = base::SplitString(
+ arg, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ std::vector<android::String16> and_headers;
+ for (const auto& header : headers) {
+ and_headers.push_back(android::String16{header.data(), header.size()});
+ }
+ return and_headers;
+}
+
+} // namespace internal
+} // namespace chromeos_update_engine
+
+int main(int argc, char** argv) {
+ chromeos_update_engine::internal::UpdateEngineClientAndroid client(argc,
+ argv);
+ return client.Run();
+}