blob: 2f9db9c8febce99d4e1935bb41c4aa113a1645ed [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.
222 void OnWeaveServiceDisconnected();
223
224 android::BinderWrapper* binder_wrapper_;
225 brillo::MessageLoop* message_loop_;
226 ServiceSubscription* service_subscription_;
227 ConnectionCallback connection_callback_;
Alex Vakulenko3faf0372016-01-08 12:22:28 -0800228 android::sp<android::weave::IWeaveServiceManager> weave_service_manager_;
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800229 android::sp<android::weave::IWeaveService> weave_service_;
Alex Vakulenko3faf0372016-01-08 12:22:28 -0800230 PairingInfoCallback pairing_info_callback_;
231 PairingInfo pairing_info_;
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800232
233 struct CommandHandlerEntry {
234 std::string component;
235 std::string command_name;
236 CommandHandlerCallback callback;
237 };
238 std::vector<CommandHandlerEntry> command_handlers_;
239
240 base::WeakPtrFactory<ServiceImpl> weak_ptr_factory_{this};
241 DISALLOW_COPY_AND_ASSIGN(ServiceImpl);
242};
243
244WeaveClient::WeaveClient(const std::weak_ptr<ServiceImpl>& service)
245 : service_{service} {}
246
247android::binder::Status WeaveClient::onServiceConnected(
248 const android::sp<android::weave::IWeaveService>& service) {
249 LOG(INFO) << "Weave service connection established successfully";
250 auto service_proxy = service_.lock();
251 if (service_proxy)
252 service_proxy->OnServiceConnected(service);
253 return android::binder::Status::ok();
254}
255
256android::binder::Status WeaveClient::onCommand(
257 const android::String16& componentName,
258 const android::String16& commandName,
259 const android::sp<android::weave::IWeaveCommand>& command) {
260 auto service_proxy = service_.lock();
261 if (service_proxy) {
262 service_proxy->OnCommand(ToString(componentName), ToString(commandName),
263 command);
264 } else {
265 command->abort(android::String16{"service_unavailable"},
266 android::String16{"Command handler is unavailable"});
267 }
268 return android::binder::Status::ok();
269}
270
Alex Vakulenko3faf0372016-01-08 12:22:28 -0800271NotificationListener::NotificationListener(
272 const std::weak_ptr<ServiceImpl>& service)
273 : service_{service} {}
274
275android::binder::Status NotificationListener::notifyServiceManagerChange(
276 const std::vector<int>& notificationIds) {
277 auto service_proxy = service_.lock();
278 if (service_proxy)
279 service_proxy->OnNotification(notificationIds);
280 return android::binder::Status::ok();
281}
282
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800283ServiceImpl::ServiceImpl(android::BinderWrapper* binder_wrapper,
284 brillo::MessageLoop* message_loop,
285 ServiceSubscription* service_subscription,
286 const ConnectionCallback& connection_callback)
287 : binder_wrapper_{binder_wrapper},
288 message_loop_{message_loop},
289 service_subscription_{service_subscription},
290 connection_callback_{connection_callback} {
291}
292
293ServiceImpl::~ServiceImpl() {
294 if (weave_service_.get()) {
295 android::sp<android::IBinder> binder =
296 android::IInterface::asBinder(weave_service_);
297 binder_wrapper_->UnregisterForDeathNotifications(binder);
298 }
299}
300
301bool ServiceImpl::AddComponent(const std::string& component,
302 const std::vector<std::string>& traits,
303 brillo::ErrorPtr* error) {
304 CHECK(weave_service_.get());
305 std::vector<android::String16> trait_list;
306 auto to_string16 = [](const std::string& name) {
307 return android::String16{name.c_str()};
308 };
309 std::transform(traits.begin(), traits.end(), std::back_inserter(trait_list),
310 to_string16);
311 return StatusToError(weave_service_->addComponent(to_string16(component),
312 trait_list),
313 error);
314}
315
316void ServiceImpl::AddCommandHandler(const std::string& component,
Alex Vakulenkoc9844512016-01-07 10:06:23 -0800317 const std::string& trait_name,
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800318 const std::string& command_name,
319 const CommandHandlerCallback& callback) {
320 CHECK(!component.empty() && !command_name.empty());
321 CHECK(weave_service_.get());
322
Alex Vakulenkoc9844512016-01-07 10:06:23 -0800323 std::string full_command_name =
324 base::StringPrintf("%s.%s", trait_name.c_str(), command_name.c_str());
325
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800326 CommandHandlerEntry entry;
327 entry.component = component;
Alex Vakulenkoc9844512016-01-07 10:06:23 -0800328 entry.command_name = full_command_name;
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800329 entry.callback = callback;
330 command_handlers_.push_back(std::move(entry));
331
332 auto status = weave_service_->registerCommandHandler(
333 android::String16{component.c_str()},
Alex Vakulenkoc9844512016-01-07 10:06:23 -0800334 android::String16{full_command_name.c_str()});
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800335 CHECK(status.isOk());
336}
337
338bool ServiceImpl::SetStateProperties(const std::string& component,
Alex Vakulenkoe9a83852016-01-28 14:34:04 -0800339 const base::DictionaryValue& dict,
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800340 brillo::ErrorPtr* error) {
341 CHECK(!component.empty());
342 CHECK(weave_service_.get());
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800343 return StatusToError(weave_service_->updateState(ToString16(component),
Alex Vakulenkoe9a83852016-01-28 14:34:04 -0800344 ToString16(dict)),
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800345 error);
346}
347
348bool ServiceImpl::SetStateProperty(const std::string& component,
Alex Vakulenkoc9844512016-01-07 10:06:23 -0800349 const std::string& trait_name,
350 const std::string& property_name,
Alex Vakulenkoe9a83852016-01-28 14:34:04 -0800351 const base::Value& value,
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800352 brillo::ErrorPtr* error) {
Alex Vakulenkoc9844512016-01-07 10:06:23 -0800353 std::string name =
354 base::StringPrintf("%s.%s", trait_name.c_str(), property_name.c_str());
Alex Vakulenkoe9a83852016-01-28 14:34:04 -0800355 base::DictionaryValue dict;
356 dict.Set(name, value.DeepCopy());
357 return SetStateProperties(component, dict, error);
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800358}
359
Alex Vakulenko3faf0372016-01-08 12:22:28 -0800360void ServiceImpl::SetPairingInfoListener(const PairingInfoCallback& callback) {
361 pairing_info_callback_ = callback;
362 if (!pairing_info_callback_.is_null() &&
363 !pairing_info_.session_id.empty() &&
364 !pairing_info_.pairing_mode.empty() &&
365 !pairing_info_.pairing_code.empty()) {
366 callback.Run(&pairing_info_);
367 }
368}
369
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800370void ServiceImpl::BeginConnect() {
371 message_loop_->PostTask(FROM_HERE,
372 base::Bind(&ServiceImpl::TryConnecting,
373 weak_ptr_factory_.GetWeakPtr()));
374}
375
376void ServiceImpl::OnServiceConnected(
377 const android::sp<android::weave::IWeaveService>& service) {
378 weave_service_ = service;
379 connection_callback_.Run(shared_from_this());
380 // Call this last in case the binder object is already gone and the death
381 // notification callback (OnWeaveServiceDisconnected) is invoked immediately.
382 // In this case, the instance of ServiceImpl will get destroyed before
383 // RegisterForDeathNotifications returns.
384 binder_wrapper_->RegisterForDeathNotifications(
385 android::IInterface::asBinder(service),
386 base::Bind(&ServiceImpl::OnWeaveServiceDisconnected,
387 weak_ptr_factory_.GetWeakPtr()));
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(INFO) << "Weave service is not available yet. Will try again later";
413 message_loop_->PostDelayedTask(FROM_HERE,
414 base::Bind(&ServiceImpl::TryConnecting,
415 weak_ptr_factory_.GetWeakPtr()),
416 base::TimeDelta::FromSeconds(1));
417 return;
418 }
419
Alex Vakulenko3faf0372016-01-08 12:22:28 -0800420 weave_service_manager_ =
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800421 android::interface_cast<android::weave::IWeaveServiceManager>(binder);
422 android::sp<WeaveClient> weave_client = new WeaveClient{shared_from_this()};
Alex Vakulenko3faf0372016-01-08 12:22:28 -0800423 weave_service_manager_->connect(weave_client);
424 android::sp<NotificationListener> notification_listener =
425 new NotificationListener{shared_from_this()};
426 weave_service_manager_->registerNotificationListener(notification_listener);
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800427}
428
429void ServiceImpl::OnWeaveServiceDisconnected() {
430 weave_service_.clear();
431 // Need to create a new instance of service to invalidate existing weak
432 // pointers.
433 auto service = std::make_shared<ServiceImpl>(
434 binder_wrapper_, message_loop_, service_subscription_,
435 connection_callback_);
436 service->BeginConnect();
437 // The subscription object owns this instance.
438 // Calling SetService() will destroy |this|.
439 service_subscription_->SetService(service);
440 // Do not call any methods or use resources of ServiceImpl after this point
441 // because the object is destroyed now.
442}
443
Alex Vakulenko3faf0372016-01-08 12:22:28 -0800444void ServiceImpl::OnNotification(const std::vector<int>& notification_ids) {
445 bool pairing_info_changed = false;
446 using NotificationListener =
447 android::weave::IWeaveServiceManagerNotificationListener;
448 android::String16 string_value;
449 for (int id : notification_ids) {
450 switch (id) {
451 case NotificationListener::PAIRING_SESSION_ID:
452 if (weave_service_manager_->getPairingSessionId(&string_value).isOk()) {
453 pairing_info_changed = true;
454 pairing_info_.session_id = ToString(string_value);
455 }
456 break;
457 case NotificationListener::PAIRING_MODE:
458 if (weave_service_manager_->getPairingMode(&string_value).isOk()) {
459 pairing_info_changed = true;
460 pairing_info_.pairing_mode = ToString(string_value);
461 }
462 break;
463 case NotificationListener::PAIRING_CODE:
464 if (weave_service_manager_->getPairingCode(&string_value).isOk()) {
465 pairing_info_changed = true;
466 pairing_info_.pairing_code = ToString(string_value);
467 }
468 break;
469 }
470 }
471
472 if (!pairing_info_changed || pairing_info_callback_.is_null())
473 return;
474
475 if (pairing_info_.session_id.empty() || pairing_info_.pairing_mode.empty() ||
476 pairing_info_.pairing_code.empty()) {
477 pairing_info_callback_.Run(nullptr);
478 } else {
479 pairing_info_callback_.Run(&pairing_info_);
480 }
481}
482
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800483std::unique_ptr<Service::Subscription> Service::Connect(
484 brillo::MessageLoop* message_loop,
485 const ConnectionCallback& callback) {
486 std::unique_ptr<ServiceSubscription> subscription{new ServiceSubscription};
487 auto service = std::make_shared<ServiceImpl>(
488 android::BinderWrapper::GetOrCreateInstance(), message_loop,
489 subscription.get(), callback);
490 subscription->SetService(service);
491 service->BeginConnect();
492 return std::move(subscription);
493}
494
495} // namespace weaved