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
33using weaved::binder_utils::StatusToError;
34using weaved::binder_utils::ToString;
35using 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
83namespace weaved {
84
85namespace {
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.
90class ServiceSubscription : public Service::Subscription {
91 public:
92  ServiceSubscription() = default;
93  ~ServiceSubscription() override = default;
94
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
106class 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.
117class 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
142class 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.
166class 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
252WeaveClient::WeaveClient(const std::weak_ptr<ServiceImpl>& service)
253    : service_{service} {}
254
255android::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
264android::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
279NotificationListener::NotificationListener(
280    const std::weak_ptr<ServiceImpl>& service)
281    : service_{service} {}
282
283android::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
291ServiceImpl::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
301ServiceImpl::~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
309bool 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
324void 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
346bool 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
356bool 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
368void 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
378void ServiceImpl::BeginConnect() {
379  message_loop_->PostTask(FROM_HERE,
380                          base::Bind(&ServiceImpl::TryConnecting,
381                                     weak_ptr_factory_.GetWeakPtr()));
382}
383
384void ServiceImpl::OnServiceConnected(
385    const android::sp<android::weave::IWeaveService>& service) {
386  weave_service_ = service;
387  connection_callback_.Run(shared_from_this());
388}
389
390void 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
407void 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
437void ServiceImpl::OnWeaveServiceDisconnected() {
438  message_loop_->PostTask(
439      FROM_HERE,
440      base::Bind(&ServiceImpl::ReconnectOnServiceDisconnection,
441                 weak_ptr_factory_.GetWeakPtr()));
442}
443
444void 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
459void 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
498std::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