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 5 #include "chromeos/dbus/introspectable_client.h" 6 7 #include <string> 8 #include <vector> 9 10 #include "base/bind.h" 11 #include "base/logging.h" 12 #include "dbus/bus.h" 13 #include "dbus/message.h" 14 #include "dbus/object_path.h" 15 #include "dbus/object_proxy.h" 16 #include "third_party/libxml/chromium/libxml_utils.h" 17 18 namespace { 19 20 // D-Bus specification constants. 21 const char kIntrospectableInterface[] = "org.freedesktop.DBus.Introspectable"; 22 const char kIntrospect[] = "Introspect"; 23 24 // String constants used for parsing D-Bus Introspection XML data. 25 const char kInterfaceNode[] = "interface"; 26 const char kInterfaceNameAttribute[] = "name"; 27 28 } // namespace 29 30 namespace chromeos { 31 32 // The IntrospectableClient implementation used in production. 33 class IntrospectableClientImpl : public IntrospectableClient { 34 public: 35 IntrospectableClientImpl() : bus_(NULL), weak_ptr_factory_(this) {} 36 37 virtual ~IntrospectableClientImpl() { 38 } 39 40 // IntrospectableClient override. 41 virtual void Introspect(const std::string& service_name, 42 const dbus::ObjectPath& object_path, 43 const IntrospectCallback& callback) OVERRIDE { 44 dbus::MethodCall method_call(kIntrospectableInterface, kIntrospect); 45 46 dbus::ObjectProxy* object_proxy = bus_->GetObjectProxy(service_name, 47 object_path); 48 49 object_proxy->CallMethod( 50 &method_call, 51 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 52 base::Bind(&IntrospectableClientImpl::OnIntrospect, 53 weak_ptr_factory_.GetWeakPtr(), 54 service_name, object_path, callback)); 55 } 56 57 protected: 58 virtual void Init(dbus::Bus* bus) OVERRIDE { bus_ = bus; } 59 60 private: 61 // Called by dbus:: when a response for Introspect() is recieved. 62 void OnIntrospect(const std::string& service_name, 63 const dbus::ObjectPath& object_path, 64 const IntrospectCallback& callback, 65 dbus::Response* response) { 66 // Parse response. 67 bool success = false; 68 std::string xml_data; 69 if (response != NULL) { 70 dbus::MessageReader reader(response); 71 if (!reader.PopString(&xml_data)) { 72 LOG(WARNING) << "Introspect response has incorrect paramters: " 73 << response->ToString(); 74 } else { 75 success = true; 76 } 77 } 78 79 // Notify client. 80 callback.Run(service_name, object_path, xml_data, success); 81 } 82 83 dbus::Bus* bus_; 84 85 // Weak pointer factory for generating 'this' pointers that might live longer 86 // than we do. 87 // Note: This should remain the last member so it'll be destroyed and 88 // invalidate its weak pointers before any other members are destroyed. 89 base::WeakPtrFactory<IntrospectableClientImpl> weak_ptr_factory_; 90 91 DISALLOW_COPY_AND_ASSIGN(IntrospectableClientImpl); 92 }; 93 94 IntrospectableClient::IntrospectableClient() { 95 } 96 97 IntrospectableClient::~IntrospectableClient() { 98 } 99 100 // static 101 std::vector<std::string> 102 IntrospectableClient::GetInterfacesFromIntrospectResult( 103 const std::string& xml_data) { 104 std::vector<std::string> interfaces; 105 106 XmlReader reader; 107 if (!reader.Load(xml_data)) 108 return interfaces; 109 110 do { 111 // Skip to the next open tag, exit when done. 112 while (!reader.SkipToElement()) { 113 if (!reader.Read()) { 114 return interfaces; 115 } 116 } 117 118 // Only look at interface nodes. 119 if (reader.NodeName() != kInterfaceNode) 120 continue; 121 122 // Skip if missing the interface name. 123 std::string interface_name; 124 if (!reader.NodeAttribute(kInterfaceNameAttribute, &interface_name)) 125 continue; 126 127 interfaces.push_back(interface_name); 128 } while (reader.Read()); 129 130 return interfaces; 131 } 132 133 // static 134 IntrospectableClient* IntrospectableClient::Create() { 135 return new IntrospectableClientImpl(); 136 } 137 138 } // namespace chromeos 139