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 #ifndef DBUS_PROPERTY_H_ 6 #define DBUS_PROPERTY_H_ 7 8 #include <stdint.h> 9 10 #include <map> 11 #include <string> 12 #include <utility> 13 #include <vector> 14 15 #include "base/bind.h" 16 #include "base/callback.h" 17 #include "base/macros.h" 18 #include "dbus/dbus_export.h" 19 #include "dbus/message.h" 20 #include "dbus/object_proxy.h" 21 22 // D-Bus objects frequently provide sets of properties accessed via a 23 // standard interface of method calls and signals to obtain the current value, 24 // set a new value and be notified of changes to the value. Unfortunately this 25 // interface makes heavy use of variants and dictionaries of variants. The 26 // classes defined here make dealing with properties in a type-safe manner 27 // possible. 28 // 29 // Client implementation classes should define a Properties structure, deriving 30 // from the PropertySet class defined here. This structure should contain a 31 // member for each property defined as an instance of the Property<> class, 32 // specifying the type to the template. Finally the structure should chain up 33 // to the PropertySet constructor, and then call RegisterProperty() for each 34 // property defined to associate them with their string name. 35 // 36 // Example: 37 // class ExampleClient { 38 // public: 39 // struct Properties : public dbus::PropertySet { 40 // dbus::Property<std::string> name; 41 // dbus::Property<uint16_t> version; 42 // dbus::Property<dbus::ObjectPath> parent; 43 // dbus::Property<std::vector<std::string> > children; 44 // 45 // Properties(dbus::ObjectProxy* object_proxy, 46 // const PropertyChangedCallback callback) 47 // : dbus::PropertySet(object_proxy, "com.example.DBus", callback) { 48 // RegisterProperty("Name", &name); 49 // RegisterProperty("Version", &version); 50 // RegisterProperty("Parent", &parent); 51 // RegisterProperty("Children", &children); 52 // } 53 // virtual ~Properties() {} 54 // }; 55 // 56 // The Properties structure requires a pointer to the object proxy of the 57 // actual object to track, and after construction should have signals 58 // connected to that object and initial values set by calling ConnectSignals() 59 // and GetAll(). The structure should not outlive the object proxy, so it 60 // is recommended that the lifecycle of both be managed together. 61 // 62 // Example (continued): 63 // 64 // typedef std::map<std::pair<dbus::ObjectProxy*, Properties*> > Object; 65 // typedef std::map<dbus::ObjectPath, Object> ObjectMap; 66 // ObjectMap object_map_; 67 // 68 // dbus::ObjectProxy* GetObjectProxy(const dbus::ObjectPath& object_path) { 69 // return GetObject(object_path).first; 70 // } 71 // 72 // Properties* GetProperties(const dbus::ObjectPath& object_path) { 73 // return GetObject(object_path).second; 74 // } 75 // 76 // Object GetObject(const dbus::ObjectPath& object_path) { 77 // ObjectMap::iterator it = object_map_.find(object_path); 78 // if (it != object_map_.end()) 79 // return it->second; 80 // 81 // dbus::ObjectProxy* object_proxy = bus->GetObjectProxy(...); 82 // // connect signals, etc. 83 // 84 // Properties* properties = new Properties( 85 // object_proxy, 86 // base::Bind(&PropertyChanged, 87 // weak_ptr_factory_.GetWeakPtr(), 88 // object_path)); 89 // properties->ConnectSignals(); 90 // properties->GetAll(); 91 // 92 // Object object = std::make_pair(object_proxy, properties); 93 // object_map_[object_path] = object; 94 // return object; 95 // } 96 // }; 97 // 98 // This now allows code using the client implementation to access properties 99 // in a type-safe manner, and assuming the PropertyChanged callback is 100 // propogated up to observers, be notified of changes. A typical access of 101 // the current value of the name property would be: 102 // 103 // ExampleClient::Properties* p = example_client->GetProperties(object_path); 104 // std::string name = p->name.value(); 105 // 106 // Normally these values are updated from signals emitted by the remote object, 107 // in case an explicit round-trip is needed to obtain the current value, the 108 // Get() method can be used and indicates whether or not the value update was 109 // successful. The updated value can be obtained in the callback using the 110 // value() method. 111 // 112 // p->children.Get(base::Bind(&OnGetChildren)); 113 // 114 // A new value can be set using the Set() method, the callback indicates 115 // success only; it is up to the remote object when (and indeed if) it updates 116 // the property value, and whether it emits a signal or a Get() call is 117 // required to obtain it. 118 // 119 // p->version.Set(20, base::Bind(&OnSetVersion)) 120 121 namespace dbus { 122 123 // D-Bus Properties interface constants, declared here rather than 124 // in property.cc because template methods use them. 125 const char kPropertiesInterface[] = "org.freedesktop.DBus.Properties"; 126 const char kPropertiesGetAll[] = "GetAll"; 127 const char kPropertiesGet[] = "Get"; 128 const char kPropertiesSet[] = "Set"; 129 const char kPropertiesChanged[] = "PropertiesChanged"; 130 131 class PropertySet; 132 133 // PropertyBase is an abstract base-class consisting of the parts of 134 // the Property<> template that are not type-specific, such as the 135 // associated PropertySet, property name, and the type-unsafe parts 136 // used by PropertySet. 137 class CHROME_DBUS_EXPORT PropertyBase { 138 public: 139 PropertyBase(); 140 virtual ~PropertyBase(); 141 142 // Initializes the |property_set| and property |name| so that method 143 // calls may be made from this class. This method is called by 144 // PropertySet::RegisterProperty() passing |this| for |property_set| so 145 // there should be no need to call it directly. If you do beware that 146 // no ownership or reference to |property_set| is taken so that object 147 // must outlive this one. 148 void Init(PropertySet* property_set, const std::string& name); 149 150 // Retrieves the name of this property, this may be useful in observers 151 // to avoid specifying the name in more than once place, e.g. 152 // 153 // void Client::PropertyChanged(const dbus::ObjectPath& object_path, 154 // const std::string &property_name) { 155 // Properties& properties = GetProperties(object_path); 156 // if (property_name == properties.version.name()) { 157 // // Handle version property changing 158 // } 159 // } name()160 const std::string& name() const { return name_; } 161 162 // Returns true if property is valid, false otherwise. is_valid()163 bool is_valid() const { return is_valid_; } 164 165 // Allows to mark Property as valid or invalid. set_valid(bool is_valid)166 void set_valid(bool is_valid) { is_valid_ = is_valid; } 167 168 // Method used by PropertySet to retrieve the value from a MessageReader, 169 // no knowledge of the contained type is required, this method returns 170 // true if its expected type was found, false if not. 171 // Implementation provided by specialization. 172 virtual bool PopValueFromReader(MessageReader* reader) = 0; 173 174 // Method used by PropertySet to append the set value to a MessageWriter, 175 // no knowledge of the contained type is required. 176 // Implementation provided by specialization. 177 virtual void AppendSetValueToWriter(MessageWriter* writer) = 0; 178 179 // Method used by test and stub implementations of dbus::PropertySet::Set 180 // to replace the property value with the set value without using a 181 // dbus::MessageReader. 182 virtual void ReplaceValueWithSetValue() = 0; 183 184 protected: 185 // Retrieves the associated property set. property_set()186 PropertySet* property_set() { return property_set_; } 187 188 private: 189 // Pointer to the PropertySet instance that this instance is a member of, 190 // no ownership is taken and |property_set_| must outlive this class. 191 PropertySet* property_set_; 192 193 bool is_valid_; 194 195 // Name of the property. 196 std::string name_; 197 198 DISALLOW_COPY_AND_ASSIGN(PropertyBase); 199 }; 200 201 // PropertySet groups a collection of properties for a remote object 202 // together into a single structure, fixing their types and name such 203 // that calls made through it are type-safe. 204 // 205 // Clients always sub-class this to add the properties, and should always 206 // provide a constructor that chains up to this and then calls 207 // RegisterProperty() for each property defined. 208 // 209 // After creation, client code should call ConnectSignals() and most likely 210 // GetAll() to seed initial values and update as changes occur. 211 class CHROME_DBUS_EXPORT PropertySet { 212 public: 213 // Callback for changes to cached values of properties, either notified 214 // via signal, or as a result of calls to Get() and GetAll(). The |name| 215 // argument specifies the name of the property changed. 216 typedef base::Callback<void(const std::string& name)> PropertyChangedCallback; 217 218 // Constructs a property set, where |object_proxy| specifies the proxy for 219 // the/ remote object that these properties are for, care should be taken to 220 // ensure that this object does not outlive the lifetime of the proxy; 221 // |interface| specifies the D-Bus interface of these properties, and 222 // |property_changed_callback| specifies the callback for when properties 223 // are changed, this may be a NULL callback. 224 PropertySet(ObjectProxy* object_proxy, const std::string& interface, 225 const PropertyChangedCallback& property_changed_callback); 226 227 // Destructor; we don't hold on to any references or memory that needs 228 // explicit clean-up, but clang thinks we might. 229 virtual ~PropertySet(); 230 231 // Registers a property, generally called from the subclass constructor; 232 // pass the |name| of the property as used in method calls and signals, 233 // and the pointer to the |property| member of the structure. This will 234 // call the PropertyBase::Init method. 235 void RegisterProperty(const std::string& name, PropertyBase* property); 236 237 // Connects property change notification signals to the object, generally 238 // called immediately after the object is created and before calls to other 239 // methods. Sub-classes may override to use different D-Bus signals. 240 virtual void ConnectSignals(); 241 242 // Methods connected by ConnectSignals() and called by dbus:: when 243 // a property is changed. Sub-classes may override if the property 244 // changed signal provides different arguments. 245 virtual void ChangedReceived(Signal* signal); 246 virtual void ChangedConnected(const std::string& interface_name, 247 const std::string& signal_name, 248 bool success); 249 250 // Callback for Get() method, |success| indicates whether or not the 251 // value could be retrived, if true the new value can be obtained by 252 // calling value() on the property. 253 typedef base::Callback<void(bool success)> GetCallback; 254 255 // Requests an updated value from the remote object for |property| 256 // incurring a round-trip. |callback| will be called when the new 257 // value is available. This may not be implemented by some interfaces, 258 // and may be overriden by sub-classes if interfaces use different 259 // method calls. 260 virtual void Get(PropertyBase* property, GetCallback callback); 261 virtual void OnGet(PropertyBase* property, GetCallback callback, 262 Response* response); 263 264 // The synchronous version of Get(). 265 // This should never be used on an interactive thread. 266 virtual bool GetAndBlock(PropertyBase* property); 267 268 // Queries the remote object for values of all properties and updates 269 // initial values. Sub-classes may override to use a different D-Bus 270 // method, or if the remote object does not support retrieving all 271 // properties, either ignore or obtain each property value individually. 272 virtual void GetAll(); 273 virtual void OnGetAll(Response* response); 274 275 // Callback for Set() method, |success| indicates whether or not the 276 // new property value was accepted by the remote object. 277 typedef base::Callback<void(bool success)> SetCallback; 278 279 // Requests that the remote object for |property| change the property to 280 // its new value. |callback| will be called to indicate the success or 281 // failure of the request, however the new value may not be available 282 // depending on the remote object. This method may be overridden by 283 // sub-classes if interfaces use different method calls. 284 virtual void Set(PropertyBase* property, SetCallback callback); 285 virtual void OnSet(PropertyBase* property, SetCallback callback, 286 Response* response); 287 288 // The synchronous version of Set(). 289 // This should never be used on an interactive thread. 290 virtual bool SetAndBlock(PropertyBase* property); 291 292 // Update properties by reading an array of dictionary entries, each 293 // containing a string with the name and a variant with the value, from 294 // |message_reader|. Returns false if message is in incorrect format. 295 bool UpdatePropertiesFromReader(MessageReader* reader); 296 297 // Updates a single property by reading a string with the name and a 298 // variant with the value from |message_reader|. Returns false if message 299 // is in incorrect format, or property type doesn't match. 300 bool UpdatePropertyFromReader(MessageReader* reader); 301 302 // Calls the property changed callback passed to the constructor, used 303 // by sub-classes that do not call UpdatePropertiesFromReader() or 304 // UpdatePropertyFromReader(). Takes the |name| of the changed property. 305 void NotifyPropertyChanged(const std::string& name); 306 307 // Retrieves the object proxy this property set was initialized with, 308 // provided for sub-classes overriding methods that make D-Bus calls 309 // and for Property<>. Not permitted with const references to this class. object_proxy()310 ObjectProxy* object_proxy() { return object_proxy_; } 311 312 // Retrieves the interface of this property set. interface()313 const std::string& interface() const { return interface_; } 314 315 protected: 316 // Get a weak pointer to this property set, provided so that sub-classes 317 // overriding methods that make D-Bus calls may use the existing (or 318 // override) callbacks without providing their own weak pointer factory. GetWeakPtr()319 base::WeakPtr<PropertySet> GetWeakPtr() { 320 return weak_ptr_factory_.GetWeakPtr(); 321 } 322 323 private: 324 // Invalidates properties by reading an array of names, from 325 // |message_reader|. Returns false if message is in incorrect format. 326 bool InvalidatePropertiesFromReader(MessageReader* reader); 327 328 // Pointer to object proxy for making method calls, no ownership is taken 329 // so this must outlive this class. 330 ObjectProxy* object_proxy_; 331 332 // Interface of property, e.g. "org.chromium.ExampleService", this is 333 // distinct from the interface of the method call itself which is the 334 // general D-Bus Properties interface "org.freedesktop.DBus.Properties". 335 std::string interface_; 336 337 // Callback for property changes. 338 PropertyChangedCallback property_changed_callback_; 339 340 // Map of properties (as PropertyBase*) defined in the structure to 341 // names as used in D-Bus method calls and signals. The base pointer 342 // restricts property access via this map to type-unsafe and non-specific 343 // actions only. 344 typedef std::map<const std::string, PropertyBase*> PropertiesMap; 345 PropertiesMap properties_map_; 346 347 // Weak pointer factory as D-Bus callbacks may last longer than these 348 // objects. 349 base::WeakPtrFactory<PropertySet> weak_ptr_factory_; 350 351 DISALLOW_COPY_AND_ASSIGN(PropertySet); 352 }; 353 354 // Property template, this defines the type-specific and type-safe methods 355 // of properties that can be accessed as members of a PropertySet structure. 356 // 357 // Properties provide a cached value that has an initial sensible default 358 // until the reply to PropertySet::GetAll() is retrieved and is updated by 359 // all calls to that method, PropertySet::Get() and property changed signals 360 // also handled by PropertySet. It can be obtained by calling value() on the 361 // property. 362 // 363 // It is recommended that this cached value be used where necessary, with 364 // code using PropertySet::PropertyChangedCallback to be notified of changes, 365 // rather than incurring a round-trip to the remote object for each property 366 // access. 367 // 368 // Where a round-trip is necessary, the Get() method is provided. And to 369 // update the remote object value, the Set() method is also provided; these 370 // both simply call methods on PropertySet. 371 // 372 // Handling of particular D-Bus types is performed via specialization, 373 // typically the PopValueFromReader() and AppendSetValueToWriter() methods 374 // will need to be provided, and in rare cases a constructor to provide a 375 // default value. Specializations for basic D-Bus types, strings, object 376 // paths and arrays are provided for you. 377 template <class T> 378 class CHROME_DBUS_EXPORT Property : public PropertyBase { 379 public: Property()380 Property() {} ~Property()381 ~Property() override {} 382 383 // Retrieves the cached value. value()384 const T& value() const { return value_; } 385 386 // Requests an updated value from the remote object incurring a 387 // round-trip. |callback| will be called when the new value is available. 388 // This may not be implemented by some interfaces. Get(dbus::PropertySet::GetCallback callback)389 virtual void Get(dbus::PropertySet::GetCallback callback) { 390 property_set()->Get(this, callback); 391 } 392 393 // The synchronous version of Get(). 394 // This should never be used on an interactive thread. GetAndBlock()395 virtual bool GetAndBlock() { 396 return property_set()->GetAndBlock(this); 397 } 398 399 // Requests that the remote object change the property value to |value|, 400 // |callback| will be called to indicate the success or failure of the 401 // request, however the new value may not be available depending on the 402 // remote object. Set(const T & value,dbus::PropertySet::SetCallback callback)403 virtual void Set(const T& value, dbus::PropertySet::SetCallback callback) { 404 set_value_ = value; 405 property_set()->Set(this, callback); 406 } 407 408 // The synchronous version of Set(). 409 // This should never be used on an interactive thread. SetAndBlock(const T & value)410 virtual bool SetAndBlock(const T& value) { 411 set_value_ = value; 412 return property_set()->SetAndBlock(this); 413 } 414 415 // Method used by PropertySet to retrieve the value from a MessageReader, 416 // no knowledge of the contained type is required, this method returns 417 // true if its expected type was found, false if not. 418 bool PopValueFromReader(MessageReader* reader) override; 419 420 // Method used by PropertySet to append the set value to a MessageWriter, 421 // no knowledge of the contained type is required. 422 // Implementation provided by specialization. 423 void AppendSetValueToWriter(MessageWriter* writer) override; 424 425 // Method used by test and stub implementations of dbus::PropertySet::Set 426 // to replace the property value with the set value without using a 427 // dbus::MessageReader. ReplaceValueWithSetValue()428 void ReplaceValueWithSetValue() override { 429 value_ = set_value_; 430 property_set()->NotifyPropertyChanged(name()); 431 } 432 433 // Method used by test and stub implementations to directly set the 434 // value of a property. ReplaceValue(const T & value)435 void ReplaceValue(const T& value) { 436 value_ = value; 437 property_set()->NotifyPropertyChanged(name()); 438 } 439 440 // Method used by test and stub implementations to directly set the 441 // |set_value_| of a property. ReplaceSetValueForTesting(const T & value)442 void ReplaceSetValueForTesting(const T& value) { set_value_ = value; } 443 444 private: 445 // Current cached value of the property. 446 T value_; 447 448 // Replacement value of the property. 449 T set_value_; 450 }; 451 452 // Clang and GCC don't agree on how attributes should work for explicitly 453 // instantiated templates. GCC ignores attributes on explicit instantiations 454 // (and emits a warning) while Clang requires the visiblity attribute on the 455 // explicit instantiations for them to be visible to other compilation units. 456 // Hopefully clang and GCC agree one day, and this can be cleaned up: 457 // https://llvm.org/bugs/show_bug.cgi?id=24815 458 #pragma GCC diagnostic push 459 #pragma GCC diagnostic ignored "-Wattributes" 460 461 template <> 462 CHROME_DBUS_EXPORT Property<uint8_t>::Property(); 463 template <> 464 CHROME_DBUS_EXPORT bool Property<uint8_t>::PopValueFromReader( 465 MessageReader* reader); 466 template <> 467 CHROME_DBUS_EXPORT void Property<uint8_t>::AppendSetValueToWriter( 468 MessageWriter* writer); 469 extern template class CHROME_DBUS_EXPORT Property<uint8_t>; 470 471 template <> 472 CHROME_DBUS_EXPORT Property<bool>::Property(); 473 template <> 474 CHROME_DBUS_EXPORT bool Property<bool>::PopValueFromReader( 475 MessageReader* reader); 476 template <> 477 CHROME_DBUS_EXPORT void Property<bool>::AppendSetValueToWriter( 478 MessageWriter* writer); 479 extern template class CHROME_DBUS_EXPORT Property<bool>; 480 481 template <> 482 CHROME_DBUS_EXPORT Property<int16_t>::Property(); 483 template <> 484 CHROME_DBUS_EXPORT bool Property<int16_t>::PopValueFromReader( 485 MessageReader* reader); 486 template <> 487 CHROME_DBUS_EXPORT void Property<int16_t>::AppendSetValueToWriter( 488 MessageWriter* writer); 489 extern template class CHROME_DBUS_EXPORT Property<int16_t>; 490 491 template <> 492 CHROME_DBUS_EXPORT Property<uint16_t>::Property(); 493 template <> 494 CHROME_DBUS_EXPORT bool Property<uint16_t>::PopValueFromReader( 495 MessageReader* reader); 496 template <> 497 CHROME_DBUS_EXPORT void Property<uint16_t>::AppendSetValueToWriter( 498 MessageWriter* writer); 499 extern template class CHROME_DBUS_EXPORT Property<uint16_t>; 500 501 template <> 502 CHROME_DBUS_EXPORT Property<int32_t>::Property(); 503 template <> 504 CHROME_DBUS_EXPORT bool Property<int32_t>::PopValueFromReader( 505 MessageReader* reader); 506 template <> 507 CHROME_DBUS_EXPORT void Property<int32_t>::AppendSetValueToWriter( 508 MessageWriter* writer); 509 extern template class CHROME_DBUS_EXPORT Property<int32_t>; 510 511 template <> 512 CHROME_DBUS_EXPORT Property<uint32_t>::Property(); 513 template <> 514 CHROME_DBUS_EXPORT bool Property<uint32_t>::PopValueFromReader( 515 MessageReader* reader); 516 template <> 517 CHROME_DBUS_EXPORT void Property<uint32_t>::AppendSetValueToWriter( 518 MessageWriter* writer); 519 extern template class CHROME_DBUS_EXPORT Property<uint32_t>; 520 521 template <> 522 CHROME_DBUS_EXPORT Property<int64_t>::Property(); 523 template <> 524 CHROME_DBUS_EXPORT bool Property<int64_t>::PopValueFromReader( 525 MessageReader* reader); 526 template <> 527 CHROME_DBUS_EXPORT void Property<int64_t>::AppendSetValueToWriter( 528 MessageWriter* writer); 529 extern template class CHROME_DBUS_EXPORT Property<int64_t>; 530 531 template <> 532 CHROME_DBUS_EXPORT Property<uint64_t>::Property(); 533 template <> 534 CHROME_DBUS_EXPORT bool Property<uint64_t>::PopValueFromReader( 535 MessageReader* reader); 536 template <> 537 CHROME_DBUS_EXPORT void Property<uint64_t>::AppendSetValueToWriter( 538 MessageWriter* writer); 539 extern template class CHROME_DBUS_EXPORT Property<uint64_t>; 540 541 template <> 542 CHROME_DBUS_EXPORT Property<double>::Property(); 543 template <> 544 CHROME_DBUS_EXPORT bool Property<double>::PopValueFromReader( 545 MessageReader* reader); 546 template <> 547 CHROME_DBUS_EXPORT void Property<double>::AppendSetValueToWriter( 548 MessageWriter* writer); 549 extern template class CHROME_DBUS_EXPORT Property<double>; 550 551 template <> 552 CHROME_DBUS_EXPORT bool Property<std::string>::PopValueFromReader( 553 MessageReader* reader); 554 template <> 555 CHROME_DBUS_EXPORT void Property<std::string>::AppendSetValueToWriter( 556 MessageWriter* writer); 557 extern template class CHROME_DBUS_EXPORT Property<std::string>; 558 559 template <> 560 CHROME_DBUS_EXPORT bool Property<ObjectPath>::PopValueFromReader( 561 MessageReader* reader); 562 template <> 563 CHROME_DBUS_EXPORT void Property<ObjectPath>::AppendSetValueToWriter( 564 MessageWriter* writer); 565 extern template class CHROME_DBUS_EXPORT Property<ObjectPath>; 566 567 template <> 568 CHROME_DBUS_EXPORT bool Property<std::vector<std::string>>::PopValueFromReader( 569 MessageReader* reader); 570 template <> 571 CHROME_DBUS_EXPORT void Property< 572 std::vector<std::string>>::AppendSetValueToWriter(MessageWriter* writer); 573 extern template class CHROME_DBUS_EXPORT Property<std::vector<std::string>>; 574 575 template <> 576 CHROME_DBUS_EXPORT bool Property<std::vector<ObjectPath>>::PopValueFromReader( 577 MessageReader* reader); 578 template <> 579 CHROME_DBUS_EXPORT void Property< 580 std::vector<ObjectPath>>::AppendSetValueToWriter(MessageWriter* writer); 581 extern template class CHROME_DBUS_EXPORT Property<std::vector<ObjectPath>>; 582 583 template <> 584 CHROME_DBUS_EXPORT bool Property<std::vector<uint8_t>>::PopValueFromReader( 585 MessageReader* reader); 586 template <> 587 CHROME_DBUS_EXPORT void Property<std::vector<uint8_t>>::AppendSetValueToWriter( 588 MessageWriter* writer); 589 extern template class CHROME_DBUS_EXPORT Property<std::vector<uint8_t>>; 590 591 template <> 592 CHROME_DBUS_EXPORT bool 593 Property<std::map<std::string, std::string>>::PopValueFromReader( 594 MessageReader* reader); 595 template <> 596 CHROME_DBUS_EXPORT void 597 Property<std::map<std::string, std::string>>::AppendSetValueToWriter( 598 MessageWriter* writer); 599 extern template class CHROME_DBUS_EXPORT 600 Property<std::map<std::string, std::string>>; 601 602 template <> 603 CHROME_DBUS_EXPORT bool 604 Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>:: 605 PopValueFromReader(MessageReader* reader); 606 template <> 607 CHROME_DBUS_EXPORT void 608 Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>:: 609 AppendSetValueToWriter(MessageWriter* writer); 610 extern template class CHROME_DBUS_EXPORT 611 Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>; 612 613 #pragma GCC diagnostic pop 614 615 } // namespace dbus 616 617 #endif // DBUS_PROPERTY_H_ 618