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