1//
2// Copyright (C) 2015 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "shill/dbus/chromeos_modem_manager_proxy.h"
18
19#include "shill/cellular/modem_manager.h"
20#include "shill/event_dispatcher.h"
21#include "shill/logging.h"
22
23using std::string;
24using std::vector;
25
26namespace shill {
27
28namespace Logging {
29static auto kModuleLogScope = ScopeLogger::kDBus;
30static string ObjectID(const dbus::ObjectPath* p) { return p->value(); }
31}  // namespace Logging
32
33ChromeosModemManagerProxy::ChromeosModemManagerProxy(
34    EventDispatcher* dispatcher,
35    const scoped_refptr<dbus::Bus>& bus,
36    ModemManagerClassic* manager,
37    const std::string& path,
38    const std::string& service,
39    const base::Closure& service_appeared_callback,
40    const base::Closure& service_vanished_callback)
41    : proxy_(
42        new org::freedesktop::ModemManagerProxy(
43            bus, service, dbus::ObjectPath(path))),
44      dispatcher_(dispatcher),
45      manager_(manager),
46      service_appeared_callback_(service_appeared_callback),
47      service_vanished_callback_(service_vanished_callback),
48      service_available_(false) {
49  // Register signal handlers.
50  proxy_->RegisterDeviceAddedSignalHandler(
51      base::Bind(&ChromeosModemManagerProxy::DeviceAdded,
52                 weak_factory_.GetWeakPtr()),
53      base::Bind(&ChromeosModemManagerProxy::OnSignalConnected,
54                 weak_factory_.GetWeakPtr()));
55  proxy_->RegisterDeviceRemovedSignalHandler(
56      base::Bind(&ChromeosModemManagerProxy::DeviceRemoved,
57                 weak_factory_.GetWeakPtr()),
58      base::Bind(&ChromeosModemManagerProxy::OnSignalConnected,
59                 weak_factory_.GetWeakPtr()));
60
61  // Monitor service owner changes. This callback lives for the lifetime of
62  // the ObjectProxy.
63  proxy_->GetObjectProxy()->SetNameOwnerChangedCallback(
64      base::Bind(&ChromeosModemManagerProxy::OnServiceOwnerChanged,
65                 weak_factory_.GetWeakPtr()));
66
67  // One time callback when service becomes available.
68  proxy_->GetObjectProxy()->WaitForServiceToBeAvailable(
69      base::Bind(&ChromeosModemManagerProxy::OnServiceAvailable,
70                 weak_factory_.GetWeakPtr()));
71}
72
73ChromeosModemManagerProxy::~ChromeosModemManagerProxy() {}
74
75vector<string> ChromeosModemManagerProxy::EnumerateDevices() {
76  SLOG(&proxy_->GetObjectPath(), 2) << __func__;
77  if (!service_available_) {
78    LOG(ERROR) << "Service not available";
79    return vector<string>();
80  }
81
82  vector<dbus::ObjectPath> device_paths;
83  brillo::ErrorPtr error;
84  if (!proxy_->EnumerateDevices(&device_paths, &error)) {
85    LOG(ERROR) << "Failed to enumerate devices: " << error->GetCode()
86               << " " << error->GetMessage();
87    return vector<string>();
88  }
89  vector<string> device_rpcids;
90  KeyValueStore::ConvertPathsToRpcIdentifiers(device_paths, &device_rpcids);
91  return device_rpcids;
92}
93
94void ChromeosModemManagerProxy::DeviceAdded(const dbus::ObjectPath& device) {
95  SLOG(&proxy_->GetObjectPath(), 2) << __func__;
96  manager_->OnDeviceAdded(device.value());
97}
98
99void ChromeosModemManagerProxy::DeviceRemoved(const dbus::ObjectPath& device) {
100  SLOG(&proxy_->GetObjectPath(), 2) << __func__;
101  manager_->OnDeviceRemoved(device.value());
102}
103
104void ChromeosModemManagerProxy::OnServiceAvailable(bool available) {
105  LOG(INFO) << __func__ << ": " << available;
106
107  // The callback might invoke calls to the ObjectProxy, so defer the callback
108  // to event loop.
109  if (available && !service_appeared_callback_.is_null()) {
110    dispatcher_->PostTask(service_appeared_callback_);
111  } else if (!available && !service_vanished_callback_.is_null()) {
112    dispatcher_->PostTask(service_vanished_callback_);
113  }
114  service_available_ = available;
115}
116
117void ChromeosModemManagerProxy::OnServiceOwnerChanged(
118    const string& old_owner, const string& new_owner) {
119  LOG(INFO) << __func__ << " old: " << old_owner << " new: " << new_owner;
120  if (new_owner.empty()) {
121    OnServiceAvailable(false);
122  } else {
123    OnServiceAvailable(true);
124  }
125}
126
127void ChromeosModemManagerProxy::OnSignalConnected(
128    const string& interface_name, const string& signal_name, bool success) {
129  SLOG(&proxy_->GetObjectPath(), 2) << __func__
130      << "interface: " << interface_name
131             << " signal: " << signal_name << "success: " << success;
132  if (!success) {
133    LOG(ERROR) << "Failed to connect signal " << signal_name
134        << " to interface " << interface_name;
135  }
136}
137
138}  // namespace shill
139