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. 4 #include "chromeos/dbus/modem_messaging_client.h" 5 6 #include <map> 7 #include <utility> 8 9 #include "base/bind.h" 10 #include "base/memory/weak_ptr.h" 11 #include "base/message_loop/message_loop.h" 12 #include "base/stl_util.h" 13 #include "base/values.h" 14 #include "dbus/bus.h" 15 #include "dbus/message.h" 16 #include "dbus/object_proxy.h" 17 #include "third_party/cros_system_api/dbus/service_constants.h" 18 19 namespace chromeos { 20 21 namespace { 22 23 // A class which makes method calls for SMS services via the 24 // org.freedesktop.ModemManager1.Messaging object. 25 class ModemMessagingProxy { 26 public: 27 typedef ModemMessagingClient::SmsReceivedHandler SmsReceivedHandler; 28 typedef ModemMessagingClient::ListCallback ListCallback; 29 typedef ModemMessagingClient::DeleteCallback DeleteCallback; 30 31 ModemMessagingProxy(dbus::Bus* bus, 32 const std::string& service_name, 33 const dbus::ObjectPath& object_path) 34 : bus_(bus), 35 proxy_(bus->GetObjectProxy(service_name, object_path)), 36 service_name_(service_name), 37 weak_ptr_factory_(this) { 38 proxy_->ConnectToSignal( 39 modemmanager::kModemManager1MessagingInterface, 40 modemmanager::kSMSAddedSignal, 41 base::Bind(&ModemMessagingProxy::OnSmsAdded, 42 weak_ptr_factory_.GetWeakPtr()), 43 base::Bind(&ModemMessagingProxy::OnSignalConnected, 44 weak_ptr_factory_.GetWeakPtr())); 45 } 46 virtual ~ModemMessagingProxy() {} 47 48 // Sets SmsReceived signal handler. 49 void SetSmsReceivedHandler(const SmsReceivedHandler& handler) { 50 DCHECK(sms_received_handler_.is_null()); 51 sms_received_handler_ = handler; 52 } 53 54 // Resets SmsReceived signal handler. 55 void ResetSmsReceivedHandler() { 56 sms_received_handler_.Reset(); 57 } 58 59 // Calls Delete method. 60 void Delete(const dbus::ObjectPath& message_path, 61 const DeleteCallback& callback) { 62 dbus::MethodCall method_call(modemmanager::kModemManager1MessagingInterface, 63 modemmanager::kSMSDeleteFunction); 64 dbus::MessageWriter writer(&method_call); 65 writer.AppendObjectPath(message_path); 66 proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 67 base::Bind(&ModemMessagingProxy::OnDelete, 68 weak_ptr_factory_.GetWeakPtr(), 69 callback)); 70 } 71 72 // Calls List method. 73 virtual void List(const ListCallback& callback) { 74 dbus::MethodCall method_call(modemmanager::kModemManager1MessagingInterface, 75 modemmanager::kSMSListFunction); 76 proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 77 base::Bind(&ModemMessagingProxy::OnList, 78 weak_ptr_factory_.GetWeakPtr(), 79 callback)); 80 } 81 82 private: 83 // Handles SmsAdded signal. 84 void OnSmsAdded(dbus::Signal* signal) { 85 dbus::ObjectPath message_path; 86 bool complete = false; 87 dbus::MessageReader reader(signal); 88 if (!reader.PopObjectPath(&message_path) || 89 !reader.PopBool(&complete)) { 90 LOG(ERROR) << "Invalid signal: " << signal->ToString(); 91 return; 92 } 93 if (!sms_received_handler_.is_null()) { 94 sms_received_handler_.Run(message_path, complete); 95 } 96 } 97 98 // Handles responses of Delete method calls. 99 void OnDelete(const DeleteCallback& callback, dbus::Response* response) { 100 if (!response) 101 return; 102 callback.Run(); 103 } 104 105 // Handles responses of List method calls. 106 void OnList(const ListCallback& callback, dbus::Response* response) { 107 if (!response) 108 return; 109 dbus::MessageReader reader(response); 110 std::vector<dbus::ObjectPath> sms_paths; 111 if (!reader.PopArrayOfObjectPaths(&sms_paths)) 112 LOG(WARNING) << "Invalid response: " << response->ToString(); 113 callback.Run(sms_paths); 114 } 115 116 // Handles the result of signal connection setup. 117 void OnSignalConnected(const std::string& interface, 118 const std::string& signal, 119 bool succeeded) { 120 LOG_IF(ERROR, !succeeded) << "Connect to " << interface << " " 121 << signal << " failed."; 122 } 123 124 dbus::Bus* bus_; 125 dbus::ObjectProxy* proxy_; 126 std::string service_name_; 127 SmsReceivedHandler sms_received_handler_; 128 129 // Note: This should remain the last member so it'll be destroyed and 130 // invalidate its weak pointers before any other members are destroyed. 131 base::WeakPtrFactory<ModemMessagingProxy> weak_ptr_factory_; 132 133 DISALLOW_COPY_AND_ASSIGN(ModemMessagingProxy); 134 }; 135 136 class CHROMEOS_EXPORT ModemMessagingClientImpl : public ModemMessagingClient { 137 public: 138 explicit ModemMessagingClientImpl(dbus::Bus *bus) 139 : bus_(bus), 140 proxies_deleter_(&proxies_) { 141 } 142 143 // ModemMessagingClient override. 144 virtual void SetSmsReceivedHandler( 145 const std::string& service_name, 146 const dbus::ObjectPath& object_path, 147 const SmsReceivedHandler& handler) OVERRIDE { 148 GetProxy(service_name, object_path)->SetSmsReceivedHandler(handler); 149 } 150 151 // ModemMessagingClient override. 152 virtual void ResetSmsReceivedHandler( 153 const std::string& service_name, 154 const dbus::ObjectPath& object_path) OVERRIDE { 155 GetProxy(service_name, object_path)->ResetSmsReceivedHandler(); 156 } 157 158 // ModemMessagingClient override. 159 virtual void Delete(const std::string& service_name, 160 const dbus::ObjectPath& object_path, 161 const dbus::ObjectPath& sms_path, 162 const DeleteCallback& callback) OVERRIDE { 163 GetProxy(service_name, object_path)->Delete(sms_path, callback); 164 } 165 166 // ModemMessagingClient override. 167 virtual void List(const std::string& service_name, 168 const dbus::ObjectPath& object_path, 169 const ListCallback& callback) OVERRIDE { 170 GetProxy(service_name, object_path)->List(callback); 171 } 172 173 private: 174 typedef std::map<std::pair<std::string, std::string>, ModemMessagingProxy*> 175 ProxyMap; 176 177 // Returns a SMSProxy for the given service name and object path. 178 ModemMessagingProxy* GetProxy(const std::string& service_name, 179 const dbus::ObjectPath& object_path) { 180 const ProxyMap::key_type key(service_name, object_path.value()); 181 ProxyMap::iterator it = proxies_.find(key); 182 if (it != proxies_.end()) 183 return it->second; 184 185 // There is no proxy for the service_name and object_path, create it. 186 ModemMessagingProxy* proxy 187 = new ModemMessagingProxy(bus_, service_name, object_path); 188 proxies_.insert(ProxyMap::value_type(key, proxy)); 189 return proxy; 190 } 191 192 dbus::Bus* bus_; 193 ProxyMap proxies_; 194 STLValueDeleter<ProxyMap> proxies_deleter_; 195 196 DISALLOW_COPY_AND_ASSIGN(ModemMessagingClientImpl); 197 }; 198 199 class CHROMEOS_EXPORT ModemMessagingClientStubImpl 200 : public ModemMessagingClient { 201 public: 202 ModemMessagingClientStubImpl() {} 203 virtual ~ModemMessagingClientStubImpl() {} 204 205 // ModemMessagingClient override. 206 virtual void SetSmsReceivedHandler( 207 const std::string& service_name, 208 const dbus::ObjectPath& object_path, 209 const SmsReceivedHandler& handler) OVERRIDE { 210 DCHECK(sms_received_handler_.is_null()); 211 sms_received_handler_ = handler; 212 } 213 214 // ModemMessagingClient override. 215 virtual void ResetSmsReceivedHandler( 216 const std::string& service_name, 217 const dbus::ObjectPath& object_path) OVERRIDE { 218 sms_received_handler_.Reset(); 219 } 220 221 // ModemMessagingClient override. 222 virtual void Delete(const std::string& service_name, 223 const dbus::ObjectPath& object_path, 224 const dbus::ObjectPath& sms_path, 225 const DeleteCallback& callback) OVERRIDE { 226 std::vector<dbus::ObjectPath>::iterator it( 227 find(message_paths_.begin(), message_paths_.end(), sms_path)); 228 if (it != message_paths_.end()) 229 message_paths_.erase(it); 230 callback.Run(); 231 } 232 233 // ModemMessagingClient override. 234 virtual void List(const std::string& service_name, 235 const dbus::ObjectPath& object_path, 236 const ListCallback& callback) OVERRIDE { 237 // This entire ModemMessagingClientStubImpl is for testing. 238 // Calling List with |service_name| equal to "AddSMS" allows unit 239 // tests to confirm that the sms_received_handler is functioning. 240 if (service_name == "AddSMS") { 241 std::vector<dbus::ObjectPath> no_paths; 242 const dbus::ObjectPath kSmsPath("/SMS/0"); 243 message_paths_.push_back(kSmsPath); 244 if (!sms_received_handler_.is_null()) 245 sms_received_handler_.Run(kSmsPath, true); 246 callback.Run(no_paths); 247 } else { 248 callback.Run(message_paths_); 249 } 250 } 251 252 private: 253 SmsReceivedHandler sms_received_handler_; 254 std::vector<dbus::ObjectPath> message_paths_; 255 256 DISALLOW_COPY_AND_ASSIGN(ModemMessagingClientStubImpl); 257 }; 258 259 } // namespace 260 261 //////////////////////////////////////////////////////////////////////////////// 262 // ModemMessagingClient 263 264 ModemMessagingClient::ModemMessagingClient() {} 265 266 ModemMessagingClient::~ModemMessagingClient() {} 267 268 269 // static 270 ModemMessagingClient* ModemMessagingClient::Create( 271 DBusClientImplementationType type, 272 dbus::Bus* bus) { 273 if (type == REAL_DBUS_CLIENT_IMPLEMENTATION) { 274 return new ModemMessagingClientImpl(bus); 275 } 276 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type); 277 return new ModemMessagingClientStubImpl(); 278 } 279 280 281 } // namespace chromeos 282