blob: 1ac71399596dca3dcbce3ee35999e5eb3d13041b [file] [log] [blame]
// Copyright 2014 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos-dbus-bindings/proxy_generator.h"
#include <algorithm>
#include <utility>
#include <base/files/file_path.h>
#include <base/format_macros.h>
#include <base/logging.h>
#include <base/strings/stringprintf.h>
#include <brillo/strings/string_utils.h>
#include "chromeos-dbus-bindings/dbus_signature.h"
#include "chromeos-dbus-bindings/indented_text.h"
#include "chromeos-dbus-bindings/name_parser.h"
using base::StringPrintf;
using std::pair;
using std::string;
using std::vector;
namespace chromeos_dbus_bindings {
namespace {
// Helper struct to encapsulate information about method call parameter during
// code generation.
struct ParamDef {
ParamDef(const string& param_type, const string& param_name, bool param_ref)
: type(param_type), name(param_name), is_const_ref(param_ref) {}
string type;
string name;
bool is_const_ref;
};
string GetParamString(const ParamDef& param_def) {
return StringPrintf(param_def.is_const_ref ? "const %s& %s" : "%s* %s",
param_def.type.c_str(), param_def.name.c_str());
}
} // anonymous namespace
// static
bool ProxyGenerator::GenerateProxies(
const ServiceConfig& config,
const std::vector<Interface>& interfaces,
const base::FilePath& output_file) {
IndentedText text;
text.AddLine("// Automatic generation of D-Bus interfaces:");
for (const auto& interface : interfaces) {
text.AddLine(StringPrintf("// - %s", interface.name.c_str()));
}
string header_guard = GenerateHeaderGuard(output_file);
text.AddLine(StringPrintf("#ifndef %s", header_guard.c_str()));
text.AddLine(StringPrintf("#define %s", header_guard.c_str()));
text.AddLine("#include <memory>");
text.AddLine("#include <string>");
text.AddLine("#include <vector>");
text.AddBlankLine();
text.AddLine("#include <base/bind.h>");
text.AddLine("#include <base/callback.h>");
text.AddLine("#include <base/logging.h>");
text.AddLine("#include <base/macros.h>");
text.AddLine("#include <base/memory/ref_counted.h>");
text.AddLine("#include <brillo/any.h>");
text.AddLine("#include <brillo/dbus/dbus_method_invoker.h>");
text.AddLine("#include <brillo/dbus/dbus_property.h>");
text.AddLine("#include <brillo/dbus/dbus_signal_handler.h>");
text.AddLine("#include <brillo/errors/error.h>");
text.AddLine("#include <brillo/variant_dictionary.h>");
text.AddLine("#include <dbus/bus.h>");
text.AddLine("#include <dbus/message.h>");
text.AddLine("#include <dbus/object_manager.h>");
text.AddLine("#include <dbus/object_path.h>");
text.AddLine("#include <dbus/object_proxy.h>");
text.AddBlankLine();
if (!config.object_manager.name.empty()) {
// Add forward-declaration for Object Manager proxy class.
NameParser parser{config.object_manager.name};
parser.AddOpenNamespaces(&text, false);
text.AddLine(StringPrintf("class %s;",
parser.MakeProxyName(false).c_str()));
parser.AddCloseNamespaces(&text, false);
text.AddBlankLine();
}
for (const auto& interface : interfaces) {
GenerateInterfaceProxyInterface(config, interface, &text);
GenerateInterfaceProxy(config, interface, &text);
}
ObjectManager::GenerateProxy(config, interfaces, &text);
text.AddLine(StringPrintf("#endif // %s", header_guard.c_str()));
return WriteTextToFile(output_file, text);
}
// static
bool ProxyGenerator::GenerateMocks(const ServiceConfig& config,
const std::vector<Interface>& interfaces,
const base::FilePath& mock_file,
const base::FilePath& proxy_file,
bool use_literal_proxy_file) {
IndentedText text;
text.AddLine("// Automatic generation of D-Bus interface mock proxies for:");
for (const auto& interface : interfaces) {
text.AddLine(StringPrintf("// - %s", interface.name.c_str()));
}
string header_guard = GenerateHeaderGuard(mock_file);
text.AddLine(StringPrintf("#ifndef %s", header_guard.c_str()));
text.AddLine(StringPrintf("#define %s", header_guard.c_str()));
text.AddLine("#include <string>");
text.AddLine("#include <vector>");
text.AddBlankLine();
text.AddLine("#include <base/callback_forward.h>");
text.AddLine("#include <base/logging.h>");
text.AddLine("#include <base/macros.h>");
text.AddLine("#include <brillo/any.h>");
text.AddLine("#include <brillo/errors/error.h>");
text.AddLine("#include <brillo/variant_dictionary.h>");
text.AddLine("#include <gmock/gmock.h>");
text.AddBlankLine();
if (!proxy_file.empty()) {
// If we have a proxy header file, it would have the proxy interfaces we
// need to base our mocks on, so we need to include that header file.
base::FilePath relative_path;
if (use_literal_proxy_file) {
relative_path = proxy_file;
} else {
// Generate a relative path from |mock_file| to |proxy_file|.
// First, get the path components for both source and destination paths.
std::vector<base::FilePath::StringType> src_components;
mock_file.DirName().GetComponents(&src_components);
std::vector<base::FilePath::StringType> dest_components;
proxy_file.DirName().GetComponents(&dest_components);
// Find the common root.
// I wish we had C++14 and its 4-parameter version of std::mismatch()...
auto src_end = src_components.end();
if (src_components.size() > dest_components.size())
src_end = src_components.begin() + dest_components.size();
auto mismatch_pair = std::mismatch(src_components.begin(), src_end,
dest_components.begin());
// For each remaining components in the |src_components|, generate the
// parent directory references ("..").
size_t src_count = std::distance(mismatch_pair.first,
src_components.end());
std::vector<base::FilePath::StringType> components{
src_count, base::FilePath::kParentDirectory};
// Append the remaining components from |dest_components|.
components.insert(components.end(),
mismatch_pair.second, dest_components.end());
// Finally, add the base name of the target file name.
components.push_back(proxy_file.BaseName().value());
// Now reconstruct the relative path.
relative_path = base::FilePath{base::FilePath::kCurrentDirectory};
for (const auto& component : components)
relative_path = relative_path.Append(component);
}
text.AddLine(StringPrintf("#include \"%s\"",
relative_path.value().c_str()));
text.AddBlankLine();
}
for (const auto& interface : interfaces) {
// If we have no proxy file, we need the abstract interfaces generated here.
if (proxy_file.empty())
GenerateInterfaceProxyInterface(config, interface, &text);
GenerateInterfaceMock(config, interface, &text);
}
text.AddLine(StringPrintf("#endif // %s", header_guard.c_str()));
return WriteTextToFile(mock_file, text);
}
// static
void ProxyGenerator::GenerateInterfaceProxyInterface(
const ServiceConfig& config,
const Interface& interface,
IndentedText* text) {
NameParser parser{interface.name};
string proxy_name = parser.MakeProxyName(false);
string base_interface_name = proxy_name + "Interface";
parser.AddOpenNamespaces(text, false);
text->AddBlankLine();
text->AddLine(StringPrintf("// Abstract interface proxy for %s.",
parser.MakeFullCppName().c_str()));
text->AddComments(interface.doc_string);
text->AddLine(StringPrintf("class %s {", base_interface_name.c_str()));
text->AddLineWithOffset("public:", kScopeOffset);
text->PushOffset(kBlockOffset);
text->AddLine(
StringPrintf("virtual ~%s() = default;", base_interface_name.c_str()));
for (const auto& method : interface.methods) {
AddMethodProxy(method, interface.name, true, text);
AddAsyncMethodProxy(method, interface.name, true, text);
}
for (const auto& signal : interface.signals) {
AddSignalHandlerRegistration(signal, interface.name, true, text);
}
AddProperties(interface, true, text);
text->AddBlankLine();
text->AddLine("virtual const dbus::ObjectPath& GetObjectPath() const = 0;");
text->AddLine("virtual dbus::ObjectProxy* GetObjectProxy() const = 0;");
if (!interface.properties.empty()) {
if (config.object_manager.name.empty())
AddInitializeProperties(proxy_name, true, text);
else
AddSetPropertyChanged(proxy_name, true, text);
}
text->PopOffset();
text->AddLine("};");
text->AddBlankLine();
parser.AddCloseNamespaces(text, false);
text->AddBlankLine();
}
// static
void ProxyGenerator::GenerateInterfaceProxy(const ServiceConfig& config,
const Interface& interface,
IndentedText* text) {
NameParser parser{interface.name};
string proxy_name = parser.MakeProxyName(false);
string base_interface_name = proxy_name + "Interface";
parser.AddOpenNamespaces(text, false);
text->AddBlankLine();
text->AddLine(StringPrintf("// Interface proxy for %s.",
parser.MakeFullCppName().c_str()));
text->AddComments(interface.doc_string);
text->AddLine(StringPrintf("class %s final : public %s {",
proxy_name.c_str(), base_interface_name.c_str()));
text->AddLineWithOffset("public:", kScopeOffset);
text->PushOffset(kBlockOffset);
AddPropertySet(config, interface, text);
AddConstructor(config, interface, proxy_name, text);
AddDestructor(proxy_name, text);
for (const auto& signal : interface.signals) {
AddSignalHandlerRegistration(signal, interface.name, false, text);
}
AddReleaseObjectProxy(text);
AddGetObjectPath(text);
AddGetObjectProxy(text);
if (!interface.properties.empty()) {
if (config.object_manager.name.empty())
AddInitializeProperties(proxy_name, false, text);
else
AddSetPropertyChanged(proxy_name, false, text);
AddGetProperties(text);
}
for (const auto& method : interface.methods) {
AddMethodProxy(method, interface.name, false, text);
AddAsyncMethodProxy(method, interface.name, false, text);
}
AddProperties(interface, false, text);
text->PopOffset();
text->AddBlankLine();
text->AddLineWithOffset("private:", kScopeOffset);
text->PushOffset(kBlockOffset);
if (!config.object_manager.name.empty() && !interface.properties.empty())
AddOnPropertyChanged(text);
text->AddLine("scoped_refptr<dbus::Bus> bus_;");
if (config.service_name.empty()) {
text->AddLine("std::string service_name_;");
} else {
text->AddLine(StringPrintf("const std::string service_name_{\"%s\"};",
config.service_name.c_str()));
}
if (interface.path.empty()) {
text->AddLine("dbus::ObjectPath object_path_;");
} else {
text->AddLine(StringPrintf("const dbus::ObjectPath object_path_{\"%s\"};",
interface.path.c_str()));
}
if (!config.object_manager.name.empty() && !interface.properties.empty()) {
text->AddLine("PropertySet* property_set_;");
text->AddLine(
StringPrintf("base::Callback<void(%sInterface*, const std::string&)> "
"on_property_changed_;",
proxy_name.c_str()));
}
text->AddLine("dbus::ObjectProxy* dbus_object_proxy_;");
if (config.object_manager.name.empty() && !interface.properties.empty())
text->AddLine("std::unique_ptr<PropertySet> property_set_;");
text->AddBlankLine();
if (!config.object_manager.name.empty() && !interface.properties.empty()) {
text->AddLine(StringPrintf(
"friend class %s;",
NameParser{config.object_manager.name}.MakeProxyName(true).c_str()));
}
text->AddLine(StringPrintf("DISALLOW_COPY_AND_ASSIGN(%s);",
proxy_name.c_str()));
text->PopOffset();
text->AddLine("};");
text->AddBlankLine();
parser.AddCloseNamespaces(text, false);
text->AddBlankLine();
}
// static
void ProxyGenerator::GenerateInterfaceMock(const ServiceConfig& config,
const Interface& interface,
IndentedText* text) {
NameParser parser{interface.name};
string proxy_name = parser.MakeProxyName(false);
string base_interface_name = proxy_name + "Interface";
string mock_name = proxy_name + "Mock";
parser.AddOpenNamespaces(text, false);
text->AddBlankLine();
text->AddLine(StringPrintf("// Mock object for %s.",
base_interface_name.c_str()));
text->AddLine(StringPrintf("class %s : public %s {",
mock_name.c_str(), base_interface_name.c_str()));
text->AddLineWithOffset("public:", kScopeOffset);
text->PushOffset(kBlockOffset);
text->AddLine(StringPrintf("%s() = default;", mock_name.c_str()));
text->AddBlankLine();
for (const auto& method : interface.methods) {
AddMethodMock(method, interface.name, text);
AddAsyncMethodMock(method, interface.name, text);
}
for (const auto& signal : interface.signals) {
AddSignalHandlerRegistrationMock(signal, text);
}
DbusSignature signature;
for (const auto& prop : interface.properties) {
string type;
CHECK(signature.Parse(prop.type, &type));
MakeConstReferenceIfNeeded(&type);
string name = NameParser{prop.name}.MakeVariableName();
text->AddLine(StringPrintf("MOCK_CONST_METHOD0(%s, %s());",
name.c_str(), type.c_str()));
if (prop.access == "readwrite") {
text->AddLine(StringPrintf("MOCK_METHOD2(set_%s, void(%s, "
"const base::Callback<bool>&));",
name.c_str(), type.c_str()));
}
}
text->AddLine(
"MOCK_CONST_METHOD0(GetObjectPath, const dbus::ObjectPath&());");
text->AddLine(
"MOCK_CONST_METHOD0(GetObjectProxy, dbus::ObjectProxy*());");
if (!interface.properties.empty()) {
if (config.object_manager.name.empty()) {
text->AddLineAndPushOffsetTo(
"MOCK_METHOD1(InitializeProperties,", 1, '(');
text->AddLine(StringPrintf(
"void(const base::Callback<void(%sInterface*, "
"const std::string&)>&));", proxy_name.c_str()));
text->PopOffset();
} else {
text->AddLineAndPushOffsetTo(
"MOCK_METHOD1(SetPropertyChangedCallback,", 1, '(');
text->AddLine(StringPrintf("void(const base::Callback<void(%sInterface*, "
"const std::string&)>&));",
proxy_name.c_str()));
text->PopOffset();
}
}
text->PopOffset();
text->AddBlankLine();
text->AddLineWithOffset("private:", kScopeOffset);
text->AddLineWithOffset(StringPrintf("DISALLOW_COPY_AND_ASSIGN(%s);",
mock_name.c_str()),
kBlockOffset);
text->AddLine("};");
parser.AddCloseNamespaces(text, false);
text->AddBlankLine();
}
// static
void ProxyGenerator::AddConstructor(const ServiceConfig& config,
const Interface& interface,
const string& class_name,
IndentedText* text) {
IndentedText block;
vector<ParamDef> args{{"scoped_refptr<dbus::Bus>", "bus", true}};
if (config.service_name.empty())
args.emplace_back("std::string", "service_name", true);
if (interface.path.empty())
args.emplace_back("dbus::ObjectPath", "object_path", true);
if (!config.object_manager.name.empty() && !interface.properties.empty())
args.emplace_back("PropertySet", "property_set", false);
if (args.size() == 1) {
block.AddLine(StringPrintf("%s(%s) :", class_name.c_str(),
GetParamString(args.front()).c_str()));
} else {
block.AddLine(StringPrintf("%s(", class_name.c_str()));
block.PushOffset(kLineContinuationOffset);
for (size_t i = 0; i < args.size() - 1; i++) {
block.AddLine(StringPrintf("%s,", GetParamString(args[i]).c_str()));
}
block.AddLine(StringPrintf("%s) :", GetParamString(args.back()).c_str()));
}
block.PushOffset(kLineContinuationOffset);
for (const auto& arg : args) {
block.AddLine(StringPrintf("%s_{%s},", arg.name.c_str(),
arg.name.c_str()));
}
block.AddLine("dbus_object_proxy_{");
block.AddLineWithOffset(
"bus_->GetObjectProxy(service_name_, object_path_)} {",
kLineContinuationOffset);
block.PopOffset();
if (args.size() > 1)
block.PopOffset();
block.AddLine("}");
block.AddBlankLine();
text->AddBlock(block);
}
// static
void ProxyGenerator::AddDestructor(const string& class_name,
IndentedText* text) {
IndentedText block;
block.AddLine(StringPrintf("~%s() override {", class_name.c_str()));
block.AddLine("}");
text->AddBlock(block);
}
// static
void ProxyGenerator::AddReleaseObjectProxy(IndentedText* text) {
text->AddBlankLine();
text->AddLine("void ReleaseObjectProxy(const base::Closure& callback) {");
text->AddLineWithOffset(
"bus_->RemoveObjectProxy(service_name_, object_path_, callback);",
kBlockOffset);
text->AddLine("}");
}
// static
void ProxyGenerator::AddGetObjectPath(IndentedText* text) {
text->AddBlankLine();
text->AddLine("const dbus::ObjectPath& GetObjectPath() const override {");
text->AddLineWithOffset("return object_path_;", kBlockOffset);
text->AddLine("}");
}
// static
void ProxyGenerator::AddGetObjectProxy(IndentedText* text) {
text->AddBlankLine();
text->AddLine("dbus::ObjectProxy* GetObjectProxy() const override {");
text->AddLineWithOffset("return dbus_object_proxy_;", kBlockOffset);
text->AddLine("}");
}
// static
void ProxyGenerator::AddInitializeProperties(const string& class_name,
bool declaration_only,
IndentedText* text) {
text->AddBlankLine();
text->AddLine(StringPrintf("%svoid InitializeProperties(",
declaration_only ? "virtual " : ""));
text->AddLineWithOffset(
StringPrintf("const base::Callback<void(%sInterface*, "
"const std::string&)>& callback) %s",
class_name.c_str(),
declaration_only ? "= 0;" : "override {"),
kLineContinuationOffset);
if (!declaration_only) {
IndentedText block;
block.PushOffset(kBlockOffset);
block.AddLine("property_set_.reset(");
block.AddLineWithOffset(
"new PropertySet(dbus_object_proxy_, base::Bind(callback, this)));",
kLineContinuationOffset);
block.AddLine("property_set_->ConnectSignals();");
block.AddLine("property_set_->GetAll();");
text->AddBlock(block);
text->AddLine("}");
}
}
// static
void ProxyGenerator::AddSetPropertyChanged(const string& class_name,
bool declaration_only,
IndentedText* text) {
text->AddBlankLine();
text->AddLine(StringPrintf("%svoid SetPropertyChangedCallback(",
declaration_only ? "virtual " : ""));
text->AddLineWithOffset(
StringPrintf("const base::Callback<void(%sInterface*, "
"const std::string&)>& callback) %s",
class_name.c_str(),
declaration_only ? "= 0;" : "override {"),
kLineContinuationOffset);
if (!declaration_only) {
text->AddLineWithOffset("on_property_changed_ = callback;", kBlockOffset);
text->AddLine("}");
}
}
// static
void ProxyGenerator::AddGetProperties(IndentedText* text) {
text->AddBlankLine();
// Dereference and take the address since sometimes property_set_ is a raw
// pointer and sometimes it is a std::unique_ptr.
text->AddLine(
"const PropertySet* GetProperties() const { "
"return &(*property_set_); }");
text->AddLine("PropertySet* GetProperties() { return &(*property_set_); }");
}
// static
void ProxyGenerator::AddOnPropertyChanged(IndentedText* text) {
text->AddLine("void OnPropertyChanged(const std::string& property_name) {");
text->PushOffset(kBlockOffset);
text->AddLine("if (!on_property_changed_.is_null())");
text->PushOffset(kBlockOffset);
text->AddLine("on_property_changed_.Run(this, property_name);");
text->PopOffset();
text->PopOffset();
text->AddLine("}");
text->AddBlankLine();
}
void ProxyGenerator::AddSignalHandlerRegistration(
const Interface::Signal& signal,
const string& interface_name,
bool declaration_only,
IndentedText* text) {
IndentedText block;
block.AddBlankLine();
block.AddLine(StringPrintf("%svoid Register%sSignalHandler(",
declaration_only ? "virtual " : "",
signal.name.c_str()));
block.PushOffset(kLineContinuationOffset);
AddSignalCallbackArg(signal, false, &block);
block.AddLine(StringPrintf(
"dbus::ObjectProxy::OnConnectedCallback on_connected_callback)%s",
declaration_only ? " = 0;" : " override {"));
if (!declaration_only) {
block.PopOffset(); // Method signature arguments
block.PushOffset(kBlockOffset);
block.AddLine("brillo::dbus_utils::ConnectToSignal(");
block.PushOffset(kLineContinuationOffset);
block.AddLine("dbus_object_proxy_,");
block.AddLine(StringPrintf("\"%s\",", interface_name.c_str()));
block.AddLine(StringPrintf("\"%s\",", signal.name.c_str()));
block.AddLine("signal_callback,");
block.AddLine("on_connected_callback);");
block.PopOffset(); // Function call line continuation
block.PopOffset(); // Method body
block.AddLine("}");
}
text->AddBlock(block);
}
// static
void ProxyGenerator::AddPropertySet(const ServiceConfig& config,
const Interface& interface,
IndentedText* text) {
if (config.object_manager.name.empty() && interface.properties.empty())
return;
IndentedText block;
block.AddLine("class PropertySet : public dbus::PropertySet {");
block.AddLineWithOffset("public:", kScopeOffset);
block.PushOffset(kBlockOffset);
block.AddLineAndPushOffsetTo("PropertySet(dbus::ObjectProxy* object_proxy,",
1, '(');
block.AddLine("const PropertyChangedCallback& callback)");
block.PopOffset();
block.PushOffset(kLineContinuationOffset);
block.AddLineAndPushOffsetTo(": dbus::PropertySet{object_proxy,", 1, '{');
block.AddLine(StringPrintf("\"%s\",", interface.name.c_str()));
block.AddLine("callback} {");
block.PopOffset();
block.PopOffset();
block.PushOffset(kBlockOffset);
for (const auto& prop : interface.properties) {
block.AddLine(
StringPrintf("RegisterProperty(%sName(), &%s);",
prop.name.c_str(),
NameParser{prop.name}.MakeVariableName().c_str()));
}
block.PopOffset();
block.AddLine("}");
block.AddBlankLine();
DbusSignature signature;
for (const auto& prop : interface.properties) {
string type;
CHECK(signature.Parse(prop.type, &type));
block.AddLine(
StringPrintf("brillo::dbus_utils::Property<%s> %s;",
type.c_str(),
NameParser{prop.name}.MakeVariableName().c_str()));
}
block.AddBlankLine();
block.PopOffset();
block.AddLineWithOffset("private:", kScopeOffset);
block.AddLineWithOffset("DISALLOW_COPY_AND_ASSIGN(PropertySet);",
kBlockOffset);
block.AddLine("};");
block.AddBlankLine();
text->AddBlock(block);
}
// static
void ProxyGenerator::AddProperties(const Interface& interface,
bool declaration_only,
IndentedText* text) {
if (declaration_only && !interface.properties.empty())
text->AddBlankLine();
DbusSignature signature;
for (const auto& prop : interface.properties) {
if (declaration_only) {
text->AddLine(
StringPrintf("static const char* %sName() { return \"%s\"; }",
prop.name.c_str(),
prop.name.c_str()));
}
string type;
CHECK(signature.Parse(prop.type, &type));
MakeConstReferenceIfNeeded(&type);
string name = NameParser{prop.name}.MakeVariableName();
if (!declaration_only)
text->AddBlankLine();
text->AddLine(
StringPrintf("%s%s %s() const%s",
declaration_only ? "virtual " : "",
type.c_str(),
name.c_str(),
declaration_only ? " = 0;" : " override {"));
if (!declaration_only) {
text->AddLineWithOffset(
StringPrintf("return property_set_->%s.value();", name.c_str()),
kBlockOffset);
text->AddLine("}");
}
if (prop.access == "readwrite") {
if (!declaration_only)
text->AddBlankLine();
text->AddLineAndPushOffsetTo(
StringPrintf("%svoid set_%s(%s value,",
declaration_only ? "virtual " : "",
name.c_str(),
type.c_str()),
1, '(');
text->AddLine(
StringPrintf("const base::Callback<void(bool)>& callback)%s",
declaration_only ? " = 0;" : " override {"));
text->PopOffset();
if (!declaration_only) {
text->AddLineWithOffset(
StringPrintf("property_set_->%s.Set(value, callback);", name.c_str()),
kBlockOffset);
text->AddLine("}");
}
}
}
}
// static
void ProxyGenerator::AddMethodProxy(const Interface::Method& method,
const string& interface_name,
bool declaration_only,
IndentedText* text) {
IndentedText block;
DbusSignature signature;
block.AddBlankLine();
block.AddComments(method.doc_string);
block.AddLine(StringPrintf("%sbool %s(",
declaration_only ? "virtual " : "",
method.name.c_str()));
block.PushOffset(kLineContinuationOffset);
vector<string> argument_names;
int argument_number = 0;
for (const auto& argument : method.input_arguments) {
string argument_type;
CHECK(signature.Parse(argument.type, &argument_type));
MakeConstReferenceIfNeeded(&argument_type);
string argument_name = GetArgName("in", argument.name, ++argument_number);
argument_names.push_back(argument_name);
block.AddLine(StringPrintf(
"%s %s,", argument_type.c_str(), argument_name.c_str()));
}
vector<string> out_param_names{"response.get()", "error"};
for (const auto& argument : method.output_arguments) {
string argument_type;
CHECK(signature.Parse(argument.type, &argument_type));
string argument_name = GetArgName("out", argument.name, ++argument_number);
out_param_names.push_back(argument_name);
block.AddLine(StringPrintf(
"%s* %s,", argument_type.c_str(), argument_name.c_str()));
}
block.AddLine("brillo::ErrorPtr* error,");
block.AddLine(
StringPrintf("int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)%s",
declaration_only ? " = 0;" : " override {"));
block.PopOffset();
if (!declaration_only) {
block.PushOffset(kBlockOffset);
block.AddLine(
"auto response = brillo::dbus_utils::CallMethodAndBlockWithTimeout(");
block.PushOffset(kLineContinuationOffset);
block.AddLine("timeout_ms,");
block.AddLine("dbus_object_proxy_,");
block.AddLine(StringPrintf("\"%s\",", interface_name.c_str()));
block.AddLine(StringPrintf("\"%s\",", method.name.c_str()));
string last_argument = "error";
for (const auto& argument_name : argument_names) {
block.AddLine(StringPrintf("%s,", last_argument.c_str()));
last_argument = argument_name;
}
block.AddLine(StringPrintf("%s);", last_argument.c_str()));
block.PopOffset();
block.AddLine("return response && "
"brillo::dbus_utils::ExtractMethodCallResults(");
block.PushOffset(kLineContinuationOffset);
block.AddLine(brillo::string_utils::Join(", ", out_param_names) + ");");
block.PopOffset();
block.PopOffset();
block.AddLine("}");
}
text->AddBlock(block);
}
// static
void ProxyGenerator::AddAsyncMethodProxy(const Interface::Method& method,
const string& interface_name,
bool declaration_only,
IndentedText* text) {
IndentedText block;
DbusSignature signature;
block.AddBlankLine();
block.AddComments(method.doc_string);
block.AddLine(StringPrintf("%svoid %sAsync(",
declaration_only ? "virtual " : "",
method.name.c_str()));
block.PushOffset(kLineContinuationOffset);
vector<string> argument_names;
int argument_number = 0;
for (const auto& argument : method.input_arguments) {
string argument_type;
CHECK(signature.Parse(argument.type, &argument_type));
MakeConstReferenceIfNeeded(&argument_type);
string argument_name = GetArgName("in", argument.name, ++argument_number);
argument_names.push_back(argument_name);
block.AddLine(StringPrintf(
"%s %s,", argument_type.c_str(), argument_name.c_str()));
}
vector<string> out_params;
for (const auto& argument : method.output_arguments) {
string argument_type;
CHECK(signature.Parse(argument.type, &argument_type));
MakeConstReferenceIfNeeded(&argument_type);
if (!argument.name.empty())
base::StringAppendF(&argument_type, " /*%s*/", argument.name.c_str());
out_params.push_back(argument_type);
}
block.AddLine(StringPrintf(
"const base::Callback<void(%s)>& success_callback,",
brillo::string_utils::Join(", ", out_params).c_str()));
block.AddLine(
"const base::Callback<void(brillo::Error*)>& error_callback,");
block.AddLine(
StringPrintf("int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)%s",
declaration_only ? " = 0;" : " override {"));
block.PopOffset();
if (!declaration_only) {
block.PushOffset(kBlockOffset);
block.AddLine("brillo::dbus_utils::CallMethodWithTimeout(");
block.PushOffset(kLineContinuationOffset);
block.AddLine("timeout_ms,");
block.AddLine("dbus_object_proxy_,");
block.AddLine(StringPrintf("\"%s\",", interface_name.c_str()));
block.AddLine(StringPrintf("\"%s\",", method.name.c_str()));
block.AddLine("success_callback,");
string last_argument = "error_callback";
for (const auto& argument_name : argument_names) {
block.AddLine(StringPrintf("%s,", last_argument.c_str()));
last_argument = argument_name;
}
block.AddLine(StringPrintf("%s);", last_argument.c_str()));
block.PopOffset();
block.PopOffset();
block.AddLine("}");
}
text->AddBlock(block);
}
// static
void ProxyGenerator::AddMethodMock(const Interface::Method& method,
const string& /* interface_name */,
IndentedText* text) {
DbusSignature signature;
vector<string> arguments;
for (const auto& argument : method.input_arguments) {
string argument_type;
CHECK(signature.Parse(argument.type, &argument_type));
MakeConstReferenceIfNeeded(&argument_type);
if (!argument.name.empty())
base::StringAppendF(&argument_type, " /*in_%s*/", argument.name.c_str());
arguments.push_back(argument_type);
}
for (const auto& argument : method.output_arguments) {
string argument_type;
CHECK(signature.Parse(argument.type, &argument_type));
argument_type += '*';
if (!argument.name.empty())
base::StringAppendF(&argument_type, " /*out_%s*/", argument.name.c_str());
arguments.push_back(argument_type);
}
arguments.push_back("brillo::ErrorPtr* /*error*/");
arguments.push_back("int /*timeout_ms*/");
AddMockMethodDeclaration(method.name, "bool", arguments, text);
}
// static
void ProxyGenerator::AddAsyncMethodMock(const Interface::Method& method,
const string& /* interface_name */,
IndentedText* text) {
DbusSignature signature;
vector<string> arguments;
for (const auto& argument : method.input_arguments) {
string argument_type;
CHECK(signature.Parse(argument.type, &argument_type));
MakeConstReferenceIfNeeded(&argument_type);
if (!argument.name.empty())
base::StringAppendF(&argument_type, " /*in_%s*/", argument.name.c_str());
arguments.push_back(argument_type);
}
vector<string> out_params;
for (const auto& argument : method.output_arguments) {
string argument_type;
CHECK(signature.Parse(argument.type, &argument_type));
MakeConstReferenceIfNeeded(&argument_type);
if (!argument.name.empty())
base::StringAppendF(&argument_type, " /*%s*/", argument.name.c_str());
out_params.push_back(argument_type);
}
arguments.push_back(StringPrintf(
"const base::Callback<void(%s)>& /*success_callback*/",
brillo::string_utils::Join(", ", out_params).c_str()));
arguments.push_back(
"const base::Callback<void(brillo::Error*)>& /*error_callback*/");
arguments.push_back("int /*timeout_ms*/");
AddMockMethodDeclaration(method.name + "Async", "void", arguments, text);
}
void ProxyGenerator::AddMockMethodDeclaration(const string& method_name,
const string& return_type,
const vector<string>& arguments,
IndentedText* text) {
IndentedText block;
// GMOCK doesn't go all the way up to 11, so we need to handle methods with
// 11 arguments or more in a different way.
if (arguments.size() >= 11) {
block.AddLineAndPushOffsetTo(
StringPrintf("%s %s(%s,",
return_type.c_str(),
method_name.c_str(),
arguments.front().c_str()),
1, '(');
for (size_t i = 1; i < arguments.size() - 1; i++)
block.AddLine(StringPrintf("%s,", arguments[i].c_str()));
block.AddLine(StringPrintf("%s) override {", arguments.back().c_str()));
block.PopOffset();
block.PushOffset(kBlockOffset);
block.AddLine(StringPrintf(
"LOG(WARNING) << \"%s(): gmock can't handle methods with %" PRIuS
" arguments. You can override this method in a subclass if you need"
" to.\";",
method_name.c_str(), arguments.size()));
if (return_type == "void") {
// No return added here.
} else if (return_type == "bool") {
block.AddLine("return false;");
} else {
LOG(FATAL) << "The return type is not supported.";
}
block.PopOffset();
block.AddLine("}");
} else {
block.AddLineAndPushOffsetTo(
StringPrintf("MOCK_METHOD%zu(%s,",
arguments.size(), method_name.c_str()),
1, '(');
block.AddLineAndPushOffsetTo(
StringPrintf("%s(%s,", return_type.c_str(), arguments.front().c_str()),
1, '(');
for (size_t i = 1; i < arguments.size() - 1; i++)
block.AddLine(StringPrintf("%s,", arguments[i].c_str()));
block.AddLine(StringPrintf("%s));", arguments.back().c_str()));
block.PopOffset();
block.PopOffset();
}
text->AddBlock(block);
}
// static
void ProxyGenerator::AddSignalHandlerRegistrationMock(
const Interface::Signal& signal,
IndentedText* text) {
IndentedText callback_arg_text;
AddSignalCallbackArg(signal, true, &callback_arg_text);
vector<string> arg_lines = callback_arg_text.GetLines();
IndentedText block;
block.AddLineAndPushOffsetTo(
StringPrintf("MOCK_METHOD2(Register%sSignalHandler,",
signal.name.c_str()),
1, '(');
for (size_t i = 0; i < arg_lines.size(); ++i) {
if (i == 0)
block.AddLineAndPushOffsetTo("void(" + arg_lines[i], 1, '(');
else
block.AddLine(arg_lines[i]);
}
block.AddLine(
"dbus::ObjectProxy::OnConnectedCallback /*on_connected_callback*/));");
text->AddBlock(block);
}
// static
void ProxyGenerator::AddSignalCallbackArg(const Interface::Signal& signal,
bool comment_arg_name,
IndentedText* block) {
DbusSignature signature;
string signal_callback = StringPrintf("%ssignal_callback%s",
comment_arg_name ? "/*" : "",
comment_arg_name ? "*/" : "");
if (signal.arguments.empty()) {
block->AddLine(StringPrintf("const base::Closure& %s,",
signal_callback.c_str()));
} else {
string last_argument;
string prefix{"const base::Callback<void("};
for (const auto argument : signal.arguments) {
if (!last_argument.empty()) {
if (!prefix.empty()) {
block->AddLineAndPushOffsetTo(
StringPrintf("%s%s,", prefix.c_str(), last_argument.c_str()),
1, '(');
prefix.clear();
} else {
block->AddLine(StringPrintf("%s,", last_argument.c_str()));
}
}
CHECK(signature.Parse(argument.type, &last_argument));
MakeConstReferenceIfNeeded(&last_argument);
}
block->AddLine(StringPrintf("%s%s)>& %s,",
prefix.c_str(),
last_argument.c_str(),
signal_callback.c_str()));
if (prefix.empty()) {
block->PopOffset();
}
}
}
// static
void ProxyGenerator::ObjectManager::GenerateProxy(
const ServiceConfig& config,
const std::vector<Interface>& interfaces,
IndentedText* text) {
if (config.object_manager.name.empty())
return;
NameParser object_manager{config.object_manager.name};
object_manager.AddOpenNamespaces(text, false);
text->AddBlankLine();
string class_name = object_manager.type_name + "Proxy";
text->AddLine(StringPrintf("class %s : "
"public dbus::ObjectManager::Interface {",
class_name.c_str()));
text->AddLineWithOffset("public:", kScopeOffset);
text->PushOffset(kBlockOffset);
AddConstructor(config, class_name, interfaces, text);
AddDestructor(class_name, interfaces, text);
AddGetObjectManagerProxy(text);
for (const auto& itf : interfaces) {
AddInterfaceAccessors(itf, text);
}
text->PopOffset();
text->AddLineWithOffset("private:", kScopeOffset);
text->PushOffset(kBlockOffset);
AddOnPropertyChanged(interfaces, text);
AddObjectAdded(config, interfaces, text);
AddObjectRemoved(interfaces, text);
AddCreateProperties(interfaces, class_name, text);
AddDataMembers(config, interfaces, class_name, text);
text->AddLine(StringPrintf("DISALLOW_COPY_AND_ASSIGN(%s);",
class_name.c_str()));
text->PopOffset();
text->AddLine("};");
text->AddBlankLine();
object_manager.AddCloseNamespaces(text, false);
text->AddBlankLine();
}
void ProxyGenerator::ObjectManager::AddConstructor(
const ServiceConfig& config,
const std::string& class_name,
const std::vector<Interface>& interfaces,
IndentedText* text) {
if (config.service_name.empty()) {
text->AddLineAndPushOffsetTo(
StringPrintf("%s(const scoped_refptr<dbus::Bus>& bus,",
class_name.c_str()),
1, '(');
text->AddLine("const std::string& service_name)");
text->PopOffset();
} else {
text->AddLine(StringPrintf("%s(const scoped_refptr<dbus::Bus>& bus)",
class_name.c_str()));
}
text->PushOffset(kLineContinuationOffset);
text->AddLine(": bus_{bus},");
text->PushOffset(kBlockOffset);
if (config.service_name.empty()) {
text->AddLine("service_name_{service_name},");
}
text->AddLine("dbus_object_manager_{bus->GetObjectManager(");
text->PushOffset(kLineContinuationOffset);
if (config.service_name.empty()) {
text->AddLine("service_name,");
} else {
text->AddLine(StringPrintf("\"%s\",", config.service_name.c_str()));
}
text->AddLine(StringPrintf("dbus::ObjectPath{\"%s\"})} {",
config.object_manager.object_path.c_str()));
text->PopOffset();
text->PopOffset();
text->PopOffset();
text->PushOffset(kBlockOffset);
for (const auto& itf : interfaces) {
text->AddLine(
StringPrintf("dbus_object_manager_->RegisterInterface(\"%s\", this);",
itf.name.c_str()));
}
text->PopOffset();
text->AddLine("}");
text->AddBlankLine();
}
void ProxyGenerator::ObjectManager::AddDestructor(
const std::string& class_name,
const std::vector<Interface>& interfaces,
IndentedText* text) {
text->AddLine(StringPrintf("~%s() override {", class_name.c_str()));
text->PushOffset(kBlockOffset);
for (const auto& itf : interfaces) {
text->AddLine(
StringPrintf("dbus_object_manager_->UnregisterInterface(\"%s\");",
itf.name.c_str()));
}
text->PopOffset();
text->AddLine("}");
text->AddBlankLine();
}
void ProxyGenerator::ObjectManager::AddGetObjectManagerProxy(
IndentedText* text) {
text->AddLine("dbus::ObjectManager* GetObjectManagerProxy() const {");
text->AddLineWithOffset("return dbus_object_manager_;", kBlockOffset);
text->AddLine("}");
text->AddBlankLine();
}
void ProxyGenerator::ObjectManager::AddInterfaceAccessors(
const Interface& interface,
IndentedText* text) {
NameParser itf_name{interface.name};
string map_name = itf_name.MakeVariableName() + "_instances_";
// GetProxy().
if (interface.path.empty()) {
// We have no fixed path, so there could be multiple instances of this itf.
text->AddLine(StringPrintf("%sInterface* Get%s(",
itf_name.MakeProxyName(true).c_str(),
itf_name.MakeProxyName(false).c_str()));
text->PushOffset(kLineContinuationOffset);
text->AddLine("const dbus::ObjectPath& object_path) {");
text->PopOffset();
text->PushOffset(kBlockOffset);
text->AddLine(StringPrintf("auto p = %s.find(object_path);",
map_name.c_str()));
text->AddLine(StringPrintf("if (p != %s.end())", map_name.c_str()));
text->PushOffset(kBlockOffset);
text->AddLine("return p->second.get();");
text->PopOffset();
text->AddLine("return nullptr;");
text->PopOffset();
text->AddLine("}");
} else {
// We have a fixed path, so the object could be considered a "singleton".
// Skip the object_path parameter and return the first available instance.
text->AddLine(StringPrintf("%sInterface* Get%s() {",
itf_name.MakeProxyName(true).c_str(),
itf_name.MakeProxyName(false).c_str()));
text->PushOffset(kBlockOffset);
text->AddLine(StringPrintf("if (%s.empty())", map_name.c_str()));
text->AddLineWithOffset("return nullptr;", kBlockOffset);
text->AddLine(StringPrintf("return %s.begin()->second.get();",
map_name.c_str()));
text->PopOffset();
text->AddLine("}");
}
// GetInstances().
text->AddLine(
StringPrintf("std::vector<%sInterface*> Get%sInstances() const {",
itf_name.MakeProxyName(true).c_str(),
itf_name.type_name.c_str()));
text->PushOffset(kBlockOffset);
text->AddLine(StringPrintf("std::vector<%sInterface*> values;",
itf_name.MakeProxyName(true).c_str()));
text->AddLine(StringPrintf("values.reserve(%s.size());", map_name.c_str()));
text->AddLine(StringPrintf("for (const auto& pair : %s)", map_name.c_str()));
text->AddLineWithOffset("values.push_back(pair.second.get());", kBlockOffset);
text->AddLine("return values;");
text->PopOffset();
text->AddLine("}");
// SetAddedCallback().
text->AddLine(StringPrintf("void Set%sAddedCallback(",
itf_name.type_name.c_str()));
text->PushOffset(kLineContinuationOffset);
text->AddLine(
StringPrintf("const base::Callback<void(%sInterface*)>& callback) {",
itf_name.MakeProxyName(true).c_str()));
text->PopOffset();
text->PushOffset(kBlockOffset);
text->AddLine(StringPrintf("on_%s_added_ = callback;",
itf_name.MakeVariableName().c_str()));
text->PopOffset();
text->AddLine("}");
// SetRemovedCallback().
text->AddLine(StringPrintf("void Set%sRemovedCallback(",
itf_name.type_name.c_str()));
text->PushOffset(kLineContinuationOffset);
text->AddLine("const base::Callback<void(const dbus::ObjectPath&)>& "
"callback) {");
text->PopOffset();
text->PushOffset(kBlockOffset);
text->AddLine(StringPrintf("on_%s_removed_ = callback;",
itf_name.MakeVariableName().c_str()));
text->PopOffset();
text->AddLine("}");
text->AddBlankLine();
}
void ProxyGenerator::ObjectManager::AddOnPropertyChanged(
const std::vector<Interface>& interfaces,
IndentedText* text) {
// If there are no interfaces with properties, comment out parameter
// names for OnPropertyChanged() to prevent compiler warnings on unused
// function parameters.
auto has_props = [](const Interface& itf) { return !itf.properties.empty(); };
auto itf_with_props = std::find_if(interfaces.begin(), interfaces.end(),
has_props);
if (itf_with_props == interfaces.end()) {
text->AddLineAndPushOffsetTo("void OnPropertyChanged("
"const dbus::ObjectPath& /* object_path */,",
1, '(');
text->AddLine("const std::string& /* interface_name */,");
text->AddLine("const std::string& /* property_name */) {}");
text->PopOffset();
text->AddBlankLine();
return;
}
text->AddLineAndPushOffsetTo("void OnPropertyChanged("
"const dbus::ObjectPath& object_path,",
1, '(');
text->AddLine("const std::string& interface_name,");
text->AddLine("const std::string& property_name) {");
text->PopOffset();
text->PushOffset(kBlockOffset);
for (const auto& itf : interfaces) {
if (itf.properties.empty())
continue;
NameParser itf_name{itf.name};
text->AddLine(StringPrintf("if (interface_name == \"%s\") {",
itf.name.c_str()));
text->PushOffset(kBlockOffset);
string map_name = itf_name.MakeVariableName() + "_instances_";
text->AddLine(StringPrintf("auto p = %s.find(object_path);",
map_name.c_str()));
text->AddLine(StringPrintf("if (p == %s.end())", map_name.c_str()));
text->PushOffset(kBlockOffset);
text->AddLine("return;");
text->PopOffset();
text->AddLine("p->second->OnPropertyChanged(property_name);");
text->AddLine("return;");
text->PopOffset();
text->AddLine("}");
}
text->PopOffset();
text->AddLine("}");
text->AddBlankLine();
}
void ProxyGenerator::ObjectManager::AddObjectAdded(
const ServiceConfig& config,
const std::vector<Interface>& interfaces,
IndentedText* text) {
text->AddLine("void ObjectAdded(");
text->PushOffset(kLineContinuationOffset);
text->AddLine("const dbus::ObjectPath& object_path,");
text->AddLine("const std::string& interface_name) override {");
text->PopOffset();
text->PushOffset(kBlockOffset);
for (const auto& itf : interfaces) {
NameParser itf_name{itf.name};
string var_name = itf_name.MakeVariableName();
text->AddLine(StringPrintf("if (interface_name == \"%s\") {",
itf.name.c_str()));
text->PushOffset(kBlockOffset);
if (!itf.properties.empty()) {
text->AddLine("auto property_set =");
text->PushOffset(kLineContinuationOffset);
text->AddLine(StringPrintf("static_cast<%s::PropertySet*>(",
itf_name.MakeProxyName(true).c_str()));
text->PushOffset(kLineContinuationOffset);
text->AddLine("dbus_object_manager_->GetProperties(object_path, "
"interface_name));");
text->PopOffset();
text->PopOffset();
}
text->AddLine(StringPrintf("std::unique_ptr<%s> %s_proxy{",
itf_name.MakeProxyName(true).c_str(),
var_name.c_str()));
text->PushOffset(kBlockOffset);
string new_instance = StringPrintf("new %s{bus_",
itf_name.MakeProxyName(true).c_str());
if (config.service_name.empty()) {
new_instance += ", service_name_";
}
if (itf.path.empty())
new_instance += ", object_path";
if (!itf.properties.empty())
new_instance += ", property_set";
new_instance += "}";
text->AddLine(new_instance);
text->PopOffset();
text->AddLine("};");
text->AddLine(StringPrintf("auto p = %s_instances_.emplace(object_path, "
"std::move(%s_proxy));",
var_name.c_str(), var_name.c_str()));
text->AddLine(StringPrintf("if (!on_%s_added_.is_null())",
var_name.c_str()));
text->PushOffset(kBlockOffset);
text->AddLine(StringPrintf("on_%s_added_.Run(p.first->second.get());",
var_name.c_str()));
text->PopOffset();
text->AddLine("return;");
text->PopOffset();
text->AddLine("}");
}
text->PopOffset();
text->AddLine("}");
text->AddBlankLine();
}
void ProxyGenerator::ObjectManager::AddObjectRemoved(
const std::vector<Interface>& interfaces,
IndentedText* text) {
text->AddLine("void ObjectRemoved(");
text->PushOffset(kLineContinuationOffset);
text->AddLine("const dbus::ObjectPath& object_path,");
text->AddLine("const std::string& interface_name) override {");
text->PopOffset();
text->PushOffset(kBlockOffset);
for (const auto& itf : interfaces) {
NameParser itf_name{itf.name};
string var_name = itf_name.MakeVariableName();
text->AddLine(StringPrintf("if (interface_name == \"%s\") {",
itf.name.c_str()));
text->PushOffset(kBlockOffset);
text->AddLine(StringPrintf("auto p = %s_instances_.find(object_path);",
var_name.c_str()));
text->AddLine(StringPrintf("if (p != %s_instances_.end()) {",
var_name.c_str()));
text->PushOffset(kBlockOffset);
text->AddLine(StringPrintf("if (!on_%s_removed_.is_null())",
var_name.c_str()));
text->PushOffset(kBlockOffset);
text->AddLine(StringPrintf("on_%s_removed_.Run(object_path);",
var_name.c_str()));
text->PopOffset();
text->AddLine(StringPrintf("%s_instances_.erase(p);",
var_name.c_str()));
text->PopOffset();
text->AddLine("}");
text->AddLine("return;");
text->PopOffset();
text->AddLine("}");
}
text->PopOffset();
text->AddLine("}");
text->AddBlankLine();
}
void ProxyGenerator::ObjectManager::AddCreateProperties(
const std::vector<Interface>& interfaces,
const std::string& class_name,
IndentedText* text) {
text->AddLine("dbus::PropertySet* CreateProperties(");
text->PushOffset(kLineContinuationOffset);
text->AddLine("dbus::ObjectProxy* object_proxy,");
text->AddLine("const dbus::ObjectPath& object_path,");
text->AddLine("const std::string& interface_name) override {");
text->PopOffset();
text->PushOffset(kBlockOffset);
for (const auto& itf : interfaces) {
NameParser itf_name{itf.name};
text->AddLine(StringPrintf("if (interface_name == \"%s\") {",
itf.name.c_str()));
text->PushOffset(kBlockOffset);
text->AddLine(StringPrintf("return new %s::PropertySet{",
itf_name.MakeProxyName(true).c_str()));
text->PushOffset(kLineContinuationOffset);
text->AddLine("object_proxy,");
text->AddLineAndPushOffsetTo(
StringPrintf("base::Bind(&%s::OnPropertyChanged,",
class_name.c_str()),
1, '(');
text->AddLine("weak_ptr_factory_.GetWeakPtr(),");
text->AddLine("object_path,");
text->AddLine("interface_name)");
text->PopOffset();
text->PopOffset();
text->AddLine("};");
text->PopOffset();
text->AddLine("}");
}
text->AddLineAndPushOffsetTo("LOG(FATAL) << \"Creating properties for "
"unsupported interface \"", 1, ' ');
text->AddLine("<< interface_name;");
text->PopOffset();
text->AddLine("return nullptr;");
text->PopOffset();
text->AddLine("}");
text->AddBlankLine();
}
void ProxyGenerator::ObjectManager::AddDataMembers(
const ServiceConfig& config,
const std::vector<Interface>& interfaces,
const std::string& class_name,
IndentedText* text) {
text->AddLine("scoped_refptr<dbus::Bus> bus_;");
if (config.service_name.empty()) {
text->AddLine("std::string service_name_;");
}
text->AddLine("dbus::ObjectManager* dbus_object_manager_;");
for (const auto& itf : interfaces) {
NameParser itf_name{itf.name};
string var_name = itf_name.MakeVariableName();
text->AddLineAndPushOffsetTo("std::map<dbus::ObjectPath,", 1, '<');
text->AddLine(StringPrintf("std::unique_ptr<%s>> %s_instances_;",
itf_name.MakeProxyName(true).c_str(),
var_name.c_str()));
text->PopOffset();
text->AddLine(
StringPrintf("base::Callback<void(%sInterface*)> on_%s_added_;",
itf_name.MakeProxyName(true).c_str(),
var_name.c_str()));
text->AddLine(StringPrintf("base::Callback<void(const dbus::ObjectPath&)> "
"on_%s_removed_;",
var_name.c_str()));
}
text->AddLine(
StringPrintf("base::WeakPtrFactory<%s> weak_ptr_factory_{this};",
class_name.c_str()));
text->AddBlankLine();
}
// static
string ProxyGenerator::GetHandlerNameForSignal(const string& signal) {
return StringPrintf("On%sSignal", signal.c_str());
}
} // namespace chromeos_dbus_bindings