Initial commit of Java backend to hidl-gen.
Change-Id: I38b62637df74d3e5daf702a8996502d0d5726033
diff --git a/AST.h b/AST.h
index 026d90b..65dd016 100644
--- a/AST.h
+++ b/AST.h
@@ -54,6 +54,7 @@
Type *lookupTypeInternal(const std::string &namePath) const;
status_t generateCpp(const std::string &outputPath) const;
+ status_t generateJava(const std::string &outputPath) const;
void getImportedPackages(std::set<FQName> *importSet) const;
@@ -101,7 +102,14 @@
bool isReader,
Type::ErrorMode mode) const;
+ void emitJavaReaderWriter(
+ Formatter &out,
+ const std::string &parcelObj,
+ const TypedVar *arg,
+ bool isReader) const;
+
status_t emitTypeDeclarations(Formatter &out) const;
+ status_t emitJavaTypeDeclarations(Formatter &out) const;
DISALLOW_COPY_AND_ASSIGN(AST);
};
diff --git a/Android.mk b/Android.mk
index a0496eb..8ecfa50 100644
--- a/Android.mk
+++ b/Android.mk
@@ -15,6 +15,7 @@
Formatter.cpp \
FQName.cpp \
generateCpp.cpp \
+ generateJava.cpp \
HandleType.cpp \
hidl-gen_y.yy \
hidl-gen_l.ll \
diff --git a/ArrayType.cpp b/ArrayType.cpp
index 732f2e6..3679429 100644
--- a/ArrayType.cpp
+++ b/ArrayType.cpp
@@ -33,6 +33,10 @@
}
}
+std::string ArrayType::getJavaType() const {
+ return mElementType->getJavaType() + "[]";
+}
+
void ArrayType::emitReaderWriter(
Formatter &out,
const std::string &name,
@@ -142,5 +146,19 @@
return mElementType->needsEmbeddedReadWrite();
}
+void ArrayType::emitJavaReaderWriter(
+ Formatter &out,
+ const std::string &parcelObj,
+ const std::string &argName,
+ bool isReader) const {
+ emitJavaReaderWriterWithSuffix(
+ out,
+ parcelObj,
+ argName,
+ isReader,
+ mElementType->getJavaSuffix() + "Array",
+ mDimension);
+}
+
} // namespace android
diff --git a/ArrayType.h b/ArrayType.h
index c95204b..0a245f8 100644
--- a/ArrayType.h
+++ b/ArrayType.h
@@ -13,6 +13,8 @@
std::string getCppType(StorageMode mode, std::string *extra) const override;
+ std::string getJavaType() const override;
+
void emitReaderWriter(
Formatter &out,
const std::string &name,
@@ -34,6 +36,12 @@
bool needsEmbeddedReadWrite() const override;
+ void emitJavaReaderWriter(
+ Formatter &out,
+ const std::string &parcelObj,
+ const std::string &argName,
+ bool isReader) const override;
+
private:
Type *mElementType;
std::string mDimension;
diff --git a/EnumType.cpp b/EnumType.cpp
index 95cb6be..2c6f729 100644
--- a/EnumType.cpp
+++ b/EnumType.cpp
@@ -38,6 +38,14 @@
return fullName();
}
+std::string EnumType::getJavaType() const {
+ return mStorageType->resolveToScalarType()->getJavaType();
+}
+
+std::string EnumType::getJavaSuffix() const {
+ return mStorageType->resolveToScalarType()->getJavaSuffix();
+}
+
void EnumType::emitReaderWriter(
Formatter &out,
const std::string &name,
@@ -106,6 +114,94 @@
return OK;
}
+// Attempt to convert enum value literals into their signed equivalents,
+// i.e. if an enum value is stored in typeName 'byte', the value "192"
+// will be converted to the output "-64".
+static bool MakeSignedIntegerValue(
+ const std::string &typeName, const char *value, std::string *output) {
+ output->clear();
+
+ char *end;
+ long long x = strtoll(value, &end, 10);
+
+ if (end > value && *end == '\0' && errno != ERANGE) {
+ char out[32];
+ if (typeName == "byte") {
+ sprintf(out, "%d", (int)(int8_t)x);
+ } else if (typeName == "short") {
+ sprintf(out, "%d", (int)(int16_t)x);
+ } else if (typeName == "int") {
+ sprintf(out, "%d", (int)(int32_t)x);
+ } else {
+ assert(typeName == "long");
+ sprintf(out, "%lldL", (int64_t)x);
+ }
+
+ *output = out;
+ return true;
+ }
+
+ return false;
+}
+
+status_t EnumType::emitJavaTypeDeclarations(Formatter &out) const {
+ const ScalarType *scalarType = mStorageType->resolveToScalarType();
+ CHECK(scalarType != NULL);
+
+ out << "public final class "
+ << localName()
+ << " {\n";
+
+ out.indent();
+
+ const std::string typeName = scalarType->getJavaType();
+
+ std::vector<const EnumType *> chain;
+ const EnumType *type = this;
+ for (;;) {
+ chain.push_back(type);
+
+ const Type *superType = type->storageType();
+ if (superType == NULL || !superType->isEnum()) {
+ break;
+ }
+
+ type = static_cast<const EnumType *>(superType);
+ }
+
+ for (auto it = chain.rbegin(); it != chain.rend(); ++it) {
+ const auto &type = *it;
+
+ for (const auto &entry : type->values()) {
+ out << "public static final "
+ << typeName
+ << " "
+ << entry->name();
+
+ const char *value = entry->value();
+ if (value != NULL) {
+ out << " = ";
+
+ std::string convertedValue;
+ if (MakeSignedIntegerValue(typeName, value, &convertedValue)) {
+ out << convertedValue;
+ } else {
+ // The value is not an integer, but some other string,
+ // hopefully referring to some other enum name.
+ out << value;
+ }
+ }
+
+ out << ";\n";
+ }
+ }
+
+ out.unindent();
+ out << "};\n\n";
+
+ return OK;
+}
+
////////////////////////////////////////////////////////////////////////////////
EnumValue::EnumValue(const char *name, const char *value)
diff --git a/EnumType.h b/EnumType.h
index 939cd3b..6453166 100644
--- a/EnumType.h
+++ b/EnumType.h
@@ -23,6 +23,9 @@
std::string getCppType(StorageMode mode, std::string *extra) const override;
+ std::string getJavaType() const override;
+ std::string getJavaSuffix() const override;
+
void emitReaderWriter(
Formatter &out,
const std::string &name,
@@ -32,6 +35,7 @@
ErrorMode mode) const override;
status_t emitTypeDeclarations(Formatter &out) const override;
+ status_t emitJavaTypeDeclarations(Formatter &out) const override;
private:
std::vector<EnumValue *> *mValues;
diff --git a/FQName.cpp b/FQName.cpp
index 45e3ad4..dc35f70 100644
--- a/FQName.cpp
+++ b/FQName.cpp
@@ -186,6 +186,17 @@
return out;
}
+std::string FQName::javaPackage() const {
+ std::vector<std::string> components;
+ getPackageAndVersionComponents(&components, true /* cpp_compatible */);
+
+ return JoinStrings(components, ".");
+}
+
+std::string FQName::javaName() const {
+ return javaPackage() + "." + name();
+}
+
void FQName::getPackageComponents(std::vector<std::string> *components) const {
SplitString(package(), '.', components);
}
diff --git a/FQName.h b/FQName.h
index 02c03bd..ae7fe80 100644
--- a/FQName.h
+++ b/FQName.h
@@ -36,13 +36,20 @@
bool operator==(const FQName &other) const;
// Returns an absolute C++ namespace prefix, i.e.
- // ::android::hardware::Foo.
+ // ::android::hardware::Foo::V1_0.
std::string cppNamespace() const;
// Returns a fully qualified absolute C++ type name, i.e.
- // ::android::hardware::Foo::bar::baz.
+ // ::android::hardware::Foo::V1_0::bar::baz.
std::string cppName() const;
+ // Returns the java package name, i.e. "android.hardware.Foo.V1_0".
+ std::string javaPackage() const;
+
+ // Returns the fully qualified java type name,
+ // i.e. "android.hardware.Foo.V1_0.IBar"
+ std::string javaName() const;
+
void getPackageComponents(std::vector<std::string> *components) const;
void getPackageAndVersionComponents(
diff --git a/Formatter.cpp b/Formatter.cpp
index c07b9df..060513c 100644
--- a/Formatter.cpp
+++ b/Formatter.cpp
@@ -69,13 +69,6 @@
void Formatter::setNamespace(const std::string &space) {
mSpace = space;
- if (!mSpace.empty()) {
- // The intent is for this to strip out all local namespace prefixes,
- // so that a type "::android::hardware::Foo::bar::baz"
- // is reduced to the equivalent "bar::baz" in the scope of the namespace
- // "::android::hardware::Foo".
- mSpace += "::";
- }
}
void Formatter::output(const std::string &text) const {
diff --git a/HandleType.cpp b/HandleType.cpp
index 7ad2368..b799f0e 100644
--- a/HandleType.cpp
+++ b/HandleType.cpp
@@ -2,6 +2,8 @@
#include "Formatter.h"
+#include <android-base/logging.h>
+
namespace android {
HandleType::HandleType() {}
@@ -12,6 +14,11 @@
return "const ::native_handle_t*";
}
+std::string HandleType::getJavaType() const {
+ CHECK(!"Should not be here");
+ return std::string();
+}
+
void HandleType::emitReaderWriter(
Formatter &out,
const std::string &name,
diff --git a/HandleType.h b/HandleType.h
index 08dedb3..cab0cf8 100644
--- a/HandleType.h
+++ b/HandleType.h
@@ -10,6 +10,7 @@
HandleType();
std::string getCppType(StorageMode mode, std::string *extra) const override;
+ std::string getJavaType() const override;
void emitReaderWriter(
Formatter &out,
diff --git a/Interface.cpp b/Interface.cpp
index 203be93..ab117f2 100644
--- a/Interface.cpp
+++ b/Interface.cpp
@@ -47,6 +47,10 @@
}
}
+std::string Interface::getJavaType() const {
+ return fullJavaName();
+}
+
void Interface::emitReaderWriter(
Formatter &out,
const std::string &name,
@@ -90,5 +94,25 @@
}
}
+void Interface::emitJavaReaderWriter(
+ Formatter &out,
+ const std::string &parcelObj,
+ const std::string &argName,
+ bool isReader) const {
+ if (isReader) {
+ out << fullJavaName()
+ << ".asInterface("
+ << parcelObj
+ << ".readStrongBinder());\n";
+ } else {
+ out << parcelObj
+ << ".writeStrongBinder("
+ << argName
+ << " == null ? null : "
+ << argName
+ << ".asBinder());\n";
+ }
+}
+
} // namespace android
diff --git a/Interface.h b/Interface.h
index d7bf0a3..a7d9afb 100644
--- a/Interface.h
+++ b/Interface.h
@@ -29,6 +29,8 @@
std::string getCppType(StorageMode mode, std::string *extra) const override;
+ std::string getJavaType() const override;
+
void emitReaderWriter(
Formatter &out,
const std::string &name,
@@ -37,6 +39,12 @@
bool isReader,
ErrorMode mode) const override;
+ void emitJavaReaderWriter(
+ Formatter &out,
+ const std::string &parcelObj,
+ const std::string &argName,
+ bool isReader) const override;
+
private:
Interface *mSuperType;
std::vector<Method *> mMethods;
diff --git a/Method.cpp b/Method.cpp
index 2569701..8c140ff 100644
--- a/Method.cpp
+++ b/Method.cpp
@@ -53,6 +53,27 @@
return out;
}
+// static
+std::string Method::GetJavaSignature(const std::vector<TypedVar *> &args) {
+ bool first = true;
+ std::string out;
+ for (const auto &arg : args) {
+ if (!first) {
+ out += ", ";
+ }
+
+ std::string extra;
+ out += arg->type().getJavaType();
+ out += " ";
+ out += arg->name();
+ out += extra;
+
+ first = false;
+ }
+
+ return out;
+}
+
void Method::dumpAnnotations(Formatter &out) const {
if (mAnnotationsByName->size() == 0) {
return;
diff --git a/Method.h b/Method.h
index 86c8f50..e449542 100644
--- a/Method.h
+++ b/Method.h
@@ -26,6 +26,7 @@
const KeyedVector<std::string, Annotation *> &annotations() const;
static std::string GetSignature(const std::vector<TypedVar *> &args);
+ static std::string GetJavaSignature(const std::vector<TypedVar *> &args);
void dumpAnnotations(Formatter &out) const;
diff --git a/NamedType.cpp b/NamedType.cpp
index 77d2596..ed1ffe8 100644
--- a/NamedType.cpp
+++ b/NamedType.cpp
@@ -24,5 +24,9 @@
return mFullName.cppName();
}
+std::string NamedType::fullJavaName() const {
+ return mFullName.javaName();
+}
+
} // namespace android
diff --git a/NamedType.h b/NamedType.h
index e7e9605..d0d24ea 100644
--- a/NamedType.h
+++ b/NamedType.h
@@ -19,6 +19,7 @@
const FQName &fqName() const;
std::string localName() const;
std::string fullName() const;
+ std::string fullJavaName() const;
private:
std::string mLocalName;
diff --git a/ScalarType.cpp b/ScalarType.cpp
index b15734b..bf111ca 100644
--- a/ScalarType.cpp
+++ b/ScalarType.cpp
@@ -39,6 +39,46 @@
return kName[mKind];
}
+std::string ScalarType::getJavaType() const {
+ static const char *const kName[] = {
+ "byte",
+ "boolean",
+ "long",
+ "byte",
+ "byte",
+ "short",
+ "short",
+ "int",
+ "int",
+ "long",
+ "long",
+ "float",
+ "double"
+ };
+
+ return kName[mKind];
+}
+
+std::string ScalarType::getJavaSuffix() const {
+ static const char *const kSuffix[] = {
+ "Int8",
+ "Int8",
+ "Pointer",
+ "Int8",
+ "Int8",
+ "Int16",
+ "Int16",
+ "Int32",
+ "Int32",
+ "Int64",
+ "Int64",
+ "Float",
+ "Double"
+ };
+
+ return kSuffix[mKind];
+}
+
void ScalarType::emitReaderWriter(
Formatter &out,
const std::string &name,
diff --git a/ScalarType.h b/ScalarType.h
index 38b79d4..3e84597 100644
--- a/ScalarType.h
+++ b/ScalarType.h
@@ -31,6 +31,9 @@
std::string getCppType(StorageMode mode, std::string *extra) const override;
+ std::string getJavaType() const override;
+ std::string getJavaSuffix() const override;
+
void emitReaderWriter(
Formatter &out,
const std::string &name,
diff --git a/Scope.cpp b/Scope.cpp
index 5e8e687..ec865af 100644
--- a/Scope.cpp
+++ b/Scope.cpp
@@ -4,6 +4,8 @@
#include "Formatter.h"
#include "Interface.h"
+#include <android-base/logging.h>
+
namespace android {
Scope::Scope() {}
@@ -65,6 +67,11 @@
return false;
}
+std::string Scope::getJavaType() const {
+ CHECK(!"Should not be here");
+ return std::string();
+}
+
status_t Scope::emitTypeDeclarations(Formatter &out) const {
for (size_t i = 0; i < mTypes.size(); ++i) {
status_t err = mTypes[i]->emitTypeDeclarations(out);
@@ -77,6 +84,18 @@
return OK;
}
+status_t Scope::emitJavaTypeDeclarations(Formatter &out) const {
+ for (size_t i = 0; i < mTypes.size(); ++i) {
+ status_t err = mTypes[i]->emitJavaTypeDeclarations(out);
+
+ if (err != OK) {
+ return err;
+ }
+ }
+
+ return OK;
+}
+
status_t Scope::emitTypeDefinitions(
Formatter &out, const std::string prefix) const {
for (size_t i = 0; i < mTypes.size(); ++i) {
diff --git a/Scope.h b/Scope.h
index 90380e9..66b11f9 100644
--- a/Scope.h
+++ b/Scope.h
@@ -29,7 +29,10 @@
bool containsSingleInterface(std::string *ifaceName) const;
+ std::string getJavaType() const override;
+
status_t emitTypeDeclarations(Formatter &out) const override;
+ status_t emitJavaTypeDeclarations(Formatter &out) const override;
status_t emitTypeDefinitions(
Formatter &out, const std::string prefix) const override;
diff --git a/StringType.cpp b/StringType.cpp
index 5411e91..ca01687 100644
--- a/StringType.cpp
+++ b/StringType.cpp
@@ -23,6 +23,14 @@
}
}
+std::string StringType::getJavaType() const {
+ return "String";
+}
+
+std::string StringType::getJavaSuffix() const {
+ return "String";
+}
+
void StringType::emitReaderWriter(
Formatter &out,
const std::string &name,
diff --git a/StringType.h b/StringType.h
index e7e00d4..0fc6223 100644
--- a/StringType.h
+++ b/StringType.h
@@ -11,6 +11,9 @@
std::string getCppType(StorageMode mode, std::string *extra) const override;
+ std::string getJavaType() const override;
+ std::string getJavaSuffix() const override;
+
void emitReaderWriter(
Formatter &out,
const std::string &name,
diff --git a/Type.cpp b/Type.cpp
index bec4655..1e7e2d5 100644
--- a/Type.cpp
+++ b/Type.cpp
@@ -45,6 +45,11 @@
return std::string();
}
+std::string Type::getJavaSuffix() const {
+ CHECK(!"Should not be here");
+ return std::string();
+}
+
void Type::emitReaderWriter(
Formatter &,
const std::string &,
@@ -68,6 +73,20 @@
CHECK(!"Should not be here");
}
+void Type::emitJavaReaderWriter(
+ Formatter &out,
+ const std::string &parcelObj,
+ const std::string &argName,
+ bool isReader) const {
+ emitJavaReaderWriterWithSuffix(
+ out,
+ parcelObj,
+ argName,
+ isReader,
+ getJavaSuffix(),
+ "" /* extra */);
+}
+
void Type::handleError(Formatter &out, ErrorMode mode) const {
switch (mode) {
case ErrorMode_Ignore:
@@ -189,6 +208,10 @@
return OK;
}
+status_t Type::emitJavaTypeDeclarations(Formatter &) const {
+ return OK;
+}
+
bool Type::needsEmbeddedReadWrite() const {
return false;
}
@@ -209,5 +232,28 @@
return getCppType(StorageMode_Argument, extra);
}
+void Type::emitJavaReaderWriterWithSuffix(
+ Formatter &out,
+ const std::string &parcelObj,
+ const std::string &argName,
+ bool isReader,
+ const std::string &suffix,
+ const std::string &extra) const {
+ out << parcelObj
+ << "."
+ << (isReader ? "read" : "write")
+ << suffix
+ << "(";
+
+ if (isReader) {
+ out << extra;
+ } else {
+ out << (extra.empty() ? "" : (extra + ", "));
+ out << argName;
+ }
+
+ out << ");\n";
+}
+
} // namespace android
diff --git a/Type.h b/Type.h
index 03c6615..c24b907 100644
--- a/Type.h
+++ b/Type.h
@@ -40,6 +40,9 @@
std::string getCppResultType(std::string *extra) const;
std::string getCppArgumentType(std::string *extra) const;
+ virtual std::string getJavaType() const = 0;
+ virtual std::string getJavaSuffix() const;
+
enum ErrorMode {
ErrorMode_Ignore,
ErrorMode_Goto,
@@ -65,11 +68,19 @@
const std::string &parentName,
const std::string &offsetText) const;
+ virtual void emitJavaReaderWriter(
+ Formatter &out,
+ const std::string &parcelObj,
+ const std::string &argName,
+ bool isReader) const;
+
virtual status_t emitTypeDeclarations(Formatter &out) const;
virtual status_t emitTypeDefinitions(
Formatter &out, const std::string prefix) const;
+ virtual status_t emitJavaTypeDeclarations(Formatter &out) const;
+
virtual bool needsEmbeddedReadWrite() const;
virtual bool resultNeedsDeref() const;
@@ -90,6 +101,14 @@
const std::string &typeName,
const std::string &childName) const;
+ void emitJavaReaderWriterWithSuffix(
+ Formatter &out,
+ const std::string &parcelObj,
+ const std::string &argName,
+ bool isReader,
+ const std::string &suffix,
+ const std::string &extra) const;
+
private:
DISALLOW_COPY_AND_ASSIGN(Type);
};
diff --git a/TypeDef.cpp b/TypeDef.cpp
index 1e3c5b7..bbdacd7 100644
--- a/TypeDef.cpp
+++ b/TypeDef.cpp
@@ -34,6 +34,11 @@
return true;
}
+std::string TypeDef::getJavaType() const {
+ CHECK(!"Should not be here");
+ return std::string();
+}
+
bool TypeDef::needsEmbeddedReadWrite() const {
CHECK(!"Should not be here");
return false;
diff --git a/TypeDef.h b/TypeDef.h
index f3030bf..23d939d 100644
--- a/TypeDef.h
+++ b/TypeDef.h
@@ -17,6 +17,8 @@
bool isEnum() const override;
bool isTypeDef() const override;
+ std::string getJavaType() const override;
+
bool needsEmbeddedReadWrite() const override;
bool resultNeedsDeref() const override;
diff --git a/VectorType.cpp b/VectorType.cpp
index fcfda4b..fc2360e 100644
--- a/VectorType.cpp
+++ b/VectorType.cpp
@@ -30,6 +30,14 @@
}
}
+std::string VectorType::getJavaType() const {
+ return mElementType->getJavaType() + "[]";
+}
+
+std::string VectorType::getJavaSuffix() const {
+ return mElementType->getJavaSuffix() + "Vector";
+}
+
void VectorType::emitReaderWriter(
Formatter &out,
const std::string &name,
diff --git a/VectorType.h b/VectorType.h
index f0db95c..905214b 100644
--- a/VectorType.h
+++ b/VectorType.h
@@ -11,6 +11,9 @@
std::string getCppType(StorageMode mode, std::string *extra) const override;
+ std::string getJavaType() const override;
+ std::string getJavaSuffix() const override;
+
void emitReaderWriter(
Formatter &out,
const std::string &name,
diff --git a/generateCpp.cpp b/generateCpp.cpp
index a8f95a6..51e8143 100644
--- a/generateCpp.cpp
+++ b/generateCpp.cpp
@@ -79,7 +79,7 @@
out << "namespace " << component << " {\n";
}
- out.setNamespace(mPackage.cppNamespace());
+ out.setNamespace(mPackage.cppNamespace() + "::");
} else {
out.setNamespace(std::string());
diff --git a/generateJava.cpp b/generateJava.cpp
new file mode 100644
index 0000000..2b0fbf8
--- /dev/null
+++ b/generateJava.cpp
@@ -0,0 +1,498 @@
+#include "AST.h"
+
+#include "Coordinator.h"
+#include "Formatter.h"
+#include "Interface.h"
+#include "Method.h"
+#include "Scope.h"
+
+#include <android-base/logging.h>
+
+namespace android {
+
+static std::string upcase(const std::string in) {
+ std::string out{in};
+
+ for (auto &ch : out) {
+ ch = toupper(ch);
+ }
+
+ return out;
+}
+
+void AST::emitJavaReaderWriter(
+ Formatter &out,
+ const std::string &parcelObj,
+ const TypedVar *arg,
+ bool isReader) const {
+ if (isReader) {
+ out << arg->type().getJavaType()
+ << " "
+ << arg->name()
+ << " = ";
+ }
+
+ arg->type().emitJavaReaderWriter(out, parcelObj, arg->name(), isReader);
+}
+
+status_t AST::generateJava(const std::string &outputPath) const {
+ std::string ifaceName;
+ if (!AST::isInterface(&ifaceName)) {
+ fprintf(stderr, "Common types are unsupported in the Java backend.\n");
+ return UNKNOWN_ERROR;
+ }
+
+ // cut off the leading 'I'.
+ const std::string baseName = ifaceName.substr(1);
+
+ std::string path = outputPath;
+ path.append(mCoordinator->convertPackageRootToPath(mPackage));
+ path.append(mCoordinator->getPackagePath(mPackage, true /* relative */));
+ path.append(ifaceName);
+ path.append(".java");
+
+ CHECK(Coordinator::MakeParentHierarchy(path));
+ FILE *file = fopen(path.c_str(), "w");
+
+ if (file == NULL) {
+ return -errno;
+ }
+
+ Formatter out(file);
+
+ std::vector<std::string> packageComponents;
+ getPackageAndVersionComponents(
+ &packageComponents, true /* cpp_compatible */);
+
+ out << "package " << mPackage.javaPackage() << ";\n\n";
+
+ out << "import android.os.IHwBinder;\n";
+ out << "import android.os.IHwInterface;\n";
+ out << "import android.os.HwBinder;\n";
+ out << "import android.os.HwParcel;\n\n";
+
+ for (const auto &item : mImportedNames) {
+ out << "import " << item.javaName() << ";\n";
+ }
+
+ if (!mImportedNames.empty()) {
+ out << "\n";
+ }
+
+ out.setNamespace(mPackage.javaPackage() + ".");
+
+ const Interface *iface = mRootScope->getInterface();
+ const Interface *superType = iface->superType();
+
+ out << "public interface " << ifaceName << " extends ";
+
+ if (superType != NULL) {
+ out << superType->fullJavaName();
+ } else {
+ out << "IHwInterface";
+ }
+
+ out << " {\n";
+ out.indent();
+
+ out << "public static final String kInterfaceName = \""
+ << mPackage.string()
+ << "::"
+ << ifaceName
+ << "\";\n\n";
+
+ out << "public static "
+ << ifaceName
+ << " asInterface(IHwBinder binder) {\n";
+
+ out.indent();
+
+ out << "if (binder == null) {\n";
+ out.indent();
+ out << "return null;\n";
+ out.unindent();
+ out << "}\n\n";
+
+ out << "IHwInterface iface =\n";
+ out.indent();
+ out.indent();
+ out << "binder.queryLocalInterface(kInterfaceName);\n\n";
+ out.unindent();
+ out.unindent();
+
+ out << "if ((iface != null) && (iface instanceof "
+ << ifaceName
+ << ")) {\n";
+
+ out.indent();
+ out << "return (" << ifaceName << ")iface;\n";
+ out.unindent();
+ out << "}\n\n";
+
+ out << "return new " << ifaceName << ".Proxy(binder);\n";
+
+ out.unindent();
+ out << "}\n\n";
+
+ out << "public IHwBinder asBinder();\n\n";
+
+ status_t err = emitJavaTypeDeclarations(out);
+
+ if (err != OK) {
+ return err;
+ }
+
+ const std::string base = (superType != NULL)
+ ? (superType->fullJavaName() + ".kOpEnd")
+ : "IHwBinder.FIRST_CALL_TRANSACTION";
+
+ bool first = true;
+ size_t index = 0;
+ for (const auto &method : iface->methods()) {
+ out << "public static final int kOp_"
+ << upcase(method->name())
+ << " = "
+ << base;
+
+ if (!first) {
+ out << " + " << index;
+ }
+
+ out << ";\n";
+
+ ++index;
+ first = false;
+ }
+
+ out << "public static final int kOpEnd = "
+ << base
+ << " + "
+ << index
+ << ";";
+
+ out << "\n\n";
+
+ for (const auto &method : iface->methods()) {
+ const bool returnsValue = !method->results().empty();
+ const bool needsCallback = method->results().size() > 1;
+
+ if (needsCallback) {
+ out << "\npublic abstract class "
+ << method->name()
+ << "Callback {\n";
+
+ out.indent();
+
+ out << "public abstract void onValues("
+ << Method::GetJavaSignature(method->results())
+ << ");\n";
+
+ out.unindent();
+ out << "}\n\n";
+ }
+
+ if (returnsValue && !needsCallback) {
+ out << method->results()[0]->type().getJavaType();
+ } else {
+ out << "void";
+ }
+
+ out << " "
+ << method->name()
+ << "("
+ << Method::GetJavaSignature(method->args());
+
+ if (needsCallback) {
+ if (!method->args().empty()) {
+ out << ", ";
+ }
+
+ out << method->name()
+ << "Callback cb";
+ }
+
+ out << ");\n";
+ }
+
+ out << "\npublic static final class Proxy implements "
+ << ifaceName
+ << " {\n";
+
+ out.indent();
+
+ out << "private IHwBinder mRemote;\n\n";
+ out << "public Proxy(IHwBinder remote) {\n";
+ out.indent();
+ out << "mRemote = remote;\n";
+ out.unindent();
+ out << "}\n\n";
+
+ out << "public IHwBinder asBinder() {\n";
+ out.indent();
+ out << "return mRemote;\n";
+ out.unindent();
+ out << "}\n\n";
+
+ std::vector<const Interface *> chain;
+ while (iface != NULL) {
+ chain.push_back(iface);
+ iface = iface->superType();
+ }
+
+ for (auto it = chain.rbegin(); it != chain.rend(); ++it) {
+ const Interface *superInterface = *it;
+
+ out << "// Methods from "
+ << superInterface->fullName()
+ << " follow.\n";
+
+ for (const auto &method : superInterface->methods()) {
+ const bool returnsValue = !method->results().empty();
+ const bool needsCallback = method->results().size() > 1;
+
+ out << "public ";
+ if (returnsValue && !needsCallback) {
+ out << method->results()[0]->type().getJavaType();
+ } else {
+ out << "void";
+ }
+
+ out << " "
+ << method->name()
+ << "("
+ << Method::GetJavaSignature(method->args());
+
+ if (needsCallback) {
+ if (!method->args().empty()) {
+ out << ", ";
+ }
+
+ out << method->name()
+ << "Callback cb";
+ }
+
+ out << ") {\n";
+ out.indent();
+
+ out << "HwParcel request = new HwParcel();\n";
+ out << "request.writeInterfaceToken("
+ << superInterface->fullJavaName()
+ << ".kInterfaceName);\n";
+
+ for (const auto &arg : method->args()) {
+ emitJavaReaderWriter(
+ out,
+ "request",
+ arg,
+ false /* isReader */);
+ }
+
+ out << "\nHwParcel reply = new HwParcel();\n"
+ << "mRemote.transact(kOp_"
+ << upcase(method->name())
+ << ", request, reply, 0 /* flags */);\n"
+ << "reply.verifySuccess();\n"
+ << "request.releaseTemporaryStorage();\n";
+
+ if (returnsValue) {
+ out << "\n";
+
+ for (const auto &arg : method->results()) {
+ emitJavaReaderWriter(
+ out,
+ "reply",
+ arg,
+ true /* isReader */);
+ }
+
+ if (needsCallback) {
+ out << "cb.onValues(";
+
+ bool firstField = true;
+ for (const auto &arg : method->results()) {
+ if (!firstField) {
+ out << ", ";
+ }
+
+ out << arg->name();
+ firstField = false;
+ }
+
+ out << ");\n";
+ } else {
+ const std::string returnName = method->results()[0]->name();
+ out << "return " << returnName << ";\n";
+ }
+ }
+
+ out.unindent();
+ out << "}\n\n";
+ }
+ }
+
+ out.unindent();
+ out << "}\n";
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ out << "\npublic static abstract class Stub extends HwBinder "
+ << "implements "
+ << ifaceName << " {\n";
+
+ out.indent();
+
+ out << "public IHwBinder asBinder() {\n";
+ out.indent();
+ out << "return this;\n";
+ out.unindent();
+ out << "}\n\n";
+
+ out << "public IHwInterface queryLocalInterface(String descriptor) {\n";
+ out.indent();
+ // XXX what about potential superClasses?
+ out << "if (kInterfaceName.equals(descriptor)) {\n";
+ out.indent();
+ out << "return this;\n";
+ out.unindent();
+ out << "}\n";
+ out << "return null;\n";
+ out.unindent();
+ out << "}\n\n";
+
+ out << "public void onTransact("
+ << "int code, HwParcel request, final HwParcel reply, "
+ << "int flags) {\n";
+
+ out.indent();
+
+ out << "switch (code) {\n";
+
+ out.indent();
+
+ for (auto it = chain.rbegin(); it != chain.rend(); ++it) {
+ const Interface *superInterface = *it;
+
+ for (const auto &method : superInterface->methods()) {
+ const bool returnsValue = !method->results().empty();
+ const bool needsCallback = method->results().size() > 1;
+
+ out << "case "
+ << superInterface->fullJavaName()
+ << ".kOp_"
+ <<
+ upcase(method->name())
+ << ":\n{\n";
+
+ out.indent();
+
+ out << "request.enforceInterface("
+ << superInterface->fullJavaName()
+ << ".kInterfaceName);\n\n";
+
+ for (const auto &arg : method->args()) {
+ emitJavaReaderWriter(
+ out,
+ "request",
+ arg,
+ true /* isReader */);
+ }
+
+ if (!needsCallback && returnsValue) {
+ const TypedVar *returnArg = method->results()[0];
+
+ out << returnArg->type().getJavaType()
+ << " "
+ << returnArg->name()
+ << " = ";
+ }
+
+ out << method->name()
+ << "(";
+
+ bool firstField = true;
+ for (const auto &arg : method->args()) {
+ if (!firstField) {
+ out << ", ";
+ }
+
+ out << arg->name();
+
+ firstField = false;
+ }
+
+ if (needsCallback) {
+ if (!firstField) {
+ out << ", ";
+ }
+
+ out << "new " << method->name() << "Callback() {\n";
+ out.indent();
+
+ out << "@Override\n"
+ << "public void onValues("
+ << Method::GetJavaSignature(method->results())
+ << ") {\n";
+
+ out.indent();
+ out << "reply.writeStatus(HwParcel.STATUS_SUCCESS);\n";
+
+ for (const auto &arg : method->results()) {
+ emitJavaReaderWriter(
+ out,
+ "reply",
+ arg,
+ false /* isReader */);
+ }
+
+ out << "reply.send();\n"
+ << "}}";
+
+ out.unindent();
+ out.unindent();
+ }
+
+ out << ");\n";
+
+ if (!needsCallback) {
+ out << "reply.writeStatus(HwParcel.STATUS_SUCCESS);\n";
+
+ if (returnsValue) {
+ const TypedVar *returnArg = method->results()[0];
+
+ emitJavaReaderWriter(
+ out,
+ "reply",
+ returnArg,
+ false /* isReader */);
+ }
+
+ out << "reply.send();\n";
+ }
+
+ out << "break;\n";
+ out.unindent();
+ out << "}\n\n";
+ }
+ }
+
+ out.unindent();
+ out << "}\n";
+
+ out.unindent();
+ out << "}\n";
+
+ out.unindent();
+ out << "}\n";
+
+ out.unindent();
+ out << "}\n";
+
+ return OK;
+}
+
+status_t AST::emitJavaTypeDeclarations(Formatter &out) const {
+ return mRootScope->emitJavaTypeDeclarations(out);
+}
+
+} // namespace android
+
diff --git a/main.cpp b/main.cpp
index 752e5f8..9b0bfab 100644
--- a/main.cpp
+++ b/main.cpp
@@ -31,7 +31,8 @@
const FQName &fqName,
const char *,
Coordinator *coordinator,
- const std::string &outputDir) {
+ const std::string &outputDir,
+ bool java = false) {
CHECK(fqName.isFullyQualified());
@@ -45,7 +46,8 @@
return UNKNOWN_ERROR;
}
- status_t err = ast->generateCpp(outputDir);
+ status_t err =
+ java ? ast->generateJava(outputDir) : ast->generateCpp(outputDir);
return err;
}
@@ -54,7 +56,8 @@
const FQName &packageFQName,
const char *hidl_gen,
Coordinator *coordinator,
- const std::string &outputDir) {
+ const std::string &outputDir,
+ bool java = false) {
CHECK(packageFQName.isValid() &&
!packageFQName.isFullyQualified() &&
@@ -71,7 +74,9 @@
}
for (const auto &fqName : packageInterfaces) {
- err = generateSourcesForFile(fqName, hidl_gen, coordinator, outputDir);
+ err = generateSourcesForFile(
+ fqName, hidl_gen, coordinator, outputDir, java);
+
if (err != OK) {
return err;
}
@@ -222,7 +227,7 @@
return OutputHandler::PASS_PACKAGE;
}
-OutputHandler::ValRes validateForCpp(const FQName &fqName) {
+OutputHandler::ValRes validateForCppOrJava(const FQName &fqName) {
if (fqName.package().empty()) {
fprintf(stderr, "Expecting package name\n");
return OutputHandler::FAILED;
@@ -240,8 +245,8 @@
static std::vector<OutputHandler> formats = {
{"c++",
- true,
- validateForCpp,
+ true /* mNeedsOutputDir */,
+ validateForCppOrJava,
[](const FQName &fqName,
const char *hidl_gen, Coordinator *coordinator,
const std::string &outputDir) -> status_t {
@@ -260,8 +265,31 @@
}
},
+ {"java",
+ true /* mNeedsOutputDir */,
+ validateForCppOrJava,
+ [](const FQName &fqName,
+ const char *hidl_gen, Coordinator *coordinator,
+ const std::string &outputDir) -> status_t {
+ if (fqName.isFullyQualified()) {
+ return generateSourcesForFile(fqName,
+ hidl_gen,
+ coordinator,
+ outputDir,
+ true /* java */);
+ }
+ else {
+ return generateSourcesForPackage(fqName,
+ hidl_gen,
+ coordinator,
+ outputDir,
+ true /* java */);
+ }
+ }
+ },
+
{"makefile",
- false,
+ false /* mNeedsOutputDir */,
validateForMakefile,
generateMakefileForPackage,
},
diff --git a/test/Android.mk b/test/Android.mk
index 240f3ed..b753dd6 100644
--- a/test/Android.mk
+++ b/test/Android.mk
@@ -7,18 +7,19 @@
LOCAL_SRC_FILES := \
main.cpp \
-LOCAL_SHARED_LIBRARIES := \
- libandroid_runtime \
- libbase \
- libcutils \
- libhwbinder \
- libnativehelper \
- libutils \
- android.hardware.tests.foo@1.0 \
- android.hardware.tests.bar@1.0
+LOCAL_SHARED_LIBRARIES := \
+ libandroid_runtime \
+ libbase \
+ libcutils \
+ libhwbinder \
+ libnativehelper \
+ libutils \
+ android.hardware.foo@1.0 \
+ android.hardware.bar@1.0 \
+ android.hardware.nfc@1.0 \
LOCAL_MODULE_TAGS := samples
LOCAL_CFLAGS := -O0 -g
-include $(BUILD_EXECUTABLE)
+# include $(BUILD_EXECUTABLE)