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/test_service.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/test/test_timeouts.h"
      9 #include "base/threading/platform_thread.h"
     10 #include "dbus/bus.h"
     11 #include "dbus/exported_object.h"
     12 #include "dbus/message.h"
     13 #include "dbus/object_manager.h"
     14 #include "dbus/object_path.h"
     15 #include "dbus/property.h"
     16 
     17 namespace {
     18 
     19 void EmptyCallback(bool /* success */) {
     20 }
     21 
     22 }  // namespace
     23 
     24 namespace dbus {
     25 
     26 // Echo, SlowEcho, AsyncEcho, BrokenMethod, GetAll, Get, Set, PerformAction,
     27 // GetManagedObjects
     28 const int TestService::kNumMethodsToExport = 9;
     29 
     30 TestService::Options::Options()
     31     : request_ownership_options(Bus::REQUIRE_PRIMARY) {
     32 }
     33 
     34 TestService::Options::~Options() {
     35 }
     36 
     37 TestService::TestService(const Options& options)
     38     : base::Thread("TestService"),
     39       request_ownership_options_(options.request_ownership_options),
     40       dbus_task_runner_(options.dbus_task_runner),
     41       on_name_obtained_(false, false),
     42       num_exported_methods_(0) {
     43 }
     44 
     45 TestService::~TestService() {
     46   Stop();
     47 }
     48 
     49 bool TestService::StartService() {
     50   base::Thread::Options thread_options;
     51   thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
     52   return StartWithOptions(thread_options);
     53 }
     54 
     55 bool TestService::WaitUntilServiceIsStarted() {
     56   const base::TimeDelta timeout(TestTimeouts::action_max_timeout());
     57   // Wait until the ownership of the service name is obtained.
     58   return on_name_obtained_.TimedWait(timeout);
     59 }
     60 
     61 void TestService::ShutdownAndBlock() {
     62   message_loop()->PostTask(
     63       FROM_HERE,
     64       base::Bind(&TestService::ShutdownAndBlockInternal,
     65                  base::Unretained(this)));
     66 }
     67 
     68 bool TestService::HasDBusThread() {
     69   return bus_->HasDBusThread();
     70 }
     71 
     72 void TestService::ShutdownAndBlockInternal() {
     73   if (HasDBusThread())
     74     bus_->ShutdownOnDBusThreadAndBlock();
     75   else
     76     bus_->ShutdownAndBlock();
     77 }
     78 
     79 void TestService::SendTestSignal(const std::string& message) {
     80   message_loop()->PostTask(
     81       FROM_HERE,
     82       base::Bind(&TestService::SendTestSignalInternal,
     83                  base::Unretained(this),
     84                  message));
     85 }
     86 
     87 void TestService::SendTestSignalFromRoot(const std::string& message) {
     88   message_loop()->PostTask(
     89       FROM_HERE,
     90       base::Bind(&TestService::SendTestSignalFromRootInternal,
     91                  base::Unretained(this),
     92                  message));
     93 }
     94 
     95 void TestService::SendTestSignalInternal(const std::string& message) {
     96   Signal signal("org.chromium.TestInterface", "Test");
     97   MessageWriter writer(&signal);
     98   writer.AppendString(message);
     99   exported_object_->SendSignal(&signal);
    100 }
    101 
    102 void TestService::SendTestSignalFromRootInternal(const std::string& message) {
    103   Signal signal("org.chromium.TestInterface", "Test");
    104   MessageWriter writer(&signal);
    105   writer.AppendString(message);
    106 
    107   bus_->RequestOwnership("org.chromium.TestService",
    108                          request_ownership_options_,
    109                          base::Bind(&TestService::OnOwnership,
    110                                     base::Unretained(this),
    111                                     base::Bind(&EmptyCallback)));
    112 
    113   // Use "/" just like dbus-send does.
    114   ExportedObject* root_object = bus_->GetExportedObject(ObjectPath("/"));
    115   root_object->SendSignal(&signal);
    116 }
    117 
    118 void TestService::RequestOwnership(base::Callback<void(bool)> callback) {
    119   message_loop()->PostTask(
    120       FROM_HERE,
    121       base::Bind(&TestService::RequestOwnershipInternal,
    122                  base::Unretained(this),
    123                  callback));
    124 }
    125 
    126 void TestService::RequestOwnershipInternal(
    127     base::Callback<void(bool)> callback) {
    128   bus_->RequestOwnership("org.chromium.TestService",
    129                          request_ownership_options_,
    130                          base::Bind(&TestService::OnOwnership,
    131                                     base::Unretained(this),
    132                                     callback));
    133 }
    134 
    135 void TestService::OnOwnership(base::Callback<void(bool)> callback,
    136                               const std::string& service_name,
    137                               bool success) {
    138   has_ownership_ = success;
    139   LOG_IF(ERROR, !success) << "Failed to own: " << service_name;
    140   callback.Run(success);
    141 
    142   on_name_obtained_.Signal();
    143 }
    144 
    145 void TestService::ReleaseOwnership(base::Closure callback) {
    146   bus_->GetDBusTaskRunner()->PostTask(
    147       FROM_HERE,
    148       base::Bind(&TestService::ReleaseOwnershipInternal,
    149                  base::Unretained(this),
    150                  callback));
    151 }
    152 
    153 void TestService::ReleaseOwnershipInternal(
    154     base::Closure callback) {
    155   bus_->ReleaseOwnership("org.chromium.TestService");
    156   has_ownership_ = false;
    157 
    158   bus_->GetOriginTaskRunner()->PostTask(
    159       FROM_HERE,
    160       callback);
    161 }
    162 
    163 void TestService::SetSendImmediatePropertiesChanged() {
    164   send_immediate_properties_changed_ = true;
    165 }
    166 
    167 void TestService::OnExported(const std::string& interface_name,
    168                              const std::string& method_name,
    169                              bool success) {
    170   if (!success) {
    171     LOG(ERROR) << "Failed to export: " << interface_name << "."
    172                << method_name;
    173     // Returning here will make WaitUntilServiceIsStarted() to time out
    174     // and return false.
    175     return;
    176   }
    177 
    178   ++num_exported_methods_;
    179   if (num_exported_methods_ == kNumMethodsToExport) {
    180     // As documented in exported_object.h, the service name should be
    181     // requested after all methods are exposed.
    182     bus_->RequestOwnership("org.chromium.TestService",
    183                            request_ownership_options_,
    184                            base::Bind(&TestService::OnOwnership,
    185                                       base::Unretained(this),
    186                                       base::Bind(&EmptyCallback)));
    187   }
    188 }
    189 
    190 void TestService::Run(base::MessageLoop* message_loop) {
    191   Bus::Options bus_options;
    192   bus_options.bus_type = Bus::SESSION;
    193   bus_options.connection_type = Bus::PRIVATE;
    194   bus_options.dbus_task_runner = dbus_task_runner_;
    195   bus_ = new Bus(bus_options);
    196 
    197   exported_object_ = bus_->GetExportedObject(
    198       ObjectPath("/org/chromium/TestObject"));
    199 
    200   int num_methods = 0;
    201   exported_object_->ExportMethod(
    202       "org.chromium.TestInterface",
    203       "Echo",
    204       base::Bind(&TestService::Echo,
    205                  base::Unretained(this)),
    206       base::Bind(&TestService::OnExported,
    207                  base::Unretained(this)));
    208   ++num_methods;
    209 
    210   exported_object_->ExportMethod(
    211       "org.chromium.TestInterface",
    212       "SlowEcho",
    213       base::Bind(&TestService::SlowEcho,
    214                  base::Unretained(this)),
    215       base::Bind(&TestService::OnExported,
    216                  base::Unretained(this)));
    217   ++num_methods;
    218 
    219   exported_object_->ExportMethod(
    220       "org.chromium.TestInterface",
    221       "AsyncEcho",
    222       base::Bind(&TestService::AsyncEcho,
    223                  base::Unretained(this)),
    224       base::Bind(&TestService::OnExported,
    225                  base::Unretained(this)));
    226   ++num_methods;
    227 
    228   exported_object_->ExportMethod(
    229       "org.chromium.TestInterface",
    230       "BrokenMethod",
    231       base::Bind(&TestService::BrokenMethod,
    232                  base::Unretained(this)),
    233       base::Bind(&TestService::OnExported,
    234                  base::Unretained(this)));
    235   ++num_methods;
    236 
    237   exported_object_->ExportMethod(
    238       "org.chromium.TestInterface",
    239       "PerformAction",
    240       base::Bind(&TestService::PerformAction,
    241                  base::Unretained(this)),
    242       base::Bind(&TestService::OnExported,
    243                  base::Unretained(this)));
    244   ++num_methods;
    245 
    246   exported_object_->ExportMethod(
    247        kPropertiesInterface,
    248        kPropertiesGetAll,
    249        base::Bind(&TestService::GetAllProperties,
    250                   base::Unretained(this)),
    251        base::Bind(&TestService::OnExported,
    252                   base::Unretained(this)));
    253   ++num_methods;
    254 
    255   exported_object_->ExportMethod(
    256        kPropertiesInterface,
    257        kPropertiesGet,
    258        base::Bind(&TestService::GetProperty,
    259                   base::Unretained(this)),
    260        base::Bind(&TestService::OnExported,
    261                   base::Unretained(this)));
    262   ++num_methods;
    263 
    264   exported_object_->ExportMethod(
    265        kPropertiesInterface,
    266        kPropertiesSet,
    267        base::Bind(&TestService::SetProperty,
    268                   base::Unretained(this)),
    269        base::Bind(&TestService::OnExported,
    270                   base::Unretained(this)));
    271   ++num_methods;
    272 
    273   exported_object_manager_ = bus_->GetExportedObject(
    274       ObjectPath("/org/chromium/TestService"));
    275 
    276   exported_object_manager_->ExportMethod(
    277        kObjectManagerInterface,
    278        kObjectManagerGetManagedObjects,
    279        base::Bind(&TestService::GetManagedObjects,
    280                   base::Unretained(this)),
    281        base::Bind(&TestService::OnExported,
    282                   base::Unretained(this)));
    283   ++num_methods;
    284 
    285   // Just print an error message as we don't want to crash tests.
    286   // Tests will fail at a call to WaitUntilServiceIsStarted().
    287   if (num_methods != kNumMethodsToExport) {
    288     LOG(ERROR) << "The number of methods does not match";
    289   }
    290   message_loop->Run();
    291 }
    292 
    293 void TestService::Echo(MethodCall* method_call,
    294                        ExportedObject::ResponseSender response_sender) {
    295   MessageReader reader(method_call);
    296   std::string text_message;
    297   if (!reader.PopString(&text_message)) {
    298     response_sender.Run(scoped_ptr<Response>());
    299     return;
    300   }
    301 
    302   scoped_ptr<Response> response = Response::FromMethodCall(method_call);
    303   MessageWriter writer(response.get());
    304   writer.AppendString(text_message);
    305   response_sender.Run(response.Pass());
    306 }
    307 
    308 void TestService::SlowEcho(MethodCall* method_call,
    309                            ExportedObject::ResponseSender response_sender) {
    310   base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
    311   Echo(method_call, response_sender);
    312 }
    313 
    314 void TestService::AsyncEcho(MethodCall* method_call,
    315                             ExportedObject::ResponseSender response_sender) {
    316   // Schedule a call to Echo() to send an asynchronous response after we return.
    317   message_loop()->PostDelayedTask(FROM_HERE,
    318                                   base::Bind(&TestService::Echo,
    319                                              base::Unretained(this),
    320                                              method_call,
    321                                              response_sender),
    322                                   TestTimeouts::tiny_timeout());
    323 }
    324 
    325 void TestService::BrokenMethod(MethodCall* method_call,
    326                                ExportedObject::ResponseSender response_sender) {
    327   response_sender.Run(scoped_ptr<Response>());
    328 }
    329 
    330 
    331 void TestService::GetAllProperties(
    332     MethodCall* method_call,
    333     ExportedObject::ResponseSender response_sender) {
    334   MessageReader reader(method_call);
    335   std::string interface;
    336   if (!reader.PopString(&interface)) {
    337     response_sender.Run(scoped_ptr<Response>());
    338     return;
    339   }
    340 
    341   scoped_ptr<Response> response = Response::FromMethodCall(method_call);
    342   MessageWriter writer(response.get());
    343 
    344   AddPropertiesToWriter(&writer);
    345 
    346   response_sender.Run(response.Pass());
    347 }
    348 
    349 void TestService::GetProperty(MethodCall* method_call,
    350                               ExportedObject::ResponseSender response_sender) {
    351   MessageReader reader(method_call);
    352   std::string interface;
    353   if (!reader.PopString(&interface)) {
    354     response_sender.Run(scoped_ptr<Response>());
    355     return;
    356   }
    357 
    358   std::string name;
    359   if (!reader.PopString(&name)) {
    360     response_sender.Run(scoped_ptr<Response>());
    361     return;
    362   }
    363 
    364   if (name == "Name") {
    365     // Return the previous value for the "Name" property:
    366     // Variant<"TestService">
    367     scoped_ptr<Response> response = Response::FromMethodCall(method_call);
    368     MessageWriter writer(response.get());
    369 
    370     writer.AppendVariantOfString("TestService");
    371 
    372     response_sender.Run(response.Pass());
    373   } else if (name == "Version") {
    374     // Return a new value for the "Version" property:
    375     // Variant<20>
    376     scoped_ptr<Response> response = Response::FromMethodCall(method_call);
    377     MessageWriter writer(response.get());
    378 
    379     writer.AppendVariantOfInt16(20);
    380 
    381     response_sender.Run(response.Pass());
    382   } else if (name == "Methods") {
    383     // Return the previous value for the "Methods" property:
    384     // Variant<["Echo", "SlowEcho", "AsyncEcho", "BrokenMethod"]>
    385     scoped_ptr<Response> response = Response::FromMethodCall(method_call);
    386     MessageWriter writer(response.get());
    387     MessageWriter variant_writer(NULL);
    388     MessageWriter variant_array_writer(NULL);
    389 
    390     writer.OpenVariant("as", &variant_writer);
    391     variant_writer.OpenArray("s", &variant_array_writer);
    392     variant_array_writer.AppendString("Echo");
    393     variant_array_writer.AppendString("SlowEcho");
    394     variant_array_writer.AppendString("AsyncEcho");
    395     variant_array_writer.AppendString("BrokenMethod");
    396     variant_writer.CloseContainer(&variant_array_writer);
    397     writer.CloseContainer(&variant_writer);
    398 
    399     response_sender.Run(response.Pass());
    400   } else if (name == "Objects") {
    401     // Return the previous value for the "Objects" property:
    402     // Variant<[objectpath:"/TestObjectPath"]>
    403     scoped_ptr<Response> response = Response::FromMethodCall(method_call);
    404     MessageWriter writer(response.get());
    405     MessageWriter variant_writer(NULL);
    406     MessageWriter variant_array_writer(NULL);
    407 
    408     writer.OpenVariant("ao", &variant_writer);
    409     variant_writer.OpenArray("o", &variant_array_writer);
    410     variant_array_writer.AppendObjectPath(ObjectPath("/TestObjectPath"));
    411     variant_writer.CloseContainer(&variant_array_writer);
    412     writer.CloseContainer(&variant_writer);
    413 
    414     response_sender.Run(response.Pass());
    415   } else if (name == "Bytes") {
    416     // Return the previous value for the "Bytes" property:
    417     // Variant<[0x54, 0x65, 0x73, 0x74]>
    418     scoped_ptr<Response> response = Response::FromMethodCall(method_call);
    419     MessageWriter writer(response.get());
    420     MessageWriter variant_writer(NULL);
    421     MessageWriter variant_array_writer(NULL);
    422 
    423     writer.OpenVariant("ay", &variant_writer);
    424     const uint8 bytes[] = { 0x54, 0x65, 0x73, 0x74 };
    425     variant_writer.AppendArrayOfBytes(bytes, sizeof(bytes));
    426     writer.CloseContainer(&variant_writer);
    427 
    428     response_sender.Run(response.Pass());
    429   } else {
    430     // Return error.
    431     response_sender.Run(scoped_ptr<Response>());
    432     return;
    433   }
    434 }
    435 
    436 void TestService::SetProperty(MethodCall* method_call,
    437                               ExportedObject::ResponseSender response_sender) {
    438   MessageReader reader(method_call);
    439   std::string interface;
    440   if (!reader.PopString(&interface)) {
    441     response_sender.Run(scoped_ptr<Response>());
    442     return;
    443   }
    444 
    445   std::string name;
    446   if (!reader.PopString(&name)) {
    447     response_sender.Run(scoped_ptr<Response>());
    448     return;
    449   }
    450 
    451   if (name != "Name") {
    452     response_sender.Run(scoped_ptr<Response>());
    453     return;
    454   }
    455 
    456   std::string value;
    457   if (!reader.PopVariantOfString(&value)) {
    458     response_sender.Run(scoped_ptr<Response>());
    459     return;
    460   }
    461 
    462   SendPropertyChangedSignal(value);
    463 
    464   response_sender.Run(Response::FromMethodCall(method_call));
    465 }
    466 
    467 void TestService::PerformAction(
    468       MethodCall* method_call,
    469       ExportedObject::ResponseSender response_sender) {
    470   MessageReader reader(method_call);
    471   std::string action;
    472   ObjectPath object_path;
    473   if (!reader.PopString(&action) || !reader.PopObjectPath(&object_path)) {
    474     response_sender.Run(scoped_ptr<Response>());
    475     return;
    476   }
    477 
    478   if (action == "AddObject") {
    479     AddObject(object_path);
    480   } else if (action == "RemoveObject") {
    481     RemoveObject(object_path);
    482   } else if (action == "SetSendImmediatePropertiesChanged") {
    483     SetSendImmediatePropertiesChanged();
    484   } if (action == "ReleaseOwnership") {
    485     ReleaseOwnership(base::Bind(&TestService::PerformActionResponse,
    486                                 base::Unretained(this),
    487                                 method_call, response_sender));
    488     return;
    489   } else if (action == "Ownership") {
    490     ReleaseOwnership(base::Bind(&TestService::OwnershipReleased,
    491                                 base::Unretained(this),
    492                                 method_call, response_sender));
    493     return;
    494   }
    495 
    496   scoped_ptr<Response> response = Response::FromMethodCall(method_call);
    497   response_sender.Run(response.Pass());
    498 }
    499 
    500 void TestService::PerformActionResponse(
    501     MethodCall* method_call,
    502     ExportedObject::ResponseSender response_sender) {
    503   scoped_ptr<Response> response = Response::FromMethodCall(method_call);
    504   response_sender.Run(response.Pass());
    505 }
    506 
    507 void TestService::OwnershipReleased(
    508     MethodCall* method_call,
    509     ExportedObject::ResponseSender response_sender) {
    510   RequestOwnership(base::Bind(&TestService::OwnershipRegained,
    511                               base::Unretained(this),
    512                               method_call, response_sender));
    513 }
    514 
    515 
    516 void TestService::OwnershipRegained(
    517     MethodCall* method_call,
    518     ExportedObject::ResponseSender response_sender,
    519     bool success) {
    520   PerformActionResponse(method_call, response_sender);
    521 }
    522 
    523 
    524 void TestService::GetManagedObjects(
    525     MethodCall* method_call,
    526     ExportedObject::ResponseSender response_sender) {
    527   scoped_ptr<Response> response = Response::FromMethodCall(method_call);
    528   MessageWriter writer(response.get());
    529 
    530   // The managed objects response is a dictionary of object paths identifying
    531   // the object(s) with a dictionary of strings identifying the interface(s)
    532   // they implement and then a dictionary of property values.
    533   //
    534   // Thus this looks something like:
    535   //
    536   // {
    537   //   "/org/chromium/TestObject": {
    538   //     "org.chromium.TestInterface": { /* Properties */ }
    539   //   }
    540   // }
    541 
    542 
    543   MessageWriter array_writer(NULL);
    544   MessageWriter dict_entry_writer(NULL);
    545   MessageWriter object_array_writer(NULL);
    546   MessageWriter object_dict_entry_writer(NULL);
    547 
    548   writer.OpenArray("{oa{sa{sv}}}", &array_writer);
    549 
    550   array_writer.OpenDictEntry(&dict_entry_writer);
    551   dict_entry_writer.AppendObjectPath(ObjectPath("/org/chromium/TestObject"));
    552   dict_entry_writer.OpenArray("{sa{sv}}", &object_array_writer);
    553 
    554   object_array_writer.OpenDictEntry(&object_dict_entry_writer);
    555   object_dict_entry_writer.AppendString("org.chromium.TestInterface");
    556   AddPropertiesToWriter(&object_dict_entry_writer);
    557   object_array_writer.CloseContainer(&object_dict_entry_writer);
    558 
    559   dict_entry_writer.CloseContainer(&object_array_writer);
    560 
    561   array_writer.CloseContainer(&dict_entry_writer);
    562   writer.CloseContainer(&array_writer);
    563 
    564   response_sender.Run(response.Pass());
    565 
    566   if (send_immediate_properties_changed_)
    567     SendPropertyChangedSignal("ChangedTestServiceName");
    568 }
    569 
    570 void TestService::AddPropertiesToWriter(MessageWriter* writer) {
    571   // The properties response is a dictionary of strings identifying the
    572   // property and a variant containing the property value. We return all
    573   // of the properties, thus the response is:
    574   //
    575   // {
    576   //   "Name": Variant<"TestService">,
    577   //   "Version": Variant<10>,
    578   //   "Methods": Variant<["Echo", "SlowEcho", "AsyncEcho", "BrokenMethod"]>,
    579   //   "Objects": Variant<[objectpath:"/TestObjectPath"]>
    580   //   "Bytes": Variant<[0x54, 0x65, 0x73, 0x74]>
    581   // }
    582 
    583   MessageWriter array_writer(NULL);
    584   MessageWriter dict_entry_writer(NULL);
    585   MessageWriter variant_writer(NULL);
    586   MessageWriter variant_array_writer(NULL);
    587 
    588   writer->OpenArray("{sv}", &array_writer);
    589 
    590   array_writer.OpenDictEntry(&dict_entry_writer);
    591   dict_entry_writer.AppendString("Name");
    592   dict_entry_writer.AppendVariantOfString("TestService");
    593   array_writer.CloseContainer(&dict_entry_writer);
    594 
    595   array_writer.OpenDictEntry(&dict_entry_writer);
    596   dict_entry_writer.AppendString("Version");
    597   dict_entry_writer.AppendVariantOfInt16(10);
    598   array_writer.CloseContainer(&dict_entry_writer);
    599 
    600   array_writer.OpenDictEntry(&dict_entry_writer);
    601   dict_entry_writer.AppendString("Methods");
    602   dict_entry_writer.OpenVariant("as", &variant_writer);
    603   variant_writer.OpenArray("s", &variant_array_writer);
    604   variant_array_writer.AppendString("Echo");
    605   variant_array_writer.AppendString("SlowEcho");
    606   variant_array_writer.AppendString("AsyncEcho");
    607   variant_array_writer.AppendString("BrokenMethod");
    608   variant_writer.CloseContainer(&variant_array_writer);
    609   dict_entry_writer.CloseContainer(&variant_writer);
    610   array_writer.CloseContainer(&dict_entry_writer);
    611 
    612   array_writer.OpenDictEntry(&dict_entry_writer);
    613   dict_entry_writer.AppendString("Objects");
    614   dict_entry_writer.OpenVariant("ao", &variant_writer);
    615   variant_writer.OpenArray("o", &variant_array_writer);
    616   variant_array_writer.AppendObjectPath(ObjectPath("/TestObjectPath"));
    617   variant_writer.CloseContainer(&variant_array_writer);
    618   dict_entry_writer.CloseContainer(&variant_writer);
    619   array_writer.CloseContainer(&dict_entry_writer);
    620 
    621   array_writer.OpenDictEntry(&dict_entry_writer);
    622   dict_entry_writer.AppendString("Bytes");
    623   dict_entry_writer.OpenVariant("ay", &variant_writer);
    624   const uint8 bytes[] = { 0x54, 0x65, 0x73, 0x74 };
    625   variant_writer.AppendArrayOfBytes(bytes, sizeof(bytes));
    626   dict_entry_writer.CloseContainer(&variant_writer);
    627   array_writer.CloseContainer(&dict_entry_writer);
    628 
    629   writer->CloseContainer(&array_writer);
    630 }
    631 
    632 void TestService::AddObject(const ObjectPath& object_path) {
    633   message_loop()->PostTask(
    634       FROM_HERE,
    635       base::Bind(&TestService::AddObjectInternal,
    636                  base::Unretained(this),
    637                  object_path));
    638 }
    639 
    640 void TestService::AddObjectInternal(const ObjectPath& object_path) {
    641   Signal signal(kObjectManagerInterface, kObjectManagerInterfacesAdded);
    642   MessageWriter writer(&signal);
    643   writer.AppendObjectPath(object_path);
    644 
    645   MessageWriter array_writer(NULL);
    646   MessageWriter dict_entry_writer(NULL);
    647 
    648   writer.OpenArray("{sa{sv}}", &array_writer);
    649   array_writer.OpenDictEntry(&dict_entry_writer);
    650   dict_entry_writer.AppendString("org.chromium.TestInterface");
    651   AddPropertiesToWriter(&dict_entry_writer);
    652   array_writer.CloseContainer(&dict_entry_writer);
    653   writer.CloseContainer(&array_writer);
    654 
    655   exported_object_manager_->SendSignal(&signal);
    656 }
    657 
    658 void TestService::RemoveObject(const ObjectPath& object_path) {
    659   message_loop()->PostTask(FROM_HERE,
    660                            base::Bind(&TestService::RemoveObjectInternal,
    661                                       base::Unretained(this),
    662                                       object_path));
    663 }
    664 
    665 void TestService::RemoveObjectInternal(const ObjectPath& object_path) {
    666   Signal signal(kObjectManagerInterface, kObjectManagerInterfacesRemoved);
    667   MessageWriter writer(&signal);
    668 
    669   writer.AppendObjectPath(object_path);
    670 
    671   std::vector<std::string> interfaces;
    672   interfaces.push_back("org.chromium.TestInterface");
    673   writer.AppendArrayOfStrings(interfaces);
    674 
    675   exported_object_manager_->SendSignal(&signal);
    676 }
    677 
    678 void TestService::SendPropertyChangedSignal(const std::string& name) {
    679   message_loop()->PostTask(
    680       FROM_HERE,
    681       base::Bind(&TestService::SendPropertyChangedSignalInternal,
    682                  base::Unretained(this),
    683                  name));
    684 }
    685 
    686 void TestService::SendPropertyChangedSignalInternal(const std::string& name) {
    687   Signal signal(kPropertiesInterface, kPropertiesChanged);
    688   MessageWriter writer(&signal);
    689   writer.AppendString("org.chromium.TestInterface");
    690 
    691   MessageWriter array_writer(NULL);
    692   MessageWriter dict_entry_writer(NULL);
    693 
    694   writer.OpenArray("{sv}", &array_writer);
    695   array_writer.OpenDictEntry(&dict_entry_writer);
    696   dict_entry_writer.AppendString("Name");
    697   dict_entry_writer.AppendVariantOfString(name);
    698   array_writer.CloseContainer(&dict_entry_writer);
    699   writer.CloseContainer(&array_writer);
    700 
    701   exported_object_->SendSignal(&signal);
    702 }
    703 
    704 }  // namespace dbus
    705