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 <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   //   }
    160   const std::string& name() const { return name_; }
    161 
    162   // Returns true if property is valid, false otherwise.
    163   bool is_valid() const { return is_valid_; }
    164 
    165   // Allows to mark Property as valid or invalid.
    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.
    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.
    310   ObjectProxy* object_proxy() { return object_proxy_; }
    311 
    312   // Retrieves the interface of this property set.
    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.
    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:
    380   Property() {}
    381   ~Property() override {}
    382 
    383   // Retrieves the cached 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.
    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.
    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.
    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.
    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.
    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.
    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.
    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