Home | History | Annotate | Download | only in libweaved
      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 
     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 
    252 WeaveClient::WeaveClient(const std::weak_ptr<ServiceImpl>& service)
    253     : service_{service} {}
    254 
    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 
    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 
    279 NotificationListener::NotificationListener(
    280     const std::weak_ptr<ServiceImpl>& service)
    281     : service_{service} {}
    282 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    378 void ServiceImpl::BeginConnect() {
    379   message_loop_->PostTask(FROM_HERE,
    380                           base::Bind(&ServiceImpl::TryConnecting,
    381                                      weak_ptr_factory_.GetWeakPtr()));
    382 }
    383 
    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 
    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 
    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 
    437 void ServiceImpl::OnWeaveServiceDisconnected() {
    438   message_loop_->PostTask(
    439       FROM_HERE,
    440       base::Bind(&ServiceImpl::ReconnectOnServiceDisconnection,
    441                  weak_ptr_factory_.GetWeakPtr()));
    442 }
    443 
    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 
    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 
    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