blob: c48fb4199b667d8485c17fc315a97b1b4cac9e9d [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"
32#include "common/data_conversion.h"
33
34using weaved::binder_utils::StatusToError;
35using weaved::binder_utils::ToString;
36using weaved::binder_utils::ToString16;
37
38// The semantic of weaved connection is a bit complicated and that's why we have
39// the numerous classes defined here.
40// When the client wants to connect to weaved they would call Service::Connect
41// and provide a callback to be invoked when the connection is fully established
42// and ready to be used.
43//
44// Service::Connect() creates an instance of ServiceImpl class and sets the only
45// strong pointer into ServiceSubscription class which is returned to the client
46// as std::unqiue_ptr<Service::Subscription>. This allows us to hide the actual
47// service object from the client until the connection is fully ready to be
48// used, and at the same time give the client an exclusive ownership of the
49// connection. They are free to destroy the Subscription and abort the
50// connection at any point.
51//
52// At the same time an asynchronous process to establish a connection to weaved
53// over binder is initiated. ServiceImpl periodically tries to get hold of
54// IWeaveServiceManager binder object from binder service manager. Once this
55// succeeds, we know that weaved is running. We create a callback binder object,
56// WeaveClient, which implements IWeaveClient binder interface and pass it to
57// weaved in IWeaveServiceManager::connect() method. The weaved daemon keeps the
58// list of all the clients registered with it for two reasons:
59// 1. It watches each client for death notifications and cleans up the
60// resources added by the client (e.g. weave components) when the client
61// dies.
62// 2. It notifies the client of weaved being ready to talk to (by calling
63// onServiceConnected callback) and when new weave commands are available
64// for the client (via onCommand callback).
65// When weaved is fully initialized (which can take some time after the daemon
66// physically starts up), it invokes IWeaveClient::onServiceConnection on each
67// client and passes a unique copy of IWeaveService to each of the client.
68// The clients will use its own IWeaveService interface to further interact with
69// weaved. This allows weaved to distinguish binder calls from each client and
70// maintain the track record of which client adds each resource.
71
72// Once IWeaveClient::onServiceConnection is called, we have a fully-established
73// service connection to weaved and we invoke the client callback provided in
74// the original call to Service::Connect() and pass the weak pointer to the
75// service as an argument.
76
77// In case a connection to weaved is lost, the ServiceImpl class will be deleted
78// and any weak pointers to it the client may have will be invalidated.
79// A new instance of ServiceImpl is created and the strong reference in
80// ServiceSubscription is replace to the new instance. A new re-connection cycle
81// is started as if the client just invoked Service::Connect() again on the new
82// instance of ServiceImpl.
83
84namespace weaved {
85
86namespace {
87// An implementation for service subscription. This object keeps a reference to
88// the actual instance of weaved service object. This is generally the only hard
89// reference to the shared pointer to the service object. The client receives
90// a weak pointer only.
91class ServiceSubscription : public Service::Subscription {
92 public:
93 ServiceSubscription() = default;
94 ~ServiceSubscription() override = default;
95
96 void SetService(const std::shared_ptr<Service>& service) {
97 service_ = service;
98 }
99
100 private:
101 std::shared_ptr<Service> service_;
102 DISALLOW_COPY_AND_ASSIGN(ServiceSubscription);
103};
104
105} // anonymous namespace
106
107class ServiceImpl;
108
109// Each system process wishing to expose functionality via weave establishes a
110// connection to weaved via Binder. The communication channel is two-way.
111// The client obtains a reference to weaved's android::weave::IWeaveService from
112// the system service manager, and registers an instance of
113// android::weave::IWeaveClient with weaved via IWeaveService.
114// WeaveClient is an implementation of android::weave::IWeaveClient binder
115// interface. Apart from providing callback methods (such as onCommand), it is
116// used by weaved to track the life-time of this particular client. If the
117// client exits, weaved automatically cleans up resources added by this client.
118class WeaveClient : public android::weave::BnWeaveClient {
119 public:
120 explicit WeaveClient(const std::weak_ptr<ServiceImpl>& service);
121
122 private:
123 // Implementation for IWeaveClient interface.
124 // A notification that the service binder is successfully instantiated and
125 // weaved daemon is ready to process incoming request for component creation,
126 // device state updates and so on.
127 android::binder::Status onServiceConnected(
128 const android::sp<android::weave::IWeaveService>& service) override;
129
130 // A callback invoked when a new command for which a handler was registered
131 // is added to the command queue.
132 android::binder::Status onCommand(
133 const android::String16& componentName,
134 const android::String16& commandName,
135 const android::sp<android::weave::IWeaveCommand>& command) override;
136
137 std::weak_ptr<ServiceImpl> service_;
138
139 base::WeakPtrFactory<WeaveClient> weak_ptr_factory_{this};
140 DISALLOW_COPY_AND_ASSIGN(WeaveClient);
141};
142
Alex Vakulenko3faf0372016-01-08 12:22:28 -0800143class NotificationListener
144 : public android::weave::BnWeaveServiceManagerNotificationListener {
145 public:
146 explicit NotificationListener(const std::weak_ptr<ServiceImpl>& service);
147
148 private:
149 // Implementation for IWeaveServiceManagerNotificationListener interface.
150 android::binder::Status notifyServiceManagerChange(
151 const std::vector<int>& notificationIds) override;
152
153 std::weak_ptr<ServiceImpl> service_;
154
155 base::WeakPtrFactory<NotificationListener> weak_ptr_factory_{this};
156 DISALLOW_COPY_AND_ASSIGN(NotificationListener);
157};
158
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800159// ServiceImpl is a concrete implementation of weaved::Service interface.
160// This object is a wrapper around android::weave::IWeaveService binder
161// interface to weaved daemon.
162// This class is created as soon as Service::Connect() is called and it
163// initiates connection attempts to IWeaveService binder. Only when the
164// connection is successful and we receive callback notification from weaved
165// that the service is ready, we invoke the client-provided callback and pass
166// a weak pointer to Service fro the client to talk to weaved.
167class ServiceImpl : public std::enable_shared_from_this<ServiceImpl>,
168 public Service {
169 public:
170 // A constructor. Client code never creates this instance directly, but rather
171 // uses Service::Connect which is responsible for creating a instance of this
172 // class.
173 ServiceImpl(android::BinderWrapper* binder_wrapper,
174 brillo::MessageLoop* message_loop,
175 ServiceSubscription* service_subscription,
176 const ConnectionCallback& connection_callback);
177 ~ServiceImpl() override;
178
179 // Service interface methods.
180 bool AddComponent(const std::string& component,
181 const std::vector<std::string>& traits,
182 brillo::ErrorPtr* error) override;
183 void AddCommandHandler(const std::string& component,
Alex Vakulenkoc9844512016-01-07 10:06:23 -0800184 const std::string& trait_name,
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800185 const std::string& command_name,
186 const CommandHandlerCallback& callback) override;
187 bool SetStateProperties(const std::string& component,
188 const brillo::VariantDictionary& dict,
189 brillo::ErrorPtr* error) override;
190 bool SetStateProperty(const std::string& component,
Alex Vakulenkoc9844512016-01-07 10:06:23 -0800191 const std::string& trait_name,
192 const std::string& property_name,
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800193 const brillo::Any& value,
194 brillo::ErrorPtr* error) override;
Alex Vakulenko3faf0372016-01-08 12:22:28 -0800195 void SetPairingInfoListener(const PairingInfoCallback& callback) override;
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800196
197 // Helper method called from Service::Connect() to initiate binder connection
198 // to weaved. This message just posts a task to the message loop to invoke
199 // TryConnecting() method.
200 void BeginConnect();
201
202 // A callback method for WeaveClient::onServiceConnected().
203 void OnServiceConnected(
204 const android::sp<android::weave::IWeaveService>& service);
205
206 // A callback method for WeaveClient::onCommand().
207 void OnCommand(const std::string& component_name,
208 const std::string& command_name,
209 const android::sp<android::weave::IWeaveCommand>& command);
210
Alex Vakulenko3faf0372016-01-08 12:22:28 -0800211 // A callback method for NotificationListener::notifyServiceManagerChange().
212 void OnNotification(const std::vector<int>& notification_ids);
213
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800214 private:
215 // Connects to weaved daemon over binder if the service manager is available
216 // and weaved daemon itself is ready to accept connections. If not, schedules
217 // another retry after a delay (1 second).
218 void TryConnecting();
219
220 // A callback for weaved connection termination. When binder service manager
221 // notifies client of weaved binder object destruction (e.g. weaved quits),
222 // this callback is invoked and initiates re-connection process.
223 void OnWeaveServiceDisconnected();
224
225 android::BinderWrapper* binder_wrapper_;
226 brillo::MessageLoop* message_loop_;
227 ServiceSubscription* service_subscription_;
228 ConnectionCallback connection_callback_;
Alex Vakulenko3faf0372016-01-08 12:22:28 -0800229 android::sp<android::weave::IWeaveServiceManager> weave_service_manager_;
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800230 android::sp<android::weave::IWeaveService> weave_service_;
Alex Vakulenko3faf0372016-01-08 12:22:28 -0800231 PairingInfoCallback pairing_info_callback_;
232 PairingInfo pairing_info_;
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800233
234 struct CommandHandlerEntry {
235 std::string component;
236 std::string command_name;
237 CommandHandlerCallback callback;
238 };
239 std::vector<CommandHandlerEntry> command_handlers_;
240
241 base::WeakPtrFactory<ServiceImpl> weak_ptr_factory_{this};
242 DISALLOW_COPY_AND_ASSIGN(ServiceImpl);
243};
244
245WeaveClient::WeaveClient(const std::weak_ptr<ServiceImpl>& service)
246 : service_{service} {}
247
248android::binder::Status WeaveClient::onServiceConnected(
249 const android::sp<android::weave::IWeaveService>& service) {
250 LOG(INFO) << "Weave service connection established successfully";
251 auto service_proxy = service_.lock();
252 if (service_proxy)
253 service_proxy->OnServiceConnected(service);
254 return android::binder::Status::ok();
255}
256
257android::binder::Status WeaveClient::onCommand(
258 const android::String16& componentName,
259 const android::String16& commandName,
260 const android::sp<android::weave::IWeaveCommand>& command) {
261 auto service_proxy = service_.lock();
262 if (service_proxy) {
263 service_proxy->OnCommand(ToString(componentName), ToString(commandName),
264 command);
265 } else {
266 command->abort(android::String16{"service_unavailable"},
267 android::String16{"Command handler is unavailable"});
268 }
269 return android::binder::Status::ok();
270}
271
Alex Vakulenko3faf0372016-01-08 12:22:28 -0800272NotificationListener::NotificationListener(
273 const std::weak_ptr<ServiceImpl>& service)
274 : service_{service} {}
275
276android::binder::Status NotificationListener::notifyServiceManagerChange(
277 const std::vector<int>& notificationIds) {
278 auto service_proxy = service_.lock();
279 if (service_proxy)
280 service_proxy->OnNotification(notificationIds);
281 return android::binder::Status::ok();
282}
283
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800284ServiceImpl::ServiceImpl(android::BinderWrapper* binder_wrapper,
285 brillo::MessageLoop* message_loop,
286 ServiceSubscription* service_subscription,
287 const ConnectionCallback& connection_callback)
288 : binder_wrapper_{binder_wrapper},
289 message_loop_{message_loop},
290 service_subscription_{service_subscription},
291 connection_callback_{connection_callback} {
292}
293
294ServiceImpl::~ServiceImpl() {
295 if (weave_service_.get()) {
296 android::sp<android::IBinder> binder =
297 android::IInterface::asBinder(weave_service_);
298 binder_wrapper_->UnregisterForDeathNotifications(binder);
299 }
300}
301
302bool ServiceImpl::AddComponent(const std::string& component,
303 const std::vector<std::string>& traits,
304 brillo::ErrorPtr* error) {
305 CHECK(weave_service_.get());
306 std::vector<android::String16> trait_list;
307 auto to_string16 = [](const std::string& name) {
308 return android::String16{name.c_str()};
309 };
310 std::transform(traits.begin(), traits.end(), std::back_inserter(trait_list),
311 to_string16);
312 return StatusToError(weave_service_->addComponent(to_string16(component),
313 trait_list),
314 error);
315}
316
317void ServiceImpl::AddCommandHandler(const std::string& component,
Alex Vakulenkoc9844512016-01-07 10:06:23 -0800318 const std::string& trait_name,
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800319 const std::string& command_name,
320 const CommandHandlerCallback& callback) {
321 CHECK(!component.empty() && !command_name.empty());
322 CHECK(weave_service_.get());
323
Alex Vakulenkoc9844512016-01-07 10:06:23 -0800324 std::string full_command_name =
325 base::StringPrintf("%s.%s", trait_name.c_str(), command_name.c_str());
326
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800327 CommandHandlerEntry entry;
328 entry.component = component;
Alex Vakulenkoc9844512016-01-07 10:06:23 -0800329 entry.command_name = full_command_name;
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800330 entry.callback = callback;
331 command_handlers_.push_back(std::move(entry));
332
333 auto status = weave_service_->registerCommandHandler(
334 android::String16{component.c_str()},
Alex Vakulenkoc9844512016-01-07 10:06:23 -0800335 android::String16{full_command_name.c_str()});
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800336 CHECK(status.isOk());
337}
338
339bool ServiceImpl::SetStateProperties(const std::string& component,
340 const brillo::VariantDictionary& dict,
341 brillo::ErrorPtr* error) {
342 CHECK(!component.empty());
343 CHECK(weave_service_.get());
344 auto properties = details::VariantDictionaryToDictionaryValue(dict, error);
345 if (!properties)
346 return false;
347 return StatusToError(weave_service_->updateState(ToString16(component),
348 ToString16(*properties)),
349 error);
350}
351
352bool ServiceImpl::SetStateProperty(const std::string& component,
Alex Vakulenkoc9844512016-01-07 10:06:23 -0800353 const std::string& trait_name,
354 const std::string& property_name,
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800355 const brillo::Any& value,
356 brillo::ErrorPtr* error) {
Alex Vakulenkoc9844512016-01-07 10:06:23 -0800357 std::string name =
358 base::StringPrintf("%s.%s", trait_name.c_str(), property_name.c_str());
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800359 return SetStateProperties(component, brillo::VariantDictionary{{name, value}},
360 error);
361}
362
Alex Vakulenko3faf0372016-01-08 12:22:28 -0800363void ServiceImpl::SetPairingInfoListener(const PairingInfoCallback& callback) {
364 pairing_info_callback_ = callback;
365 if (!pairing_info_callback_.is_null() &&
366 !pairing_info_.session_id.empty() &&
367 !pairing_info_.pairing_mode.empty() &&
368 !pairing_info_.pairing_code.empty()) {
369 callback.Run(&pairing_info_);
370 }
371}
372
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800373void ServiceImpl::BeginConnect() {
374 message_loop_->PostTask(FROM_HERE,
375 base::Bind(&ServiceImpl::TryConnecting,
376 weak_ptr_factory_.GetWeakPtr()));
377}
378
379void ServiceImpl::OnServiceConnected(
380 const android::sp<android::weave::IWeaveService>& service) {
381 weave_service_ = service;
382 connection_callback_.Run(shared_from_this());
383 // Call this last in case the binder object is already gone and the death
384 // notification callback (OnWeaveServiceDisconnected) is invoked immediately.
385 // In this case, the instance of ServiceImpl will get destroyed before
386 // RegisterForDeathNotifications returns.
387 binder_wrapper_->RegisterForDeathNotifications(
388 android::IInterface::asBinder(service),
389 base::Bind(&ServiceImpl::OnWeaveServiceDisconnected,
390 weak_ptr_factory_.GetWeakPtr()));
391}
392
393void ServiceImpl::OnCommand(
394 const std::string& component_name,
395 const std::string& command_name,
396 const android::sp<android::weave::IWeaveCommand>& command) {
397 VLOG(2) << "Weave command received for component '" << component_name << "': "
398 << command_name;
399 for (const auto& entry : command_handlers_) {
400 if (entry.component == component_name &&
401 entry.command_name == command_name) {
402 std::unique_ptr<Command> command_instance{new Command{command}};
403 return entry.callback.Run(std::move(command_instance));
404 }
405 }
406 LOG(WARNING) << "Unexpected command notification. Command = " << command_name
407 << ", component = " << component_name;
408}
409
410void ServiceImpl::TryConnecting() {
411 LOG(INFO) << "Connecting to weave service over binder";
412 android::sp<android::IBinder> binder =
413 binder_wrapper_->GetService(weaved::binder::kWeaveServiceName);
414 if (!binder.get()) {
415 LOG(INFO) << "Weave service is not available yet. Will try again later";
416 message_loop_->PostDelayedTask(FROM_HERE,
417 base::Bind(&ServiceImpl::TryConnecting,
418 weak_ptr_factory_.GetWeakPtr()),
419 base::TimeDelta::FromSeconds(1));
420 return;
421 }
422
Alex Vakulenko3faf0372016-01-08 12:22:28 -0800423 weave_service_manager_ =
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800424 android::interface_cast<android::weave::IWeaveServiceManager>(binder);
425 android::sp<WeaveClient> weave_client = new WeaveClient{shared_from_this()};
Alex Vakulenko3faf0372016-01-08 12:22:28 -0800426 weave_service_manager_->connect(weave_client);
427 android::sp<NotificationListener> notification_listener =
428 new NotificationListener{shared_from_this()};
429 weave_service_manager_->registerNotificationListener(notification_listener);
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800430}
431
432void ServiceImpl::OnWeaveServiceDisconnected() {
433 weave_service_.clear();
434 // Need to create a new instance of service to invalidate existing weak
435 // pointers.
436 auto service = std::make_shared<ServiceImpl>(
437 binder_wrapper_, message_loop_, service_subscription_,
438 connection_callback_);
439 service->BeginConnect();
440 // The subscription object owns this instance.
441 // Calling SetService() will destroy |this|.
442 service_subscription_->SetService(service);
443 // Do not call any methods or use resources of ServiceImpl after this point
444 // because the object is destroyed now.
445}
446
Alex Vakulenko3faf0372016-01-08 12:22:28 -0800447void ServiceImpl::OnNotification(const std::vector<int>& notification_ids) {
448 bool pairing_info_changed = false;
449 using NotificationListener =
450 android::weave::IWeaveServiceManagerNotificationListener;
451 android::String16 string_value;
452 for (int id : notification_ids) {
453 switch (id) {
454 case NotificationListener::PAIRING_SESSION_ID:
455 if (weave_service_manager_->getPairingSessionId(&string_value).isOk()) {
456 pairing_info_changed = true;
457 pairing_info_.session_id = ToString(string_value);
458 }
459 break;
460 case NotificationListener::PAIRING_MODE:
461 if (weave_service_manager_->getPairingMode(&string_value).isOk()) {
462 pairing_info_changed = true;
463 pairing_info_.pairing_mode = ToString(string_value);
464 }
465 break;
466 case NotificationListener::PAIRING_CODE:
467 if (weave_service_manager_->getPairingCode(&string_value).isOk()) {
468 pairing_info_changed = true;
469 pairing_info_.pairing_code = ToString(string_value);
470 }
471 break;
472 }
473 }
474
475 if (!pairing_info_changed || pairing_info_callback_.is_null())
476 return;
477
478 if (pairing_info_.session_id.empty() || pairing_info_.pairing_mode.empty() ||
479 pairing_info_.pairing_code.empty()) {
480 pairing_info_callback_.Run(nullptr);
481 } else {
482 pairing_info_callback_.Run(&pairing_info_);
483 }
484}
485
Alex Vakulenkoae29f7d2015-12-21 16:30:37 -0800486std::unique_ptr<Service::Subscription> Service::Connect(
487 brillo::MessageLoop* message_loop,
488 const ConnectionCallback& callback) {
489 std::unique_ptr<ServiceSubscription> subscription{new ServiceSubscription};
490 auto service = std::make_shared<ServiceImpl>(
491 android::BinderWrapper::GetOrCreateInstance(), message_loop,
492 subscription.get(), callback);
493 subscription->SetService(service);
494 service->BeginConnect();
495 return std::move(subscription);
496}
497
498} // namespace weaved