1 // Copyright 2014 The Chromium OS 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 "chromeos-dbus-bindings/proxy_generator.h" 6 7 #include <utility> 8 9 #include <base/files/file_path.h> 10 #include <base/format_macros.h> 11 #include <base/logging.h> 12 #include <base/strings/stringprintf.h> 13 #include <brillo/strings/string_utils.h> 14 15 #include "chromeos-dbus-bindings/dbus_signature.h" 16 #include "chromeos-dbus-bindings/indented_text.h" 17 #include "chromeos-dbus-bindings/name_parser.h" 18 19 using base::StringPrintf; 20 using std::pair; 21 using std::string; 22 using std::vector; 23 24 namespace chromeos_dbus_bindings { 25 26 namespace { 27 // Helper struct to encapsulate information about method call parameter during 28 // code generation. 29 struct ParamDef { 30 ParamDef(const string& param_type, const string& param_name, bool param_ref) 31 : type(param_type), name(param_name), is_const_ref(param_ref) {} 32 33 string type; 34 string name; 35 bool is_const_ref; 36 }; 37 38 string GetParamString(const ParamDef& param_def) { 39 return StringPrintf(param_def.is_const_ref ? "const %s& %s" : "%s* %s", 40 param_def.type.c_str(), param_def.name.c_str()); 41 } 42 } // anonymous namespace 43 44 // static 45 bool ProxyGenerator::GenerateProxies( 46 const ServiceConfig& config, 47 const std::vector<Interface>& interfaces, 48 const base::FilePath& output_file) { 49 IndentedText text; 50 51 text.AddLine("// Automatic generation of D-Bus interfaces:"); 52 for (const auto& interface : interfaces) { 53 text.AddLine(StringPrintf("// - %s", interface.name.c_str())); 54 } 55 string header_guard = GenerateHeaderGuard(output_file); 56 text.AddLine(StringPrintf("#ifndef %s", header_guard.c_str())); 57 text.AddLine(StringPrintf("#define %s", header_guard.c_str())); 58 text.AddLine("#include <memory>"); 59 text.AddLine("#include <string>"); 60 text.AddLine("#include <vector>"); 61 text.AddBlankLine(); 62 text.AddLine("#include <base/bind.h>"); 63 text.AddLine("#include <base/callback.h>"); 64 text.AddLine("#include <base/logging.h>"); 65 text.AddLine("#include <base/macros.h>"); 66 text.AddLine("#include <base/memory/ref_counted.h>"); 67 text.AddLine("#include <brillo/any.h>"); 68 text.AddLine("#include <brillo/dbus/dbus_method_invoker.h>"); 69 text.AddLine("#include <brillo/dbus/dbus_property.h>"); 70 text.AddLine("#include <brillo/dbus/dbus_signal_handler.h>"); 71 text.AddLine("#include <brillo/errors/error.h>"); 72 text.AddLine("#include <brillo/variant_dictionary.h>"); 73 text.AddLine("#include <dbus/bus.h>"); 74 text.AddLine("#include <dbus/message.h>"); 75 text.AddLine("#include <dbus/object_manager.h>"); 76 text.AddLine("#include <dbus/object_path.h>"); 77 text.AddLine("#include <dbus/object_proxy.h>"); 78 text.AddBlankLine(); 79 80 if (!config.object_manager.name.empty()) { 81 // Add forward-declaration for Object Manager proxy class. 82 NameParser parser{config.object_manager.name}; 83 parser.AddOpenNamespaces(&text, false); 84 text.AddLine(StringPrintf("class %s;", 85 parser.MakeProxyName(false).c_str())); 86 parser.AddCloseNamespaces(&text, false); 87 text.AddBlankLine(); 88 } 89 90 for (const auto& interface : interfaces) { 91 GenerateInterfaceProxyInterface(config, interface, &text); 92 GenerateInterfaceProxy(config, interface, &text); 93 } 94 95 ObjectManager::GenerateProxy(config, interfaces, &text); 96 97 text.AddLine(StringPrintf("#endif // %s", header_guard.c_str())); 98 return WriteTextToFile(output_file, text); 99 } 100 101 // static 102 bool ProxyGenerator::GenerateMocks(const ServiceConfig& config, 103 const std::vector<Interface>& interfaces, 104 const base::FilePath& mock_file, 105 const base::FilePath& proxy_file, 106 bool use_literal_proxy_file) { 107 IndentedText text; 108 109 text.AddLine("// Automatic generation of D-Bus interface mock proxies for:"); 110 for (const auto& interface : interfaces) { 111 text.AddLine(StringPrintf("// - %s", interface.name.c_str())); 112 } 113 string header_guard = GenerateHeaderGuard(mock_file); 114 text.AddLine(StringPrintf("#ifndef %s", header_guard.c_str())); 115 text.AddLine(StringPrintf("#define %s", header_guard.c_str())); 116 text.AddLine("#include <string>"); 117 text.AddLine("#include <vector>"); 118 text.AddBlankLine(); 119 text.AddLine("#include <base/callback_forward.h>"); 120 text.AddLine("#include <base/logging.h>"); 121 text.AddLine("#include <base/macros.h>"); 122 text.AddLine("#include <brillo/any.h>"); 123 text.AddLine("#include <brillo/errors/error.h>"); 124 text.AddLine("#include <brillo/variant_dictionary.h>"); 125 text.AddLine("#include <gmock/gmock.h>"); 126 text.AddBlankLine(); 127 128 if (!proxy_file.empty()) { 129 // If we have a proxy header file, it would have the proxy interfaces we 130 // need to base our mocks on, so we need to include that header file. 131 base::FilePath relative_path; 132 if (use_literal_proxy_file) { 133 relative_path = proxy_file; 134 } else { 135 // Generate a relative path from |mock_file| to |proxy_file|. 136 137 // First, get the path components for both source and destination paths. 138 std::vector<base::FilePath::StringType> src_components; 139 mock_file.DirName().GetComponents(&src_components); 140 std::vector<base::FilePath::StringType> dest_components; 141 proxy_file.DirName().GetComponents(&dest_components); 142 143 // Find the common root. 144 145 // I wish we had C++14 and its 4-parameter version of std::mismatch()... 146 auto src_end = src_components.end(); 147 if (src_components.size() > dest_components.size()) 148 src_end = src_components.begin() + dest_components.size(); 149 150 auto mismatch_pair = std::mismatch(src_components.begin(), src_end, 151 dest_components.begin()); 152 153 // For each remaining components in the |src_components|, generate the 154 // parent directory references (".."). 155 size_t src_count = std::distance(mismatch_pair.first, 156 src_components.end()); 157 std::vector<base::FilePath::StringType> components{ 158 src_count, base::FilePath::kParentDirectory}; 159 // Append the remaining components from |dest_components|. 160 components.insert(components.end(), 161 mismatch_pair.second, dest_components.end()); 162 // Finally, add the base name of the target file name. 163 components.push_back(proxy_file.BaseName().value()); 164 // Now reconstruct the relative path. 165 relative_path = base::FilePath{base::FilePath::kCurrentDirectory}; 166 for (const auto& component : components) 167 relative_path = relative_path.Append(component); 168 } 169 text.AddLine(StringPrintf("#include \"%s\"", 170 relative_path.value().c_str())); 171 text.AddBlankLine(); 172 } 173 174 for (const auto& interface : interfaces) { 175 // If we have no proxy file, we need the abstract interfaces generated here. 176 if (proxy_file.empty()) 177 GenerateInterfaceProxyInterface(config, interface, &text); 178 GenerateInterfaceMock(config, interface, &text); 179 } 180 181 text.AddLine(StringPrintf("#endif // %s", header_guard.c_str())); 182 return WriteTextToFile(mock_file, text); 183 } 184 185 // static 186 void ProxyGenerator::GenerateInterfaceProxyInterface( 187 const ServiceConfig& config, 188 const Interface& interface, 189 IndentedText* text) { 190 NameParser parser{interface.name}; 191 string proxy_name = parser.MakeProxyName(false); 192 string base_interface_name = proxy_name + "Interface"; 193 194 parser.AddOpenNamespaces(text, false); 195 text->AddBlankLine(); 196 197 text->AddLine(StringPrintf("// Abstract interface proxy for %s.", 198 parser.MakeFullCppName().c_str())); 199 text->AddComments(interface.doc_string); 200 text->AddLine(StringPrintf("class %s {", base_interface_name.c_str())); 201 text->AddLineWithOffset("public:", kScopeOffset); 202 text->PushOffset(kBlockOffset); 203 text->AddLine( 204 StringPrintf("virtual ~%s() = default;", base_interface_name.c_str())); 205 206 for (const auto& method : interface.methods) { 207 AddMethodProxy(method, interface.name, true, text); 208 AddAsyncMethodProxy(method, interface.name, true, text); 209 } 210 for (const auto& signal : interface.signals) { 211 AddSignalHandlerRegistration(signal, interface.name, true, text); 212 } 213 AddProperties(config, interface, true, text); 214 text->AddBlankLine(); 215 text->AddLine("virtual const dbus::ObjectPath& GetObjectPath() const = 0;"); 216 if (!config.object_manager.name.empty() && !interface.properties.empty()) 217 AddPropertyPublicMethods(proxy_name, true, text); 218 219 text->PopOffset(); 220 text->AddLine("};"); 221 text->AddBlankLine(); 222 223 parser.AddCloseNamespaces(text, false); 224 text->AddBlankLine(); 225 } 226 227 // static 228 void ProxyGenerator::GenerateInterfaceProxy(const ServiceConfig& config, 229 const Interface& interface, 230 IndentedText* text) { 231 NameParser parser{interface.name}; 232 string proxy_name = parser.MakeProxyName(false); 233 string base_interface_name = proxy_name + "Interface"; 234 235 parser.AddOpenNamespaces(text, false); 236 text->AddBlankLine(); 237 238 text->AddLine(StringPrintf("// Interface proxy for %s.", 239 parser.MakeFullCppName().c_str())); 240 text->AddComments(interface.doc_string); 241 text->AddLine(StringPrintf("class %s final : public %s {", 242 proxy_name.c_str(), base_interface_name.c_str())); 243 text->AddLineWithOffset("public:", kScopeOffset); 244 text->PushOffset(kBlockOffset); 245 AddPropertySet(config, interface, text); 246 AddConstructor(config, interface, proxy_name, text); 247 AddDestructor(proxy_name, text); 248 for (const auto& signal : interface.signals) { 249 AddSignalHandlerRegistration(signal, interface.name, false, text); 250 } 251 AddReleaseObjectProxy(text); 252 AddGetObjectPath(text); 253 AddGetObjectProxy(text); 254 if (!config.object_manager.name.empty() && !interface.properties.empty()) 255 AddPropertyPublicMethods(proxy_name, false, text); 256 for (const auto& method : interface.methods) { 257 AddMethodProxy(method, interface.name, false, text); 258 AddAsyncMethodProxy(method, interface.name, false, text); 259 } 260 AddProperties(config, interface, false, text); 261 262 text->PopOffset(); 263 text->AddBlankLine(); 264 text->AddLineWithOffset("private:", kScopeOffset); 265 266 text->PushOffset(kBlockOffset); 267 if (!config.object_manager.name.empty() && !interface.properties.empty()) 268 AddOnPropertyChanged(text); 269 text->AddLine("scoped_refptr<dbus::Bus> bus_;"); 270 if (config.service_name.empty()) { 271 text->AddLine("std::string service_name_;"); 272 } else { 273 text->AddLine(StringPrintf("const std::string service_name_{\"%s\"};", 274 config.service_name.c_str())); 275 } 276 if (interface.path.empty()) { 277 text->AddLine("dbus::ObjectPath object_path_;"); 278 } else { 279 text->AddLine(StringPrintf("const dbus::ObjectPath object_path_{\"%s\"};", 280 interface.path.c_str())); 281 } 282 if (!config.object_manager.name.empty() && !interface.properties.empty()) { 283 text->AddLine("PropertySet* property_set_;"); 284 text->AddLine( 285 StringPrintf("base::Callback<void(%sInterface*, const std::string&)> " 286 "on_property_changed_;", 287 proxy_name.c_str())); 288 } 289 text->AddLine("dbus::ObjectProxy* dbus_object_proxy_;"); 290 text->AddBlankLine(); 291 292 if (!config.object_manager.name.empty() && !interface.properties.empty()) { 293 text->AddLine(StringPrintf( 294 "friend class %s;", 295 NameParser{config.object_manager.name}.MakeProxyName(true).c_str())); 296 } 297 text->AddLine(StringPrintf("DISALLOW_COPY_AND_ASSIGN(%s);", 298 proxy_name.c_str())); 299 text->PopOffset(); 300 text->AddLine("};"); 301 302 text->AddBlankLine(); 303 304 parser.AddCloseNamespaces(text, false); 305 306 text->AddBlankLine(); 307 } 308 309 // static 310 void ProxyGenerator::GenerateInterfaceMock(const ServiceConfig& config, 311 const Interface& interface, 312 IndentedText* text) { 313 NameParser parser{interface.name}; 314 string proxy_name = parser.MakeProxyName(false); 315 string base_interface_name = proxy_name + "Interface"; 316 string mock_name = proxy_name + "Mock"; 317 318 parser.AddOpenNamespaces(text, false); 319 text->AddBlankLine(); 320 321 text->AddLine(StringPrintf("// Mock object for %s.", 322 base_interface_name.c_str())); 323 text->AddLine(StringPrintf("class %s : public %s {", 324 mock_name.c_str(), base_interface_name.c_str())); 325 text->AddLineWithOffset("public:", kScopeOffset); 326 text->PushOffset(kBlockOffset); 327 text->AddLine(StringPrintf("%s() = default;", mock_name.c_str())); 328 text->AddBlankLine(); 329 330 for (const auto& method : interface.methods) { 331 AddMethodMock(method, interface.name, text); 332 AddAsyncMethodMock(method, interface.name, text); 333 } 334 for (const auto& signal : interface.signals) { 335 AddSignalHandlerRegistrationMock(signal, text); 336 } 337 338 DbusSignature signature; 339 for (const auto& prop : interface.properties) { 340 string type; 341 CHECK(signature.Parse(prop.type, &type)); 342 MakeConstReferenceIfNeeded(&type); 343 string name = NameParser{prop.name}.MakeVariableName(); 344 text->AddLine(StringPrintf("MOCK_CONST_METHOD0(%s, %s());", 345 name.c_str(), type.c_str())); 346 if (prop.access == "readwrite") { 347 text->AddLine(StringPrintf("MOCK_METHOD2(set_%s, void(%s, " 348 "const base::Callback<bool>&));", 349 name.c_str(), type.c_str())); 350 } 351 } 352 text->AddLine( 353 "MOCK_CONST_METHOD0(GetObjectPath, const dbus::ObjectPath&());"); 354 if (!config.object_manager.name.empty() && !interface.properties.empty()) { 355 text->AddLineAndPushOffsetTo( 356 "MOCK_METHOD1(SetPropertyChangedCallback,", 1, '('); 357 text->AddLine(StringPrintf( 358 "void(const base::Callback<void(%sInterface*, const std::string&)>&));", 359 proxy_name.c_str())); 360 text->PopOffset(); 361 } 362 363 text->PopOffset(); 364 text->AddBlankLine(); 365 text->AddLineWithOffset("private:", kScopeOffset); 366 text->AddLineWithOffset(StringPrintf("DISALLOW_COPY_AND_ASSIGN(%s);", 367 mock_name.c_str()), 368 kBlockOffset); 369 text->AddLine("};"); 370 371 parser.AddCloseNamespaces(text, false); 372 text->AddBlankLine(); 373 } 374 375 // static 376 void ProxyGenerator::AddConstructor(const ServiceConfig& config, 377 const Interface& interface, 378 const string& class_name, 379 IndentedText* text) { 380 IndentedText block; 381 vector<ParamDef> args{{"scoped_refptr<dbus::Bus>", "bus", true}}; 382 if (config.service_name.empty()) 383 args.emplace_back("std::string", "service_name", true); 384 if (interface.path.empty()) 385 args.emplace_back("dbus::ObjectPath", "object_path", true); 386 if (!config.object_manager.name.empty() && !interface.properties.empty()) 387 args.emplace_back("PropertySet", "property_set", false); 388 389 if (args.size() == 1) { 390 block.AddLine(StringPrintf("%s(%s) :", class_name.c_str(), 391 GetParamString(args.front()).c_str())); 392 } else { 393 block.AddLine(StringPrintf("%s(", class_name.c_str())); 394 block.PushOffset(kLineContinuationOffset); 395 for (size_t i = 0; i < args.size() - 1; i++) { 396 block.AddLine(StringPrintf("%s,", GetParamString(args[i]).c_str())); 397 } 398 block.AddLine(StringPrintf("%s) :", GetParamString(args.back()).c_str())); 399 } 400 block.PushOffset(kLineContinuationOffset); 401 for (const auto& arg : args) { 402 block.AddLine(StringPrintf("%s_{%s},", arg.name.c_str(), 403 arg.name.c_str())); 404 } 405 block.AddLine("dbus_object_proxy_{"); 406 block.AddLineWithOffset( 407 "bus_->GetObjectProxy(service_name_, object_path_)} {", 408 kLineContinuationOffset); 409 block.PopOffset(); 410 if (args.size() > 1) 411 block.PopOffset(); 412 block.AddLine("}"); 413 block.AddBlankLine(); 414 text->AddBlock(block); 415 } 416 417 // static 418 void ProxyGenerator::AddDestructor(const string& class_name, 419 IndentedText* text) { 420 IndentedText block; 421 block.AddLine(StringPrintf("~%s() override {", class_name.c_str())); 422 block.AddLine("}"); 423 text->AddBlock(block); 424 } 425 426 // static 427 void ProxyGenerator::AddReleaseObjectProxy(IndentedText* text) { 428 text->AddBlankLine(); 429 text->AddLine("void ReleaseObjectProxy(const base::Closure& callback) {"); 430 text->AddLineWithOffset( 431 "bus_->RemoveObjectProxy(service_name_, object_path_, callback);", 432 kBlockOffset); 433 text->AddLine("}"); 434 } 435 436 // static 437 void ProxyGenerator::AddGetObjectPath(IndentedText* text) { 438 text->AddBlankLine(); 439 text->AddLine("const dbus::ObjectPath& GetObjectPath() const override {"); 440 text->AddLineWithOffset("return object_path_;", kBlockOffset); 441 text->AddLine("}"); 442 } 443 444 // static 445 void ProxyGenerator::AddGetObjectProxy(IndentedText* text) { 446 text->AddBlankLine(); 447 text->AddLine("dbus::ObjectProxy* GetObjectProxy() const { " 448 "return dbus_object_proxy_; }"); 449 } 450 451 // static 452 void ProxyGenerator::AddPropertyPublicMethods(const string& class_name, 453 bool declaration_only, 454 IndentedText* text) { 455 text->AddBlankLine(); 456 text->AddLine(StringPrintf("%svoid SetPropertyChangedCallback(", 457 declaration_only ? "virtual " : "")); 458 text->AddLineWithOffset( 459 StringPrintf("const base::Callback<void(%sInterface*, " 460 "const std::string&)>& callback) %s", 461 class_name.c_str(), 462 declaration_only ? "= 0;" : "override {"), 463 kLineContinuationOffset); 464 if (!declaration_only) { 465 text->AddLineWithOffset("on_property_changed_ = callback;", kBlockOffset); 466 text->AddLine("}"); 467 text->AddBlankLine(); 468 469 text->AddLine( 470 "const PropertySet* GetProperties() const { return property_set_; }"); 471 text->AddLine("PropertySet* GetProperties() { return property_set_; }"); 472 } 473 } 474 475 // static 476 void ProxyGenerator::AddOnPropertyChanged(IndentedText* text) { 477 text->AddLine("void OnPropertyChanged(const std::string& property_name) {"); 478 text->PushOffset(kBlockOffset); 479 text->AddLine("if (!on_property_changed_.is_null())"); 480 text->PushOffset(kBlockOffset); 481 text->AddLine("on_property_changed_.Run(this, property_name);"); 482 text->PopOffset(); 483 text->PopOffset(); 484 text->AddLine("}"); 485 text->AddBlankLine(); 486 } 487 488 void ProxyGenerator::AddSignalHandlerRegistration( 489 const Interface::Signal& signal, 490 const string& interface_name, 491 bool declaration_only, 492 IndentedText* text) { 493 IndentedText block; 494 block.AddBlankLine(); 495 block.AddLine(StringPrintf("%svoid Register%sSignalHandler(", 496 declaration_only ? "virtual " : "", 497 signal.name.c_str())); 498 block.PushOffset(kLineContinuationOffset); 499 AddSignalCallbackArg(signal, false, &block); 500 block.AddLine(StringPrintf( 501 "dbus::ObjectProxy::OnConnectedCallback on_connected_callback)%s", 502 declaration_only ? " = 0;" : " override {")); 503 if (!declaration_only) { 504 block.PopOffset(); // Method signature arguments 505 block.PushOffset(kBlockOffset); 506 block.AddLine("brillo::dbus_utils::ConnectToSignal("); 507 block.PushOffset(kLineContinuationOffset); 508 block.AddLine("dbus_object_proxy_,"); 509 block.AddLine(StringPrintf("\"%s\",", interface_name.c_str())); 510 block.AddLine(StringPrintf("\"%s\",", signal.name.c_str())); 511 block.AddLine("signal_callback,"); 512 block.AddLine("on_connected_callback);"); 513 block.PopOffset(); // Function call line continuation 514 block.PopOffset(); // Method body 515 block.AddLine("}"); 516 } 517 text->AddBlock(block); 518 } 519 520 // static 521 void ProxyGenerator::AddPropertySet(const ServiceConfig& config, 522 const Interface& interface, 523 IndentedText* text) { 524 // Must have ObjectManager in order for property system to work correctly. 525 if (config.object_manager.name.empty()) 526 return; 527 528 IndentedText block; 529 block.AddLine("class PropertySet : public dbus::PropertySet {"); 530 block.AddLineWithOffset("public:", kScopeOffset); 531 block.PushOffset(kBlockOffset); 532 block.AddLineAndPushOffsetTo("PropertySet(dbus::ObjectProxy* object_proxy,", 533 1, '('); 534 block.AddLine("const PropertyChangedCallback& callback)"); 535 block.PopOffset(); 536 block.PushOffset(kLineContinuationOffset); 537 block.AddLineAndPushOffsetTo(": dbus::PropertySet{object_proxy,", 1, '{'); 538 block.AddLine(StringPrintf("\"%s\",", interface.name.c_str())); 539 block.AddLine("callback} {"); 540 block.PopOffset(); 541 block.PopOffset(); 542 block.PushOffset(kBlockOffset); 543 for (const auto& prop : interface.properties) { 544 block.AddLine( 545 StringPrintf("RegisterProperty(%sName(), &%s);", 546 prop.name.c_str(), 547 NameParser{prop.name}.MakeVariableName().c_str())); 548 } 549 block.PopOffset(); 550 block.AddLine("}"); 551 block.AddBlankLine(); 552 553 DbusSignature signature; 554 for (const auto& prop : interface.properties) { 555 string type; 556 CHECK(signature.Parse(prop.type, &type)); 557 block.AddLine( 558 StringPrintf("brillo::dbus_utils::Property<%s> %s;", 559 type.c_str(), 560 NameParser{prop.name}.MakeVariableName().c_str())); 561 } 562 block.AddBlankLine(); 563 564 block.PopOffset(); 565 block.AddLineWithOffset("private:", kScopeOffset); 566 block.AddLineWithOffset("DISALLOW_COPY_AND_ASSIGN(PropertySet);", 567 kBlockOffset); 568 block.AddLine("};"); 569 block.AddBlankLine(); 570 571 text->AddBlock(block); 572 } 573 574 // static 575 void ProxyGenerator::AddProperties(const ServiceConfig& config, 576 const Interface& interface, 577 bool declaration_only, 578 IndentedText* text) { 579 // Must have ObjectManager in order for property system to work correctly. 580 if (config.object_manager.name.empty()) 581 return; 582 583 if (declaration_only && !interface.properties.empty()) 584 text->AddBlankLine(); 585 586 DbusSignature signature; 587 for (const auto& prop : interface.properties) { 588 if (declaration_only) { 589 text->AddLine( 590 StringPrintf("static const char* %sName() { return \"%s\"; }", 591 prop.name.c_str(), 592 prop.name.c_str())); 593 } 594 string type; 595 CHECK(signature.Parse(prop.type, &type)); 596 MakeConstReferenceIfNeeded(&type); 597 string name = NameParser{prop.name}.MakeVariableName(); 598 if (!declaration_only) 599 text->AddBlankLine(); 600 text->AddLine( 601 StringPrintf("%s%s %s() const%s", 602 declaration_only ? "virtual " : "", 603 type.c_str(), 604 name.c_str(), 605 declaration_only ? " = 0;" : " override {")); 606 if (!declaration_only) { 607 text->AddLineWithOffset( 608 StringPrintf("return property_set_->%s.value();", name.c_str()), 609 kBlockOffset); 610 text->AddLine("}"); 611 } 612 if (prop.access == "readwrite") { 613 if (!declaration_only) 614 text->AddBlankLine(); 615 text->AddLineAndPushOffsetTo( 616 StringPrintf("%svoid set_%s(%s value,", 617 declaration_only ? "virtual " : "", 618 name.c_str(), 619 type.c_str()), 620 1, '('); 621 text->AddLine( 622 StringPrintf("const base::Callback<void(bool)>& callback)%s", 623 declaration_only ? " = 0;" : " override {")); 624 text->PopOffset(); 625 if (!declaration_only) { 626 text->AddLineWithOffset( 627 StringPrintf("property_set_->%s.Set(value, callback);", name.c_str()), 628 kBlockOffset); 629 text->AddLine("}"); 630 } 631 } 632 } 633 } 634 635 // static 636 void ProxyGenerator::AddMethodProxy(const Interface::Method& method, 637 const string& interface_name, 638 bool declaration_only, 639 IndentedText* text) { 640 IndentedText block; 641 DbusSignature signature; 642 block.AddBlankLine(); 643 block.AddComments(method.doc_string); 644 block.AddLine(StringPrintf("%sbool %s(", 645 declaration_only ? "virtual " : "", 646 method.name.c_str())); 647 block.PushOffset(kLineContinuationOffset); 648 vector<string> argument_names; 649 int argument_number = 0; 650 for (const auto& argument : method.input_arguments) { 651 string argument_type; 652 CHECK(signature.Parse(argument.type, &argument_type)); 653 MakeConstReferenceIfNeeded(&argument_type); 654 string argument_name = GetArgName("in", argument.name, ++argument_number); 655 argument_names.push_back(argument_name); 656 block.AddLine(StringPrintf( 657 "%s %s,", argument_type.c_str(), argument_name.c_str())); 658 } 659 vector<string> out_param_names{"response.get()", "error"}; 660 for (const auto& argument : method.output_arguments) { 661 string argument_type; 662 CHECK(signature.Parse(argument.type, &argument_type)); 663 string argument_name = GetArgName("out", argument.name, ++argument_number); 664 out_param_names.push_back(argument_name); 665 block.AddLine(StringPrintf( 666 "%s* %s,", argument_type.c_str(), argument_name.c_str())); 667 } 668 block.AddLine("brillo::ErrorPtr* error,"); 669 block.AddLine( 670 StringPrintf("int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)%s", 671 declaration_only ? " = 0;" : " override {")); 672 block.PopOffset(); 673 if (!declaration_only) { 674 block.PushOffset(kBlockOffset); 675 676 block.AddLine( 677 "auto response = brillo::dbus_utils::CallMethodAndBlockWithTimeout("); 678 block.PushOffset(kLineContinuationOffset); 679 block.AddLine("timeout_ms,"); 680 block.AddLine("dbus_object_proxy_,"); 681 block.AddLine(StringPrintf("\"%s\",", interface_name.c_str())); 682 block.AddLine(StringPrintf("\"%s\",", method.name.c_str())); 683 string last_argument = "error"; 684 for (const auto& argument_name : argument_names) { 685 block.AddLine(StringPrintf("%s,", last_argument.c_str())); 686 last_argument = argument_name; 687 } 688 block.AddLine(StringPrintf("%s);", last_argument.c_str())); 689 block.PopOffset(); 690 691 block.AddLine("return response && " 692 "brillo::dbus_utils::ExtractMethodCallResults("); 693 block.PushOffset(kLineContinuationOffset); 694 block.AddLine(brillo::string_utils::Join(", ", out_param_names) + ");"); 695 block.PopOffset(); 696 block.PopOffset(); 697 block.AddLine("}"); 698 } 699 text->AddBlock(block); 700 } 701 702 // static 703 void ProxyGenerator::AddAsyncMethodProxy(const Interface::Method& method, 704 const string& interface_name, 705 bool declaration_only, 706 IndentedText* text) { 707 IndentedText block; 708 DbusSignature signature; 709 block.AddBlankLine(); 710 block.AddComments(method.doc_string); 711 block.AddLine(StringPrintf("%svoid %sAsync(", 712 declaration_only ? "virtual " : "", 713 method.name.c_str())); 714 block.PushOffset(kLineContinuationOffset); 715 vector<string> argument_names; 716 int argument_number = 0; 717 for (const auto& argument : method.input_arguments) { 718 string argument_type; 719 CHECK(signature.Parse(argument.type, &argument_type)); 720 MakeConstReferenceIfNeeded(&argument_type); 721 string argument_name = GetArgName("in", argument.name, ++argument_number); 722 argument_names.push_back(argument_name); 723 block.AddLine(StringPrintf( 724 "%s %s,", argument_type.c_str(), argument_name.c_str())); 725 } 726 vector<string> out_params; 727 for (const auto& argument : method.output_arguments) { 728 string argument_type; 729 CHECK(signature.Parse(argument.type, &argument_type)); 730 MakeConstReferenceIfNeeded(&argument_type); 731 if (!argument.name.empty()) 732 base::StringAppendF(&argument_type, " /*%s*/", argument.name.c_str()); 733 out_params.push_back(argument_type); 734 } 735 block.AddLine(StringPrintf( 736 "const base::Callback<void(%s)>& success_callback,", 737 brillo::string_utils::Join(", ", out_params).c_str())); 738 block.AddLine( 739 "const base::Callback<void(brillo::Error*)>& error_callback,"); 740 block.AddLine( 741 StringPrintf("int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)%s", 742 declaration_only ? " = 0;" : " override {")); 743 block.PopOffset(); 744 if (!declaration_only) { 745 block.PushOffset(kBlockOffset); 746 747 block.AddLine("brillo::dbus_utils::CallMethodWithTimeout("); 748 block.PushOffset(kLineContinuationOffset); 749 block.AddLine("timeout_ms,"); 750 block.AddLine("dbus_object_proxy_,"); 751 block.AddLine(StringPrintf("\"%s\",", interface_name.c_str())); 752 block.AddLine(StringPrintf("\"%s\",", method.name.c_str())); 753 block.AddLine("success_callback,"); 754 string last_argument = "error_callback"; 755 for (const auto& argument_name : argument_names) { 756 block.AddLine(StringPrintf("%s,", last_argument.c_str())); 757 last_argument = argument_name; 758 } 759 block.AddLine(StringPrintf("%s);", last_argument.c_str())); 760 block.PopOffset(); 761 762 block.PopOffset(); 763 block.AddLine("}"); 764 } 765 text->AddBlock(block); 766 } 767 768 // static 769 void ProxyGenerator::AddMethodMock(const Interface::Method& method, 770 const string& /* interface_name */, 771 IndentedText* text) { 772 DbusSignature signature; 773 vector<string> arguments; 774 for (const auto& argument : method.input_arguments) { 775 string argument_type; 776 CHECK(signature.Parse(argument.type, &argument_type)); 777 MakeConstReferenceIfNeeded(&argument_type); 778 if (!argument.name.empty()) 779 base::StringAppendF(&argument_type, " /*in_%s*/", argument.name.c_str()); 780 arguments.push_back(argument_type); 781 } 782 for (const auto& argument : method.output_arguments) { 783 string argument_type; 784 CHECK(signature.Parse(argument.type, &argument_type)); 785 argument_type += '*'; 786 if (!argument.name.empty()) 787 base::StringAppendF(&argument_type, " /*out_%s*/", argument.name.c_str()); 788 arguments.push_back(argument_type); 789 } 790 arguments.push_back("brillo::ErrorPtr* /*error*/"); 791 arguments.push_back("int /*timeout_ms*/"); 792 AddMockMethodDeclaration(method.name, "bool", arguments, text); 793 } 794 795 // static 796 void ProxyGenerator::AddAsyncMethodMock(const Interface::Method& method, 797 const string& /* interface_name */, 798 IndentedText* text) { 799 DbusSignature signature; 800 vector<string> arguments; 801 for (const auto& argument : method.input_arguments) { 802 string argument_type; 803 CHECK(signature.Parse(argument.type, &argument_type)); 804 MakeConstReferenceIfNeeded(&argument_type); 805 if (!argument.name.empty()) 806 base::StringAppendF(&argument_type, " /*in_%s*/", argument.name.c_str()); 807 arguments.push_back(argument_type); 808 } 809 vector<string> out_params; 810 for (const auto& argument : method.output_arguments) { 811 string argument_type; 812 CHECK(signature.Parse(argument.type, &argument_type)); 813 MakeConstReferenceIfNeeded(&argument_type); 814 if (!argument.name.empty()) 815 base::StringAppendF(&argument_type, " /*%s*/", argument.name.c_str()); 816 out_params.push_back(argument_type); 817 } 818 arguments.push_back(StringPrintf( 819 "const base::Callback<void(%s)>& /*success_callback*/", 820 brillo::string_utils::Join(", ", out_params).c_str())); 821 arguments.push_back( 822 "const base::Callback<void(brillo::Error*)>& /*error_callback*/"); 823 arguments.push_back("int /*timeout_ms*/"); 824 AddMockMethodDeclaration(method.name + "Async", "void", arguments, text); 825 } 826 827 void ProxyGenerator::AddMockMethodDeclaration(const string& method_name, 828 const string& return_type, 829 const vector<string>& arguments, 830 IndentedText* text) { 831 IndentedText block; 832 // GMOCK doesn't go all the way up to 11, so we need to handle methods with 833 // 11 arguments or more in a different way. 834 if (arguments.size() >= 11) { 835 block.AddLineAndPushOffsetTo( 836 StringPrintf("%s %s(%s,", 837 return_type.c_str(), 838 method_name.c_str(), 839 arguments.front().c_str()), 840 1, '('); 841 for (size_t i = 1; i < arguments.size() - 1; i++) 842 block.AddLine(StringPrintf("%s,", arguments[i].c_str())); 843 block.AddLine(StringPrintf("%s) override {", arguments.back().c_str())); 844 block.PopOffset(); 845 block.PushOffset(kBlockOffset); 846 block.AddLine(StringPrintf( 847 "LOG(WARNING) << \"%s(): gmock can't handle methods with %" PRIuS 848 " arguments. You can override this method in a subclass if you need" 849 " to.\";", 850 method_name.c_str(), arguments.size())); 851 if (return_type == "void") { 852 // No return added here. 853 } else if (return_type == "bool") { 854 block.AddLine("return false;"); 855 } else { 856 LOG(FATAL) << "The return type is not supported."; 857 } 858 block.PopOffset(); 859 block.AddLine("}"); 860 } else { 861 block.AddLineAndPushOffsetTo( 862 StringPrintf("MOCK_METHOD%zu(%s,", 863 arguments.size(), method_name.c_str()), 864 1, '('); 865 block.AddLineAndPushOffsetTo( 866 StringPrintf("%s(%s,", return_type.c_str(), arguments.front().c_str()), 867 1, '('); 868 for (size_t i = 1; i < arguments.size() - 1; i++) 869 block.AddLine(StringPrintf("%s,", arguments[i].c_str())); 870 block.AddLine(StringPrintf("%s));", arguments.back().c_str())); 871 block.PopOffset(); 872 block.PopOffset(); 873 } 874 text->AddBlock(block); 875 } 876 877 // static 878 void ProxyGenerator::AddSignalHandlerRegistrationMock( 879 const Interface::Signal& signal, 880 IndentedText* text) { 881 IndentedText callback_arg_text; 882 AddSignalCallbackArg(signal, true, &callback_arg_text); 883 vector<string> arg_lines = callback_arg_text.GetLines(); 884 885 IndentedText block; 886 block.AddLineAndPushOffsetTo( 887 StringPrintf("MOCK_METHOD2(Register%sSignalHandler,", 888 signal.name.c_str()), 889 1, '('); 890 for (size_t i = 0; i < arg_lines.size(); ++i) { 891 if (i == 0) 892 block.AddLineAndPushOffsetTo("void(" + arg_lines[i], 1, '('); 893 else 894 block.AddLine(arg_lines[i]); 895 } 896 block.AddLine( 897 "dbus::ObjectProxy::OnConnectedCallback /*on_connected_callback*/));"); 898 text->AddBlock(block); 899 } 900 901 // static 902 void ProxyGenerator::AddSignalCallbackArg(const Interface::Signal& signal, 903 bool comment_arg_name, 904 IndentedText* block) { 905 DbusSignature signature; 906 string signal_callback = StringPrintf("%ssignal_callback%s", 907 comment_arg_name ? "/*" : "", 908 comment_arg_name ? "*/" : ""); 909 if (signal.arguments.empty()) { 910 block->AddLine(StringPrintf("const base::Closure& %s,", 911 signal_callback.c_str())); 912 } else { 913 string last_argument; 914 string prefix{"const base::Callback<void("}; 915 for (const auto argument : signal.arguments) { 916 if (!last_argument.empty()) { 917 if (!prefix.empty()) { 918 block->AddLineAndPushOffsetTo( 919 StringPrintf("%s%s,", prefix.c_str(), last_argument.c_str()), 920 1, '('); 921 prefix.clear(); 922 } else { 923 block->AddLine(StringPrintf("%s,", last_argument.c_str())); 924 } 925 } 926 CHECK(signature.Parse(argument.type, &last_argument)); 927 MakeConstReferenceIfNeeded(&last_argument); 928 } 929 block->AddLine(StringPrintf("%s%s)>& %s,", 930 prefix.c_str(), 931 last_argument.c_str(), 932 signal_callback.c_str())); 933 if (prefix.empty()) { 934 block->PopOffset(); 935 } 936 } 937 } 938 939 // static 940 void ProxyGenerator::ObjectManager::GenerateProxy( 941 const ServiceConfig& config, 942 const std::vector<Interface>& interfaces, 943 IndentedText* text) { 944 if (config.object_manager.name.empty()) 945 return; 946 947 NameParser object_manager{config.object_manager.name}; 948 object_manager.AddOpenNamespaces(text, false); 949 text->AddBlankLine(); 950 951 string class_name = object_manager.type_name + "Proxy"; 952 text->AddLine(StringPrintf("class %s : " 953 "public dbus::ObjectManager::Interface {", 954 class_name.c_str())); 955 text->AddLineWithOffset("public:", kScopeOffset); 956 text->PushOffset(kBlockOffset); 957 958 AddConstructor(config, class_name, interfaces, text); 959 AddDestructor(class_name, interfaces, text); 960 AddGetObjectManagerProxy(text); 961 for (const auto& itf : interfaces) { 962 AddInterfaceAccessors(itf, text); 963 } 964 text->PopOffset(); 965 966 text->AddLineWithOffset("private:", kScopeOffset); 967 text->PushOffset(kBlockOffset); 968 AddOnPropertyChanged(interfaces, text); 969 AddObjectAdded(config, interfaces, text); 970 AddObjectRemoved(interfaces, text); 971 AddCreateProperties(interfaces, class_name, text); 972 AddDataMembers(config, interfaces, class_name, text); 973 974 text->AddLine(StringPrintf("DISALLOW_COPY_AND_ASSIGN(%s);", 975 class_name.c_str())); 976 text->PopOffset(); 977 text->AddLine("};"); 978 text->AddBlankLine(); 979 object_manager.AddCloseNamespaces(text, false); 980 text->AddBlankLine(); 981 } 982 983 void ProxyGenerator::ObjectManager::AddConstructor( 984 const ServiceConfig& config, 985 const std::string& class_name, 986 const std::vector<Interface>& interfaces, 987 IndentedText* text) { 988 if (config.service_name.empty()) { 989 text->AddLineAndPushOffsetTo( 990 StringPrintf("%s(const scoped_refptr<dbus::Bus>& bus,", 991 class_name.c_str()), 992 1, '('); 993 text->AddLine("const std::string& service_name)"); 994 text->PopOffset(); 995 } else { 996 text->AddLine(StringPrintf("%s(const scoped_refptr<dbus::Bus>& bus)", 997 class_name.c_str())); 998 } 999 text->PushOffset(kLineContinuationOffset); 1000 text->AddLine(": bus_{bus},"); 1001 text->PushOffset(kBlockOffset); 1002 if (config.service_name.empty()) { 1003 text->AddLine("service_name_{service_name},"); 1004 } 1005 text->AddLine("dbus_object_manager_{bus->GetObjectManager("); 1006 text->PushOffset(kLineContinuationOffset); 1007 if (config.service_name.empty()) { 1008 text->AddLine("service_name,"); 1009 } else { 1010 text->AddLine(StringPrintf("\"%s\",", config.service_name.c_str())); 1011 } 1012 text->AddLine(StringPrintf("dbus::ObjectPath{\"%s\"})} {", 1013 config.object_manager.object_path.c_str())); 1014 text->PopOffset(); 1015 text->PopOffset(); 1016 text->PopOffset(); 1017 text->PushOffset(kBlockOffset); 1018 for (const auto& itf : interfaces) { 1019 text->AddLine( 1020 StringPrintf("dbus_object_manager_->RegisterInterface(\"%s\", this);", 1021 itf.name.c_str())); 1022 } 1023 text->PopOffset(); 1024 text->AddLine("}"); 1025 text->AddBlankLine(); 1026 } 1027 1028 void ProxyGenerator::ObjectManager::AddDestructor( 1029 const std::string& class_name, 1030 const std::vector<Interface>& interfaces, 1031 IndentedText* text) { 1032 text->AddLine(StringPrintf("~%s() override {", class_name.c_str())); 1033 text->PushOffset(kBlockOffset); 1034 for (const auto& itf : interfaces) { 1035 text->AddLine( 1036 StringPrintf("dbus_object_manager_->UnregisterInterface(\"%s\");", 1037 itf.name.c_str())); 1038 } 1039 text->PopOffset(); 1040 text->AddLine("}"); 1041 text->AddBlankLine(); 1042 } 1043 1044 void ProxyGenerator::ObjectManager::AddGetObjectManagerProxy( 1045 IndentedText* text) { 1046 text->AddLine("dbus::ObjectManager* GetObjectManagerProxy() const {"); 1047 text->AddLineWithOffset("return dbus_object_manager_;", kBlockOffset); 1048 text->AddLine("}"); 1049 text->AddBlankLine(); 1050 } 1051 1052 void ProxyGenerator::ObjectManager::AddInterfaceAccessors( 1053 const Interface& interface, 1054 IndentedText* text) { 1055 NameParser itf_name{interface.name}; 1056 string map_name = itf_name.MakeVariableName() + "_instances_"; 1057 1058 // GetProxy(). 1059 if (interface.path.empty()) { 1060 // We have no fixed path, so there could be multiple instances of this itf. 1061 text->AddLine(StringPrintf("%sInterface* Get%s(", 1062 itf_name.MakeProxyName(true).c_str(), 1063 itf_name.MakeProxyName(false).c_str())); 1064 text->PushOffset(kLineContinuationOffset); 1065 text->AddLine("const dbus::ObjectPath& object_path) {"); 1066 text->PopOffset(); 1067 text->PushOffset(kBlockOffset); 1068 text->AddLine(StringPrintf("auto p = %s.find(object_path);", 1069 map_name.c_str())); 1070 text->AddLine(StringPrintf("if (p != %s.end())", map_name.c_str())); 1071 text->PushOffset(kBlockOffset); 1072 text->AddLine("return p->second.get();"); 1073 text->PopOffset(); 1074 text->AddLine("return nullptr;"); 1075 text->PopOffset(); 1076 text->AddLine("}"); 1077 } else { 1078 // We have a fixed path, so the object could be considered a "singleton". 1079 // Skip the object_path parameter and return the first available instance. 1080 text->AddLine(StringPrintf("%sInterface* Get%s() {", 1081 itf_name.MakeProxyName(true).c_str(), 1082 itf_name.MakeProxyName(false).c_str())); 1083 text->PushOffset(kBlockOffset); 1084 text->AddLine(StringPrintf("if (%s.empty())", map_name.c_str())); 1085 text->AddLineWithOffset("return nullptr;", kBlockOffset); 1086 text->AddLine(StringPrintf("return %s.begin()->second.get();", 1087 map_name.c_str())); 1088 text->PopOffset(); 1089 text->AddLine("}"); 1090 } 1091 1092 // GetInstances(). 1093 text->AddLine( 1094 StringPrintf("std::vector<%sInterface*> Get%sInstances() const {", 1095 itf_name.MakeProxyName(true).c_str(), 1096 itf_name.type_name.c_str())); 1097 text->PushOffset(kBlockOffset); 1098 text->AddLine(StringPrintf("std::vector<%sInterface*> values;", 1099 itf_name.MakeProxyName(true).c_str())); 1100 text->AddLine(StringPrintf("values.reserve(%s.size());", map_name.c_str())); 1101 text->AddLine(StringPrintf("for (const auto& pair : %s)", map_name.c_str())); 1102 text->AddLineWithOffset("values.push_back(pair.second.get());", kBlockOffset); 1103 text->AddLine("return values;"); 1104 text->PopOffset(); 1105 text->AddLine("}"); 1106 1107 // SetAddedCallback(). 1108 text->AddLine(StringPrintf("void Set%sAddedCallback(", 1109 itf_name.type_name.c_str())); 1110 text->PushOffset(kLineContinuationOffset); 1111 text->AddLine( 1112 StringPrintf("const base::Callback<void(%sInterface*)>& callback) {", 1113 itf_name.MakeProxyName(true).c_str())); 1114 text->PopOffset(); 1115 text->PushOffset(kBlockOffset); 1116 text->AddLine(StringPrintf("on_%s_added_ = callback;", 1117 itf_name.MakeVariableName().c_str())); 1118 text->PopOffset(); 1119 text->AddLine("}"); 1120 1121 // SetRemovedCallback(). 1122 text->AddLine(StringPrintf("void Set%sRemovedCallback(", 1123 itf_name.type_name.c_str())); 1124 text->PushOffset(kLineContinuationOffset); 1125 text->AddLine("const base::Callback<void(const dbus::ObjectPath&)>& " 1126 "callback) {"); 1127 text->PopOffset(); 1128 text->PushOffset(kBlockOffset); 1129 text->AddLine(StringPrintf("on_%s_removed_ = callback;", 1130 itf_name.MakeVariableName().c_str())); 1131 text->PopOffset(); 1132 text->AddLine("}"); 1133 1134 text->AddBlankLine(); 1135 } 1136 1137 void ProxyGenerator::ObjectManager::AddOnPropertyChanged( 1138 const std::vector<Interface>& interfaces, 1139 IndentedText* text) { 1140 // If there are no interfaces with properties, comment out parameter 1141 // names for OnPropertyChanged() to prevent compiler warnings on unused 1142 // function parameters. 1143 auto has_props = [](const Interface& itf) { return !itf.properties.empty(); }; 1144 auto itf_with_props = std::find_if(interfaces.begin(), interfaces.end(), 1145 has_props); 1146 if (itf_with_props == interfaces.end()) { 1147 text->AddLineAndPushOffsetTo("void OnPropertyChanged(" 1148 "const dbus::ObjectPath& /* object_path */,", 1149 1, '('); 1150 text->AddLine("const std::string& /* interface_name */,"); 1151 text->AddLine("const std::string& /* property_name */) {}"); 1152 text->PopOffset(); 1153 text->AddBlankLine(); 1154 return; 1155 } 1156 text->AddLineAndPushOffsetTo("void OnPropertyChanged(" 1157 "const dbus::ObjectPath& object_path,", 1158 1, '('); 1159 text->AddLine("const std::string& interface_name,"); 1160 text->AddLine("const std::string& property_name) {"); 1161 text->PopOffset(); 1162 text->PushOffset(kBlockOffset); 1163 for (const auto& itf : interfaces) { 1164 if (itf.properties.empty()) 1165 continue; 1166 1167 NameParser itf_name{itf.name}; 1168 text->AddLine(StringPrintf("if (interface_name == \"%s\") {", 1169 itf.name.c_str())); 1170 text->PushOffset(kBlockOffset); 1171 string map_name = itf_name.MakeVariableName() + "_instances_"; 1172 text->AddLine(StringPrintf("auto p = %s.find(object_path);", 1173 map_name.c_str())); 1174 text->AddLine(StringPrintf("if (p == %s.end())", map_name.c_str())); 1175 text->PushOffset(kBlockOffset); 1176 text->AddLine("return;"); 1177 text->PopOffset(); 1178 text->AddLine("p->second->OnPropertyChanged(property_name);"); 1179 text->AddLine("return;"); 1180 text->PopOffset(); 1181 text->AddLine("}"); 1182 } 1183 text->PopOffset(); 1184 text->AddLine("}"); 1185 text->AddBlankLine(); 1186 } 1187 1188 void ProxyGenerator::ObjectManager::AddObjectAdded( 1189 const ServiceConfig& config, 1190 const std::vector<Interface>& interfaces, 1191 IndentedText* text) { 1192 text->AddLine("void ObjectAdded("); 1193 text->PushOffset(kLineContinuationOffset); 1194 text->AddLine("const dbus::ObjectPath& object_path,"); 1195 text->AddLine("const std::string& interface_name) override {"); 1196 text->PopOffset(); 1197 text->PushOffset(kBlockOffset); 1198 for (const auto& itf : interfaces) { 1199 NameParser itf_name{itf.name}; 1200 string var_name = itf_name.MakeVariableName(); 1201 text->AddLine(StringPrintf("if (interface_name == \"%s\") {", 1202 itf.name.c_str())); 1203 text->PushOffset(kBlockOffset); 1204 if (!itf.properties.empty()) { 1205 text->AddLine("auto property_set ="); 1206 text->PushOffset(kLineContinuationOffset); 1207 text->AddLine(StringPrintf("static_cast<%s::PropertySet*>(", 1208 itf_name.MakeProxyName(true).c_str())); 1209 text->PushOffset(kLineContinuationOffset); 1210 text->AddLine("dbus_object_manager_->GetProperties(object_path, " 1211 "interface_name));"); 1212 text->PopOffset(); 1213 text->PopOffset(); 1214 } 1215 text->AddLine(StringPrintf("std::unique_ptr<%s> %s_proxy{", 1216 itf_name.MakeProxyName(true).c_str(), 1217 var_name.c_str())); 1218 text->PushOffset(kBlockOffset); 1219 string new_instance = StringPrintf("new %s{bus_", 1220 itf_name.MakeProxyName(true).c_str()); 1221 if (config.service_name.empty()) { 1222 new_instance += ", service_name_"; 1223 } 1224 if (itf.path.empty()) 1225 new_instance += ", object_path"; 1226 if (!itf.properties.empty()) 1227 new_instance += ", property_set"; 1228 new_instance += "}"; 1229 text->AddLine(new_instance); 1230 text->PopOffset(); 1231 text->AddLine("};"); 1232 text->AddLine(StringPrintf("auto p = %s_instances_.emplace(object_path, " 1233 "std::move(%s_proxy));", 1234 var_name.c_str(), var_name.c_str())); 1235 text->AddLine(StringPrintf("if (!on_%s_added_.is_null())", 1236 var_name.c_str())); 1237 text->PushOffset(kBlockOffset); 1238 text->AddLine(StringPrintf("on_%s_added_.Run(p.first->second.get());", 1239 var_name.c_str())); 1240 text->PopOffset(); 1241 text->AddLine("return;"); 1242 text->PopOffset(); 1243 text->AddLine("}"); 1244 } 1245 text->PopOffset(); 1246 text->AddLine("}"); 1247 text->AddBlankLine(); 1248 } 1249 1250 void ProxyGenerator::ObjectManager::AddObjectRemoved( 1251 const std::vector<Interface>& interfaces, 1252 IndentedText* text) { 1253 text->AddLine("void ObjectRemoved("); 1254 text->PushOffset(kLineContinuationOffset); 1255 text->AddLine("const dbus::ObjectPath& object_path,"); 1256 text->AddLine("const std::string& interface_name) override {"); 1257 text->PopOffset(); 1258 text->PushOffset(kBlockOffset); 1259 for (const auto& itf : interfaces) { 1260 NameParser itf_name{itf.name}; 1261 string var_name = itf_name.MakeVariableName(); 1262 text->AddLine(StringPrintf("if (interface_name == \"%s\") {", 1263 itf.name.c_str())); 1264 text->PushOffset(kBlockOffset); 1265 text->AddLine(StringPrintf("auto p = %s_instances_.find(object_path);", 1266 var_name.c_str())); 1267 text->AddLine(StringPrintf("if (p != %s_instances_.end()) {", 1268 var_name.c_str())); 1269 text->PushOffset(kBlockOffset); 1270 text->AddLine(StringPrintf("if (!on_%s_removed_.is_null())", 1271 var_name.c_str())); 1272 text->PushOffset(kBlockOffset); 1273 text->AddLine(StringPrintf("on_%s_removed_.Run(object_path);", 1274 var_name.c_str())); 1275 text->PopOffset(); 1276 text->AddLine(StringPrintf("%s_instances_.erase(p);", 1277 var_name.c_str())); 1278 text->PopOffset(); 1279 text->AddLine("}"); 1280 text->AddLine("return;"); 1281 text->PopOffset(); 1282 text->AddLine("}"); 1283 } 1284 text->PopOffset(); 1285 text->AddLine("}"); 1286 text->AddBlankLine(); 1287 } 1288 1289 void ProxyGenerator::ObjectManager::AddCreateProperties( 1290 const std::vector<Interface>& interfaces, 1291 const std::string& class_name, 1292 IndentedText* text) { 1293 text->AddLine("dbus::PropertySet* CreateProperties("); 1294 text->PushOffset(kLineContinuationOffset); 1295 text->AddLine("dbus::ObjectProxy* object_proxy,"); 1296 text->AddLine("const dbus::ObjectPath& object_path,"); 1297 text->AddLine("const std::string& interface_name) override {"); 1298 text->PopOffset(); 1299 text->PushOffset(kBlockOffset); 1300 for (const auto& itf : interfaces) { 1301 NameParser itf_name{itf.name}; 1302 text->AddLine(StringPrintf("if (interface_name == \"%s\") {", 1303 itf.name.c_str())); 1304 text->PushOffset(kBlockOffset); 1305 text->AddLine(StringPrintf("return new %s::PropertySet{", 1306 itf_name.MakeProxyName(true).c_str())); 1307 text->PushOffset(kLineContinuationOffset); 1308 text->AddLine("object_proxy,"); 1309 text->AddLineAndPushOffsetTo( 1310 StringPrintf("base::Bind(&%s::OnPropertyChanged,", 1311 class_name.c_str()), 1312 1, '('); 1313 text->AddLine("weak_ptr_factory_.GetWeakPtr(),"); 1314 text->AddLine("object_path,"); 1315 text->AddLine("interface_name)"); 1316 text->PopOffset(); 1317 text->PopOffset(); 1318 text->AddLine("};"); 1319 text->PopOffset(); 1320 text->AddLine("}"); 1321 } 1322 text->AddLineAndPushOffsetTo("LOG(FATAL) << \"Creating properties for " 1323 "unsupported interface \"", 1, ' '); 1324 text->AddLine("<< interface_name;"); 1325 text->PopOffset(); 1326 text->AddLine("return nullptr;"); 1327 text->PopOffset(); 1328 text->AddLine("}"); 1329 text->AddBlankLine(); 1330 } 1331 1332 void ProxyGenerator::ObjectManager::AddDataMembers( 1333 const ServiceConfig& config, 1334 const std::vector<Interface>& interfaces, 1335 const std::string& class_name, 1336 IndentedText* text) { 1337 text->AddLine("scoped_refptr<dbus::Bus> bus_;"); 1338 if (config.service_name.empty()) { 1339 text->AddLine("std::string service_name_;"); 1340 } 1341 text->AddLine("dbus::ObjectManager* dbus_object_manager_;"); 1342 for (const auto& itf : interfaces) { 1343 NameParser itf_name{itf.name}; 1344 string var_name = itf_name.MakeVariableName(); 1345 text->AddLineAndPushOffsetTo("std::map<dbus::ObjectPath,", 1, '<'); 1346 text->AddLine(StringPrintf("std::unique_ptr<%s>> %s_instances_;", 1347 itf_name.MakeProxyName(true).c_str(), 1348 var_name.c_str())); 1349 text->PopOffset(); 1350 text->AddLine( 1351 StringPrintf("base::Callback<void(%sInterface*)> on_%s_added_;", 1352 itf_name.MakeProxyName(true).c_str(), 1353 var_name.c_str())); 1354 text->AddLine(StringPrintf("base::Callback<void(const dbus::ObjectPath&)> " 1355 "on_%s_removed_;", 1356 var_name.c_str())); 1357 } 1358 text->AddLine( 1359 StringPrintf("base::WeakPtrFactory<%s> weak_ptr_factory_{this};", 1360 class_name.c_str())); 1361 text->AddBlankLine(); 1362 } 1363 1364 // static 1365 string ProxyGenerator::GetHandlerNameForSignal(const string& signal) { 1366 return StringPrintf("On%sSignal", signal.c_str()); 1367 } 1368 1369 } // namespace chromeos_dbus_bindings 1370