C++程序  |  603行  |  21.43 KB

/*
 * 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& underlying_cpp_type_nulllable,
            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_nulllable,
                                    underlying_cpp_type_nulllable,
                                    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, 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", "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), 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",
      "::std::unique_ptr<::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", "::std::unique_ptr<::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", "::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