1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chromeos/dbus/shill_service_client.h"
8 #include "base/memory/weak_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/stl_util.h"
11 #include "base/values.h"
12 #include "chromeos/dbus/shill_property_changed_observer.h"
13 #include "chromeos/network/network_event_log.h"
15 #include "dbus/message.h"
16 #include "dbus/object_proxy.h"
17 #include "third_party/cros_system_api/dbus/service_constants.h"
23 #ifndef DBUS_ERROR_UNKNOWN_OBJECT
24 // The linux_chromeos ASAN builder has an older version of dbus-protocol.h
25 // so make sure this is defined.
26 #define DBUS_ERROR_UNKNOWN_OBJECT "org.freedesktop.DBus.Error.UnknownObject"
29 // Error callback for GetProperties.
30 void OnGetDictionaryError(
31 const std::string
& method_name
,
32 const dbus::ObjectPath
& service_path
,
33 const ShillServiceClient::DictionaryValueCallback
& callback
,
34 const std::string
& error_name
,
35 const std::string
& error_message
) {
36 const std::string log_string
=
37 "Failed to call org.chromium.shill.Service." + method_name
+
38 " for: " + service_path
.value() + ": " +
39 error_name
+ ": " + error_message
;
41 // Suppress ERROR messages for UnknownMethod/Object" since this can
42 // happen under normal conditions. See crbug.com/130660 and crbug.com/222210.
43 if (error_name
== DBUS_ERROR_UNKNOWN_METHOD
||
44 error_name
== DBUS_ERROR_UNKNOWN_OBJECT
)
45 VLOG(1) << log_string
;
47 LOG(ERROR
) << log_string
;
49 base::DictionaryValue empty_dictionary
;
50 callback
.Run(DBUS_METHOD_CALL_FAILURE
, empty_dictionary
);
53 // The ShillServiceClient implementation.
54 class ShillServiceClientImpl
: public ShillServiceClient
{
56 explicit ShillServiceClientImpl()
58 weak_ptr_factory_(this) {
61 ~ShillServiceClientImpl() override
{
62 for (HelperMap::iterator iter
= helpers_
.begin();
63 iter
!= helpers_
.end(); ++iter
) {
64 ShillClientHelper
* helper
= iter
->second
;
65 bus_
->RemoveObjectProxy(shill::kFlimflamServiceName
,
66 helper
->object_proxy()->object_path(),
67 base::Bind(&base::DoNothing
));
72 void AddPropertyChangedObserver(
73 const dbus::ObjectPath
& service_path
,
74 ShillPropertyChangedObserver
* observer
) override
{
75 GetHelper(service_path
)->AddPropertyChangedObserver(observer
);
78 void RemovePropertyChangedObserver(
79 const dbus::ObjectPath
& service_path
,
80 ShillPropertyChangedObserver
* observer
) override
{
81 GetHelper(service_path
)->RemovePropertyChangedObserver(observer
);
84 void GetProperties(const dbus::ObjectPath
& service_path
,
85 const DictionaryValueCallback
& callback
) override
{
86 dbus::MethodCall
method_call(shill::kFlimflamServiceInterface
,
87 shill::kGetPropertiesFunction
);
88 GetHelper(service_path
)->CallDictionaryValueMethodWithErrorCallback(
90 base::Bind(callback
, DBUS_METHOD_CALL_SUCCESS
),
91 base::Bind(&OnGetDictionaryError
, "GetProperties",
92 service_path
, callback
));
95 void SetProperty(const dbus::ObjectPath
& service_path
,
96 const std::string
& name
,
97 const base::Value
& value
,
98 const base::Closure
& callback
,
99 const ErrorCallback
& error_callback
) override
{
100 dbus::MethodCall
method_call(shill::kFlimflamServiceInterface
,
101 shill::kSetPropertyFunction
);
102 dbus::MessageWriter
writer(&method_call
);
103 writer
.AppendString(name
);
104 ShillClientHelper::AppendValueDataAsVariant(&writer
, value
);
105 GetHelper(service_path
)->CallVoidMethodWithErrorCallback(&method_call
,
110 void SetProperties(const dbus::ObjectPath
& service_path
,
111 const base::DictionaryValue
& properties
,
112 const base::Closure
& callback
,
113 const ErrorCallback
& error_callback
) override
{
114 dbus::MethodCall
method_call(shill::kFlimflamServiceInterface
,
115 shill::kSetPropertiesFunction
);
116 dbus::MessageWriter
writer(&method_call
);
117 ShillClientHelper::AppendServicePropertiesDictionary(&writer
, properties
);
118 GetHelper(service_path
)->CallVoidMethodWithErrorCallback(&method_call
,
123 void ClearProperty(const dbus::ObjectPath
& service_path
,
124 const std::string
& name
,
125 const base::Closure
& callback
,
126 const ErrorCallback
& error_callback
) override
{
127 dbus::MethodCall
method_call(shill::kFlimflamServiceInterface
,
128 shill::kClearPropertyFunction
);
129 dbus::MessageWriter
writer(&method_call
);
130 writer
.AppendString(name
);
131 GetHelper(service_path
)->CallVoidMethodWithErrorCallback(&method_call
,
136 void ClearProperties(const dbus::ObjectPath
& service_path
,
137 const std::vector
<std::string
>& names
,
138 const ListValueCallback
& callback
,
139 const ErrorCallback
& error_callback
) override
{
140 dbus::MethodCall
method_call(shill::kFlimflamServiceInterface
,
141 shill::kClearPropertiesFunction
);
142 dbus::MessageWriter
writer(&method_call
);
143 writer
.AppendArrayOfStrings(names
);
144 GetHelper(service_path
)->CallListValueMethodWithErrorCallback(
150 void Connect(const dbus::ObjectPath
& service_path
,
151 const base::Closure
& callback
,
152 const ErrorCallback
& error_callback
) override
{
153 dbus::MethodCall
method_call(shill::kFlimflamServiceInterface
,
154 shill::kConnectFunction
);
155 GetHelper(service_path
)->CallVoidMethodWithErrorCallback(
156 &method_call
, callback
, error_callback
);
159 void Disconnect(const dbus::ObjectPath
& service_path
,
160 const base::Closure
& callback
,
161 const ErrorCallback
& error_callback
) override
{
162 dbus::MethodCall
method_call(shill::kFlimflamServiceInterface
,
163 shill::kDisconnectFunction
);
164 GetHelper(service_path
)->CallVoidMethodWithErrorCallback(&method_call
,
169 void Remove(const dbus::ObjectPath
& service_path
,
170 const base::Closure
& callback
,
171 const ErrorCallback
& error_callback
) override
{
172 dbus::MethodCall
method_call(shill::kFlimflamServiceInterface
,
173 shill::kRemoveServiceFunction
);
174 GetHelper(service_path
)->CallVoidMethodWithErrorCallback(&method_call
,
179 void ActivateCellularModem(const dbus::ObjectPath
& service_path
,
180 const std::string
& carrier
,
181 const base::Closure
& callback
,
182 const ErrorCallback
& error_callback
) override
{
183 dbus::MethodCall
method_call(shill::kFlimflamServiceInterface
,
184 shill::kActivateCellularModemFunction
);
185 dbus::MessageWriter
writer(&method_call
);
186 writer
.AppendString(carrier
);
187 GetHelper(service_path
)->CallVoidMethodWithErrorCallback(&method_call
,
192 void CompleteCellularActivation(
193 const dbus::ObjectPath
& service_path
,
194 const base::Closure
& callback
,
195 const ErrorCallback
& error_callback
) override
{
196 dbus::MethodCall
method_call(shill::kFlimflamServiceInterface
,
197 shill::kCompleteCellularActivationFunction
);
198 dbus::MessageWriter
writer(&method_call
);
199 GetHelper(service_path
)->CallVoidMethodWithErrorCallback(&method_call
,
204 void GetLoadableProfileEntries(
205 const dbus::ObjectPath
& service_path
,
206 const DictionaryValueCallback
& callback
) override
{
207 dbus::MethodCall
method_call(shill::kFlimflamServiceInterface
,
208 shill::kGetLoadableProfileEntriesFunction
);
209 GetHelper(service_path
)->CallDictionaryValueMethodWithErrorCallback(
211 base::Bind(callback
, DBUS_METHOD_CALL_SUCCESS
),
212 base::Bind(&OnGetDictionaryError
, "GetLoadableProfileEntries",
213 service_path
, callback
));
216 ShillServiceClient::TestInterface
* GetTestInterface() override
{
221 void Init(dbus::Bus
* bus
) override
{ bus_
= bus
; }
224 typedef std::map
<std::string
, ShillClientHelper
*> HelperMap
;
226 // Returns the corresponding ShillClientHelper for the profile.
227 ShillClientHelper
* GetHelper(const dbus::ObjectPath
& service_path
) {
228 HelperMap::iterator it
= helpers_
.find(service_path
.value());
229 if (it
!= helpers_
.end())
232 // There is no helper for the profile, create it.
233 NET_LOG_DEBUG("AddShillClientHelper", service_path
.value());
234 dbus::ObjectProxy
* object_proxy
=
235 bus_
->GetObjectProxy(shill::kFlimflamServiceName
, service_path
);
236 ShillClientHelper
* helper
= new ShillClientHelper(object_proxy
);
237 helper
->SetReleasedCallback(
238 base::Bind(&ShillServiceClientImpl::NotifyReleased
,
239 weak_ptr_factory_
.GetWeakPtr()));
240 helper
->MonitorPropertyChanged(shill::kFlimflamServiceInterface
);
241 helpers_
.insert(HelperMap::value_type(service_path
.value(), helper
));
245 void NotifyReleased(ShillClientHelper
* helper
) {
246 // New Shill Service DBus objects are created relatively frequently, so
247 // remove them when they become inactive (no observers and no active method
249 dbus::ObjectPath object_path
= helper
->object_proxy()->object_path();
250 // Make sure we don't release the proxy used by ShillManagerClient ("/").
251 // This shouldn't ever happen, but might if a bug in the code requests
252 // a service with path "/", or a bug in Shill passes "/" as a service path.
253 // Either way this would cause an invalid memory access in
254 // ShillManagerClient, see crbug.com/324849.
255 if (object_path
== dbus::ObjectPath(shill::kFlimflamServicePath
)) {
256 NET_LOG_ERROR("ShillServiceClient service has invalid path",
257 shill::kFlimflamServicePath
);
260 NET_LOG_DEBUG("RemoveShillClientHelper", object_path
.value());
261 bus_
->RemoveObjectProxy(shill::kFlimflamServiceName
,
262 object_path
, base::Bind(&base::DoNothing
));
263 helpers_
.erase(object_path
.value());
269 base::WeakPtrFactory
<ShillServiceClientImpl
> weak_ptr_factory_
;
271 DISALLOW_COPY_AND_ASSIGN(ShillServiceClientImpl
);
276 ShillServiceClient::ShillServiceClient() {}
278 ShillServiceClient::~ShillServiceClient() {}
281 ShillServiceClient
* ShillServiceClient::Create() {
282 return new ShillServiceClientImpl();
285 } // namespace chromeos