/* * 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 #include #include #include #include #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 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 GetHeaders(bool is_nullable, const string& cpp_header) { vector 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 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 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>>", "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>>", "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", {"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", {"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& 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