blob: 2ac1523b73b87d549e1f5f487c2e6875f5652785 [file] [log] [blame]
/*
* Copyright (C) 2015, 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 "type_cpp.h"
#include <algorithm>
#include <iostream>
#include <vector>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include "logging.h"
using std::cerr;
using std::endl;
using std::set;
using std::string;
using std::unique_ptr;
using std::vector;
using android::base::Split;
using android::base::Join;
using android::base::StringPrintf;
namespace android {
namespace aidl {
namespace cpp {
namespace {
const char kNoPackage[] = "";
const char kNoHeader[] = "";
const char kNoValidMethod[] = "";
Type* const kNoArrayType = nullptr;
Type* const kNoNullableType = nullptr;
bool is_cpp_keyword(const std::string& str) {
static const std::vector<std::string> kCppKeywords{
"alignas", "alignof", "and", "and_eq", "asm", "auto", "bitand", "bitor",
"bool", "break", "case", "catch", "char", "char16_t", "char32_t", "class",
"compl", "concept", "const", "constexpr", "const_cast", "continue",
"decltype", "default", "delete", "do", "double", "dynamic_cast", "else",
"enum", "explicit", "export", "extern", "false", "float", "for", "friend",
"goto", "if", "inline", "int", "long", "mutable", "namespace", "new",
"noexcept", "not", "not_eq", "nullptr", "operator", "or", "or_eq",
"private", "protected", "public", "register", "reinterpret_cast",
"requires", "return", "short", "signed", "sizeof", "static",
"static_assert", "static_cast", "struct", "switch", "template", "this",
"thread_local", "throw", "true", "try", "typedef", "typeid", "typename",
"union", "unsigned", "using", "virtual", "void", "volatile", "wchar_t",
"while", "xor", "xor_eq",
};
return std::find(kCppKeywords.begin(), kCppKeywords.end(), str) !=
kCppKeywords.end();
}
class VoidType : public Type {
public:
VoidType() : Type(ValidatableType::KIND_BUILT_IN, kNoPackage, "void",
{}, "void", kNoValidMethod, kNoValidMethod) {}
virtual ~VoidType() = default;
bool CanBeOutParameter() const override { return false; }
bool CanWriteToParcel() const override { return false; }
}; // class VoidType
class CppArrayType : public Type {
public:
CppArrayType(int kind, // from ValidatableType
const std::string& package,
const string& underlying_aidl_type,
const string& cpp_header,
const string& underlying_cpp_type,
const string& read_method,
const string& write_method,
bool is_nullable,
const string& src_file_name = "")
: Type(kind, package,
underlying_aidl_type + "[]",
GetHeaders(is_nullable, cpp_header),
GetCppType(is_nullable, underlying_cpp_type),
read_method, write_method, kNoArrayType,
(is_nullable)
? kNoNullableType
// All arrays are nullable.
: new CppArrayType(kind, package, underlying_aidl_type,
cpp_header, underlying_cpp_type,
read_method, write_method, true),
src_file_name) {}
bool CanBeOutParameter() const override { return true; }
private:
static vector<string> GetHeaders(bool is_nullable, const string& cpp_header) {
vector<string> result = {"vector"};
if (is_nullable) {
result.push_back("memory");
}
if (!cpp_header.empty()) {
result.push_back(cpp_header);
}
return result;
}
static string GetCppType(bool is_nullable,
const string& underlying_cpp_type) {
if (is_nullable)
return StringPrintf("::std::unique_ptr<::std::vector<%s>>",
underlying_cpp_type.c_str());
return StringPrintf("::std::vector<%s>",
underlying_cpp_type.c_str());
}
DISALLOW_COPY_AND_ASSIGN(CppArrayType);
}; // class CppArrayType
class PrimitiveType : public Type {
public:
PrimitiveType(const std::string& aidl_type,
const std::string& header,
const std::string& cpp_type,
const std::string& read_method,
const std::string& write_method,
const std::string& read_array_method,
const std::string& write_array_method)
: Type(ValidatableType::KIND_BUILT_IN, kNoPackage, aidl_type, {header},
cpp_type, read_method, write_method,
new CppArrayType(ValidatableType::KIND_BUILT_IN, kNoPackage,
aidl_type, header, cpp_type,
read_array_method, write_array_method,
false)) {}
virtual ~PrimitiveType() = default;
bool IsCppPrimitive() const override { return true; }
private:
DISALLOW_COPY_AND_ASSIGN(PrimitiveType);
}; // class PrimitiveType
// Unfortunately, bytes in Java are signed. However, most C authors would
// say that a byte is not in fact signed. Compromise: customize this otherwise
// normal primitive to use signed single bytes, but unsigned byte arrays.
class ByteType : public Type {
public:
ByteType()
: Type(ValidatableType::KIND_BUILT_IN, kNoPackage, "byte",
{"cstdint"}, "int8_t", "readByte", "writeByte",
new CppArrayType(ValidatableType::KIND_BUILT_IN, kNoPackage,
"byte", "cstdint", "uint8_t",
"readByteVector", "writeByteVector",
false)) {}
virtual ~ByteType() = default;
bool IsCppPrimitive() const override { return true; }
private:
DISALLOW_COPY_AND_ASSIGN(ByteType);
}; // class PrimitiveType
class BinderType : public Type {
public:
BinderType(const AidlInterface& interface, const std::string& src_file_name)
: BinderType(interface, src_file_name,
new BinderType(interface, src_file_name, kNoNullableType,
"readNullableStrongBinder"),
"readStrongBinder") {}
virtual ~BinderType() = default;
string WriteCast(const string& val) const override {
return write_cast_ + "(" + val + ")";
}
private:
BinderType(const AidlInterface& interface,
const std::string& src_file_name,
Type* nullable_type, const std::string& read)
: Type(ValidatableType::KIND_GENERATED,
interface.GetPackage(), interface.GetName(),
{GetCppHeader(interface)}, GetCppName(interface),
read, "writeStrongBinder", kNoArrayType, nullable_type,
src_file_name, interface.GetLine()),
write_cast_(GetRawCppName(interface) + "::asBinder") {}
static string GetCppName(const AidlInterface& interface) {
return "::android::sp<" + GetRawCppName(interface) + ">";
}
static string GetRawCppName(const AidlInterface& interface) {
vector<string> name = interface.GetSplitPackage();
string ret;
name.push_back(interface.GetName());
for (const auto& term : name) {
ret += "::" + term;
}
return ret;
}
static string GetCppHeader(const AidlInterface& interface) {
vector<string> name = interface.GetSplitPackage();
name.push_back(interface.GetName());
return Join(name, '/') + ".h";
}
std::string write_cast_;
};
class NullableParcelableType : public Type {
public:
NullableParcelableType(const AidlParcelable& parcelable,
const std::string& src_file_name)
: Type(ValidatableType::KIND_PARCELABLE,
parcelable.GetPackage(), parcelable.GetName(),
{parcelable.GetCppHeader()}, GetCppName(parcelable),
"readParcelable", "writeNullableParcelable",
kNoArrayType, kNoNullableType,
src_file_name, parcelable.GetLine()) {}
virtual ~NullableParcelableType() = default;
bool CanBeOutParameter() const override { return true; }
private:
static string GetCppName(const AidlParcelable& parcelable) {
return "::std::unique_ptr<::" + Join(parcelable.GetSplitPackage(), "::") +
"::" + parcelable.GetCppName() + ">";
}
};
class ParcelableType : public Type {
public:
ParcelableType(const AidlParcelable& parcelable,
const std::string& src_file_name)
: Type(ValidatableType::KIND_PARCELABLE,
parcelable.GetPackage(), parcelable.GetName(),
{parcelable.GetCppHeader()}, GetCppName(parcelable),
"readParcelable", "writeParcelable",
new CppArrayType(
ValidatableType::KIND_PARCELABLE, parcelable.GetPackage(),
parcelable.GetName(), parcelable.GetCppHeader(),
GetCppName(parcelable),
"readParcelableVector", "writeParcelableVector", false,
src_file_name),
new NullableParcelableType(parcelable, src_file_name),
src_file_name, parcelable.GetLine()) {}
virtual ~ParcelableType() = default;
bool CanBeOutParameter() const override { return true; }
private:
static string GetCppName(const AidlParcelable& parcelable) {
return "::" + Join(parcelable.GetSplitPackage(), "::") +
"::" + parcelable.GetCppName();
}
};
class NullableMap : public Type {
public:
NullableMap()
: Type(ValidatableType::KIND_BUILT_IN,
"java.util", "Map",
{"binder/Map.h", "binder/Value.h"},
"::std::unique_ptr<::android::binder::Map>",
"readNullableMap", "writeNullableMap") {}
virtual ~NullableMap() = default;
bool CanBeOutParameter() const override { return true; }
};
class MapType : public Type {
public:
MapType()
: Type(ValidatableType::KIND_BUILT_IN,
"java.util", "Map",
{"binder/Map.h","binder/Value.h"},
"::android::binder::Map",
"readMap", "writeMap",
kNoArrayType,
new NullableMap() ) {}
virtual ~MapType() = default;
bool CanBeOutParameter() const override { return true; }
private:
DISALLOW_COPY_AND_ASSIGN(MapType);
}; // class MapType
class NullableStringListType : public Type {
public:
NullableStringListType()
: Type(ValidatableType::KIND_BUILT_IN,
"java.util", "List<" + string(kStringCanonicalName) + ">",
{"utils/String16.h", "memory", "vector"},
"::std::unique_ptr<::std::vector<std::unique_ptr<::android::String16>>>",
"readString16Vector", "writeString16Vector") {}
virtual ~NullableStringListType() = default;
bool CanBeOutParameter() const override { return true; }
private:
DISALLOW_COPY_AND_ASSIGN(NullableStringListType);
}; // class NullableStringListType
class StringListType : public Type {
public:
StringListType()
: Type(ValidatableType::KIND_BUILT_IN,
"java.util", "List<" + string(kStringCanonicalName) + ">",
{"utils/String16.h", "vector"},
"::std::vector<::android::String16>",
"readString16Vector", "writeString16Vector",
kNoArrayType, new NullableStringListType()) {}
virtual ~StringListType() = default;
bool CanBeOutParameter() const override { return true; }
private:
DISALLOW_COPY_AND_ASSIGN(StringListType);
}; // class StringListType
class NullableUtf8InCppStringListType : public Type {
public:
NullableUtf8InCppStringListType()
: Type(ValidatableType::KIND_BUILT_IN,
"java.util", "List<" + string(kUtf8InCppStringCanonicalName) + ">",
{"memory", "string", "vector"},
"::std::unique_ptr<::std::vector<std::unique_ptr<::std::string>>>",
"readUtf8VectorFromUtf16Vector", "writeUtf8VectorAsUtf16Vector") {}
virtual ~NullableUtf8InCppStringListType() = default;
bool CanBeOutParameter() const override { return true; }
private:
DISALLOW_COPY_AND_ASSIGN(NullableUtf8InCppStringListType);
}; // class NullableUtf8InCppStringListType
class Utf8InCppStringListType : public Type {
public:
Utf8InCppStringListType()
: Type(ValidatableType::KIND_BUILT_IN,
"java.util", "List<" + string(kUtf8InCppStringCanonicalName) + ">",
{"string", "vector"},
"::std::vector<::std::string>",
"readUtf8VectorFromUtf16Vector", "writeUtf8VectorAsUtf16Vector",
kNoArrayType, new NullableUtf8InCppStringListType()) {}
virtual ~Utf8InCppStringListType() = default;
bool CanBeOutParameter() const override { return true; }
private:
DISALLOW_COPY_AND_ASSIGN(Utf8InCppStringListType);
}; // class Utf8InCppStringListType
class NullableBinderListType : public Type {
public:
NullableBinderListType()
: Type(ValidatableType::KIND_BUILT_IN, "java.util",
"List<android.os.IBinder>", {"binder/IBinder.h", "vector"},
"::std::unique_ptr<::std::vector<::android::sp<::android::IBinder>>>",
"readStrongBinderVector", "writeStrongBinderVector") {}
virtual ~NullableBinderListType() = default;
bool CanBeOutParameter() const override { return true; }
private:
DISALLOW_COPY_AND_ASSIGN(NullableBinderListType);
}; // class NullableBinderListType
class BinderListType : public Type {
public:
BinderListType()
: Type(ValidatableType::KIND_BUILT_IN, "java.util",
"List<android.os.IBinder>", {"binder/IBinder.h", "vector"},
"::std::vector<::android::sp<::android::IBinder>>",
"readStrongBinderVector", "writeStrongBinderVector",
kNoArrayType, new NullableBinderListType()) {}
virtual ~BinderListType() = default;
bool CanBeOutParameter() const override { return true; }
private:
DISALLOW_COPY_AND_ASSIGN(BinderListType);
}; // class BinderListType
} // namespace
Type::Type(int kind,
const std::string& package,
const std::string& aidl_type,
const vector<string>& headers,
const string& cpp_type,
const string& read_method,
const string& write_method,
Type* array_type,
Type* nullable_type,
const string& src_file_name,
int line)
: ValidatableType(kind, package, aidl_type, src_file_name, line),
headers_(headers),
aidl_type_(aidl_type),
cpp_type_(cpp_type),
parcel_read_method_(read_method),
parcel_write_method_(write_method),
array_type_(array_type),
nullable_type_(nullable_type) {}
bool Type::CanWriteToParcel() const { return true; }
void TypeNamespace::Init() {
Add(new ByteType());
Add(new PrimitiveType(
"int",
"cstdint", "int32_t", "readInt32", "writeInt32",
"readInt32Vector", "writeInt32Vector"));
Add(new PrimitiveType(
"long",
"cstdint", "int64_t", "readInt64", "writeInt64",
"readInt64Vector", "writeInt64Vector"));
Add(new PrimitiveType(
"float",
kNoHeader, "float", "readFloat", "writeFloat",
"readFloatVector", "writeFloatVector"));
Add(new PrimitiveType(
"double",
kNoHeader, "double", "readDouble", "writeDouble",
"readDoubleVector", "writeDoubleVector"));
Add(new PrimitiveType(
"boolean",
kNoHeader, "bool", "readBool", "writeBool",
"readBoolVector", "writeBoolVector"));
// C++11 defines the char16_t type as a built in for Unicode characters.
Add(new PrimitiveType(
"char",
kNoHeader, "char16_t", "readChar", "writeChar",
"readCharVector", "writeCharVector"));
Type* string_array_type = new CppArrayType(
ValidatableType::KIND_BUILT_IN, "java.lang", "String",
"utils/String16.h", "::android::String16",
"readString16Vector", "writeString16Vector", false);
Type* nullable_string_type =
new Type(ValidatableType::KIND_BUILT_IN, "java.lang", "String",
{"memory", "utils/String16.h"}, "::std::unique_ptr<::android::String16>",
"readString16", "writeString16");
string_type_ = new Type(ValidatableType::KIND_BUILT_IN, "java.lang", "String",
{"utils/String16.h"}, "::android::String16",
"readString16", "writeString16",
string_array_type, nullable_string_type);
Add(string_type_);
using ::android::aidl::kAidlReservedTypePackage;
using ::android::aidl::kUtf8InCppStringClass;
// This type is a Utf16 string in the parcel, but deserializes to
// a std::string in Utf8 format when we use it in C++.
Type* cpp_utf8_string_array = new CppArrayType(
ValidatableType::KIND_BUILT_IN,
kAidlReservedTypePackage, kUtf8InCppStringClass,
"string", "::std::string",
"readUtf8VectorFromUtf16Vector", "writeUtf8VectorAsUtf16Vector",
false);
Type* nullable_cpp_utf8_string_type = new Type(
ValidatableType::KIND_BUILT_IN,
kAidlReservedTypePackage, kUtf8InCppStringClass,
{"string", "memory"}, "::std::unique_ptr<::std::string>",
"readUtf8FromUtf16", "writeUtf8AsUtf16");
Add(new Type(
ValidatableType::KIND_BUILT_IN,
kAidlReservedTypePackage, kUtf8InCppStringClass,
{"string"}, "::std::string", "readUtf8FromUtf16", "writeUtf8AsUtf16",
cpp_utf8_string_array, nullable_cpp_utf8_string_type));
Type* nullable_ibinder = new Type(
ValidatableType::KIND_BUILT_IN, "android.os", "IBinder",
{"binder/IBinder.h"}, "::android::sp<::android::IBinder>",
"readNullableStrongBinder", "writeStrongBinder");
ibinder_type_ = new Type(
ValidatableType::KIND_BUILT_IN, "android.os", "IBinder",
{"binder/IBinder.h"}, "::android::sp<::android::IBinder>",
"readStrongBinder", "writeStrongBinder",
kNoArrayType, nullable_ibinder);
Add(ibinder_type_);
Add(new MapType());
Add(new BinderListType());
Add(new StringListType());
Add(new Utf8InCppStringListType());
Type* fd_vector_type = new CppArrayType(
ValidatableType::KIND_BUILT_IN, kNoPackage, "FileDescriptor",
"android-base/unique_fd.h",
"::android::base::unique_fd",
"readUniqueFileDescriptorVector", "writeUniqueFileDescriptorVector",
false);
Add(new Type(
ValidatableType::KIND_BUILT_IN, kNoPackage, "FileDescriptor",
{"android-base/unique_fd.h"}, "::android::base::unique_fd",
"readUniqueFileDescriptor", "writeUniqueFileDescriptor",
fd_vector_type));
void_type_ = new class VoidType();
Add(void_type_);
}
bool TypeNamespace::AddParcelableType(const AidlParcelable& p,
const string& filename) {
if (p.GetCppHeader().empty()) {
LOG(ERROR) << "Parcelable " << p.GetCanonicalName()
<< " has no C++ header defined.";
return false;
}
Add(new ParcelableType(p, filename));
return true;
}
bool TypeNamespace::AddBinderType(const AidlInterface& b,
const string& file_name) {
Add(new BinderType(b, file_name));
return true;
}
bool TypeNamespace::AddListType(const std::string& type_name) {
const Type* contained_type = FindTypeByCanonicalName(type_name);
if (!contained_type) {
LOG(ERROR) << "Cannot create List<" << type_name << "> because contained "
"type cannot be found or is invalid.";
return false;
}
if (contained_type->IsCppPrimitive()) {
LOG(ERROR) << "Cannot create List<" << type_name << "> because contained "
"type is a primitive in Java and Java List cannot hold "
"primitives.";
return false;
}
if (contained_type->CanonicalName() == kStringCanonicalName ||
contained_type->CanonicalName() == kUtf8InCppStringCanonicalName ||
contained_type == IBinderType()) {
return true;
}
// TODO Support lists of parcelables b/23600712
LOG(ERROR) << "aidl-cpp does not yet support List<" << type_name << ">";
return false;
}
bool TypeNamespace::AddMapType(const std::string& /* key_type_name */,
const std::string& /* value_type_name */) {
// TODO Support list types b/25242025
LOG(ERROR) << "aidl does not implement support for typed maps!";
return false;
}
bool TypeNamespace::IsValidPackage(const string& package) const {
if (package.empty()) {
return false;
}
auto pieces = Split(package, ".");
for (const string& piece : pieces) {
if (is_cpp_keyword(piece)) {
return false;
}
}
return true;
}
const ValidatableType* TypeNamespace::GetArgType(const AidlArgument& a,
int arg_index,
const std::string& filename,
const AidlInterface& interface) const {
const string error_prefix = StringPrintf(
"In file %s line %d parameter %s (%d):\n ",
filename.c_str(), a.GetLine(), a.GetName().c_str(), arg_index);
// check that the name doesn't match a keyword
if (is_cpp_keyword(a.GetName().c_str())) {
cerr << error_prefix << "Argument name is a C++ keyword"
<< endl;
return nullptr;
}
return ::android::aidl::TypeNamespace::GetArgType(a, arg_index, filename,
interface);
}
} // namespace cpp
} // namespace aidl
} // namespace android