blob: ef1cc0f51f08c724799869ecef989bd685e812e2 [file] [log] [blame]
/*
* 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_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& raw_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"},
};
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 = raw_type.IsNullable();
const bool isVector =
raw_type.IsArray() || (raw_type.IsGeneric() && raw_type.GetName() == "List");
const bool utf8 = raw_type.IsUtf8InCpp();
const auto& type = raw_type.IsGeneric() ? *raw_type.GetTypeParameters().at(0) : raw_type;
const string& aidl_name = type.GetName();
if (isVector) {
if (kBuiltinVector.find(aidl_name) != kBuiltinVector.end()) {
CHECK(AidlTypenames::IsBuiltinTypename(aidl_name));
if (utf8) {
CHECK(aidl_name == "String");
return readMethod ? "Utf8VectorFromUtf16Vector" : "Utf8VectorAsUtf16Vector";
}
return kBuiltinVector[aidl_name];
}
} else {
if (kBuiltin.find(aidl_name) != kBuiltin.end()) {
CHECK(AidlTypenames::IsBuiltinTypename(aidl_name));
if (aidl_name == "IBinder" && nullable && readMethod) {
return "NullableStrongBinder";
}
if (aidl_name == "ParcelFileDescriptor" && nullable && !readMethod) {
return "NullableParcelable";
}
if (utf8) {
CHECK(aidl_name == "String");
return readMethod ? "Utf8FromUtf16" : "Utf8AsUtf16";
}
return kBuiltin[aidl_name];
}
}
CHECK(!AidlTypenames::IsBuiltinTypename(aidl_name));
auto definedType = typenames.TryGetDefinedType(type.GetName());
if (definedType != nullptr && definedType->AsInterface() != nullptr) {
if (isVector) {
return "StrongBinderVector";
}
if (nullable && readMethod) {
return "NullableStrongBinder";
}
return "StrongBinder";
}
// The type must be either primitive or interface or parcelable,
// so it cannot be nullptr.
CHECK(definedType != nullptr) << type.GetName() << " is not found.";
// Parcelable
if (isVector) {
return "ParcelableVector";
}
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 auto& type = raw_type.IsGeneric() ? (*raw_type.GetTypeParameters().at(0)) : raw_type;
if (raw_type.IsNullable() && !AidlTypenames::IsPrimitiveTypename(type.GetName()) &&
type.GetName() != "IBinder") {
return "::std::unique_ptr<" + 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"},
};
CHECK(!raw_type.IsGeneric() ||
(raw_type.GetName() == "List" && raw_type.GetTypeParameters().size() == 1));
const auto& type = raw_type.IsGeneric() ? (*raw_type.GetTypeParameters().at(0)) : raw_type;
const string& aidl_name = type.GetName();
if (m.find(aidl_name) != m.end()) {
CHECK(AidlTypenames::IsBuiltinTypename(aidl_name));
if (aidl_name == "byte" && type.IsArray()) {
return "uint8_t";
} else if (raw_type.IsUtf8InCpp()) {
CHECK(aidl_name == "String");
return WrapIfNullable("::std::string", raw_type);
}
return WrapIfNullable(m[aidl_name], raw_type);
}
auto definedType = typenames.TryGetDefinedType(type.GetName());
if (definedType != nullptr && definedType->AsInterface() != nullptr) {
return "::android::sp<" + GetRawCppName(type) + ">";
}
return WrapIfNullable(GetRawCppName(type), raw_type);
}
} // namespace
std::string ConstantValueDecorator(const AidlTypeSpecifier& type, const std::string& raw_value) {
if (type.GetName() == "long") {
return raw_value + "L";
}
if (type.GetName() == "String" && !type.IsArray() && !type.IsUtf8InCpp()) {
return "::android::String16(" + raw_value + ")";
}
return raw_value;
};
std::string GetTransactionIdFor(const AidlMethod& method) {
ostringstream output;
output << "::android::IBinder::FIRST_CALL_TRANSACTION + ";
output << method.GetId() << " /* " << method.GetName() << " */";
return output.str();
}
std::string CppNameOf(const AidlTypeSpecifier& type, const AidlTypenames& typenames) {
if (type.IsArray() || type.IsGeneric()) {
std::string cpp_name = GetCppName(type, typenames);
if (type.IsNullable()) {
return "::std::unique_ptr<::std::vector<" + cpp_name + ">>";
}
return "::std::vector<" + cpp_name + ">";
}
return GetCppName(type, typenames);
}
std::string ParcelReadMethodOf(const AidlTypeSpecifier& type, const AidlTypenames& typenames) {
if (auto enum_decl = typenames.GetEnumDeclaration(type); enum_decl != nullptr) {
return ParcelReadMethodOf(enum_decl->GetBackingType(), 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) {
return StringPrintf("(%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) {
if (auto enum_decl = typenames.GetEnumDeclaration(type); enum_decl != nullptr) {
return ParcelWriteMethodOf(enum_decl->GetBackingType(), 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) {
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& raw_type, const AidlTypenames& typenames,
std::set<std::string>& headers) {
bool isVector = raw_type.IsArray() || raw_type.IsGeneric();
bool isNullable = raw_type.IsNullable();
bool utf8 = raw_type.IsUtf8InCpp();
CHECK(!raw_type.IsGeneric() ||
(raw_type.GetName() == "List" && raw_type.GetTypeParameters().size() == 1));
const auto& type = raw_type.IsGeneric() ? *raw_type.GetTypeParameters().at(0) : raw_type;
auto definedType = typenames.TryGetDefinedType(type.GetName());
if (isVector) {
headers.insert("vector");
}
if (isNullable) {
if (type.GetName() != "IBinder") {
headers.insert("memory");
}
}
if (type.GetName() == "String") {
headers.insert(utf8 ? "string" : "utils/String16.h");
}
if (type.GetName() == "IBinder") {
headers.insert("binder/IBinder.h");
}
if (type.GetName() == "FileDescriptor") {
headers.insert("android-base/unique_fd.h");
}
if (type.GetName() == "ParcelFileDescriptor") {
headers.insert("binder/ParcelFileDescriptor.h");
}
static const std::set<string> need_cstdint{"byte", "int", "long"};
if (need_cstdint.find(type.GetName()) != need_cstdint.end()) {
headers.insert("cstdint");
}
if (definedType == nullptr) {
return;
}
if (definedType->AsInterface() != nullptr || definedType->AsStructuredParcelable() != nullptr ||
definedType->AsEnumDeclaration() != 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