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 explicit IntrospectableClientImpl(dbus::Bus* bus) 36 : bus_(bus), 37 weak_ptr_factory_(this) { 38 } 39 40 virtual ~IntrospectableClientImpl() { 41 } 42 43 // IntrospectableClient override. 44 virtual void Introspect(const std::string& service_name, 45 const dbus::ObjectPath& object_path, 46 const IntrospectCallback& callback) OVERRIDE { 47 dbus::MethodCall method_call(kIntrospectableInterface, kIntrospect); 48 49 dbus::ObjectProxy* object_proxy = bus_->GetObjectProxy(service_name, 50 object_path); 51 52 object_proxy->CallMethod( 53 &method_call, 54 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 55 base::Bind(&IntrospectableClientImpl::OnIntrospect, 56 weak_ptr_factory_.GetWeakPtr(), 57 service_name, object_path, callback)); 58 } 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 // The IntrospectableClient implementation used on Linux desktop, which does 95 // nothing. 96 class IntrospectableClientStubImpl : public IntrospectableClient { 97 public: 98 // IntrospectableClient override. 99 virtual void Introspect(const std::string& service_name, 100 const dbus::ObjectPath& object_path, 101 const IntrospectCallback& callback) OVERRIDE { 102 VLOG(1) << "Introspect: " << service_name << " " << object_path.value(); 103 callback.Run(service_name, object_path, "", false); 104 } 105 }; 106 107 IntrospectableClient::IntrospectableClient() { 108 } 109 110 IntrospectableClient::~IntrospectableClient() { 111 } 112 113 // static 114 std::vector<std::string> 115 IntrospectableClient::GetInterfacesFromIntrospectResult( 116 const std::string& xml_data) { 117 std::vector<std::string> interfaces; 118 119 XmlReader reader; 120 if (!reader.Load(xml_data)) 121 return interfaces; 122 123 do { 124 // Skip to the next open tag, exit when done. 125 while (!reader.SkipToElement()) { 126 if (!reader.Read()) { 127 return interfaces; 128 } 129 } 130 131 // Only look at interface nodes. 132 if (reader.NodeName() != kInterfaceNode) 133 continue; 134 135 // Skip if missing the interface name. 136 std::string interface_name; 137 if (!reader.NodeAttribute(kInterfaceNameAttribute, &interface_name)) 138 continue; 139 140 interfaces.push_back(interface_name); 141 } while (reader.Read()); 142 143 return interfaces; 144 } 145 146 // static 147 IntrospectableClient* IntrospectableClient::Create( 148 DBusClientImplementationType type, 149 dbus::Bus* bus) { 150 if (type == REAL_DBUS_CLIENT_IMPLEMENTATION) 151 return new IntrospectableClientImpl(bus); 152 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type); 153 return new IntrospectableClientStubImpl(); 154 } 155 156 } // namespace chromeos 157