• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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