Home | History | Annotate | Download | only in chromeos-dbus-bindings
      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