• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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