1 // Copyright 2016 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "libweaved/service.h"
16
17 #include <algorithm>
18
19 #include <base/bind.h>
20 #include <base/memory/weak_ptr.h>
21 #include <base/strings/stringprintf.h>
22 #include <binderwrapper/binder_wrapper.h>
23 #include <brillo/message_loops/message_loop.h>
24
25 #include "android/weave/BnWeaveClient.h"
26 #include "android/weave/BnWeaveServiceManagerNotificationListener.h"
27 #include "android/weave/IWeaveCommand.h"
28 #include "android/weave/IWeaveService.h"
29 #include "android/weave/IWeaveServiceManager.h"
30 #include "common/binder_constants.h"
31 #include "common/binder_utils.h"
32
33 using weaved::binder_utils::StatusToError;
34 using weaved::binder_utils::ToString;
35 using weaved::binder_utils::ToString16;
36
37 // The semantic of weaved connection is a bit complicated and that's why we have
38 // the numerous classes defined here.
39 // When the client wants to connect to weaved they would call Service::Connect
40 // and provide a callback to be invoked when the connection is fully established
41 // and ready to be used.
42 //
43 // Service::Connect() creates an instance of ServiceImpl class and sets the only
44 // strong pointer into ServiceSubscription class which is returned to the client
45 // as std::unqiue_ptr<Service::Subscription>. This allows us to hide the actual
46 // service object from the client until the connection is fully ready to be
47 // used, and at the same time give the client an exclusive ownership of the
48 // connection. They are free to destroy the Subscription and abort the
49 // connection at any point.
50 //
51 // At the same time an asynchronous process to establish a connection to weaved
52 // over binder is initiated. ServiceImpl periodically tries to get hold of
53 // IWeaveServiceManager binder object from binder service manager. Once this
54 // succeeds, we know that weaved is running. We create a callback binder object,
55 // WeaveClient, which implements IWeaveClient binder interface and pass it to
56 // weaved in IWeaveServiceManager::connect() method. The weaved daemon keeps the
57 // list of all the clients registered with it for two reasons:
58 // 1. It watches each client for death notifications and cleans up the
59 // resources added by the client (e.g. weave components) when the client
60 // dies.
61 // 2. It notifies the client of weaved being ready to talk to (by calling
62 // onServiceConnected callback) and when new weave commands are available
63 // for the client (via onCommand callback).
64 // When weaved is fully initialized (which can take some time after the daemon
65 // physically starts up), it invokes IWeaveClient::onServiceConnection on each
66 // client and passes a unique copy of IWeaveService to each of the client.
67 // The clients will use its own IWeaveService interface to further interact with
68 // weaved. This allows weaved to distinguish binder calls from each client and
69 // maintain the track record of which client adds each resource.
70
71 // Once IWeaveClient::onServiceConnection is called, we have a fully-established
72 // service connection to weaved and we invoke the client callback provided in
73 // the original call to Service::Connect() and pass the weak pointer to the
74 // service as an argument.
75
76 // In case a connection to weaved is lost, the ServiceImpl class will be deleted
77 // and any weak pointers to it the client may have will be invalidated.
78 // A new instance of ServiceImpl is created and the strong reference in
79 // ServiceSubscription is replace to the new instance. A new re-connection cycle
80 // is started as if the client just invoked Service::Connect() again on the new
81 // instance of ServiceImpl.
82
83 namespace weaved {
84
85 namespace {
86 // An implementation for service subscription. This object keeps a reference to
87 // the actual instance of weaved service object. This is generally the only hard
88 // reference to the shared pointer to the service object. The client receives
89 // a weak pointer only.
90 class ServiceSubscription : public Service::Subscription {
91 public:
92 ServiceSubscription() = default;
93 ~ServiceSubscription() override = default;
94
SetService(const std::shared_ptr<Service> & service)95 void SetService(const std::shared_ptr<Service>& service) {
96 service_ = service;
97 }
98
99 private:
100 std::shared_ptr<Service> service_;
101 DISALLOW_COPY_AND_ASSIGN(ServiceSubscription);
102 };
103
104 } // anonymous namespace
105
106 class ServiceImpl;
107
108 // Each system process wishing to expose functionality via weave establishes a
109 // connection to weaved via Binder. The communication channel is two-way.
110 // The client obtains a reference to weaved's android::weave::IWeaveService from
111 // the system service manager, and registers an instance of
112 // android::weave::IWeaveClient with weaved via IWeaveService.
113 // WeaveClient is an implementation of android::weave::IWeaveClient binder
114 // interface. Apart from providing callback methods (such as onCommand), it is
115 // used by weaved to track the life-time of this particular client. If the
116 // client exits, weaved automatically cleans up resources added by this client.
117 class WeaveClient : public android::weave::BnWeaveClient {
118 public:
119 explicit WeaveClient(const std::weak_ptr<ServiceImpl>& service);
120
121 private:
122 // Implementation for IWeaveClient interface.
123 // A notification that the service binder is successfully instantiated and
124 // weaved daemon is ready to process incoming request for component creation,
125 // device state updates and so on.
126 android::binder::Status onServiceConnected(
127 const android::sp<android::weave::IWeaveService>& service) override;
128
129 // A callback invoked when a new command for which a handler was registered
130 // is added to the command queue.
131 android::binder::Status onCommand(
132 const android::String16& componentName,
133 const android::String16& commandName,
134 const android::sp<android::weave::IWeaveCommand>& command) override;
135
136 std::weak_ptr<ServiceImpl> service_;
137
138 base::WeakPtrFactory<WeaveClient> weak_ptr_factory_{this};
139 DISALLOW_COPY_AND_ASSIGN(WeaveClient);
140 };
141
142 class NotificationListener
143 : public android::weave::BnWeaveServiceManagerNotificationListener {
144 public:
145 explicit NotificationListener(const std::weak_ptr<ServiceImpl>& service);
146
147 private:
148 // Implementation for IWeaveServiceManagerNotificationListener interface.
149 android::binder::Status notifyServiceManagerChange(
150 const std::vector<int>& notificationIds) override;
151
152 std::weak_ptr<ServiceImpl> service_;
153
154 base::WeakPtrFactory<NotificationListener> weak_ptr_factory_{this};
155 DISALLOW_COPY_AND_ASSIGN(NotificationListener);
156 };
157
158 // ServiceImpl is a concrete implementation of weaved::Service interface.
159 // This object is a wrapper around android::weave::IWeaveService binder
160 // interface to weaved daemon.
161 // This class is created as soon as Service::Connect() is called and it
162 // initiates connection attempts to IWeaveService binder. Only when the
163 // connection is successful and we receive callback notification from weaved
164 // that the service is ready, we invoke the client-provided callback and pass
165 // a weak pointer to Service fro the client to talk to weaved.
166 class ServiceImpl : public std::enable_shared_from_this<ServiceImpl>,
167 public Service {
168 public:
169 // A constructor. Client code never creates this instance directly, but rather
170 // uses Service::Connect which is responsible for creating a instance of this
171 // class.
172 ServiceImpl(android::BinderWrapper* binder_wrapper,
173 brillo::MessageLoop* message_loop,
174 ServiceSubscription* service_subscription,
175 const ConnectionCallback& connection_callback);
176 ~ServiceImpl() override;
177
178 // Service interface methods.
179 bool AddComponent(const std::string& component,
180 const std::vector<std::string>& traits,
181 brillo::ErrorPtr* error) override;
182 void AddCommandHandler(const std::string& component,
183 const std::string& trait_name,
184 const std::string& command_name,
185 const CommandHandlerCallback& callback) override;
186 bool SetStateProperties(const std::string& component,
187 const base::DictionaryValue& dict,
188 brillo::ErrorPtr* error) override;
189 bool SetStateProperty(const std::string& component,
190 const std::string& trait_name,
191 const std::string& property_name,
192 const base::Value& value,
193 brillo::ErrorPtr* error) override;
194 void SetPairingInfoListener(const PairingInfoCallback& callback) override;
195
196 // Helper method called from Service::Connect() to initiate binder connection
197 // to weaved. This message just posts a task to the message loop to invoke
198 // TryConnecting() method.
199 void BeginConnect();
200
201 // A callback method for WeaveClient::onServiceConnected().
202 void OnServiceConnected(
203 const android::sp<android::weave::IWeaveService>& service);
204
205 // A callback method for WeaveClient::onCommand().
206 void OnCommand(const std::string& component_name,
207 const std::string& command_name,
208 const android::sp<android::weave::IWeaveCommand>& command);
209
210 // A callback method for NotificationListener::notifyServiceManagerChange().
211 void OnNotification(const std::vector<int>& notification_ids);
212
213 private:
214 // Connects to weaved daemon over binder if the service manager is available
215 // and weaved daemon itself is ready to accept connections. If not, schedules
216 // another retry after a delay (1 second).
217 void TryConnecting();
218
219 // A callback for weaved connection termination. When binder service manager
220 // notifies client of weaved binder object destruction (e.g. weaved quits),
221 // this callback is invoked and initiates re-connection process.
222 // Since the callback can happen synchronously from any call into the binder
223 // driver, this method just posts a message that just asynchronously invokes
224 // "ReconnectOnServiceDisconnection".
225 void OnWeaveServiceDisconnected();
226
227 // Asynchronous notification callback of binder service death. Tears down
228 // this instance of ServiceImpl class, creates a new one and re-initiates
229 // the binder connection to the service.
230 void ReconnectOnServiceDisconnection();
231
232 android::BinderWrapper* binder_wrapper_;
233 brillo::MessageLoop* message_loop_;
234 ServiceSubscription* service_subscription_;
235 ConnectionCallback connection_callback_;
236 android::sp<android::weave::IWeaveServiceManager> weave_service_manager_;
237 android::sp<android::weave::IWeaveService> weave_service_;
238 PairingInfoCallback pairing_info_callback_;
239 PairingInfo pairing_info_;
240
241 struct CommandHandlerEntry {
242 std::string component;
243 std::string command_name;
244 CommandHandlerCallback callback;
245 };
246 std::vector<CommandHandlerEntry> command_handlers_;
247
248 base::WeakPtrFactory<ServiceImpl> weak_ptr_factory_{this};
249 DISALLOW_COPY_AND_ASSIGN(ServiceImpl);
250 };
251
WeaveClient(const std::weak_ptr<ServiceImpl> & service)252 WeaveClient::WeaveClient(const std::weak_ptr<ServiceImpl>& service)
253 : service_{service} {}
254
onServiceConnected(const android::sp<android::weave::IWeaveService> & service)255 android::binder::Status WeaveClient::onServiceConnected(
256 const android::sp<android::weave::IWeaveService>& service) {
257 LOG(INFO) << "Weave service connection established successfully";
258 auto service_proxy = service_.lock();
259 if (service_proxy)
260 service_proxy->OnServiceConnected(service);
261 return android::binder::Status::ok();
262 }
263
onCommand(const android::String16 & componentName,const android::String16 & commandName,const android::sp<android::weave::IWeaveCommand> & command)264 android::binder::Status WeaveClient::onCommand(
265 const android::String16& componentName,
266 const android::String16& commandName,
267 const android::sp<android::weave::IWeaveCommand>& command) {
268 auto service_proxy = service_.lock();
269 if (service_proxy) {
270 service_proxy->OnCommand(ToString(componentName), ToString(commandName),
271 command);
272 } else {
273 command->abort(android::String16{"service_unavailable"},
274 android::String16{"Command handler is unavailable"});
275 }
276 return android::binder::Status::ok();
277 }
278
NotificationListener(const std::weak_ptr<ServiceImpl> & service)279 NotificationListener::NotificationListener(
280 const std::weak_ptr<ServiceImpl>& service)
281 : service_{service} {}
282
notifyServiceManagerChange(const std::vector<int> & notificationIds)283 android::binder::Status NotificationListener::notifyServiceManagerChange(
284 const std::vector<int>& notificationIds) {
285 auto service_proxy = service_.lock();
286 if (service_proxy)
287 service_proxy->OnNotification(notificationIds);
288 return android::binder::Status::ok();
289 }
290
ServiceImpl(android::BinderWrapper * binder_wrapper,brillo::MessageLoop * message_loop,ServiceSubscription * service_subscription,const ConnectionCallback & connection_callback)291 ServiceImpl::ServiceImpl(android::BinderWrapper* binder_wrapper,
292 brillo::MessageLoop* message_loop,
293 ServiceSubscription* service_subscription,
294 const ConnectionCallback& connection_callback)
295 : binder_wrapper_{binder_wrapper},
296 message_loop_{message_loop},
297 service_subscription_{service_subscription},
298 connection_callback_{connection_callback} {
299 }
300
~ServiceImpl()301 ServiceImpl::~ServiceImpl() {
302 if (weave_service_.get()) {
303 android::sp<android::IBinder> binder =
304 android::IInterface::asBinder(weave_service_);
305 binder_wrapper_->UnregisterForDeathNotifications(binder);
306 }
307 }
308
AddComponent(const std::string & component,const std::vector<std::string> & traits,brillo::ErrorPtr * error)309 bool ServiceImpl::AddComponent(const std::string& component,
310 const std::vector<std::string>& traits,
311 brillo::ErrorPtr* error) {
312 CHECK(weave_service_.get());
313 std::vector<android::String16> trait_list;
314 auto to_string16 = [](const std::string& name) {
315 return android::String16{name.c_str()};
316 };
317 std::transform(traits.begin(), traits.end(), std::back_inserter(trait_list),
318 to_string16);
319 return StatusToError(weave_service_->addComponent(to_string16(component),
320 trait_list),
321 error);
322 }
323
AddCommandHandler(const std::string & component,const std::string & trait_name,const std::string & command_name,const CommandHandlerCallback & callback)324 void ServiceImpl::AddCommandHandler(const std::string& component,
325 const std::string& trait_name,
326 const std::string& command_name,
327 const CommandHandlerCallback& callback) {
328 CHECK(!component.empty() && !command_name.empty());
329 CHECK(weave_service_.get());
330
331 std::string full_command_name =
332 base::StringPrintf("%s.%s", trait_name.c_str(), command_name.c_str());
333
334 CommandHandlerEntry entry;
335 entry.component = component;
336 entry.command_name = full_command_name;
337 entry.callback = callback;
338 command_handlers_.push_back(std::move(entry));
339
340 auto status = weave_service_->registerCommandHandler(
341 android::String16{component.c_str()},
342 android::String16{full_command_name.c_str()});
343 CHECK(status.isOk());
344 }
345
SetStateProperties(const std::string & component,const base::DictionaryValue & dict,brillo::ErrorPtr * error)346 bool ServiceImpl::SetStateProperties(const std::string& component,
347 const base::DictionaryValue& dict,
348 brillo::ErrorPtr* error) {
349 CHECK(!component.empty());
350 CHECK(weave_service_.get());
351 return StatusToError(weave_service_->updateState(ToString16(component),
352 ToString16(dict)),
353 error);
354 }
355
SetStateProperty(const std::string & component,const std::string & trait_name,const std::string & property_name,const base::Value & value,brillo::ErrorPtr * error)356 bool ServiceImpl::SetStateProperty(const std::string& component,
357 const std::string& trait_name,
358 const std::string& property_name,
359 const base::Value& value,
360 brillo::ErrorPtr* error) {
361 std::string name =
362 base::StringPrintf("%s.%s", trait_name.c_str(), property_name.c_str());
363 base::DictionaryValue dict;
364 dict.Set(name, value.DeepCopy());
365 return SetStateProperties(component, dict, error);
366 }
367
SetPairingInfoListener(const PairingInfoCallback & callback)368 void ServiceImpl::SetPairingInfoListener(const PairingInfoCallback& callback) {
369 pairing_info_callback_ = callback;
370 if (!pairing_info_callback_.is_null() &&
371 !pairing_info_.session_id.empty() &&
372 !pairing_info_.pairing_mode.empty() &&
373 !pairing_info_.pairing_code.empty()) {
374 callback.Run(&pairing_info_);
375 }
376 }
377
BeginConnect()378 void ServiceImpl::BeginConnect() {
379 message_loop_->PostTask(FROM_HERE,
380 base::Bind(&ServiceImpl::TryConnecting,
381 weak_ptr_factory_.GetWeakPtr()));
382 }
383
OnServiceConnected(const android::sp<android::weave::IWeaveService> & service)384 void ServiceImpl::OnServiceConnected(
385 const android::sp<android::weave::IWeaveService>& service) {
386 weave_service_ = service;
387 connection_callback_.Run(shared_from_this());
388 }
389
OnCommand(const std::string & component_name,const std::string & command_name,const android::sp<android::weave::IWeaveCommand> & command)390 void ServiceImpl::OnCommand(
391 const std::string& component_name,
392 const std::string& command_name,
393 const android::sp<android::weave::IWeaveCommand>& command) {
394 VLOG(2) << "Weave command received for component '" << component_name << "': "
395 << command_name;
396 for (const auto& entry : command_handlers_) {
397 if (entry.component == component_name &&
398 entry.command_name == command_name) {
399 std::unique_ptr<Command> command_instance{new Command{command}};
400 return entry.callback.Run(std::move(command_instance));
401 }
402 }
403 LOG(WARNING) << "Unexpected command notification. Command = " << command_name
404 << ", component = " << component_name;
405 }
406
TryConnecting()407 void ServiceImpl::TryConnecting() {
408 LOG(INFO) << "Connecting to weave service over binder";
409 android::sp<android::IBinder> binder =
410 binder_wrapper_->GetService(weaved::binder::kWeaveServiceName);
411 if (!binder.get()) {
412 LOG(WARNING) << "Weave service is not available yet. Will try again later";
413 message_loop_->PostDelayedTask(
414 FROM_HERE,
415 base::Bind(&ServiceImpl::TryConnecting, weak_ptr_factory_.GetWeakPtr()),
416 base::TimeDelta::FromSeconds(1));
417 return;
418 }
419
420 bool register_success = binder_wrapper_->RegisterForDeathNotifications(
421 binder, base::Bind(&ServiceImpl::OnWeaveServiceDisconnected,
422 weak_ptr_factory_.GetWeakPtr()));
423 if (!register_success) {
424 // Something really bad happened here, restart the connection.
425 OnWeaveServiceDisconnected();
426 return;
427 }
428 weave_service_manager_ =
429 android::interface_cast<android::weave::IWeaveServiceManager>(binder);
430 android::sp<WeaveClient> weave_client = new WeaveClient{shared_from_this()};
431 weave_service_manager_->connect(weave_client);
432 android::sp<NotificationListener> notification_listener =
433 new NotificationListener{shared_from_this()};
434 weave_service_manager_->registerNotificationListener(notification_listener);
435 }
436
OnWeaveServiceDisconnected()437 void ServiceImpl::OnWeaveServiceDisconnected() {
438 message_loop_->PostTask(
439 FROM_HERE,
440 base::Bind(&ServiceImpl::ReconnectOnServiceDisconnection,
441 weak_ptr_factory_.GetWeakPtr()));
442 }
443
ReconnectOnServiceDisconnection()444 void ServiceImpl::ReconnectOnServiceDisconnection() {
445 weave_service_.clear();
446 // Need to create a new instance of service to invalidate existing weak
447 // pointers.
448 auto service = std::make_shared<ServiceImpl>(
449 binder_wrapper_, message_loop_, service_subscription_,
450 connection_callback_);
451 service->BeginConnect();
452 // The subscription object owns this instance.
453 // Calling SetService() will destroy |this|.
454 service_subscription_->SetService(service);
455 // Do not call any methods or use resources of ServiceImpl after this point
456 // because the object is destroyed now.
457 }
458
OnNotification(const std::vector<int> & notification_ids)459 void ServiceImpl::OnNotification(const std::vector<int>& notification_ids) {
460 bool pairing_info_changed = false;
461 using NotificationListener =
462 android::weave::IWeaveServiceManagerNotificationListener;
463 android::String16 string_value;
464 for (int id : notification_ids) {
465 switch (id) {
466 case NotificationListener::PAIRING_SESSION_ID:
467 if (weave_service_manager_->getPairingSessionId(&string_value).isOk()) {
468 pairing_info_changed = true;
469 pairing_info_.session_id = ToString(string_value);
470 }
471 break;
472 case NotificationListener::PAIRING_MODE:
473 if (weave_service_manager_->getPairingMode(&string_value).isOk()) {
474 pairing_info_changed = true;
475 pairing_info_.pairing_mode = ToString(string_value);
476 }
477 break;
478 case NotificationListener::PAIRING_CODE:
479 if (weave_service_manager_->getPairingCode(&string_value).isOk()) {
480 pairing_info_changed = true;
481 pairing_info_.pairing_code = ToString(string_value);
482 }
483 break;
484 }
485 }
486
487 if (!pairing_info_changed || pairing_info_callback_.is_null())
488 return;
489
490 if (pairing_info_.session_id.empty() || pairing_info_.pairing_mode.empty() ||
491 pairing_info_.pairing_code.empty()) {
492 pairing_info_callback_.Run(nullptr);
493 } else {
494 pairing_info_callback_.Run(&pairing_info_);
495 }
496 }
497
Connect(brillo::MessageLoop * message_loop,const ConnectionCallback & callback)498 std::unique_ptr<Service::Subscription> Service::Connect(
499 brillo::MessageLoop* message_loop,
500 const ConnectionCallback& callback) {
501 std::unique_ptr<ServiceSubscription> subscription{new ServiceSubscription};
502 auto service = std::make_shared<ServiceImpl>(
503 android::BinderWrapper::GetOrCreateInstance(), message_loop,
504 subscription.get(), callback);
505 subscription->SetService(service);
506 service->BeginConnect();
507 return std::move(subscription);
508 }
509
510 } // namespace weaved
511