Home | History | Annotate | Download | only in dbus
      1 // Copyright 2013 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 
      5 #include "chromeos/dbus/nfc_client_helpers.h"
      6 
      7 #include "base/stl_util.h"
      8 #include "dbus/values_util.h"
      9 
     10 namespace chromeos {
     11 namespace nfc_client_helpers {
     12 
     13 const char kNoResponseError[] = "org.chromium.Error.NoResponse";
     14 const char kUnknownObjectError[] = "org.chromium.Error.UnknownObject";
     15 
     16 void OnSuccess(const base::Closure& callback, dbus::Response* response) {
     17   DCHECK(response);
     18   callback.Run();
     19 }
     20 
     21 void OnError(const ErrorCallback& error_callback,
     22              dbus::ErrorResponse* response) {
     23   // Error response has optional error message argument.
     24   std::string error_name;
     25   std::string error_message;
     26   if (response) {
     27     dbus::MessageReader reader(response);
     28     error_name = response->GetErrorName();
     29     reader.PopString(&error_message);
     30   } else {
     31     error_name = kNoResponseError;
     32     error_message = "";
     33   }
     34   error_callback.Run(error_name, error_message);
     35 }
     36 
     37 DBusObjectMap::DBusObjectMap(const std::string& service_name,
     38                              Delegate* delegate,
     39                              dbus::Bus* bus)
     40     : bus_(bus),
     41       service_name_(service_name),
     42       delegate_(delegate) {
     43   DCHECK(bus_);
     44   DCHECK(delegate_);
     45 }
     46 
     47 DBusObjectMap::~DBusObjectMap() {
     48   // Clean up the Properties structures. We don't explicitly delete the object
     49   // proxies, as they are owned by dbus::Bus.
     50   for (ObjectMap::iterator iter = object_map_.begin();
     51        iter != object_map_.end(); ++iter) {
     52     const dbus::ObjectPath& object_path = iter->first;
     53     ObjectPropertyPair pair = iter->second;
     54     delegate_->ObjectRemoved(object_path);
     55     CleanUpObjectPropertyPair(pair);
     56   }
     57 }
     58 
     59 dbus::ObjectProxy* DBusObjectMap::GetObjectProxy(
     60     const dbus::ObjectPath& object_path) {
     61   return GetObjectPropertyPair(object_path).first;
     62 }
     63 
     64 NfcPropertySet* DBusObjectMap::GetObjectProperties(
     65     const dbus::ObjectPath& object_path) {
     66   return GetObjectPropertyPair(object_path).second;
     67 }
     68 
     69 void DBusObjectMap::UpdateObjects(const ObjectPathVector& object_paths) {
     70   // This set is used to query if an object path was removed, while updating
     71   // the removed paths below. The iterator is used as a hint to accelerate
     72   // insertion.
     73   std::set<dbus::ObjectPath> object_path_set;
     74   std::set<dbus::ObjectPath>::iterator object_path_set_iter =
     75       object_path_set.begin();
     76 
     77   // Add all objects.
     78   for (ObjectPathVector::const_iterator iter = object_paths.begin();
     79        iter != object_paths.end(); ++iter) {
     80     const dbus::ObjectPath &object_path = *iter;
     81     AddObject(object_path);
     82     // Neard usually returns object paths in ascending order. Give a hint here
     83     // to make insertion amortized constant.
     84     object_path_set_iter =
     85         object_path_set.insert(object_path_set_iter, object_path);
     86   }
     87 
     88   // Remove all objects that are not in |object_paths|.
     89   ObjectMap::const_iterator iter = object_map_.begin();
     90   while (iter != object_map_.end()) {
     91     // It is safe to use a const reference here, as DBusObjectMap::RemoveObject
     92     // won't access it after the iterator becomes invalidated.
     93     const dbus::ObjectPath &object_path = iter->first;
     94     ++iter;
     95     if (!ContainsKey(object_path_set, object_path))
     96       RemoveObject(object_path);
     97   }
     98 }
     99 
    100 bool DBusObjectMap::AddObject(const dbus::ObjectPath& object_path) {
    101   ObjectMap::iterator iter = object_map_.find(object_path);
    102   if (iter != object_map_.end())
    103     return false;
    104 
    105   DCHECK(bus_);
    106   DCHECK(delegate_);
    107   dbus::ObjectProxy* object_proxy = bus_->GetObjectProxy(service_name_,
    108                                                          object_path);
    109 
    110   // Create the properties structure.
    111   NfcPropertySet* properties = delegate_->CreateProperties(object_proxy);
    112   properties->ConnectSignals();
    113   properties->GetAll();
    114   ObjectPropertyPair object = std::make_pair(object_proxy, properties);
    115   object_map_[object_path] = object;
    116   VLOG(1) << "Created proxy for object with Path: " << object_path.value()
    117           << ", Service: " << service_name_;
    118   delegate_->ObjectAdded(object_path);
    119   return true;
    120 }
    121 
    122 void DBusObjectMap::RemoveObject(const dbus::ObjectPath& object_path) {
    123   DCHECK(bus_);
    124   DCHECK(delegate_);
    125   ObjectMap::iterator iter = object_map_.find(object_path);
    126   if (iter == object_map_.end())
    127     return;
    128 
    129   // Notify the delegate, so that it can perform any clean up that is
    130   // necessary.
    131   delegate_->ObjectRemoved(object_path);
    132 
    133   // Clean up the object proxy and the properties structure.
    134   ObjectPropertyPair pair = iter->second;
    135   CleanUpObjectPropertyPair(pair);
    136   object_map_.erase(iter);
    137   VLOG(1) << "Object proxy removed for object path: "
    138           << object_path.value();
    139 }
    140 
    141 void DBusObjectMap::RefreshProperties(const dbus::ObjectPath& object_path) {
    142   NfcPropertySet* properties = GetObjectProperties(object_path);
    143   if (properties)
    144     properties->GetAll();
    145 }
    146 
    147 void DBusObjectMap::RefreshAllProperties() {
    148   for (ObjectMap::const_iterator iter = object_map_.begin();
    149        iter != object_map_.end(); ++iter) {
    150     const dbus::ObjectPath& object_path = iter->first;
    151     RefreshProperties(object_path);
    152   }
    153 }
    154 
    155 ObjectPathVector DBusObjectMap::GetObjectPaths() {
    156   std::vector<dbus::ObjectPath> object_paths;
    157   for (ObjectMap::const_iterator iter = object_map_.begin();
    158        iter != object_map_.end(); ++iter) {
    159     const dbus::ObjectPath& object_path = iter->first;
    160     object_paths.push_back(object_path);
    161   }
    162   return object_paths;
    163 }
    164 
    165 DBusObjectMap::ObjectPropertyPair DBusObjectMap::GetObjectPropertyPair(
    166     const dbus::ObjectPath& object_path) {
    167   ObjectMap::iterator iter = object_map_.find(object_path);
    168   if (iter != object_map_.end())
    169     return iter->second;
    170   return std::make_pair(static_cast<dbus::ObjectProxy*>(NULL),
    171                         static_cast<NfcPropertySet*>(NULL));
    172 }
    173 
    174 void DBusObjectMap::CleanUpObjectPropertyPair(const ObjectPropertyPair& pair) {
    175   // Don't remove the object proxy. There is a bug in dbus::Bus that causes a
    176   // crash when object proxies are removed, due to the proxy objects not being
    177   // properly reference counted. (See crbug.com/170182 and crbug.com/328264).
    178   NfcPropertySet* properties = pair.second;
    179   delete properties;
    180 }
    181 
    182 ObjectProxyTree::ObjectProxyTree() {
    183 }
    184 
    185 ObjectProxyTree::~ObjectProxyTree() {
    186   for (PathsToObjectMapsType::iterator iter = paths_to_object_maps_.begin();
    187        iter != paths_to_object_maps_.end(); ++iter) {
    188     DBusObjectMap* object_map = iter->second;
    189     delete object_map;
    190   }
    191 }
    192 
    193 bool ObjectProxyTree::CreateObjectMap(const dbus::ObjectPath& object_path,
    194                                       const std::string& service_name,
    195                                       DBusObjectMap::Delegate* delegate,
    196                                       dbus::Bus* bus) {
    197   if (ContainsKey(paths_to_object_maps_, object_path)) {
    198     LOG(ERROR) << "Mapping already exists for object path: "
    199                << object_path.value();
    200     return false;
    201   }
    202   paths_to_object_maps_[object_path] =
    203       new DBusObjectMap(service_name, delegate, bus);
    204   return true;
    205 }
    206 
    207 void ObjectProxyTree::RemoveObjectMap(const dbus::ObjectPath& object_path) {
    208   PathsToObjectMapsType::iterator iter =
    209       paths_to_object_maps_.find(object_path);
    210   if (iter == paths_to_object_maps_.end())
    211     return;
    212   DBusObjectMap* object_map = iter->second;
    213   paths_to_object_maps_.erase(iter);
    214   delete object_map;
    215 }
    216 
    217 DBusObjectMap* ObjectProxyTree::GetObjectMap(
    218     const dbus::ObjectPath& object_path) {
    219   PathsToObjectMapsType::iterator iter =
    220       paths_to_object_maps_.find(object_path);
    221   if (iter == paths_to_object_maps_.end())
    222     return NULL;
    223   return iter->second;
    224 }
    225 
    226 dbus::ObjectProxy* ObjectProxyTree::FindObjectProxy(
    227     const dbus::ObjectPath& object_proxy_path) {
    228   for (PathsToObjectMapsType::iterator iter = paths_to_object_maps_.begin();
    229        iter != paths_to_object_maps_.end(); ++iter) {
    230     DBusObjectMap* object_map = iter->second;
    231     dbus::ObjectProxy* object_proxy =
    232         object_map->GetObjectProxy(object_proxy_path);
    233     if (object_proxy)
    234       return object_proxy;
    235   }
    236   return NULL;
    237 }
    238 
    239 NfcPropertySet* ObjectProxyTree::FindObjectProperties(
    240     const dbus::ObjectPath& object_proxy_path) {
    241   for (PathsToObjectMapsType::iterator iter = paths_to_object_maps_.begin();
    242        iter != paths_to_object_maps_.end(); ++iter) {
    243     DBusObjectMap* object_map = iter->second;
    244     NfcPropertySet* properties =
    245         object_map->GetObjectProperties(object_proxy_path);
    246     if (properties)
    247       return properties;
    248   }
    249   return NULL;
    250 }
    251 
    252 }  // namespace nfc_client_helpers
    253 }  // namespace chromeos
    254