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 #include "dbus/property.h"
      6 
      7 #include <stddef.h>
      8 
      9 #include <memory>
     10 
     11 #include "base/bind.h"
     12 #include "base/logging.h"
     13 
     14 #include "dbus/message.h"
     15 #include "dbus/object_path.h"
     16 #include "dbus/object_proxy.h"
     17 
     18 namespace dbus {
     19 
     20 //
     21 // PropertyBase implementation.
     22 //
     23 
     24 PropertyBase::PropertyBase() : property_set_(nullptr), is_valid_(false) {}
     25 
     26 PropertyBase::~PropertyBase() {}
     27 
     28 void PropertyBase::Init(PropertySet* property_set, const std::string& name) {
     29   DCHECK(!property_set_);
     30   property_set_ = property_set;
     31   is_valid_ = false;
     32   name_ = name;
     33 }
     34 
     35 //
     36 // PropertySet implementation.
     37 //
     38 
     39 PropertySet::PropertySet(
     40     ObjectProxy* object_proxy,
     41     const std::string& interface,
     42     const PropertyChangedCallback& property_changed_callback)
     43     : object_proxy_(object_proxy),
     44       interface_(interface),
     45       property_changed_callback_(property_changed_callback),
     46       weak_ptr_factory_(this) {}
     47 
     48 PropertySet::~PropertySet() {
     49 }
     50 
     51 void PropertySet::RegisterProperty(const std::string& name,
     52                                    PropertyBase* property) {
     53   property->Init(this, name);
     54   properties_map_[name] = property;
     55 }
     56 
     57 void PropertySet::ConnectSignals() {
     58   DCHECK(object_proxy_);
     59   object_proxy_->ConnectToSignal(
     60       kPropertiesInterface,
     61       kPropertiesChanged,
     62       base::Bind(&PropertySet::ChangedReceived,
     63                  weak_ptr_factory_.GetWeakPtr()),
     64       base::Bind(&PropertySet::ChangedConnected,
     65                  weak_ptr_factory_.GetWeakPtr()));
     66 }
     67 
     68 
     69 void PropertySet::ChangedReceived(Signal* signal) {
     70   DCHECK(signal);
     71   MessageReader reader(signal);
     72 
     73   std::string interface;
     74   if (!reader.PopString(&interface)) {
     75     LOG(WARNING) << "Property changed signal has wrong parameters: "
     76                  << "expected interface name: " << signal->ToString();
     77     return;
     78   }
     79 
     80   if (interface != this->interface())
     81     return;
     82 
     83   if (!UpdatePropertiesFromReader(&reader)) {
     84     LOG(WARNING) << "Property changed signal has wrong parameters: "
     85                  << "expected dictionary: " << signal->ToString();
     86   }
     87 
     88   if (!InvalidatePropertiesFromReader(&reader)) {
     89     LOG(WARNING) << "Property changed signal has wrong parameters: "
     90                  << "expected array to invalidate: " << signal->ToString();
     91   }
     92 }
     93 
     94 void PropertySet::ChangedConnected(const std::string& interface_name,
     95                                    const std::string& signal_name,
     96                                    bool success) {
     97   LOG_IF(WARNING, !success) << "Failed to connect to " << signal_name
     98                             << "signal.";
     99 }
    100 
    101 
    102 void PropertySet::Get(PropertyBase* property, GetCallback callback) {
    103   MethodCall method_call(kPropertiesInterface, kPropertiesGet);
    104   MessageWriter writer(&method_call);
    105   writer.AppendString(interface());
    106   writer.AppendString(property->name());
    107 
    108   DCHECK(object_proxy_);
    109   object_proxy_->CallMethod(&method_call,
    110                             ObjectProxy::TIMEOUT_USE_DEFAULT,
    111                             base::Bind(&PropertySet::OnGet,
    112                                        GetWeakPtr(),
    113                                        property,
    114                                        callback));
    115 }
    116 
    117 void PropertySet::OnGet(PropertyBase* property, GetCallback callback,
    118                         Response* response) {
    119   if (!response) {
    120     LOG(WARNING) << property->name() << ": Get: failed.";
    121     return;
    122   }
    123 
    124   MessageReader reader(response);
    125   if (property->PopValueFromReader(&reader)) {
    126     property->set_valid(true);
    127     NotifyPropertyChanged(property->name());
    128   } else {
    129     if (property->is_valid()) {
    130       property->set_valid(false);
    131       NotifyPropertyChanged(property->name());
    132     }
    133   }
    134 
    135   if (!callback.is_null())
    136     callback.Run(response);
    137 }
    138 
    139 bool PropertySet::GetAndBlock(PropertyBase* property) {
    140   MethodCall method_call(kPropertiesInterface, kPropertiesGet);
    141   MessageWriter writer(&method_call);
    142   writer.AppendString(interface());
    143   writer.AppendString(property->name());
    144 
    145   DCHECK(object_proxy_);
    146   std::unique_ptr<dbus::Response> response(object_proxy_->CallMethodAndBlock(
    147       &method_call, ObjectProxy::TIMEOUT_USE_DEFAULT));
    148 
    149   if (!response.get()) {
    150     LOG(WARNING) << property->name() << ": GetAndBlock: failed.";
    151     return false;
    152   }
    153 
    154   MessageReader reader(response.get());
    155   if (property->PopValueFromReader(&reader)) {
    156     property->set_valid(true);
    157     NotifyPropertyChanged(property->name());
    158   } else {
    159     if (property->is_valid()) {
    160       property->set_valid(false);
    161       NotifyPropertyChanged(property->name());
    162     }
    163   }
    164   return true;
    165 }
    166 
    167 void PropertySet::GetAll() {
    168   MethodCall method_call(kPropertiesInterface, kPropertiesGetAll);
    169   MessageWriter writer(&method_call);
    170   writer.AppendString(interface());
    171 
    172   DCHECK(object_proxy_);
    173   object_proxy_->CallMethod(&method_call,
    174                             ObjectProxy::TIMEOUT_USE_DEFAULT,
    175                             base::Bind(&PropertySet::OnGetAll,
    176                                        weak_ptr_factory_.GetWeakPtr()));
    177 }
    178 
    179 void PropertySet::OnGetAll(Response* response) {
    180   if (!response) {
    181     LOG(WARNING) << "GetAll request failed for: " << interface_;
    182     return;
    183   }
    184 
    185   MessageReader reader(response);
    186   if (!UpdatePropertiesFromReader(&reader)) {
    187     LOG(WARNING) << "GetAll response has wrong parameters: "
    188                  << "expected dictionary: " << response->ToString();
    189   }
    190 }
    191 
    192 void PropertySet::Set(PropertyBase* property, SetCallback callback) {
    193   MethodCall method_call(kPropertiesInterface, kPropertiesSet);
    194   MessageWriter writer(&method_call);
    195   writer.AppendString(interface());
    196   writer.AppendString(property->name());
    197   property->AppendSetValueToWriter(&writer);
    198 
    199   DCHECK(object_proxy_);
    200   object_proxy_->CallMethod(&method_call,
    201                             ObjectProxy::TIMEOUT_USE_DEFAULT,
    202                             base::Bind(&PropertySet::OnSet,
    203                                        GetWeakPtr(),
    204                                        property,
    205                                        callback));
    206 }
    207 
    208 bool PropertySet::SetAndBlock(PropertyBase* property) {
    209   MethodCall method_call(kPropertiesInterface, kPropertiesSet);
    210   MessageWriter writer(&method_call);
    211   writer.AppendString(interface());
    212   writer.AppendString(property->name());
    213   property->AppendSetValueToWriter(&writer);
    214 
    215   DCHECK(object_proxy_);
    216   std::unique_ptr<dbus::Response> response(object_proxy_->CallMethodAndBlock(
    217       &method_call, ObjectProxy::TIMEOUT_USE_DEFAULT));
    218   if (response.get())
    219     return true;
    220   return false;
    221 }
    222 
    223 void PropertySet::OnSet(PropertyBase* property,
    224                         SetCallback callback,
    225                         Response* response) {
    226   LOG_IF(WARNING, !response) << property->name() << ": Set: failed.";
    227   if (!callback.is_null())
    228     callback.Run(response);
    229 }
    230 
    231 bool PropertySet::UpdatePropertiesFromReader(MessageReader* reader) {
    232   DCHECK(reader);
    233   MessageReader array_reader(NULL);
    234   if (!reader->PopArray(&array_reader))
    235     return false;
    236 
    237   while (array_reader.HasMoreData()) {
    238     MessageReader dict_entry_reader(NULL);
    239     if (array_reader.PopDictEntry(&dict_entry_reader))
    240       UpdatePropertyFromReader(&dict_entry_reader);
    241   }
    242 
    243   return true;
    244 }
    245 
    246 bool PropertySet::UpdatePropertyFromReader(MessageReader* reader) {
    247   DCHECK(reader);
    248 
    249   std::string name;
    250   if (!reader->PopString(&name))
    251     return false;
    252 
    253   PropertiesMap::iterator it = properties_map_.find(name);
    254   if (it == properties_map_.end())
    255     return false;
    256 
    257   PropertyBase* property = it->second;
    258   if (property->PopValueFromReader(reader)) {
    259     property->set_valid(true);
    260     NotifyPropertyChanged(name);
    261     return true;
    262   } else {
    263     if (property->is_valid()) {
    264       property->set_valid(false);
    265       NotifyPropertyChanged(property->name());
    266     }
    267     return false;
    268   }
    269 }
    270 
    271 bool PropertySet::InvalidatePropertiesFromReader(MessageReader* reader) {
    272   DCHECK(reader);
    273   MessageReader array_reader(NULL);
    274   if (!reader->PopArray(&array_reader))
    275     return false;
    276 
    277   while (array_reader.HasMoreData()) {
    278     std::string name;
    279     if (!array_reader.PopString(&name))
    280       return false;
    281 
    282     PropertiesMap::iterator it = properties_map_.find(name);
    283     if (it == properties_map_.end())
    284       continue;
    285 
    286     PropertyBase* property = it->second;
    287     if (property->is_valid()) {
    288       property->set_valid(false);
    289       NotifyPropertyChanged(property->name());
    290     }
    291   }
    292 
    293   return true;
    294 }
    295 
    296 void PropertySet::NotifyPropertyChanged(const std::string& name) {
    297   if (!property_changed_callback_.is_null())
    298     property_changed_callback_.Run(name);
    299 }
    300 
    301 //
    302 // Property<Byte> specialization.
    303 //
    304 
    305 template <>
    306 Property<uint8_t>::Property()
    307     : value_(0) {}
    308 
    309 template <>
    310 bool Property<uint8_t>::PopValueFromReader(MessageReader* reader) {
    311   return reader->PopVariantOfByte(&value_);
    312 }
    313 
    314 template <>
    315 void Property<uint8_t>::AppendSetValueToWriter(MessageWriter* writer) {
    316   writer->AppendVariantOfByte(set_value_);
    317 }
    318 
    319 //
    320 // Property<bool> specialization.
    321 //
    322 
    323 template <>
    324 Property<bool>::Property() : value_(false) {
    325 }
    326 
    327 template <>
    328 bool Property<bool>::PopValueFromReader(MessageReader* reader) {
    329   return reader->PopVariantOfBool(&value_);
    330 }
    331 
    332 template <>
    333 void Property<bool>::AppendSetValueToWriter(MessageWriter* writer) {
    334   writer->AppendVariantOfBool(set_value_);
    335 }
    336 
    337 //
    338 // Property<int16_t> specialization.
    339 //
    340 
    341 template <>
    342 Property<int16_t>::Property()
    343     : value_(0) {}
    344 
    345 template <>
    346 bool Property<int16_t>::PopValueFromReader(MessageReader* reader) {
    347   return reader->PopVariantOfInt16(&value_);
    348 }
    349 
    350 template <>
    351 void Property<int16_t>::AppendSetValueToWriter(MessageWriter* writer) {
    352   writer->AppendVariantOfInt16(set_value_);
    353 }
    354 
    355 //
    356 // Property<uint16_t> specialization.
    357 //
    358 
    359 template <>
    360 Property<uint16_t>::Property()
    361     : value_(0) {}
    362 
    363 template <>
    364 bool Property<uint16_t>::PopValueFromReader(MessageReader* reader) {
    365   return reader->PopVariantOfUint16(&value_);
    366 }
    367 
    368 template <>
    369 void Property<uint16_t>::AppendSetValueToWriter(MessageWriter* writer) {
    370   writer->AppendVariantOfUint16(set_value_);
    371 }
    372 
    373 //
    374 // Property<int32_t> specialization.
    375 //
    376 
    377 template <>
    378 Property<int32_t>::Property()
    379     : value_(0) {}
    380 
    381 template <>
    382 bool Property<int32_t>::PopValueFromReader(MessageReader* reader) {
    383   return reader->PopVariantOfInt32(&value_);
    384 }
    385 
    386 template <>
    387 void Property<int32_t>::AppendSetValueToWriter(MessageWriter* writer) {
    388   writer->AppendVariantOfInt32(set_value_);
    389 }
    390 
    391 //
    392 // Property<uint32_t> specialization.
    393 //
    394 
    395 template <>
    396 Property<uint32_t>::Property()
    397     : value_(0) {}
    398 
    399 template <>
    400 bool Property<uint32_t>::PopValueFromReader(MessageReader* reader) {
    401   return reader->PopVariantOfUint32(&value_);
    402 }
    403 
    404 template <>
    405 void Property<uint32_t>::AppendSetValueToWriter(MessageWriter* writer) {
    406   writer->AppendVariantOfUint32(set_value_);
    407 }
    408 
    409 //
    410 // Property<int64_t> specialization.
    411 //
    412 
    413 template <>
    414 Property<int64_t>::Property()
    415     : value_(0), set_value_(0) {}
    416 
    417 template <>
    418 bool Property<int64_t>::PopValueFromReader(MessageReader* reader) {
    419   return reader->PopVariantOfInt64(&value_);
    420 }
    421 
    422 template <>
    423 void Property<int64_t>::AppendSetValueToWriter(MessageWriter* writer) {
    424   writer->AppendVariantOfInt64(set_value_);
    425 }
    426 
    427 //
    428 // Property<uint64_t> specialization.
    429 //
    430 
    431 template <>
    432 Property<uint64_t>::Property()
    433     : value_(0) {}
    434 
    435 template <>
    436 bool Property<uint64_t>::PopValueFromReader(MessageReader* reader) {
    437   return reader->PopVariantOfUint64(&value_);
    438 }
    439 
    440 template <>
    441 void Property<uint64_t>::AppendSetValueToWriter(MessageWriter* writer) {
    442   writer->AppendVariantOfUint64(set_value_);
    443 }
    444 
    445 //
    446 // Property<double> specialization.
    447 //
    448 
    449 template <>
    450 Property<double>::Property() : value_(0.0) {
    451 }
    452 
    453 template <>
    454 bool Property<double>::PopValueFromReader(MessageReader* reader) {
    455   return reader->PopVariantOfDouble(&value_);
    456 }
    457 
    458 template <>
    459 void Property<double>::AppendSetValueToWriter(MessageWriter* writer) {
    460   writer->AppendVariantOfDouble(set_value_);
    461 }
    462 
    463 //
    464 // Property<std::string> specialization.
    465 //
    466 
    467 template <>
    468 bool Property<std::string>::PopValueFromReader(MessageReader* reader) {
    469   return reader->PopVariantOfString(&value_);
    470 }
    471 
    472 template <>
    473 void Property<std::string>::AppendSetValueToWriter(MessageWriter* writer) {
    474   writer->AppendVariantOfString(set_value_);
    475 }
    476 
    477 //
    478 // Property<ObjectPath> specialization.
    479 //
    480 
    481 template <>
    482 bool Property<ObjectPath>::PopValueFromReader(MessageReader* reader) {
    483   return reader->PopVariantOfObjectPath(&value_);
    484 }
    485 
    486 template <>
    487 void Property<ObjectPath>::AppendSetValueToWriter(MessageWriter* writer) {
    488   writer->AppendVariantOfObjectPath(set_value_);
    489 }
    490 
    491 //
    492 // Property<std::vector<std::string> > specialization.
    493 //
    494 
    495 template <>
    496 bool Property<std::vector<std::string> >::PopValueFromReader(
    497     MessageReader* reader) {
    498   MessageReader variant_reader(NULL);
    499   if (!reader->PopVariant(&variant_reader))
    500     return false;
    501 
    502   value_.clear();
    503   return variant_reader.PopArrayOfStrings(&value_);
    504 }
    505 
    506 template <>
    507 void Property<std::vector<std::string> >::AppendSetValueToWriter(
    508     MessageWriter* writer) {
    509   MessageWriter variant_writer(NULL);
    510   writer->OpenVariant("as", &variant_writer);
    511   variant_writer.AppendArrayOfStrings(set_value_);
    512   writer->CloseContainer(&variant_writer);
    513 }
    514 
    515 //
    516 // Property<std::vector<ObjectPath> > specialization.
    517 //
    518 
    519 template <>
    520 bool Property<std::vector<ObjectPath> >::PopValueFromReader(
    521     MessageReader* reader) {
    522   MessageReader variant_reader(NULL);
    523   if (!reader->PopVariant(&variant_reader))
    524     return false;
    525 
    526   value_.clear();
    527   return variant_reader.PopArrayOfObjectPaths(&value_);
    528 }
    529 
    530 template <>
    531 void Property<std::vector<ObjectPath> >::AppendSetValueToWriter(
    532     MessageWriter* writer) {
    533   MessageWriter variant_writer(NULL);
    534   writer->OpenVariant("ao", &variant_writer);
    535   variant_writer.AppendArrayOfObjectPaths(set_value_);
    536   writer->CloseContainer(&variant_writer);
    537 }
    538 
    539 //
    540 // Property<std::vector<uint8_t> > specialization.
    541 //
    542 
    543 template <>
    544 bool Property<std::vector<uint8_t>>::PopValueFromReader(MessageReader* reader) {
    545   MessageReader variant_reader(NULL);
    546   if (!reader->PopVariant(&variant_reader))
    547     return false;
    548 
    549   value_.clear();
    550   const uint8_t* bytes = NULL;
    551   size_t length = 0;
    552   if (!variant_reader.PopArrayOfBytes(&bytes, &length))
    553     return false;
    554   value_.assign(bytes, bytes + length);
    555   return true;
    556 }
    557 
    558 template <>
    559 void Property<std::vector<uint8_t>>::AppendSetValueToWriter(
    560     MessageWriter* writer) {
    561   MessageWriter variant_writer(NULL);
    562   writer->OpenVariant("ay", &variant_writer);
    563   variant_writer.AppendArrayOfBytes(set_value_.data(), set_value_.size());
    564   writer->CloseContainer(&variant_writer);
    565 }
    566 
    567 //
    568 // Property<std::map<std::string, std::string>> specialization.
    569 //
    570 
    571 template <>
    572 bool Property<std::map<std::string, std::string>>::PopValueFromReader(
    573     MessageReader* reader) {
    574   MessageReader variant_reader(NULL);
    575   MessageReader array_reader(NULL);
    576   if (!reader->PopVariant(&variant_reader) ||
    577       !variant_reader.PopArray(&array_reader))
    578     return false;
    579   value_.clear();
    580   while (array_reader.HasMoreData()) {
    581     dbus::MessageReader dict_entry_reader(NULL);
    582     if (!array_reader.PopDictEntry(&dict_entry_reader))
    583       return false;
    584     std::string key;
    585     std::string value;
    586     if (!dict_entry_reader.PopString(&key) ||
    587         !dict_entry_reader.PopString(&value))
    588       return false;
    589     value_[key] = value;
    590   }
    591   return true;
    592 }
    593 
    594 template <>
    595 void Property<std::map<std::string, std::string>>::AppendSetValueToWriter(
    596     MessageWriter* writer) {
    597   MessageWriter variant_writer(NULL);
    598   MessageWriter dict_writer(NULL);
    599   writer->OpenVariant("a{ss}", &variant_writer);
    600   variant_writer.OpenArray("{ss}", &dict_writer);
    601   for (const auto& pair : set_value_) {
    602     dbus::MessageWriter entry_writer(NULL);
    603     dict_writer.OpenDictEntry(&entry_writer);
    604     entry_writer.AppendString(pair.first);
    605     entry_writer.AppendString(pair.second);
    606     dict_writer.CloseContainer(&entry_writer);
    607   }
    608   variant_writer.CloseContainer(&dict_writer);
    609   writer->CloseContainer(&variant_writer);
    610 }
    611 
    612 //
    613 // Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>
    614 // specialization.
    615 //
    616 
    617 template <>
    618 bool Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>::
    619     PopValueFromReader(MessageReader* reader) {
    620   MessageReader variant_reader(NULL);
    621   MessageReader array_reader(NULL);
    622   if (!reader->PopVariant(&variant_reader) ||
    623       !variant_reader.PopArray(&array_reader))
    624     return false;
    625 
    626   value_.clear();
    627   while (array_reader.HasMoreData()) {
    628     dbus::MessageReader struct_reader(NULL);
    629     if (!array_reader.PopStruct(&struct_reader))
    630       return false;
    631 
    632     std::pair<std::vector<uint8_t>, uint16_t> entry;
    633     const uint8_t* bytes = NULL;
    634     size_t length = 0;
    635     if (!struct_reader.PopArrayOfBytes(&bytes, &length))
    636       return false;
    637     entry.first.assign(bytes, bytes + length);
    638     if (!struct_reader.PopUint16(&entry.second))
    639       return false;
    640     value_.push_back(entry);
    641   }
    642   return true;
    643 }
    644 
    645 template <>
    646 void Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>::
    647     AppendSetValueToWriter(MessageWriter* writer) {
    648   MessageWriter variant_writer(NULL);
    649   MessageWriter array_writer(NULL);
    650   writer->OpenVariant("a(ayq)", &variant_writer);
    651   variant_writer.OpenArray("(ayq)", &array_writer);
    652   for (const auto& pair : set_value_) {
    653     dbus::MessageWriter struct_writer(nullptr);
    654     array_writer.OpenStruct(&struct_writer);
    655     struct_writer.AppendArrayOfBytes(std::get<0>(pair).data(),
    656                                      std::get<0>(pair).size());
    657     struct_writer.AppendUint16(std::get<1>(pair));
    658     array_writer.CloseContainer(&struct_writer);
    659   }
    660   variant_writer.CloseContainer(&array_writer);
    661   writer->CloseContainer(&variant_writer);
    662 }
    663 
    664 //
    665 // Property<std::unordered_map<std::string, std::vector<uint8_t>>>
    666 // specialization.
    667 //
    668 
    669 template <>
    670 bool Property<std::unordered_map<std::string, std::vector<uint8_t>>>::
    671     PopValueFromReader(MessageReader* reader) {
    672   MessageReader variant_reader(nullptr);
    673   MessageReader dict_reader(nullptr);
    674   if (!reader->PopVariant(&variant_reader) ||
    675       !variant_reader.PopArray(&dict_reader))
    676     return false;
    677 
    678   value_.clear();
    679   while (dict_reader.HasMoreData()) {
    680     MessageReader entry_reader(nullptr);
    681     if (!dict_reader.PopDictEntry(&entry_reader))
    682       return false;
    683 
    684     std::string key;
    685     MessageReader value_varient_reader(nullptr);
    686     if (!entry_reader.PopString(&key) ||
    687         !entry_reader.PopVariant(&value_varient_reader))
    688       return false;
    689 
    690     const uint8_t* bytes = nullptr;
    691     size_t length = 0;
    692     if (!value_varient_reader.PopArrayOfBytes(&bytes, &length))
    693       return false;
    694 
    695     value_[key].assign(bytes, bytes + length);
    696   }
    697   return true;
    698 }
    699 
    700 template <>
    701 void Property<std::unordered_map<std::string, std::vector<uint8_t>>>::
    702     AppendSetValueToWriter(MessageWriter* writer) {
    703   MessageWriter variant_writer(nullptr);
    704   MessageWriter dict_writer(nullptr);
    705 
    706   writer->OpenVariant("a{sv}", &variant_writer);
    707   variant_writer.OpenArray("{sv}", &dict_writer);
    708 
    709   for (const auto& pair : set_value_) {
    710     MessageWriter entry_writer(nullptr);
    711     dict_writer.OpenDictEntry(&entry_writer);
    712 
    713     entry_writer.AppendString(pair.first);
    714 
    715     MessageWriter value_varient_writer(nullptr);
    716     entry_writer.OpenVariant("ay", &value_varient_writer);
    717     value_varient_writer.AppendArrayOfBytes(pair.second.data(),
    718                                             pair.second.size());
    719     entry_writer.CloseContainer(&value_varient_writer);
    720 
    721     dict_writer.CloseContainer(&entry_writer);
    722   }
    723 
    724   variant_writer.CloseContainer(&dict_writer);
    725   writer->CloseContainer(&variant_writer);
    726 }
    727 
    728 //
    729 // Property<std::unordered_map<uint16_t, std::vector<uint8_t>>>
    730 // specialization.
    731 //
    732 
    733 template <>
    734 bool Property<std::unordered_map<uint16_t, std::vector<uint8_t>>>::
    735     PopValueFromReader(MessageReader* reader) {
    736   MessageReader variant_reader(nullptr);
    737   MessageReader dict_reader(nullptr);
    738   if (!reader->PopVariant(&variant_reader) ||
    739       !variant_reader.PopArray(&dict_reader))
    740     return false;
    741 
    742   value_.clear();
    743   while (dict_reader.HasMoreData()) {
    744     MessageReader entry_reader(nullptr);
    745     if (!dict_reader.PopDictEntry(&entry_reader))
    746       return false;
    747 
    748     uint16_t key;
    749     MessageReader value_varient_reader(nullptr);
    750     if (!entry_reader.PopUint16(&key) ||
    751         !entry_reader.PopVariant(&value_varient_reader))
    752       return false;
    753 
    754     const uint8_t* bytes = nullptr;
    755     size_t length = 0;
    756     if (!value_varient_reader.PopArrayOfBytes(&bytes, &length))
    757       return false;
    758 
    759     value_[key].assign(bytes, bytes + length);
    760   }
    761   return true;
    762 }
    763 
    764 template <>
    765 void Property<std::unordered_map<uint16_t, std::vector<uint8_t>>>::
    766     AppendSetValueToWriter(MessageWriter* writer) {
    767   MessageWriter variant_writer(nullptr);
    768   MessageWriter dict_writer(nullptr);
    769 
    770   writer->OpenVariant("a{qv}", &variant_writer);
    771   variant_writer.OpenArray("{qv}", &dict_writer);
    772 
    773   for (const auto& pair : set_value_) {
    774     MessageWriter entry_writer(nullptr);
    775     dict_writer.OpenDictEntry(&entry_writer);
    776 
    777     entry_writer.AppendUint16(pair.first);
    778 
    779     MessageWriter value_varient_writer(nullptr);
    780     entry_writer.OpenVariant("ay", &value_varient_writer);
    781     value_varient_writer.AppendArrayOfBytes(pair.second.data(),
    782                                             pair.second.size());
    783     entry_writer.CloseContainer(&value_varient_writer);
    784 
    785     dict_writer.CloseContainer(&entry_writer);
    786   }
    787 
    788   variant_writer.CloseContainer(&dict_writer);
    789   writer->CloseContainer(&variant_writer);
    790 }
    791 
    792 template class Property<uint8_t>;
    793 template class Property<bool>;
    794 template class Property<int16_t>;
    795 template class Property<uint16_t>;
    796 template class Property<int32_t>;
    797 template class Property<uint32_t>;
    798 template class Property<int64_t>;
    799 template class Property<uint64_t>;
    800 template class Property<double>;
    801 template class Property<std::string>;
    802 template class Property<ObjectPath>;
    803 template class Property<std::vector<std::string> >;
    804 template class Property<std::vector<ObjectPath> >;
    805 template class Property<std::vector<uint8_t>>;
    806 template class Property<std::map<std::string, std::string>>;
    807 template class Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>;
    808 template class Property<std::unordered_map<std::string, std::vector<uint8_t>>>;
    809 template class Property<std::unordered_map<uint16_t, std::vector<uint8_t>>>;
    810 
    811 }  // namespace dbus
    812