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