blob: 797a7d56976e790cb19d3bcb95574d3e4f096fb0 [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 <utility>
#include <base/logging.h>
#include <base/strings/stringprintf.h>
#include <chromeos/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 <chromeos/any.h>");
text.AddLine("#include <chromeos/dbus/dbus_method_invoker.h>");
text.AddLine("#include <chromeos/dbus/dbus_property.h>");
text.AddLine("#include <chromeos/dbus/dbus_signal_handler.h>");
text.AddLine("#include <chromeos/errors/error.h>");
text.AddLine("#include <chromeos/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) {
GenerateInterfaceProxy(config, interface, &text);
}
ObjectManager::GenerateProxy(config, interfaces, &text);
text.AddLine(StringPrintf("#endif // %s", header_guard.c_str()));
return WriteTextToFile(output_file, text);
}
// static
void ProxyGenerator::GenerateInterfaceProxy(const ServiceConfig& config,
const Interface& interface,
IndentedText* text) {
NameParser parser{interface.name};
string proxy_name = parser.MakeProxyName(false);
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 {", proxy_name.c_str()));
text->AddLineWithOffset("public:", kScopeOffset);
text->PushOffset(kBlockOffset);
AddPropertySet(config, interface, text);
AddConstructor(config, interface, proxy_name, text);
AddDestructor(proxy_name, text);
AddSignalHandlerRegistration(interface, text);
AddReleaseObjectProxy(text);
AddGetObjectPath(text);
AddGetObjectProxy(text);
if (!config.object_manager.name.empty() && !interface.properties.empty())
AddPropertyPublicMethods(proxy_name, text);
for (const auto& method : interface.methods) {
AddMethodProxy(method, interface.name, text);
AddAsyncMethodProxy(method, interface.name, text);
}
AddProperties(config, interface, text);
text->PopOffset();
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(%s*, const std::string&)> "
"on_property_changed_;",
proxy_name.c_str()));
}
text->AddLine("dbus::ObjectProxy* dbus_object_proxy_;");
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::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() {", class_name.c_str()));
block.AddLine("}");
block.AddBlankLine();
text->AddBlock(block);
}
// static
void ProxyGenerator::AddReleaseObjectProxy(IndentedText* text) {
text->AddLine("void ReleaseObjectProxy(const base::Closure& callback) {");
text->AddLineWithOffset(
"bus_->RemoveObjectProxy(service_name_, object_path_, callback);",
kBlockOffset);
text->AddLine("}");
text->AddBlankLine();
}
// static
void ProxyGenerator::AddGetObjectPath(IndentedText* text) {
text->AddLine("const dbus::ObjectPath& GetObjectPath() const {");
text->AddLineWithOffset("return object_path_;", kBlockOffset);
text->AddLine("}");
text->AddBlankLine();
}
// static
void ProxyGenerator::AddGetObjectProxy(IndentedText* text) {
text->AddLine("dbus::ObjectProxy* GetObjectProxy() const { "
"return dbus_object_proxy_; }");
text->AddBlankLine();
}
// static
void ProxyGenerator::AddPropertyPublicMethods(const string& class_name,
IndentedText* text) {
text->AddLine("void SetPropertyChangedCallback(");
text->AddLineWithOffset(
StringPrintf("const base::Callback<void(%s*, "
"const std::string&)>& callback) {", class_name.c_str()),
kLineContinuationOffset);
text->AddLineWithOffset("on_property_changed_ = callback;", kBlockOffset);
text->AddLine("}");
text->AddBlankLine();
text->AddLine("const PropertySet* GetProperties() const "
"{ return property_set_; }");
text->AddLine("PropertySet* GetProperties() { return property_set_; }");
text->AddBlankLine();
}
// 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& interface,
IndentedText* text) {
IndentedText block;
DbusSignature signature;
for (const auto& signal : interface.signals) {
block.AddLine(
StringPrintf("void Register%sSignalHandler(", signal.name.c_str()));
block.PushOffset(kLineContinuationOffset);
if (signal.arguments.empty()) {
block.AddLine("const base::Closure& signal_callback,");
} 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)>& signal_callback,",
prefix.c_str(),
last_argument.c_str()));
if (prefix.empty()) {
block.PopOffset();
}
}
block.AddLine("dbus::ObjectProxy::OnConnectedCallback "
"on_connected_callback) {");
block.PopOffset(); // Method signature arguments
block.PushOffset(kBlockOffset);
block.AddLine("chromeos::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("}");
block.AddBlankLine();
}
text->AddBlock(block);
}
// static
void ProxyGenerator::AddPropertySet(const ServiceConfig& config,
const Interface& interface,
IndentedText* text) {
// Must have ObjectManager in order for property system to work correctly.
if (config.object_manager.name.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(\"%s\", &%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("chromeos::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 ServiceConfig& config,
const Interface& interface,
IndentedText* text) {
// Must have ObjectManager in order for property system to work correctly.
if (config.object_manager.name.empty())
return;
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("%s %s() const {",
type.c_str(),
name.c_str()));
text->AddLineWithOffset(
StringPrintf("return property_set_->%s.value();", name.c_str()),
kBlockOffset);
text->AddLine("}");
text->AddBlankLine();
}
}
// static
void ProxyGenerator::AddMethodProxy(const Interface::Method& method,
const string& interface_name,
IndentedText* text) {
IndentedText block;
DbusSignature signature;
block.AddComments(method.doc_string);
block.AddLine(StringPrintf("bool %s(", 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("chromeos::ErrorPtr* error,");
block.AddLine("int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) {");
block.PopOffset();
block.PushOffset(kBlockOffset);
block.AddLine(
"auto response = chromeos::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 && "
"chromeos::dbus_utils::ExtractMethodCallResults(");
block.PushOffset(kLineContinuationOffset);
block.AddLine(chromeos::string_utils::Join(", ", out_param_names) + ");");
block.PopOffset();
block.PopOffset();
block.AddLine("}");
block.AddBlankLine();
text->AddBlock(block);
}
// static
void ProxyGenerator::AddAsyncMethodProxy(const Interface::Method& method,
const string& interface_name,
IndentedText* text) {
IndentedText block;
DbusSignature signature;
block.AddComments(method.doc_string);
block.AddLine(StringPrintf("void %sAsync(", 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,",
chromeos::string_utils::Join(", ", out_params).c_str()));
block.AddLine(
"const base::Callback<void(chromeos::Error*)>& error_callback,");
block.AddLine("int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT) {");
block.PopOffset();
block.PushOffset(kBlockOffset);
block.AddLine("chromeos::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("}");
block.AddBlankLine();
text->AddBlock(block);
}
// 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(interfaces, text);
AddObjectRemoved(interfaces, text);
AddCreateProperties(interfaces, class_name, text);
AddDataMembers(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);
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().
text->AddLine(StringPrintf("%s* 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("}");
// GetInstances().
text->AddLine(StringPrintf("std::vector<%s*> Get%sInstances() const {",
itf_name.MakeProxyName(true).c_str(),
itf_name.type_name.c_str()));
text->PushOffset(kBlockOffset);
text->AddLine(StringPrintf("std::vector<%s*> 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(%s*)>& 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) {
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 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 (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 std::vector<Interface>& interfaces,
const std::string& class_name,
IndentedText* text) {
text->AddLine("scoped_refptr<dbus::Bus> bus_;");
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(%s*)> 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