1 //
2 // Copyright (C) 2020 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 // update_engine console client installed to APEXes for scripts to invoke
18 // directly. Uses the stable API.
19
20 #include <fcntl.h>
21 #include <sysexits.h>
22 #include <unistd.h>
23
24 #include <vector>
25
26 #include <aidl/android/os/BnUpdateEngineStableCallback.h>
27 #include <aidl/android/os/IUpdateEngineStable.h>
28 #include <android-base/logging.h>
29 #include <android-base/strings.h>
30 #include <android/binder_manager.h>
31 #include <android/binder_process.h>
32 #include <android/binder_ibinder.h>
33 #include <common/error_code.h>
34 #include <gflags/gflags.h>
35
36 namespace chromeos_update_engine::internal {
37
38 DEFINE_string(payload,
39 "file:///path/to/payload.bin",
40 "The file URI to the update payload to use, or path to the file");
41 DEFINE_int64(offset,
42 0,
43 "The offset in the payload where the CrAU update starts.");
44 DEFINE_int64(size,
45 0,
46 "The size of the CrAU part of the payload. If 0 is passed, it "
47 "will be autodetected.");
48 DEFINE_string(headers,
49 "",
50 "A list of key-value pairs, one element of the list per line.");
51
Exit(int return_code)52 [[noreturn]] int Exit(int return_code) {
53 LOG(INFO) << "Exit: " << return_code;
54 exit(return_code);
55 }
56 // Called whenever the UpdateEngine daemon dies.
UpdateEngineServiceDied(void *)57 void UpdateEngineServiceDied(void*) {
58 LOG(ERROR) << "UpdateEngineService died.";
59 Exit(EX_SOFTWARE);
60 }
61
62 class UpdateEngineClientAndroid {
63 public:
64 UpdateEngineClientAndroid() = default;
65 int Run();
66
67 private:
68 class UECallback : public aidl::android::os::BnUpdateEngineStableCallback {
69 public:
70 UECallback() = default;
71
72 // android::os::BnUpdateEngineStableCallback overrides.
73 ndk::ScopedAStatus onStatusUpdate(int status_code, float progress) override;
74 ndk::ScopedAStatus onPayloadApplicationComplete(int error_code) override;
75 };
76
77 static std::vector<std::string> ParseHeaders(const std::string& arg);
78
79 const ndk::ScopedAIBinder_DeathRecipient death_recipient_{
80 AIBinder_DeathRecipient_new(&UpdateEngineServiceDied)};
81 std::shared_ptr<aidl::android::os::IUpdateEngineStable> service_;
82 std::shared_ptr<aidl::android::os::BnUpdateEngineStableCallback> callback_;
83 };
84
onStatusUpdate(int status_code,float progress)85 ndk::ScopedAStatus UpdateEngineClientAndroid::UECallback::onStatusUpdate(
86 int status_code, float progress) {
87 LOG(INFO) << "onStatusUpdate(" << status_code << ", " << progress << ")";
88 return ndk::ScopedAStatus::ok();
89 }
90
91 ndk::ScopedAStatus
onPayloadApplicationComplete(int error_code)92 UpdateEngineClientAndroid::UECallback::onPayloadApplicationComplete(
93 int error_code) {
94 LOG(INFO) << "onPayloadApplicationComplete(" << error_code << ")";
95 auto code = static_cast<ErrorCode>(error_code);
96 Exit((code == ErrorCode::kSuccess || code == ErrorCode::kUpdatedButNotActive)
97 ? EX_OK
98 : EX_SOFTWARE);
99 }
100
Run()101 int UpdateEngineClientAndroid::Run() {
102 service_ = aidl::android::os::IUpdateEngineStable::fromBinder(ndk::SpAIBinder(
103 AServiceManager_getService("android.os.UpdateEngineStableService")));
104 if (service_ == nullptr) {
105 LOG(ERROR)
106 << "Failed to get IUpdateEngineStable binder from service manager.";
107 return EX_SOFTWARE;
108 }
109
110 // Register a callback object with the service.
111 callback_ = ndk::SharedRefBase::make<UECallback>();
112 bool bound;
113 if (!service_->bind(callback_, &bound).isOk() || !bound) {
114 LOG(ERROR) << "Failed to bind() the UpdateEngine daemon.";
115 return EX_SOFTWARE;
116 }
117
118 auto headers = ParseHeaders(FLAGS_headers);
119 ndk::ScopedAStatus status;
120 const char* payload_path;
121 std::string file_prefix = "file://";
122 if (android::base::StartsWith(FLAGS_payload, file_prefix)) {
123 payload_path = FLAGS_payload.data() + file_prefix.length();
124 } else {
125 payload_path = FLAGS_payload.data();
126 }
127 ndk::ScopedFileDescriptor ufd(
128 TEMP_FAILURE_RETRY(open(payload_path, O_RDONLY)));
129 if (ufd.get() < 0) {
130 PLOG(ERROR) << "Can't open " << payload_path;
131 return EX_SOFTWARE;
132 }
133 status = service_->applyPayloadFd(ufd, FLAGS_offset, FLAGS_size, headers);
134 if (!status.isOk()) {
135 LOG(ERROR) << "Cannot apply payload: " << status.getDescription();
136 return EX_SOFTWARE;
137 }
138
139 // When following updates status changes, exit if the update_engine daemon
140 // dies.
141 if (AIBinder_linkToDeath(service_->asBinder().get(),
142 death_recipient_.get(),
143 nullptr) != STATUS_OK) {
144 return EX_SOFTWARE;
145 }
146
147 return EX_OK;
148 }
149
ParseHeaders(const std::string & arg)150 std::vector<std::string> UpdateEngineClientAndroid::ParseHeaders(
151 const std::string& arg) {
152 std::vector<std::string> lines = android::base::Split(arg, "\n");
153 std::vector<std::string> headers;
154 for (const auto& line : lines) {
155 auto header = android::base::Trim(line);
156 if (!header.empty()) {
157 headers.push_back(header);
158 }
159 }
160 return headers;
161 }
162
163 } // namespace chromeos_update_engine::internal
164
main(int argc,char ** argv)165 int main(int argc, char** argv) {
166 android::base::InitLogging(argv);
167 gflags::ParseCommandLineFlags(&argc, &argv, true);
168
169 // Unlike other update_engine* processes that uses message loops,
170 // update_engine_stable_client uses a thread pool model. However, number of
171 // threads is limited to 1; that is, 0 additional threads should be spawned.
172 // This avoids some race conditions.
173 if (!ABinderProcess_setThreadPoolMaxThreadCount(0)) {
174 LOG(ERROR) << "Cannot set thread pool max thread count";
175 return EX_SOFTWARE;
176 }
177 ABinderProcess_startThreadPool();
178
179 chromeos_update_engine::internal::UpdateEngineClientAndroid client{};
180 int code = client.Run();
181 if (code != EX_OK)
182 return code;
183
184 ABinderProcess_joinThreadPool();
185 LOG(ERROR) << "Exited from joinThreadPool.";
186 return EX_SOFTWARE;
187 }
188