blob: 350aa51a073b38955f0000cef5752cc64257af92 [file] [log] [blame]
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -08001// 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>
Alex Vakulenkoc9844512016-01-07 10:06:23 -080021#include <base/strings/stringprintf.h>
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -080022#include <binderwrapper/binder_wrapper.h>
23#include <brillo/message_loops/message_loop.h>
24
25#include "android/weave/BnWeaveClient.h"
Alex Vakulenko3faf0372016-01-08 12:22:28 -080026#include "android/weave/BnWeaveServiceManagerNotificationListener.h"
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -080027#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"
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -080032
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
Alex Vakulenko3faf0372016-01-08 12:22:28 -0800142class 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
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800158// 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,
Alex Vakulenkoc9844512016-01-07 10:06:23 -0800183 const std::string& trait_name,
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800184 const std::string& command_name,
185 const CommandHandlerCallback& callback) override;
186 bool SetStateProperties(const std::string& component,
Alex Vakulenkoe9a83852016-01-28 14:34:04 -0800187 const base::DictionaryValue& dict,
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800188 brillo::ErrorPtr* error) override;
189 bool SetStateProperty(const std::string& component,
Alex Vakulenkoc9844512016-01-07 10:06:23 -0800190 const std::string& trait_name,
191 const std::string& property_name,
Alex Vakulenkoe9a83852016-01-28 14:34:04 -0800192 const base::Value& value,
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800193 brillo::ErrorPtr* error) override;
Alex Vakulenko3faf0372016-01-08 12:22:28 -0800194 void SetPairingInfoListener(const PairingInfoCallback& callback) override;
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800195
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
Alex Vakulenko3faf0372016-01-08 12:22:28 -0800210 // A callback method for NotificationListener::notifyServiceManagerChange().
211 void OnNotification(const std::vector<int>& notification_ids);
212
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800213 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.
Alex Vakulenkofc025832016-02-04 11:28:20 -0800222 // 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".
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800225 void OnWeaveServiceDisconnected();
226
Alex Vakulenkofc025832016-02-04 11:28:20 -0800227 // 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
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800232 android::BinderWrapper* binder_wrapper_;
233 brillo::MessageLoop* message_loop_;
234 ServiceSubscription* service_subscription_;
235 ConnectionCallback connection_callback_;
Alex Vakulenko3faf0372016-01-08 12:22:28 -0800236 android::sp<android::weave::IWeaveServiceManager> weave_service_manager_;
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800237 android::sp<android::weave::IWeaveService> weave_service_;
Alex Vakulenko3faf0372016-01-08 12:22:28 -0800238 PairingInfoCallback pairing_info_callback_;
239 PairingInfo pairing_info_;
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800240
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
Alex Vakulenko3faf0372016-01-08 12:22:28 -0800279NotificationListener::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
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800291ServiceImpl::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,
Alex Vakulenkoc9844512016-01-07 10:06:23 -0800325 const std::string& trait_name,
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800326 const std::string& command_name,
327 const CommandHandlerCallback& callback) {
328 CHECK(!component.empty() && !command_name.empty());
329 CHECK(weave_service_.get());
330
Alex Vakulenkoc9844512016-01-07 10:06:23 -0800331 std::string full_command_name =
332 base::StringPrintf("%s.%s", trait_name.c_str(), command_name.c_str());
333
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800334 CommandHandlerEntry entry;
335 entry.component = component;
Alex Vakulenkoc9844512016-01-07 10:06:23 -0800336 entry.command_name = full_command_name;
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800337 entry.callback = callback;
338 command_handlers_.push_back(std::move(entry));
339
340 auto status = weave_service_->registerCommandHandler(
341 android::String16{component.c_str()},
Alex Vakulenkoc9844512016-01-07 10:06:23 -0800342 android::String16{full_command_name.c_str()});
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800343 CHECK(status.isOk());
344}
345
346bool ServiceImpl::SetStateProperties(const std::string& component,
Alex Vakulenkoe9a83852016-01-28 14:34:04 -0800347 const base::DictionaryValue& dict,
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800348 brillo::ErrorPtr* error) {
349 CHECK(!component.empty());
350 CHECK(weave_service_.get());
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800351 return StatusToError(weave_service_->updateState(ToString16(component),
Alex Vakulenkoe9a83852016-01-28 14:34:04 -0800352 ToString16(dict)),
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800353 error);
354}
355
356bool ServiceImpl::SetStateProperty(const std::string& component,
Alex Vakulenkoc9844512016-01-07 10:06:23 -0800357 const std::string& trait_name,
358 const std::string& property_name,
Alex Vakulenkoe9a83852016-01-28 14:34:04 -0800359 const base::Value& value,
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800360 brillo::ErrorPtr* error) {
Alex Vakulenkoc9844512016-01-07 10:06:23 -0800361 std::string name =
362 base::StringPrintf("%s.%s", trait_name.c_str(), property_name.c_str());
Alex Vakulenkoe9a83852016-01-28 14:34:04 -0800363 base::DictionaryValue dict;
364 dict.Set(name, value.DeepCopy());
365 return SetStateProperties(component, dict, error);
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800366}
367
Alex Vakulenko3faf0372016-01-08 12:22:28 -0800368void 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
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800378void 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());
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800388}
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()) {
Alex Vakulenkofc025832016-02-04 11:28:20 -0800412 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));
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800417 return;
418 }
419
Alex Vakulenkofc025832016-02-04 11:28:20 -0800420 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 }
Alex Vakulenko3faf0372016-01-08 12:22:28 -0800428 weave_service_manager_ =
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800429 android::interface_cast<android::weave::IWeaveServiceManager>(binder);
430 android::sp<WeaveClient> weave_client = new WeaveClient{shared_from_this()};
Alex Vakulenko3faf0372016-01-08 12:22:28 -0800431 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);
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800435}
436
437void ServiceImpl::OnWeaveServiceDisconnected() {
Alex Vakulenkofc025832016-02-04 11:28:20 -0800438 message_loop_->PostTask(
439 FROM_HERE,
440 base::Bind(&ServiceImpl::ReconnectOnServiceDisconnection,
441 weak_ptr_factory_.GetWeakPtr()));
442}
443
444void ServiceImpl::ReconnectOnServiceDisconnection() {
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800445 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
Alex Vakulenko3faf0372016-01-08 12:22:28 -0800459void 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
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800498std::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