You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
365 lines
12 KiB
365 lines
12 KiB
/*
|
|
* Copyright (C) 2018, The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "aidl_to_cpp.h"
|
|
#include "aidl_to_cpp_common.h"
|
|
#include "aidl_language.h"
|
|
#include "logging.h"
|
|
|
|
#include <android-base/stringprintf.h>
|
|
#include <android-base/strings.h>
|
|
|
|
#include <functional>
|
|
#include <unordered_map>
|
|
|
|
using android::base::Join;
|
|
using android::base::Split;
|
|
using android::base::StringPrintf;
|
|
using std::ostringstream;
|
|
|
|
namespace android {
|
|
namespace aidl {
|
|
namespace cpp {
|
|
|
|
namespace {
|
|
std::string RawParcelMethod(const AidlTypeSpecifier& type, const AidlTypenames& typenames,
|
|
bool readMethod) {
|
|
static map<string, string> kBuiltin = {
|
|
{"byte", "Byte"},
|
|
{"boolean", "Bool"},
|
|
{"char", "Char"},
|
|
{"double", "Double"},
|
|
{"FileDescriptor", "UniqueFileDescriptor"},
|
|
{"float", "Float"},
|
|
{"IBinder", "StrongBinder"},
|
|
{"int", "Int32"},
|
|
{"long", "Int64"},
|
|
{"ParcelFileDescriptor", "Parcelable"},
|
|
{"String", "String16"},
|
|
{"ParcelableHolder", "Parcelable"},
|
|
};
|
|
|
|
static map<string, string> kBuiltinVector = {
|
|
{"FileDescriptor", "UniqueFileDescriptorVector"},
|
|
{"double", "DoubleVector"},
|
|
{"char", "CharVector"},
|
|
{"boolean", "BoolVector"},
|
|
{"byte", "ByteVector"},
|
|
{"float", "FloatVector"},
|
|
{"IBinder", "StrongBinderVector"},
|
|
{"String", "String16Vector"},
|
|
{"int", "Int32Vector"},
|
|
{"long", "Int64Vector"},
|
|
{"ParcelFileDescriptor", "ParcelableVector"},
|
|
};
|
|
|
|
const bool nullable = type.IsNullable();
|
|
const bool isVector = type.IsArray() || typenames.IsList(type);
|
|
const bool utf8 = type.IsUtf8InCpp();
|
|
|
|
if (auto enum_decl = typenames.GetEnumDeclaration(type); enum_decl != nullptr) {
|
|
if (isVector) {
|
|
return "EnumVector";
|
|
} else {
|
|
return RawParcelMethod(enum_decl->GetBackingType(), typenames, readMethod);
|
|
}
|
|
}
|
|
|
|
if (isVector) {
|
|
string element_name;
|
|
if (typenames.IsList(type)) {
|
|
AIDL_FATAL_IF(type.GetTypeParameters().size() != 1, type);
|
|
element_name = type.GetTypeParameters().at(0)->GetName();
|
|
} else {
|
|
element_name = type.GetName();
|
|
}
|
|
if (kBuiltinVector.find(element_name) != kBuiltinVector.end()) {
|
|
AIDL_FATAL_IF(!AidlTypenames::IsBuiltinTypename(element_name), type);
|
|
if (utf8) {
|
|
AIDL_FATAL_IF(element_name != "String", type);
|
|
return readMethod ? "Utf8VectorFromUtf16Vector" : "Utf8VectorAsUtf16Vector";
|
|
}
|
|
return kBuiltinVector[element_name];
|
|
}
|
|
auto definedType = typenames.TryGetDefinedType(element_name);
|
|
if (definedType != nullptr && definedType->AsInterface() != nullptr) {
|
|
return "StrongBinderVector";
|
|
}
|
|
return "ParcelableVector";
|
|
}
|
|
|
|
const string& type_name = type.GetName();
|
|
if (kBuiltin.find(type_name) != kBuiltin.end()) {
|
|
AIDL_FATAL_IF(!AidlTypenames::IsBuiltinTypename(type_name), type);
|
|
if (type_name == "IBinder" && nullable && readMethod) {
|
|
return "NullableStrongBinder";
|
|
}
|
|
if (type_name == "ParcelFileDescriptor" && nullable && !readMethod) {
|
|
return "NullableParcelable";
|
|
}
|
|
if (utf8) {
|
|
AIDL_FATAL_IF(type_name != "String", type);
|
|
return readMethod ? "Utf8FromUtf16" : "Utf8AsUtf16";
|
|
}
|
|
return kBuiltin[type_name];
|
|
}
|
|
|
|
AIDL_FATAL_IF(AidlTypenames::IsBuiltinTypename(type.GetName()), type);
|
|
auto definedType = typenames.TryGetDefinedType(type.GetName());
|
|
// The type must be either primitive or interface or parcelable,
|
|
// so it cannot be nullptr.
|
|
AIDL_FATAL_IF(definedType == nullptr, type) << type.GetName() << " is not found.";
|
|
|
|
if (definedType->AsInterface() != nullptr) {
|
|
if (nullable && readMethod) {
|
|
return "NullableStrongBinder";
|
|
}
|
|
return "StrongBinder";
|
|
}
|
|
|
|
// Parcelable
|
|
if (nullable && !readMethod) {
|
|
return "NullableParcelable";
|
|
}
|
|
return "Parcelable";
|
|
}
|
|
|
|
std::string GetRawCppName(const AidlTypeSpecifier& type) {
|
|
return "::" + Join(type.GetSplitName(), "::");
|
|
}
|
|
|
|
std::string WrapIfNullable(const std::string type_str, const AidlTypeSpecifier& raw_type,
|
|
const AidlTypenames& typenames) {
|
|
const auto& type = typenames.IsList(raw_type) ? (*raw_type.GetTypeParameters().at(0)) : raw_type;
|
|
|
|
if (raw_type.IsNullable() && !AidlTypenames::IsPrimitiveTypename(type.GetName()) &&
|
|
type.GetName() != "IBinder" && typenames.GetEnumDeclaration(type) == nullptr) {
|
|
return "::std::optional<" + type_str + ">";
|
|
}
|
|
return type_str;
|
|
}
|
|
|
|
std::string GetCppName(const AidlTypeSpecifier& raw_type, const AidlTypenames& typenames) {
|
|
// map from AIDL built-in type name to the corresponding Cpp type name
|
|
static map<string, string> m = {
|
|
{"boolean", "bool"},
|
|
{"byte", "int8_t"},
|
|
{"char", "char16_t"},
|
|
{"double", "double"},
|
|
{"FileDescriptor", "::android::base::unique_fd"},
|
|
{"float", "float"},
|
|
{"IBinder", "::android::sp<::android::IBinder>"},
|
|
{"int", "int32_t"},
|
|
{"long", "int64_t"},
|
|
{"ParcelFileDescriptor", "::android::os::ParcelFileDescriptor"},
|
|
{"String", "::android::String16"},
|
|
{"void", "void"},
|
|
{"ParcelableHolder", "::android::os::ParcelableHolder"},
|
|
};
|
|
AIDL_FATAL_IF(typenames.IsList(raw_type) && raw_type.GetTypeParameters().size() != 1, raw_type);
|
|
const auto& type = typenames.IsList(raw_type) ? (*raw_type.GetTypeParameters().at(0)) : raw_type;
|
|
const string& aidl_name = type.GetName();
|
|
if (m.find(aidl_name) != m.end()) {
|
|
AIDL_FATAL_IF(!AidlTypenames::IsBuiltinTypename(aidl_name), raw_type);
|
|
if (aidl_name == "byte" && type.IsArray()) {
|
|
return "uint8_t";
|
|
} else if (raw_type.IsUtf8InCpp()) {
|
|
AIDL_FATAL_IF(aidl_name != "String", type);
|
|
return WrapIfNullable("::std::string", raw_type, typenames);
|
|
}
|
|
return WrapIfNullable(m[aidl_name], raw_type, typenames);
|
|
}
|
|
auto definedType = typenames.TryGetDefinedType(type.GetName());
|
|
if (definedType != nullptr && definedType->AsInterface() != nullptr) {
|
|
return "::android::sp<" + GetRawCppName(type) + ">";
|
|
}
|
|
|
|
return WrapIfNullable(GetRawCppName(type), raw_type, typenames);
|
|
}
|
|
} // namespace
|
|
std::string ConstantValueDecorator(const AidlTypeSpecifier& type, const std::string& raw_value) {
|
|
if (type.IsArray()) {
|
|
return raw_value;
|
|
}
|
|
|
|
if (type.GetName() == "long") {
|
|
return raw_value + "L";
|
|
}
|
|
|
|
if (type.GetName() == "String" && !type.IsUtf8InCpp()) {
|
|
return "::android::String16(" + raw_value + ")";
|
|
}
|
|
|
|
if (auto defined_type = type.GetDefinedType(); defined_type) {
|
|
auto enum_type = defined_type->AsEnumDeclaration();
|
|
AIDL_FATAL_IF(!enum_type, type) << "Invalid type for \"" << raw_value << "\"";
|
|
return GetRawCppName(type) + "::" + raw_value.substr(raw_value.find_last_of('.') + 1);
|
|
}
|
|
|
|
return raw_value;
|
|
};
|
|
|
|
std::string GetTransactionIdFor(const AidlInterface& iface, const AidlMethod& method) {
|
|
return ClassName(iface, ClassNames::SERVER) + "::TRANSACTION_" + method.GetName();
|
|
}
|
|
|
|
std::string CppNameOf(const AidlTypeSpecifier& type, const AidlTypenames& typenames) {
|
|
if (type.IsArray() || typenames.IsList(type)) {
|
|
std::string cpp_name = GetCppName(type, typenames);
|
|
if (type.IsNullable()) {
|
|
return "::std::optional<::std::vector<" + cpp_name + ">>";
|
|
}
|
|
return "::std::vector<" + cpp_name + ">";
|
|
} else if (type.IsGeneric()) {
|
|
std::vector<std::string> type_params;
|
|
for (const auto& parameter : type.GetTypeParameters()) {
|
|
type_params.push_back(CppNameOf(*parameter, typenames));
|
|
}
|
|
return StringPrintf("%s<%s>", GetCppName(type, typenames).c_str(),
|
|
base::Join(type_params, ", ").c_str());
|
|
}
|
|
return GetCppName(type, typenames);
|
|
}
|
|
|
|
bool IsNonCopyableType(const AidlTypeSpecifier& type, const AidlTypenames& typenames) {
|
|
if (type.IsArray() || typenames.IsList(type)) {
|
|
return false;
|
|
}
|
|
|
|
const std::string cpp_name = GetCppName(type, typenames);
|
|
if (cpp_name == "::android::base::unique_fd") {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
std::string ParcelReadMethodOf(const AidlTypeSpecifier& type, const AidlTypenames& typenames) {
|
|
return "read" + RawParcelMethod(type, typenames, true /* readMethod */);
|
|
}
|
|
|
|
std::string ParcelReadCastOf(const AidlTypeSpecifier& type, const AidlTypenames& typenames,
|
|
const std::string& variable_name) {
|
|
if (auto enum_decl = typenames.GetEnumDeclaration(type);
|
|
enum_decl != nullptr && !type.IsArray()) {
|
|
return StringPrintf("reinterpret_cast<%s *>(%s)",
|
|
CppNameOf(enum_decl->GetBackingType(), typenames).c_str(),
|
|
variable_name.c_str());
|
|
}
|
|
|
|
return variable_name;
|
|
}
|
|
|
|
std::string ParcelWriteMethodOf(const AidlTypeSpecifier& type, const AidlTypenames& typenames) {
|
|
return "write" + RawParcelMethod(type, typenames, false /* readMethod */);
|
|
}
|
|
|
|
std::string ParcelWriteCastOf(const AidlTypeSpecifier& type, const AidlTypenames& typenames,
|
|
const std::string& variable_name) {
|
|
if (auto enum_decl = typenames.GetEnumDeclaration(type);
|
|
enum_decl != nullptr && !type.IsArray()) {
|
|
return StringPrintf("static_cast<%s>(%s)",
|
|
CppNameOf(enum_decl->GetBackingType(), typenames).c_str(),
|
|
variable_name.c_str());
|
|
}
|
|
|
|
if (typenames.GetInterface(type) != nullptr) {
|
|
return GetRawCppName(type) + "::asBinder(" + variable_name + ")";
|
|
}
|
|
|
|
return variable_name;
|
|
}
|
|
|
|
void AddHeaders(const AidlTypeSpecifier& type, const AidlTypenames& typenames,
|
|
std::set<std::string>* headers) {
|
|
AIDL_FATAL_IF(typenames.IsList(type) && type.GetTypeParameters().size() != 1, type);
|
|
bool isVector = type.IsArray() || typenames.IsList(type);
|
|
bool isNullable = type.IsNullable();
|
|
bool utf8 = type.IsUtf8InCpp();
|
|
|
|
if (isVector) {
|
|
headers->insert("vector");
|
|
}
|
|
if (type.IsGeneric()) {
|
|
for (const auto& parameter : type.GetTypeParameters()) {
|
|
AddHeaders(*parameter, typenames, headers);
|
|
}
|
|
}
|
|
if (isNullable) {
|
|
if (type.GetName() != "IBinder") {
|
|
headers->insert("optional");
|
|
}
|
|
}
|
|
if (typenames.IsList(type)) {
|
|
// Nothing else to do for List.
|
|
return;
|
|
}
|
|
if (type.GetName() == "String") {
|
|
headers->insert(utf8 ? "string" : "utils/String16.h");
|
|
return;
|
|
}
|
|
if (type.GetName() == "IBinder") {
|
|
headers->insert("binder/IBinder.h");
|
|
return;
|
|
}
|
|
if (type.GetName() == "FileDescriptor") {
|
|
headers->insert("android-base/unique_fd.h");
|
|
return;
|
|
}
|
|
if (type.GetName() == "ParcelFileDescriptor") {
|
|
headers->insert("binder/ParcelFileDescriptor.h");
|
|
return;
|
|
}
|
|
if (type.GetName() == "ParcelableHolder") {
|
|
headers->insert("binder/ParcelableHolder.h");
|
|
return;
|
|
}
|
|
|
|
static const std::set<string> need_cstdint{"byte", "int", "long"};
|
|
if (need_cstdint.find(type.GetName()) != need_cstdint.end()) {
|
|
headers->insert("cstdint");
|
|
return;
|
|
}
|
|
|
|
if (AidlTypenames::IsPrimitiveTypename(type.GetName())) {
|
|
return;
|
|
}
|
|
|
|
auto definedType = typenames.TryGetDefinedType(type.GetName());
|
|
AIDL_FATAL_IF(definedType == nullptr, type) << "Unexpected type: " << type.GetName();
|
|
|
|
if (definedType->AsInterface() != nullptr || definedType->AsStructuredParcelable() != nullptr ||
|
|
definedType->AsEnumDeclaration() != nullptr || definedType->AsUnionDeclaration() != nullptr) {
|
|
AddHeaders(*definedType, headers);
|
|
} else if (definedType->AsParcelable() != nullptr) {
|
|
const std::string cpp_header = definedType->AsParcelable()->GetCppHeader();
|
|
AIDL_FATAL_IF(cpp_header.empty(), definedType->AsParcelable())
|
|
<< "Parcelable " << definedType->AsParcelable()->GetCanonicalName()
|
|
<< " has no C++ header defined.";
|
|
headers->insert(cpp_header);
|
|
}
|
|
}
|
|
|
|
void AddHeaders(const AidlDefinedType& definedType, std::set<std::string>* headers) {
|
|
vector<string> name = definedType.GetSplitPackage();
|
|
name.push_back(definedType.GetName());
|
|
const std::string cpp_header = Join(name, '/') + ".h";
|
|
headers->insert(cpp_header);
|
|
}
|
|
|
|
} // namespace cpp
|
|
} // namespace aidl
|
|
} // namespace android
|