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