• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
EmptyCallback(bool)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 
Options()30 TestService::Options::Options()
31     : request_ownership_options(Bus::REQUIRE_PRIMARY) {
32 }
33 
~Options()34 TestService::Options::~Options() {
35 }
36 
TestService(const Options & options)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 
~TestService()45 TestService::~TestService() {
46   Stop();
47 }
48 
StartService()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 
WaitUntilServiceIsStarted()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 
ShutdownAndBlock()61 void TestService::ShutdownAndBlock() {
62   message_loop()->PostTask(
63       FROM_HERE,
64       base::Bind(&TestService::ShutdownAndBlockInternal,
65                  base::Unretained(this)));
66 }
67 
HasDBusThread()68 bool TestService::HasDBusThread() {
69   return bus_->HasDBusThread();
70 }
71 
ShutdownAndBlockInternal()72 void TestService::ShutdownAndBlockInternal() {
73   if (HasDBusThread())
74     bus_->ShutdownOnDBusThreadAndBlock();
75   else
76     bus_->ShutdownAndBlock();
77 }
78 
SendTestSignal(const std::string & message)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 
SendTestSignalFromRoot(const std::string & message)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 
SendTestSignalInternal(const std::string & message)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 
SendTestSignalFromRootInternal(const std::string & message)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 
RequestOwnership(base::Callback<void (bool)> callback)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 
RequestOwnershipInternal(base::Callback<void (bool)> callback)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 
OnOwnership(base::Callback<void (bool)> callback,const std::string & service_name,bool success)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 
ReleaseOwnership(base::Closure callback)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 
ReleaseOwnershipInternal(base::Closure callback)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 
SetSendImmediatePropertiesChanged()163 void TestService::SetSendImmediatePropertiesChanged() {
164   send_immediate_properties_changed_ = true;
165 }
166 
OnExported(const std::string & interface_name,const std::string & method_name,bool success)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 
Run(base::MessageLoop * message_loop)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 
Echo(MethodCall * method_call,ExportedObject::ResponseSender response_sender)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 
SlowEcho(MethodCall * method_call,ExportedObject::ResponseSender response_sender)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 
AsyncEcho(MethodCall * method_call,ExportedObject::ResponseSender response_sender)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 
BrokenMethod(MethodCall * method_call,ExportedObject::ResponseSender response_sender)325 void TestService::BrokenMethod(MethodCall* method_call,
326                                ExportedObject::ResponseSender response_sender) {
327   response_sender.Run(scoped_ptr<Response>());
328 }
329 
330 
GetAllProperties(MethodCall * method_call,ExportedObject::ResponseSender response_sender)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 
GetProperty(MethodCall * method_call,ExportedObject::ResponseSender response_sender)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 
SetProperty(MethodCall * method_call,ExportedObject::ResponseSender response_sender)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 
PerformAction(MethodCall * method_call,ExportedObject::ResponseSender response_sender)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 
PerformActionResponse(MethodCall * method_call,ExportedObject::ResponseSender response_sender)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 
OwnershipReleased(MethodCall * method_call,ExportedObject::ResponseSender response_sender)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 
OwnershipRegained(MethodCall * method_call,ExportedObject::ResponseSender response_sender,bool success)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 
GetManagedObjects(MethodCall * method_call,ExportedObject::ResponseSender response_sender)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 
AddPropertiesToWriter(MessageWriter * writer)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 
AddObject(const ObjectPath & object_path)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 
AddObjectInternal(const ObjectPath & object_path)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 
RemoveObject(const ObjectPath & object_path)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 
RemoveObjectInternal(const ObjectPath & object_path)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 
SendPropertyChangedSignal(const std::string & name)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 
SendPropertyChangedSignalInternal(const std::string & name)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