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