1 //
2 // Copyright (C) 2015 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 #include "update_engine/binder_service_android.h"
18 
19 #include <memory>
20 
21 #include <base/bind.h>
22 #include <base/logging.h>
23 #include <binderwrapper/binder_wrapper.h>
24 #include <brillo/errors/error.h>
25 #include <utils/String8.h>
26 
27 using android::binder::Status;
28 using android::os::IUpdateEngineCallback;
29 using android::os::ParcelFileDescriptor;
30 using std::string;
31 using std::vector;
32 using update_engine::UpdateEngineStatus;
33 
34 namespace {
35 Status ErrorPtrToStatus(const brillo::ErrorPtr& error) {
36   return Status::fromServiceSpecificError(
37       1, android::String8{error->GetMessage().c_str()});
38 }
39 
40 vector<string> ToVecString(const vector<android::String16>& inp) {
41   vector<string> out;
42   out.reserve(inp.size());
43   for (const auto& e : inp) {
44     out.emplace_back(android::String8{e}.string());
45   }
46   return out;
47 }
48 
49 }  // namespace
50 
51 namespace chromeos_update_engine {
52 
53 BinderUpdateEngineAndroidService::BinderUpdateEngineAndroidService(
54     ServiceDelegateAndroidInterface* service_delegate)
55     : service_delegate_(service_delegate) {}
56 
57 void BinderUpdateEngineAndroidService::SendStatusUpdate(
58     const UpdateEngineStatus& update_engine_status) {
59   last_status_ = static_cast<int>(update_engine_status.status);
60   last_progress_ = update_engine_status.progress;
61   for (auto& callback : callbacks_) {
62     callback->onStatusUpdate(last_status_, last_progress_);
63   }
64 }
65 
66 void BinderUpdateEngineAndroidService::SendPayloadApplicationComplete(
67     ErrorCode error_code) {
68   for (auto& callback : callbacks_) {
69     callback->onPayloadApplicationComplete(static_cast<int>(error_code));
70   }
71 }
72 
73 Status BinderUpdateEngineAndroidService::bind(
74     const android::sp<IUpdateEngineCallback>& callback, bool* return_value) {
75   // Send an status update on connection (except when no update sent so far).
76   // Even though the status update is oneway, it still returns an erroneous
77   // status in case of a selinux denial. We should at least check this status
78   // and fails the binding.
79   if (last_status_ != -1) {
80     auto status = callback->onStatusUpdate(last_status_, last_progress_);
81     if (!status.isOk()) {
82       LOG(ERROR) << "Failed to call onStatusUpdate() from callback: "
83                  << status.toString8();
84       *return_value = false;
85       return Status::ok();
86     }
87   }
88 
89   callbacks_.emplace_back(callback);
90 
91   const android::sp<IBinder>& callback_binder =
92       IUpdateEngineCallback::asBinder(callback);
93   auto binder_wrapper = android::BinderWrapper::Get();
94   binder_wrapper->RegisterForDeathNotifications(
95       callback_binder,
96       base::Bind(
97           base::IgnoreResult(&BinderUpdateEngineAndroidService::UnbindCallback),
98           base::Unretained(this),
99           base::Unretained(callback_binder.get())));
100 
101   *return_value = true;
102   return Status::ok();
103 }
104 
105 Status BinderUpdateEngineAndroidService::unbind(
106     const android::sp<IUpdateEngineCallback>& callback, bool* return_value) {
107   const android::sp<IBinder>& callback_binder =
108       IUpdateEngineCallback::asBinder(callback);
109   auto binder_wrapper = android::BinderWrapper::Get();
110   binder_wrapper->UnregisterForDeathNotifications(callback_binder);
111 
112   *return_value = UnbindCallback(callback_binder.get());
113   return Status::ok();
114 }
115 
116 Status BinderUpdateEngineAndroidService::applyPayload(
117     const android::String16& url,
118     int64_t payload_offset,
119     int64_t payload_size,
120     const vector<android::String16>& header_kv_pairs) {
121   const string payload_url{android::String8{url}.string()};
122   vector<string> str_headers = ToVecString(header_kv_pairs);
123 
124   brillo::ErrorPtr error;
125   if (!service_delegate_->ApplyPayload(
126           payload_url, payload_offset, payload_size, str_headers, &error)) {
127     return ErrorPtrToStatus(error);
128   }
129   return Status::ok();
130 }
131 
132 Status BinderUpdateEngineAndroidService::applyPayloadFd(
133     const ParcelFileDescriptor& pfd,
134     int64_t payload_offset,
135     int64_t payload_size,
136     const vector<android::String16>& header_kv_pairs) {
137   vector<string> str_headers = ToVecString(header_kv_pairs);
138 
139   brillo::ErrorPtr error;
140   if (!service_delegate_->ApplyPayload(
141           pfd.get(), payload_offset, payload_size, str_headers, &error)) {
142     return ErrorPtrToStatus(error);
143   }
144   return Status::ok();
145 }
146 
147 Status BinderUpdateEngineAndroidService::suspend() {
148   brillo::ErrorPtr error;
149   if (!service_delegate_->SuspendUpdate(&error))
150     return ErrorPtrToStatus(error);
151   return Status::ok();
152 }
153 
154 Status BinderUpdateEngineAndroidService::resume() {
155   brillo::ErrorPtr error;
156   if (!service_delegate_->ResumeUpdate(&error))
157     return ErrorPtrToStatus(error);
158   return Status::ok();
159 }
160 
161 Status BinderUpdateEngineAndroidService::cancel() {
162   brillo::ErrorPtr error;
163   if (!service_delegate_->CancelUpdate(&error))
164     return ErrorPtrToStatus(error);
165   return Status::ok();
166 }
167 
168 Status BinderUpdateEngineAndroidService::resetStatus() {
169   brillo::ErrorPtr error;
170   if (!service_delegate_->ResetStatus(&error))
171     return ErrorPtrToStatus(error);
172   return Status::ok();
173 }
174 
175 Status BinderUpdateEngineAndroidService::verifyPayloadApplicable(
176     const android::String16& metadata_filename, bool* return_value) {
177   const std::string payload_metadata{
178       android::String8{metadata_filename}.string()};
179   LOG(INFO) << "Received a request of verifying payload metadata in "
180             << payload_metadata << ".";
181   brillo::ErrorPtr error;
182   *return_value =
183       service_delegate_->VerifyPayloadApplicable(payload_metadata, &error);
184   if (error != nullptr)
185     return ErrorPtrToStatus(error);
186   return Status::ok();
187 }
188 
189 bool BinderUpdateEngineAndroidService::UnbindCallback(const IBinder* callback) {
190   auto it = std::find_if(
191       callbacks_.begin(),
192       callbacks_.end(),
193       [&callback](const android::sp<IUpdateEngineCallback>& elem) {
194         return IUpdateEngineCallback::asBinder(elem).get() == callback;
195       });
196   if (it == callbacks_.end()) {
197     LOG(ERROR) << "Unable to unbind unknown callback.";
198     return false;
199   }
200   callbacks_.erase(it);
201   return true;
202 }
203 
204 Status BinderUpdateEngineAndroidService::allocateSpaceForPayload(
205     const android::String16& metadata_filename,
206     const vector<android::String16>& header_kv_pairs,
207     int64_t* return_value) {
208   const std::string payload_metadata{
209       android::String8{metadata_filename}.string()};
210   vector<string> str_headers = ToVecString(header_kv_pairs);
211   LOG(INFO) << "Received a request of allocating space for " << payload_metadata
212             << ".";
213   brillo::ErrorPtr error;
214   *return_value =
215       static_cast<int64_t>(service_delegate_->AllocateSpaceForPayload(
216           payload_metadata, str_headers, &error));
217   if (error != nullptr)
218     return ErrorPtrToStatus(error);
219   return Status::ok();
220 }
221 
222 class CleanupSuccessfulUpdateCallback
223     : public CleanupSuccessfulUpdateCallbackInterface {
224  public:
225   CleanupSuccessfulUpdateCallback(
226       const android::sp<IUpdateEngineCallback>& callback)
227       : callback_(callback) {}
228   void OnCleanupComplete(int32_t error_code) {
229     ignore_result(callback_->onPayloadApplicationComplete(error_code));
230   }
231   void OnCleanupProgressUpdate(double progress) {
232     ignore_result(callback_->onStatusUpdate(
233         static_cast<int32_t>(
234             update_engine::UpdateStatus::CLEANUP_PREVIOUS_UPDATE),
235         progress));
236   }
237   void RegisterForDeathNotifications(base::Closure unbind) {
238     const android::sp<android::IBinder>& callback_binder =
239         IUpdateEngineCallback::asBinder(callback_);
240     auto binder_wrapper = android::BinderWrapper::Get();
241     binder_wrapper->RegisterForDeathNotifications(callback_binder, unbind);
242   }
243 
244  private:
245   android::sp<IUpdateEngineCallback> callback_;
246 };
247 
248 Status BinderUpdateEngineAndroidService::cleanupSuccessfulUpdate(
249     const android::sp<IUpdateEngineCallback>& callback) {
250   brillo::ErrorPtr error;
251   service_delegate_->CleanupSuccessfulUpdate(
252       std::make_unique<CleanupSuccessfulUpdateCallback>(callback), &error);
253   if (error != nullptr)
254     return ErrorPtrToStatus(error);
255   return Status::ok();
256 }
257 
258 }  // namespace chromeos_update_engine
259