Compile update_engine_client for non-Brillo targets.
The non-Brillo Android targets use the reduced binder interface. This
patch creates a similar update_engine_client command line tool to use
with the non-Brillo interface and compiles it for those targets.
Bug: 25631767
TEST=`mmma system/update_engine` on edison-eng and aosp_arm-eng.
Change-Id: I598144db2b703322c8469fa0982a70dc62572936
diff --git a/update_engine_client_android.cc b/update_engine_client_android.cc
new file mode 100644
index 0000000..5005da7
--- /dev/null
+++ b/update_engine_client_android.cc
@@ -0,0 +1,216 @@
+//
+// 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 <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/update_status_utils.h"
+#include "update_engine/common/error_code.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:
+ 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;
+
+ // Copy of argc and argv passed to main().
+ int argc_;
+ char** argv_;
+
+ android::sp<android::os::IUpdateEngine> service_;
+ android::sp<android::os::BnUpdateEngineCallback> 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);
+ // TODO(deymo): Print the ErrorCode as a string.
+ LOG(INFO) << "onPayloadApplicationComplete(" << error_code << ")";
+ client_->ExitWhenIdle(code == ErrorCode::kSuccess ? 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_string(headers,
+ "",
+ "A list of key-value pairs, one element of the list per line.");
+
+ 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(follow,
+ false,
+ "Follow status update changes until a final state is reached. "
+ "Exit status is 0 if the update succeeded, and 1 otherwise.");
+
+ // 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::kLogToSyslog);
+ 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();
+ }
+
+ if (FLAGS_suspend) {
+ return ExitWhenIdle(service_->suspend());
+ }
+
+ if (FLAGS_resume) {
+ return ExitWhenIdle(service_->resume());
+ }
+
+ if (FLAGS_cancel) {
+ return ExitWhenIdle(service_->cancel());
+ }
+
+ 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) {
+ std::vector<std::string> headers = base::SplitString(
+ FLAGS_headers, "\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()});
+ }
+ Status status = service_->applyPayload(
+ android::String16{FLAGS_payload.data(), FLAGS_payload.size()},
+ and_headers);
+ if (!status.isOk())
+ return ExitWhenIdle(status);
+ }
+
+ if (!keep_running)
+ return ExitWhenIdle(EX_OK);
+
+ // Initialize a binder watcher.
+ binder_watcher_.Init();
+ 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;
+}
+
+} // namespace internal
+} // namespace chromeos_update_engine
+
+int main(int argc, char** argv) {
+ chromeos_update_engine::internal::UpdateEngineClientAndroid client(
+ argc, argv);
+ return client.Run();
+}