[automerger skipped] Fillout requesting SID. am: 3559fb01be -s ours
am: bb4209bc4c -s ours
am skip reason: change_id I3a7f6c0b3cc8bab24e0639a3e7121ef536b2603b with SHA1 ca8cf63c53 is in history
Change-Id: I98b45bbd96df75d59424a1f8fbb34e6dcb194384
diff --git a/AST.cpp b/AST.cpp
index cb260e2..834dc5a 100644
--- a/AST.cpp
+++ b/AST.cpp
@@ -83,16 +83,21 @@
return mRootScope.getInterface() != nullptr;
}
-bool AST::containsInterfaces() const {
- return mRootScope.containsInterfaces();
+bool AST::definesInterfaces() const {
+ return mRootScope.definesInterfaces();
}
status_t AST::postParse() {
status_t err;
- // lookupTypes is the first pass.
+ // lookupTypes is the first pass for references to be resolved.
err = lookupTypes();
if (err != OK) return err;
+
+ // Indicate that all types are now in "postParse" stage.
+ err = setParseStage(Type::ParseStage::PARSE, Type::ParseStage::POST_PARSE);
+ if (err != OK) return err;
+
// validateDefinedTypesUniqueNames is the first call
// after lookup, as other errors could appear because
// user meant different type than we assumed.
@@ -104,13 +109,15 @@
if (err != OK) return err;
err = resolveInheritance();
if (err != OK) return err;
- err = lookupLocalIdentifiers();
+ err = lookupConstantExpressions();
if (err != OK) return err;
// checkAcyclicConstantExpressions is after resolveInheritance,
// as resolveInheritance autofills enum values.
err = checkAcyclicConstantExpressions();
if (err != OK) return err;
- err = evaluate();
+ err = validateConstantExpressions();
+ if (err != OK) return err;
+ err = evaluateConstantExpressions();
if (err != OK) return err;
err = validate();
if (err != OK) return err;
@@ -127,13 +134,9 @@
return OK;
},
true /* processBeforeDependencies */);
- std::unordered_set<const Type*> visited;
- mRootScope.recursivePass(
- [](Type* type) {
- type->setPostParseCompleted();
- return OK;
- },
- &visited);
+
+ err = setParseStage(Type::ParseStage::POST_PARSE, Type::ParseStage::COMPLETED);
+ if (err != OK) return err;
return OK;
}
@@ -142,20 +145,50 @@
const std::function<status_t(ConstantExpression*)>& func, bool processBeforeDependencies) {
std::unordered_set<const Type*> visitedTypes;
std::unordered_set<const ConstantExpression*> visitedCE;
- return mRootScope.recursivePass(
- [&](Type* type) -> status_t {
- for (auto* ce : type->getConstantExpressions()) {
- status_t err = ce->recursivePass(func, &visitedCE, processBeforeDependencies);
- if (err != OK) return err;
- }
- return OK;
- },
- &visitedTypes);
+ return mRootScope.recursivePass(Type::ParseStage::POST_PARSE,
+ [&](Type* type) -> status_t {
+ for (auto* ce : type->getConstantExpressions()) {
+ status_t err = ce->recursivePass(
+ func, &visitedCE, processBeforeDependencies);
+ if (err != OK) return err;
+ }
+ return OK;
+ },
+ &visitedTypes);
+}
+
+status_t AST::constantExpressionRecursivePass(
+ const std::function<status_t(const ConstantExpression*)>& func,
+ bool processBeforeDependencies) const {
+ std::unordered_set<const Type*> visitedTypes;
+ std::unordered_set<const ConstantExpression*> visitedCE;
+ return mRootScope.recursivePass(Type::ParseStage::POST_PARSE,
+ [&](const Type* type) -> status_t {
+ for (auto* ce : type->getConstantExpressions()) {
+ status_t err = ce->recursivePass(
+ func, &visitedCE, processBeforeDependencies);
+ if (err != OK) return err;
+ }
+ return OK;
+ },
+ &visitedTypes);
+}
+
+status_t AST::setParseStage(Type::ParseStage oldStage, Type::ParseStage newStage) {
+ std::unordered_set<const Type*> visited;
+ return mRootScope.recursivePass(oldStage,
+ [oldStage, newStage](Type* type) {
+ CHECK(type->getParseStage() == oldStage);
+ type->setParseStage(newStage);
+ return OK;
+ },
+ &visited);
}
status_t AST::lookupTypes() {
std::unordered_set<const Type*> visited;
return mRootScope.recursivePass(
+ Type::ParseStage::PARSE,
[&](Type* type) -> status_t {
Scope* scope = type->isScope() ? static_cast<Scope*>(type) : type->parent();
@@ -182,6 +215,7 @@
status_t AST::gatherReferencedTypes() {
std::unordered_set<const Type*> visited;
return mRootScope.recursivePass(
+ Type::ParseStage::POST_PARSE,
[&](Type* type) -> status_t {
for (auto* nextRef : type->getReferences()) {
const Type *targetType = nextRef->get();
@@ -196,11 +230,12 @@
&visited);
}
-status_t AST::lookupLocalIdentifiers() {
+status_t AST::lookupConstantExpressions() {
std::unordered_set<const Type*> visitedTypes;
std::unordered_set<const ConstantExpression*> visitedCE;
return mRootScope.recursivePass(
+ Type::ParseStage::POST_PARSE,
[&](Type* type) -> status_t {
Scope* scope = type->isScope() ? static_cast<Scope*>(type) : type->parent();
@@ -214,6 +249,18 @@
if (iden == nullptr) return UNKNOWN_ERROR;
nextRef->set(iden);
}
+ for (auto* nextRef : ce->getTypeReferences()) {
+ if (nextRef->isResolved()) continue;
+
+ Type* nextType = lookupType(nextRef->getLookupFqName(), scope);
+ if (nextType == nullptr) {
+ std::cerr << "ERROR: Failed to lookup type '"
+ << nextRef->getLookupFqName().string() << "' at "
+ << nextRef->location() << "\n";
+ return UNKNOWN_ERROR;
+ }
+ nextRef->set(nextType);
+ }
return OK;
},
&visitedCE, true /* processBeforeDependencies */);
@@ -228,6 +275,7 @@
status_t AST::validateDefinedTypesUniqueNames() const {
std::unordered_set<const Type*> visited;
return mRootScope.recursivePass(
+ Type::ParseStage::POST_PARSE,
[&](const Type* type) -> status_t {
// We only want to validate type definition names in this place.
if (type->isScope()) {
@@ -240,10 +288,17 @@
status_t AST::resolveInheritance() {
std::unordered_set<const Type*> visited;
- return mRootScope.recursivePass(&Type::resolveInheritance, &visited);
+ return mRootScope.recursivePass(Type::ParseStage::POST_PARSE, &Type::resolveInheritance,
+ &visited);
}
-status_t AST::evaluate() {
+status_t AST::validateConstantExpressions() const {
+ return constantExpressionRecursivePass(
+ [](const ConstantExpression* ce) { return ce->validate(); },
+ true /* processBeforeDependencies */);
+}
+
+status_t AST::evaluateConstantExpressions() {
return constantExpressionRecursivePass(
[](ConstantExpression* ce) {
ce->evaluate();
@@ -254,7 +309,7 @@
status_t AST::validate() const {
std::unordered_set<const Type*> visited;
- return mRootScope.recursivePass(&Type::validate, &visited);
+ return mRootScope.recursivePass(Type::ParseStage::POST_PARSE, &Type::validate, &visited);
}
status_t AST::topologicalReorder() {
@@ -264,14 +319,14 @@
if (err != OK) return err;
std::unordered_set<const Type*> visited;
- mRootScope.recursivePass(
- [&](Type* type) {
- if (type->isScope()) {
- static_cast<Scope*>(type)->topologicalReorder(reversedOrder);
- }
- return OK;
- },
- &visited);
+ mRootScope.recursivePass(Type::ParseStage::POST_PARSE,
+ [&](Type* type) {
+ if (type->isScope()) {
+ static_cast<Scope*>(type)->topologicalReorder(reversedOrder);
+ }
+ return OK;
+ },
+ &visited);
return OK;
}
@@ -279,29 +334,31 @@
std::unordered_set<const Type*> visitedTypes;
std::unordered_set<const ConstantExpression*> visitedCE;
std::unordered_set<const ConstantExpression*> stack;
- return mRootScope.recursivePass(
- [&](const Type* type) -> status_t {
- for (auto* ce : type->getConstantExpressions()) {
- status_t err = ce->checkAcyclic(&visitedCE, &stack).status;
- CHECK(err != OK || stack.empty());
- if (err != OK) return err;
- }
- return OK;
- },
- &visitedTypes);
+ return mRootScope.recursivePass(Type::ParseStage::POST_PARSE,
+ [&](const Type* type) -> status_t {
+ for (auto* ce : type->getConstantExpressions()) {
+ status_t err =
+ ce->checkAcyclic(&visitedCE, &stack).status;
+ CHECK(err != OK || stack.empty());
+ if (err != OK) return err;
+ }
+ return OK;
+ },
+ &visitedTypes);
}
status_t AST::checkForwardReferenceRestrictions() const {
std::unordered_set<const Type*> visited;
- return mRootScope.recursivePass(
- [](const Type* type) -> status_t {
- for (const Reference<Type>* ref : type->getReferences()) {
- status_t err = type->checkForwardReferenceRestrictions(*ref);
- if (err != OK) return err;
- }
- return OK;
- },
- &visited);
+ return mRootScope.recursivePass(Type::ParseStage::POST_PARSE,
+ [](const Type* type) -> status_t {
+ for (const Reference<Type>* ref : type->getReferences()) {
+ status_t err =
+ type->checkForwardReferenceRestrictions(*ref);
+ if (err != OK) return err;
+ }
+ return OK;
+ },
+ &visited);
}
bool AST::addImport(const char *import) {
@@ -448,7 +505,6 @@
FQName enumTypeName = fqName.typeName();
std::string enumValueName = fqName.valueName();
- CHECK(enumTypeName.isValid());
CHECK(!enumValueName.empty());
Type* type = lookupType(enumTypeName, scope);
@@ -475,8 +531,6 @@
}
Type* AST::lookupType(const FQName& fqName, Scope* scope) {
- CHECK(fqName.isValid());
-
if (fqName.name().empty()) {
// Given a package and version???
return nullptr;
diff --git a/AST.h b/AST.h
index 4de98bd..9472582 100644
--- a/AST.h
+++ b/AST.h
@@ -53,7 +53,7 @@
// package and version really.
FQName package() const;
bool isInterface() const;
- bool containsInterfaces() const;
+ bool definesInterfaces() const;
// Adds package, version and scope stack to local name
FQName makeFullName(const char* localName, Scope* scope) const;
@@ -84,12 +84,19 @@
// Recursive pass on constant expression tree
status_t constantExpressionRecursivePass(
const std::function<status_t(ConstantExpression*)>& func, bool processBeforeDependencies);
+ status_t constantExpressionRecursivePass(
+ const std::function<status_t(const ConstantExpression*)>& func,
+ bool processBeforeDependencies) const;
+
+ // Recursive tree pass that sets ParseStage of all types to newStage.
+ status_t setParseStage(Type::ParseStage oldStage, Type::ParseStage newStage);
// Recursive tree pass that looks up all referenced types
status_t lookupTypes();
// Recursive tree pass that looks up all referenced local identifiers
- status_t lookupLocalIdentifiers();
+ // and types referenced by constant expressions
+ status_t lookupConstantExpressions();
// Recursive tree pass that validates that all defined types
// have unique names in their scopes.
@@ -99,8 +106,11 @@
// that depend on super types
status_t resolveInheritance();
+ // Recursive tree pass that validates constant expressions
+ status_t validateConstantExpressions() const;
+
// Recursive tree pass that evaluates constant expressions
- status_t evaluate();
+ status_t evaluateConstantExpressions();
// Recursive tree pass that validates all type-related
// syntax restrictions
@@ -138,6 +148,8 @@
void generateVts(Formatter& out) const;
+ void generateDependencies(Formatter& out) const;
+
void getImportedPackages(std::set<FQName> *importSet) const;
// Run getImportedPackages on this, then run getImportedPackages on
@@ -260,9 +272,9 @@
bool includeParents = true) const;
void generateStubImplMethod(Formatter& out, const std::string& className,
const Method* method) const;
- void generatePassthroughMethod(Formatter& out, const Method* method) const;
+ void generatePassthroughMethod(Formatter& out, const Method* method, const Interface* superInterface) const;
void generateStaticProxyMethodSource(Formatter& out, const std::string& className,
- const Method* method) const;
+ const Method* method, const Interface* superInterface) const;
void generateProxyMethodSource(Formatter& out, const std::string& className,
const Method* method, const Interface* superInterface) const;
void generateAdapterMethod(Formatter& out, const Method* method) const;
@@ -276,7 +288,7 @@
void generateStubSourceForMethod(Formatter& out, const Method* method,
const Interface* superInterface) const;
void generateStaticStubMethodSource(Formatter& out, const FQName& fqName,
- const Method* method) const;
+ const Method* method, const Interface* superInterface) const;
void generatePassthroughSource(Formatter& out) const;
@@ -303,7 +315,8 @@
void generateCppInstrumentationCall(
Formatter &out,
InstrumentationEvent event,
- const Method *method) const;
+ const Method *method,
+ const Interface* superInterface) const;
void declareCppReaderLocals(Formatter& out, const std::vector<NamedReference<Type>*>& arg,
bool forResults) const;
diff --git a/Android.bp b/Android.bp
index dd51705..5e3566f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -16,11 +16,14 @@
name: "hidl-gen-defaults",
cpp_std: "experimental",
cflags: [
- "-O0",
- "-g",
"-Wall",
"-Werror",
],
+ target: {
+ host: {
+ cflags: ["-O0", "-g"],
+ }
+ }
}
// This configuration is inherited by all hidl-gen-generated modules.
@@ -31,6 +34,10 @@
"-Werror",
"-Wextra-semi",
],
+ tidy_checks: [
+ // _hidl_cb and addOnewayTask are stuck because of the legacy ABI
+ "-performance-unnecessary-value-param",
+ ],
product_variables: {
debuggable: {
cflags: ["-D__ANDROID_DEBUGGABLE__"]
@@ -49,26 +56,6 @@
},
}
-//
-// libhidl-gen-hash
-//
-cc_library {
- name: "libhidl-gen-hash",
- host_supported: true,
- defaults: ["hidl-gen-defaults"],
- srcs: ["Hash.cpp"],
- local_include_dirs: ["include_hash/hidl-hash"],
- export_include_dirs: ["include_hash"],
- shared_libs: [
- "libbase",
- "libcrypto",
- "libssl",
- ],
-}
-
-//
-// libhidl-gen
-//
cc_library_host_shared {
name: "libhidl-gen",
defaults: ["hidl-gen-defaults"],
@@ -101,19 +88,17 @@
"libbase",
"liblog",
"libhidl-gen-hash",
+ "libhidl-gen-host-utils",
"libhidl-gen-utils",
],
export_shared_lib_headers: [
"libbase",
+ "libhidl-gen-host-utils",
"libhidl-gen-utils",
],
export_include_dirs: ["."], // for tests
}
-//
-// libhidl-gen-ast
-//
-
cc_library_host_shared {
name: "libhidl-gen-ast",
defaults: ["hidl-gen-defaults"],
@@ -122,6 +107,7 @@
"generateCpp.cpp",
"generateCppAdapter.cpp",
"generateCppImpl.cpp",
+ "generateDependencies.cpp",
"generateJava.cpp",
"generateVts.cpp",
"hidl-gen_y.yy",
@@ -133,6 +119,7 @@
"liblog",
"libhidl-gen",
"libhidl-gen-hash",
+ "libhidl-gen-host-utils",
"libhidl-gen-utils",
],
export_shared_lib_headers: [
@@ -142,9 +129,6 @@
export_include_dirs: ["."], // for tests
}
-//
-// hidl-gen
-//
cc_binary_host {
name: "hidl-gen",
defaults: ["hidl-gen-defaults"],
@@ -155,6 +139,7 @@
"libhidl-gen",
"libhidl-gen-ast",
"libhidl-gen-hash",
+ "libhidl-gen-host-utils",
"libhidl-gen-utils",
],
}
diff --git a/Annotation.cpp b/Annotation.cpp
index e5a66b0..438cff6 100644
--- a/Annotation.cpp
+++ b/Annotation.cpp
@@ -84,24 +84,17 @@
const std::string& name, std::vector<ConstantExpression*>* values)
: AnnotationParam(name), mValues(values) {}
-std::string convertToString(const ConstantExpression* value) {
- if (value->descriptionIsTrivial()) {
- return value->value();
- }
- return value->value() + " /* " + value->description() + " */";
-}
-
std::vector<std::string> ConstantExpressionAnnotationParam::getValues() const {
std::vector<std::string> ret;
for (const auto* value : *mValues) {
- ret.push_back(convertToString(value));
+ ret.push_back(value->value());
};
return ret;
}
std::string ConstantExpressionAnnotationParam::getSingleValue() const {
CHECK_EQ(mValues->size(), 1u) << mName << " requires one value but has multiple";
- return convertToString(mValues->at(0));
+ return mValues->at(0)->value();
}
std::vector<const ConstantExpression*> ConstantExpressionAnnotationParam::getConstantExpressions()
diff --git a/ArrayType.cpp b/ArrayType.cpp
index 5155a27..ec849bc 100644
--- a/ArrayType.cpp
+++ b/ArrayType.cpp
@@ -80,7 +80,7 @@
status_t ArrayType::validate() const {
CHECK(!mElementType->isArray());
- if (mElementType->isBinder()) {
+ if (mElementType->isInterface()) {
std::cerr << "ERROR: Arrays of interface types are not supported"
<< " at " << mElementType.location() << "\n";
@@ -97,14 +97,7 @@
std::string arrayType = space + "hidl_array<" + base;
for (size_t i = 0; i < mSizes.size(); ++i) {
- arrayType += ", ";
- arrayType += mSizes[i]->cppValue();
-
- if (!mSizes[i]->descriptionIsTrivial()) {
- arrayType += " /* ";
- arrayType += mSizes[i]->description();
- arrayType += " */";
- }
+ arrayType += ", " + mSizes[i]->cppValue();
}
arrayType += ">";
@@ -142,12 +135,8 @@
if (forInitializer) {
base += mSizes[i]->javaValue();
- }
-
- if (!forInitializer || !mSizes[i]->descriptionIsTrivial()) {
- if (forInitializer)
- base += " ";
- base += "/* " + mSizes[i]->description() + " */";
+ } else {
+ base += "/* " + mSizes[i]->expression() + " */";
}
base += "]";
@@ -156,10 +145,6 @@
return base;
}
-std::string ArrayType::getJavaWrapperType() const {
- return mElementType->getJavaWrapperType();
-}
-
std::string ArrayType::getVtsType() const {
return "TYPE_ARRAY";
}
@@ -366,7 +351,8 @@
out << streamName << ".append(java.util.Arrays."
<< (countDimensions() > 1 ? "deepToString" : "toString")
<< "("
- << name << "));\n";
+ << name
+ << "));\n";
}
@@ -434,15 +420,17 @@
void ArrayType::emitJavaFieldInitializer(
Formatter &out, const std::string &fieldName) const {
- std::string typeName = getJavaType(false /* forInitializer */);
- std::string initName = getJavaType(true /* forInitializer */);
+ const std::string typeName = getJavaType(false /* forInitializer */);
+ const std::string fieldDeclaration = typeName + " " + fieldName;
- out << "final "
- << typeName
- << " "
- << fieldName
+ emitJavaFieldDefaultInitialValue(out, fieldDeclaration);
+}
+
+void ArrayType::emitJavaFieldDefaultInitialValue(
+ Formatter &out, const std::string &declaredFieldName) const {
+ out << declaredFieldName
<< " = new "
- << initName
+ << getJavaType(true /* forInitializer */)
<< ";\n";
}
@@ -488,15 +476,13 @@
indexString += "[" + iteratorName + "]";
}
- if (isReader && mElementType->isCompoundType()) {
- std::string typeName =
- mElementType->getJavaType(false /* forInitializer */);
+ const bool isIndexed = (loopDimensions > 0);
+ const std::string fieldNameWithCast = isIndexed
+ ? "(" + getJavaTypeCast(fieldName) + ")" + indexString
+ : getJavaTypeCast(fieldName);
- out << fieldName
- << indexString
- << " = new "
- << typeName
- << "();\n";
+ if (isReader && mElementType->isCompoundType()) {
+ mElementType->emitJavaFieldDefaultInitialValue(out, fieldNameWithCast);
}
if (!isPrimitiveArray) {
@@ -505,7 +491,7 @@
depth + 1,
parcelName,
blobName,
- fieldName + indexString,
+ fieldNameWithCast,
offsetName,
isReader);
@@ -521,20 +507,43 @@
<< "Array("
<< offsetName
<< ", "
- << fieldName
- << indexString
+ << fieldNameWithCast
<< ", "
<< mSizes.back()->javaValue()
<< " /* size */);\n";
} else {
+ std::string elemName = "_hidl_array_item_" + std::to_string(depth);
+
+ out << mElementType->getJavaType(false /* forInitializer */)
+ << "[] "
+ << elemName
+ << " = "
+ << fieldNameWithCast
+ << ";\n\n";
+
+ out << "if ("
+ << elemName
+ << " == null || "
+ << elemName
+ << ".length != "
+ << mSizes.back()->javaValue()
+ << ") {\n";
+
+ out.indent();
+
+ out << "throw new IllegalArgumentException("
+ << "\"Array element is not of the expected length\");\n";
+
+ out.unindent();
+ out << "}\n\n";
+
out << blobName
<< ".put"
<< mElementType->getJavaSuffix()
<< "Array("
<< offsetName
<< ", "
- << fieldName
- << indexString
+ << elemName
<< ");\n";
}
@@ -560,7 +569,7 @@
void ArrayType::emitVtsTypeDeclarations(Formatter& out) const {
out << "type: " << getVtsType() << "\n";
- out << "vector_size: " << mSizes[0]->value() << "\n";
+ out << "vector_size: " << mSizes[0]->rawValue() << "\n";
out << "vector_value: {\n";
out.indent();
// Simple array case.
@@ -569,7 +578,7 @@
} else { // Multi-dimension array case.
for (size_t index = 1; index < mSizes.size(); index++) {
out << "type: " << getVtsType() << "\n";
- out << "vector_size: " << mSizes[index]->value() << "\n";
+ out << "vector_size: " << mSizes[index]->rawValue() << "\n";
out << "vector_value: {\n";
out.indent();
if (index == mSizes.size() - 1) {
diff --git a/ArrayType.h b/ArrayType.h
index 2c13a33..2ced071 100644
--- a/ArrayType.h
+++ b/ArrayType.h
@@ -56,8 +56,6 @@
std::string getJavaType(bool forInitializer) const override;
- std::string getJavaWrapperType() const override;
-
std::string getVtsType() const override;
void emitReaderWriter(
@@ -121,6 +119,9 @@
void emitJavaFieldInitializer(
Formatter &out, const std::string &fieldName) const override;
+ void emitJavaFieldDefaultInitialValue(
+ Formatter &out, const std::string &declaredFieldName) const override;
+
void emitJavaFieldReaderWriter(
Formatter &out,
size_t depth,
diff --git a/CompoundType.cpp b/CompoundType.cpp
index 87f0f14..6f75d7c 100644
--- a/CompoundType.cpp
+++ b/CompoundType.cpp
@@ -17,6 +17,7 @@
#include "CompoundType.h"
#include "ArrayType.h"
+#include "ScalarType.h"
#include "VectorType.h"
#include <android-base/logging.h>
@@ -28,7 +29,7 @@
CompoundType::CompoundType(Style style, const char* localName, const FQName& fullName,
const Location& location, Scope* parent)
- : Scope(localName, fullName, location, parent), mStyle(style), mFields(NULL) {}
+ : Scope(localName, fullName, location, parent), mStyle(style), mFields(nullptr) {}
CompoundType::Style CompoundType::style() const {
return mStyle;
@@ -49,12 +50,18 @@
const Type& type = field->type();
if ((type.isVector() && static_cast<const VectorType*>(&type)->isVectorOfBinders())) {
- std::cerr << "ERROR: Struct/Union must not contain references to interfaces at "
+ std::cerr << "ERROR: Struct/union cannot contain vectors of interfaces at "
<< field->location() << "\n";
return UNKNOWN_ERROR;
}
if (mStyle == STYLE_UNION) {
+ if (type.isInterface()) {
+ std::cerr << "ERROR: Union cannot contain interfaces at " << field->location()
+ << "\n";
+ return UNKNOWN_ERROR;
+ }
+
if (type.needsEmbeddedReadWrite()) {
std::cerr << "ERROR: Union must not contain any types that need fixup at "
<< field->location() << "\n";
@@ -63,9 +70,18 @@
}
}
+ if (mStyle == STYLE_SAFE_UNION && mFields->size() < 2) {
+ std::cerr << "ERROR: Safe union must contain at least two types to be useful at "
+ << location() << "\n";
+ return UNKNOWN_ERROR;
+ }
+
status_t err = validateUniqueNames();
if (err != OK) return err;
+ err = validateSubTypeNames();
+ if (err != OK) return err;
+
return Scope::validate();
}
@@ -84,6 +100,29 @@
return OK;
}
+void CompoundType::emitInvalidSubTypeNamesError(const std::string& subTypeName,
+ const Location& location) const {
+ std::cerr << "ERROR: Type name '" << subTypeName << "' defined at "
+ << location << " conflicts with a member function of "
+ << "safe_union " << localName() << ". Consider renaming or "
+ << "moving its definition outside the safe_union scope.\n";
+}
+
+status_t CompoundType::validateSubTypeNames() const {
+ if (mStyle != STYLE_SAFE_UNION) { return OK; }
+ const auto& subTypes = Scope::getSubTypes();
+
+ for (const auto& subType : subTypes) {
+ if (subType->localName() == "getDiscriminator") {
+ emitInvalidSubTypeNamesError(subType->localName(),
+ subType->location());
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ return OK;
+}
+
bool CompoundType::isCompoundType() const {
return true;
}
@@ -108,6 +147,9 @@
case STYLE_UNION: {
return "union " + localName();
}
+ case STYLE_SAFE_UNION: {
+ return "safe_union " + localName();
+ }
}
CHECK(!"Should not be here");
}
@@ -127,6 +169,7 @@
case StorageMode_Result:
return base + (containsInterface()?"":"*");
}
+ CHECK(!"Should not be here");
}
std::string CompoundType::getJavaType(bool /* forInitializer */) const {
@@ -143,6 +186,10 @@
{
return "TYPE_UNION";
}
+ case STYLE_SAFE_UNION:
+ {
+ return "TYPE_SAFE_UNION";
+ }
}
CHECK(!"Should not be here");
}
@@ -163,6 +210,108 @@
return false;
}
+void CompoundType::emitSafeUnionUnknownDiscriminatorError(Formatter& out, const std::string& value,
+ bool fatal) const {
+ if (fatal) {
+ out << "::android::hardware::details::logAlwaysFatal(";
+ } else {
+ out << "ALOGE(\"%s\", ";
+ }
+ out << "(\n";
+ out.indent(2, [&] {
+ out << "\"Unknown union discriminator (value: \" +\n"
+ << "std::to_string(" << getUnionDiscriminatorType()->getCppTypeCast(value)
+ << ") + \").\").c_str());\n";
+ });
+}
+
+void CompoundType::emitSafeUnionReaderWriterForInterfaces(
+ Formatter &out,
+ const std::string &name,
+ const std::string &parcelObj,
+ bool parcelObjIsPointer,
+ bool isReader,
+ ErrorMode mode) const {
+
+ CHECK(mStyle == STYLE_SAFE_UNION);
+
+ out.block([&] {
+ const auto discriminatorType = getUnionDiscriminatorType();
+ if (isReader) {
+ out << discriminatorType->getCppStackType()
+ << " _hidl_d_primitive;\n";
+ } else {
+ out << "const "
+ << discriminatorType->getCppStackType()
+ << " _hidl_d_primitive = "
+ << discriminatorType->getCppTypeCast(name + ".getDiscriminator()")
+ << ";\n";
+ }
+
+ getUnionDiscriminatorType()->emitReaderWriter(out, "_hidl_d_primitive", parcelObj,
+ parcelObjIsPointer, isReader, mode);
+ out << "switch (("
+ << fullName()
+ << "::hidl_discriminator) _hidl_d_primitive) ";
+
+ out.block([&] {
+ for (const auto& field : *mFields) {
+ out << "case "
+ << fullName()
+ << "::hidl_discriminator::"
+ << field->name()
+ << ": ";
+
+ const std::string tempFieldName = "_hidl_temp_" + field->name();
+ out.block([&] {
+ if (isReader) {
+ out << field->type().getCppResultType()
+ << " "
+ << tempFieldName
+ << ";\n";
+
+ field->type().emitReaderWriter(out, tempFieldName, parcelObj,
+ parcelObjIsPointer, isReader, mode);
+
+ const std::string derefOperator = field->type().resultNeedsDeref()
+ ? "*" : "";
+ out << name
+ << "."
+ << field->name()
+ << "(std::move("
+ << derefOperator
+ << tempFieldName
+ << "));\n";
+ } else {
+ const std::string fieldValue = name + "." + field->name() + "()";
+ out << field->type().getCppArgumentType()
+ << " "
+ << tempFieldName
+ << " = "
+ << fieldValue
+ << ";\n";
+
+ field->type().emitReaderWriter(out, tempFieldName, parcelObj,
+ parcelObjIsPointer, isReader, mode);
+ }
+ out << "break;\n";
+ }).endl();
+ }
+
+ out << "default: ";
+ out.block([&] {
+ emitSafeUnionUnknownDiscriminatorError(out, "_hidl_d_primitive",
+ !isReader /*fatal*/);
+ if (isReader) {
+ out << "_hidl_err = BAD_VALUE;\n";
+ handleError(out, mode);
+ }
+ })
+ .endl();
+ }).endl();
+ }).endl();
+}
+
void CompoundType::emitReaderWriter(
Formatter &out,
const std::string &name,
@@ -175,9 +324,44 @@
parcelObj + (parcelObjIsPointer ? "->" : ".");
if(containsInterface()){
+ if (mStyle == STYLE_SAFE_UNION) {
+ emitSafeUnionReaderWriterForInterfaces(out, name, parcelObj,
+ parcelObjIsPointer,
+ isReader, mode);
+ return;
+ }
+
for (const auto& field : *mFields) {
- field->type().emitReaderWriter(out, name + "." + field->name(),
- parcelObj, parcelObjIsPointer, isReader, mode);
+ const std::string tempFieldName = "_hidl_temp_" + field->name();
+ const std::string fieldValue = name + "." + field->name();
+
+ out.block([&] {
+ if (isReader) {
+ out << field->type().getCppResultType()
+ << " "
+ << tempFieldName
+ << ";\n";
+ } else {
+ out << field->type().getCppArgumentType()
+ << " "
+ << tempFieldName
+ << " = "
+ << fieldValue
+ << ";\n";
+ }
+
+ field->type().emitReaderWriter(out, tempFieldName, parcelObj,
+ parcelObjIsPointer, isReader, mode);
+ if (isReader) {
+ const std::string derefOperator = field->type().resultNeedsDeref()
+ ? "*" : "";
+ out << fieldValue
+ << " = std::move("
+ << derefOperator
+ << tempFieldName
+ << ");\n";
+ }
+ }).endl();
}
} else {
const std::string parentName = "_hidl_" + name + "_parent";
@@ -202,10 +386,11 @@
<< ");\n";
handleError(out, mode);
}
- if (mStyle != STYLE_STRUCT) {
- return;
- }
- if (needsEmbeddedReadWrite()) {
+
+ bool needEmbeddedReadWrite = needsEmbeddedReadWrite();
+ CHECK(mStyle != STYLE_UNION || !needEmbeddedReadWrite);
+
+ if (needEmbeddedReadWrite) {
emitReaderWriterEmbedded(out, 0 /* depth */, name, name, /* sanitizedName */
isReader /* nameIsPointer */, parcelObj, parcelObjIsPointer,
isReader, mode, parentName, "0 /* parentOffset */");
@@ -249,20 +434,19 @@
out << "new " << fullJavaName() << "();\n";
}
- out << argName
- << "."
- << (isReader ? "readFromParcel" : "writeToParcel")
- << "("
- << parcelObj
- << ");\n";
+ out << "(" << getJavaTypeCast(argName) << ")."
+ << (isReader ? "readFromParcel" : "writeToParcel") << "(" << parcelObj << ");\n";
}
void CompoundType::emitJavaFieldInitializer(
Formatter &out, const std::string &fieldName) const {
- out << "final "
- << fullJavaName()
- << " "
- << fieldName
+ const std::string fieldDeclaration = fullJavaName() + " " + fieldName;
+ emitJavaFieldDefaultInitialValue(out, fieldDeclaration);
+}
+
+void CompoundType::emitJavaFieldDefaultInitialValue(
+ Formatter &out, const std::string &declaredFieldName) const {
+ out << declaredFieldName
<< " = new "
<< fullJavaName()
<< "();\n";
@@ -277,8 +461,9 @@
const std::string &offset,
bool isReader) const {
if (isReader) {
- out << fieldName
- << ".readEmbeddedFromParcel("
+ out << "("
+ << getJavaTypeCast(fieldName)
+ << ").readEmbeddedFromParcel("
<< parcelName
<< ", "
<< blobName
@@ -374,7 +559,164 @@
handleError(out, mode);
}
+void CompoundType::emitLayoutAsserts(Formatter& out, const Layout& layout,
+ const std::string& layoutName) const {
+ out << "static_assert(sizeof("
+ << fullName()
+ << layoutName
+ << ") == "
+ << layout.size
+ << ", \"wrong size\");\n";
+
+ out << "static_assert(__alignof("
+ << fullName()
+ << layoutName
+ << ") == "
+ << layout.align
+ << ", \"wrong alignment\");\n";
+}
+
+void CompoundType::emitSafeUnionTypeDeclarations(Formatter& out) const {
+ out << "struct "
+ << localName()
+ << " final {\n";
+
+ out.indent();
+
+ Scope::emitTypeDeclarations(out);
+
+ bool hasPointer = containsPointer();
+ CompoundLayout layout = hasPointer
+ ? CompoundLayout()
+ : getCompoundAlignmentAndSize();
+
+ out << "enum class hidl_discriminator : "
+ << getUnionDiscriminatorType()->getCppType(StorageMode_Stack, false)
+ << " ";
+
+ out.block([&] {
+ const auto elements = getSafeUnionEnumElements(true /* useCppTypeName */);
+ for (size_t i = 0; i < elements.size(); i++) {
+ out << elements[i].fieldName
+ << " = "
+ << i
+ << ",";
+
+ if (!elements[i].fieldTypeName.empty()) {
+ out << " // "
+ << elements[i].fieldTypeName;
+ }
+ out << "\n";
+ }
+ });
+ out << ";\n\n";
+
+ out << localName() << "();\n" // Constructor
+ << "~" << localName() << "();\n" // Destructor
+ << localName() << "(" << localName() << "&&);\n" // Move constructor
+ << localName() << "(const " << localName() << "&);\n" // Copy constructor
+ << localName() << "& operator=(" << localName() << "&&);\n" // Move assignment
+ << localName() << "& operator=(const " << localName() << "&);\n\n"; // Copy assignment
+
+ for (const auto& field : *mFields) {
+ // Setter (copy)
+ out << "void "
+ << field->name()
+ << "("
+ << field->type().getCppArgumentType()
+ << ");\n";
+
+ if (field->type().resolveToScalarType() == nullptr) {
+ // Setter (move)
+ out << "void "
+ << field->name()
+ << "("
+ << field->type().getCppStackType()
+ << "&&);\n";
+ }
+
+ // Getter (mutable)
+ out << field->type().getCppStackType()
+ << "& "
+ << field->name()
+ << "();\n";
+
+ // Getter (immutable)
+ out << field->type().getCppArgumentType()
+ << " "
+ << field->name()
+ << "() const;\n\n";
+ }
+
+ out << "// Utility methods\n";
+ out << "hidl_discriminator getDiscriminator() const;\n\n";
+
+ out << "constexpr size_t hidl_getUnionOffset() const ";
+ out.block([&] {
+ out << "return offsetof(" << fullName() << ", hidl_u);\n";
+ }).endl().endl();
+
+ out.unindent();
+ out << "private:\n";
+ out.indent();
+
+ out << "void hidl_destructUnion();\n\n";
+
+ out << "hidl_discriminator hidl_d";
+ if (!hasPointer) {
+ out << " __attribute__ ((aligned("
+ << layout.discriminator.align << "))) ";
+ }
+ out << ";\n";
+ out << "union hidl_union final {\n";
+ out.indent();
+
+ for (const auto& field : *mFields) {
+
+ size_t fieldAlign, fieldSize;
+ field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
+
+ out << field->type().getCppStackType()
+ << " "
+ << field->name();
+
+ if (!hasPointer) {
+ out << " __attribute__ ((aligned("
+ << fieldAlign
+ << ")))";
+ }
+ out << ";\n";
+ }
+
+ out << "\n"
+ << "hidl_union();\n"
+ << "~hidl_union();\n";
+
+ out.unindent();
+ out << "} hidl_u;\n";
+
+ if (!hasPointer) {
+ out << "\n";
+
+ emitLayoutAsserts(out, layout.innerStruct, "::hidl_union");
+ emitLayoutAsserts(out, layout.discriminator, "::hidl_discriminator");
+ }
+
+ out.unindent();
+ out << "};\n\n";
+
+ if (!hasPointer) {
+ emitLayoutAsserts(out, layout.overall, "");
+ out << "\n";
+ }
+}
+
void CompoundType::emitTypeDeclarations(Formatter& out) const {
+ if (mStyle == STYLE_SAFE_UNION) {
+ emitSafeUnionTypeDeclarations(out);
+ return;
+ }
+
out << ((mStyle == STYLE_STRUCT) ? "struct" : "union")
<< " "
<< localName()
@@ -405,10 +747,7 @@
size_t fieldAlign, fieldSize;
field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
- size_t pad = offset % fieldAlign;
- if (pad > 0) {
- offset += fieldAlign - pad;
- }
+ offset += Layout::getPad(offset, fieldAlign);
if (pass == 0) {
out << field->type().getCppStackType()
@@ -438,24 +777,27 @@
}
}
- size_t structAlign, structSize;
- getAlignmentAndSize(&structAlign, &structSize);
-
- out << "static_assert(sizeof("
- << fullName()
- << ") == "
- << structSize
- << ", \"wrong size\");\n";
-
- out << "static_assert(__alignof("
- << fullName()
- << ") == "
- << structAlign
- << ", \"wrong alignment\");\n\n";
+ CompoundLayout layout = getCompoundAlignmentAndSize();
+ emitLayoutAsserts(out, layout.overall, "");
+ out << "\n";
}
void CompoundType::emitTypeForwardDeclaration(Formatter& out) const {
- out << ((mStyle == STYLE_STRUCT) ? "struct" : "union") << " " << localName() << ";\n";
+ switch (mStyle) {
+ case STYLE_UNION: {
+ out << "union";
+ break;
+ }
+ case STYLE_STRUCT:
+ case STYLE_SAFE_UNION: {
+ out << "struct";
+ break;
+ }
+ default: {
+ CHECK(!"Should not be here");
+ }
+ }
+ out << " " << localName() << ";\n";
}
void CompoundType::emitPackageTypeDeclarations(Formatter& out) const {
@@ -464,6 +806,27 @@
out << "static inline std::string toString("
<< getCppArgumentType()
<< (mFields->empty() ? "" : " o")
+ << ");\n";
+
+ if (canCheckEquality()) {
+ out << "static inline bool operator==("
+ << getCppArgumentType() << " lhs, " << getCppArgumentType() << " rhs);\n";
+
+ out << "static inline bool operator!=("
+ << getCppArgumentType() << " lhs, " << getCppArgumentType() << " rhs);\n";
+ } else {
+ out << "// operator== and operator!= are not generated for " << localName() << "\n";
+ }
+
+ out.endl();
+}
+
+void CompoundType::emitPackageTypeHeaderDefinitions(Formatter& out) const {
+ Scope::emitPackageTypeHeaderDefinitions(out);
+
+ out << "static inline std::string toString("
+ << getCppArgumentType()
+ << (mFields->empty() ? "" : " o")
<< ") ";
out.block([&] {
@@ -472,15 +835,49 @@
<< "std::string os;\n";
out << "os += \"{\";\n";
- for (const NamedReference<Type>* field : *mFields) {
- out << "os += \"";
- if (field != *(mFields->begin())) {
- out << ", ";
- }
- out << "." << field->name() << " = \";\n";
- field->type().emitDump(out, "os", "o." + field->name());
+ if (mStyle == STYLE_SAFE_UNION) {
+ out << "\nswitch (o.getDiscriminator()) {\n";
+ out.indent();
}
+ for (const NamedReference<Type>* field : *mFields) {
+ if (mStyle == STYLE_SAFE_UNION) {
+ out << "case "
+ << fullName()
+ << "::hidl_discriminator::"
+ << field->name()
+ << ": ";
+
+ out.block([&] {
+ out << "os += \"."
+ << field->name()
+ << " = \";\n"
+ << "os += toString(o."
+ << field->name()
+ << "());\n"
+ << "break;\n";
+ }).endl();
+ } else {
+ out << "os += \"";
+ if (field != *(mFields->begin())) {
+ out << ", ";
+ }
+ out << "." << field->name() << " = \";\n";
+ field->type().emitDump(out, "os", "o." + field->name());
+ }
+ }
+
+ if (mStyle == STYLE_SAFE_UNION) {
+ out << "default: ";
+ out.block([&] {
+ emitSafeUnionUnknownDiscriminatorError(out, "o.getDiscriminator()",
+ true /*fatal*/);
+ })
+ .endl();
+
+ out.unindent();
+ out << "}\n";
+ }
out << "os += \"}\"; return os;\n";
}).endl().endl();
@@ -489,16 +886,53 @@
<< getCppArgumentType() << " " << (mFields->empty() ? "/* lhs */" : "lhs") << ", "
<< getCppArgumentType() << " " << (mFields->empty() ? "/* rhs */" : "rhs") << ") ";
out.block([&] {
- for (const auto &field : *mFields) {
- out.sIf("lhs." + field->name() + " != rhs." + field->name(), [&] {
+ if (mStyle == STYLE_SAFE_UNION) {
+ out.sIf("lhs.getDiscriminator() != rhs.getDiscriminator()", [&] {
out << "return false;\n";
}).endl();
+
+ out << "switch (lhs.getDiscriminator()) {\n";
+ out.indent();
+ }
+
+ for (const auto& field : *mFields) {
+ if (mStyle == STYLE_SAFE_UNION) {
+ out << "case "
+ << fullName()
+ << "::hidl_discriminator::"
+ << field->name()
+ << ": ";
+
+ out.block([&] {
+ out << "return (lhs."
+ << field->name()
+ << "() == rhs."
+ << field->name()
+ << "());\n";
+ }).endl();
+ } else {
+ out.sIf("lhs." + field->name() + " != rhs." + field->name(), [&] {
+ out << "return false;\n";
+ }).endl();
+ }
+ }
+
+ if (mStyle == STYLE_SAFE_UNION) {
+ out << "default: ";
+ out.block([&] {
+ emitSafeUnionUnknownDiscriminatorError(out, "lhs.getDiscriminator()",
+ true /*fatal*/);
+ })
+ .endl();
+
+ out.unindent();
+ out << "}\n";
}
out << "return true;\n";
}).endl().endl();
out << "static inline bool operator!=("
- << getCppArgumentType() << " lhs," << getCppArgumentType() << " rhs)";
+ << getCppArgumentType() << " lhs, " << getCppArgumentType() << " rhs)";
out.block([&] {
out << "return !(lhs == rhs);\n";
}).endl().endl();
@@ -548,6 +982,327 @@
}
}
+static void emitSafeUnionFieldConstructor(Formatter& out,
+ const NamedReference<Type>* field,
+ const std::string& initializerObjectName) {
+ out << "new (&hidl_u."
+ << field->name()
+ << ") "
+ << field->type().getCppStackType()
+ << "("
+ << initializerObjectName
+ << ");\n";
+}
+
+static void emitSafeUnionSetterDefinition(Formatter& out,
+ const NamedReference<Type>* field,
+ const std::string& parameterName,
+ bool usesMoveSemantics) {
+ out.block([&] {
+ out << "if (hidl_d != hidl_discriminator::"
+ << field->name()
+ << ") ";
+
+ const std::string argumentName = usesMoveSemantics
+ ? ("std::move(" + parameterName + ")")
+ : parameterName;
+ out.block([&] {
+ out << "hidl_destructUnion();\n"
+ << "::std::memset(&hidl_u, 0, sizeof(hidl_u));\n\n";
+
+ emitSafeUnionFieldConstructor(out, field, argumentName);
+ out << "hidl_d = hidl_discriminator::"
+ << field->name()
+ << ";\n";
+ }).endl();
+
+ out << "else if (&(hidl_u."
+ << field->name()
+ << ") != &"
+ << parameterName
+ << ") ";
+
+ out.block([&] {
+ out << "hidl_u."
+ << field->name()
+ << " = "
+ << argumentName
+ << ";\n";
+ }).endl();
+ }).endl().endl();
+}
+
+static void emitSafeUnionGetterDefinition(Formatter& out, const std::string& fieldName) {
+ out.block([&] {
+ out << "if (CC_UNLIKELY(hidl_d != hidl_discriminator::"
+ << fieldName
+ << ")) ";
+
+ out.block([&] {
+ out << "LOG_ALWAYS_FATAL(\"Bad safe_union access: safe_union has discriminator %\" "
+ << "PRIu64 \" but discriminator %\" PRIu64 \" was accessed.\",\n";
+ out.indent(2, [&] {
+ out << "static_cast<uint64_t>(hidl_d), "
+ << "static_cast<uint64_t>(hidl_discriminator::" << fieldName << "));";
+ }).endl();
+ }).endl().endl();
+
+ out << "return hidl_u."
+ << fieldName
+ << ";\n";
+ }).endl().endl();
+}
+
+std::vector<CompoundType::SafeUnionEnumElement> CompoundType::getSafeUnionEnumElements(
+ bool useCppTypeName) const {
+ std::vector<SafeUnionEnumElement> elements;
+
+ for (const auto& field : *mFields) {
+ const std::string fieldTypeName = useCppTypeName
+ ? field->type().getCppStackType(true /* specifyNamespaces */)
+ : field->type().getJavaType(true /* forInitializer */);
+
+ elements.push_back({field->name(), fieldTypeName});
+ }
+
+ return elements;
+}
+
+void CompoundType::emitSafeUnionCopyAndAssignDefinition(Formatter& out,
+ const std::string& parameterName,
+ bool isCopyConstructor,
+ bool usesMoveSemantics) const {
+ out.block([&] {
+ if (!isCopyConstructor) {
+ out << "if (this == &"
+ << parameterName
+ << ") { return *this; }\n\n";
+ }
+
+ out << "switch ("
+ << parameterName
+ << ".hidl_d) ";
+
+ out.block([&] {
+ for (const auto& field : *mFields) {
+ const std::string parameterFieldName = (parameterName + ".hidl_u." +
+ field->name());
+
+ const std::string argumentName = usesMoveSemantics
+ ? ("std::move(" + parameterFieldName + ")")
+ : parameterFieldName;
+
+ out << "case hidl_discriminator::"
+ << field->name()
+ << ": ";
+
+ if (isCopyConstructor) {
+ out.block([&] {
+ emitSafeUnionFieldConstructor(out, field, argumentName);
+ out << "break;\n";
+ }).endl();
+ } else {
+ out.block([&] {
+ out << field->name()
+ << "("
+ << argumentName
+ << ");\n"
+ << "break;\n";
+ }).endl();
+ }
+ }
+
+ out << "default: ";
+ out.block([&] {
+ emitSafeUnionUnknownDiscriminatorError(out, parameterName + ".hidl_d",
+ true /*fatal*/);
+ })
+ .endl();
+ }).endl();
+
+ if (isCopyConstructor) {
+ out << "\nhidl_d = "
+ << parameterName
+ << ".hidl_d;\n";
+ } else {
+ out << "return *this;\n";
+ }
+ }).endl().endl();
+}
+
+void CompoundType::emitSafeUnionTypeConstructors(Formatter& out) const {
+
+ // Default constructor
+ out << fullName()
+ << "::"
+ << localName()
+ << "() ";
+
+ out.block([&] {
+ out << "static_assert(offsetof("
+ << fullName()
+ << ", hidl_d) == 0, \"wrong offset\");\n";
+
+ if (!containsPointer()) {
+ CompoundLayout layout = getCompoundAlignmentAndSize();
+ out << "static_assert(offsetof("
+ << fullName()
+ << ", hidl_u) == "
+ << layout.innerStruct.offset
+ << ", \"wrong offset\");\n";
+ }
+ out.endl();
+
+ CHECK(!mFields->empty());
+ out << "hidl_d = hidl_discriminator::" << mFields->at(0)->name() << ";\n";
+ emitSafeUnionFieldConstructor(out, mFields->at(0), "");
+ }).endl().endl();
+
+ // Destructor
+ out << fullName()
+ << "::~"
+ << localName()
+ << "() ";
+
+ out.block([&] {
+ out << "hidl_destructUnion();\n";
+ }).endl().endl();
+
+ // Move constructor
+ out << fullName()
+ << "::"
+ << localName()
+ << "("
+ << localName()
+ << "&& other) ";
+
+ emitSafeUnionCopyAndAssignDefinition(
+ out, "other", true /* isCopyConstructor */, true /* usesMoveSemantics */);
+
+ // Copy constructor
+ out << fullName()
+ << "::"
+ << localName()
+ << "(const "
+ << localName()
+ << "& other) ";
+
+ emitSafeUnionCopyAndAssignDefinition(
+ out, "other", true /* isCopyConstructor */, false /* usesMoveSemantics */);
+
+ // Move assignment operator
+ out << fullName()
+ << "& ("
+ << fullName()
+ << "::operator=)("
+ << localName()
+ << "&& other) ";
+
+ emitSafeUnionCopyAndAssignDefinition(
+ out, "other", false /* isCopyConstructor */, true /* usesMoveSemantics */);
+
+ // Copy assignment operator
+ out << fullName()
+ << "& ("
+ << fullName()
+ << "::operator=)(const "
+ << localName()
+ << "& other) ";
+
+ emitSafeUnionCopyAndAssignDefinition(
+ out, "other", false /* isCopyConstructor */, false /* usesMoveSemantics */);
+}
+
+void CompoundType::emitSafeUnionTypeDefinitions(Formatter& out) const {
+ emitSafeUnionTypeConstructors(out);
+
+ out << "void "
+ << fullName()
+ << "::hidl_destructUnion() ";
+
+ out.block([&] {
+ out << "switch (hidl_d) ";
+ out.block([&] {
+
+ for (const auto& field : *mFields) {
+ out << "case hidl_discriminator::"
+ << field->name()
+ << ": ";
+
+ out.block([&] {
+ out << "::android::hardware::details::destructElement(&(hidl_u."
+ << field->name()
+ << "));\n"
+ << "break;\n";
+ }).endl();
+ }
+
+ out << "default: ";
+ out.block(
+ [&] { emitSafeUnionUnknownDiscriminatorError(out, "hidl_d", true /*fatal*/); })
+ .endl();
+ }).endl().endl();
+ }).endl().endl();
+
+ for (const NamedReference<Type>* field : *mFields) {
+ // Setter (copy)
+ out << "void "
+ << fullName()
+ << "::"
+ << field->name()
+ << "("
+ << field->type().getCppArgumentType()
+ << " o) ";
+
+ emitSafeUnionSetterDefinition(out, field, "o", false /* usesMoveSemantics */);
+
+ if (field->type().resolveToScalarType() == nullptr) {
+ // Setter (move)
+ out << "void "
+ << fullName()
+ << "::"
+ << field->name()
+ << "("
+ << field->type().getCppStackType()
+ << "&& o) ";
+
+ emitSafeUnionSetterDefinition(out, field, "o", true /* usesMoveSemantics */);
+ }
+
+ // Getter (mutable)
+ out << field->type().getCppStackType()
+ << "& ("
+ << fullName()
+ << "::"
+ << field->name()
+ << ")() ";
+
+ emitSafeUnionGetterDefinition(out, field->name());
+
+ // Getter (immutable)
+ out << field->type().getCppArgumentType()
+ << " ("
+ << fullName()
+ << "::"
+ << field->name()
+ << ")() const ";
+
+ emitSafeUnionGetterDefinition(out, field->name());
+ }
+
+ // Trivial constructor/destructor for internal union
+ out << fullName() << "::hidl_union::hidl_union() {}\n\n"
+ << fullName() << "::hidl_union::~hidl_union() {}\n\n";
+
+ // Utility method
+ out << fullName() << "::hidl_discriminator ("
+ << fullName() << "::getDiscriminator)() const ";
+
+ out.block([&] {
+ out << "return hidl_d;\n";
+ }).endl().endl();
+}
+
void CompoundType::emitTypeDefinitions(Formatter& out, const std::string& prefix) const {
std::string space = prefix.empty() ? "" : (prefix + "::");
Scope::emitTypeDefinitions(out, space + localName());
@@ -561,6 +1316,22 @@
emitResolveReferenceDef(out, prefix, true /* isReader */);
emitResolveReferenceDef(out, prefix, false /* isReader */);
}
+
+ if (mStyle == STYLE_SAFE_UNION) {
+ emitSafeUnionTypeDefinitions(out);
+ }
+}
+
+static void emitJavaSafeUnionUnknownDiscriminatorError(Formatter& out, bool fatal) {
+ out << "throw new ";
+
+ if (fatal) {
+ out << "Error";
+ } else {
+ out << "IllegalStateException";
+ }
+
+ out << "(\"Unknown union discriminator (value: \" + hidl_d + \").\");\n";
}
void CompoundType::emitJavaTypeDeclarations(Formatter& out, bool atTopLevel) const {
@@ -578,15 +1349,132 @@
Scope::emitJavaTypeDeclarations(out, false /* atTopLevel */);
- for (const auto& field : *mFields) {
- field->emitDocComment(out);
+ if (mStyle == STYLE_SAFE_UNION) {
+ out << "public " << localName() << "() ";
+ out.block([&] {
+ CHECK(!mFields->empty());
+ mFields->at(0)->type().emitJavaFieldDefaultInitialValue(out, "hidl_o");
+ }).endl().endl();
- out << "public ";
+ const std::string discriminatorStorageType = (
+ getUnionDiscriminatorType()->getJavaType(false));
- field->type().emitJavaFieldInitializer(out, field->name());
- }
+ out << "public static final class hidl_discriminator ";
+ out.block([&] {
+ const auto elements = getSafeUnionEnumElements(false /* useCppTypeName */);
+ for (size_t idx = 0; idx < elements.size(); idx++) {
+ out << "public static final "
+ << discriminatorStorageType
+ << " "
+ << elements[idx].fieldName
+ << " = "
+ << idx
+ << ";";
- if (!mFields->empty()) {
+ if (!elements[idx].fieldTypeName.empty()) {
+ out << " // "
+ << elements[idx].fieldTypeName;
+ }
+ out << "\n";
+ }
+
+ out << "\n"
+ << "public static final String getName("
+ << discriminatorStorageType
+ << " value) ";
+
+ out.block([&] {
+ out << "switch (value) ";
+ out.block([&] {
+ for (size_t idx = 0; idx < elements.size(); idx++) {
+ out << "case "
+ << idx
+ << ": { return \""
+ << elements[idx].fieldName
+ << "\"; }\n";
+ }
+ out << "default: { return \"Unknown\"; }\n";
+ }).endl();
+ }).endl().endl();
+
+ out << "private hidl_discriminator() {}\n";
+ }).endl().endl();
+
+ out << "private " << discriminatorStorageType << " hidl_d = 0;\n";
+ out << "private Object hidl_o = null;\n";
+
+ for (const auto& field : *mFields) {
+ // Setter
+ out << "public void "
+ << field->name()
+ << "("
+ << field->type().getJavaType(false)
+ << " "
+ << field->name()
+ << ") ";
+
+ out.block([&] {
+ out << "hidl_d = hidl_discriminator."
+ << field->name()
+ << ";\n";
+
+ out << "hidl_o = "
+ << field->name()
+ << ";\n";
+ }).endl().endl();
+
+ // Getter
+ out << "public "
+ << field->type().getJavaType(false)
+ << " "
+ << field->name()
+ << "() ";
+
+ out.block([&] {
+ out << "if (hidl_d != hidl_discriminator."
+ << field->name()
+ << ") ";
+
+ out.block([&] {
+ out << "String className = (hidl_o != null) ? "
+ << "hidl_o.getClass().getName() : \"null\";\n";
+
+ out << "throw new IllegalStateException(\n";
+ out.indent(2, [&] {
+ out << "\"Read access to inactive union components is disallowed. \" +\n"
+ << "\"Discriminator value is \" + hidl_d + \" (corresponding \" +\n"
+ << "\"to \" + hidl_discriminator.getName(hidl_d) + \"), and \" +\n"
+ << "\"hidl_o is of type \" + className + \".\");\n";
+ });
+ }).endl();
+
+ out << "if (hidl_o != null && !"
+ << field->type().getJavaTypeClass()
+ << ".class.isInstance(hidl_o)) ";
+
+ out.block([&] {
+ out << "throw new Error(\"Union is in a corrupted state.\");\n";
+ }).endl();
+
+ out << "return ("
+ << field->type().getJavaTypeCast("hidl_o")
+ << ");\n";
+ }).endl().endl();
+ }
+
+ out << "// Utility method\n"
+ << "public "
+ << discriminatorStorageType
+ << " getDiscriminator() { return hidl_d; }\n\n";
+
+ } else {
+ for (const auto& field : *mFields) {
+ field->emitDocComment(out);
+
+ out << "public ";
+ field->type().emitJavaFieldInitializer(out, field->name());
+ }
+
out << "\n";
}
@@ -606,14 +1494,24 @@
out << "return false;\n";
}).endl();
out << fullJavaName() << " other = (" << fullJavaName() << ")otherObject;\n";
- for (const auto &field : *mFields) {
- std::string condition = (field->type().isScalar() || field->type().isEnum())
- ? "this." + field->name() + " != other." + field->name()
- : ("!android.os.HidlSupport.deepEquals(this." + field->name()
- + ", other." + field->name() + ")");
- out.sIf(condition, [&] {
+
+ if (mStyle == STYLE_SAFE_UNION) {
+ out.sIf("this.hidl_d != other.hidl_d", [&] {
out << "return false;\n";
}).endl();
+ out.sIf("!android.os.HidlSupport.deepEquals(this.hidl_o, other.hidl_o)", [&] {
+ out << "return false;\n";
+ }).endl();
+ } else {
+ for (const auto &field : *mFields) {
+ std::string condition = (field->type().isScalar() || field->type().isEnum())
+ ? "this." + field->name() + " != other." + field->name()
+ : ("!android.os.HidlSupport.deepEquals(this." + field->name()
+ + ", other." + field->name() + ")");
+ out.sIf(condition, [&] {
+ out << "return false;\n";
+ }).endl();
+ }
}
out << "return true;\n";
}).endl().endl();
@@ -622,9 +1520,14 @@
out.block([&] {
out << "return java.util.Objects.hash(\n";
out.indent(2, [&] {
- out.join(mFields->begin(), mFields->end(), ", \n", [&] (const auto &field) {
- out << "android.os.HidlSupport.deepHashCode(this." << field->name() << ")";
- });
+ if (mStyle == STYLE_SAFE_UNION) {
+ out << "android.os.HidlSupport.deepHashCode(this.hidl_o),\n"
+ << "java.util.Objects.hashCode(this.hidl_d)";
+ } else {
+ out.join(mFields->begin(), mFields->end(), ", \n", [&] (const auto &field) {
+ out << "android.os.HidlSupport.deepHashCode(this." << field->name() << ")";
+ });
+ }
});
out << ");\n";
}).endl().endl();
@@ -638,32 +1541,96 @@
out.block([&] {
out << "java.lang.StringBuilder builder = new java.lang.StringBuilder();\n"
<< "builder.append(\"{\");\n";
- for (const auto &field : *mFields) {
- out << "builder.append(\"";
- if (field != *(mFields->begin())) {
- out << ", ";
- }
- out << "." << field->name() << " = \");\n";
- field->type().emitJavaDump(out, "builder", "this." + field->name());
+
+ if (mStyle == STYLE_SAFE_UNION) {
+ out << "switch (this.hidl_d) {\n";
+ out.indent();
}
+
+ for (const auto &field : *mFields) {
+ if (mStyle == STYLE_SAFE_UNION) {
+ out << "case hidl_discriminator."
+ << field->name()
+ << ": ";
+
+ out.block([&] {
+ out << "builder.append(\""
+ << "."
+ << field->name()
+ << " = \");\n";
+
+ field->type().emitJavaDump(out, "builder", "this." + field->name() + "()");
+ out << "break;\n";
+ }).endl();
+ }
+ else {
+ out << "builder.append(\"";
+ if (field != *(mFields->begin())) {
+ out << ", ";
+ }
+ out << "." << field->name() << " = \");\n";
+ field->type().emitJavaDump(out, "builder", "this." + field->name());
+ }
+ }
+
+ if (mStyle == STYLE_SAFE_UNION) {
+ out << "default: ";
+ out.block([&] { emitJavaSafeUnionUnknownDiscriminatorError(out, true /*fatal*/); })
+ .endl();
+
+ out.unindent();
+ out << "}\n";
+ }
+
out << "builder.append(\"}\");\nreturn builder.toString();\n";
}).endl().endl();
- size_t structAlign, structSize;
- getAlignmentAndSize(&structAlign, &structSize);
+ CompoundLayout layout = getCompoundAlignmentAndSize();
////////////////////////////////////////////////////////////////////////////
out << "public final void readFromParcel(android.os.HwParcel parcel) {\n";
out.indent();
if (containsInterface()) {
+
+ if (mStyle == STYLE_SAFE_UNION) {
+ out << "hidl_d = ";
+ getUnionDiscriminatorType()->emitJavaReaderWriter(
+ out, "parcel", "hidl_d", true);
+
+ out << "switch (hidl_d) {\n";
+ out.indent();
+ }
+
for (const auto& field : *mFields) {
- out << field->name() << " = ";
- field->type().emitJavaReaderWriter(out, "parcel", field->name(), true);
+ if (mStyle == STYLE_SAFE_UNION) {
+ out << "case hidl_discriminator."
+ << field->name()
+ << ": ";
+
+ out.block([&] {
+ out << "hidl_o = ";
+ field->type().emitJavaReaderWriter(out, "parcel", "hidl_o", true);
+
+ out << "break;\n";
+ }).endl();
+ } else {
+ out << field->name() << " = ";
+ field->type().emitJavaReaderWriter(out, "parcel", field->name(), true);
+ }
+ }
+
+ if (mStyle == STYLE_SAFE_UNION) {
+ out << "default: ";
+ out.block([&] { emitJavaSafeUnionUnknownDiscriminatorError(out, false /*fatal*/); })
+ .endl();
+
+ out.unindent();
+ out << "}\n";
}
} else {
out << "android.os.HwBlob blob = parcel.readBuffer(";
- out << structSize << "/* size */);\n";
+ out << layout.overall.size << " /* size */);\n";
out << "readEmbeddedFromParcel(parcel, blob, 0 /* parentOffset */);\n";
}
out.unindent();
@@ -708,20 +1675,52 @@
out.indent(2);
out << "android.os.HwParcel parcel, android.os.HwBlob _hidl_blob, long _hidl_offset) {\n";
out.unindent();
- size_t offset = 0;
+
+ if (mStyle == STYLE_SAFE_UNION) {
+ getUnionDiscriminatorType()->emitJavaFieldReaderWriter(
+ out, 0 /* depth */, "parcel", "_hidl_blob", "hidl_d",
+ "_hidl_offset + " + std::to_string(layout.discriminator.offset),
+ true /* isReader */);
+
+ out << "switch (this.hidl_d) {\n";
+ out.indent();
+ }
+
+ size_t offset = layout.innerStruct.offset;
for (const auto& field : *mFields) {
- size_t fieldAlign, fieldSize;
- field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
- size_t pad = offset % fieldAlign;
- if (pad > 0) {
- offset += fieldAlign - pad;
+ if (mStyle == STYLE_SAFE_UNION) {
+ out << "case hidl_discriminator."
+ << field->name()
+ << ": ";
+
+ out.block([&] {
+ field->type().emitJavaFieldDefaultInitialValue(out, "hidl_o");
+ field->type().emitJavaFieldReaderWriter(
+ out, 0 /* depth */, "parcel", "_hidl_blob", "hidl_o",
+ "_hidl_offset + " + std::to_string(offset), true /* isReader */);
+
+ out << "break;\n";
+ }).endl();
+ } else {
+ size_t fieldAlign, fieldSize;
+ field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
+
+ offset += Layout::getPad(offset, fieldAlign);
+ field->type().emitJavaFieldReaderWriter(
+ out, 0 /* depth */, "parcel", "_hidl_blob", field->name(),
+ "_hidl_offset + " + std::to_string(offset), true /* isReader */);
+ offset += fieldSize;
}
+ }
- field->type().emitJavaFieldReaderWriter(
- out, 0 /* depth */, "parcel", "_hidl_blob", field->name(),
- "_hidl_offset + " + std::to_string(offset), true /* isReader */);
- offset += fieldSize;
+ if (mStyle == STYLE_SAFE_UNION) {
+ out << "default: ";
+ out.block([&] { emitJavaSafeUnionUnknownDiscriminatorError(out, false /*fatal*/); })
+ .endl();
+
+ out.unindent();
+ out << "}\n";
}
out.unindent();
out << "}\n\n";
@@ -733,11 +1732,40 @@
out.indent();
if (containsInterface()) {
+ if (mStyle == STYLE_SAFE_UNION) {
+ getUnionDiscriminatorType()->emitJavaReaderWriter(
+ out, "parcel", "hidl_d", false);
+
+ out << "switch (this.hidl_d) {\n";
+ out.indent();
+ }
+
for (const auto& field : *mFields) {
- field->type().emitJavaReaderWriter(out, "parcel", field->name(), false);
+ if (mStyle == STYLE_SAFE_UNION) {
+ out << "case hidl_discriminator."
+ << field->name()
+ << ": ";
+
+ out.block([&] {
+ field->type().emitJavaReaderWriter(out, "parcel", field->name() + "()", false);
+ out << "break;\n";
+ }).endl();
+ } else {
+ field->type().emitJavaReaderWriter(out, "parcel", field->name(), false);
+ }
+ }
+
+ if (mStyle == STYLE_SAFE_UNION) {
+ out << "default: ";
+ out.block([&] { emitJavaSafeUnionUnknownDiscriminatorError(out, true /*fatal*/); })
+ .endl();
+
+ out.unindent();
+ out << "}\n";
}
} else {
- out << "android.os.HwBlob _hidl_blob = new android.os.HwBlob(" << structSize
+ out << "android.os.HwBlob _hidl_blob = new android.os.HwBlob("
+ << layout.overall.size
<< " /* size */);\n";
out << "writeEmbeddedToBlob(_hidl_blob, 0 /* parentOffset */);\n"
@@ -755,10 +1783,10 @@
if (containsInterface()) {
out << "parcel.writeInt32(_hidl_vec.size());\n";
- out << "for(" << fullJavaName() << " tmp: _hidl_vec)\n";
- out.indent();
- emitJavaReaderWriter(out, "parcel", "tmp", false);
- out.unindent();
+ out << "for(" << fullJavaName() << " tmp: _hidl_vec) ";
+ out.block([&] {
+ emitJavaReaderWriter(out, "parcel", "tmp", false);
+ }).endl();
} else {
out << "android.os.HwBlob _hidl_blob = new android.os.HwBlob(" << vecSize
<< " /* sizeof(hidl_vec<T>) */);\n";
@@ -774,26 +1802,57 @@
////////////////////////////////////////////////////////////////////////////
if (containsInterface()) {
- out << "// writeEmbeddedFromParcel() is not generated\n";
+ out << "// writeEmbeddedToBlob() is not generated\n";
} else {
out << "public final void writeEmbeddedToBlob(\n";
out.indent(2);
out << "android.os.HwBlob _hidl_blob, long _hidl_offset) {\n";
out.unindent();
- size_t offset = 0;
- for (const auto& field : *mFields) {
- size_t fieldAlign, fieldSize;
- field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
- size_t pad = offset % fieldAlign;
- if (pad > 0) {
- offset += fieldAlign - pad;
- }
- field->type().emitJavaFieldReaderWriter(
- out, 0 /* depth */, "parcel", "_hidl_blob", field->name(),
- "_hidl_offset + " + std::to_string(offset), false /* isReader */);
- offset += fieldSize;
+
+ if (mStyle == STYLE_SAFE_UNION) {
+ getUnionDiscriminatorType()->emitJavaFieldReaderWriter(
+ out, 0 /* depth */, "parcel", "_hidl_blob", "hidl_d",
+ "_hidl_offset + " + std::to_string(layout.discriminator.offset),
+ false /* isReader */);
+
+ out << "switch (this.hidl_d) {\n";
+ out.indent();
}
+ size_t offset = layout.innerStruct.offset;
+ for (const auto& field : *mFields) {
+ if (mStyle == STYLE_SAFE_UNION) {
+ out << "case hidl_discriminator."
+ << field->name()
+ << ": ";
+
+ out.block([&] {
+ field->type().emitJavaFieldReaderWriter(
+ out, 0 /* depth */, "parcel", "_hidl_blob", field->name() + "()",
+ "_hidl_offset + " + std::to_string(offset), false /* isReader */);
+
+ out << "break;\n";
+ }).endl();
+ } else {
+ size_t fieldAlign, fieldSize;
+ field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
+
+ offset += Layout::getPad(offset, fieldAlign);
+ field->type().emitJavaFieldReaderWriter(
+ out, 0 /* depth */, "parcel", "_hidl_blob", field->name(),
+ "_hidl_offset + " + std::to_string(offset), false /* isReader */);
+ offset += fieldSize;
+ }
+ }
+
+ if (mStyle == STYLE_SAFE_UNION) {
+ out << "default: ";
+ out.block([&] { emitJavaSafeUnionUnknownDiscriminatorError(out, true /*fatal*/); })
+ .endl();
+
+ out.unindent();
+ out << "}\n";
+ }
out.unindent();
out << "}\n";
}
@@ -814,18 +1873,7 @@
out.indent(2);
- bool useName = false;
- for (const auto &field : *mFields) {
- if (field->type().useNameInEmitReaderWriterEmbedded(isReader)) {
- useName = true;
- break;
- }
- }
- std::string name = useName ? "obj" : "/* obj */";
- // if not useName, then obj should not be used at all,
- // then the #error should not be emitted.
- std::string error = useName ? "" : "\n#error\n";
-
+ const std::string name = "obj";
if (isReader) {
out << "const " << space << localName() << " &" << name << ",\n";
out << "const ::android::hardware::Parcel &parcel,\n";
@@ -844,15 +1892,35 @@
out << "::android::status_t _hidl_err = ::android::OK;\n\n";
+ if (mStyle == STYLE_SAFE_UNION) {
+ out << "switch (" << name << ".getDiscriminator()) {\n";
+ out.indent();
+ }
+
for (const auto &field : *mFields) {
if (!field->type().needsEmbeddedReadWrite()) {
continue;
}
+ if (mStyle == STYLE_SAFE_UNION) {
+ out << "case " << fullName() << "::hidl_discriminator::"
+ << field->name() << ": {\n";
+ out.indent();
+ }
+
+ const std::string fieldName = (mStyle == STYLE_SAFE_UNION)
+ ? (name + "." + field->name() + "()")
+ : (name + "." + field->name());
+
+ const std::string fieldOffset = (mStyle == STYLE_SAFE_UNION)
+ ? (name + ".hidl_getUnionOffset() " +
+ "/* safe_union: union offset into struct */")
+ : ("offsetof(" + fullName() + ", " + field->name() + ")");
+
field->type().emitReaderWriterEmbedded(
out,
0 /* depth */,
- name + "." + field->name() + error,
+ fieldName,
field->name() /* sanitizedName */,
false /* nameIsPointer */,
"parcel",
@@ -860,11 +1928,19 @@
isReader,
ErrorMode_Return,
"parentHandle",
- "parentOffset + offsetof("
- + fullName()
- + ", "
- + field->name()
- + ")");
+ "parentOffset + " + fieldOffset);
+
+ if (mStyle == STYLE_SAFE_UNION) {
+ out << "break;\n";
+ out.unindent();
+ out << "}\n";
+ }
+ }
+
+ if (mStyle == STYLE_SAFE_UNION) {
+ out << "default: { break; }\n";
+ out.unindent();
+ out << "}\n";
}
out << "return _hidl_err;\n";
@@ -918,15 +1994,35 @@
// should not be used at all, then the #error should not be emitted.
std::string error = useParent ? "" : "\n#error\n";
+ if (mStyle == STYLE_SAFE_UNION) {
+ out << "switch (" << nameDeref << "getDiscriminator()) {\n";
+ out.indent();
+ }
+
for (const auto &field : *mFields) {
if (!field->type().needsResolveReferences()) {
continue;
}
+ if (mStyle == STYLE_SAFE_UNION) {
+ out << "case " << fullName() << "::hidl_discriminator::"
+ << field->name() << ": {\n";
+ out.indent();
+ }
+
+ const std::string fieldName = (mStyle == STYLE_SAFE_UNION)
+ ? (nameDeref + field->name() + "()")
+ : (nameDeref + field->name());
+
+ const std::string fieldOffset = (mStyle == STYLE_SAFE_UNION)
+ ? (nameDeref + "hidl_getUnionOffset() " +
+ "/* safe_union: union offset into struct */")
+ : ("offsetof(" + fullName() + ", " + field->name() + ")");
+
field->type().emitResolveReferencesEmbedded(
out,
0 /* depth */,
- nameDeref + field->name(),
+ fieldName,
field->name() /* sanitizedName */,
false, // nameIsPointer
"parcel", // const std::string &parcelObj,
@@ -935,12 +2031,21 @@
ErrorMode_Return,
parentHandleName + error,
parentOffsetName
- + " + offsetof("
- + fullName()
- + ", "
- + field->name()
- + ")"
+ + " + "
+ + fieldOffset
+ error);
+
+ if (mStyle == STYLE_SAFE_UNION) {
+ out << "break;\n";
+ out.unindent();
+ out << "}\n";
+ }
+ }
+
+ if (mStyle == STYLE_SAFE_UNION) {
+ out << "default: { _hidl_err = ::android::BAD_VALUE; break; }\n";
+ out.unindent();
+ out << "}\n";
}
out << "return _hidl_err;\n";
@@ -950,7 +2055,7 @@
}
bool CompoundType::needsEmbeddedReadWrite() const {
- if (mStyle != STYLE_STRUCT) {
+ if (mStyle == STYLE_UNION) {
return false;
}
@@ -964,7 +2069,7 @@
}
bool CompoundType::deepNeedsResolveReferences(std::unordered_set<const Type*>* visited) const {
- if (mStyle != STYLE_STRUCT) {
+ if (mStyle == STYLE_UNION) {
return false;
}
@@ -998,6 +2103,15 @@
out << "sub_union: {\n";
break;
}
+ case STYLE_SAFE_UNION:
+ {
+ out << "sub_safe_union: {\n";
+ break;
+ }
+ default:
+ {
+ CHECK(!"Should not be here");
+ }
}
out.indent();
type->emitVtsTypeDeclarations(out);
@@ -1018,6 +2132,15 @@
out << "union_value: {\n";
break;
}
+ case STYLE_SAFE_UNION:
+ {
+ out << "safe_union_value: {\n";
+ break;
+ }
+ default:
+ {
+ CHECK(!"Should not be here");
+ }
}
out.indent();
out << "name: \"" << field->name() << "\"\n";
@@ -1033,7 +2156,7 @@
}
bool CompoundType::deepIsJavaCompatible(std::unordered_set<const Type*>* visited) const {
- if (mStyle != STYLE_STRUCT) {
+ if (mStyle == STYLE_UNION) {
return false;
}
@@ -1057,48 +2180,86 @@
}
void CompoundType::getAlignmentAndSize(size_t *align, size_t *size) const {
- *align = 1;
- *size = 0;
+ CompoundLayout layout = getCompoundAlignmentAndSize();
+ *align = layout.overall.align;
+ *size = layout.overall.size;
+}
- size_t offset = 0;
+CompoundType::CompoundLayout CompoundType::getCompoundAlignmentAndSize() const {
+ CompoundLayout compoundLayout;
+
+ // Local aliases for convenience
+ Layout& overall = compoundLayout.overall;
+ Layout& innerStruct = compoundLayout.innerStruct;
+ Layout& discriminator = compoundLayout.discriminator;
+
+ if (mStyle == STYLE_SAFE_UNION) {
+ getUnionDiscriminatorType()->getAlignmentAndSize(
+ &(discriminator.align), &(discriminator.size));
+
+ innerStruct.offset = discriminator.size;
+ }
+
for (const auto &field : *mFields) {
+
// Each field is aligned according to its alignment requirement.
// The surrounding structure's alignment is the maximum of its
// fields' aligments.
-
size_t fieldAlign, fieldSize;
field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
+ size_t lPad = Layout::getPad(innerStruct.size, fieldAlign);
- size_t pad = offset % fieldAlign;
- if (pad > 0) {
- offset += fieldAlign - pad;
- }
+ innerStruct.size = (mStyle == STYLE_STRUCT)
+ ? (innerStruct.size + lPad + fieldSize)
+ : std::max(innerStruct.size, fieldSize);
- if (mStyle == STYLE_STRUCT) {
- offset += fieldSize;
- } else {
- *size = std::max(*size, fieldSize);
- }
+ innerStruct.align = std::max(innerStruct.align, fieldAlign);
+ }
- if (fieldAlign > (*align)) {
- *align = fieldAlign;
+ // Pad the inner structure's size
+ innerStruct.size += Layout::getPad(innerStruct.size,
+ innerStruct.align);
+
+ // Compute its final offset
+ innerStruct.offset += Layout::getPad(innerStruct.offset,
+ innerStruct.align);
+
+ overall.size = innerStruct.offset + innerStruct.size;
+
+ // An empty struct/union still occupies a byte of space in C++.
+ if (overall.size == 0) {
+ overall.size = 1;
+ }
+
+ // Pad the overall structure's size
+ overall.align = std::max(innerStruct.align, discriminator.align);
+ overall.size += Layout::getPad(overall.size, overall.align);
+
+ return compoundLayout;
+}
+
+std::unique_ptr<ScalarType> CompoundType::getUnionDiscriminatorType() const {
+ static const std::vector<std::pair<int, ScalarType::Kind> > scalars {
+ {8, ScalarType::Kind::KIND_UINT8},
+ {16, ScalarType::Kind::KIND_UINT16},
+ {32, ScalarType::Kind::KIND_UINT32},
+ };
+
+ size_t numFields = mFields->size();
+ auto kind = ScalarType::Kind::KIND_UINT64;
+
+ for (const auto& scalar : scalars) {
+ if (numFields <= (1ULL << scalar.first)) {
+ kind = scalar.second; break;
}
}
- if (mStyle == STYLE_STRUCT) {
- *size = offset;
- }
+ return std::unique_ptr<ScalarType>(new ScalarType(kind, nullptr));
+}
- // Final padding to account for the structure's alignment.
- size_t pad = (*size) % (*align);
- if (pad > 0) {
- (*size) += (*align) - pad;
- }
-
- if (*size == 0) {
- // An empty struct still occupies a byte of space in C++.
- *size = 1;
- }
+size_t CompoundType::Layout::getPad(size_t offset, size_t align) {
+ size_t remainder = offset % align;
+ return (remainder > 0) ? (align - remainder) : 0;
}
} // namespace android
diff --git a/CompoundType.h b/CompoundType.h
index 3ef5f02..e02090a 100644
--- a/CompoundType.h
+++ b/CompoundType.h
@@ -29,6 +29,7 @@
enum Style {
STYLE_STRUCT,
STYLE_UNION,
+ STYLE_SAFE_UNION,
};
CompoundType(Style style, const char* localName, const FQName& fullName,
@@ -48,6 +49,7 @@
status_t validate() const override;
status_t validateUniqueNames() const;
+ status_t validateSubTypeNames() const;
std::string getCppType(StorageMode mode,
bool specifyNamespaces) const override;
@@ -108,6 +110,9 @@
void emitJavaFieldInitializer(
Formatter &out, const std::string &fieldName) const override;
+ void emitJavaFieldDefaultInitialValue(
+ Formatter &out, const std::string &declaredFieldName) const override;
+
void emitJavaFieldReaderWriter(
Formatter &out,
size_t depth,
@@ -120,6 +125,7 @@
void emitTypeDeclarations(Formatter& out) const override;
void emitTypeForwardDeclaration(Formatter& out) const override;
void emitPackageTypeDeclarations(Formatter& out) const override;
+ void emitPackageTypeHeaderDefinitions(Formatter& out) const override;
void emitPackageHwDeclarations(Formatter& out) const override;
void emitTypeDefinitions(Formatter& out, const std::string& prefix) const override;
@@ -140,9 +146,61 @@
bool containsInterface() const;
private:
+
+ struct Layout {
+ size_t offset;
+ size_t align;
+ size_t size;
+
+ Layout() : offset(0), align(1), size(0) {}
+ static size_t getPad(size_t offset, size_t align);
+ };
+
+ struct CompoundLayout {
+ Layout overall;
+ Layout innerStruct;
+ Layout discriminator;
+ };
+
Style mStyle;
std::vector<NamedReference<Type>*>* mFields;
+ void emitLayoutAsserts(Formatter& out, const Layout& localLayout,
+ const std::string& localLayoutName) const;
+
+ void emitInvalidSubTypeNamesError(const std::string& subTypeName,
+ const Location& location) const;
+
+ void emitSafeUnionTypeDefinitions(Formatter& out) const;
+ void emitSafeUnionTypeConstructors(Formatter& out) const;
+ void emitSafeUnionTypeDeclarations(Formatter& out) const;
+ std::unique_ptr<ScalarType> getUnionDiscriminatorType() const;
+
+ void emitSafeUnionUnknownDiscriminatorError(Formatter& out, const std::string& value,
+ bool fatal) const;
+
+ void emitSafeUnionCopyAndAssignDefinition(Formatter& out,
+ const std::string& parameterName,
+ bool isCopyConstructor,
+ bool usesMoveSemantics) const;
+
+ struct SafeUnionEnumElement {
+ std::string fieldName;
+ std::string fieldTypeName;
+ };
+
+ std::vector<SafeUnionEnumElement> getSafeUnionEnumElements(bool useCppTypeName) const;
+
+ CompoundLayout getCompoundAlignmentAndSize() const;
+
+ void emitSafeUnionReaderWriterForInterfaces(
+ Formatter &out,
+ const std::string &name,
+ const std::string &parcelObj,
+ bool parcelObjIsPointer,
+ bool isReader,
+ ErrorMode mode) const;
+
void emitStructReaderWriter(
Formatter &out, const std::string &prefix, bool isReader) const;
void emitResolveReferenceDef(Formatter& out, const std::string& prefix, bool isReader) const;
diff --git a/ConstantExpression.cpp b/ConstantExpression.cpp
index 8a2b875..002bf56 100644
--- a/ConstantExpression.cpp
+++ b/ConstantExpression.cpp
@@ -173,7 +173,7 @@
CHECK(!expr.empty());
CHECK(isSupported(kind));
- mTrivialDescription = true;
+ mTrivialDescription = std::to_string(value) == expr;
mExpr = expr;
mValueKind = kind;
mValue = value;
@@ -254,7 +254,7 @@
CHECK(mUnary->isEvaluated());
mIsEvaluated = true;
- mExpr = std::string("(") + mOp + mUnary->description() + ")";
+ mExpr = std::string("(") + mOp + mUnary->mExpr + ")";
mValueKind = mUnary->mValueKind;
#define CASE_UNARY(__type__) \
@@ -270,7 +270,7 @@
CHECK(mRval->isEvaluated());
mIsEvaluated = true;
- mExpr = std::string("(") + mLval->description() + " " + mOp + " " + mRval->description() + ")";
+ mExpr = std::string("(") + mLval->mExpr + " " + mOp + " " + mRval->mExpr + ")";
bool isArithmeticOrBitflip = OP_IS_BIN_ARITHMETIC || OP_IS_BIN_BITFLIP;
@@ -330,8 +330,7 @@
CHECK(mFalseVal->isEvaluated());
mIsEvaluated = true;
- mExpr = std::string("(") + mCond->description() + "?" + mTrueVal->description() + ":" +
- mFalseVal->description() + ")";
+ mExpr = std::string("(") + mCond->mExpr + "?" + mTrueVal->mExpr + ":" + mFalseVal->mExpr + ")";
// note: for ?:, unlike arithmetic ops, integral promotion is not processed.
mValueKind = usualArithmeticConversion(mTrueVal->mValueKind, mFalseVal->mValueKind);
@@ -356,34 +355,54 @@
mIsEvaluated = true;
}
+status_t AttributeConstantExpression::validate() const {
+ if (mTag == "len") {
+ if (!mReference->isEnum()) {
+ std::cerr << "ERROR: " << mExpr << " refers to " << mReference->typeName()
+ << " but should refer to an enum." << std::endl;
+ return UNKNOWN_ERROR;
+ }
+ } else {
+ std::cerr << "ERROR: " << mExpr << " is not a supported tag" << std::endl;
+ return UNKNOWN_ERROR;
+ }
+
+ return OK;
+}
+
+void AttributeConstantExpression::evaluate() {
+ if (isEvaluated()) return;
+
+ CHECK(mTag == "len");
+ CHECK(mReference->isEnum());
+
+ EnumType* enumType = static_cast<EnumType*>(mReference.get());
+ mValue = enumType->numValueNames();
+
+ if (mValue <= INT32_MAX)
+ mValueKind = SK(INT32);
+ else
+ mValueKind = SK(INT64);
+
+ mIsEvaluated = true;
+}
+
std::unique_ptr<ConstantExpression> ConstantExpression::addOne(ScalarType::Kind baseKind) {
auto ret = std::make_unique<BinaryConstantExpression>(
this, "+", ConstantExpression::One(baseKind).release());
return ret;
}
-const std::string& ConstantExpression::description() const {
- CHECK(isEvaluated());
- return mExpr;
-}
-
-bool ConstantExpression::descriptionIsTrivial() const {
- CHECK(isEvaluated());
- return mTrivialDescription;
-}
-
std::string ConstantExpression::value() const {
- CHECK(isEvaluated());
- return rawValue(mValueKind);
+ return value(mValueKind);
}
std::string ConstantExpression::value(ScalarType::Kind castKind) const {
CHECK(isEvaluated());
- return rawValue(castKind);
+ return rawValue(castKind) + descriptionSuffix();
}
std::string ConstantExpression::cppValue() const {
- CHECK(isEvaluated());
return cppValue(mValueKind);
}
@@ -399,35 +418,60 @@
// -(uint64_t)9223372036854775808 == 9223372036854775808 could not
// be narrowed to int64_t.
if(castKind == SK(INT64) && (int64_t)mValue == INT64_MIN) {
- return "static_cast<" +
- ScalarType(SK(INT64), nullptr /* parent */).getCppStackType() // "int64_t"
- + ">(" + literal + "ull)";
+ literal = "static_cast<" +
+ ScalarType(SK(INT64), nullptr /* parent */).getCppStackType() // "int64_t"
+ + ">(" + literal + "ull)";
+ } else {
+ // add suffix if necessary.
+ if (castKind == SK(UINT32) || castKind == SK(UINT64)) literal += "u";
+ if (castKind == SK(UINT64) || castKind == SK(INT64)) literal += "ll";
}
- // add suffix if necessary.
- if(castKind == SK(UINT32) || castKind == SK(UINT64)) literal += "u";
- if(castKind == SK(UINT64) || castKind == SK(INT64)) literal += "ll";
- return literal;
+ return literal + descriptionSuffix();
}
std::string ConstantExpression::javaValue() const {
- CHECK(isEvaluated());
return javaValue(mValueKind);
}
std::string ConstantExpression::javaValue(ScalarType::Kind castKind) const {
CHECK(isEvaluated());
+ std::string literal;
+
switch(castKind) {
- case SK(UINT64): return rawValue(SK(INT64)) + "L";
- case SK(INT64): return rawValue(SK(INT64)) + "L";
- case SK(UINT32): return rawValue(SK(INT32));
- case SK(UINT16): return rawValue(SK(INT16));
- case SK(UINT8) : return rawValue(SK(INT8));
+ case SK(UINT64):
+ literal = rawValue(SK(INT64)) + "L";
+ break;
+ case SK(INT64):
+ literal = rawValue(SK(INT64)) + "L";
+ break;
+ case SK(UINT32):
+ literal = rawValue(SK(INT32));
+ break;
+ case SK(UINT16):
+ literal = rawValue(SK(INT16));
+ break;
+ case SK(UINT8):
+ literal = rawValue(SK(INT8));
+ break;
case SK(BOOL) :
- return this->cast<bool>() ? "true" : "false";
- default: break;
+ literal = this->cast<bool>() ? "true" : "false";
+ break;
+ default:
+ literal = rawValue(castKind);
+ break;
}
- return rawValue(castKind);
+
+ return literal + descriptionSuffix();
+}
+
+const std::string& ConstantExpression::expression() const {
+ CHECK(isEvaluated());
+ return mExpr;
+}
+
+std::string ConstantExpression::rawValue() const {
+ return rawValue(mValueKind);
}
std::string ConstantExpression::rawValue(ScalarType::Kind castKind) const {
@@ -435,7 +479,7 @@
#define CASE_STR(__type__) return std::to_string(this->cast<__type__>());
- SWITCH_KIND(castKind, CASE_STR, SHOULD_NOT_REACH(); return 0; );
+ SWITCH_KIND(castKind, CASE_STR, SHOULD_NOT_REACH(); return nullptr; );
}
template<typename T>
@@ -447,6 +491,17 @@
SWITCH_KIND(mValueKind, CASE_CAST_T, SHOULD_NOT_REACH(); return 0; );
}
+std::string ConstantExpression::descriptionSuffix() const {
+ CHECK(isEvaluated());
+
+ if (!mTrivialDescription) {
+ CHECK(!mExpr.empty());
+
+ return " /* " + mExpr + " */";
+ }
+ return "";
+}
+
size_t ConstantExpression::castSizeT() const {
CHECK(isEvaluated());
return this->cast<size_t>();
@@ -456,6 +511,10 @@
return false;
}
+status_t ConstantExpression::validate() const {
+ return OK;
+}
+
std::vector<ConstantExpression*> ConstantExpression::getConstantExpressions() {
const auto& constRet = static_cast<const ConstantExpression*>(this)->getConstantExpressions();
std::vector<ConstantExpression*> ret(constRet.size());
@@ -476,6 +535,18 @@
return {};
}
+std::vector<Reference<Type>*> ConstantExpression::getTypeReferences() {
+ const auto& constRet = static_cast<const ConstantExpression*>(this)->getTypeReferences();
+ std::vector<Reference<Type>*> ret(constRet.size());
+ std::transform(constRet.begin(), constRet.end(), ret.begin(),
+ [](const auto* ce) { return const_cast<Reference<Type>*>(ce); });
+ return ret;
+}
+
+std::vector<const Reference<Type>*> ConstantExpression::getTypeReferences() const {
+ return {};
+}
+
status_t ConstantExpression::recursivePass(const std::function<status_t(ConstantExpression*)>& func,
std::unordered_set<const ConstantExpression*>* visited,
bool processBeforeDependencies) {
@@ -655,6 +726,22 @@
return {&mReference};
}
+AttributeConstantExpression::AttributeConstantExpression(const Reference<Type>& value,
+ const std::string& fqname,
+ const std::string& tag)
+ : mReference(value), mTag(tag) {
+ mExpr = fqname + "#" + tag;
+}
+
+std::vector<const ConstantExpression*> AttributeConstantExpression::getConstantExpressions() const {
+ // Returns reference instead
+ return {};
+}
+
+std::vector<const Reference<Type>*> AttributeConstantExpression::getTypeReferences() const {
+ return {&mReference};
+}
+
/*
Evaluating expressions in HIDL language
diff --git a/ConstantExpression.h b/ConstantExpression.h
index 9784885..b770716 100644
--- a/ConstantExpression.h
+++ b/ConstantExpression.h
@@ -60,6 +60,9 @@
std::unordered_set<const ConstantExpression*>* visited,
bool processBeforeDependencies) const;
+ // If this object is in an invalid state.
+ virtual status_t validate() const;
+
// Evaluates current constant expression
// Doesn't call recursive evaluation, so must be called after dependencies
virtual void evaluate() = 0;
@@ -70,6 +73,9 @@
std::vector<Reference<LocalIdentifier>*> getReferences();
virtual std::vector<const Reference<LocalIdentifier>*> getReferences() const;
+ std::vector<Reference<Type>*> getTypeReferences();
+ virtual std::vector<const Reference<Type>*> getTypeReferences() const;
+
// Recursive tree pass checkAcyclic return type.
// Stores cycle end for nice error messages.
struct CheckAcyclicStatus {
@@ -93,11 +99,11 @@
/* Returns true iff the value has already been evaluated. */
bool isEvaluated() const;
- /* Evaluated result in a string form. */
+ /* Evaluated result in a string form with comment if applicable. */
std::string value() const;
- /* Evaluated result in a string form. */
+ /* Evaluated result in a string form with comment if applicable. */
std::string cppValue() const;
- /* Evaluated result in a string form. */
+ /* Evaluated result in a string form with comment if applicable. */
std::string javaValue() const;
/* Evaluated result in a string form, with given contextual kind. */
std::string value(ScalarType::Kind castKind) const;
@@ -105,10 +111,10 @@
std::string cppValue(ScalarType::Kind castKind) const;
/* Evaluated result in a string form, with given contextual kind. */
std::string javaValue(ScalarType::Kind castKind) const;
- /* Formatted expression with type. */
- const std::string& description() const;
- /* See mTrivialDescription */
- bool descriptionIsTrivial() const;
+
+ /* The expression representing this value for use in comments when the value is not needed */
+ const std::string& expression() const;
+
/* Return a ConstantExpression that is 1 plus the original. */
std::unique_ptr<ConstantExpression> addOne(ScalarType::Kind baseKind);
@@ -118,6 +124,14 @@
// Post parse passes must be proceeded during owner package parsin
void setPostParseCompleted();
+ /*
+ * Helper function for all cpp/javaValue methods.
+ * Returns a plain string (without any prefixes or suffixes, just the
+ * digits) converted from mValue.
+ */
+ std::string rawValue() const;
+ std::string rawValue(ScalarType::Kind castKind) const;
+
private:
/* If the result value has been evaluated. */
bool mIsEvaluated = false;
@@ -133,11 +147,9 @@
bool mIsPostParseCompleted = false;
/*
- * Helper function for all cpp/javaValue methods.
- * Returns a plain string (without any prefixes or suffixes, just the
- * digits) converted from mValue.
+ * Helper function, gives suffix comment to add to value/cppValue/javaValue
*/
- std::string rawValue(ScalarType::Kind castKind) const;
+ std::string descriptionSuffix() const;
/*
* Return the value casted to the given type.
@@ -152,17 +164,16 @@
friend struct BinaryConstantExpression;
friend struct TernaryConstantExpression;
friend struct ReferenceConstantExpression;
+ friend struct AttributeConstantExpression;
};
struct LiteralConstantExpression : public ConstantExpression {
LiteralConstantExpression(ScalarType::Kind kind, uint64_t value);
+ LiteralConstantExpression(ScalarType::Kind kind, uint64_t value, const std::string& expr);
void evaluate() override;
std::vector<const ConstantExpression*> getConstantExpressions() const override;
static LiteralConstantExpression* tryParse(const std::string& value);
-
-private:
- LiteralConstantExpression(ScalarType::Kind kind, uint64_t value, const std::string& expr);
};
struct UnaryConstantExpression : public ConstantExpression {
@@ -211,6 +222,22 @@
Reference<LocalIdentifier> mReference;
};
+// This constant expression is a compile-time calculatable expression based on another type
+struct AttributeConstantExpression : public ConstantExpression {
+ AttributeConstantExpression(const Reference<Type>& value, const std::string& fqname,
+ const std::string& tag);
+
+ status_t validate() const override;
+ void evaluate() override;
+
+ std::vector<const ConstantExpression*> getConstantExpressions() const override;
+ std::vector<const Reference<Type>*> getTypeReferences() const override;
+
+ private:
+ Reference<Type> mReference;
+ const std::string mTag;
+};
+
} // namespace android
#endif // CONSTANT_EXPRESSION_H_
diff --git a/Coordinator.cpp b/Coordinator.cpp
index 96c9658..2e9ae08 100644
--- a/Coordinator.cpp
+++ b/Coordinator.cpp
@@ -33,7 +33,7 @@
static bool existdir(const char *name) {
DIR *dir = opendir(name);
- if (dir == NULL) {
+ if (dir == nullptr) {
return false;
}
closedir(dir);
@@ -262,7 +262,7 @@
*ast = new AST(this, &Hash::getHash(path));
- if (typesAST != NULL) {
+ if (typesAST != nullptr) {
// If types.hal for this AST's package existed, make it's defined
// types available to the (about to be parsed) AST right away.
(*ast)->addImportedAST(typesAST);
@@ -320,7 +320,7 @@
fqName.name().c_str());
err = UNKNOWN_ERROR;
- } else if ((*ast)->containsInterfaces()) {
+ } else if ((*ast)->definesInterfaces()) {
fprintf(stderr,
"ERROR: types.hal file at '%s' declares at least one "
"interface type.\n",
@@ -442,7 +442,7 @@
status_t Coordinator::getPackageInterfaceFiles(
const FQName &package,
std::vector<std::string> *fileNames) const {
- fileNames->clear();
+ if (fileNames) fileNames->clear();
std::string packagePath;
status_t err =
@@ -450,18 +450,33 @@
if (err != OK) return err;
const std::string path = makeAbsolute(packagePath);
- DIR* dir = opendir(path.c_str());
+ std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir);
- if (dir == NULL) {
+ if (dir == nullptr) {
fprintf(stderr, "ERROR: Could not open package path %s for package %s:\n%s\n",
packagePath.c_str(), package.string().c_str(), path.c_str());
return -errno;
}
+ if (fileNames == nullptr) {
+ return OK;
+ }
+
struct dirent *ent;
- while ((ent = readdir(dir)) != NULL) {
- if (ent->d_type != DT_REG) {
- continue;
+ while ((ent = readdir(dir.get())) != nullptr) {
+ // filesystems may not support d_type and return DT_UNKNOWN
+ if (ent->d_type == DT_UNKNOWN) {
+ struct stat sb;
+ const auto filename = packagePath + std::string(ent->d_name);
+ if (stat(filename.c_str(), &sb) == -1) {
+ fprintf(stderr, "ERROR: Could not stat %s\n", filename.c_str());
+ return -errno;
+ }
+ if ((sb.st_mode & S_IFMT) != S_IFREG) {
+ continue;
+ }
+ } else if (ent->d_type != DT_REG) {
+ continue;
}
const auto suffix = ".hal";
@@ -476,9 +491,6 @@
fileNames->push_back(std::string(ent->d_name, d_namelen - suffix_len));
}
- closedir(dir);
- dir = NULL;
-
std::sort(fileNames->begin(), fileNames->end(),
[](const std::string& lhs, const std::string& rhs) -> bool {
if (lhs == "types") {
diff --git a/EnumType.cpp b/EnumType.cpp
index ead64ba..3268264 100644
--- a/EnumType.cpp
+++ b/EnumType.cpp
@@ -49,6 +49,14 @@
}
}
+size_t EnumType::numValueNames() const {
+ size_t count = 0;
+ for (const auto it : typeChain()) {
+ count += it->values().size();
+ }
+ return count;
+}
+
void EnumType::addValue(EnumValue* value) {
CHECK(value != nullptr);
mValues.push_back(value);
@@ -168,8 +176,8 @@
return mStorageType->resolveToScalarType()->getJavaSuffix();
}
-std::string EnumType::getJavaWrapperType() const {
- return mStorageType->resolveToScalarType()->getJavaWrapperType();
+std::string EnumType::getJavaTypeClass() const {
+ return mStorageType->resolveToScalarType()->getJavaTypeClass();
}
std::string EnumType::getVtsType() const {
@@ -185,8 +193,8 @@
return resolveToScalarType()->getJavaType(forInitializer);
}
-std::string EnumType::getBitfieldJavaWrapperType() const {
- return resolveToScalarType()->getJavaWrapperType();
+std::string EnumType::getBitfieldJavaTypeClass() const {
+ return resolveToScalarType()->getJavaTypeClass();
}
LocalIdentifier *EnumType::lookupIdentifier(const std::string &name) const {
@@ -210,7 +218,7 @@
bool isReader,
ErrorMode mode) const {
const ScalarType *scalarType = mStorageType->resolveToScalarType();
- CHECK(scalarType != NULL);
+ CHECK(scalarType != nullptr);
scalarType->emitReaderWriterWithCast(
out,
@@ -260,16 +268,7 @@
std::string value = entry->cppValue(scalarType->getKind());
CHECK(!value.empty()); // use autofilled values for c++.
- out << " = " << value;
-
- out << ",";
-
- std::string comment = entry->comment();
- if (!comment.empty()) {
- out << " // " << comment;
- }
-
- out << "\n";
+ out << " = " << value << ",\n";
}
}
@@ -290,27 +289,17 @@
elementCount += type->mValues.size();
}
- out << "template<> struct hidl_enum_iterator<" << getCppStackType() << ">\n";
+ out << "template<> constexpr std::array<" << getCppStackType() << ", " << elementCount
+ << "> hidl_enum_values<" << getCppStackType() << "> = ";
out.block([&] {
- out << "const " << getCppStackType() << "* begin() { return static_begin(); }\n";
- out << "const " << getCppStackType() << "* end() { return begin() + " << elementCount
- << "; }\n";
- out << "private:\n";
- out << "static const " << getCppStackType() << "* static_begin() ";
- out.block([&] {
- out << "static const " << getCppStackType() << " kVals[" << elementCount << "] ";
- out.block([&] {
- auto enumerators = typeChain();
- std::reverse(enumerators.begin(), enumerators.end());
- for (const auto* type : enumerators) {
- for (const auto* enumValue : type->mValues) {
- out << fullName() << "::" << enumValue->name() << ",\n";
- }
- }
- }) << ";\n";
- out << "return &kVals[0];\n";
- });
- }) << ";\n\n";
+ auto enumerators = typeChain();
+ std::reverse(enumerators.begin(), enumerators.end());
+ for (const auto* type : enumerators) {
+ for (const auto* enumValue : type->mValues) {
+ out << fullName() << "::" << enumValue->name() << ",\n";
+ }
+ }
+ }) << ";\n";
}
void EnumType::emitEnumBitwiseOperator(
@@ -356,7 +345,7 @@
out << ");\n";
});
- out << "}\n\n";
+ out << "}\n";
}
void EnumType::emitBitFieldBitwiseAssignmentOperator(
@@ -375,20 +364,27 @@
out << "return v;\n";
});
- out << "}\n\n";
+ out << "}\n";
}
void EnumType::emitGlobalTypeDeclarations(Formatter& out) const {
out << "namespace android {\n";
out << "namespace hardware {\n";
+ out << "namespace details {\n";
emitIteratorDeclaration(out);
+ out << "} // namespace details\n";
out << "} // namespace hardware\n";
- out << "} // namespace android\n";
+ out << "} // namespace android\n\n";
}
void EnumType::emitPackageTypeDeclarations(Formatter& out) const {
+ out << "template<typename>\n"
+ << "static inline std::string toString(" << resolveToScalarType()->getCppArgumentType()
+ << " o);\n";
+ out << "static inline std::string toString(" << getCppArgumentType() << " o);\n\n";
+
emitEnumBitwiseOperator(out, true /* lhsIsEnum */, true /* rhsIsEnum */, "|");
emitEnumBitwiseOperator(out, false /* lhsIsEnum */, true /* rhsIsEnum */, "|");
emitEnumBitwiseOperator(out, true /* lhsIsEnum */, false /* rhsIsEnum */, "|");
@@ -399,12 +395,13 @@
emitBitFieldBitwiseAssignmentOperator(out, "|");
emitBitFieldBitwiseAssignmentOperator(out, "&");
- const ScalarType *scalarType = mStorageType->resolveToScalarType();
- CHECK(scalarType != NULL);
+ out.endl();
+}
- out << "template<typename>\n"
- << "static inline std::string toString(" << resolveToScalarType()->getCppArgumentType()
- << " o);\n";
+void EnumType::emitPackageTypeHeaderDefinitions(Formatter& out) const {
+ const ScalarType *scalarType = mStorageType->resolveToScalarType();
+ CHECK(scalarType != nullptr);
+
out << "template<>\n"
<< "inline std::string toString<" << getCppStackType() << ">("
<< scalarType->getCppArgumentType() << " o) ";
@@ -455,7 +452,7 @@
void EnumType::emitJavaTypeDeclarations(Formatter& out, bool atTopLevel) const {
const ScalarType *scalarType = mStorageType->resolveToScalarType();
- CHECK(scalarType != NULL);
+ CHECK(scalarType != nullptr);
out << "public "
<< (atTopLevel ? "" : "static ")
@@ -485,16 +482,7 @@
// javaValue will make the number signed.
std::string value = entry->javaValue(scalarType->getKind());
CHECK(!value.empty()); // use autofilled values for java.
- out << value;
-
- out << ";";
-
- std::string comment = entry->comment();
- if (!comment.empty()) {
- out << " // " << comment;
- }
-
- out << "\n";
+ out << value << ";\n";
}
}
@@ -512,7 +500,6 @@
}).endl();
auto bitfieldType = getBitfieldJavaType(false /* forInitializer */);
- auto bitfieldWrapperType = getBitfieldJavaWrapperType();
out << "\n"
<< "public static final String dumpBitfield("
<< bitfieldType << " o) ";
@@ -563,7 +550,7 @@
out << "scalar_value: {\n";
out.indent();
// use autofilled values for vts.
- std::string value = entry->value(scalarType->getKind());
+ std::string value = entry->rawValue(scalarType->getKind());
CHECK(!value.empty());
out << mStorageType->resolveToScalarType()->getVtsScalarType()
<< ": "
@@ -704,16 +691,7 @@
// javaValue will make the number signed.
std::string value = entry->javaValue(scalarType->getKind());
CHECK(!value.empty()); // use autofilled values for java.
- out << value;
-
- out << ";";
-
- std::string comment = entry->comment();
- if (!comment.empty()) {
- out << " // " << comment;
- }
-
- out << "\n";
+ out << value << ";\n";
}
}
@@ -742,16 +720,7 @@
std::string value = entry->cppValue(scalarType->getKind());
CHECK(!value.empty()); // use autofilled values for c++.
- out << " = " << value;
-
- out << ",";
-
- std::string comment = entry->comment();
- if (!comment.empty()) {
- out << " // " << comment;
- }
-
- out << "\n";
+ out << " = " << value << ",\n";
}
}
@@ -774,9 +743,9 @@
return mName;
}
-std::string EnumValue::value(ScalarType::Kind castKind) const {
+std::string EnumValue::rawValue(ScalarType::Kind castKind) const {
CHECK(mValue != nullptr);
- return mValue->value(castKind);
+ return mValue->rawValue(castKind);
}
std::string EnumValue::cppValue(ScalarType::Kind castKind) const {
@@ -788,12 +757,6 @@
return mValue->javaValue(castKind);
}
-std::string EnumValue::comment() const {
- CHECK(mValue != nullptr);
- if (mValue->descriptionIsTrivial()) return "";
- return mValue->description();
-}
-
ConstantExpression *EnumValue::constExpr() const {
CHECK(mValue != nullptr);
return mValue;
@@ -866,8 +829,8 @@
return resolveToScalarType()->getJavaSuffix();
}
-std::string BitFieldType::getJavaWrapperType() const {
- return getElementEnumType()->getBitfieldJavaWrapperType();
+std::string BitFieldType::getJavaTypeClass() const {
+ return getElementEnumType()->getBitfieldJavaTypeClass();
}
std::string BitFieldType::getVtsType() const {
diff --git a/EnumType.h b/EnumType.h
index eef4eb2..8ae7c36 100644
--- a/EnumType.h
+++ b/EnumType.h
@@ -39,6 +39,9 @@
void forEachValueFromRoot(const std::function<void(EnumValue*)> f) const;
+ // This is the number of distinct keys (even if they have colliding values)
+ size_t numValueNames() const;
+
LocalIdentifier *lookupIdentifier(const std::string &name) const override;
bool isElidableType() const override;
@@ -52,16 +55,15 @@
bool specifyNamespaces) const override;
std::string getJavaType(bool forInitializer) const override;
+ std::string getJavaTypeClass() const override;
std::string getJavaSuffix() const override;
- std::string getJavaWrapperType() const override;
-
std::string getVtsType() const override;
std::string getBitfieldCppType(StorageMode mode, bool specifyNamespaces = true) const;
std::string getBitfieldJavaType(bool forInitializer = false) const;
- std::string getBitfieldJavaWrapperType() const;
+ std::string getBitfieldJavaTypeClass() const;
// Return the type that corresponds to bitfield<T>.
const BitFieldType* getBitfieldType() const;
@@ -94,6 +96,7 @@
void emitTypeForwardDeclaration(Formatter& out) const override;
void emitGlobalTypeDeclarations(Formatter& out) const override;
void emitPackageTypeDeclarations(Formatter& out) const override;
+ void emitPackageTypeHeaderDefinitions(Formatter& out) const override;
void emitJavaTypeDeclarations(Formatter& out, bool atTopLevel) const override;
@@ -141,10 +144,9 @@
EnumValue(const char* name, ConstantExpression* value, const Location& location);
std::string name() const;
- std::string value(ScalarType::Kind castKind) const;
+ std::string rawValue(ScalarType::Kind castKind) const;
std::string cppValue(ScalarType::Kind castKind) const;
std::string javaValue(ScalarType::Kind castKind) const;
- std::string comment() const;
void autofill(const EnumType* prevType, EnumValue* prevValue, const ScalarType* type);
ConstantExpression* constExpr() const override;
@@ -183,11 +185,10 @@
bool specifyNamespaces) const override;
std::string getJavaType(bool forInitializer) const override;
+ std::string getJavaTypeClass() const override;
std::string getJavaSuffix() const override;
- std::string getJavaWrapperType() const override;
-
std::string getVtsType() const override;
const EnumType* getEnumType() const;
diff --git a/HandleType.cpp b/HandleType.cpp
index 7b6545d..56660a6 100644
--- a/HandleType.cpp
+++ b/HandleType.cpp
@@ -51,6 +51,14 @@
}
}
+std::string HandleType::getJavaType(bool /* forInitializer */) const {
+ return "android.os.NativeHandle";
+}
+
+std::string HandleType::getJavaSuffix() const {
+ return "NativeHandle";
+}
+
std::string HandleType::getVtsType() const {
return "TYPE_HANDLE";
}
@@ -89,15 +97,11 @@
}
}
-bool HandleType::useNameInEmitReaderWriterEmbedded(bool isReader) const {
- return !isReader;
-}
-
void HandleType::emitReaderWriterEmbedded(
Formatter &out,
size_t /* depth */,
const std::string &name,
- const std::string &sanitizedName,
+ const std::string & /* sanitizedName */,
bool nameIsPointer,
const std::string &parcelObj,
bool parcelObjIsPointer,
@@ -105,52 +109,65 @@
ErrorMode mode,
const std::string &parentName,
const std::string &offsetText) const {
+ emitReaderWriterEmbeddedForTypeName(
+ out,
+ name,
+ nameIsPointer,
+ parcelObj,
+ parcelObjIsPointer,
+ isReader,
+ mode,
+ parentName,
+ offsetText,
+ "::android::hardware::hidl_handle",
+ "" /* childName */,
+ "::android::hardware");
+}
+
+void HandleType::emitJavaFieldInitializer(
+ Formatter &out, const std::string &fieldName) const {
+ const std::string fieldDeclaration = getJavaType(false) + " " + fieldName;
+ emitJavaFieldDefaultInitialValue(out, fieldDeclaration);
+}
+
+void HandleType::emitJavaFieldDefaultInitialValue(
+ Formatter &out, const std::string &declaredFieldName) const {
+ out << declaredFieldName
+ << " = new "
+ << getJavaType(true)
+ << "();\n";
+}
+
+void HandleType::emitJavaFieldReaderWriter(
+ Formatter &out,
+ size_t /* depth */,
+ const std::string &parcelName,
+ const std::string &blobName,
+ const std::string &fieldName,
+ const std::string &offset,
+ bool isReader) const {
if (isReader) {
- const std::string ptrName = "_hidl_" + sanitizedName + "_ptr";
+ out << fieldName
+ << " = "
+ << parcelName
+ << ".readEmbeddedNativeHandle(\n";
- out << "const native_handle_t *"
- << ptrName << ";\n"
- << "_hidl_err = "
- << parcelObj
- << (parcelObjIsPointer ? "->" : ".")
- << "readNullableEmbeddedNativeHandle(\n";
+ out.indent(2, [&] {
+ out << blobName
+ << ".handle(),\n"
+ << offset
+ << " + 0 /* offsetof(hidl_handle, mHandle) */);\n\n";
+ });
- out.indent();
- out.indent();
-
- out << parentName
- << ",\n"
- << offsetText
- << ",\n"
- << "&" << ptrName
- << "\n"
- << ");\n\n";
-
- out.unindent();
- out.unindent();
-
- handleError(out, mode);
- } else {
- out << "_hidl_err = "
- << parcelObj
- << (parcelObjIsPointer ? "->" : ".")
- << "writeEmbeddedNativeHandle(\n";
-
- out.indent();
- out.indent();
-
- out << (nameIsPointer ? ("*" + name) : name)
- << ",\n"
- << parentName
- << ",\n"
- << offsetText
- << ");\n\n";
-
- out.unindent();
- out.unindent();
-
- handleError(out, mode);
+ return;
}
+
+ out << blobName
+ << ".putNativeHandle("
+ << offset
+ << ", "
+ << fieldName
+ << ");\n";
}
bool HandleType::needsEmbeddedReadWrite() const {
@@ -158,7 +175,7 @@
}
bool HandleType::deepIsJavaCompatible(std::unordered_set<const Type*>* /* visited */) const {
- return false;
+ return true;
}
static HidlTypeAssertion assertion("hidl_handle", 16 /* size */);
diff --git a/HandleType.h b/HandleType.h
index feaddb0..8d3a984 100644
--- a/HandleType.h
+++ b/HandleType.h
@@ -33,6 +33,10 @@
StorageMode mode,
bool specifyNamespaces) const override;
+ std::string getJavaType(bool forInitializer) const override;
+
+ std::string getJavaSuffix() const override;
+
std::string getVtsType() const override;
void emitReaderWriter(
@@ -56,12 +60,25 @@
const std::string &parentName,
const std::string &offsetText) const override;
+ void emitJavaFieldInitializer(
+ Formatter &out, const std::string &fieldName) const override;
+
+ void emitJavaFieldDefaultInitialValue(
+ Formatter &out, const std::string &declaredFieldName) const override;
+
+ void emitJavaFieldReaderWriter(
+ Formatter &out,
+ size_t depth,
+ const std::string &parcelName,
+ const std::string &blobName,
+ const std::string &fieldName,
+ const std::string &offset,
+ bool isReader) const override;
+
bool needsEmbeddedReadWrite() const override;
bool deepIsJavaCompatible(std::unordered_set<const Type*>* visited) const override;
- bool useNameInEmitReaderWriterEmbedded(bool isReader) const override;
-
void getAlignmentAndSize(size_t *align, size_t *size) const override;
void emitVtsTypeDeclarations(Formatter& out) const override;
diff --git a/HidlTypeAssertion.cpp b/HidlTypeAssertion.cpp
index 4522f15..6e4822a 100644
--- a/HidlTypeAssertion.cpp
+++ b/HidlTypeAssertion.cpp
@@ -46,7 +46,7 @@
return a.first < b.first;
});
- for (auto entry : registry()) {
+ for (const auto& entry : registry()) {
out << "static_assert(sizeof(::android::hardware::"
<< entry.first
<< ") == "
diff --git a/Interface.cpp b/Interface.cpp
index d18ceaa..073e44c 100644
--- a/Interface.cpp
+++ b/Interface.cpp
@@ -68,6 +68,9 @@
LAST_HIDL_TRANSACTION = 0x0fffffff,
};
+const std::unique_ptr<ConstantExpression> Interface::FLAG_ONE_WAY =
+ std::make_unique<LiteralConstantExpression>(ScalarType::KIND_UINT32, 0x01, "oneway");
+
Interface::Interface(const char* localName, const FQName& fullName, const Location& location,
Scope* parent, const Reference<Type>& superType, const Hash* fileHash)
: Scope(localName, fullName, location, parent), mSuperType(superType), mFileHash(fileHash) {}
@@ -141,7 +144,7 @@
{
{IMPL_INTERFACE,
[](auto &out) {
- out << "return true;";
+ out << "return true;\n";
}
},
{IMPL_PROXY,
@@ -171,16 +174,16 @@
{IMPL_PROXY,
[](auto &out) {
out << "std::unique_lock<std::mutex> lock(_hidl_mMutex);\n"
- << "for (auto it = _hidl_mDeathRecipients.begin();"
- << "it != _hidl_mDeathRecipients.end();"
+ << "for (auto it = _hidl_mDeathRecipients.rbegin();"
+ << "it != _hidl_mDeathRecipients.rend();"
<< "++it) {\n";
out.indent([&] {
out.sIf("(*it)->getRecipient() == recipient", [&] {
out << "::android::status_t status = remote()->unlinkToDeath(*it);\n"
- << "_hidl_mDeathRecipients.erase(it);\n"
+ << "_hidl_mDeathRecipients.erase(it.base()-1);\n"
<< "return status == ::android::OK;\n";
});
- });
+ }).endl();
out << "}\n";
out << "return false;\n";
}
@@ -212,10 +215,10 @@
HIDL_SYSPROPS_CHANGED_TRANSACTION,
{ { IMPL_INTERFACE, [](auto &out) {
out << "::android::report_sysprop_change();\n";
- out << "return ::android::hardware::Void();";
+ out << "return ::android::hardware::Void();\n";
} } }, /*cppImpl */
{ { IMPL_INTERFACE, [](auto &out) { /* javaImpl */
- out << "android.os.HwBinder.enableInstrumentation();";
+ out << "android.os.HwBinder.enableInstrumentation();\n";
} } } /*javaImpl */
);
return true;
@@ -281,7 +284,7 @@
out << ",\n";
out << chain[i]->fullJavaName() << ".kInterfaceName";
}
- out << "));";
+ out << "));\n";
out.unindent(); out.unindent();
} } } /* javaImpl */
);
@@ -353,7 +356,7 @@
out << "_hidl_cb("
<< fullName()
<< "::descriptor);\n"
- << "return ::android::hardware::Void();";
+ << "return ::android::hardware::Void();\n";
} } }, /* cppImpl */
{ { IMPL_INTERFACE, [this](auto &out) {
out << "return "
@@ -385,7 +388,7 @@
out << "_hidl_cb({ -1 /* pid */, 0 /* ptr */, \n"
<< sArch
<< "});\n"
- << "return ::android::hardware::Void();";
+ << "return ::android::hardware::Void();\n";
}
},
{IMPL_STUB_IMPL,
@@ -398,7 +401,7 @@
<< sArch << "\n";
});
out << ");\n"
- << "return ::android::hardware::Void();";
+ << "return ::android::hardware::Void();\n";
}
}
}, /* cppImpl */
@@ -409,7 +412,7 @@
<< "info.pid = android.os.HidlSupport.getPidIfSharable();\n"
<< "info.ptr = 0;\n"
<< "info.arch = android.hidl.base.V1_0.DebugInfo.Architecture.UNKNOWN;\n"
- << "return info;";
+ << "return info;\n";
} } } /* javaImpl */
);
@@ -421,20 +424,18 @@
return false;
}
- method->fillImplementation(
- HIDL_DEBUG_TRANSACTION,
- {
- {IMPL_INTERFACE,
- [](auto &out) {
- out << "(void)fd;\n"
- << "(void)options;\n"
- << "return ::android::hardware::Void();";
- }
- },
- }, /* cppImpl */
- {
- /* unused, as the debug method is hidden from Java */
- } /* javaImpl */
+ method->fillImplementation(HIDL_DEBUG_TRANSACTION,
+ {
+ {IMPL_INTERFACE,
+ [](auto& out) {
+ out << "(void)fd;\n"
+ << "(void)options;\n"
+ << "return ::android::hardware::Void();\n";
+ }},
+ }, /* cppImpl */
+ {
+ {IMPL_INTERFACE, [](auto& out) { out << "return;\n"; }},
+ } /* javaImpl */
);
return true;
@@ -665,10 +666,6 @@
return true;
}
-bool Interface::isBinder() const {
- return true;
-}
-
const std::vector<Method *> &Interface::userDefinedMethods() const {
return mUserMethods;
}
@@ -820,13 +817,7 @@
out << "} else {\n";
out.indent();
out << "::android::sp<::android::hardware::IBinder> _hidl_binder = "
- << "::android::hardware::toBinder<\n";
- out.indent(2, [&] {
- out << fqName().cppName()
- << ">("
- << name
- << ");\n";
- });
+ << "::android::hardware::getOrCreateCachedBinder(" << name << ".get());\n";
out << "if (_hidl_binder.get() != nullptr) {\n";
out.indent([&] {
out << "_hidl_err = "
@@ -848,6 +839,12 @@
void Interface::emitPackageTypeDeclarations(Formatter& out) const {
Scope::emitPackageTypeDeclarations(out);
+ out << "static inline std::string toString(" << getCppArgumentType() << " o);\n\n";
+}
+
+void Interface::emitPackageTypeHeaderDefinitions(Formatter& out) const {
+ Scope::emitPackageTypeHeaderDefinitions(out);
+
out << "static inline std::string toString(" << getCppArgumentType() << " o) ";
out.block([&] {
@@ -899,7 +896,7 @@
}
}
-void Interface::emitVtsMethodDeclaration(Formatter& out) const {
+void Interface::emitVtsMethodDeclaration(Formatter& out, bool isInherited) const {
for (const auto &method : methods()) {
if (method->isHidlReserved()) {
continue;
@@ -908,10 +905,12 @@
out << "api: {\n";
out.indent();
out << "name: \"" << method->name() << "\"\n";
+ out << "is_inherited: " << (isInherited ? "true" : "false") << "\n";
// Generate declaration for each return value.
for (const auto &result : method->results()) {
out << "return_type_hidl: {\n";
out.indent();
+ out << "name: \"" << result->name() << "\"\n";
result->type().emitVtsAttributeType(out);
out.unindent();
out << "}\n";
@@ -920,6 +919,7 @@
for (const auto &arg : method->args()) {
out << "arg: {\n";
out.indent();
+ out << "name: \"" << arg->name() << "\"\n";
arg->type().emitVtsAttributeType(out);
out.unindent();
out << "}\n";
@@ -986,7 +986,7 @@
}
}
- return Scope::isJavaCompatible(visited);
+ return Scope::deepIsJavaCompatible(visited);
}
bool Interface::isNeverStrongReference() const {
diff --git a/Interface.h b/Interface.h
index 0c94c0c..aa3d18f 100644
--- a/Interface.h
+++ b/Interface.h
@@ -22,6 +22,7 @@
#include <hidl-hash/Hash.h>
+#include "ConstantExpression.h"
#include "Reference.h"
#include "Scope.h"
@@ -31,10 +32,7 @@
struct InterfaceAndMethod;
struct Interface : public Scope {
- enum {
- /////////////////// Flag(s) - DO NOT CHANGE
- FLAG_ONEWAY = 0x00000001,
- };
+ const static std::unique_ptr<ConstantExpression> FLAG_ONE_WAY;
Interface(const char* localName, const FQName& fullName, const Location& location,
Scope* parent, const Reference<Type>& superType, const Hash* fileHash);
@@ -46,7 +44,6 @@
bool isElidableType() const override;
bool isInterface() const override;
- bool isBinder() const override;
bool isIBase() const { return fqName() == gIBaseFqName; }
std::string typeName() const override;
@@ -115,6 +112,7 @@
ErrorMode mode) const override;
void emitPackageTypeDeclarations(Formatter& out) const override;
+ void emitPackageTypeHeaderDefinitions(Formatter& out) const override;
void emitTypeDefinitions(Formatter& out, const std::string& prefix) const override;
void getAlignmentAndSize(size_t* align, size_t* size) const override;
@@ -127,7 +125,7 @@
void emitVtsAttributeType(Formatter& out) const override;
void emitVtsAttributeDeclaration(Formatter& out) const;
- void emitVtsMethodDeclaration(Formatter& out) const;
+ void emitVtsMethodDeclaration(Formatter& out, bool isInherited) const;
bool hasOnewayMethods() const;
diff --git a/Method.cpp b/Method.cpp
index 64a9a65..d81af7c 100644
--- a/Method.cpp
+++ b/Method.cpp
@@ -139,10 +139,6 @@
}
}
-bool Method::isHiddenFromJava() const {
- return isHidlReserved() && name() == "debug";
-}
-
bool Method::overridesCppImpl(MethodImplType type) const {
CHECK(mIsHidlReserved);
return mCppImpl.find(type) != mCppImpl.end();
@@ -257,10 +253,6 @@
}
bool Method::deepIsJavaCompatible(std::unordered_set<const Type*>* visited) const {
- if (isHiddenFromJava()) {
- return true;
- }
-
if (!std::all_of(mArgs->begin(), mArgs->end(),
[&](const auto* arg) { return (*arg)->isJavaCompatible(visited); })) {
return false;
diff --git a/Method.h b/Method.h
index 711f087..22dd08f 100644
--- a/Method.h
+++ b/Method.h
@@ -65,7 +65,6 @@
void cppImpl(MethodImplType type, Formatter &out) const;
void javaImpl(MethodImplType type, Formatter &out) const;
bool isHidlReserved() const { return mIsHidlReserved; }
- bool isHiddenFromJava() const;
const std::vector<Annotation *> &annotations() const;
std::vector<Reference<Type>*> getReferences();
diff --git a/PointerType.cpp b/PointerType.cpp
index cdf4a99..2b8e5a4 100644
--- a/PointerType.cpp
+++ b/PointerType.cpp
@@ -31,8 +31,8 @@
return true;
}
-std::string PointerType::getCppType(StorageMode /* mode */,
- bool /* specifyNamespaces */) const {
+std::string PointerType::getCppType(StorageMode /*mode*/,
+ bool /*specifyNamespaces*/) const {
return "void*";
}
@@ -47,16 +47,36 @@
void PointerType::emitReaderWriter(
Formatter& out,
const std::string& name,
- const std::string& /* parcelObj */,
- bool /* parcelObjIsPointer */,
- bool /* isReader */,
- ErrorMode /* mode */) const {
+ const std::string& /*parcelObj*/,
+ bool /*parcelObjIsPointer*/,
+ bool /*isReader*/,
+ ErrorMode /*mode*/) const {
out << "(void)" << name << ";\n";
- out << "LOG_ALWAYS_FATAL(\"Pointer is only supported in passthrough mode\");\n";
+ out << "LOG_ALWAYS_FATAL(\"Pointer is only supported in passthrough mode\");\n\n";
+}
+
+void PointerType::emitReaderWriterEmbedded(
+ Formatter& out,
+ size_t /*depth*/,
+ const std::string& name,
+ const std::string& /*sanitizedName*/,
+ bool /*nameIsPointer*/,
+ const std::string& parcelObj,
+ bool parcelObjIsPointer,
+ bool isReader,
+ ErrorMode mode,
+ const std::string& parentName,
+ const std::string& offsetText) const {
+ out << "(void) " << parcelObj << ";\n";
+ out << "(void) " << parentName << ";\n";
+ out << "(void) (" << offsetText << ");\n";
+
+ // same exact code
+ emitReaderWriter(out, name, parcelObj, parcelObjIsPointer, isReader, mode);
}
bool PointerType::needsEmbeddedReadWrite() const {
- return false;
+ return true;
}
bool PointerType::resultNeedsDeref() const {
diff --git a/PointerType.h b/PointerType.h
index 30c4a32..a5004c2 100644
--- a/PointerType.h
+++ b/PointerType.h
@@ -45,6 +45,19 @@
bool isReader,
ErrorMode mode) const override;
+ void emitReaderWriterEmbedded(
+ Formatter &out,
+ size_t depth,
+ const std::string &name,
+ const std::string &sanitizedName,
+ bool nameIsPointer,
+ const std::string &parcelObj,
+ bool parcelObjIsPointer,
+ bool isReader,
+ ErrorMode mode,
+ const std::string &parentName,
+ const std::string &offsetText) const override;
+
bool needsEmbeddedReadWrite() const override;
bool resultNeedsDeref() const override;
diff --git a/README.md b/README.md
index 4859cae..5743edc 100644
--- a/README.md
+++ b/README.md
@@ -1,33 +1,58 @@
-# hidl-gen user guide
+# hidl-gen
+
+Full documentation can be found here:
+<https://source.android.com/devices/architecture/hidl/>
+
+hidl-gen is a compiler for the HIDL (HAL Interface Design Language) which generates
+C++ and Java endpoints for RPC mechanisms. The main userspace libraries which this
+compiler uses can be found at system/libhidl.
## 1. Build
```
-croot
-make hidl-gen
+m hidl-gen
```
## 2. Run
+Note that options for hidl-gen expected to be invoked by the build system
+are marked with 'internal' in the help menu.
+
```
-hidl-gen -o output-path -L language (-r interface-root) fqname
+hidl-gen -h
-output-path: directory to store the output files.
-language: output file for given language. e.g.c++, vts..
-
-fqname: fully qualified name of the input files.
-For singe file input, follow the format: package@version::fileName
-For directory input, follow the format: package@version
-
-interface-root(optional): prefix and root path for fqname.
-If not set, use the default prefix: android.hardware and default root path
-defined in $TOP.
-
-examples:
-
-croot
-hidl-gen -o output -L c++ -r android.hardware:hardware/interfaces -r android.hidl:system/libhidl/transport android.hardware.nfc@1.0::INfc.hal
-hidl-gen -o output -L vts -r android.hardware:hardware/interfaces -r android.hidl:system/libhidl/transport android.hardware.nfc@1.0
-hidl-gen -o test -L c++ -r android.hardware:hardware/interfaces -r android.hidl:system/libhidl/transport android.hardware.nfc@1.0
-hidl-gen -L hash -r android.hardware:hardware/interfaces -r android.hidl:system/libhidl/transport android.hardware.nfc@1.0
+hidl-gen -o output -L c++-impl -r android.hardware:hardware/interfaces -r android.hidl:system/libhidl/transport android.hardware.nfc@1.0
```
+
+Some defaults for package roots are also provided
+
+```
+hidl-gen -o output -L c++-impl android.hardware.nfc@1.0
+hidl-gen -o output -L vts android.hardware.nfc@1.0
+hidl-gen -L hash android.hardware.nfc@1.0
+```
+
+Example command for vendor project
+
+```
+hidl-gen -L c++-impl -r vendor.foo:vendor/foo/interfaces vendor.foo.nfc@1.0
+```
+
+See update-makefiles-helper.sh and update-all-google-makefiles.sh for examples
+of how to generate HIDL makefiles (using the -Landroidbp option).
+
+# c2hal
+
+This is a helper tool to convert C headers to valid .hal files.
+
+```
+m c2hal && c2hal -h
+```
+
+# docs
+
+This tool generates html documentation for hal interfaces.
+
+```
+m hidl-doc && hidl-doc -h
+```
\ No newline at end of file
diff --git a/Reference.h b/Reference.h
index 7ddc889..ba39ac4 100644
--- a/Reference.h
+++ b/Reference.h
@@ -113,7 +113,7 @@
// Valid only while not resolved to prevent confusion when
// ref.hasLookupFqName() is false while ref,get()->fqName is valid.
CHECK(!isResolved());
- return mFqName.isValid();
+ return mFqName != FQName();
}
template <class OtherT>
diff --git a/ScalarType.cpp b/ScalarType.cpp
index 2e2e7b2..dc02b69 100644
--- a/ScalarType.cpp
+++ b/ScalarType.cpp
@@ -83,7 +83,7 @@
return kName[mKind];
}
-std::string ScalarType::getJavaWrapperType() const {
+std::string ScalarType::getJavaTypeClass() const {
static const char *const kName[] = {
"Boolean",
"Byte",
@@ -225,7 +225,7 @@
case KIND_INT16: // fallthrough
case KIND_UINT16: {
// Because Byte and Short doesn't have toHexString, we have to use Integer.toHexString.
- out << "Integer.toHexString(" << getJavaWrapperType() << ".toUnsignedInt(("
+ out << "Integer.toHexString(" << getJavaTypeClass() << ".toUnsignedInt(("
<< getJavaType(false /* forInitializer */) << ")(" << name << ")))";
break;
}
@@ -233,7 +233,7 @@
case KIND_UINT32: // fallthrough
case KIND_INT64: // fallthrough
case KIND_UINT64: {
- out << getJavaWrapperType() << ".toHexString(" << name << ")";
+ out << getJavaTypeClass() << ".toHexString(" << name << ")";
break;
}
case KIND_FLOAT: // fallthrough
diff --git a/ScalarType.h b/ScalarType.h
index 86305b8..10fb540 100644
--- a/ScalarType.h
+++ b/ScalarType.h
@@ -54,8 +54,8 @@
bool specifyNamespaces) const override;
std::string getJavaType(bool forInitializer) const override;
+ std::string getJavaTypeClass() const override;
- std::string getJavaWrapperType() const override;
std::string getJavaSuffix() const override;
std::string getVtsType() const override;
diff --git a/Scope.cpp b/Scope.cpp
index bff097f..d4953aa 100644
--- a/Scope.cpp
+++ b/Scope.cpp
@@ -81,7 +81,7 @@
}
LocalIdentifier *Scope::lookupIdentifier(const std::string & /*name*/) const {
- return NULL;
+ return nullptr;
}
bool Scope::isScope() const {
@@ -93,10 +93,10 @@
return static_cast<Interface *>(mTypes[0]);
}
- return NULL;
+ return nullptr;
}
-bool Scope::containsInterfaces() const {
+bool Scope::definesInterfaces() const {
for (const NamedType *type : mTypes) {
if (type->isInterface()) {
return true;
@@ -177,6 +177,12 @@
}
}
+void Scope::emitPackageTypeHeaderDefinitions(Formatter& out) const {
+ for (const Type* type : mTypes) {
+ type->emitPackageTypeHeaderDefinitions(out);
+ }
+}
+
void Scope::emitPackageHwDeclarations(Formatter& out) const {
for (const Type* type : mTypes) {
type->emitPackageHwDeclarations(out);
diff --git a/Scope.h b/Scope.h
index e8c9431..bf7d1cd 100644
--- a/Scope.h
+++ b/Scope.h
@@ -51,7 +51,7 @@
// Returns the single interface or NULL.
Interface *getInterface() const;
- bool containsInterfaces() const;
+ bool definesInterfaces() const;
const std::vector<Annotation*>& annotations() const;
@@ -66,6 +66,7 @@
void emitTypeDeclarations(Formatter& out) const override;
void emitGlobalTypeDeclarations(Formatter& out) const override;
void emitPackageTypeDeclarations(Formatter& out) const override;
+ void emitPackageTypeHeaderDefinitions(Formatter& out) const override;
void emitPackageHwDeclarations(Formatter& out) const override;
void emitJavaTypeDeclarations(Formatter& out, bool atTopLevel) const override;
diff --git a/StringType.cpp b/StringType.cpp
index a07086f..b4f72be 100644
--- a/StringType.cpp
+++ b/StringType.cpp
@@ -150,9 +150,12 @@
void StringType::emitJavaFieldInitializer(
Formatter &out, const std::string &fieldName) const {
- out << "String "
- << fieldName
- << " = new String();\n";
+ emitJavaFieldDefaultInitialValue(out, "String " + fieldName);
+}
+
+void StringType::emitJavaFieldDefaultInitialValue(
+ Formatter &out, const std::string &declaredFieldName) const {
+ out << declaredFieldName << " = new String();\n";
}
void StringType::emitJavaFieldReaderWriter(
@@ -180,7 +183,7 @@
// hidl_string's embedded buffer is never null(able), because it defaults to a
// buffer containing an empty string.
- out << fieldName << ".getBytes().length + 1,\n"
+ out << "(" << getJavaTypeCast(fieldName) << ").getBytes().length + 1,\n"
<< blobName
<< ".handle(),\n"
<< offset
diff --git a/StringType.h b/StringType.h
index a4e3691..2050875 100644
--- a/StringType.h
+++ b/StringType.h
@@ -65,6 +65,9 @@
void emitJavaFieldInitializer(
Formatter &out, const std::string &fieldName) const override;
+ void emitJavaFieldDefaultInitialValue(
+ Formatter &out, const std::string &declaredFieldName) const override;
+
void emitJavaFieldReaderWriter(
Formatter &out,
size_t depth,
diff --git a/Type.cpp b/Type.cpp
index 84be36f..256b052 100644
--- a/Type.cpp
+++ b/Type.cpp
@@ -64,10 +64,6 @@
return false;
}
-bool Type::isBinder() const {
- return false;
-}
-
bool Type::isNamedType() const {
return false;
}
@@ -158,9 +154,10 @@
return ret;
}
-status_t Type::recursivePass(const std::function<status_t(Type*)>& func,
+status_t Type::recursivePass(ParseStage stage, const std::function<status_t(Type*)>& func,
std::unordered_set<const Type*>* visited) {
- if (mIsPostParseCompleted) return OK;
+ if (mParseStage > stage) return OK;
+ if (mParseStage < stage) return UNKNOWN_ERROR;
if (visited->find(this) != visited->end()) return OK;
visited->insert(this);
@@ -169,21 +166,22 @@
if (err != OK) return err;
for (auto* nextType : getDefinedTypes()) {
- err = nextType->recursivePass(func, visited);
+ err = nextType->recursivePass(stage, func, visited);
if (err != OK) return err;
}
for (auto* nextRef : getReferences()) {
- err = nextRef->shallowGet()->recursivePass(func, visited);
+ err = nextRef->shallowGet()->recursivePass(stage, func, visited);
if (err != OK) return err;
}
return OK;
}
-status_t Type::recursivePass(const std::function<status_t(const Type*)>& func,
+status_t Type::recursivePass(ParseStage stage, const std::function<status_t(const Type*)>& func,
std::unordered_set<const Type*>* visited) const {
- if (mIsPostParseCompleted) return OK;
+ if (mParseStage > stage) return OK;
+ if (mParseStage < stage) return UNKNOWN_ERROR;
if (visited->find(this) != visited->end()) return OK;
visited->insert(this);
@@ -192,12 +190,12 @@
if (err != OK) return err;
for (const auto* nextType : getDefinedTypes()) {
- err = nextType->recursivePass(func, visited);
+ err = nextType->recursivePass(stage, func, visited);
if (err != OK) return err;
}
for (const auto* nextRef : getReferences()) {
- err = nextRef->shallowGet()->recursivePass(func, visited);
+ err = nextRef->shallowGet()->recursivePass(stage, func, visited);
if (err != OK) return err;
}
@@ -319,13 +317,13 @@
}
const ScalarType *Type::resolveToScalarType() const {
- return NULL;
+ return nullptr;
}
bool Type::isValidEnumStorageType() const {
const ScalarType *scalarType = resolveToScalarType();
- if (scalarType == NULL) {
+ if (scalarType == nullptr) {
return false;
}
@@ -354,9 +352,13 @@
return false;
}
-void Type::setPostParseCompleted() {
- CHECK(!mIsPostParseCompleted);
- mIsPostParseCompleted = true;
+Type::ParseStage Type::getParseStage() const {
+ return mParseStage;
+}
+
+void Type::setParseStage(ParseStage stage) {
+ CHECK(mParseStage < stage);
+ mParseStage = stage;
}
Scope* Type::parent() {
@@ -368,7 +370,7 @@
}
std::string Type::getCppType(StorageMode, bool) const {
- CHECK(!"Should not be here");
+ CHECK(!"Should not be here") << typeName();
return std::string();
}
@@ -378,26 +380,30 @@
}
std::string Type::getJavaType(bool /* forInitializer */) const {
- CHECK(!"Should not be here");
+ CHECK(!"Should not be here") << typeName();
return std::string();
}
-std::string Type::getJavaWrapperType() const {
+std::string Type::getJavaTypeClass() const {
return getJavaType();
}
+std::string Type::getJavaTypeCast(const std::string& objName) const {
+ return "(" + getJavaType() + ") " + objName;
+}
+
std::string Type::getJavaSuffix() const {
- CHECK(!"Should not be here");
+ CHECK(!"Should not be here") << typeName();
return std::string();
}
std::string Type::getVtsType() const {
- CHECK(!"Should not be here");
+ CHECK(!"Should not be here") << typeName();
return std::string();
}
std::string Type::getVtsValueName() const {
- CHECK(!"Should not be here");
+ CHECK(!"Should not be here") << typeName();
return std::string();
}
@@ -408,7 +414,7 @@
bool,
bool,
ErrorMode) const {
- CHECK(!"Should not be here");
+ CHECK(!"Should not be here") << typeName();
}
void Type::emitResolveReferences(
@@ -419,7 +425,7 @@
bool,
bool,
ErrorMode) const {
- CHECK(!"Should not be here");
+ CHECK(!"Should not be here") << typeName();
}
void Type::emitResolveReferencesEmbedded(
@@ -434,7 +440,7 @@
ErrorMode,
const std::string &,
const std::string &) const {
- CHECK(!"Should not be here");
+ CHECK(!"Should not be here") << typeName();
}
void Type::emitDump(
@@ -468,10 +474,6 @@
return needsResolveReferences();
}
-bool Type::useNameInEmitReaderWriterEmbedded(bool) const {
- return needsEmbeddedReadWrite();
-}
-
void Type::emitReaderWriterEmbedded(
Formatter &,
size_t,
@@ -484,7 +486,7 @@
ErrorMode,
const std::string &,
const std::string &) const {
- CHECK(!"Should not be here");
+ CHECK(!"Should not be here") << typeName();
}
void Type::emitJavaReaderWriter(
@@ -510,6 +512,8 @@
<< ";\n";
}
+void Type::emitJavaFieldDefaultInitialValue(Formatter &, const std::string &) const {}
+
void Type::emitJavaFieldReaderWriter(
Formatter &,
size_t,
@@ -518,7 +522,7 @@
const std::string &,
const std::string &,
bool) const {
- CHECK(!"Should not be here");
+ CHECK(!"Should not be here") << typeName();
}
void Type::handleError(Formatter &out, ErrorMode mode) const {
@@ -621,6 +625,8 @@
void Type::emitPackageTypeDeclarations(Formatter&) const {}
+void Type::emitPackageTypeHeaderDefinitions(Formatter&) const {}
+
void Type::emitPackageHwDeclarations(Formatter&) const {}
void Type::emitTypeDefinitions(Formatter&, const std::string&) const {}
@@ -665,6 +671,10 @@
return getCppType(StorageMode_Argument, specifyNamespaces);
}
+std::string Type::getCppTypeCast(const std::string& objName, bool specifyNamespaces) const {
+ return "(" + getCppStackType(specifyNamespaces) + ") " + objName;
+}
+
void Type::emitJavaReaderWriterWithSuffix(
Formatter &out,
const std::string &parcelObj,
diff --git a/Type.h b/Type.h
index a0ed5bc..2462f56 100644
--- a/Type.h
+++ b/Type.h
@@ -42,7 +42,6 @@
virtual ~Type();
virtual bool isArray() const;
- virtual bool isBinder() const;
virtual bool isBitField() const;
virtual bool isCompoundType() const;
virtual bool isEnum() const;
@@ -79,11 +78,24 @@
std::vector<Reference<Type>*> getStrongReferences();
virtual std::vector<const Reference<Type>*> getStrongReferences() const;
+ // Indicate stage of parsing.
+ enum class ParseStage {
+ // Indicate that the source file is being parsed and this object is being filled.
+ PARSE,
+ // Indicate that all source files are parsed, and program is working on type dependencies
+ // and validation.
+ POST_PARSE,
+ // Indicate that parsing is completed, and program is in code-generation stage.
+ COMPLETED,
+ };
+
// Proceeds recursive pass
// Makes sure to visit each node only once.
- status_t recursivePass(const std::function<status_t(Type*)>& func,
+ // If mParseStage < stage, object is not ready for this recursivePass() call
+ // yet, and function will return error.
+ status_t recursivePass(ParseStage stage, const std::function<status_t(Type*)>& func,
std::unordered_set<const Type*>* visited);
- status_t recursivePass(const std::function<status_t(const Type*)>& func,
+ status_t recursivePass(ParseStage stage, const std::function<status_t(const Type*)>& func,
std::unordered_set<const Type*>* visited) const;
// Recursive tree pass that completes type declarations
@@ -128,9 +140,9 @@
bool canCheckEquality(std::unordered_set<const Type*>* visited) const;
virtual bool deepCanCheckEquality(std::unordered_set<const Type*>* visited) const;
- // Marks that package proceeding is completed
- // Post parse passes must be proceeded during owner package parsing
- void setPostParseCompleted();
+ // ParseStage can only be incremented.
+ ParseStage getParseStage() const;
+ void setParseStage(ParseStage stage);
Scope* parent();
const Scope* parent() const;
@@ -157,13 +169,22 @@
std::string getCppArgumentType(bool specifyNamespaces = true) const;
+ std::string getCppTypeCast(const std::string& objName,
+ bool specifyNamespaces = true) const;
+
// For an array type, dimensionality information will be accumulated at the
// end of the returned string.
// if forInitializer == true, actual dimensions are included, i.e. [3][5],
// otherwise (and by default), they are omitted, i.e. [][].
virtual std::string getJavaType(bool forInitializer = false) const;
- virtual std::string getJavaWrapperType() const;
+ // Identical to getJavaType() for most types, except: primitives, in which
+ // case the wrapper type is returned, and generics (such as ArrayList<?>),
+ // where the type specialization is omitted to facilitate use of
+ // instanceof or class.isInstance().
+ virtual std::string getJavaTypeClass() const;
+
+ virtual std::string getJavaTypeCast(const std::string& objName) const;
virtual std::string getJavaSuffix() const;
virtual std::string getVtsType() const;
@@ -230,8 +251,6 @@
virtual bool useParentInEmitResolveReferencesEmbedded() const;
- virtual bool useNameInEmitReaderWriterEmbedded(bool isReader) const;
-
virtual void emitJavaReaderWriter(
Formatter &out,
const std::string &parcelObj,
@@ -242,6 +261,10 @@
Formatter &out,
const std::string &fieldName) const;
+ virtual void emitJavaFieldDefaultInitialValue(
+ Formatter &out,
+ const std::string &declaredFieldName) const;
+
virtual void emitJavaFieldReaderWriter(
Formatter &out,
size_t depth,
@@ -261,11 +284,20 @@
virtual void emitTypeForwardDeclaration(Formatter& out) const;
// Emit any declarations pertaining to this type that have to be
- // at global scope, i.e. enum class operators.
+ // directly in a namespace, i.e. enum class operators.
// For android.hardware.foo@1.0::*, this will be in namespace
// android::hardware::foo::V1_0
virtual void emitPackageTypeDeclarations(Formatter& out) const;
+ // Emit any definitions pertaining to this type that have to be
+ // directly in a namespace. Typically, these are things that are only
+ // used for a small subset of types, so by putting them in the header,
+ // the space cost is moved to the small number of clients that use the
+ // feature.
+ // For android.hardware.foo@1.0::*, this will be in namespace
+ // android::hardware::foo::V1_0
+ virtual void emitPackageTypeHeaderDefinitions(Formatter& out) const;
+
// Emit any declarations pertaining to this type that have to be
// at global scope for transport, e.g. read/writeEmbeddedTo/FromParcel
// For android.hardware.foo@1.0::*, this will be in namespace
@@ -341,7 +373,7 @@
const std::string &name) const;
private:
- bool mIsPostParseCompleted = false;
+ ParseStage mParseStage = ParseStage::PARSE;
Scope* const mParent;
DISALLOW_COPY_AND_ASSIGN(Type);
diff --git a/TypeDef.cpp b/TypeDef.cpp
index dcefc57..2543d49 100644
--- a/TypeDef.cpp
+++ b/TypeDef.cpp
@@ -27,7 +27,7 @@
const ScalarType *TypeDef::resolveToScalarType() const {
CHECK(!"Should not be here");
- return NULL;
+ return nullptr;
}
Type* TypeDef::referencedType() {
diff --git a/VectorType.cpp b/VectorType.cpp
index 03604dc..f883da7 100644
--- a/VectorType.cpp
+++ b/VectorType.cpp
@@ -45,6 +45,9 @@
return true;
}
if (elementType->isCompoundType()) {
+ if (static_cast<const CompoundType*>(elementType)->containsInterface()) {
+ return false;
+ }
return true;
}
if (elementType->isInterface()) {
@@ -72,7 +75,7 @@
}
bool VectorType::isVectorOfBinders() const {
- return mElementType->isBinder();
+ return mElementType->isInterface();
}
bool VectorType::deepCanCheckEquality(std::unordered_set<const Type*>* visited) const {
@@ -110,17 +113,15 @@
}
std::string VectorType::getJavaType(bool /* forInitializer */) const {
+ const std::string elementJavaType = mElementType->isTemplatedType()
+ ? mElementType->getJavaType()
+ : mElementType->getJavaTypeClass();
- std::string elementJavaType;
- if (mElementType->isArray()) {
- elementJavaType = mElementType->getJavaType();
- } else {
- elementJavaType = mElementType->getJavaWrapperType();
- }
+ return "java.util.ArrayList<" + elementJavaType + ">";
+}
- return "java.util.ArrayList<"
- + elementJavaType
- + ">";
+std::string VectorType::getJavaTypeClass() const {
+ return "java.util.ArrayList";
}
std::string VectorType::getVtsType() const {
@@ -544,14 +545,17 @@
void VectorType::emitJavaFieldInitializer(
Formatter &out, const std::string &fieldName) const {
- std::string javaType = getJavaType(false /* forInitializer */);
+ const std::string typeName = getJavaType(false /* forInitializer */);
+ const std::string fieldDeclaration = typeName + " " + fieldName;
- out << "final "
- << javaType
- << " "
- << fieldName
+ emitJavaFieldDefaultInitialValue(out, fieldDeclaration);
+}
+
+void VectorType::emitJavaFieldDefaultInitialValue(
+ Formatter &out, const std::string &declaredFieldName) const {
+ out << declaredFieldName
<< " = new "
- << javaType
+ << getJavaType(false /* forInitializer */)
<< "();\n";
}
@@ -563,13 +567,18 @@
const std::string &fieldName,
const std::string &offset,
bool isReader) const {
+
+ const std::string fieldNameWithCast = isReader
+ ? "(" + getJavaTypeCast(fieldName) + ")"
+ : fieldName;
+
VectorType::EmitJavaFieldReaderWriterForElementType(
out,
depth,
mElementType.get(),
parcelName,
blobName,
- fieldName,
+ fieldNameWithCast,
offset,
isReader);
}
diff --git a/VectorType.h b/VectorType.h
index 6f6ede7..cc889c9 100644
--- a/VectorType.h
+++ b/VectorType.h
@@ -43,6 +43,7 @@
bool specifyNamespaces) const override;
std::string getJavaType(bool forInitializer) const override;
+ std::string getJavaTypeClass() const override;
std::string getVtsType() const override;
std::string getVtsValueName() const override;
@@ -101,6 +102,9 @@
void emitJavaFieldInitializer(
Formatter &out, const std::string &fieldName) const override;
+ void emitJavaFieldDefaultInitialValue(
+ Formatter &out, const std::string &declaredFieldName) const override;
+
void emitJavaFieldReaderWriter(
Formatter &out,
size_t depth,
diff --git a/build/hidl_interface.go b/build/hidl_interface.go
index 55cba94..bd99cfa 100644
--- a/build/hidl_interface.go
+++ b/build/hidl_interface.go
@@ -15,9 +15,10 @@
package hidl
import (
+ "fmt"
"strings"
- "sync"
+ "github.com/google/blueprint"
"github.com/google/blueprint/proptools"
"android/soong/android"
@@ -28,19 +29,123 @@
var (
hidlInterfaceSuffix = "_interface"
+
+ pctx = android.NewPackageContext("android/hidl")
+
+ hidl = pctx.HostBinToolVariable("hidl", "hidl-gen")
+ hidlRule = pctx.StaticRule("hidlRule", blueprint.RuleParams{
+ Depfile: "${depfile}",
+ Deps: blueprint.DepsGCC,
+ Command: "rm -rf ${genDir} && ${hidl} -R -p . -d ${depfile} -o ${genDir} -L ${language} ${roots} ${fqName}",
+ CommandDeps: []string{"${hidl}"},
+ Description: "HIDL ${language}: ${in} => ${out}",
+ }, "depfile", "fqName", "genDir", "language", "roots")
)
func init() {
android.RegisterModuleType("hidl_interface", hidlInterfaceFactory)
}
+type hidlGenProperties struct {
+ Language string
+ FqName string
+ Root string
+ Interfaces []string
+ Inputs []string
+ Outputs []string
+}
+
+type hidlGenRule struct {
+ android.ModuleBase
+
+ properties hidlGenProperties
+
+ genOutputDir android.Path
+ genInputs android.Paths
+ genOutputs android.WritablePaths
+}
+
+var _ android.SourceFileProducer = (*hidlGenRule)(nil)
+var _ genrule.SourceFileGenerator = (*hidlGenRule)(nil)
+
+func (g *hidlGenRule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ g.genOutputDir = android.PathForModuleGen(ctx)
+
+ for _, input := range g.properties.Inputs {
+ g.genInputs = append(g.genInputs, android.PathForModuleSrc(ctx, input))
+ }
+
+ for _, output := range g.properties.Outputs {
+ g.genOutputs = append(g.genOutputs, android.PathForModuleGen(ctx, output))
+ }
+
+ var fullRootOptions []string
+ var currentPaths android.Paths
+ ctx.VisitDirectDeps(func(dep android.Module) {
+ switch t := dep.(type) {
+ case *hidlInterface:
+ fullRootOptions = append(fullRootOptions, t.properties.Full_root_option)
+ case *hidlPackageRoot:
+ currentPaths = append(currentPaths, t.getCurrentPaths()...)
+ default:
+ panic(fmt.Sprintf("Unrecognized hidlGenProperties dependency: %T", t))
+ }
+ })
+
+ if len(currentPaths) > 1 {
+ panic(fmt.Sprintf("Expecting one or zero current paths, but found: %v", currentPaths))
+ }
+
+ fullRootOptions = android.FirstUniqueStrings(fullRootOptions)
+
+ ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+ Rule: hidlRule,
+ Inputs: append(g.genInputs, currentPaths...),
+ Output: g.genOutputs[0],
+ ImplicitOutputs: g.genOutputs[1:],
+ Args: map[string]string{
+ "depfile": g.genOutputs[0].String() + ".d",
+ "genDir": g.genOutputDir.String(),
+ "fqName": g.properties.FqName,
+ "language": g.properties.Language,
+ "roots": strings.Join(fullRootOptions, " "),
+ },
+ })
+}
+
+func (g *hidlGenRule) GeneratedSourceFiles() android.Paths {
+ return g.genOutputs.Paths()
+}
+
+func (g *hidlGenRule) Srcs() android.Paths {
+ return g.genOutputs.Paths()
+}
+
+func (g *hidlGenRule) GeneratedDeps() android.Paths {
+ return g.genOutputs.Paths()
+}
+
+func (g *hidlGenRule) GeneratedHeaderDirs() android.Paths {
+ return android.Paths{g.genOutputDir}
+}
+
+func (g *hidlGenRule) DepsMutator(ctx android.BottomUpMutatorContext) {
+ ctx.AddDependency(ctx.Module(), nil, g.properties.FqName+hidlInterfaceSuffix)
+ ctx.AddDependency(ctx.Module(), nil, wrap("", g.properties.Interfaces, hidlInterfaceSuffix)...)
+ ctx.AddDependency(ctx.Module(), nil, g.properties.Root)
+}
+
+func hidlGenFactory() android.Module {
+ g := &hidlGenRule{}
+ g.AddProperties(&g.properties)
+ android.InitAndroidModule(g)
+ return g
+}
+
type hidlInterfaceProperties struct {
// Vndk properties for interface library only.
cc.VndkProperties
- // The owner of the module
- Owner *string
-
// List of .hal files which compose this interface.
Srcs []string
@@ -61,16 +166,49 @@
// expressed by @export annotations in the hal files.
Gen_java_constants bool
- // Don't generate "android.hidl.foo@1.0" C library. Instead
- // only generate the genrules so that this package can be
- // included in libhidltransport.
- Core_interface bool
+ // example: -randroid.hardware:hardware/interfaces
+ Full_root_option string `blueprint:"mutated"`
+}
+
+// TODO(b/119771576): These properties are shared by all Android modules, and we are specifically
+// calling these out to be copied to every create module. However, if a new property is added, it
+// could break things because this code has no way to know about that.
+type manuallyInheritCommonProperties struct {
+ Enabled *bool
+ Compile_multilib *string
+ Target struct {
+ Host struct {
+ Compile_multilib *string
+ }
+ Android struct {
+ Compile_multilib *string
+ }
+ }
+ Proprietary *bool
+ Owner *string
+ Vendor *bool
+ Soc_specific *bool
+ Device_specific *bool
+ Product_specific *bool
+ Product_services_specific *bool
+ Recovery *bool
+ Init_rc []string
+ Vintf_fragments []string
+ Required []string
+ Notice *string
+ Dist struct {
+ Targets []string
+ Dest *string
+ Dir *string
+ Suffix *string
+ }
}
type hidlInterface struct {
android.ModuleBase
- properties hidlInterfaceProperties
+ properties hidlInterfaceProperties
+ inheritCommonProperties manuallyInheritCommonProperties
}
func processSources(mctx android.LoadHookContext, srcs []string) ([]string, []string, bool) {
@@ -119,67 +257,16 @@
return dependencies, javaDependencies, !hasError
}
-func getRootList(mctx android.LoadHookContext, interfaces []string) ([]string, bool) {
- var roots []string
- hasError := false
-
- for _, i := range interfaces {
- interfaceObject := lookupInterface(i)
- if interfaceObject == nil {
- mctx.PropertyErrorf("interfaces", "Cannot find interface "+i)
- hasError = true
- continue
- }
- root := interfaceObject.properties.Root
- rootObject := lookupPackageRoot(root)
- if rootObject == nil {
- mctx.PropertyErrorf("interfaces", `Cannot find package root specification for package `+
- `root '%s' needed for module '%s'. Either this is a mispelling of the package `+
- `root, or a new hidl_package_root module needs to be added. For example, you can `+
- `fix this error by adding the following to <some path>/Android.bp:
-
-hidl_package_root {
- name: "%s",
- path: "<some path>",
-}
-
-This corresponds to the "-r%s:<some path>" option that would be passed into hidl-gen.`, root, i, root, root)
- hasError = true
- continue
- }
-
- roots = append(roots, root+":"+rootObject.properties.Path)
- }
-
- return android.FirstUniqueStrings(roots), !hasError
-}
-
-func removeCoreDependencies(mctx android.LoadHookContext, dependencies []string) ([]string, bool) {
+func removeCoreDependencies(mctx android.LoadHookContext, dependencies []string) []string {
var ret []string
- hasError := false
for _, i := range dependencies {
- interfaceObject := lookupInterface(i)
- if interfaceObject == nil {
- mctx.PropertyErrorf("interfaces", "Cannot find interface "+i)
- hasError = true
- continue
- }
-
- if !interfaceObject.properties.Core_interface {
+ if !isCorePackage(i) {
ret = append(ret, i)
}
}
- return ret, !hasError
-}
-
-func hidlGenCommand(lang string, roots []string, name *fqName) *string {
- cmd := "$(location hidl-gen) -d $(depfile) -o $(genDir)"
- cmd += " -L" + lang
- cmd += " " + strings.Join(wrap("-r", roots, ""), " ")
- cmd += " " + name.string()
- return &cmd
+ return ret
}
func hidlInterfaceMutator(mctx android.LoadHookContext, i *hidlInterface) {
@@ -189,7 +276,21 @@
}
if !name.inPackage(i.properties.Root) {
- mctx.PropertyErrorf("root", "Root, "+i.properties.Root+", for "+name.string()+" must be a prefix.")
+ mctx.PropertyErrorf("root", i.properties.Root+" must be a prefix of "+name.string()+".")
+ }
+ if lookupPackageRoot(i.properties.Root) == nil {
+ mctx.PropertyErrorf("interfaces", `Cannot find package root specification for package `+
+ `root '%s' needed for module '%s'. Either this is a mispelling of the package `+
+ `root, or a new hidl_package_root module needs to be added. For example, you can `+
+ `fix this error by adding the following to <some path>/Android.bp:
+
+hidl_package_root {
+name: "%s",
+path: "<some path>",
+}
+
+This corresponds to the "-r%s:<some path>" option that would be passed into hidl-gen.`,
+ i.properties.Root, name, i.properties.Root, i.properties.Root)
}
interfaces, types, _ := processSources(mctx, i.properties.Srcs)
@@ -199,14 +300,13 @@
}
dependencies, javaDependencies, _ := processDependencies(mctx, i.properties.Interfaces)
- roots, _ := getRootList(mctx, append(dependencies, name.string()))
- cppDependencies, _ := removeCoreDependencies(mctx, dependencies)
+ cppDependencies := removeCoreDependencies(mctx, dependencies)
if mctx.Failed() {
return
}
- shouldGenerateLibrary := !i.properties.Core_interface
+ shouldGenerateLibrary := !isCorePackage(name.string())
// explicitly true if not specified to give early warning to devs
shouldGenerateJava := i.properties.Gen_java == nil || *i.properties.Gen_java
shouldGenerateJavaConstants := i.properties.Gen_java_constants
@@ -217,46 +317,47 @@
}
// TODO(b/69002743): remove filegroups
- mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.FileGroupFactory), &fileGroupProperties{
- Name: proptools.StringPtr(name.fileGroupName()),
- Owner: i.properties.Owner,
- Srcs: i.properties.Srcs,
- })
+ mctx.CreateModule(android.ModuleFactoryAdaptor(android.FileGroupFactory), &fileGroupProperties{
+ Name: proptools.StringPtr(name.fileGroupName()),
+ Srcs: i.properties.Srcs,
+ }, &i.inheritCommonProperties)
- mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProperties{
- Name: proptools.StringPtr(name.sourcesName()),
- Depfile: proptools.BoolPtr(true),
- Owner: i.properties.Owner,
- Tools: []string{"hidl-gen"},
- Cmd: hidlGenCommand("c++-sources", roots, name),
- Srcs: i.properties.Srcs,
- Out: concat(wrap(name.dir(), interfaces, "All.cpp"),
- wrap(name.dir(), types, ".cpp")),
- })
- mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProperties{
- Name: proptools.StringPtr(name.headersName()),
- Depfile: proptools.BoolPtr(true),
- Owner: i.properties.Owner,
- Tools: []string{"hidl-gen"},
- Cmd: hidlGenCommand("c++-headers", roots, name),
- Srcs: i.properties.Srcs,
- Out: concat(wrap(name.dir()+"I", interfaces, ".h"),
+ mctx.CreateModule(android.ModuleFactoryAdaptor(hidlGenFactory), &nameProperties{
+ Name: proptools.StringPtr(name.sourcesName()),
+ }, &hidlGenProperties{
+ Language: "c++-sources",
+ FqName: name.string(),
+ Root: i.properties.Root,
+ Interfaces: i.properties.Interfaces,
+ Inputs: i.properties.Srcs,
+ Outputs: concat(wrap(name.dir(), interfaces, "All.cpp"), wrap(name.dir(), types, ".cpp")),
+ }, &i.inheritCommonProperties)
+ mctx.CreateModule(android.ModuleFactoryAdaptor(hidlGenFactory), &nameProperties{
+ Name: proptools.StringPtr(name.headersName()),
+ }, &hidlGenProperties{
+ Language: "c++-headers",
+ FqName: name.string(),
+ Root: i.properties.Root,
+ Interfaces: i.properties.Interfaces,
+ Inputs: i.properties.Srcs,
+ Outputs: concat(wrap(name.dir()+"I", interfaces, ".h"),
wrap(name.dir()+"Bs", interfaces, ".h"),
wrap(name.dir()+"BnHw", interfaces, ".h"),
wrap(name.dir()+"BpHw", interfaces, ".h"),
wrap(name.dir()+"IHw", interfaces, ".h"),
wrap(name.dir(), types, ".h"),
wrap(name.dir()+"hw", types, ".h")),
- })
+ }, &i.inheritCommonProperties)
if shouldGenerateLibrary {
mctx.CreateModule(android.ModuleFactoryAdaptor(cc.LibraryFactory), &ccProperties{
- Name: proptools.StringPtr(name.string()),
- Owner: i.properties.Owner,
- Vendor_available: proptools.BoolPtr(true),
- Defaults: []string{"hidl-module-defaults"},
- Generated_sources: []string{name.sourcesName()},
- Generated_headers: []string{name.headersName()},
+ Name: proptools.StringPtr(name.string()),
+ Recovery_available: proptools.BoolPtr(true),
+ Vendor_available: proptools.BoolPtr(true),
+ Double_loadable: proptools.BoolPtr(isDoubleLoadable(name.string())),
+ Defaults: []string{"hidl-module-defaults"},
+ Generated_sources: []string{name.sourcesName()},
+ Generated_headers: []string{name.headersName()},
Shared_libs: concat(cppDependencies, []string{
"libhidlbase",
"libhidltransport",
@@ -272,72 +373,80 @@
"libutils",
}),
Export_generated_headers: []string{name.headersName()},
- }, &i.properties.VndkProperties)
+ }, &i.properties.VndkProperties, &i.inheritCommonProperties)
}
if shouldGenerateJava {
- mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProperties{
- Name: proptools.StringPtr(name.javaSourcesName()),
- Depfile: proptools.BoolPtr(true),
- Owner: i.properties.Owner,
- Tools: []string{"hidl-gen"},
- Cmd: hidlGenCommand("java", roots, name),
- Srcs: i.properties.Srcs,
- Out: concat(wrap(name.sanitizedDir()+"I", interfaces, ".java"),
+ mctx.CreateModule(android.ModuleFactoryAdaptor(hidlGenFactory), &nameProperties{
+ Name: proptools.StringPtr(name.javaSourcesName()),
+ }, &hidlGenProperties{
+ Language: "java",
+ FqName: name.string(),
+ Root: i.properties.Root,
+ Interfaces: i.properties.Interfaces,
+ Inputs: i.properties.Srcs,
+ Outputs: concat(wrap(name.sanitizedDir()+"I", interfaces, ".java"),
wrap(name.sanitizedDir(), i.properties.Types, ".java")),
- })
- mctx.CreateModule(android.ModuleFactoryAdaptor(java.LibraryFactory(true)), &javaProperties{
+ }, &i.inheritCommonProperties)
+ mctx.CreateModule(android.ModuleFactoryAdaptor(java.LibraryFactory), &javaProperties{
Name: proptools.StringPtr(name.javaName()),
- Owner: i.properties.Owner,
- Sdk_version: proptools.StringPtr("system_current"),
Defaults: []string{"hidl-java-module-defaults"},
No_framework_libs: proptools.BoolPtr(true),
+ Installable: proptools.BoolPtr(true),
Srcs: []string{":" + name.javaSourcesName()},
- Static_libs: append(javaDependencies, "hwbinder"),
- })
+ Static_libs: javaDependencies,
+
+ // This should ideally be system_current, but android.hidl.base-V1.0-java is used
+ // to build framework, which is used to build system_current. Use core_current
+ // plus hwbinder.stubs, which together form a subset of system_current that does
+ // not depend on framework.
+ Sdk_version: proptools.StringPtr("core_current"),
+ Libs: []string{"hwbinder.stubs"},
+ }, &i.inheritCommonProperties)
}
if shouldGenerateJavaConstants {
- mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProperties{
- Name: proptools.StringPtr(name.javaConstantsSourcesName()),
- Depfile: proptools.BoolPtr(true),
- Owner: i.properties.Owner,
- Tools: []string{"hidl-gen"},
- Cmd: hidlGenCommand("java-constants", roots, name),
- Srcs: i.properties.Srcs,
- Out: []string{name.sanitizedDir() + "Constants.java"},
- })
- mctx.CreateModule(android.ModuleFactoryAdaptor(java.LibraryFactory(true)), &javaProperties{
+ mctx.CreateModule(android.ModuleFactoryAdaptor(hidlGenFactory), &nameProperties{
+ Name: proptools.StringPtr(name.javaConstantsSourcesName()),
+ }, &hidlGenProperties{
+ Language: "java-constants",
+ FqName: name.string(),
+ Root: i.properties.Root,
+ Interfaces: i.properties.Interfaces,
+ Inputs: i.properties.Srcs,
+ Outputs: []string{name.sanitizedDir() + "Constants.java"},
+ }, &i.inheritCommonProperties)
+ mctx.CreateModule(android.ModuleFactoryAdaptor(java.LibraryFactory), &javaProperties{
Name: proptools.StringPtr(name.javaConstantsName()),
- Owner: i.properties.Owner,
Defaults: []string{"hidl-java-module-defaults"},
No_framework_libs: proptools.BoolPtr(true),
Srcs: []string{":" + name.javaConstantsSourcesName()},
- })
+ }, &i.inheritCommonProperties)
}
- mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProperties{
- Name: proptools.StringPtr(name.adapterHelperSourcesName()),
- Depfile: proptools.BoolPtr(true),
- Owner: i.properties.Owner,
- Tools: []string{"hidl-gen"},
- Cmd: hidlGenCommand("c++-adapter-sources", roots, name),
- Srcs: i.properties.Srcs,
- Out: wrap(name.dir()+"A", concat(interfaces, types), ".cpp"),
- })
- mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProperties{
- Name: proptools.StringPtr(name.adapterHelperHeadersName()),
- Depfile: proptools.BoolPtr(true),
- Owner: i.properties.Owner,
- Tools: []string{"hidl-gen"},
- Cmd: hidlGenCommand("c++-adapter-headers", roots, name),
- Srcs: i.properties.Srcs,
- Out: wrap(name.dir()+"A", concat(interfaces, types), ".h"),
- })
+ mctx.CreateModule(android.ModuleFactoryAdaptor(hidlGenFactory), &nameProperties{
+ Name: proptools.StringPtr(name.adapterHelperSourcesName()),
+ }, &hidlGenProperties{
+ Language: "c++-adapter-sources",
+ FqName: name.string(),
+ Root: i.properties.Root,
+ Interfaces: i.properties.Interfaces,
+ Inputs: i.properties.Srcs,
+ Outputs: wrap(name.dir()+"A", concat(interfaces, types), ".cpp"),
+ }, &i.inheritCommonProperties)
+ mctx.CreateModule(android.ModuleFactoryAdaptor(hidlGenFactory), &nameProperties{
+ Name: proptools.StringPtr(name.adapterHelperHeadersName()),
+ }, &hidlGenProperties{
+ Language: "c++-adapter-headers",
+ FqName: name.string(),
+ Root: i.properties.Root,
+ Interfaces: i.properties.Interfaces,
+ Inputs: i.properties.Srcs,
+ Outputs: wrap(name.dir()+"A", concat(interfaces, types), ".h"),
+ }, &i.inheritCommonProperties)
mctx.CreateModule(android.ModuleFactoryAdaptor(cc.LibraryFactory), &ccProperties{
Name: proptools.StringPtr(name.adapterHelperName()),
- Owner: i.properties.Owner,
Vendor_available: proptools.BoolPtr(true),
Defaults: []string{"hidl-module-defaults"},
Generated_sources: []string{name.adapterHelperSourcesName()},
@@ -363,19 +472,19 @@
}, wrap("", dependencies, "-adapter-helper"), cppDependencies, libraryIfExists),
Export_generated_headers: []string{name.adapterHelperHeadersName()},
Group_static_libs: proptools.BoolPtr(true),
- })
- mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProperties{
- Name: proptools.StringPtr(name.adapterSourcesName()),
- Depfile: proptools.BoolPtr(true),
- Owner: i.properties.Owner,
- Tools: []string{"hidl-gen"},
- Cmd: hidlGenCommand("c++-adapter-main", roots, name),
- Srcs: i.properties.Srcs,
- Out: []string{"main.cpp"},
- })
+ }, &i.inheritCommonProperties)
+ mctx.CreateModule(android.ModuleFactoryAdaptor(hidlGenFactory), &nameProperties{
+ Name: proptools.StringPtr(name.adapterSourcesName()),
+ }, &hidlGenProperties{
+ Language: "c++-adapter-main",
+ FqName: name.string(),
+ Root: i.properties.Root,
+ Interfaces: i.properties.Interfaces,
+ Inputs: i.properties.Srcs,
+ Outputs: []string{"main.cpp"},
+ }, &i.inheritCommonProperties)
mctx.CreateModule(android.ModuleFactoryAdaptor(cc.TestFactory), &ccProperties{
Name: proptools.StringPtr(name.adapterName()),
- Owner: i.properties.Owner,
Generated_sources: []string{name.adapterSourcesName()},
Shared_libs: []string{
"libbase",
@@ -391,38 +500,71 @@
name.adapterHelperName(),
}, wrap("", dependencies, "-adapter-helper"), cppDependencies, libraryIfExists),
Group_static_libs: proptools.BoolPtr(true),
- })
+ }, &i.inheritCommonProperties)
}
func (h *hidlInterface) Name() string {
return h.ModuleBase.Name() + hidlInterfaceSuffix
}
func (h *hidlInterface) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ visited := false
+ ctx.VisitDirectDeps(func(dep android.Module) {
+ if visited {
+ panic("internal error, multiple dependencies found but only one added")
+ }
+ visited = true
+ h.properties.Full_root_option = dep.(*hidlPackageRoot).getFullPackageRoot()
+ })
+ if !visited {
+ panic("internal error, no dependencies found but dependency added")
+ }
+
}
func (h *hidlInterface) DepsMutator(ctx android.BottomUpMutatorContext) {
+ ctx.AddDependency(ctx.Module(), nil, h.properties.Root)
}
-var hidlInterfaceMutex sync.Mutex
-var hidlInterfaces []*hidlInterface
-
func hidlInterfaceFactory() android.Module {
i := &hidlInterface{}
i.AddProperties(&i.properties)
+ i.AddProperties(&i.inheritCommonProperties)
android.InitAndroidModule(i)
android.AddLoadHook(i, func(ctx android.LoadHookContext) { hidlInterfaceMutator(ctx, i) })
- hidlInterfaceMutex.Lock()
- hidlInterfaces = append(hidlInterfaces, i)
- hidlInterfaceMutex.Unlock()
-
return i
}
-func lookupInterface(name string) *hidlInterface {
- for _, i := range hidlInterfaces {
- if i.ModuleBase.Name() == name {
- return i
+var doubleLoadablePackageNames = []string{
+ "android.hardware.configstore@",
+ "android.hardware.graphics.allocator@",
+ "android.hardware.graphics.bufferqueue@",
+ "android.hardware.media.omx@",
+ "android.hardware.media@",
+ "android.hardware.neuralnetworks@",
+ "android.hidl.allocator@",
+ "android.hidl.token@",
+}
+
+func isDoubleLoadable(name string) bool {
+ for _, pkgname := range doubleLoadablePackageNames {
+ if strings.HasPrefix(name, pkgname) {
+ return true
}
}
- return nil
+ return false
+}
+
+// packages in libhidltransport
+var coreDependencyPackageNames = []string{
+ "android.hidl.base@",
+ "android.hidl.manager@",
+}
+
+func isCorePackage(name string) bool {
+ for _, pkgname := range coreDependencyPackageNames {
+ if strings.HasPrefix(name, pkgname) {
+ return true
+ }
+ }
+ return false
}
diff --git a/build/hidl_package_root.go b/build/hidl_package_root.go
index 1f68af4..14e0e18 100644
--- a/build/hidl_package_root.go
+++ b/build/hidl_package_root.go
@@ -17,6 +17,8 @@
import (
"sync"
+ "github.com/google/blueprint/proptools"
+
"android/soong/android"
)
@@ -28,12 +30,33 @@
android.ModuleBase
properties struct {
- // path to this module from root
- Path string
+ // Path to the package root from android build root. It is recommended not to set this and
+ // use the current path. This will be deprecated in the future.
+ Path *string
+
+ // True if there should be a current.txt API file here.
+ Use_current *bool
}
+
+ currentPaths android.Paths
+}
+
+func (r *hidlPackageRoot) getFullPackageRoot() string {
+ return "-r" + r.Name() + ":" + *r.properties.Path
+}
+
+func (r *hidlPackageRoot) getCurrentPaths() android.Paths {
+ return r.currentPaths
}
func (r *hidlPackageRoot) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ if r.properties.Path == nil {
+ r.properties.Path = proptools.StringPtr(ctx.ModuleDir())
+ }
+
+ if proptools.BoolDefault(r.properties.Use_current, false) {
+ r.currentPaths = append(r.currentPaths, android.PathForModuleSrc(ctx, "current.txt"))
+ }
}
func (r *hidlPackageRoot) DepsMutator(ctx android.BottomUpMutatorContext) {
}
diff --git a/build/properties.go b/build/properties.go
index d2f8a35..a08e0bd 100644
--- a/build/properties.go
+++ b/build/properties.go
@@ -24,21 +24,12 @@
Srcs []string
}
-type genruleProperties struct {
- Name *string
- Owner *string
- Tools []string
- Cmd *string
- Srcs []string
- Out []string
- Depfile *bool
-}
-
type ccProperties struct {
Name *string
Owner *string
Defaults []string
Vendor_available *bool
+ Recovery_available *bool
Generated_sources []string
Generated_headers []string
Group_static_libs *bool
@@ -47,6 +38,7 @@
Export_shared_lib_headers []string
Export_static_lib_headers []string
Export_generated_headers []string
+ Double_loadable *bool
}
type javaProperties struct {
@@ -54,6 +46,7 @@
Owner *string
Defaults []string
No_framework_libs *bool
+ Installable *bool
Sdk_version *string
Srcs []string
Libs []string
diff --git a/c2hal/AST.cpp b/c2hal/AST.cpp
index 783a04e..5e7928c 100644
--- a/c2hal/AST.cpp
+++ b/c2hal/AST.cpp
@@ -37,7 +37,7 @@
const std::string &outputDir,
const std::string &package,
bool isOpenGl)
- : mScanner(NULL),
+ : mScanner(nullptr),
mPath(path),
mOutputDir(outputDir),
mPackage(package),
@@ -47,21 +47,21 @@
AST::~AST() {
delete mExpression;
- if(mDeclarations != NULL) {
+ if(mDeclarations != nullptr) {
for(auto* decl : *mDeclarations) {
delete decl;
}
}
delete mDeclarations;
- if(mInterfaces != NULL) {
+ if(mInterfaces != nullptr) {
for(auto* inter : *mInterfaces) {
delete inter;
}
}
delete mInterfaces;
- if(mIncludes != NULL) {
+ if(mIncludes != nullptr) {
for(auto* incl : *mIncludes) {
delete incl;
}
@@ -116,10 +116,10 @@
}
void AST::processContents() {
- CHECK(mDeclarations != NULL);
+ CHECK(mDeclarations != nullptr);
for (auto &declaration : *mDeclarations) {
- CHECK(declaration != NULL);
+ CHECK(declaration != nullptr);
declaration->processContents(*this);
}
@@ -209,7 +209,7 @@
auto var = new EnumVarDeclaration(define->getName(),
define->getExpression());
- define->setExpression(NULL);
+ define->setExpression(nullptr);
constants->push_back(var);
it = mDeclarations->erase(it);
@@ -233,7 +233,7 @@
}
status_t AST::generateCode() const {
- CHECK(mDeclarations != NULL);
+ CHECK(mDeclarations != nullptr);
status_t err;
@@ -259,7 +259,7 @@
FILE *file = fopen((getFileDir() + fileName).c_str(), "w");
- if(file == NULL) {
+ if(file == nullptr) {
return -errno;
}
@@ -280,7 +280,7 @@
FILE *file = fopen((getFileDir() + "types.hal").c_str(), "w");
- if(file == NULL) {
+ if(file == nullptr) {
return -errno;
}
diff --git a/c2hal/AST.h b/c2hal/AST.h
index c3d6c5c..813efcb 100644
--- a/c2hal/AST.h
+++ b/c2hal/AST.h
@@ -62,18 +62,18 @@
Scope<Define *> &getDefinesScope();
private:
- void * mScanner = NULL;
+ void * mScanner = nullptr;
std::string mPath;
std::string mOutputDir;
std::string mPackage;
bool mIsOpenGl;
- Expression* mExpression = NULL;
+ Expression* mExpression = nullptr;
- std::vector<Declaration *> *mDeclarations = NULL;
- std::vector<CompositeDeclaration *> *mInterfaces = NULL;
- std::vector<Include *> *mIncludes = NULL;
+ std::vector<Declaration *> *mDeclarations = nullptr;
+ std::vector<CompositeDeclaration *> *mInterfaces = nullptr;
+ std::vector<Include *> *mIncludes = nullptr;
Scope<Define *> mDefinesScope;
diff --git a/c2hal/Android.bp b/c2hal/Android.bp
index 3dd9c6a..4c34235 100644
--- a/c2hal/Android.bp
+++ b/c2hal/Android.bp
@@ -36,6 +36,7 @@
shared_libs: [
"libbase",
"liblog",
+ "libhidl-gen-host-utils",
"libhidl-gen-utils",
],
diff --git a/c2hal/CompositeDeclaration.cpp b/c2hal/CompositeDeclaration.cpp
index 70cf775..13d04a6 100644
--- a/c2hal/CompositeDeclaration.cpp
+++ b/c2hal/CompositeDeclaration.cpp
@@ -37,7 +37,7 @@
}
CompositeDeclaration::~CompositeDeclaration() {
- if(mFieldDeclarations != NULL) {
+ if(mFieldDeclarations != nullptr) {
for(auto* decl : *mFieldDeclarations) {
delete decl;
}
diff --git a/c2hal/Define.cpp b/c2hal/Define.cpp
index 6c3248e..6938226 100644
--- a/c2hal/Define.cpp
+++ b/c2hal/Define.cpp
@@ -53,7 +53,7 @@
}
mExpression = ast.getExpression();
- ast.setExpression(NULL);
+ ast.setExpression(nullptr);
mExpressionType = mExpression->getType(ast);
diff --git a/c2hal/Define.h b/c2hal/Define.h
index e66159d..6f84974 100644
--- a/c2hal/Define.h
+++ b/c2hal/Define.h
@@ -44,7 +44,7 @@
const std::string mSlurp;
Expression::Type mExpressionType;
- Expression* mExpression = NULL;
+ Expression* mExpression = nullptr;
DISALLOW_COPY_AND_ASSIGN(Define);
};
diff --git a/c2hal/EnumVarDeclaration.cpp b/c2hal/EnumVarDeclaration.cpp
index d0218a3..f2673c4 100644
--- a/c2hal/EnumVarDeclaration.cpp
+++ b/c2hal/EnumVarDeclaration.cpp
@@ -43,7 +43,7 @@
void EnumVarDeclaration::generateSource(Formatter &out) const {
out << getName();
- if(mExpression != NULL) {
+ if(mExpression != nullptr) {
out << " = " << mExpression->toString(StringHelper::kUpperSnakeCase);
}
diff --git a/c2hal/EnumVarDeclaration.h b/c2hal/EnumVarDeclaration.h
index cb62ff3..a6d2d3f 100644
--- a/c2hal/EnumVarDeclaration.h
+++ b/c2hal/EnumVarDeclaration.h
@@ -41,7 +41,7 @@
void processContents(AST &ast) override;
private:
- Expression *mExpression = NULL;
+ Expression *mExpression = nullptr;
DISALLOW_COPY_AND_ASSIGN(EnumVarDeclaration);
};
diff --git a/c2hal/Expression.cpp b/c2hal/Expression.cpp
index 0ab864f..4ac92e4 100644
--- a/c2hal/Expression.cpp
+++ b/c2hal/Expression.cpp
@@ -111,7 +111,7 @@
Define *define = ast.getDefinesScope().lookup(mValue);
- if (define == NULL) {
+ if (define == nullptr) {
return Type::UNKNOWN;
}
@@ -228,7 +228,7 @@
: mId(id), mArgs(args)
{}
~FunctionCall() {
- if(mArgs != NULL) {
+ if(mArgs != nullptr) {
for(auto* args : *mArgs) {
delete args;
}
diff --git a/c2hal/FunctionDeclaration.cpp b/c2hal/FunctionDeclaration.cpp
index 12b7dc0..493b317 100644
--- a/c2hal/FunctionDeclaration.cpp
+++ b/c2hal/FunctionDeclaration.cpp
@@ -35,7 +35,7 @@
FunctionDeclaration::~FunctionDeclaration() {
delete mType;
- if(mParams != NULL) {
+ if(mParams != nullptr) {
for(auto* param : *mParams) {
delete param;
}
diff --git a/c2hal/Type.cpp b/c2hal/Type.cpp
index 9e21c01..ea8e6c0 100644
--- a/c2hal/Type.cpp
+++ b/c2hal/Type.cpp
@@ -26,13 +26,13 @@
{}
Type::~Type() {
- if(mArrays != NULL) {
+ if(mArrays != nullptr) {
for(auto* array : *mArrays) {
delete array;
}
}
- if(mQualifiers != NULL) {
+ if(mQualifiers != nullptr) {
for(auto* qual : *mQualifiers) {
delete qual;
}
@@ -115,7 +115,7 @@
}
const std::string Type::getHidlType() const {
- if (mQualifiers == NULL) {
+ if (mQualifiers == nullptr) {
return "";
}
@@ -175,7 +175,7 @@
}
}
- if (mArrays != NULL) {
+ if (mArrays != nullptr) {
for (const auto &array : *mArrays) {
ss << "[" << array->toString() << "]";
}
@@ -185,7 +185,7 @@
}
const std::string Type::getRawQualifierList() const {
- if (mQualifiers == NULL) {
+ if (mQualifiers == nullptr) {
return "";
}
@@ -240,13 +240,13 @@
}
std::string Type::removeLastId() {
- if(mQualifiers == NULL || mQualifiers->size() == 0) {
+ if(mQualifiers == nullptr || mQualifiers->size() == 0) {
return "";
}
Qualifier *last = (*mQualifiers)[mQualifiers->size() - 1];
- if(last == NULL || last->qualification != Qualifier::ID) {
+ if(last == nullptr || last->qualification != Qualifier::ID) {
return "";
}
diff --git a/c2hal/Type.h b/c2hal/Type.h
index 8cd0477..dc7d13d 100644
--- a/c2hal/Type.h
+++ b/c2hal/Type.h
@@ -104,10 +104,10 @@
const std::string getRawQualifierList() const;
const std::string getSpecialTypeName() const;
- std::vector<Qualifier*> *mQualifiers = NULL;
+ std::vector<Qualifier*> *mQualifiers = nullptr;
/* [ expression ] [ expression ] ... [ expression ] */
- std::vector<Expression*> *mArrays = NULL;
+ std::vector<Expression*> *mArrays = nullptr;
DISALLOW_COPY_AND_ASSIGN(Type);
};
diff --git a/docs/src/main.kt b/docs/src/main.kt
index 2069d2e..60cf0b7 100644
--- a/docs/src/main.kt
+++ b/docs/src/main.kt
@@ -47,7 +47,7 @@
if (writer.writeToFile()) println("$LOG_NAME Wrote file: ${writer.path}")
} catch (ex: ParseException) {
- if (config.skipError) {
+ if (config.warnOnly) {
System.err.println("$LOG_NAME Error parsing file, skipping: $fp")
continue
} else {
diff --git a/docs/src/parser/config.kt b/docs/src/parser/config.kt
index 125b4ac..38b0576 100644
--- a/docs/src/parser/config.kt
+++ b/docs/src/parser/config.kt
@@ -28,33 +28,27 @@
println("""
Usage: hidl-doc [-i path]
-i=path Add input HAL file or directory to parse
- -o=dir Output directory of generated HTML [${config.outDir}]
+ -o=dir Output directory of generated HTML
-x=path Exclude file or directory from files to parse
-v Verbose mode, print parsing info
-h Print this help and exit
Error modes:
-w Warn on errors instead of exiting
-l Lint. Warn-only and do not generate files
- -e Error and exit on warnings
- -s Skip files that encounter parse errors
""".trim())
}
object config {
val files = mutableListOf<File>()
- var outDir = toPath("~/out/hidl-doc/html")
+ lateinit var outDir: Path
var verbose = false
var lintMode = false
var warnOnly = false
- var errorOnly = false
- var skipError = false
override fun toString(): String {
return """
verbose: $verbose
warnOnly: $warnOnly
-errorOnly: $errorOnly
-skipError: $skipError
outDir: $outDir
files: $files
"""
@@ -71,26 +65,24 @@
val dirPathArgs = mutableListOf<Path>()
val filePathArgs = mutableListOf<Path>()
val excludedPathArgs = mutableListOf<Path>()
+ var maybeOutDir: Path? = null
val iter = args.iterator()
- var arg: String
//parse command-line arguments
while (iter.hasNext()) {
- arg = iter.next()
+ var arg = iter.next()
when (arg) {
"-i" -> {
- val path = toPath(iter.next())
+ val path = Paths.get(iter.next())
if (Files.isDirectory(path)) dirPathArgs.add(path) else filePathArgs.add(path)
}
- "-x" -> excludedPathArgs.add(toPath(iter.next()).toAbsolutePath())
- "-o" -> outDir = toPath(iter.next())
+ "-x" -> excludedPathArgs.add(Paths.get(iter.next()).toAbsolutePath())
+ "-o" -> maybeOutDir = Paths.get(iter.next())
"-v" -> verbose = true
"-l" -> { lintMode = true; warnOnly = true }
"-w" -> warnOnly = true
- "-e" -> errorOnly = true
- "-s" -> skipError = true
"-h" -> {
printUsage()
exitProcess(0)
@@ -103,6 +95,12 @@
}
}
+ if (maybeOutDir == null) {
+ System.err.println("Error: No output directory supplied (-o)")
+ exitProcess(1)
+ }
+ outDir = maybeOutDir
+
//collect files (explicitly passed and search directories)
val allFiles = mutableListOf<File>()
@@ -148,9 +146,4 @@
}
}
}
-
- private fun toPath(string: String): Path {
- //replace shell expansion for HOME
- return Paths.get(string.replaceFirst("~", System.getProperty("user.home")))
- }
}
\ No newline at end of file
diff --git a/docs/src/writer/elements/MethodElement.kt b/docs/src/writer/elements/MethodElement.kt
index dcd6c2a..ad5c0ec 100644
--- a/docs/src/writer/elements/MethodElement.kt
+++ b/docs/src/writer/elements/MethodElement.kt
@@ -65,11 +65,11 @@
?.let { formatTextasHTML(it.description, useParagraphs = false) }
?: run {
val msg = "Missing @${tag.value} doc annotation for '${arg.type} ${arg.name}'"
- if (config.errorOnly) {
- throw ParseException(msg, 0)
- } else {
+ if (config.warnOnly) {
warn(msg)
"" //return empty string if it can't find it
+ } else {
+ throw ParseException(msg, 0)
}
}
}
diff --git a/generateCpp.cpp b/generateCpp.cpp
index fa2a3ca..98e3d27 100644
--- a/generateCpp.cpp
+++ b/generateCpp.cpp
@@ -140,8 +140,7 @@
const std::string interfaceName = fqName.getInterfaceName();
const std::string functionName = isTry ? "tryGetService" : "getService";
- out << "// static\n"
- << "::android::sp<" << interfaceName << "> " << interfaceName << "::" << functionName << "("
+ out << "::android::sp<" << interfaceName << "> " << interfaceName << "::" << functionName << "("
<< "const std::string &serviceName, const bool getStub) ";
out.block([&] {
out << "return ::android::hardware::details::getServiceInternal<"
@@ -163,20 +162,7 @@
out << "::android::status_t " << interfaceName << "::registerAsService("
<< "const std::string &serviceName) ";
out.block([&] {
- out << "::android::hardware::details::onRegistration(\""
- << fqName.getPackageAndVersion().string() << "\", \""
- << interfaceName
- << "\", serviceName);\n\n";
- out << "const ::android::sp<::android::hidl::manager::V1_0::IServiceManager> sm\n";
- out.indent(2, [&] {
- out << "= ::android::hardware::defaultServiceManager();\n";
- });
- out.sIf("sm == nullptr", [&] {
- out << "return ::android::INVALID_OPERATION;\n";
- }).endl();
- out << "::android::hardware::Return<bool> ret = "
- << "sm->add(serviceName.c_str(), this);\n"
- << "return ret.isOk() && ret ? ::android::OK : ::android::UNKNOWN_ERROR;\n";
+ out << "return ::android::hardware::details::registerAsServiceInternal(this, serviceName);\n";
}).endl().endl();
out << "bool " << interfaceName << "::registerForNotifications(\n";
@@ -247,7 +233,7 @@
const Interface *superType = iface->superType();
- if (superType == NULL) {
+ if (superType == nullptr) {
out << " : virtual public ::android::RefBase";
} else {
out << " : public "
@@ -338,11 +324,22 @@
out << "};\n\n";
}
+ out << "//\n";
+ out << "// type declarations for package\n";
+ out << "//\n\n";
mRootScope.emitPackageTypeDeclarations(out);
+ out << "//\n";
+ out << "// type header definitions for package\n";
+ out << "//\n\n";
+ mRootScope.emitPackageTypeHeaderDefinitions(out);
out << "\n";
enterLeaveNamespace(out, false /* enter */);
+ out << "\n";
+ out << "//\n";
+ out << "// global type declarations for package\n";
+ out << "//\n\n";
mRootScope.emitGlobalTypeDeclarations(out);
out << "\n#endif // " << guard << "\n";
@@ -391,14 +388,12 @@
return mRootScope.emitTypeDeclarations(out);
}
-static void wrapPassthroughArg(Formatter& out, const NamedReference<Type>* arg,
- bool addPrefixToName, std::function<void(void)> handleError) {
+static std::string wrapPassthroughArg(Formatter& out, const NamedReference<Type>* arg,
+ std::string name, std::function<void(void)> handleError) {
if (!arg->type().isInterface()) {
- return;
+ return name;
}
- std::string name = (addPrefixToName ? "_hidl_out_" : "") + arg->name();
- std::string wrappedName = (addPrefixToName ? "_hidl_out_wrapped_" : "_hidl_wrapped_")
- + arg->name();
+ std::string wrappedName = "_hidl_wrapped_" + name;
const Interface &iface = static_cast<const Interface &>(arg->type());
out << iface.getCppStackType() << " " << wrappedName << ";\n";
// TODO(elsk): b/33754152 Should not wrap this if object is Bs*
@@ -416,12 +411,14 @@
}).sElse([&] {
out << wrappedName << " = " << name << ";\n";
}).endl().endl();
+
+ return wrappedName;
}
-void AST::generatePassthroughMethod(Formatter& out, const Method* method) const {
+void AST::generatePassthroughMethod(Formatter& out, const Method* method, const Interface* superInterface) const {
method->generateCppSignature(out);
- out << " {\n";
+ out << " override {\n";
out.indent();
if (method->isHidlReserved()
@@ -442,20 +439,23 @@
generateCppInstrumentationCall(
out,
InstrumentationEvent::PASSTHROUGH_ENTRY,
- method);
+ method,
+ superInterface);
-
+ std::vector<std::string> wrappedArgNames;
for (const auto &arg : method->args()) {
- wrapPassthroughArg(out, arg, false /* addPrefixToName */, [&] {
+ std::string name = wrapPassthroughArg(out, arg, arg->name(), [&] {
out << "return ::android::hardware::Status::fromExceptionCode(\n";
out.indent(2, [&] {
out << "::android::hardware::Status::EX_TRANSACTION_FAILED,\n"
<< "\"Cannot wrap passthrough interface.\");\n";
});
});
+
+ wrappedArgNames.push_back(name);
}
- out << "auto _hidl_error = ::android::hardware::Void();\n";
+ out << "::android::hardware::Status _hidl_error = ::android::hardware::Status::ok();\n";
out << "auto _hidl_return = ";
if (method->isOneway()) {
@@ -464,10 +464,8 @@
", mEnableInstrumentation = this->mEnableInstrumentation, "
"mInstrumentationCallbacks = this->mInstrumentationCallbacks\n"
<< "#endif // __ANDROID_DEBUGGABLE__\n";
- for (const auto &arg : method->args()) {
- out << ", "
- << (arg->type().isInterface() ? "_hidl_wrapped_" : "")
- << arg->name();
+ for (const std::string& arg : wrappedArgNames) {
+ out << ", " << arg;
}
out << "] {\n";
out.indent();
@@ -480,6 +478,15 @@
out.join(method->args().begin(), method->args().end(), ", ", [&](const auto &arg) {
out << (arg->type().isInterface() ? "_hidl_wrapped_" : "") << arg->name();
});
+
+ std::function<void(void)> kHandlePassthroughError = [&] {
+ out << "_hidl_error = ::android::hardware::Status::fromExceptionCode(\n";
+ out.indent(2, [&] {
+ out << "::android::hardware::Status::EX_TRANSACTION_FAILED,\n"
+ << "\"Cannot wrap passthrough interface.\");\n";
+ });
+ };
+
if (returnsValue && elidedReturn == nullptr) {
// never true if oneway since oneway methods don't return values
@@ -497,46 +504,54 @@
generateCppInstrumentationCall(
out,
InstrumentationEvent::PASSTHROUGH_EXIT,
- method);
+ method,
+ superInterface);
+ std::vector<std::string> wrappedOutNames;
for (const auto &arg : method->results()) {
- wrapPassthroughArg(out, arg, true /* addPrefixToName */, [&] {
- out << "_hidl_error = ::android::hardware::Status::fromExceptionCode(\n";
- out.indent(2, [&] {
- out << "::android::hardware::Status::EX_TRANSACTION_FAILED,\n"
- << "\"Cannot wrap passthrough interface.\");\n";
- });
- out << "return;\n";
- });
+ wrappedOutNames.push_back(
+ wrapPassthroughArg(out, arg, "_hidl_out_" + arg->name(), kHandlePassthroughError));
}
out << "_hidl_cb(";
- out.join(method->results().begin(), method->results().end(), ", ", [&](const auto &arg) {
- out << (arg->type().isInterface() ? "_hidl_out_wrapped_" : "_hidl_out_")
- << arg->name();
- });
+ out.join(wrappedOutNames.begin(), wrappedOutNames.end(), ", ",
+ [&](const std::string& arg) { out << arg; });
out << ");\n";
out.unindent();
out << "});\n\n";
} else {
out << ");\n\n";
- // used by generateCppInstrumentationCall
if (elidedReturn != nullptr) {
- out << "#ifdef __ANDROID_DEBUGGABLE__\n"
- << elidedReturn->type().getCppResultType() << " _hidl_out_" << elidedReturn->name()
- << " = _hidl_return;\n"
- << "#endif // __ANDROID_DEBUGGABLE__\n";
+ const std::string outName = "_hidl_out_" + elidedReturn->name();
+
+ out << elidedReturn->type().getCppResultType() << " " << outName
+ << " = _hidl_return;\n";
+ out << "(void) " << outName << ";\n";
+
+ const std::string wrappedName =
+ wrapPassthroughArg(out, elidedReturn, outName, kHandlePassthroughError);
+
+ if (outName != wrappedName) {
+ // update the original value since it is used by generateCppInstrumentationCall
+ out << outName << " = " << wrappedName << ";\n\n";
+
+ // update the value to be returned
+ out << "_hidl_return = " << outName << "\n;";
+ }
}
generateCppInstrumentationCall(
out,
InstrumentationEvent::PASSTHROUGH_EXIT,
- method);
+ method,
+ superInterface);
}
if (method->isOneway()) {
out.unindent();
out << "});\n";
+ } else {
+ out << "if (!_hidl_error.isOk()) return _hidl_error;\n";
}
out << "return _hidl_return;\n";
@@ -779,9 +794,12 @@
<< mPackage.string() << "::" << baseName
<< "\"\n\n";
- out << "#include <android/log.h>\n";
+ out << "#include <log/log.h>\n";
out << "#include <cutils/trace.h>\n";
out << "#include <hidl/HidlTransportSupport.h>\n\n";
+ out << "#include <hidl/Static.h>\n";
+ out << "#include <hwbinder/ProcessState.h>\n";
+ out << "#include <utils/Trace.h>\n";
if (iface) {
// This is a no-op for IServiceManager itself.
out << "#include <android/hidl/manager/1.0/IServiceManager.h>\n";
@@ -998,7 +1016,7 @@
}
void AST::generateStaticProxyMethodSource(Formatter& out, const std::string& klassName,
- const Method* method) const {
+ const Method* method, const Interface* superInterface) const {
if (method->isHidlReserved() && method->overridesCppImpl(IMPL_PROXY)) {
return;
}
@@ -1037,7 +1055,8 @@
generateCppInstrumentationCall(
out,
InstrumentationEvent::CLIENT_API_ENTRY,
- method);
+ method,
+ superInterface);
out << "::android::hardware::Parcel _hidl_data;\n";
out << "::android::hardware::Parcel _hidl_reply;\n";
@@ -1091,7 +1110,7 @@
<< " */, _hidl_data, &_hidl_reply";
if (method->isOneway()) {
- out << ", " << Interface::FLAG_ONEWAY << " /* oneway */";
+ out << ", " << Interface::FLAG_ONE_WAY->cppValue();
}
out << ");\n";
@@ -1144,7 +1163,8 @@
generateCppInstrumentationCall(
out,
InstrumentationEvent::CLIENT_API_EXIT,
- method);
+ method,
+ superInterface);
if (elidedReturn != nullptr) {
out << "_hidl_status.setFromStatusT(_hidl_err);\n";
@@ -1198,8 +1218,8 @@
out << "}\n\n";
generateMethods(out,
- [&](const Method* method, const Interface*) {
- generateStaticProxyMethodSource(out, klassName, method);
+ [&](const Method* method, const Interface* superInterface) {
+ generateStaticProxyMethodSource(out, klassName, method, superInterface);
},
false /* include parents */);
@@ -1275,8 +1295,8 @@
}).endl().endl();
generateMethods(out,
- [&](const Method* method, const Interface*) {
- return generateStaticStubMethodSource(out, iface->fqName(), method);
+ [&](const Method* method, const Interface* superInterface) {
+ return generateStaticStubMethodSource(out, iface->fqName(), method, superInterface);
},
false /* include parents */);
@@ -1323,8 +1343,8 @@
out.indent();
- out << "bool _hidl_is_oneway = _hidl_flags & " << Interface::FLAG_ONEWAY
- << " /* oneway */;\n";
+ out << "bool _hidl_is_oneway = _hidl_flags & " << Interface::FLAG_ONE_WAY->cppValue()
+ << ";\n";
out << "if (_hidl_is_oneway != " << (method->isOneway() ? "true" : "false") << ") ";
out.block([&] { out << "return ::android::UNKNOWN_ERROR;\n"; }).endl().endl();
@@ -1394,7 +1414,7 @@
}
void AST::generateStaticStubMethodSource(Formatter& out, const FQName& fqName,
- const Method* method) const {
+ const Method* method, const Interface* superInterface) const {
if (method->isHidlReserved() && method->overridesCppImpl(IMPL_STUB)) {
return;
}
@@ -1459,7 +1479,8 @@
generateCppInstrumentationCall(
out,
InstrumentationEvent::SERVER_API_ENTRY,
- method);
+ method,
+ superInterface);
const bool returnsValue = !method->results().empty();
const NamedReference<Type>* elidedReturn = method->canElideCallback();
@@ -1511,7 +1532,8 @@
generateCppInstrumentationCall(
out,
InstrumentationEvent::SERVER_API_EXIT,
- method);
+ method,
+ superInterface);
out << "_hidl_cb(*_hidl_reply);\n";
} else {
@@ -1581,7 +1603,8 @@
generateCppInstrumentationCall(
out,
InstrumentationEvent::SERVER_API_EXIT,
- method);
+ method,
+ superInterface);
out << "_hidl_cb(*_hidl_reply);\n";
@@ -1593,7 +1616,8 @@
generateCppInstrumentationCall(
out,
InstrumentationEvent::SERVER_API_EXIT,
- method);
+ method,
+ superInterface);
}
if (returnsValue) {
@@ -1669,8 +1693,8 @@
generateTemplatizationLink(out);
generateCppTag(out, "android::hardware::details::bs_tag");
- generateMethods(out, [&](const Method* method, const Interface*) {
- generatePassthroughMethod(out, method);
+ generateMethods(out, [&](const Method* method, const Interface* superInterface) {
+ generatePassthroughMethod(out, method, superInterface);
});
out.unindent();
@@ -1721,7 +1745,7 @@
});
for (const Interface *superType : iface->typeChain()) {
- out << "// static \n::android::hardware::Return<"
+ out << "::android::hardware::Return<"
<< childTypeResult
<< "> "
<< iface->localName()
@@ -1813,12 +1837,6 @@
<< baseString + "::server\");\n";
break;
}
- case CLIENT_API_ENTRY:
- {
- out << "atrace_begin(ATRACE_TAG_HAL, \""
- << baseString + "::client\");\n";
- break;
- }
case PASSTHROUGH_ENTRY:
{
out << "atrace_begin(ATRACE_TAG_HAL, \""
@@ -1826,12 +1844,21 @@
break;
}
case SERVER_API_EXIT:
- case CLIENT_API_EXIT:
case PASSTHROUGH_EXIT:
{
out << "atrace_end(ATRACE_TAG_HAL);\n";
break;
}
+ // client uses scope because of gotos
+ // this isn't done for server because the profiled code isn't alone in its scope
+ // this isn't done for passthrough becuase the profiled boundary isn't even in the same code
+ case CLIENT_API_ENTRY: {
+ out << "::android::ScopedTrace PASTE(___tracer, __LINE__) (ATRACE_TAG_HAL, \""
+ << baseString + "::client\");\n";
+ break;
+ }
+ case CLIENT_API_EXIT:
+ break;
default:
{
CHECK(false) << "Unsupported instrumentation event: " << event;
@@ -1842,7 +1869,8 @@
void AST::generateCppInstrumentationCall(
Formatter &out,
InstrumentationEvent event,
- const Method *method) const {
+ const Method *method,
+ const Interface* superInterface) const {
generateCppAtraceCall(out, event, method);
out << "#ifdef __ANDROID_DEBUGGABLE__\n";
@@ -1920,18 +1948,16 @@
}
}
- const Interface* iface = mRootScope.getInterface();
-
out << "for (const auto &callback: mInstrumentationCallbacks) {\n";
out.indent();
out << "callback("
<< event_str
<< ", \""
- << mPackage.package()
+ << superInterface->fqName().package()
<< "\", \""
- << mPackage.version()
+ << superInterface->fqName().version()
<< "\", \""
- << iface->localName()
+ << superInterface->localName()
<< "\", \""
<< method->name()
<< "\", &_hidl_args);\n";
diff --git a/generateCppAdapter.cpp b/generateCppAdapter.cpp
index 1fbfb57..1d88d3c 100644
--- a/generateCppAdapter.cpp
+++ b/generateCppAdapter.cpp
@@ -54,7 +54,7 @@
out << "public:\n";
out << "typedef " << mockName << " Pure;\n";
- out << klassName << "(::android::sp<" << mockName << "> impl);\n";
+ out << klassName << "(const ::android::sp<" << mockName << ">& impl);\n";
generateMethods(out, [&](const Method* method, const Interface* /* interface */) {
if (method->isHidlReserved()) {
@@ -103,8 +103,8 @@
const std::string mockName = getInterface()->fqName().cppName();
- out << klassName << "::" << klassName << "(::android::sp<" << mockName
- << "> impl) : mImpl(impl) {}";
+ out << klassName << "::" << klassName << "(const ::android::sp<" << mockName
+ << ">& impl) : mImpl(impl) {}";
generateMethods(out, [&](const Method* method, const Interface* /* interface */) {
generateAdapterMethod(out, method);
@@ -128,13 +128,6 @@
return;
}
- // TODO(b/66900959): if we are creating the adapter for a 1.1 IFoo
- // and we are using a method that takes/returns a 1.0 Callback, but
- // there exists a 1.1 Callback (or other subclass that is depended
- // on by this module), then wrap with the adapter subclass adapter
- // IFF that callback is a subclass. However, if the callback
- // is 1.0 ICallback, then wrap with a 1.0 adapter.
-
const Interface* interface = static_cast<const Interface*>(type);
out << "static_cast<::android::sp<" << interface->fqName().cppName() << ">>("
<< interface->fqName().cppName() << "::castFrom("
diff --git a/generateCppImpl.cpp b/generateCppImpl.cpp
index 18fac6b..1485119 100644
--- a/generateCppImpl.cpp
+++ b/generateCppImpl.cpp
@@ -77,10 +77,8 @@
const Interface* iface = mRootScope.getInterface();
const std::string baseName = iface->getBaseName();
- const std::string guard = makeHeaderGuard(baseName, false /* indicateGenerated */);
-
- out << "#ifndef " << guard << "\n";
- out << "#define " << guard << "\n\n";
+ out << "// FIXME: your file license if you have one\n\n";
+ out << "#pragma once\n\n";
generateCppPackageInclude(out, mPackage, iface->localName());
@@ -131,8 +129,6 @@
out << "} // namespace implementation\n";
enterLeaveNamespace(out, false /* leave */);
-
- out << "\n#endif // " << guard << "\n";
}
void AST::generateCppImplSource(Formatter& out) const {
@@ -144,6 +140,7 @@
const Interface* iface = mRootScope.getInterface();
const std::string baseName = iface->getBaseName();
+ out << "// FIXME: your file license if you have one\n\n";
out << "#include \"" << baseName << ".h\"\n\n";
enterLeaveNamespace(out, true /* enter */);
diff --git a/generateDependencies.cpp b/generateDependencies.cpp
new file mode 100644
index 0000000..7c47c43
--- /dev/null
+++ b/generateDependencies.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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 "AST.h"
+
+#include <android-base/logging.h>
+#include <hidl-util/Formatter.h>
+#include <string>
+#include <vector>
+
+#include "NamedType.h"
+#include "Type.h"
+
+namespace android {
+
+void AST::generateDependencies(Formatter& out) const {
+ std::unordered_set<const Type*> visited;
+ (void)mRootScope.recursivePass(
+ Type::ParseStage::COMPLETED,
+ [&](const Type* type) {
+ if (type != &mRootScope && type->isNamedType()) {
+ out << static_cast<const NamedType*>(type)->fqName().string() << "\n";
+ }
+ return OK;
+ },
+ &visited);
+}
+
+} // namespace android
diff --git a/generateJava.cpp b/generateJava.cpp
index bdbe25a..33bd289 100644
--- a/generateJava.cpp
+++ b/generateJava.cpp
@@ -130,7 +130,7 @@
out << "public interface " << ifaceName << " extends ";
- if (superType != NULL) {
+ if (superType != nullptr) {
out << superType->fullJavaName();
} else {
out << "android.os.IHwInterface";
@@ -216,10 +216,6 @@
emitJavaTypeDeclarations(out);
for (const auto &method : iface->methods()) {
- if (method->isHiddenFromJava()) {
- continue;
- }
-
const bool returnsValue = !method->results().empty();
const bool needsCallback = method->results().size() > 1;
@@ -312,10 +308,6 @@
for (const auto &tuple : iface->allMethodsFromRoot()) {
const Method *method = tuple.method();
- if (method->isHiddenFromJava()) {
- continue;
- }
-
const Interface *superInterface = tuple.interface();
if (prevInterface != superInterface) {
out << "// Methods from "
@@ -383,7 +375,7 @@
<< " */, _hidl_request, _hidl_reply, ";
if (method->isOneway()) {
- out << Interface::FLAG_ONEWAY << " /* oneway */";
+ out << Interface::FLAG_ONE_WAY->javaValue();
} else {
out << "0 /* flags */";
}
@@ -457,19 +449,15 @@
out << "}\n\n";
for (Method *method : iface->hidlReservedMethods()) {
- if (method->isHiddenFromJava()) {
- continue;
- }
-
// b/32383557 this is a hack. We need to change this if we have more reserved methods.
CHECK_LE(method->results().size(), 1u);
std::string resultType = method->results().size() == 0 ? "void" :
method->results()[0]->type().getJavaType();
- out << "@Override\npublic final "
- << resultType
- << " "
- << method->name()
- << "(";
+
+ bool canBeOverriden = method->name() == "debug";
+
+ out << "@Override\npublic " << (canBeOverriden ? "" : "final ") << resultType << " "
+ << method->name() << "(";
method->emitJavaArgSignature(out);
out << ") {\n";
@@ -535,8 +523,8 @@
out.indent();
- out << "boolean _hidl_is_oneway = (_hidl_flags & " << Interface::FLAG_ONEWAY
- << " /* oneway */) != 0\n;";
+ out << "boolean _hidl_is_oneway = (_hidl_flags & " << Interface::FLAG_ONE_WAY->javaValue()
+ << ") != 0;\n";
out << "if (_hidl_is_oneway != " << (method->isOneway() ? "true" : "false") << ") ";
out.block([&] {
out << "_hidl_reply.writeStatus(" << UNKNOWN_ERROR << ");\n";
@@ -556,19 +544,6 @@
<< superInterface->fullJavaName()
<< ".kInterfaceName);\n\n";
- if (method->isHiddenFromJava()) {
- // This is a method hidden from the Java side of things, it must not
- // return any value and will simply signal success.
- CHECK(!returnsValue);
-
- out << "_hidl_reply.writeStatus(android.os.HwParcel.STATUS_SUCCESS);\n";
- out << "_hidl_reply.send();\n";
- out << "break;\n";
- out.unindent();
- out << "}\n\n";
- continue;
- }
-
for (const auto &arg : method->args()) {
emitJavaReaderWriter(
out,
diff --git a/generateVts.cpp b/generateVts.cpp
index 8a37ae3..722a656 100644
--- a/generateVts.cpp
+++ b/generateVts.cpp
@@ -53,12 +53,12 @@
const Interface *iface = AST::getInterface();
out << "component_class: HAL_HIDL\n";
- out << "component_type_version: " << mPackage.version()
- << "\n";
out << "component_name: \""
<< (iface ? iface->localName() : "types")
<< "\"\n\n";
+ out << "component_type_version_major: " << mPackage.getPackageMajorVersion() << "\n";
+ out << "component_type_version_minor: " << mPackage.getPackageMinorVersion() << "\n";
out << "package: \"" << mPackage.package() << "\"\n\n";
// Generate import statement for all imported interface/types.
@@ -78,17 +78,15 @@
out << "interface: {\n";
out.indent();
- std::vector<const Interface *> chain = iface->typeChain();
-
// Generate all the attribute declarations first.
emitVtsTypeDeclarations(out);
// Generate all the method declarations.
- for (auto it = chain.rbegin(); it != chain.rend(); ++it) {
- const Interface *superInterface = *it;
- superInterface->emitVtsMethodDeclaration(out);
+ for (const Interface* superInterface : iface->superTypeChain()) {
+ superInterface->emitVtsMethodDeclaration(out, true /*isInhereted*/);
}
+ iface->emitVtsMethodDeclaration(out, false /*isInhereted*/);
out.unindent();
out << "}\n";
} else {
diff --git a/hashing/Android.bp b/hashing/Android.bp
new file mode 100644
index 0000000..9f63a27
--- /dev/null
+++ b/hashing/Android.bp
@@ -0,0 +1,26 @@
+// 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.
+
+cc_library {
+ name: "libhidl-gen-hash",
+ host_supported: true,
+ defaults: ["hidl-gen-defaults"],
+ srcs: ["Hash.cpp"],
+ export_include_dirs: ["include"],
+ shared_libs: [
+ "libbase",
+ "libcrypto",
+ "libssl",
+ ],
+}
diff --git a/Hash.cpp b/hashing/Hash.cpp
similarity index 78%
rename from Hash.cpp
rename to hashing/Hash.cpp
index 7eb315b..e88ce17 100644
--- a/Hash.cpp
+++ b/hashing/Hash.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "Hash.h"
+#include <hidl-hash/Hash.h>
#include <algorithm>
#include <fstream>
@@ -50,7 +50,7 @@
getMutableHash(path).mHash = kEmptyHash;
}
-static std::vector<uint8_t> sha256File(const std::string &path) {
+static std::vector<uint8_t> sha256File(const std::string& path) {
std::ifstream stream(path);
std::stringstream fileStream;
fileStream << stream.rdbuf();
@@ -58,17 +58,14 @@
std::vector<uint8_t> ret = std::vector<uint8_t>(SHA256_DIGEST_LENGTH);
- SHA256(reinterpret_cast<const uint8_t *>(fileContent.c_str()),
- fileContent.size(), ret.data());
+ SHA256(reinterpret_cast<const uint8_t*>(fileContent.c_str()), fileContent.size(), ret.data());
return ret;
}
-Hash::Hash(const std::string &path)
- : mPath(path),
- mHash(sha256File(path)) {}
+Hash::Hash(const std::string& path) : mPath(path), mHash(sha256File(path)) {}
-std::string Hash::hexString(const std::vector<uint8_t> &hash) {
+std::string Hash::hexString(const std::vector<uint8_t>& hash) {
std::ostringstream s;
s << std::hex << std::setfill('0');
for (uint8_t i : hash) {
@@ -81,11 +78,11 @@
return hexString(mHash);
}
-const std::vector<uint8_t> &Hash::raw() const {
+const std::vector<uint8_t>& Hash::raw() const {
return mHash;
}
-const std::string &Hash::getPath() const {
+const std::string& Hash::getPath() const {
return mPath;
}
@@ -94,14 +91,11 @@
#define SPACES " +"
#define MAYBE_SPACES " *"
#define OPTIONAL_COMMENT "(?:#.*)?"
-static const std::regex kHashLine(
- "(?:"
- MAYBE_SPACES HASH SPACES FQNAME MAYBE_SPACES
- ")?"
- OPTIONAL_COMMENT);
+static const std::regex kHashLine("(?:" MAYBE_SPACES HASH SPACES FQNAME MAYBE_SPACES
+ ")?" OPTIONAL_COMMENT);
struct HashFile {
- static const HashFile *parse(const std::string &path, std::string *err) {
+ static const HashFile* parse(const std::string& path, std::string* err) {
static std::map<std::string, HashFile*> hashfiles;
auto it = hashfiles.find(path);
@@ -112,7 +106,7 @@
return it->second;
}
- std::vector<std::string> lookup(const std::string &fqName) const {
+ std::vector<std::string> lookup(const std::string& fqName) const {
auto it = hashes.find(fqName);
if (it == hashes.end()) {
@@ -122,18 +116,18 @@
return it->second;
}
-private:
- static HashFile *readHashFile(const std::string &path, std::string *err) {
+ private:
+ static HashFile* readHashFile(const std::string& path, std::string* err) {
std::ifstream stream(path);
if (!stream) {
return nullptr;
}
- HashFile *file = new HashFile();
+ HashFile* file = new HashFile();
file->path = path;
std::string line;
- while(std::getline(stream, line)) {
+ while (std::getline(stream, line)) {
std::smatch match;
bool valid = std::regex_match(line, match, kHashLine);
@@ -164,13 +158,13 @@
}
std::string path;
- std::map<std::string,std::vector<std::string>> hashes;
+ std::map<std::string, std::vector<std::string>> hashes;
};
std::vector<std::string> Hash::lookupHash(const std::string& path, const std::string& interfaceName,
std::string* err, bool* fileExists) {
*err = "";
- const HashFile *file = HashFile::parse(path, err);
+ const HashFile* file = HashFile::parse(path, err);
if (file == nullptr || err->size() > 0) {
if (fileExists != nullptr) *fileExists = false;
@@ -182,4 +176,4 @@
return file->lookup(interfaceName);
}
-} // android
+} // namespace android
diff --git a/include_hash/hidl-hash/Hash.h b/hashing/include/hidl-hash/Hash.h
similarity index 80%
rename from include_hash/hidl-hash/Hash.h
rename to hashing/include/hidl-hash/Hash.h
index e443ef5..edb667e 100644
--- a/include_hash/hidl-hash/Hash.h
+++ b/hashing/include/hidl-hash/Hash.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef HIDL_GEN_HASH_HASH_H_
-#define HIDL_GEN_HASH_HASH_H_
+#pragma once
#include <string>
#include <vector>
@@ -26,7 +25,7 @@
static const std::vector<uint8_t> kEmptyHash;
// path to .hal file
- static const Hash &getHash(const std::string &path);
+ static const Hash& getHash(const std::string& path);
static void clearHash(const std::string& path);
// returns matching hashes of interfaceName in path
@@ -36,14 +35,14 @@
const std::string& interfaceName, std::string* err,
bool* fileExists = nullptr);
- static std::string hexString(const std::vector<uint8_t> &hash);
+ static std::string hexString(const std::vector<uint8_t>& hash);
std::string hexString() const;
- const std::vector<uint8_t> &raw() const;
- const std::string &getPath() const;
+ const std::vector<uint8_t>& raw() const;
+ const std::string& getPath() const;
-private:
- Hash(const std::string &path);
+ private:
+ Hash(const std::string& path);
static Hash& getMutableHash(const std::string& path);
@@ -52,6 +51,3 @@
};
} // namespace android
-
-#endif // HIDL_GEN_HASH_HASH_H_
-
diff --git a/hidl-gen_l.ll b/hidl-gen_l.ll
index c94df01..835d8f6 100644
--- a/hidl-gen_l.ll
+++ b/hidl-gen_l.ll
@@ -68,11 +68,6 @@
#define YY_USER_ACTION yylloc->step(); yylloc->columns(yyleng);
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunused-parameter"
-#pragma clang diagnostic ignored "-Wdeprecated-register"
-#pragma clang diagnostic ignored "-Wregister"
-
%}
%option yylineno
@@ -111,6 +106,7 @@
"import" { return token::IMPORT; }
"interface" { return token::INTERFACE; }
"package" { return token::PACKAGE; }
+"safe_union" { return token::SAFE_UNION; }
"struct" { return token::STRUCT; }
"typedef" { return token::TYPEDEF; }
"union" { return token::UNION; }
@@ -173,6 +169,7 @@
"!=" { return(token::NEQ); }
"?" { return('?'); }
"@" { return('@'); }
+"#" { return('#'); }
{COMPONENT} { yylval->str = strdup(yytext); return token::IDENTIFIER; }
{FQNAME} { yylval->str = strdup(yytext); return token::FQNAME; }
@@ -193,8 +190,6 @@
%%
-#pragma clang diagnostic pop
-
namespace android {
status_t parseFile(AST* ast, std::unique_ptr<FILE, std::function<void(FILE *)>> file) {
diff --git a/hidl-gen_y.yy b/hidl-gen_y.yy
index f445199..65f4323 100644
--- a/hidl-gen_y.yy
+++ b/hidl-gen_y.yy
@@ -107,13 +107,22 @@
return true;
}
+bool isValidCompoundTypeField(CompoundType::Style style, const std::string& identifier,
+ std::string *errorMsg) {
+ // Unions don't support fix-up types; as such, they can't
+ // have name collisions with embedded read/write methods.
+ if (style == CompoundType::STYLE_UNION) { return true; }
+
+ return isValidStructField(identifier, errorMsg);;
+}
+
bool isValidIdentifier(const std::string& identifier, std::string *errorMsg) {
static const std::vector<std::string> keywords({
"uint8_t", "uint16_t", "uint32_t", "uint64_t",
"int8_t", "int16_t", "int32_t", "int64_t", "bool", "float", "double",
"interface", "struct", "union", "string", "vec", "enum", "ref", "handle",
"package", "import", "typedef", "generates", "oneway", "extends",
- "fmq_sync", "fmq_unsync",
+ "fmq_sync", "fmq_unsync", "safe_union",
});
static const std::vector<std::string> cppKeywords({
"alignas", "alignof", "and", "and_eq", "asm", "atomic_cancel", "atomic_commit",
@@ -234,6 +243,7 @@
%token<str> STRING_LITERAL "string literal"
%token<void> TYPEDEF "keyword `typedef`"
%token<void> UNION "keyword `union`"
+%token<void> SAFE_UNION "keyword `safe_union`"
%token<templatedType> TEMPLATED "templated type"
%token<void> ONEWAY "keyword `oneway`"
%token<str> UNKNOWN "unknown character"
@@ -262,6 +272,8 @@
/* Precedence level 3, RTL; but we have to use %left here */
%left UNARY_MINUS UNARY_PLUS '!' '~'
+%token '#'
+
%type<docComment> doc_comments
%type<str> error_stmt error
@@ -284,7 +296,7 @@
%type<constantExpression> const_expr
%type<enumValue> enum_value commentable_enum_value
%type<enumValues> enum_values enum_declaration_body
-%type<typedVars> typed_vars
+%type<typedVars> typed_vars non_empty_typed_vars
%type<typedVar> typed_var
%type<method> method_declaration commentable_method_declaration
%type<compoundStyle> struct_or_union_keyword
@@ -726,7 +738,8 @@
;
const_expr
- : INTEGER {
+ : INTEGER
+ {
$$ = LiteralConstantExpression::tryParse($1);
if ($$ == nullptr) {
@@ -747,6 +760,11 @@
$$ = new ReferenceConstantExpression(
Reference<LocalIdentifier>(*$1, convertYYLoc(@1)), $1->string());
}
+ | fqname '#' IDENTIFIER
+ {
+ $$ = new AttributeConstantExpression(
+ Reference<Type>(*$1, convertYYLoc(@1)), $1->string(), $3);
+ }
| const_expr '?' const_expr ':' const_expr
{
$$ = new TernaryConstantExpression($1, $3, $5);
@@ -834,7 +852,14 @@
{
$$ = new TypedVarVector();
}
- | typed_var
+ | non_empty_typed_vars
+ {
+ $$ = $1;
+ }
+ ;
+
+non_empty_typed_vars
+ : typed_var
{
$$ = new TypedVarVector();
if (!$$->add($1)) {
@@ -843,7 +868,7 @@
ast->addSyntaxError();
}
}
- | typed_vars ',' typed_var
+ | non_empty_typed_vars ',' typed_var
{
$$ = $1;
if (!$$->add($3)) {
@@ -876,6 +901,7 @@
struct_or_union_keyword
: STRUCT { $$ = CompoundType::STYLE_STRUCT; }
| UNION { $$ = CompoundType::STYLE_UNION; }
+ | SAFE_UNION { $$ = CompoundType::STYLE_SAFE_UNION; }
;
named_struct_or_union_declaration
@@ -929,8 +955,9 @@
CHECK((*scope)->isCompoundType());
std::string errorMsg;
- if (static_cast<CompoundType *>(*scope)->style() == CompoundType::STYLE_STRUCT &&
- !isValidStructField($2, &errorMsg)) {
+ auto style = static_cast<CompoundType *>(*scope)->style();
+
+ if (!isValidCompoundTypeField(style, $2, &errorMsg)) {
std::cerr << "ERROR: " << errorMsg << " at "
<< @2 << "\n";
YYERROR;
@@ -942,9 +969,11 @@
CHECK((*scope)->isCompoundType());
std::string errorMsg;
- if (static_cast<CompoundType *>(*scope)->style() == CompoundType::STYLE_STRUCT &&
- $1 != nullptr && $1->isNamedType() &&
- !isValidStructField(static_cast<NamedType*>($1)->localName().c_str(), &errorMsg)) {
+ auto style = static_cast<CompoundType *>(*scope)->style();
+
+ if ($1 != nullptr && $1->isNamedType() &&
+ !isValidCompoundTypeField(style, static_cast<NamedType*>(
+ $1)->localName().c_str(), &errorMsg)) {
std::cerr << "ERROR: " << errorMsg << " at "
<< @2 << "\n";
YYERROR;
diff --git a/host_utils/Android.bp b/host_utils/Android.bp
new file mode 100644
index 0000000..f6e80f8
--- /dev/null
+++ b/host_utils/Android.bp
@@ -0,0 +1,28 @@
+// 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.
+
+cc_library_host_shared {
+ name: "libhidl-gen-host-utils",
+ defaults: ["hidl-gen-defaults"],
+ srcs: [
+ "Formatter.cpp",
+ "StringHelper.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ ],
+
+ local_include_dirs: ["include/hidl-util"],
+ export_include_dirs: ["include"],
+}
diff --git a/utils/Formatter.cpp b/host_utils/Formatter.cpp
similarity index 96%
rename from utils/Formatter.cpp
rename to host_utils/Formatter.cpp
index 338cb17..b1bc22c 100644
--- a/utils/Formatter.cpp
+++ b/host_utils/Formatter.cpp
@@ -22,10 +22,10 @@
namespace android {
-Formatter::Formatter() : mFile(NULL /* invalid */), mIndentDepth(0), mAtStartOfLine(true) {}
+Formatter::Formatter() : mFile(nullptr /* invalid */), mIndentDepth(0), mAtStartOfLine(true) {}
Formatter::Formatter(FILE* file, size_t spacesPerIndent)
- : mFile(file == NULL ? stdout : file),
+ : mFile(file == nullptr ? stdout : file),
mIndentDepth(0),
mSpacesPerIndent(spacesPerIndent),
mAtStartOfLine(true) {}
@@ -34,7 +34,7 @@
if (mFile != stdout) {
fclose(mFile);
}
- mFile = NULL;
+ mFile = nullptr;
}
void Formatter::indent(size_t level) {
diff --git a/utils/StringHelper.cpp b/host_utils/StringHelper.cpp
similarity index 100%
rename from utils/StringHelper.cpp
rename to host_utils/StringHelper.cpp
diff --git a/utils/include/hidl-util/Formatter.h b/host_utils/include/hidl-util/Formatter.h
similarity index 100%
rename from utils/include/hidl-util/Formatter.h
rename to host_utils/include/hidl-util/Formatter.h
diff --git a/utils/include/hidl-util/StringHelper.h b/host_utils/include/hidl-util/StringHelper.h
similarity index 100%
rename from utils/include/hidl-util/StringHelper.h
rename to host_utils/include/hidl-util/StringHelper.h
diff --git a/main.cpp b/main.cpp
index dabbdaa..0efdf29 100644
--- a/main.cpp
+++ b/main.cpp
@@ -461,10 +461,11 @@
fqName.string() == "android.hardware.graphics.mapper@2.1" ||
fqName.string() == "android.hardware.renderscript@1.0" ||
fqName.string() == "android.hidl.memory.token@1.0" ||
- fqName.string() == "android.hidl.memory@1.0";
+ fqName.string() == "android.hidl.memory@1.0" ||
+ fqName.string() == "android.hidl.safe_union@1.0";
}
-bool isSystemPackage(const FQName &package) {
+bool isCoreAndroidPackage(const FQName& package) {
return package.inPackage("android.hidl") ||
package.inPackage("android.system") ||
package.inPackage("android.frameworks") ||
@@ -534,8 +535,7 @@
static status_t generateAndroidBpForPackage(Formatter& out, const FQName& packageFQName,
const Coordinator* coordinator) {
- CHECK(packageFQName.isValid() && !packageFQName.isFullyQualified() &&
- packageFQName.name().empty());
+ CHECK(!packageFQName.isFullyQualified() && packageFQName.name().empty());
std::vector<FQName> packageInterfaces;
@@ -552,7 +552,7 @@
for (const auto& fqName : packageInterfaces) {
AST* ast = coordinator->parse(fqName);
- if (ast == NULL) {
+ if (ast == nullptr) {
fprintf(stderr, "ERROR: Could not parse %s. Aborting.\n", fqName.string().c_str());
return UNKNOWN_ERROR;
@@ -579,9 +579,15 @@
err = isTestPackage(packageFQName, coordinator, &generateForTest);
if (err != OK) return err;
- bool isVndk = !generateForTest && isSystemPackage(packageFQName);
+ bool isCoreAndroid = isCoreAndroidPackage(packageFQName);
+
+ bool isVndk = !generateForTest && isCoreAndroid;
bool isVndkSp = isVndk && isSystemProcessSupportedPackage(packageFQName);
+ // Currently, all platform-provided interfaces are in the VNDK, so if it isn't in the VNDK, it
+ // is device specific and so should be put in the product partition.
+ bool isProduct = !isCoreAndroid;
+
std::string packageRoot;
err = coordinator->getPackageRoot(packageFQName, &packageRoot);
if (err != OK) return err;
@@ -595,9 +601,6 @@
out << "owner: \"" << coordinator->getOwner() << "\",\n";
}
out << "root: \"" << packageRoot << "\",\n";
- if (isHidlTransportPackage(packageFQName)) {
- out << "core_interface: true,\n";
- }
if (isVndk) {
out << "vndk: ";
out.block([&]() {
@@ -607,6 +610,9 @@
}
}) << ",\n";
}
+ if (isProduct) {
+ out << "product_specific: true,\n";
+ }
(out << "srcs: [\n").indent([&] {
for (const auto& fqName : packageInterfaces) {
out << "\"" << fqName.name() << ".hal\",\n";
@@ -667,7 +673,7 @@
for (const auto &fqName : packageInterfaces) {
AST *ast = coordinator->parse(fqName);
- if (ast == NULL) {
+ if (ast == nullptr) {
fprintf(stderr,
"ERROR: Could not parse %s. Aborting.\n",
fqName.string().c_str());
@@ -678,6 +684,7 @@
ast->getImportedPackages(&importedPackages);
}
+ out << "// FIXME: your file license if you have one\n\n";
out << "cc_library_shared {\n";
out.indent([&] {
out << "// FIXME: this should only be -impl for a passthrough hal.\n"
@@ -785,10 +792,8 @@
FileGenerator::GenerationFunction generateExportHeaderForPackage(bool forJava) {
return [forJava](Formatter& out, const FQName& packageFQName,
const Coordinator* coordinator) -> status_t {
- CHECK(packageFQName.isValid()
- && !packageFQName.package().empty()
- && !packageFQName.version().empty()
- && packageFQName.name().empty());
+ CHECK(!packageFQName.package().empty() && !packageFQName.version().empty() &&
+ packageFQName.name().empty());
std::vector<FQName> packageInterfaces;
@@ -804,7 +809,7 @@
for (const auto &fqName : packageInterfaces) {
AST *ast = coordinator->parse(fqName);
- if (ast == NULL) {
+ if (ast == nullptr) {
fprintf(stderr,
"ERROR: Could not parse %s. Aborting.\n",
fqName.string().c_str());
@@ -874,7 +879,7 @@
AST* ast = coordinator->parse(fqName, {} /* parsed */,
Coordinator::Enforce::NO_HASH /* enforcement */);
- if (ast == NULL) {
+ if (ast == nullptr) {
fprintf(stderr, "ERROR: Could not parse %s. Aborting.\n", fqName.string().c_str());
return UNKNOWN_ERROR;
@@ -1174,13 +1179,28 @@
},
}
},
+ {
+ "dependencies",
+ "Prints all depended types.",
+ OutputMode::NOT_NEEDED,
+ Coordinator::Location::STANDARD_OUT,
+ GenerationGranularity::PER_FILE,
+ validateForSource,
+ {
+ {
+ FileGenerator::alwaysGenerate,
+ nullptr /* file name for fqName */,
+ astGenerationFunction(&AST::generateDependencies),
+ },
+ },
+ },
};
// clang-format on
static void usage(const char *me) {
fprintf(stderr,
"usage: %s [-p <root path>] -o <output path> -L <language> [-O <owner>] (-r <interface "
- "root>)+ [-v] [-d <depfile>] FQNAME...\n\n",
+ "root>)+ [-R] [-v] [-d <depfile>] FQNAME...\n\n",
me);
fprintf(stderr,
@@ -1194,6 +1214,7 @@
fprintf(stderr, " -O <owner>: The owner of the module for -Landroidbp(-impl)?.\n");
fprintf(stderr, " -o <output path>: Location to output files.\n");
fprintf(stderr, " -p <root path>: Android build root, defaults to $ANDROID_BUILD_TOP or pwd.\n");
+ fprintf(stderr, " -R: Do not add default package roots if not specified in -r\n");
fprintf(stderr, " -r <package:path root>: E.g., android.hardware:hardware/interfaces.\n");
fprintf(stderr, " -v: verbose output.\n");
fprintf(stderr, " -d <depfile>: location of depfile to write to.\n");
@@ -1214,9 +1235,10 @@
const OutputHandler* outputFormat = nullptr;
Coordinator coordinator;
std::string outputPath;
+ bool suppressDefaultPackagePaths = false;
int res;
- while ((res = getopt(argc, argv, "hp:o:O:r:L:vd:")) >= 0) {
+ while ((res = getopt(argc, argv, "hp:o:O:r:L:vd:R")) >= 0) {
switch (res) {
case 'p': {
if (!coordinator.getRootPath().empty()) {
@@ -1276,6 +1298,11 @@
break;
}
+ case 'R': {
+ suppressDefaultPackagePaths = true;
+ break;
+ }
+
case 'L': {
if (outputFormat != nullptr) {
fprintf(stderr,
@@ -1365,15 +1392,24 @@
coordinator.setOutputPath(outputPath);
- coordinator.addDefaultPackagePath("android.hardware", "hardware/interfaces");
- coordinator.addDefaultPackagePath("android.hidl", "system/libhidl/transport");
- coordinator.addDefaultPackagePath("android.frameworks", "frameworks/hardware/interfaces");
- coordinator.addDefaultPackagePath("android.system", "system/hardware/interfaces");
+ if (!suppressDefaultPackagePaths) {
+ coordinator.addDefaultPackagePath("android.hardware", "hardware/interfaces");
+ coordinator.addDefaultPackagePath("android.hidl", "system/libhidl/transport");
+ coordinator.addDefaultPackagePath("android.frameworks", "frameworks/hardware/interfaces");
+ coordinator.addDefaultPackagePath("android.system", "system/hardware/interfaces");
+ }
for (int i = 0; i < argc; ++i) {
+ const char* arg = argv[i];
+
FQName fqName;
- if (!FQName::parse(argv[i], &fqName)) {
- fprintf(stderr, "ERROR: Invalid fully-qualified name as argument: %s.\n", argv[i]);
+ if (!FQName::parse(arg, &fqName)) {
+ fprintf(stderr, "ERROR: Invalid fully-qualified name as argument: %s.\n", arg);
+ exit(1);
+ }
+
+ if (coordinator.getPackageInterfaceFiles(fqName, nullptr /*fileNames*/) != OK) {
+ fprintf(stderr, "ERROR: Could not get sources for %s.\n", arg);
exit(1);
}
diff --git a/scripts/gen-docs.sh b/scripts/gen-docs.sh
new file mode 100755
index 0000000..d56ba27
--- /dev/null
+++ b/scripts/gen-docs.sh
@@ -0,0 +1,84 @@
+#!/usr/bin/env bash
+
+# TODO: use the build system to generate docs once we can
+
+# e.x. convertFqName "android.hardware.foo@1.0::foo::IFoo" "\5" -> IFoo
+function convertFqName() {
+ # android.hardware.foo@1.0::foo::IFoo
+ # \1 => android.hardware.foo
+ # \3 => 1
+ # \4 => 0
+ # \5 => IFoo # optional capture group
+ local FQNAME="^(([a-zA-Z0-9]+\.)*[a-zA-Z0-9]+)@([0-9]+).([0-9]+)(::([a-zA-Z0-9]+))?$"
+
+ local fqName="$1"
+ local pattern="$2"
+
+ echo $1 | sed -E "s/$FQNAME/$2/g"
+}
+function assertInterfaceFqName() {
+ if [ -n "$(convertFqName "$1")" ]; then
+ echo "$1 is not an interface fqname"
+ return 1
+ fi
+}
+function javaTarget() { convertFqName "$1" "\1-V\3.\4-java"; }
+function cppTarget() { convertFqName "$1" "\1@\3.\4"; }
+
+function hidl-gen-output() {
+ local out="$1"
+
+ while read -r fqName; do
+ echo "Generating output for $fqName."
+ hidl-gen -Lc++-headers -o "$out/cpp" "$fqName" || exit 1
+ hidl-gen -Ljava -o "$out/java" "$fqName" 2>/dev/null
+ done
+}
+
+function current-interfaces() {
+ [ $# = 1 ] || { echo "usage: current-interfaces <package root directory>" && return 1; }
+
+ local package_root="$1"
+ [ -d "$package_root" ] || { echo "current-interfaces: directory $package_root does not exist" && return 1; }
+
+ local current_file="$package_root/current.txt"
+ [ -f "$current_file" ] || { echo "current-interfaces: current file $current_file does not exist" && return 1; }
+
+ cat "$current_file" | cut -d '#' -f1 | awk '{print $2}' | sed "/^ *$/d" | sort | uniq
+}
+
+function google-interfaces() {
+ local roots=(
+ hardware/interfaces
+ system/hardware/interfaces
+ frameworks/hardware/interfaces
+ system/libhidl/transport
+ )
+
+ for root in "${roots[@]}"; do
+ current-interfaces "$ANDROID_BUILD_TOP/$root"
+ done | sort | uniq
+}
+
+function google-interface-packages() {
+ google-interfaces | cut -d ':' -f1 | sort | uniq
+}
+
+function hidl-doc-generate-sources() {
+ local outputDir="$1"
+ [ -z "$1" ] && outputDir="gen"
+
+ echo "Generating sources in $(realpath $outputDir)"
+
+ google-interface-packages | hidl-gen-output "$outputDir"
+
+ echo "Deleting implementation-related files from $outputDir."
+ rm $(find "$outputDir/cpp" -\( -name "IHw*.h" \
+ -o -name "BnHw*.h" \
+ -o -name "BpHw*.h" \
+ -o -name "Bs*.h" \
+ -o -name "hwtypes.h" \))
+
+ echo "Done: generated sources are in $outputDir"
+}
+
diff --git a/test/Android.bp b/test/Android.bp
new file mode 100644
index 0000000..1459fa6
--- /dev/null
+++ b/test/Android.bp
@@ -0,0 +1,3 @@
+hidl_package_root {
+ name: "hidl.tests",
+}
diff --git a/test/error_test/Android.bp b/test/error_test/Android.bp
index 42345b2..4c8c899 100644
--- a/test/error_test/Android.bp
+++ b/test/error_test/Android.bp
@@ -6,8 +6,6 @@
"echo 'int main(){return 0;}' > $(genDir)/TODO_b_37575883.cpp",
out: ["TODO_b_37575883.cpp"],
srcs: [
- "hidl_error_test.sh",
-
"**/*.hal",
"**/required_error",
],
diff --git a/test/error_test/hidl_error_test.sh b/test/error_test/hidl_error_test.sh
index 2f5d522..d747776 100755
--- a/test/error_test/hidl_error_test.sh
+++ b/test/error_test/hidl_error_test.sh
@@ -1,12 +1,17 @@
#!/bin/bash
-if [ $# -ne 1 ]; then
+if [ $# -gt 1 ]; then
echo "usage: hidl_error_test.sh hidl-gen_path"
exit 1
fi
-readonly HIDL_GEN_PATH=$1
-readonly HIDL_ERROR_TEST_DIR="$ANDROID_BUILD_TOP/system/tools/hidl/test/error_test"
+readonly HIDL_GEN_PATH=${1:-hidl-gen}
+readonly HIDL_ERROR_TEST_DIR="${ANDROID_BUILD_TOP:-.}/system/tools/hidl/test/error_test"
+
+if [ ! -d $HIDL_ERROR_TEST_DIR ]; then
+ echo "cannot find test directory: $HIDL_ERROR_TEST_DIR"
+ exit 1
+fi
for dir in $(ls -d $HIDL_ERROR_TEST_DIR/*/); do
package=$(basename $dir)
diff --git a/test/error_test/len_tag_wrong_type/1.0/IFoo.hal b/test/error_test/len_tag_wrong_type/1.0/IFoo.hal
new file mode 100644
index 0000000..9567c2d
--- /dev/null
+++ b/test/error_test/len_tag_wrong_type/1.0/IFoo.hal
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+package test.missing_variable_type@1.0;
+
+interface IFoo {
+ struct A {};
+
+ enum B : uint32_t {
+ C = A#len, // bad (A is not an enum)
+ };
+};
diff --git a/test/error_test/len_tag_wrong_type/1.0/required_error b/test/error_test/len_tag_wrong_type/1.0/required_error
new file mode 100644
index 0000000..b064671
--- /dev/null
+++ b/test/error_test/len_tag_wrong_type/1.0/required_error
@@ -0,0 +1 @@
+len refers to struct A but should refer to an enum
\ No newline at end of file
diff --git a/test/error_test/no_empty_safe_union/1.0/required_error b/test/error_test/no_empty_safe_union/1.0/required_error
new file mode 100644
index 0000000..be35cb5
--- /dev/null
+++ b/test/error_test/no_empty_safe_union/1.0/required_error
@@ -0,0 +1 @@
+Safe union must contain at least two types to be useful
\ No newline at end of file
diff --git a/test/error_test/no_empty_safe_union/1.0/types.hal b/test/error_test/no_empty_safe_union/1.0/types.hal
new file mode 100644
index 0000000..05d319e
--- /dev/null
+++ b/test/error_test/no_empty_safe_union/1.0/types.hal
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+package test.empty_generates@1.0;
+
+safe_union Empty {};
diff --git a/test/error_test/no_leading_comma_argument_list/1.0/IFoo.hal b/test/error_test/no_leading_comma_argument_list/1.0/IFoo.hal
new file mode 100644
index 0000000..a3946eb
--- /dev/null
+++ b/test/error_test/no_leading_comma_argument_list/1.0/IFoo.hal
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+package test.no_leading_comma_argument_list@1.0;
+
+interface IFoo {
+ foo(, int32_t v);
+};
diff --git a/test/error_test/no_leading_comma_argument_list/1.0/required_error b/test/error_test/no_leading_comma_argument_list/1.0/required_error
new file mode 100644
index 0000000..b8795e6
--- /dev/null
+++ b/test/error_test/no_leading_comma_argument_list/1.0/required_error
@@ -0,0 +1 @@
+syntax error, unexpected ','
diff --git a/test/error_test/no_leading_comma_result_list/1.0/IFoo.hal b/test/error_test/no_leading_comma_result_list/1.0/IFoo.hal
new file mode 100644
index 0000000..dab99cb
--- /dev/null
+++ b/test/error_test/no_leading_comma_result_list/1.0/IFoo.hal
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+package test.no_leading_comma_result_list@1.0;
+
+interface IFoo {
+ foo() generates (, int32_t v);
+};
diff --git a/test/error_test/no_leading_comma_result_list/1.0/required_error b/test/error_test/no_leading_comma_result_list/1.0/required_error
new file mode 100644
index 0000000..b8795e6
--- /dev/null
+++ b/test/error_test/no_leading_comma_result_list/1.0/required_error
@@ -0,0 +1 @@
+syntax error, unexpected ','
diff --git a/test/error_test/no_single_element_safe_union/1.0/required_error b/test/error_test/no_single_element_safe_union/1.0/required_error
new file mode 100644
index 0000000..be35cb5
--- /dev/null
+++ b/test/error_test/no_single_element_safe_union/1.0/required_error
@@ -0,0 +1 @@
+Safe union must contain at least two types to be useful
\ No newline at end of file
diff --git a/test/error_test/no_single_element_safe_union/1.0/types.hal b/test/error_test/no_single_element_safe_union/1.0/types.hal
new file mode 100644
index 0000000..b7ace5b
--- /dev/null
+++ b/test/error_test/no_single_element_safe_union/1.0/types.hal
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+package test.empty_generates@1.0;
+
+safe_union Empty { uint8_t a; };
diff --git a/test/error_test/tag_name_does_not_exist/1.0/IFoo.hal b/test/error_test/tag_name_does_not_exist/1.0/IFoo.hal
new file mode 100644
index 0000000..196da53
--- /dev/null
+++ b/test/error_test/tag_name_does_not_exist/1.0/IFoo.hal
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+package test.missing_variable_type@1.0;
+
+interface IFoo {
+ enum B : uint32_t{
+ C = B#tag_does_not_exist, // bad (this tag doesn't exist)
+ };
+};
diff --git a/test/error_test/tag_name_does_not_exist/1.0/required_error b/test/error_test/tag_name_does_not_exist/1.0/required_error
new file mode 100644
index 0000000..5c7ecba
--- /dev/null
+++ b/test/error_test/tag_name_does_not_exist/1.0/required_error
@@ -0,0 +1 @@
+tag_does_not_exist is not a supported tag
\ No newline at end of file
diff --git a/test/hidl_test/Android.bp b/test/hidl_test/Android.bp
index 73110a6..4308ed7 100644
--- a/test/hidl_test/Android.bp
+++ b/test/hidl_test/Android.bp
@@ -23,6 +23,7 @@
// libs should be used on device.
static_libs: [
"libfootest",
+ "libhidl-gen-utils",
"libpointertest",
"android.hardware.tests.expression@1.0",
"android.hardware.tests.foo@1.0",
@@ -34,6 +35,8 @@
"android.hardware.tests.memory@1.0",
"android.hardware.tests.multithread@1.0",
"android.hardware.tests.trie@1.0",
+ "android.hardware.tests.safeunion.cpp@1.0",
+ "android.hardware.tests.safeunion@1.0",
],
// impls should never be static, these are used only for testing purposes
@@ -49,6 +52,8 @@
"android.hardware.tests.memory@1.0-impl",
"android.hardware.tests.multithread@1.0-impl",
"android.hardware.tests.trie@1.0-impl",
+ "android.hardware.tests.safeunion.cpp@1.0-impl",
+ "android.hardware.tests.safeunion@1.0-impl",
],
group_static_libs: true,
diff --git a/test/hidl_test/Android.mk b/test/hidl_test/Android.mk
index f328223..c82e0ef 100644
--- a/test/hidl_test/Android.mk
+++ b/test/hidl_test/Android.mk
@@ -31,14 +31,14 @@
hidl_test_helper \
hidl_test_servers
-LOCAL_REQUIRED_MODULES_arm64 := hidl_test_servers_32 hidl_test_client_32
-LOCAL_REQUIRED_MODULES_mips64 := hidl_test_servers_32 hidl_test_client_32
-LOCAL_REQUIRED_MODULES_x86_64 := hidl_test_servers_32 hidl_test_client_32
+ifneq ($(TARGET_2ND_ARCH),)
+LOCAL_REQUIRED_MODULES += hidl_test_servers$(TARGET_2ND_ARCH_MODULE_SUFFIX)
+LOCAL_REQUIRED_MODULES += hidl_test_client$(TARGET_2ND_ARCH_MODULE_SUFFIX)
+endif
include $(BUILD_PREBUILT)
include $(CLEAR_VARS)
LOCAL_MODULE := VtsHidlUnitTests
-VTS_CONFIG_SRC_DIR := system/tools/hidl/tests
-include test/vts/tools/build/Android.host_config.mk
diff --git a/test/hidl_test/hidl_test.h b/test/hidl_test/hidl_test.h
index 0ad17ef..3a2f7f7 100644
--- a/test/hidl_test/hidl_test.h
+++ b/test/hidl_test/hidl_test.h
@@ -2,6 +2,7 @@
#define HIDL_TEST_H_
#include <android/hardware/tests/bar/1.0/IBar.h>
+#include <android/hardware/tests/baz/1.0/IBaz.h>
#include <android/hardware/tests/hash/1.0/IHash.h>
#include <android/hardware/tests/inheritance/1.0/IChild.h>
#include <android/hardware/tests/inheritance/1.0/IFetcher.h>
@@ -10,11 +11,14 @@
#include <android/hardware/tests/multithread/1.0/IMultithread.h>
#include <android/hardware/tests/pointer/1.0/IGraph.h>
#include <android/hardware/tests/pointer/1.0/IPointer.h>
+#include <android/hardware/tests/safeunion/1.0/ISafeUnion.h>
+#include <android/hardware/tests/safeunion/cpp/1.0/ICppSafeUnion.h>
#include <android/hardware/tests/trie/1.0/ITrie.h>
template <template <typename Type> class Service>
void runOnEachServer(void) {
using ::android::hardware::tests::bar::V1_0::IBar;
+ using ::android::hardware::tests::baz::V1_0::IBaz;
using ::android::hardware::tests::hash::V1_0::IHash;
using ::android::hardware::tests::inheritance::V1_0::IChild;
using ::android::hardware::tests::inheritance::V1_0::IFetcher;
@@ -23,18 +27,23 @@
using ::android::hardware::tests::multithread::V1_0::IMultithread;
using ::android::hardware::tests::pointer::V1_0::IGraph;
using ::android::hardware::tests::pointer::V1_0::IPointer;
+ using ::android::hardware::tests::safeunion::cpp::V1_0::ICppSafeUnion;
+ using ::android::hardware::tests::safeunion::V1_0::ISafeUnion;
using ::android::hardware::tests::trie::V1_0::ITrie;
Service<IMemoryTest>::run("memory");
Service<IChild>::run("child");
Service<IParent>::run("parent");
Service<IFetcher>::run("fetcher");
+ Service<IBaz>::run("baz");
Service<IBar>::run("foo");
Service<IHash>::run("default");
Service<IGraph>::run("graph");
Service<IPointer>::run("pointer");
Service<IMultithread>::run("multithread");
Service<ITrie>::run("trie");
+ Service<ICppSafeUnion>::run("default");
+ Service<ISafeUnion>::run("safeunion");
}
#endif // HIDL_TEST_H_
diff --git a/test/hidl_test/hidl_test_client.cpp b/test/hidl_test/hidl_test_client.cpp
index 718a32c..e986fc6 100644
--- a/test/hidl_test/hidl_test_client.cpp
+++ b/test/hidl_test/hidl_test_client.cpp
@@ -3,10 +3,11 @@
#include "FooCallback.h"
#include "hidl_test.h"
+#include <android-base/file.h>
#include <android-base/logging.h>
-#include <android/hidl/manager/1.1/IServiceManager.h>
#include <android/hidl/manager/1.0/IServiceNotification.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
#include <android/hidl/allocator/1.0/IAllocator.h>
#include <android/hidl/memory/1.0/IMemory.h>
@@ -19,6 +20,7 @@
#include <android/hardware/tests/bar/1.0/IComplicated.h>
#include <android/hardware/tests/bar/1.0/IImportRules.h>
#include <android/hardware/tests/baz/1.0/IBaz.h>
+#include <android/hardware/tests/expression/1.0/IExpression.h>
#include <android/hardware/tests/foo/1.0/BnHwSimple.h>
#include <android/hardware/tests/foo/1.0/BpHwSimple.h>
#include <android/hardware/tests/foo/1.0/BsSimple.h>
@@ -32,6 +34,9 @@
#include <android/hardware/tests/multithread/1.0/IMultithread.h>
#include <android/hardware/tests/pointer/1.0/IGraph.h>
#include <android/hardware/tests/pointer/1.0/IPointer.h>
+#include <android/hardware/tests/safeunion/1.0/IOtherInterface.h>
+#include <android/hardware/tests/safeunion/1.0/ISafeUnion.h>
+#include <android/hardware/tests/safeunion/cpp/1.0/ICppSafeUnion.h>
#include <android/hardware/tests/trie/1.0/ITrie.h>
#include <gtest/gtest.h>
@@ -51,10 +56,12 @@
#include <condition_variable>
#include <fstream>
#include <future>
+#include <limits>
#include <mutex>
#include <random>
#include <set>
#include <sstream>
+#include <sys/stat.h>
#include <thread>
#include <type_traits>
#include <unordered_set>
@@ -63,6 +70,7 @@
#include <hidl-test/FooHelper.h>
#include <hidl-test/PointerHelper.h>
+#include <hidl-util/FQName.h>
#include <hidl/ServiceManagement.h>
#include <hidl/Status.h>
@@ -90,55 +98,69 @@
static HidlEnvironment *gHidlEnvironment = nullptr;
+using ::android::Condition;
+using ::android::DELAY_NS;
+using ::android::DELAY_S;
+using ::android::FQName;
+using ::android::MultiDimensionalToString;
+using ::android::Mutex;
+using ::android::ONEWAY_TOLERANCE_NS;
+using ::android::sp;
+using ::android::to_string;
+using ::android::TOLERANCE_NS;
+using ::android::wp;
+using ::android::hardware::GrantorDescriptor;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_death_recipient;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::HidlMemory;
+using ::android::hardware::MQDescriptor;
+using ::android::hardware::MQFlavor;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::tests::bar::V1_0::IBar;
+using ::android::hardware::tests::bar::V1_0::IComplicated;
+using ::android::hardware::tests::baz::V1_0::IBaz;
+using ::android::hardware::tests::expression::V1_0::IExpression;
using ::android::hardware::tests::foo::V1_0::Abc;
using ::android::hardware::tests::foo::V1_0::IFoo;
using ::android::hardware::tests::foo::V1_0::IFooCallback;
using ::android::hardware::tests::foo::V1_0::ISimple;
using ::android::hardware::tests::foo::V1_0::implementation::FooCallback;
-using ::android::hardware::tests::bar::V1_0::IBar;
-using ::android::hardware::tests::bar::V1_0::IComplicated;
-using ::android::hardware::tests::baz::V1_0::IBaz;
using ::android::hardware::tests::hash::V1_0::IHash;
+using ::android::hardware::tests::inheritance::V1_0::IChild;
using ::android::hardware::tests::inheritance::V1_0::IFetcher;
using ::android::hardware::tests::inheritance::V1_0::IGrandparent;
using ::android::hardware::tests::inheritance::V1_0::IParent;
-using ::android::hardware::tests::inheritance::V1_0::IChild;
-using ::android::hardware::tests::pointer::V1_0::IGraph;
-using ::android::hardware::tests::pointer::V1_0::IPointer;
using ::android::hardware::tests::memory::V1_0::IMemoryTest;
using ::android::hardware::tests::multithread::V1_0::IMultithread;
+using ::android::hardware::tests::pointer::V1_0::IGraph;
+using ::android::hardware::tests::pointer::V1_0::IPointer;
+using ::android::hardware::tests::safeunion::cpp::V1_0::ICppSafeUnion;
+using ::android::hardware::tests::safeunion::V1_0::IOtherInterface;
+using ::android::hardware::tests::safeunion::V1_0::ISafeUnion;
using ::android::hardware::tests::trie::V1_0::ITrie;
using ::android::hardware::tests::trie::V1_0::TrieNode;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_death_recipient;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::HidlMemory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
using ::android::hidl::allocator::V1_0::IAllocator;
using ::android::hidl::base::V1_0::IBase;
-using ::android::hidl::manager::V1_1::IServiceManager;
using ::android::hidl::manager::V1_0::IServiceNotification;
-using ::android::hidl::memory::V1_0::IMemory;
-using ::android::hidl::memory::token::V1_0::IMemoryToken;
+using ::android::hidl::manager::V1_2::IServiceManager;
using ::android::hidl::memory::block::V1_0::MemoryBlock;
+using ::android::hidl::memory::token::V1_0::IMemoryToken;
+using ::android::hidl::memory::V1_0::IMemory;
using ::android::hidl::token::V1_0::ITokenManager;
-using ::android::sp;
-using ::android::wp;
-using ::android::to_string;
-using ::android::Mutex;
-using ::android::MultiDimensionalToString;
-using ::android::Condition;
-using ::android::DELAY_S;
-using ::android::DELAY_NS;
-using ::android::TOLERANCE_NS;
-using ::android::ONEWAY_TOLERANCE_NS;
using std::to_string;
+using HandleTypeSafeUnion = ISafeUnion::HandleTypeSafeUnion;
+using InterfaceTypeSafeUnion = ISafeUnion::InterfaceTypeSafeUnion;
+using LargeSafeUnion = ISafeUnion::LargeSafeUnion;
+using SmallSafeUnion = ISafeUnion::SmallSafeUnion;
+
template <typename T>
-using hidl_enum_iterator = ::android::hardware::hidl_enum_iterator<T>;
+using hidl_enum_range = ::android::hardware::hidl_enum_range<T>;
template <typename T>
static inline ::testing::AssertionResult isOk(const ::android::hardware::Return<T> &ret) {
@@ -176,6 +198,32 @@
return ss.str();
}
+// does not check for fd equality
+static void checkNativeHandlesDataEquality(const native_handle_t* reference,
+ const native_handle_t* result) {
+ if (reference == nullptr || result == nullptr) {
+ EXPECT_EQ(reference, result);
+ return;
+ }
+
+ ASSERT_EQ(reference->version, result->version);
+ EXPECT_EQ(reference->numFds, result->numFds);
+ EXPECT_EQ(reference->numInts, result->numInts);
+
+ int offset = reference->numFds;
+ int numInts = reference->numInts;
+ EXPECT_ARRAYEQ(&(reference->data[offset]), &(result->data[offset]), numInts);
+}
+
+template <typename T, MQFlavor flavor>
+static void checkMQDescriptorEquality(const MQDescriptor<T, flavor>& expected,
+ const MQDescriptor<T, flavor>& actual) {
+ checkNativeHandlesDataEquality(expected.handle(), actual.handle());
+ EXPECT_EQ(expected.grantors().size(), actual.grantors().size());
+ EXPECT_EQ(expected.getQuantum(), actual.getQuantum());
+ EXPECT_EQ(expected.getFlags(), actual.getFlags());
+}
+
struct Simple : public ISimple {
Simple(int32_t cookie)
: mCookie(cookie) {
@@ -270,6 +318,16 @@
int32_t mCookie;
};
+struct OtherInterface : public IOtherInterface {
+ Return<void> concatTwoStrings(const hidl_string& a, const hidl_string& b,
+ concatTwoStrings_cb _hidl_cb) override {
+ hidl_string result = std::string(a) + std::string(b);
+ _hidl_cb(result);
+
+ return Void();
+ }
+};
+
struct ServiceNotification : public IServiceNotification {
std::mutex mutex;
std::condition_variable condition;
@@ -308,6 +366,7 @@
sp<IMemoryTest> memoryTest;
sp<IFetcher> fetcher;
sp<IFoo> foo;
+ sp<IBaz> baz;
sp<IBaz> dyingBaz;
sp<IBar> bar;
sp<IGraph> graphInterface;
@@ -315,6 +374,8 @@
sp<IPointer> validationPointerInterface;
sp<IMultithread> multithreadInterface;
sp<ITrie> trieInterface;
+ sp<ICppSafeUnion> cppSafeunionInterface;
+ sp<ISafeUnion> safeunionInterface;
TestMode mode;
bool enableDelayMeasurementTests;
HidlEnvironment(TestMode mode, bool enableDelayMeasurementTests) :
@@ -352,9 +413,13 @@
ASSERT_NE(foo, nullptr);
ASSERT_EQ(foo->isRemote(), mode == BINDERIZED);
+ baz = IBaz::getService("baz", mode == PASSTHROUGH /* getStub */);
+ ASSERT_NE(baz, nullptr);
+ ASSERT_EQ(baz->isRemote(), mode == BINDERIZED);
+
dyingBaz = IBaz::getService("dyingBaz", mode == PASSTHROUGH /* getStub */);
- ASSERT_NE(foo, nullptr);
- ASSERT_EQ(foo->isRemote(), mode == BINDERIZED);
+ ASSERT_NE(dyingBaz, nullptr);
+ ASSERT_EQ(dyingBaz->isRemote(), mode == BINDERIZED);
bar = IBar::getService("foo", mode == PASSTHROUGH /* getStub */);
ASSERT_NE(bar, nullptr);
@@ -380,6 +445,15 @@
trieInterface = ITrie::getService("trie", mode == PASSTHROUGH /* getStub */);
ASSERT_NE(trieInterface, nullptr);
ASSERT_EQ(trieInterface->isRemote(), mode == BINDERIZED);
+
+ cppSafeunionInterface =
+ ICppSafeUnion::getService("default", mode == PASSTHROUGH /* getStub */);
+ ASSERT_NE(cppSafeunionInterface, nullptr);
+ ASSERT_EQ(cppSafeunionInterface->isRemote(), mode == BINDERIZED);
+
+ safeunionInterface = ISafeUnion::getService("safeunion", mode == PASSTHROUGH /* getStub */);
+ ASSERT_NE(safeunionInterface, nullptr);
+ ASSERT_EQ(safeunionInterface->isRemote(), mode == BINDERIZED);
}
virtual void SetUp() {
@@ -397,12 +471,15 @@
sp<IMemoryTest> memoryTest;
sp<IFetcher> fetcher;
sp<IFoo> foo;
+ sp<IBaz> baz;
sp<IBaz> dyingBaz;
sp<IBar> bar;
sp<IGraph> graphInterface;
sp<IPointer> pointerInterface;
sp<IPointer> validationPointerInterface;
sp<ITrie> trieInterface;
+ sp<ICppSafeUnion> cppSafeunionInterface;
+ sp<ISafeUnion> safeunionInterface;
TestMode mode = TestMode::PASSTHROUGH;
virtual void SetUp() override {
@@ -413,12 +490,15 @@
memoryTest = gHidlEnvironment->memoryTest;
fetcher = gHidlEnvironment->fetcher;
foo = gHidlEnvironment->foo;
+ baz = gHidlEnvironment->baz;
dyingBaz = gHidlEnvironment->dyingBaz;
bar = gHidlEnvironment->bar;
graphInterface = gHidlEnvironment->graphInterface;
pointerInterface = gHidlEnvironment->pointerInterface;
validationPointerInterface = gHidlEnvironment->validationPointerInterface;
trieInterface = gHidlEnvironment->trieInterface;
+ cppSafeunionInterface = gHidlEnvironment->cppSafeunionInterface;
+ safeunionInterface = gHidlEnvironment->safeunionInterface;
mode = gHidlEnvironment->mode;
ALOGI("Test setup complete");
}
@@ -435,26 +515,36 @@
auto handle2 = native_handle_create(0, 1);
handle->data[0] = 5;
handle2->data[0] = 6;
- IFoo::Everything e {
- .u = {.p = reinterpret_cast<void *>(0x5)},
+ IFoo::Everything e{
+ .u = {.number = 3},
.number = 10,
.h = handle,
.descSync = {std::vector<GrantorDescriptor>(), handle, 5},
.descUnsync = {std::vector<GrantorDescriptor>(), handle2, 6},
.mem = hidl_memory("mymem", handle, 5),
- .p = reinterpret_cast<void *>(0x6),
+ .p = reinterpret_cast<void*>(0x6),
.vs = {"hello", "world"},
.multidimArray = hidl_vec<hidl_string>{"hello", "great", "awesome", "nice"}.data(),
.sArray = hidl_vec<hidl_string>{"awesome", "thanks", "you're welcome"}.data(),
.anotherStruct = {.first = "first", .last = "last"},
- .bf = IFoo::BitField::V0 | IFoo::BitField::V2
- };
+ .bf = IFoo::BitField::V0 | IFoo::BitField::V2};
LOG(INFO) << toString(e);
LOG(INFO) << toString(foo);
// toString is for debugging purposes only; no good EXPECT
// statement can be written here.
}
+TEST_F(HidlTest, ConstantExpressionTest) {
+ // these tests are written so that these always evaluate to one
+
+ for (const auto value : hidl_enum_range<IExpression::OperatorSanityCheck>()) {
+ EXPECT_EQ(1, static_cast<int32_t>(value));
+ }
+ for (const auto value : hidl_enum_range<IExpression::EnumTagTest>()) {
+ EXPECT_EQ(1, static_cast<int32_t>(value));
+ }
+}
+
TEST_F(HidlTest, PassthroughLookupTest) {
// IFoo is special because it returns an interface no matter
// what instance name is requested. In general, this is BAD!
@@ -472,30 +562,52 @@
using SkipsValues = ::android::hardware::tests::foo::V1_0::EnumIterators::SkipsValues;
using MultipleValues = ::android::hardware::tests::foo::V1_0::EnumIterators::MultipleValues;
- for (const auto value : hidl_enum_iterator<Empty>()) {
+ for (const auto value : hidl_enum_range<Empty>()) {
(void)value;
- EXPECT_TRUE(false) << "Empty iterator should not iterate";
+ ADD_FAILURE() << "Empty range should not iterate";
}
- auto it1 = hidl_enum_iterator<Grandchild>().begin();
+ EXPECT_EQ(hidl_enum_range<Grandchild>().begin(), hidl_enum_range<Grandchild>().cbegin());
+ EXPECT_EQ(hidl_enum_range<Grandchild>().end(), hidl_enum_range<Grandchild>().cend());
+ EXPECT_EQ(hidl_enum_range<Grandchild>().rbegin(), hidl_enum_range<Grandchild>().crbegin());
+ EXPECT_EQ(hidl_enum_range<Grandchild>().rend(), hidl_enum_range<Grandchild>().crend());
+
+ auto it1 = hidl_enum_range<Grandchild>().begin();
EXPECT_EQ(Grandchild::A, *it1++);
EXPECT_EQ(Grandchild::B, *it1++);
- EXPECT_EQ(hidl_enum_iterator<Grandchild>().end(), it1);
+ EXPECT_EQ(hidl_enum_range<Grandchild>().end(), it1);
+ auto it1r = hidl_enum_range<Grandchild>().rbegin();
+ EXPECT_EQ(Grandchild::B, *it1r++);
+ EXPECT_EQ(Grandchild::A, *it1r++);
+ EXPECT_EQ(hidl_enum_range<Grandchild>().rend(), it1r);
- auto it2 = hidl_enum_iterator<SkipsValues>().begin();
+ auto it2 = hidl_enum_range<SkipsValues>().begin();
EXPECT_EQ(SkipsValues::A, *it2++);
EXPECT_EQ(SkipsValues::B, *it2++);
EXPECT_EQ(SkipsValues::C, *it2++);
EXPECT_EQ(SkipsValues::D, *it2++);
EXPECT_EQ(SkipsValues::E, *it2++);
- EXPECT_EQ(hidl_enum_iterator<SkipsValues>().end(), it2);
+ EXPECT_EQ(hidl_enum_range<SkipsValues>().end(), it2);
+ auto it2r = hidl_enum_range<SkipsValues>().rbegin();
+ EXPECT_EQ(SkipsValues::E, *it2r++);
+ EXPECT_EQ(SkipsValues::D, *it2r++);
+ EXPECT_EQ(SkipsValues::C, *it2r++);
+ EXPECT_EQ(SkipsValues::B, *it2r++);
+ EXPECT_EQ(SkipsValues::A, *it2r++);
+ EXPECT_EQ(hidl_enum_range<SkipsValues>().rend(), it2r);
- auto it3 = hidl_enum_iterator<MultipleValues>().begin();
+ auto it3 = hidl_enum_range<MultipleValues>().begin();
EXPECT_EQ(MultipleValues::A, *it3++);
EXPECT_EQ(MultipleValues::B, *it3++);
EXPECT_EQ(MultipleValues::C, *it3++);
EXPECT_EQ(MultipleValues::D, *it3++);
- EXPECT_EQ(hidl_enum_iterator<MultipleValues>().end(), it3);
+ EXPECT_EQ(hidl_enum_range<MultipleValues>().end(), it3);
+ auto it3r = hidl_enum_range<MultipleValues>().rbegin();
+ EXPECT_EQ(MultipleValues::D, *it3r++);
+ EXPECT_EQ(MultipleValues::C, *it3r++);
+ EXPECT_EQ(MultipleValues::B, *it3r++);
+ EXPECT_EQ(MultipleValues::A, *it3r++);
+ EXPECT_EQ(hidl_enum_range<MultipleValues>().rend(), it3r);
}
TEST_F(HidlTest, EnumToStringTest) {
@@ -536,28 +648,6 @@
ASSERT_NE(manager, nullptr);
}
-TEST_F(HidlTest, HashTest) {
- static constexpr uint64_t kHashSize = 32u;
- // unreleased interface has an empty hash
- uint8_t ihash[kHashSize] = {0};
- uint8_t ibase[kHashSize] = {189, 218, 182, 24, 77, 122, 52, 109, 166, 160, 125,
- 192, 130, 140, 241, 154, 105, 111, 76, 170, 54, 17,
- 197, 31, 46, 20, 86, 90, 20, 180, 15, 217};
- auto service = IHash::getService(mode == PASSTHROUGH /* getStub */);
- EXPECT_OK(service->getHashChain([&](const auto& chain) {
- ASSERT_EQ(chain.size(), 2u);
- EXPECT_EQ(chain[0].size(), kHashSize);
- EXPECT_ARRAYEQ(ihash, chain[0], kHashSize);
- EXPECT_EQ(chain[1].size(), kHashSize);
- EXPECT_ARRAYEQ(ibase, chain[1], kHashSize);
- }));
- EXPECT_OK(manager->getHashChain([&](const auto& managerChain) {
- EXPECT_EQ(managerChain[managerChain.size() - 1].size(), kHashSize);
- EXPECT_ARRAYEQ(ibase, managerChain[managerChain.size() - 1], kHashSize)
- << "Hash for IBase doesn't match!";
- }));
-}
-
TEST_F(HidlTest, ServiceListTest) {
static const std::set<std::string> binderizedSet = {
"android.hardware.tests.pointer@1.0::IPointer/pointer",
@@ -632,6 +722,30 @@
}));
}
+TEST_F(HidlTest, ServiceListManifestByInterfaceTest) {
+ // system service
+ EXPECT_OK(manager->listManifestByInterface(IServiceManager::descriptor,
+ [](const hidl_vec<hidl_string>& registered) {
+ ASSERT_EQ(1, registered.size());
+ EXPECT_EQ("default", registered[0]);
+ }));
+ // vendor service (this is required on all devices)
+ EXPECT_OK(
+ manager->listManifestByInterface("android.hardware.configstore@1.0::ISurfaceFlingerConfigs",
+ [](const hidl_vec<hidl_string>& registered) {
+ ASSERT_EQ(1, registered.size());
+ EXPECT_EQ("default", registered[0]);
+ }));
+ // test service that will never be in a manifest
+ EXPECT_OK(manager->listManifestByInterface(
+ IParent::descriptor,
+ [](const hidl_vec<hidl_string>& registered) { ASSERT_EQ(0, registered.size()); }));
+ // invalid service
+ EXPECT_OK(manager->listManifestByInterface(
+ "!(*#&$ASDASLKDJasdlkjfads",
+ [](const hidl_vec<hidl_string>& registered) { ASSERT_EQ(0, registered.size()); }));
+}
+
TEST_F(HidlTest, SubInterfaceServiceRegistrationTest) {
using ::android::hardware::interfacesEqual;
@@ -675,7 +789,7 @@
std::unique_lock<std::mutex> lock(notification->mutex);
- notification->condition.wait_for(lock, std::chrono::milliseconds(2), [¬ification]() {
+ notification->condition.wait_for(lock, std::chrono::milliseconds(500), [¬ification]() {
return notification->getRegistrations().size() >= 2;
});
@@ -731,7 +845,7 @@
std::unique_lock<std::mutex> lock(notification->mutex);
- notification->condition.wait_for(lock, std::chrono::milliseconds(2), [¬ification]() {
+ notification->condition.wait_for(lock, std::chrono::milliseconds(500), [¬ification]() {
return notification->getRegistrations().size() >= 2;
});
@@ -747,6 +861,16 @@
"['" + descriptor + "/" + instanceOne + "', '" + descriptor + "/" + instanceTwo + "']");
}
+TEST_F(HidlTest, DebugDumpTest) {
+ EXPECT_OK(manager->debugDump([](const auto& list) {
+ for (const auto& debugInfo : list) {
+ FQName name;
+ EXPECT_TRUE(FQName::parse(debugInfo.interfaceName, &name)) << debugInfo.interfaceName;
+ EXPECT_TRUE(debugInfo.instanceName.size() > 0);
+ }
+ }));
+}
+
TEST_F(HidlTest, InterfacesEqualTest) {
using android::hardware::interfacesEqual;
@@ -1196,7 +1320,7 @@
EXPECT_OK(foo->haveATypeFromAnotherFile(abcParam));
ALOGI("CLIENT haveATypeFromAnotherFile returned.");
native_handle_delete(handle);
- abcParam.z = NULL;
+ abcParam.z = nullptr;
}
TEST_F(HidlTest, FooHaveSomeStringsTest) {
@@ -1404,6 +1528,26 @@
}));
}
+TEST_F(HidlTest, StructWithFmq) {
+ IFoo::WithFmq w = {
+ .scatterGathered =
+ {
+ .descSync = {std::vector<GrantorDescriptor>(), native_handle_create(0, 1), 5},
+ },
+ .containsPointer =
+ {
+ .descSync = {std::vector<GrantorDescriptor>(), native_handle_create(0, 1), 5},
+ .foo = nullptr,
+ },
+ };
+ EXPECT_OK(foo->repeatWithFmq(w, [&](const IFoo::WithFmq& returned) {
+ checkMQDescriptorEquality(w.scatterGathered.descSync, returned.scatterGathered.descSync);
+ checkMQDescriptorEquality(w.containsPointer.descSync, returned.containsPointer.descSync);
+
+ EXPECT_EQ(w.containsPointer.foo, returned.containsPointer.foo);
+ }));
+}
+
TEST_F(HidlTest, FooNonNullCallbackTest) {
hidl_array<hidl_string, 5, 3> in;
@@ -1512,6 +1656,41 @@
EXPECT_OK(foo->closeHandles());
}
+TEST_F(HidlTest, BazStructWithInterfaceTest) {
+ using ::android::hardware::interfacesEqual;
+
+ const std::string testString = "Hello, World!";
+ const std::array<int8_t, 7> testArray{-1, -2, -3, 0, 1, 2, 3};
+ const hidl_vec<hidl_string> testStrings{"So", "Many", "Words"};
+ const hidl_vec<bool> testVector{false, true, false, true, true, true};
+
+ hidl_vec<bool> goldenResult(testVector.size());
+ for (size_t i = 0; i < testVector.size(); i++) {
+ goldenResult[i] = !testVector[i];
+ }
+
+ IBaz::StructWithInterface swi;
+ swi.number = 42;
+ swi.array = testArray;
+ swi.oneString = testString;
+ swi.vectorOfStrings = testStrings;
+ swi.dummy = baz;
+
+ EXPECT_OK(baz->haveSomeStructWithInterface(swi, [&](const IBaz::StructWithInterface& swiBack) {
+ EXPECT_EQ(42, swiBack.number);
+ for (size_t i = 0; i < testArray.size(); i++) {
+ EXPECT_EQ(testArray[i], swiBack.array[i]);
+ }
+
+ EXPECT_EQ(testString, std::string(swiBack.oneString));
+ EXPECT_EQ(testStrings, swiBack.vectorOfStrings);
+
+ EXPECT_TRUE(interfacesEqual(swi.dummy, swiBack.dummy));
+ EXPECT_OK(swiBack.dummy->someBoolVectorMethod(
+ testVector, [&](const hidl_vec<bool>& result) { EXPECT_EQ(goldenResult, result); }));
+ }));
+}
+
struct HidlDeathRecipient : hidl_death_recipient {
std::mutex mutex;
std::condition_variable condition;
@@ -1533,6 +1712,10 @@
sp<HidlDeathRecipient> recipient2 = new HidlDeathRecipient();
EXPECT_TRUE(dyingBaz->linkToDeath(recipient, 0x1481));
+
+ EXPECT_TRUE(dyingBaz->linkToDeath(recipient, 0x1482));
+ EXPECT_TRUE(dyingBaz->unlinkToDeath(recipient));
+
EXPECT_TRUE(dyingBaz->linkToDeath(recipient2, 0x2592));
EXPECT_TRUE(dyingBaz->unlinkToDeath(recipient2));
@@ -1802,6 +1985,479 @@
});
}
+TEST_F(HidlTest, SafeUnionNoInitTest) {
+ EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& safeUnion) {
+ EXPECT_EQ(LargeSafeUnion::hidl_discriminator::noinit, safeUnion.getDiscriminator());
+ }));
+}
+
+TEST_F(HidlTest, SafeUnionSimpleTest) {
+ EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& safeUnion) {
+ EXPECT_OK(safeunionInterface->setA(safeUnion, -5, [&](const LargeSafeUnion& safeUnion) {
+ EXPECT_EQ(LargeSafeUnion::hidl_discriminator::a, safeUnion.getDiscriminator());
+ EXPECT_EQ(-5, safeUnion.a());
+
+ uint64_t max = std::numeric_limits<uint64_t>::max();
+ EXPECT_OK(
+ safeunionInterface->setD(safeUnion, max, [&](const LargeSafeUnion& safeUnion) {
+ EXPECT_EQ(LargeSafeUnion::hidl_discriminator::d, safeUnion.getDiscriminator());
+ EXPECT_EQ(max, safeUnion.d());
+ }));
+ }));
+ }));
+}
+
+TEST_F(HidlTest, SafeUnionArrayLikeTypesTest) {
+ const std::array<int64_t, 5> testArray{1, -2, 3, -4, 5};
+ const hidl_vec<uint64_t> testVector{std::numeric_limits<uint64_t>::max()};
+
+ EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& safeUnion) {
+ EXPECT_OK(
+ safeunionInterface->setF(safeUnion, testArray, [&](const LargeSafeUnion& safeUnion) {
+ EXPECT_EQ(LargeSafeUnion::hidl_discriminator::f, safeUnion.getDiscriminator());
+
+ for (size_t i = 0; i < testArray.size(); i++) {
+ EXPECT_EQ(testArray[i], safeUnion.f()[i]);
+ }
+ }));
+
+ EXPECT_OK(
+ safeunionInterface->setI(safeUnion, testVector, [&](const LargeSafeUnion& safeUnion) {
+ EXPECT_EQ(LargeSafeUnion::hidl_discriminator::i, safeUnion.getDiscriminator());
+ EXPECT_EQ(testVector, safeUnion.i());
+ }));
+ }));
+}
+
+TEST_F(HidlTest, SafeUnionStringTypeTest) {
+ const std::string testString =
+ "This is an inordinately long test string to exercise hidl_string types in safe unions.";
+
+ EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& safeUnion) {
+ EXPECT_OK(safeunionInterface->setG(
+ safeUnion, hidl_string(testString), [&](const LargeSafeUnion& safeUnion) {
+ EXPECT_EQ(LargeSafeUnion::hidl_discriminator::g, safeUnion.getDiscriminator());
+ EXPECT_EQ(testString, std::string(safeUnion.g()));
+ }));
+ }));
+}
+
+TEST_F(HidlTest, SafeUnionCopyConstructorTest) {
+ const hidl_vec<bool> testVector{true, false, true, false, false, false, true, false,
+ true, true, true, false, false, true, false, true};
+
+ EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& safeUnion) {
+ EXPECT_OK(
+ safeunionInterface->setH(safeUnion, testVector, [&](const LargeSafeUnion& safeUnion) {
+ LargeSafeUnion safeUnionCopy(safeUnion);
+
+ EXPECT_EQ(LargeSafeUnion::hidl_discriminator::h, safeUnionCopy.getDiscriminator());
+ EXPECT_EQ(testVector, safeUnionCopy.h());
+ }));
+ }));
+}
+
+TEST_F(HidlTest, SafeUnionMoveConstructorTest) {
+ sp<IOtherInterface> otherInterface = new OtherInterface();
+ ASSERT_EQ(1, otherInterface->getStrongCount());
+
+ InterfaceTypeSafeUnion safeUnion;
+ safeUnion.c(otherInterface);
+ EXPECT_EQ(2, otherInterface->getStrongCount());
+
+ InterfaceTypeSafeUnion anotherSafeUnion(std::move(safeUnion));
+ EXPECT_EQ(InterfaceTypeSafeUnion::hidl_discriminator::c,
+ anotherSafeUnion.getDiscriminator());
+ EXPECT_EQ(2, otherInterface->getStrongCount());
+}
+
+TEST_F(HidlTest, SafeUnionCopyAssignmentTest) {
+ const hidl_vec<hidl_string> testVector{"So", "Many", "Words"};
+ InterfaceTypeSafeUnion safeUnion;
+ safeUnion.e(testVector);
+
+ InterfaceTypeSafeUnion anotherSafeUnion;
+ anotherSafeUnion = safeUnion;
+
+ EXPECT_EQ(InterfaceTypeSafeUnion::hidl_discriminator::e, anotherSafeUnion.getDiscriminator());
+ EXPECT_EQ(InterfaceTypeSafeUnion::hidl_discriminator::e, safeUnion.getDiscriminator());
+ EXPECT_NE(&(safeUnion.e()), &(anotherSafeUnion.e()));
+ EXPECT_EQ(testVector, anotherSafeUnion.e());
+ EXPECT_EQ(testVector, safeUnion.e());
+}
+
+TEST_F(HidlTest, SafeUnionMoveAssignmentTest) {
+ sp<IOtherInterface> otherInterface = new OtherInterface();
+ ASSERT_EQ(1, otherInterface->getStrongCount());
+
+ InterfaceTypeSafeUnion safeUnion;
+ safeUnion.c(otherInterface);
+ EXPECT_EQ(2, otherInterface->getStrongCount());
+
+ InterfaceTypeSafeUnion anotherSafeUnion;
+ anotherSafeUnion.a(255);
+ anotherSafeUnion = std::move(safeUnion);
+
+ EXPECT_EQ(InterfaceTypeSafeUnion::hidl_discriminator::c,
+ anotherSafeUnion.getDiscriminator());
+ EXPECT_EQ(2, otherInterface->getStrongCount());
+}
+
+TEST_F(HidlTest, SafeUnionMutateTest) {
+ const std::array<int64_t, 5> testArray{-1, -2, -3, -4, -5};
+ const std::string testString = "Test string";
+ LargeSafeUnion safeUnion;
+
+ safeUnion.f(testArray);
+ safeUnion.f()[0] += 10;
+ EXPECT_EQ(testArray[0] + 10, safeUnion.f()[0]);
+
+ safeUnion.j(ISafeUnion::J());
+ safeUnion.j().j3 = testString;
+ EXPECT_EQ(testString, std::string(safeUnion.j().j3));
+}
+
+TEST_F(HidlTest, SafeUnionNestedTest) {
+ SmallSafeUnion smallSafeUnion;
+ smallSafeUnion.a(1);
+
+ EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& safeUnion) {
+ EXPECT_OK(safeunionInterface->setL(
+ safeUnion, smallSafeUnion, [&](const LargeSafeUnion& safeUnion) {
+ EXPECT_EQ(LargeSafeUnion::hidl_discriminator::l, safeUnion.getDiscriminator());
+
+ EXPECT_EQ(SmallSafeUnion::hidl_discriminator::a, safeUnion.l().getDiscriminator());
+ EXPECT_EQ(1, safeUnion.l().a());
+ }));
+ }));
+}
+
+TEST_F(HidlTest, SafeUnionEnumTest) {
+ EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& safeUnion) {
+ EXPECT_OK(safeunionInterface->setM(
+ safeUnion, ISafeUnion::BitField::V1, [&](const LargeSafeUnion& safeUnion) {
+ EXPECT_EQ(LargeSafeUnion::hidl_discriminator::m, safeUnion.getDiscriminator());
+ EXPECT_EQ(ISafeUnion::BitField::V1, safeUnion.m());
+ }));
+ }));
+}
+
+TEST_F(HidlTest, SafeUnionBitFieldTest) {
+ EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& safeUnion) {
+ EXPECT_OK(safeunionInterface->setN(
+ safeUnion, 0 | ISafeUnion::BitField::V1, [&](const LargeSafeUnion& safeUnion) {
+ EXPECT_EQ(LargeSafeUnion::hidl_discriminator::n, safeUnion.getDiscriminator());
+ EXPECT_EQ(0 | ISafeUnion::BitField::V1, safeUnion.n());
+ }));
+ }));
+}
+
+TEST_F(HidlTest, SafeUnionInterfaceTest) {
+ const std::array<int8_t, 7> testArray{-1, -2, -3, 0, 1, 2, 3};
+ const hidl_vec<hidl_string> testVector{"So", "Many", "Words"};
+ const std::string testStringA = "Hello";
+ const std::string testStringB = "World";
+
+ const std::string serviceName = "otherinterface";
+ sp<IOtherInterface> otherInterface = new OtherInterface();
+ EXPECT_EQ(::android::OK, otherInterface->registerAsService(serviceName));
+
+ EXPECT_OK(
+ safeunionInterface->newInterfaceTypeSafeUnion([&](const InterfaceTypeSafeUnion& safeUnion) {
+ EXPECT_EQ(InterfaceTypeSafeUnion::hidl_discriminator::noinit,
+ safeUnion.getDiscriminator());
+
+ isOk(safeunionInterface->setInterfaceB(
+ safeUnion, testArray, [&](const InterfaceTypeSafeUnion& safeUnion) {
+ EXPECT_EQ(InterfaceTypeSafeUnion::hidl_discriminator::b,
+ safeUnion.getDiscriminator());
+
+ for (size_t i = 0; i < testArray.size(); i++) {
+ EXPECT_EQ(testArray[i], safeUnion.b()[i]);
+ }
+
+ EXPECT_OK(safeunionInterface->setInterfaceC(
+ safeUnion, otherInterface, [&](const InterfaceTypeSafeUnion& safeUnion) {
+ EXPECT_EQ(InterfaceTypeSafeUnion::hidl_discriminator::c,
+ safeUnion.getDiscriminator());
+
+ EXPECT_OK(safeUnion.c()->concatTwoStrings(
+ testStringA, testStringB, [&](const hidl_string& result) {
+ EXPECT_EQ(testStringA + testStringB, std::string(result));
+ }));
+ }));
+ }));
+
+ EXPECT_OK(safeunionInterface->setInterfaceD(
+ safeUnion, testStringA, [&](const InterfaceTypeSafeUnion& safeUnion) {
+ EXPECT_EQ(InterfaceTypeSafeUnion::hidl_discriminator::d,
+ safeUnion.getDiscriminator());
+ EXPECT_EQ(testStringA, safeUnion.d());
+ }));
+
+ EXPECT_OK(safeunionInterface->setInterfaceE(
+ safeUnion, testVector, [&](const InterfaceTypeSafeUnion& safeUnion) {
+ EXPECT_EQ(InterfaceTypeSafeUnion::hidl_discriminator::e,
+ safeUnion.getDiscriminator());
+ EXPECT_EQ(testVector, safeUnion.e());
+ }));
+ }));
+}
+
+TEST_F(HidlTest, SafeUnionNullHandleTest) {
+ HandleTypeSafeUnion safeUnion;
+
+ EXPECT_OK(safeunionInterface->setHandleA(
+ safeUnion, hidl_handle(nullptr), [&](const HandleTypeSafeUnion& safeUnion) {
+ EXPECT_EQ(HandleTypeSafeUnion::hidl_discriminator::a,
+ safeUnion.getDiscriminator());
+
+ checkNativeHandlesDataEquality(nullptr, safeUnion.a().getNativeHandle());
+ }));
+}
+
+TEST_F(HidlTest, SafeUnionSimpleHandleTest) {
+ const std::array<int, 6> testData{2, -32, 10, -4329454, 11, 24};
+ native_handle_t* h = native_handle_create(0, testData.size());
+ ASSERT_EQ(sizeof(testData), testData.size() * sizeof(int));
+ std::memcpy(h->data, testData.data(), sizeof(testData));
+
+ std::array<hidl_handle, 5> testArray;
+ for (size_t i = 0; i < testArray.size(); i++) {
+ testArray[i].setTo(native_handle_clone(h), true /* shouldOwn */);
+ }
+
+ std::vector<hidl_handle> testVector(256);
+ for (size_t i = 0; i < testVector.size(); i++) {
+ testVector[i].setTo(native_handle_clone(h), true /* shouldOwn */);
+ }
+
+ EXPECT_OK(
+ safeunionInterface->newHandleTypeSafeUnion([&](const HandleTypeSafeUnion& safeUnion) {
+ EXPECT_OK(safeunionInterface->setHandleA(
+ safeUnion, hidl_handle(h), [&](const HandleTypeSafeUnion& safeUnion) {
+ EXPECT_EQ(HandleTypeSafeUnion::hidl_discriminator::a,
+ safeUnion.getDiscriminator());
+
+ checkNativeHandlesDataEquality(h, safeUnion.a().getNativeHandle());
+ }));
+
+ EXPECT_OK(safeunionInterface->setHandleB(
+ safeUnion, testArray, [&](const HandleTypeSafeUnion& safeUnion) {
+ EXPECT_EQ(HandleTypeSafeUnion::hidl_discriminator::b,
+ safeUnion.getDiscriminator());
+
+ for (size_t i = 0; i < testArray.size(); i++) {
+ checkNativeHandlesDataEquality(h, safeUnion.b()[i].getNativeHandle());
+ }
+ }));
+
+ EXPECT_OK(safeunionInterface->setHandleC(
+ safeUnion, testVector, [&](const HandleTypeSafeUnion& safeUnion) {
+ EXPECT_EQ(HandleTypeSafeUnion::hidl_discriminator::c,
+ safeUnion.getDiscriminator());
+
+ for (size_t i = 0; i < testVector.size(); i++) {
+ checkNativeHandlesDataEquality(h, safeUnion.c()[i].getNativeHandle());
+ }
+ }));
+ }));
+
+ native_handle_delete(h);
+}
+
+TEST_F(HidlTest, SafeUnionVecOfHandlesWithOneFdTest) {
+ const std::vector<std::string> testStrings{"This ", "is ", "so ", "much ", "data!\n"};
+ const std::string testFileName = "/data/local/tmp/SafeUnionVecOfHandlesWithOneFdTest";
+ const std::array<int, 6> testData{2, -32, 10, -4329454, 11, 24};
+ ASSERT_EQ(sizeof(testData), testData.size() * sizeof(int));
+
+ const std::string goldenResult = std::accumulate(testStrings.begin(),
+ testStrings.end(),
+ std::string());
+
+ int fd = open(testFileName.c_str(), (O_RDWR | O_TRUNC | O_CREAT), (S_IRUSR | S_IWUSR));
+ ASSERT_TRUE(fd >= 0);
+
+ native_handle* h = native_handle_create(1 /* numFds */, testData.size() /* numInts */);
+ std::memcpy(&(h->data[1]), testData.data(), sizeof(testData));
+ h->data[0] = fd;
+
+ hidl_vec<hidl_handle> testHandles(testStrings.size());
+ for (size_t i = 0; i < testHandles.size(); i++) {
+ testHandles[i].setTo(native_handle_clone(h), true /* shouldOwn */);
+ }
+
+ EXPECT_OK(
+ safeunionInterface->newHandleTypeSafeUnion([&](const HandleTypeSafeUnion& safeUnion) {
+ EXPECT_OK(safeunionInterface->setHandleC(
+ safeUnion, testHandles, [&](const HandleTypeSafeUnion& safeUnion) {
+ EXPECT_EQ(HandleTypeSafeUnion::hidl_discriminator::c,
+ safeUnion.getDiscriminator());
+
+ for (size_t i = 0; i < safeUnion.c().size(); i++) {
+ const native_handle_t* reference = testHandles[i].getNativeHandle();
+ const native_handle_t* result = safeUnion.c()[i].getNativeHandle();
+ checkNativeHandlesDataEquality(reference, result);
+
+ // Original FDs should be dup'd
+ int resultFd = result->data[0];
+ EXPECT_NE(reference->data[0], resultFd);
+
+ EXPECT_TRUE(android::base::WriteStringToFd(testStrings[i], resultFd));
+ EXPECT_EQ(0, fsync(resultFd));
+ }
+ }));
+ }));
+
+ std::string result;
+ lseek(fd, 0, SEEK_SET);
+
+ EXPECT_TRUE(android::base::ReadFdToString(fd, &result));
+ EXPECT_EQ(goldenResult, result);
+
+ native_handle_delete(h);
+ EXPECT_EQ(0, close(fd));
+ EXPECT_EQ(0, remove(testFileName.c_str()));
+}
+
+TEST_F(HidlTest, SafeUnionHandleWithMultipleFdsTest) {
+ const std::vector<std::string> testStrings{"This ", "is ", "so ", "much ", "data!\n"};
+ const std::string testFileName = "/data/local/tmp/SafeUnionHandleWithMultipleFdsTest";
+ const std::array<int, 6> testData{2, -32, 10, -4329454, 11, 24};
+ ASSERT_EQ(sizeof(testData), testData.size() * sizeof(int));
+
+ const std::string goldenResult = std::accumulate(testStrings.begin(),
+ testStrings.end(),
+ std::string());
+
+ int fd = open(testFileName.c_str(), (O_RDWR | O_TRUNC | O_CREAT), (S_IRUSR | S_IWUSR));
+ ASSERT_TRUE(fd >= 0);
+
+ const int numFds = testStrings.size();
+ native_handle* h = native_handle_create(numFds, testData.size() /* numInts */);
+ std::memcpy(&(h->data[numFds]), testData.data(), sizeof(testData));
+ for (size_t i = 0; i < numFds; i++) {
+ h->data[i] = fd;
+ }
+
+ hidl_handle testHandle;
+ testHandle.setTo(h, false /* shouldOwn */);
+
+ EXPECT_OK(
+ safeunionInterface->newHandleTypeSafeUnion([&](const HandleTypeSafeUnion& safeUnion) {
+ EXPECT_OK(safeunionInterface->setHandleA(
+ safeUnion, testHandle, [&](const HandleTypeSafeUnion& safeUnion) {
+ EXPECT_EQ(HandleTypeSafeUnion::hidl_discriminator::a,
+ safeUnion.getDiscriminator());
+
+ const native_handle_t* result = safeUnion.a().getNativeHandle();
+ checkNativeHandlesDataEquality(h, result);
+
+ for (size_t i = 0; i < result->numFds; i++) {
+ // Original FDs should be dup'd
+ int resultFd = result->data[i];
+ EXPECT_NE(h->data[i], resultFd);
+
+ EXPECT_TRUE(android::base::WriteStringToFd(testStrings[i], resultFd));
+ EXPECT_EQ(0, fsync(resultFd));
+ }
+ }));
+ }));
+
+ std::string result;
+ lseek(fd, 0, SEEK_SET);
+
+ EXPECT_TRUE(android::base::ReadFdToString(fd, &result));
+ EXPECT_EQ(goldenResult, result);
+
+ native_handle_delete(h);
+ EXPECT_EQ(0, close(fd));
+ EXPECT_EQ(0, remove(testFileName.c_str()));
+}
+
+TEST_F(HidlTest, SafeUnionEqualityTest) {
+ EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& one) {
+ EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& two) {
+ EXPECT_TRUE(one == two);
+ EXPECT_FALSE(one != two);
+ }));
+
+ EXPECT_OK(safeunionInterface->setA(one, 1, [&](const LargeSafeUnion& one) {
+ EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& two) {
+ EXPECT_FALSE(one == two);
+ EXPECT_TRUE(one != two);
+ }));
+
+ EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& two) {
+ EXPECT_OK(safeunionInterface->setB(two, 1, [&](const LargeSafeUnion& two) {
+ EXPECT_FALSE(one == two);
+ EXPECT_TRUE(one != two);
+ }));
+ }));
+
+ EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& two) {
+ EXPECT_OK(safeunionInterface->setA(two, 2, [&](const LargeSafeUnion& two) {
+ EXPECT_FALSE(one == two);
+ EXPECT_TRUE(one != two);
+ }));
+ }));
+
+ EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& two) {
+ EXPECT_OK(safeunionInterface->setA(two, 1, [&](const LargeSafeUnion& two) {
+ EXPECT_TRUE(one == two);
+ EXPECT_FALSE(one != two);
+ }));
+ }));
+ }));
+ }));
+}
+
+TEST_F(HidlTest, SafeUnionSimpleDestructorTest) {
+ sp<IOtherInterface> otherInterface = new OtherInterface();
+ ASSERT_EQ(1, otherInterface->getStrongCount());
+
+ {
+ InterfaceTypeSafeUnion safeUnion;
+ safeUnion.c(otherInterface);
+ EXPECT_EQ(2, otherInterface->getStrongCount());
+ }
+
+ EXPECT_EQ(1, otherInterface->getStrongCount());
+}
+
+TEST_F(HidlTest, SafeUnionSwitchActiveComponentsDestructorTest) {
+ sp<IOtherInterface> otherInterface = new OtherInterface();
+ ASSERT_EQ(1, otherInterface->getStrongCount());
+
+ InterfaceTypeSafeUnion safeUnion;
+ safeUnion.c(otherInterface);
+ EXPECT_EQ(2, otherInterface->getStrongCount());
+
+ safeUnion.a(1);
+ EXPECT_EQ(1, otherInterface->getStrongCount());
+}
+
+TEST_F(HidlTest, SafeUnionCppSpecificTest) {
+ ICppSafeUnion::PointerFmqSafeUnion pointerFmqSafeUnion;
+ pointerFmqSafeUnion.fmqSync({std::vector<GrantorDescriptor>(), native_handle_create(0, 1), 5});
+
+ EXPECT_OK(cppSafeunionInterface->repeatPointerFmqSafeUnion(
+ pointerFmqSafeUnion, [&](const ICppSafeUnion::PointerFmqSafeUnion& fmq) {
+ ASSERT_EQ(pointerFmqSafeUnion.getDiscriminator(), fmq.getDiscriminator());
+ checkMQDescriptorEquality(pointerFmqSafeUnion.fmqSync(), fmq.fmqSync());
+ }));
+
+ ICppSafeUnion::FmqSafeUnion fmqSafeUnion;
+ fmqSafeUnion.fmqUnsync({std::vector<GrantorDescriptor>(), native_handle_create(0, 1), 5});
+
+ EXPECT_OK(cppSafeunionInterface->repeatFmqSafeUnion(
+ fmqSafeUnion, [&](const ICppSafeUnion::FmqSafeUnion& fmq) {
+ ASSERT_EQ(fmqSafeUnion.getDiscriminator(), fmq.getDiscriminator());
+ checkMQDescriptorEquality(fmqSafeUnion.fmqUnsync(), fmq.fmqUnsync());
+ }));
+}
+
class HidlMultithreadTest : public ::testing::Test {
public:
sp<IMultithread> multithreadInterface;
@@ -2213,9 +2869,9 @@
bool b = false;
bool p = false;
bool d = false;
- struct option longopts[] = {{0,0,0,0}};
+ struct option longopts[] = {{nullptr,0,nullptr,0}};
int res;
- while ((res = getopt_long(argc, argv, "hbpd", longopts, NULL)) >= 0) {
+ while ((res = getopt_long(argc, argv, "hbpd", longopts, nullptr)) >= 0) {
switch (res) {
case 'h': {
usage(me);
diff --git a/test/hidl_test/hidl_test_servers.cpp b/test/hidl_test/hidl_test_servers.cpp
index 2862002..3105199 100644
--- a/test/hidl_test/hidl_test_servers.cpp
+++ b/test/hidl_test/hidl_test_servers.cpp
@@ -81,7 +81,7 @@
void signal_handler(int signal) {
if (signal == SIGTERM) {
- for (auto p : gPidList) {
+ for (const auto& p : gPidList) {
killServer(p.second, p.first.c_str());
}
exit(0);
diff --git a/test/hidl_test/static_test.cpp b/test/hidl_test/static_test.cpp
index 3222f03..3d9f3f0 100644
--- a/test/hidl_test/static_test.cpp
+++ b/test/hidl_test/static_test.cpp
@@ -115,7 +115,7 @@
static_assert(IExpression::UInt64LiteralTypeGuessing::noSuffixHex1 == 0x7fffffff, "");
static_assert(IExpression::UInt64LiteralTypeGuessing::noSuffixHex2 == 0x80000000, "");
static_assert(IExpression::UInt64LiteralTypeGuessing::noSuffixHex3 == 0xffffffff, "");
-static_assert(IExpression::UInt64LiteralTypeGuessing::longHex1 == 0xffffffffl, "");
+static_assert(IExpression::UInt64LiteralTypeGuessing::longHex1 == 0xffffffffL, "");
static_assert(IExpression::UInt64LiteralTypeGuessing::longHex2 == 0Xfffffffff, "");
static_assert(IExpression::UInt64LiteralTypeGuessing::longHex3 == 0x7fffffffffffffff, "");
static_assert(IExpression::UInt64LiteralTypeGuessing::longHex4 == 0x8000000000000000, "");
@@ -151,7 +151,7 @@
static_assert(IExpression::Precedence::neg == (-4), "");
static_assert(IExpression::Precedence::literalL == (-4L), "");
static_assert(IExpression::Precedence::hex == (0xffffffff), "");
-static_assert(IExpression::Precedence::hexLong == (0xffffffffl), "");
+static_assert(IExpression::Precedence::hexLong == (0xffffffffL), "");
static_assert(IExpression::Precedence::hexLong2 == (0xfffffffff), "");
static_assert(IExpression::Precedence::simpleArithmetic == (4 + 1), "");
static_assert(IExpression::Precedence::simpleArithmetic2 == (2 + 3 - 4), "");
diff --git a/test/host_test/main.cpp b/test/host_test/main.cpp
index 9377306..5028882 100644
--- a/test/host_test/main.cpp
+++ b/test/host_test/main.cpp
@@ -46,22 +46,24 @@
coordinator.addDefaultPackagePath("a.b", "a3/b3/"); // should take path above
coordinator.addDefaultPackagePath("a.c", "a4/b4/"); // should succeed
- EXPECT_EQ_OK("a.b", coordinator.getPackageRoot, FQName("a.b.foo@1.0"));
- EXPECT_EQ_OK("a.c", coordinator.getPackageRoot, FQName("a.c.foo.bar@1.0::IFoo"));
+ EXPECT_EQ_OK("a.b", coordinator.getPackageRoot, FQName("a.b.foo", "1.0"));
+ EXPECT_EQ_OK("a.c", coordinator.getPackageRoot, FQName("a.c.foo.bar", "1.0", "IFoo"));
// getPackagePath(fqname, relative, sanitized, ...)
- EXPECT_EQ_OK("a1/b1/foo/1.0/", coordinator.getPackagePath, FQName("a.b.foo@1.0"), false, false);
- EXPECT_EQ_OK("a4/b4/foo/bar/1.0/", coordinator.getPackagePath, FQName("a.c.foo.bar@1.0::IFoo"),
- false, false);
- EXPECT_EQ_OK("a1/b1/foo/V1_0/", coordinator.getPackagePath, FQName("a.b.foo@1.0"), false, true);
- EXPECT_EQ_OK("a4/b4/foo/bar/V1_0/", coordinator.getPackagePath, FQName("a.c.foo.bar@1.0::IFoo"),
- false, true);
- EXPECT_EQ_OK("foo/1.0/", coordinator.getPackagePath, FQName("a.b.foo@1.0"), true, false);
- EXPECT_EQ_OK("foo/bar/1.0/", coordinator.getPackagePath, FQName("a.c.foo.bar@1.0::IFoo"), true,
+ EXPECT_EQ_OK("a1/b1/foo/1.0/", coordinator.getPackagePath, FQName("a.b.foo", "1.0"), false,
false);
- EXPECT_EQ_OK("foo/V1_0/", coordinator.getPackagePath, FQName("a.b.foo@1.0"), true, true);
- EXPECT_EQ_OK("foo/bar/V1_0/", coordinator.getPackagePath, FQName("a.c.foo.bar@1.0::IFoo"), true,
+ EXPECT_EQ_OK("a4/b4/foo/bar/1.0/", coordinator.getPackagePath,
+ FQName("a.c.foo.bar", "1.0", "IFoo"), false, false);
+ EXPECT_EQ_OK("a1/b1/foo/V1_0/", coordinator.getPackagePath, FQName("a.b.foo", "1.0"), false,
true);
+ EXPECT_EQ_OK("a4/b4/foo/bar/V1_0/", coordinator.getPackagePath,
+ FQName("a.c.foo.bar", "1.0", "IFoo"), false, true);
+ EXPECT_EQ_OK("foo/1.0/", coordinator.getPackagePath, FQName("a.b.foo", "1.0"), true, false);
+ EXPECT_EQ_OK("foo/bar/1.0/", coordinator.getPackagePath, FQName("a.c.foo.bar", "1.0", "IFoo"),
+ true, false);
+ EXPECT_EQ_OK("foo/V1_0/", coordinator.getPackagePath, FQName("a.b.foo", "1.0"), true, true);
+ EXPECT_EQ_OK("foo/bar/V1_0/", coordinator.getPackagePath, FQName("a.c.foo.bar", "1.0", "IFoo"),
+ true, true);
}
TEST_F(HidlGenHostTest, CoordinatorFilepathTest) {
@@ -75,7 +77,7 @@
EXPECT_EQ(OK, coordinator.addPackagePath("a.b", "a1/b1", &error));
EXPECT_TRUE(error.empty());
- const static FQName kName = FQName("a.b.c@1.2");
+ const static FQName kName = FQName("a.b.c", "1.2");
// get file names
EXPECT_EQ_OK("foo/x.y", coordinator.getFilepath, kName, Location::DIRECT, "x.y");
diff --git a/test/host_utils_test/Android.bp b/test/host_utils_test/Android.bp
new file mode 100644
index 0000000..f7962be
--- /dev/null
+++ b/test/host_utils_test/Android.bp
@@ -0,0 +1,24 @@
+// 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.
+
+cc_test_host {
+ name: "libhidl-gen-host-utils_test",
+ defaults: ["hidl-gen-defaults"],
+
+ shared_libs: [
+ "libhidl-gen-host-utils",
+ ],
+
+ srcs: ["main.cpp"],
+}
diff --git a/test/host_utils_test/main.cpp b/test/host_utils_test/main.cpp
new file mode 100644
index 0000000..8a6009e
--- /dev/null
+++ b/test/host_utils_test/main.cpp
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "libhidl-gen-host-utils"
+
+#include <hidl-util/StringHelper.h>
+
+#include <gtest/gtest.h>
+#include <vector>
+
+using ::android::StringHelper;
+
+class LibHidlGenUtilsTest : public ::testing::Test {};
+
+TEST_F(LibHidlGenUtilsTest, EndsWithTest) {
+ EXPECT_TRUE(StringHelper::EndsWith("", ""));
+ EXPECT_TRUE(StringHelper::EndsWith("a", ""));
+ EXPECT_TRUE(StringHelper::EndsWith("b", "b"));
+ EXPECT_TRUE(StringHelper::EndsWith("ab", "b"));
+ EXPECT_TRUE(StringHelper::EndsWith("ab", "ab"));
+ EXPECT_TRUE(StringHelper::EndsWith("abcd", "bcd"));
+ EXPECT_TRUE(StringHelper::EndsWith("abcd", "abcd"));
+ EXPECT_TRUE(StringHelper::EndsWith("abcdefghijk", "ijk"));
+ EXPECT_TRUE(StringHelper::EndsWith("abcdefghijk", "bcdefghijk"));
+
+ EXPECT_FALSE(StringHelper::EndsWith("", "a"));
+ EXPECT_FALSE(StringHelper::EndsWith("b", "a"));
+ EXPECT_FALSE(StringHelper::EndsWith("abcd", "ab"));
+}
+
+TEST_F(LibHidlGenUtilsTest, StartsWithTest) {
+ EXPECT_TRUE(StringHelper::StartsWith("", ""));
+ EXPECT_TRUE(StringHelper::StartsWith("a", ""));
+ EXPECT_TRUE(StringHelper::StartsWith("b", "b"));
+ EXPECT_TRUE(StringHelper::StartsWith("ab", "a"));
+ EXPECT_TRUE(StringHelper::StartsWith("ab", "ab"));
+ EXPECT_TRUE(StringHelper::StartsWith("abcd", "abc"));
+ EXPECT_TRUE(StringHelper::StartsWith("abcd", "abcd"));
+ EXPECT_TRUE(StringHelper::StartsWith("abcdefghijk", "abc"));
+ EXPECT_TRUE(StringHelper::StartsWith("abcdefghijk", "abcdefghij"));
+
+ EXPECT_FALSE(StringHelper::StartsWith("", "a"));
+ EXPECT_FALSE(StringHelper::StartsWith("b", "a"));
+ EXPECT_FALSE(StringHelper::StartsWith("abcd", "cd"));
+}
+
+TEST_F(LibHidlGenUtilsTest, Trim) {
+ EXPECT_EQ("", StringHelper::LTrim("", ""));
+ EXPECT_EQ("", StringHelper::LTrim("", "a"));
+ EXPECT_EQ("", StringHelper::LTrim("a", "a"));
+ EXPECT_EQ("a", StringHelper::LTrim("a", ""));
+ EXPECT_EQ("a", StringHelper::LTrim("a", "b"));
+ EXPECT_EQ("a", StringHelper::LTrim("ba", "b"));
+ EXPECT_EQ("f", StringHelper::LTrim("abcdef", "abcde"));
+ EXPECT_EQ("cdef", StringHelper::LTrim("abcdef", "ab"));
+ EXPECT_EQ("abcdef", StringHelper::LTrim("abcdef", ""));
+
+ EXPECT_EQ("", StringHelper::RTrim("", ""));
+ EXPECT_EQ("", StringHelper::RTrim("", "a"));
+ EXPECT_EQ("", StringHelper::RTrim("a", "a"));
+ EXPECT_EQ("a", StringHelper::RTrim("a", ""));
+ EXPECT_EQ("a", StringHelper::RTrim("a", "b"));
+ EXPECT_EQ("a", StringHelper::RTrim("ab", "b"));
+ EXPECT_EQ("a", StringHelper::RTrim("abcdef", "bcdef"));
+ EXPECT_EQ("abcd", StringHelper::RTrim("abcdef", "ef"));
+ EXPECT_EQ("abcdef", StringHelper::RTrim("abcdef", ""));
+}
+
+TEST_F(LibHidlGenUtilsTest, TrimAll) {
+ EXPECT_EQ("", StringHelper::LTrimAll("", ""));
+ EXPECT_EQ("", StringHelper::LTrimAll("", "a"));
+ EXPECT_EQ("", StringHelper::LTrimAll("", "ab"));
+ EXPECT_EQ("", StringHelper::LTrimAll("a", "a"));
+ EXPECT_EQ("", StringHelper::LTrimAll("aa", "a"));
+ EXPECT_EQ("b", StringHelper::LTrimAll("b", "a"));
+ EXPECT_EQ("b", StringHelper::LTrimAll("aaab", "a"));
+ EXPECT_EQ("c", StringHelper::LTrimAll("ababc", "ab"));
+ EXPECT_EQ("ac", StringHelper::LTrimAll("abac", "ab"));
+
+ EXPECT_EQ("", StringHelper::RTrimAll("", ""));
+ EXPECT_EQ("", StringHelper::RTrimAll("", "a"));
+ EXPECT_EQ("", StringHelper::RTrimAll("", "ab"));
+ EXPECT_EQ("", StringHelper::RTrimAll("a", "a"));
+ EXPECT_EQ("", StringHelper::RTrimAll("aa", "a"));
+ EXPECT_EQ("b", StringHelper::RTrimAll("b", "a"));
+ EXPECT_EQ("b", StringHelper::RTrimAll("baaa", "a"));
+ EXPECT_EQ("c", StringHelper::RTrimAll("cabab", "ab"));
+ EXPECT_EQ("ca", StringHelper::RTrimAll("caba", "ba"));
+}
+
+TEST_F(LibHidlGenUtilsTest, SplitString) {
+ std::vector<std::string> components;
+
+ StringHelper::SplitString("", '.', &components);
+ EXPECT_EQ(std::vector<std::string>({""}), components);
+ StringHelper::SplitString("a.", '.', &components);
+ EXPECT_EQ(std::vector<std::string>({"a", ""}), components);
+ StringHelper::SplitString(".a", '.', &components);
+ EXPECT_EQ(std::vector<std::string>({"", "a"}), components);
+ StringHelper::SplitString("..", '.', &components);
+ EXPECT_EQ(std::vector<std::string>({"", "", ""}), components);
+ StringHelper::SplitString("asdf.asdf", '.', &components);
+ EXPECT_EQ(std::vector<std::string>({"asdf", "asdf"}), components);
+}
+
+TEST_F(LibHidlGenUtilsTest, JoinStrings) {
+ EXPECT_EQ("", StringHelper::JoinStrings({}, ""));
+ EXPECT_EQ("", StringHelper::JoinStrings({}, "a"));
+ EXPECT_EQ("a", StringHelper::JoinStrings({"a"}, ""));
+ EXPECT_EQ("a,b", StringHelper::JoinStrings({"a", "b"}, ","));
+ EXPECT_EQ("ab,", StringHelper::JoinStrings({"ab", ""}, ","));
+ EXPECT_EQ(",ab", StringHelper::JoinStrings({"", "ab"}, ","));
+ EXPECT_EQ("a.,b", StringHelper::JoinStrings({"a", "b"}, ".,"));
+ EXPECT_EQ("a,b,c", StringHelper::JoinStrings({"a", "b", "c"}, ","));
+ EXPECT_EQ("abc.,def.,ghi", StringHelper::JoinStrings({"abc", "def", "ghi"}, ".,"));
+}
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/test/java_test/Android.bp b/test/java_test/Android.bp
index f7b731d..4f18adf 100644
--- a/test/java_test/Android.bp
+++ b/test/java_test/Android.bp
@@ -4,21 +4,46 @@
cflags: ["-Wall", "-Werror"],
+ // Allow dlsym'ing self for statically linked passthrough implementations
+ ldflags: ["-rdynamic"],
+
shared_libs: [
"libbase",
+ "libcutils",
"libhidlbase",
"libhidltransport",
"libhwbinder",
"liblog",
"libutils",
+ ],
+
+ static_libs: [
"android.hardware.tests.baz@1.0",
"android.hardware.tests.expression@1.0",
"android.hardware.tests.inheritance@1.0",
+ "android.hardware.tests.safeunion@1.0",
],
- required: [
+ // impls should never be static, these are used only for testing purposes
+ // and test portability since this test pairs with specific hal
+ // implementations
+ whole_static_libs: [
"android.hardware.tests.baz@1.0-impl",
+ "android.hardware.tests.safeunion@1.0-impl",
],
compile_multilib: "both",
}
+
+java_test {
+ name: "hidl_test_java_java",
+ srcs: ["**/*.java"],
+
+ static_libs: [
+ "android.hidl.manager-V1.0-java",
+ "android.hardware.tests.baz-V1.0-java",
+ "android.hardware.tests.expression-V1.0-java",
+ "android.hardware.tests.inheritance-V1.0-java",
+ "android.hardware.tests.safeunion-V1.0-java",
+ ],
+}
diff --git a/test/java_test/Android.mk b/test/java_test/Android.mk
index a41fa5d..36a73ce 100644
--- a/test/java_test/Android.mk
+++ b/test/java_test/Android.mk
@@ -1,35 +1,16 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_MODULE := hidl_test_java_lib
-LOCAL_MODULE_STEM := hidl_test_java
-LOCAL_MODULE_CLASS := JAVA_LIBRARIES
-LOCAL_JAVA_LIBRARIES := \
- android.hidl.base-V1.0-java \
- android.hidl.manager-V1.0-java \
- android.hardware.tests.baz-V1.0-java \
- android.hardware.tests.expression-V1.0-java \
- android.hardware.tests.inheritance-V1.0-java
-
-include $(BUILD_JAVA_LIBRARY)
-
-################################################################################
-
-include $(CLEAR_VARS)
LOCAL_MODULE := hidl_test_java
LOCAL_MODULE_CLASS := NATIVE_TESTS
LOCAL_SRC_FILES := hidl_test_java
LOCAL_REQUIRED_MODULES := \
- hidl_test_java_lib \
- hidl_test_java_native \
- android.hidl.base-V1.0-java \
- android.hidl.manager-V1.0-java \
- android.hardware.tests.baz-V1.0-java
+ hidl_test_java_java \
+ hidl_test_java_native
-LOCAL_REQUIRED_MODULES_arm64 := hidl_test_java_native_32
-LOCAL_REQUIRED_MODULES_x86_64 := hidl_test_java_native_32
-LOCAL_REQUIRED_MODULES_mips64 := hidl_test_java_native_32
+ifneq ($(TARGET_2ND_ARCH),)
+LOCAL_REQUIRED_MODULES += hidl_test_java_native$(TARGET_2ND_ARCH_MODULE_SUFFIX)
+endif
include $(BUILD_PREBUILT)
diff --git a/test/java_test/hidl_test_java b/test/java_test/hidl_test_java
index 1cdfb3f..fdcb00f 100644
--- a/test/java_test/hidl_test_java
+++ b/test/java_test/hidl_test_java
@@ -1,5 +1,4 @@
-base=/system
-export CLASSPATH=$base/framework/hidl_test_java.jar:$base/framework/android.hardware.tests.baz-V1.0-java.jar:$base/framework/android.hidl.base-V1.0-java.jar
+export CLASSPATH=/data/framework/hidl_test_java_java.jar
export TREBLE_TESTING_OVERRIDE=true
e=0
@@ -13,14 +12,14 @@
$native -s &
sleep 1
NATIVE_PID=$!
- app_process $base/bin com.android.commands.hidl_test_java.HidlTestJava -c \
+ app_process /data/framework com.android.commands.hidl_test_java.HidlTestJava -c \
&& echo "Java client => native server PASSED" \
|| (echo "Java client => native server FAILED" && false) || e=1
kill $NATIVE_PID 2>/dev/null
# Test Java server with native client
- app_process $base/bin com.android.commands.hidl_test_java.HidlTestJava -s &
+ app_process /data/framework com.android.commands.hidl_test_java.HidlTestJava -s &
NATIVE_PID=$!
$native -c \
&& echo "native client => Java server PASSED" \
@@ -37,4 +36,6 @@
echo "Summary: $e"
[ $e -eq 0 ] && echo "All tests PASSED." || echo "Test(s) FAILED."
+export TREBLE_TESTING_OVERRIDE=false
+
exit $e
diff --git a/test/java_test/hidl_test_java_native.cpp b/test/java_test/hidl_test_java_native.cpp
index d155e09..a7467d7 100644
--- a/test/java_test/hidl_test_java_native.cpp
+++ b/test/java_test/hidl_test_java_native.cpp
@@ -17,9 +17,12 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "hidl_test_java_native"
+#include <android-base/file.h>
#include <android-base/logging.h>
#include <android/hardware/tests/baz/1.0/IBaz.h>
+#include <android/hardware/tests/safeunion/1.0/IOtherInterface.h>
+#include <android/hardware/tests/safeunion/1.0/ISafeUnion.h>
#include <hidl/LegacySupport.h>
#include <hidl/ServiceManagement.h>
@@ -27,18 +30,30 @@
#include <hidl/HidlTransportSupport.h>
#include <hidl/Status.h>
+
+#include <numeric>
+#include <sys/stat.h>
+
using ::android::sp;
using ::android::hardware::tests::baz::V1_0::IBase;
using ::android::hardware::tests::baz::V1_0::IBaz;
using ::android::hardware::tests::baz::V1_0::IBazCallback;
+using ::android::hardware::tests::safeunion::V1_0::IOtherInterface;
+using ::android::hardware::tests::safeunion::V1_0::ISafeUnion;
using ::android::hardware::hidl_array;
using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_string;
using ::android::hardware::defaultPassthroughServiceImplementation;
using ::android::hardware::Return;
using ::android::hardware::Void;
+using HandleTypeSafeUnion = ISafeUnion::HandleTypeSafeUnion;
+using InterfaceTypeSafeUnion = ISafeUnion::InterfaceTypeSafeUnion;
+using LargeSafeUnion = ISafeUnion::LargeSafeUnion;
+using SmallSafeUnion = ISafeUnion::SmallSafeUnion;
+
struct BazCallback : public IBazCallback {
Return<void> heyItsMe(const sp<IBazCallback> &cb) override;
Return<void> hey() override;
@@ -57,6 +72,16 @@
return Void();
}
+struct OtherInterface : public IOtherInterface {
+ Return<void> concatTwoStrings(const hidl_string& a, const hidl_string& b,
+ concatTwoStrings_cb _hidl_cb) override {
+ hidl_string result = std::string(a) + std::string(b);
+ _hidl_cb(result);
+
+ return Void();
+ }
+};
+
using std::to_string;
static void usage(const char *me) {
@@ -73,17 +98,26 @@
struct HidlTest : public ::testing::Test {
sp<IBaz> baz;
+ sp<ISafeUnion> safeunionInterface;
+ sp<IOtherInterface> otherInterface;
void SetUp() override {
using namespace ::android::hardware;
- ::android::hardware::details::waitForHwService(
- IBaz::descriptor, "baz");
-
- baz = IBaz::getService("baz");
-
- CHECK(baz != NULL);
+ ::android::hardware::details::waitForHwService(IBaz::descriptor, "default");
+ baz = IBaz::getService();
+ CHECK(baz != nullptr);
CHECK(baz->isRemote());
+
+ ::android::hardware::details::waitForHwService(ISafeUnion::descriptor, "default");
+ safeunionInterface = ISafeUnion::getService();
+ CHECK(safeunionInterface != nullptr);
+ CHECK(safeunionInterface->isRemote());
+
+ ::android::hardware::details::waitForHwService(IOtherInterface::descriptor, "default");
+ otherInterface = IOtherInterface::getService();
+ CHECK(otherInterface != nullptr);
+ CHECK(otherInterface->isRemote());
}
void TearDown() override {
@@ -95,6 +129,14 @@
EXPECT_TRUE(ret.isOk());
}
+template<typename T, typename S>
+static inline bool isArrayEqual(const T arr1, const S arr2, size_t size) {
+ for(size_t i = 0; i < size; i++)
+ if(arr1[i] != arr2[i])
+ return false;
+ return true;
+}
+
TEST_F(HidlTest, GetDescriptorTest) {
EXPECT_OK(baz->interfaceDescriptor([&] (const auto &desc) {
EXPECT_EQ(desc, IBaz::descriptor);
@@ -129,6 +171,22 @@
}));
}
+TEST_F(HidlTest, SomeOtherBaseMethodInvalidString) {
+ IBase::Foo foo {
+ .y = {
+ .s = "\xff",
+ }
+ };
+
+ auto ret = baz->someOtherBaseMethod(foo, [&](const auto&) {
+ ADD_FAILURE() << "Should not accept invalid UTF-8 String";
+ });
+
+ EXPECT_FALSE(ret.isOk());
+
+ EXPECT_OK(baz->ping());
+}
+
TEST_F(HidlTest, BazSomeMethodWithFooArraysTest) {
hidl_array<IBase::Foo, 2> foo;
@@ -381,7 +439,7 @@
}
TEST_F(HidlTest, BazDoQuiteABitMethodTest) {
- auto result = baz->doQuiteABit(1, 2ll, 3.0f, 4.0);
+ auto result = baz->doQuiteABit(1, 2LL, 3.0f, 4.0);
EXPECT_OK(result);
EXPECT_EQ(result, 666.5);
@@ -574,6 +632,397 @@
in, [&](const auto &out) { EXPECT_EQ(in, out); }));
}
+TEST_F(HidlTest, SafeUnionNoInitTest) {
+ EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& safeUnion) {
+ EXPECT_EQ(LargeSafeUnion::hidl_discriminator::noinit, safeUnion.getDiscriminator());
+ }));
+}
+
+TEST_F(HidlTest, SafeUnionSimpleTest) {
+ EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& safeUnion) {
+ EXPECT_OK(safeunionInterface->setA(safeUnion, -5, [&](const LargeSafeUnion& safeUnion) {
+ EXPECT_EQ(LargeSafeUnion::hidl_discriminator::a, safeUnion.getDiscriminator());
+ EXPECT_EQ(-5, safeUnion.a());
+
+ uint64_t max = std::numeric_limits<uint64_t>::max();
+ EXPECT_OK(
+ safeunionInterface->setD(safeUnion, max, [&](const LargeSafeUnion& safeUnion) {
+ EXPECT_EQ(LargeSafeUnion::hidl_discriminator::d, safeUnion.getDiscriminator());
+ EXPECT_EQ(max, safeUnion.d());
+ }));
+ }));
+ }));
+}
+
+TEST_F(HidlTest, SafeUnionArrayLikeTypesTest) {
+ const std::array<int64_t, 5> testArray{1, -2, 3, -4, 5};
+ const hidl_vec<uint64_t> testVector{std::numeric_limits<uint64_t>::max()};
+
+ EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& safeUnion) {
+ EXPECT_OK(
+ safeunionInterface->setF(safeUnion, testArray, [&](const LargeSafeUnion& safeUnion) {
+ EXPECT_EQ(LargeSafeUnion::hidl_discriminator::f, safeUnion.getDiscriminator());
+
+ for (size_t i = 0; i < testArray.size(); i++) {
+ EXPECT_EQ(testArray[i], safeUnion.f()[i]);
+ }
+ }));
+
+ EXPECT_OK(
+ safeunionInterface->setI(safeUnion, testVector, [&](const LargeSafeUnion& safeUnion) {
+ EXPECT_EQ(LargeSafeUnion::hidl_discriminator::i, safeUnion.getDiscriminator());
+ EXPECT_EQ(testVector, safeUnion.i());
+ }));
+ }));
+}
+
+TEST_F(HidlTest, SafeUnionStringTypeTest) {
+ const std::string testString =
+ "This is an inordinately long test string to exercise hidl_string types in safe unions.";
+
+ EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& safeUnion) {
+ EXPECT_OK(safeunionInterface->setG(
+ safeUnion, hidl_string(testString), [&](const LargeSafeUnion& safeUnion) {
+ EXPECT_EQ(LargeSafeUnion::hidl_discriminator::g, safeUnion.getDiscriminator());
+ EXPECT_EQ(testString, std::string(safeUnion.g()));
+ }));
+ }));
+}
+
+TEST_F(HidlTest, SafeUnionNestedTest) {
+ SmallSafeUnion smallSafeUnion;
+ smallSafeUnion.a(1);
+
+ EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& safeUnion) {
+ EXPECT_OK(safeunionInterface->setL(
+ safeUnion, smallSafeUnion, [&](const LargeSafeUnion& safeUnion) {
+ EXPECT_EQ(LargeSafeUnion::hidl_discriminator::l, safeUnion.getDiscriminator());
+
+ EXPECT_EQ(SmallSafeUnion::hidl_discriminator::a, safeUnion.l().getDiscriminator());
+ EXPECT_EQ(1, safeUnion.l().a());
+ }));
+ }));
+}
+
+// does not check for fd equality
+static void checkNativeHandlesDataEquality(const native_handle_t* reference,
+ const native_handle_t* result) {
+ if (reference == nullptr || result == nullptr) {
+ EXPECT_EQ(reference == nullptr, result == nullptr);
+ return;
+ }
+
+ ASSERT_NE(reference, result);
+ ASSERT_EQ(reference->version, result->version);
+ EXPECT_EQ(reference->numFds, result->numFds);
+ EXPECT_EQ(reference->numInts, result->numInts);
+
+ int offset = reference->numFds;
+ int numInts = reference->numInts;
+ EXPECT_TRUE(isArrayEqual(&(reference->data[offset]), &(result->data[offset]), numInts));
+}
+
+TEST_F(HidlTest, SafeUnionInterfaceNullHandleTest) {
+ InterfaceTypeSafeUnion safeUnion;
+
+ EXPECT_OK(safeunionInterface->setInterfaceF(
+ safeUnion, hidl_handle(nullptr), [&](const InterfaceTypeSafeUnion& safeUnion) {
+ EXPECT_EQ(InterfaceTypeSafeUnion::hidl_discriminator::f,
+ safeUnion.getDiscriminator());
+
+ checkNativeHandlesDataEquality(nullptr, safeUnion.f().getNativeHandle());
+ }));
+}
+
+TEST_F(HidlTest, SafeUnionInterfaceTest) {
+ const std::array<int8_t, 7> testArray{-1, -2, -3, 0, 1, 2, 3};
+ const hidl_vec<hidl_string> testVector{"So", "Many", "Words"};
+ const std::string testStringA = "Hello";
+ const std::string testStringB = "World";
+
+ const std::array<int, 6> testHandleData{2, -32, 10, -4329454, 11, 24};
+ native_handle_t* h = native_handle_create(0, testHandleData.size());
+ CHECK(sizeof(testHandleData) == testHandleData.size() * sizeof(int));
+ std::memcpy(h->data, testHandleData.data(), sizeof(testHandleData));
+
+ std::vector<hidl_handle> testHandlesVector(256);
+ for (size_t i = 0; i < testHandlesVector.size(); i++) {
+ testHandlesVector[i].setTo(native_handle_clone(h), true /* shouldOwn */);
+ }
+
+ EXPECT_OK(
+ safeunionInterface->newInterfaceTypeSafeUnion([&](const InterfaceTypeSafeUnion& safeUnion) {
+ EXPECT_EQ(InterfaceTypeSafeUnion::hidl_discriminator::noinit,
+ safeUnion.getDiscriminator());
+
+ EXPECT_OK(safeunionInterface->setInterfaceB(
+ safeUnion, testArray, [&](const InterfaceTypeSafeUnion& safeUnion) {
+ EXPECT_EQ(InterfaceTypeSafeUnion::hidl_discriminator::b,
+ safeUnion.getDiscriminator());
+
+ for (size_t i = 0; i < testArray.size(); i++) {
+ EXPECT_EQ(testArray[i], safeUnion.b()[i]);
+ }
+ }));
+
+ EXPECT_OK(safeunionInterface->setInterfaceD(
+ safeUnion, testStringA, [&](const InterfaceTypeSafeUnion& safeUnion) {
+ EXPECT_EQ(InterfaceTypeSafeUnion::hidl_discriminator::d,
+ safeUnion.getDiscriminator());
+ EXPECT_EQ(testStringA, safeUnion.d());
+ }));
+
+ EXPECT_OK(safeunionInterface->setInterfaceE(
+ safeUnion, testVector, [&](const InterfaceTypeSafeUnion& safeUnion) {
+ EXPECT_EQ(InterfaceTypeSafeUnion::hidl_discriminator::e,
+ safeUnion.getDiscriminator());
+ EXPECT_EQ(testVector, safeUnion.e());
+ }));
+
+ EXPECT_OK(safeunionInterface->setInterfaceF(
+ safeUnion, hidl_handle(h), [&](const InterfaceTypeSafeUnion& safeUnion) {
+ EXPECT_EQ(InterfaceTypeSafeUnion::hidl_discriminator::f,
+ safeUnion.getDiscriminator());
+
+ const native_handle_t* result = safeUnion.f().getNativeHandle();
+ checkNativeHandlesDataEquality(h, result);
+ }));
+
+ EXPECT_OK(safeunionInterface->setInterfaceG(
+ safeUnion, testHandlesVector, [&](const InterfaceTypeSafeUnion& safeUnion) {
+ EXPECT_EQ(InterfaceTypeSafeUnion::hidl_discriminator::g,
+ safeUnion.getDiscriminator());
+
+ for (size_t i = 0; i < testHandlesVector.size(); i++) {
+ checkNativeHandlesDataEquality(h, safeUnion.g()[i].getNativeHandle());
+ }
+ }));
+ }));
+
+ // Same-process interface calls are not supported in Java, so we use
+ // a safe_union instance bound to this (client) process instead of
+ // safeunionInterface to exercise this test-case. Ref: b/110957763.
+ InterfaceTypeSafeUnion safeUnion;
+ safeUnion.c(otherInterface);
+
+ EXPECT_EQ(InterfaceTypeSafeUnion::hidl_discriminator::c, safeUnion.getDiscriminator());
+ EXPECT_OK(safeUnion.c()->concatTwoStrings(
+ hidl_string(testStringA), hidl_string(testStringB), [&](const hidl_string& result) {
+ EXPECT_EQ(testStringA + testStringB, std::string(result));
+ }));
+
+ native_handle_delete(h);
+}
+
+TEST_F(HidlTest, SafeUnionNullHandleTest) {
+ HandleTypeSafeUnion safeUnion;
+
+ EXPECT_OK(safeunionInterface->setHandleA(
+ safeUnion, hidl_handle(nullptr), [&](const HandleTypeSafeUnion& safeUnion) {
+ EXPECT_EQ(HandleTypeSafeUnion::hidl_discriminator::a,
+ safeUnion.getDiscriminator());
+
+ checkNativeHandlesDataEquality(nullptr, safeUnion.a().getNativeHandle());
+ }));
+}
+
+TEST_F(HidlTest, SafeUnionSimpleHandleTest) {
+ const std::array<int, 6> testData{2, -32, 10, -4329454, 11, 24};
+ native_handle_t* h = native_handle_create(0, testData.size());
+ ASSERT_EQ(sizeof(testData), testData.size() * sizeof(int));
+ std::memcpy(h->data, testData.data(), sizeof(testData));
+
+ std::array<hidl_handle, 5> testArray;
+ for (size_t i = 0; i < testArray.size(); i++) {
+ testArray[i].setTo(native_handle_clone(h), true /* shouldOwn */);
+ }
+
+ std::vector<hidl_handle> testVector(256);
+ for (size_t i = 0; i < testVector.size(); i++) {
+ testVector[i].setTo(native_handle_clone(h), true /* shouldOwn */);
+ }
+
+ EXPECT_OK(
+ safeunionInterface->newHandleTypeSafeUnion([&](const HandleTypeSafeUnion& safeUnion) {
+ EXPECT_OK(safeunionInterface->setHandleA(
+ safeUnion, hidl_handle(h), [&](const HandleTypeSafeUnion& safeUnion) {
+ EXPECT_EQ(HandleTypeSafeUnion::hidl_discriminator::a,
+ safeUnion.getDiscriminator());
+
+ checkNativeHandlesDataEquality(h, safeUnion.a().getNativeHandle());
+ }));
+
+ EXPECT_OK(safeunionInterface->setHandleB(
+ safeUnion, testArray, [&](const HandleTypeSafeUnion& safeUnion) {
+ EXPECT_EQ(HandleTypeSafeUnion::hidl_discriminator::b,
+ safeUnion.getDiscriminator());
+
+ for (size_t i = 0; i < testArray.size(); i++) {
+ checkNativeHandlesDataEquality(h, safeUnion.b()[i].getNativeHandle());
+ }
+ }));
+
+ EXPECT_OK(safeunionInterface->setHandleC(
+ safeUnion, testVector, [&](const HandleTypeSafeUnion& safeUnion) {
+ EXPECT_EQ(HandleTypeSafeUnion::hidl_discriminator::c,
+ safeUnion.getDiscriminator());
+
+ for (size_t i = 0; i < testVector.size(); i++) {
+ checkNativeHandlesDataEquality(h, safeUnion.c()[i].getNativeHandle());
+ }
+ }));
+ }));
+
+ native_handle_delete(h);
+}
+
+TEST_F(HidlTest, SafeUnionVecOfHandlesWithOneFdTest) {
+ const std::vector<std::string> testStrings{"This ", "is ", "so ", "much ", "data!\n"};
+ const std::string testFileName = "/data/local/tmp/SafeUnionVecOfHandlesWithOneFdTest";
+ const std::array<int, 6> testData{2, -32, 10, -4329454, 11, 24};
+ ASSERT_EQ(sizeof(testData), testData.size() * sizeof(int));
+
+ const std::string goldenResult = std::accumulate(testStrings.begin(),
+ testStrings.end(),
+ std::string());
+
+ int fd = open(testFileName.c_str(), (O_RDWR | O_TRUNC | O_CREAT), (S_IRUSR | S_IWUSR));
+ ASSERT_TRUE(fd >= 0);
+
+ native_handle* h = native_handle_create(1 /* numFds */, testData.size() /* numInts */);
+ std::memcpy(&(h->data[1]), testData.data(), sizeof(testData));
+ h->data[0] = fd;
+
+ hidl_vec<hidl_handle> testHandles(testStrings.size());
+ for (size_t i = 0; i < testHandles.size(); i++) {
+ testHandles[i].setTo(native_handle_clone(h), true /* shouldOwn */);
+ }
+
+ EXPECT_OK(
+ safeunionInterface->newHandleTypeSafeUnion([&](const HandleTypeSafeUnion& safeUnion) {
+ EXPECT_OK(safeunionInterface->setHandleC(
+ safeUnion, testHandles, [&](const HandleTypeSafeUnion& safeUnion) {
+ EXPECT_EQ(HandleTypeSafeUnion::hidl_discriminator::c,
+ safeUnion.getDiscriminator());
+
+ for (size_t i = 0; i < safeUnion.c().size(); i++) {
+ const native_handle_t* reference = testHandles[i].getNativeHandle();
+ const native_handle_t* result = safeUnion.c()[i].getNativeHandle();
+ checkNativeHandlesDataEquality(reference, result);
+
+ // Original FDs should be dup'd
+ int resultFd = result->data[0];
+ EXPECT_NE(reference->data[0], resultFd);
+
+ EXPECT_TRUE(android::base::WriteStringToFd(testStrings[i], resultFd));
+ EXPECT_EQ(0, fsync(resultFd));
+ }
+ }));
+ }));
+
+ std::string result;
+ lseek(fd, 0, SEEK_SET);
+
+ EXPECT_TRUE(android::base::ReadFdToString(fd, &result));
+ EXPECT_EQ(goldenResult, result);
+
+ native_handle_delete(h);
+ EXPECT_EQ(0, close(fd));
+ EXPECT_EQ(0, remove(testFileName.c_str()));
+}
+
+TEST_F(HidlTest, SafeUnionHandleWithMultipleFdsTest) {
+ const std::vector<std::string> testStrings{"This ", "is ", "so ", "much ", "data!\n"};
+ const std::string testFileName = "/data/local/tmp/SafeUnionHandleWithMultipleFdsTest";
+ const std::array<int, 6> testData{2, -32, 10, -4329454, 11, 24};
+ ASSERT_EQ(sizeof(testData), testData.size() * sizeof(int));
+
+ const std::string goldenResult = std::accumulate(testStrings.begin(),
+ testStrings.end(),
+ std::string());
+
+ int fd = open(testFileName.c_str(), (O_RDWR | O_TRUNC | O_CREAT), (S_IRUSR | S_IWUSR));
+ ASSERT_TRUE(fd >= 0);
+
+ const int numFds = testStrings.size();
+ native_handle* h = native_handle_create(numFds, testData.size() /* numInts */);
+ std::memcpy(&(h->data[numFds]), testData.data(), sizeof(testData));
+ for (size_t i = 0; i < numFds; i++) {
+ h->data[i] = fd;
+ }
+
+ hidl_handle testHandle;
+ testHandle.setTo(h, false /* shouldOwn */);
+
+ EXPECT_OK(
+ safeunionInterface->newHandleTypeSafeUnion([&](const HandleTypeSafeUnion& safeUnion) {
+ EXPECT_OK(safeunionInterface->setHandleA(
+ safeUnion, testHandle, [&](const HandleTypeSafeUnion& safeUnion) {
+ EXPECT_EQ(HandleTypeSafeUnion::hidl_discriminator::a,
+ safeUnion.getDiscriminator());
+
+ const native_handle_t* result = safeUnion.a().getNativeHandle();
+ checkNativeHandlesDataEquality(h, result);
+
+ for (size_t i = 0; i < result->numFds; i++) {
+ // Original FDs should be dup'd
+ int resultFd = result->data[i];
+ EXPECT_NE(h->data[i], resultFd);
+
+ EXPECT_TRUE(android::base::WriteStringToFd(testStrings[i], resultFd));
+ EXPECT_EQ(0, fsync(resultFd));
+ }
+ }));
+ }));
+
+ std::string result;
+ lseek(fd, 0, SEEK_SET);
+
+ EXPECT_TRUE(android::base::ReadFdToString(fd, &result));
+ EXPECT_EQ(goldenResult, result);
+
+ native_handle_delete(h);
+ EXPECT_EQ(0, close(fd));
+ EXPECT_EQ(0, remove(testFileName.c_str()));
+}
+
+TEST_F(HidlTest, SafeUnionEqualityTest) {
+ EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& one) {
+ EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& two) {
+ EXPECT_TRUE(one == two);
+ EXPECT_FALSE(one != two);
+ }));
+
+ EXPECT_OK(safeunionInterface->setA(one, 1, [&](const LargeSafeUnion& one) {
+ EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& two) {
+ EXPECT_FALSE(one == two);
+ EXPECT_TRUE(one != two);
+ }));
+
+ EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& two) {
+ EXPECT_OK(safeunionInterface->setB(two, 1, [&](const LargeSafeUnion& two) {
+ EXPECT_FALSE(one == two);
+ EXPECT_TRUE(one != two);
+ }));
+ }));
+
+ EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& two) {
+ EXPECT_OK(safeunionInterface->setA(two, 2, [&](const LargeSafeUnion& two) {
+ EXPECT_FALSE(one == two);
+ EXPECT_TRUE(one != two);
+ }));
+ }));
+
+ EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& two) {
+ EXPECT_OK(safeunionInterface->setA(two, 1, [&](const LargeSafeUnion& two) {
+ EXPECT_TRUE(one == two);
+ EXPECT_FALSE(one != two);
+ }));
+ }));
+ }));
+ }));
+}
+
int main(int argc, char **argv) {
setenv("TREBLE_TESTING_OVERRIDE", "true", true);
@@ -622,6 +1071,19 @@
return status;
}
- return defaultPassthroughServiceImplementation<IBaz>("baz");
+ ::android::status_t status;
+ configureRpcThreadpool(1, true);
+ status = registerPassthroughServiceImplementation<IBaz>();
+ CHECK(status == ::android::OK) << "IBaz didn't register";
+
+ status = registerPassthroughServiceImplementation<ISafeUnion>();
+ CHECK(status == ::android::OK) << "ISafeUnion didn't register";
+
+ sp<IOtherInterface> otherInterface = new OtherInterface();
+ status = otherInterface->registerAsService();
+ CHECK(status == ::android::OK) << "IOtherInterface didn't register";
+
+ joinRpcThreadpool();
+ return 0;
}
diff --git a/test/java_test/src/com/android/commands/hidl_test_java/HidlTestJava.java b/test/java_test/src/com/android/commands/hidl_test_java/HidlTestJava.java
index f670732..0f1394c 100644
--- a/test/java_test/src/com/android/commands/hidl_test_java/HidlTestJava.java
+++ b/test/java_test/src/com/android/commands/hidl_test_java/HidlTestJava.java
@@ -20,13 +20,26 @@
import android.hardware.tests.baz.V1_0.IBase;
import android.hardware.tests.baz.V1_0.IBaz;
import android.hardware.tests.baz.V1_0.IQuux;
+import android.hardware.tests.baz.V1_0.IBaz.MyHandle;
import android.hardware.tests.baz.V1_0.IBaz.NestedStruct;
import android.hardware.tests.baz.V1_0.IBazCallback;
+import android.hardware.tests.safeunion.V1_0.IOtherInterface;
+import android.hardware.tests.safeunion.V1_0.ISafeUnion;
+import android.hardware.tests.safeunion.V1_0.ISafeUnion.HandleTypeSafeUnion;
+import android.hardware.tests.safeunion.V1_0.ISafeUnion.InterfaceTypeSafeUnion;
+import android.hardware.tests.safeunion.V1_0.ISafeUnion.LargeSafeUnion;
+import android.hardware.tests.safeunion.V1_0.ISafeUnion.SmallSafeUnion;
import android.os.HwBinder;
+import android.os.NativeHandle;
import android.os.RemoteException;
import android.os.HidlSupport;
import android.util.Log;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.NoSuchElementException;
@@ -46,7 +59,7 @@
System.exit(exitCode);
}
- public int run(String[] args) throws RemoteException {
+ public int run(String[] args) throws RemoteException, IOException {
if (args[0].equals("-c")) {
client();
} else if (args[0].equals("-s")) {
@@ -214,7 +227,269 @@
ExpectTrue(!HidlSupport.deepEquals(l, r));
}
- private void client() throws RemoteException {
+ private void runClientSafeUnionTests() throws RemoteException, IOException {
+ ISafeUnion safeunionInterface = ISafeUnion.getService();
+
+ {
+ // SafeUnionNoInitTest
+ LargeSafeUnion safeUnion = safeunionInterface.newLargeSafeUnion();
+ ExpectTrue(safeUnion.getDiscriminator() == LargeSafeUnion.hidl_discriminator.noinit);
+ }
+ {
+ // SafeUnionSimpleTest
+ LargeSafeUnion safeUnion = safeunionInterface.newLargeSafeUnion();
+
+ safeUnion = safeunionInterface.setA(safeUnion, (byte) -5);
+ ExpectTrue(safeUnion.getDiscriminator() == LargeSafeUnion.hidl_discriminator.a);
+ ExpectTrue(safeUnion.a() == (byte) -5);
+
+ safeUnion = safeunionInterface.setD(safeUnion, Long.MAX_VALUE);
+ ExpectTrue(safeUnion.getDiscriminator() == LargeSafeUnion.hidl_discriminator.d);
+ ExpectTrue(safeUnion.d() == Long.MAX_VALUE);
+ }
+ {
+ // SafeUnionArrayLikeTypesTest
+ long[] testArray = new long[] {1, -2, 3, -4, 5};
+ ArrayList<Long> testVector = new ArrayList<Long>(Arrays.asList(Long.MAX_VALUE));
+
+ LargeSafeUnion safeUnion = safeunionInterface.newLargeSafeUnion();
+ safeUnion = safeunionInterface.setF(safeUnion, testArray);
+ ExpectTrue(safeUnion.getDiscriminator() == LargeSafeUnion.hidl_discriminator.f);
+ ExpectDeepEq(testArray, safeUnion.f());
+
+ safeUnion = safeunionInterface.newLargeSafeUnion();
+ safeUnion = safeunionInterface.setI(safeUnion, testVector);
+ ExpectTrue(safeUnion.getDiscriminator() == LargeSafeUnion.hidl_discriminator.i);
+ ExpectDeepEq(testVector, safeUnion.i());
+ }
+ {
+ // SafeUnionStringTypeTest
+ String testString = "This is an inordinately long test string.";
+
+ LargeSafeUnion safeUnion = safeunionInterface.newLargeSafeUnion();
+ safeUnion = safeunionInterface.setG(safeUnion, testString);
+ ExpectTrue(safeUnion.getDiscriminator() == LargeSafeUnion.hidl_discriminator.g);
+ ExpectDeepEq(testString, safeUnion.g());
+ }
+ {
+ // SafeUnionNestedTest
+ SmallSafeUnion smallSafeUnion = new SmallSafeUnion();
+ smallSafeUnion.a((byte) 1);
+
+ LargeSafeUnion safeUnion = safeunionInterface.newLargeSafeUnion();
+ safeUnion = safeunionInterface.setL(safeUnion, smallSafeUnion);
+ ExpectTrue(safeUnion.getDiscriminator() == LargeSafeUnion.hidl_discriminator.l);
+ ExpectTrue(safeUnion.l().getDiscriminator() == SmallSafeUnion.hidl_discriminator.a);
+ ExpectTrue(safeUnion.l().a() == (byte) 1);
+ }
+ {
+ // SafeUnionEnumTest
+ LargeSafeUnion safeUnion = safeunionInterface.newLargeSafeUnion();
+ safeUnion = safeunionInterface.setM(safeUnion, ISafeUnion.BitField.V1);
+ ExpectTrue(safeUnion.getDiscriminator() == LargeSafeUnion.hidl_discriminator.m);
+ ExpectTrue(safeUnion.m() == ISafeUnion.BitField.V1);
+ }
+ {
+ // SafeUnionBitFieldTest
+ LargeSafeUnion safeUnion = safeunionInterface.newLargeSafeUnion();
+ safeUnion = safeunionInterface.setN(safeUnion, ISafeUnion.BitField.V1);
+ ExpectTrue(safeUnion.getDiscriminator() == LargeSafeUnion.hidl_discriminator.n);
+ ExpectTrue(safeUnion.n() == ISafeUnion.BitField.V1);
+ }
+ {
+ // SafeUnionInterfaceNullNativeHandleTest
+ InterfaceTypeSafeUnion safeUnion = new InterfaceTypeSafeUnion();
+
+ safeUnion = safeunionInterface.setInterfaceF(safeUnion, null);
+ ExpectTrue(safeUnion.getDiscriminator() == InterfaceTypeSafeUnion.hidl_discriminator.f);
+ ExpectTrue(safeUnion.f() == null);
+ }
+ {
+ // SafeUnionInterfaceTest
+ byte[] testArray = new byte[] {-1, -2, -3, 0, 1, 2, 3};
+ ArrayList<String> testVector = new ArrayList(Arrays.asList("So", "Many", "Words"));
+ String testStringA = "Hello";
+ String testStringB = "World";
+
+ IOtherInterface otherInterface = IOtherInterface.getService();
+
+ ArrayList<NativeHandle> testHandlesVector = new ArrayList<>();
+ for (int i = 0; i < 128; i++) {
+ testHandlesVector.add(new NativeHandle());
+ }
+
+ InterfaceTypeSafeUnion safeUnion = safeunionInterface.newInterfaceTypeSafeUnion();
+ safeUnion = safeunionInterface.setInterfaceB(safeUnion, testArray);
+ ExpectTrue(safeUnion.getDiscriminator() == InterfaceTypeSafeUnion.hidl_discriminator.b);
+ ExpectDeepEq(testArray, safeUnion.b());
+
+ safeUnion.c(otherInterface);
+ ExpectTrue(safeUnion.getDiscriminator() == InterfaceTypeSafeUnion.hidl_discriminator.c);
+ ExpectTrue(HidlSupport.interfacesEqual(otherInterface, safeUnion.c()));
+ String result = safeUnion.c().concatTwoStrings(testStringA, testStringB);
+ Expect(result, testStringA + testStringB);
+
+ safeUnion = safeunionInterface.setInterfaceD(safeUnion, testStringA);
+ ExpectTrue(safeUnion.getDiscriminator() == InterfaceTypeSafeUnion.hidl_discriminator.d);
+ Expect(testStringA, safeUnion.d());
+
+ safeUnion = safeunionInterface.setInterfaceE(safeUnion, testVector);
+ ExpectTrue(safeUnion.getDiscriminator() == InterfaceTypeSafeUnion.hidl_discriminator.e);
+ ExpectDeepEq(testVector, safeUnion.e());
+
+ safeUnion = safeunionInterface.setInterfaceG(safeUnion, testHandlesVector);
+ ExpectTrue(safeUnion.getDiscriminator() == InterfaceTypeSafeUnion.hidl_discriminator.g);
+ ExpectTrue(safeUnion.g().size() == testHandlesVector.size());
+
+ for (int i = 0; i < testHandlesVector.size(); i++) {
+ ExpectFalse(safeUnion.g().get(i).hasSingleFileDescriptor());
+ }
+ }
+ {
+ // SafeUnionNullNativeHandleTest
+ HandleTypeSafeUnion safeUnion = new HandleTypeSafeUnion();
+
+ safeUnion = safeunionInterface.setHandleA(safeUnion, null);
+ ExpectTrue(safeUnion.getDiscriminator() == HandleTypeSafeUnion.hidl_discriminator.a);
+ ExpectTrue(safeUnion.a() == null);
+ }
+ {
+ // SafeUnionDefaultNativeHandleTest
+ NativeHandle[] testHandlesArray = new NativeHandle[5];
+ for (int i = 0; i < testHandlesArray.length; i++) {
+ testHandlesArray[i] = new NativeHandle();
+ }
+
+ ArrayList<NativeHandle> testHandlesList = new ArrayList<NativeHandle>(
+ Arrays.asList(testHandlesArray));
+
+ HandleTypeSafeUnion safeUnion = safeunionInterface.newHandleTypeSafeUnion();
+ safeUnion = safeunionInterface.setHandleA(safeUnion, new NativeHandle());
+ ExpectTrue(safeUnion.getDiscriminator() == HandleTypeSafeUnion.hidl_discriminator.a);
+ ExpectFalse(safeUnion.a().hasSingleFileDescriptor());
+
+ safeUnion = safeunionInterface.setHandleB(safeUnion, testHandlesArray);
+ ExpectTrue(safeUnion.getDiscriminator() == HandleTypeSafeUnion.hidl_discriminator.b);
+ ExpectTrue(safeUnion.b().length == testHandlesArray.length);
+
+ for (int i = 0; i < testHandlesArray.length; i++) {
+ ExpectFalse(safeUnion.b()[i].hasSingleFileDescriptor());
+ }
+
+ safeUnion = safeunionInterface.setHandleC(safeUnion, testHandlesList);
+ ExpectTrue(safeUnion.getDiscriminator() == HandleTypeSafeUnion.hidl_discriminator.c);
+ ExpectTrue(safeUnion.c().size() == testHandlesList.size());
+
+ for (int i = 0; i < testHandlesList.size(); i++) {
+ ExpectFalse(safeUnion.c().get(i).hasSingleFileDescriptor());
+ }
+ }
+ {
+ // SafeUnionNativeHandleWithFdTest
+ final String testFileName = "/data/local/tmp/SafeUnionNativeHandleWithFdTest";
+ final String[] testStrings = {"This ", "is ", "so ", "much ", "data!\n"};
+ File file = new File(testFileName);
+
+ if (file.exists()) { ExpectTrue(file.delete()); }
+ ExpectTrue(file.createNewFile());
+
+ StringBuilder builder = new StringBuilder();
+ for (String testString : testStrings) {
+ builder.append(testString);
+ }
+ final String goldenResult = builder.toString();
+
+ ArrayList<NativeHandle> testHandlesList = new ArrayList<NativeHandle>();
+ FileOutputStream fos = new FileOutputStream(file);
+ for (int i = 0; i < testStrings.length; i++) {
+ testHandlesList.add(new NativeHandle(fos.getFD(), false /*own*/));
+ }
+
+ HandleTypeSafeUnion safeUnion = safeunionInterface.newHandleTypeSafeUnion();
+ safeUnion = safeunionInterface.setHandleC(safeUnion, testHandlesList);
+ for (int i = 0; i < safeUnion.c().size(); i++) {
+ ExpectTrue(safeUnion.c().get(i).hasSingleFileDescriptor());
+
+ // If you want to copy it out of the binder buffer or save it, it needs to be duped.
+ // This isn't necessary for the test since it is kept open for the binder window.
+ NativeHandle handle = safeUnion.c().get(i);
+ if (i%2 == 0) handle = handle.dup();
+
+ // Original fd is duped if not dup'd above
+ FileDescriptor resultFd = handle.getFileDescriptor();
+ ExpectTrue(resultFd.getInt$() != fos.getFD().getInt$());
+
+ FileOutputStream otherFos = new FileOutputStream(resultFd);
+ otherFos.write(testStrings[i].getBytes());
+ otherFos.flush();
+
+ otherFos.close();
+
+ if (i%2 == 0) handle.close();
+ }
+
+ byte[] resultData = new byte[(int) file.length()];
+ FileInputStream fis = new FileInputStream(file);
+ fis.read(resultData);
+
+ String result = new String(resultData);
+ Expect(result, goldenResult);
+
+ fis.close();
+ fos.close();
+ ExpectTrue(file.delete());
+ }
+ {
+ // SafeUnionEqualityTest
+ LargeSafeUnion one = safeunionInterface.newLargeSafeUnion();
+ LargeSafeUnion two = safeunionInterface.newLargeSafeUnion();
+ ExpectTrue(one.equals(two));
+
+ one = safeunionInterface.setA(one, (byte) 1);
+ ExpectFalse(one.equals(two));
+
+ two = safeunionInterface.setB(two, (byte) 1);
+ ExpectFalse(one.equals(two));
+
+ two = safeunionInterface.setA(two, (byte) 2);
+ ExpectFalse(one.equals(two));
+
+ two = safeunionInterface.setA(two, (byte) 1);
+ ExpectTrue(one.equals(two));
+ }
+ {
+ // SafeUnionDeepEqualityTest
+ ArrayList<Long> testVectorA = new ArrayList(Arrays.asList(1L, 2L, 3L));
+ ArrayList<Long> testVectorB = new ArrayList(Arrays.asList(2L, 1L, 3L));
+
+ LargeSafeUnion one = safeunionInterface.newLargeSafeUnion();
+ LargeSafeUnion two = safeunionInterface.newLargeSafeUnion();
+
+ one = safeunionInterface.setI(one, testVectorA);
+ two = safeunionInterface.setI(two, testVectorB);
+ ExpectFalse(one.equals(two));
+
+ two = safeunionInterface.setI(two, (ArrayList<Long>) testVectorA.clone());
+ ExpectTrue(one.equals(two));
+ }
+ {
+ // SafeUnionHashCodeTest
+ ArrayList<Boolean> testVector =
+ new ArrayList(Arrays.asList(true, false, false, true, true));
+
+ LargeSafeUnion one = safeunionInterface.newLargeSafeUnion();
+ LargeSafeUnion two = safeunionInterface.newLargeSafeUnion();
+
+ one = safeunionInterface.setH(one, testVector);
+ two = safeunionInterface.setA(two, (byte) -5);
+ ExpectFalse(one.hashCode() == two.hashCode());
+
+ two = safeunionInterface.setH(two, (ArrayList<Boolean>) testVector.clone());
+ ExpectTrue(one.hashCode() == two.hashCode());
+ }
+ }
+
+ private void client() throws RemoteException, IOException {
ExpectDeepEq(null, null);
ExpectDeepNe(null, new String());
@@ -271,7 +546,7 @@
{
// Test access through base interface binder.
- IBase baseProxy = IBase.getService("baz");
+ IBase baseProxy = IBase.getService();
baseProxy.someBaseMethod();
IBaz bazProxy = IBaz.castFrom(baseProxy);
@@ -285,13 +560,13 @@
{
// Test waiting API
- IBase baseProxyA = IBaz.getService("baz", true /* retry */);
+ IBase baseProxyA = IBaz.getService(true /* retry */);
ExpectTrue(baseProxyA != null);
- IBase baseProxyB = IBaz.getService("baz", false /* retry */);
+ IBase baseProxyB = IBaz.getService(false /* retry */);
ExpectTrue(baseProxyB != null);
}
- IBaz proxy = IBaz.getService("baz");
+ IBaz proxy = IBaz.getService();
proxy.ping();
@@ -705,7 +980,7 @@
ArrayList<byte[]> in = new ArrayList<byte[]>();
int k = 0;
- for (int i = 0; i < in.size(); ++i) {
+ for (int i = 0; i < 8; ++i) {
byte[] elem = new byte[128];
for (int j = 0; j < 128; ++j, ++k) {
elem[j] = (byte)k;
@@ -714,7 +989,34 @@
}
ArrayList<byte[]> out = proxy.testByteVecs(in);
- ExpectTrue(in.equals(out));
+
+ ExpectDeepEq(in, out);
+ }
+
+ {
+ // testByteVecs w/ mismatched element lengths.
+
+ ArrayList<byte[]> in = new ArrayList<byte[]>();
+
+ int k = 0;
+ for (int i = 0; i < 8; ++i) {
+ byte[] elem = new byte[128 - i];
+ for (int j = 0; j < (128 - i); ++j, ++k) {
+ elem[j] = (byte)k;
+ }
+ in.add(elem);
+ }
+
+ boolean failedAsItShould = false;
+
+ try {
+ ArrayList<byte[]> out = proxy.testByteVecs(in);
+ }
+ catch (IllegalArgumentException e) {
+ failedAsItShould = true;
+ }
+
+ ExpectTrue(failedAsItShould);
}
{
@@ -723,7 +1025,7 @@
ArrayList<boolean[]> in = new ArrayList<boolean[]>();
int k = 0;
- for (int i = 0; i < in.size(); ++i) {
+ for (int i = 0; i < 8; ++i) {
boolean[] elem = new boolean[128];
for (int j = 0; j < 128; ++j, ++k) {
elem[j] = (k & 4) != 0;
@@ -732,7 +1034,7 @@
}
ArrayList<boolean[]> out = proxy.testBooleanVecs(in);
- ExpectTrue(in.equals(out));
+ ExpectDeepEq(in, out);
}
{
@@ -741,7 +1043,7 @@
ArrayList<double[]> in = new ArrayList<double[]>();
int k = 0;
- for (int i = 0; i < in.size(); ++i) {
+ for (int i = 0; i < 8; ++i) {
double[] elem = new double[128];
for (int j = 0; j < 128; ++j, ++k) {
elem[j] = k;
@@ -750,16 +1052,15 @@
}
ArrayList<double[]> out = proxy.testDoubleVecs(in);
- ExpectTrue(in.equals(out));
+ ExpectDeepEq(in, out);
}
-
{
// testProxyEquals
// TODO(b/68727931): test passthrough services as well.
- IBase proxy1 = IBase.getService("baz");
- IBase proxy2 = IBase.getService("baz");
- IBaz proxy3 = IBaz.getService("baz");
+ IBase proxy1 = IBase.getService();
+ IBase proxy2 = IBase.getService();
+ IBaz proxy3 = IBaz.getService();
IBazCallback callback1 = new BazCallback();
IBazCallback callback2 = new BazCallback();
IServiceManager manager = IServiceManager.getService();
@@ -789,7 +1090,7 @@
ExpectFalse(set.contains(manager));
}
{
- IBaz baz = IBaz.getService("baz");
+ IBaz baz = IBaz.getService();
ExpectTrue(baz != null);
IBaz.StructWithInterface swi = new IBaz.StructWithInterface();
swi.dummy = baz;
@@ -801,6 +1102,8 @@
ExpectTrue(swi_back.number == 12345678);
}
+ runClientSafeUnionTests();
+
// --- DEATH RECIPIENT TESTING ---
// This must always be done last, since it will kill the native server process
HidlDeathRecipient recipient1 = new HidlDeathRecipient();
@@ -808,7 +1111,12 @@
final int cookie1 = 0x1481;
final int cookie2 = 0x1482;
+ final int cookie3 = 0x1483;
ExpectTrue(proxy.linkToDeath(recipient1, cookie1));
+
+ ExpectTrue(proxy.linkToDeath(recipient1, cookie3));
+ ExpectTrue(proxy.unlinkToDeath(recipient1));
+
ExpectTrue(proxy.linkToDeath(recipient2, cookie2));
ExpectTrue(proxy.unlinkToDeath(recipient2));
try {
@@ -1087,11 +1395,242 @@
}
}
+ class SafeUnion extends ISafeUnion.Stub {
+ @Override
+ public LargeSafeUnion newLargeSafeUnion() {
+ Log.d(TAG, "SERVER: newLargeSafeUnion");
+ return new LargeSafeUnion();
+ }
+
+ @Override
+ public LargeSafeUnion setA(LargeSafeUnion safeUnion, byte a) {
+ Log.d(TAG, "SERVER: setA(" + a + ")");
+ safeUnion.a(a);
+
+ return safeUnion;
+ }
+
+ @Override
+ public LargeSafeUnion setB(LargeSafeUnion safeUnion, short b) {
+ Log.d(TAG, "SERVER: setB(" + b + ")");
+ safeUnion.b(b);
+
+ return safeUnion;
+ }
+
+ @Override
+ public LargeSafeUnion setC(LargeSafeUnion safeUnion, int c) {
+ Log.d(TAG, "SERVER: setC(" + c + ")");
+ safeUnion.c(c);
+
+ return safeUnion;
+ }
+
+ @Override
+ public LargeSafeUnion setD(LargeSafeUnion safeUnion, long d) {
+ Log.d(TAG, "SERVER: setD(" + d + ")");
+ safeUnion.d(d);
+
+ return safeUnion;
+ }
+
+ @Override
+ public LargeSafeUnion setE(LargeSafeUnion safeUnion, byte[/* 13 */] e) {
+ Log.d(TAG, "SERVER: setE(" + e + ")");
+ safeUnion.e(e);
+
+ return safeUnion;
+ }
+
+ @Override
+ public LargeSafeUnion setF(LargeSafeUnion safeUnion, long[/* 5 */] f) {
+ Log.d(TAG, "SERVER: setF(" + f + ")");
+ safeUnion.f(f);
+
+ return safeUnion;
+ }
+
+ @Override
+ public LargeSafeUnion setG(LargeSafeUnion safeUnion, String g) {
+ Log.d(TAG, "SERVER: setG(" + g + ")");
+ safeUnion.g(g);
+
+ return safeUnion;
+ }
+
+ @Override
+ public LargeSafeUnion setH(LargeSafeUnion safeUnion, ArrayList<Boolean> h) {
+ Log.d(TAG, "SERVER: setH(" + h + ")");
+ safeUnion.h(h);
+
+ return safeUnion;
+ }
+
+ @Override
+ public LargeSafeUnion setI(LargeSafeUnion safeUnion, ArrayList<Long> i) {
+ Log.d(TAG, "SERVER: setI(" + i + ")");
+ safeUnion.i(i);
+
+ return safeUnion;
+ }
+
+ @Override
+ public LargeSafeUnion setJ(LargeSafeUnion safeUnion, ISafeUnion.J j) {
+ Log.d(TAG, "SERVER: setJ(" + j + ")");
+ safeUnion.j(j);
+
+ return safeUnion;
+ }
+
+ @Override
+ public LargeSafeUnion setK(LargeSafeUnion safeUnion, LargeSafeUnion.K k) {
+ Log.d(TAG, "SERVER: setK(" + k + ")");
+ safeUnion.k(k);
+
+ return safeUnion;
+ }
+
+ @Override
+ public LargeSafeUnion setL(LargeSafeUnion safeUnion, SmallSafeUnion l) {
+ Log.d(TAG, "SERVER: setL(" + l + ")");
+ safeUnion.l(l);
+
+ return safeUnion;
+ }
+
+ @Override
+ public LargeSafeUnion setM(LargeSafeUnion safeUnion, byte m) {
+ Log.d(TAG, "SERVER: setM(" + m + ")");
+ safeUnion.m(m);
+
+ return safeUnion;
+ }
+
+ @Override
+ public LargeSafeUnion setN(LargeSafeUnion safeUnion, byte n) {
+ Log.d(TAG, "SERVER: setN(" + n + ")");
+ safeUnion.n(n);
+
+ return safeUnion;
+ }
+
+ @Override
+ public InterfaceTypeSafeUnion newInterfaceTypeSafeUnion() {
+ Log.d(TAG, "SERVER: newInterfaceTypeSafeUnion");
+ return new InterfaceTypeSafeUnion();
+ }
+
+ @Override
+ public InterfaceTypeSafeUnion setInterfaceA(InterfaceTypeSafeUnion safeUnion, int a) {
+ Log.d(TAG, "SERVER: setInterfaceA(" + a + ")");
+ safeUnion.a(a);
+
+ return safeUnion;
+ }
+
+ @Override
+ public InterfaceTypeSafeUnion setInterfaceB(
+ InterfaceTypeSafeUnion safeUnion, byte[/* 7 */] b) {
+ Log.d(TAG, "SERVER: setInterfaceB(" + b + ")");
+ safeUnion.b(b);
+
+ return safeUnion;
+ }
+
+ @Override
+ public InterfaceTypeSafeUnion setInterfaceC(
+ InterfaceTypeSafeUnion safeUnion, IOtherInterface c) {
+ Log.d(TAG, "SERVER: setInterfaceC(" + c + ")");
+ safeUnion.c(c);
+
+ return safeUnion;
+ }
+
+ @Override
+ public InterfaceTypeSafeUnion setInterfaceD(InterfaceTypeSafeUnion safeUnion, String d) {
+ Log.d(TAG, "SERVER: setInterfaceD(" + d + ")");
+ safeUnion.d(d);
+
+ return safeUnion;
+ }
+
+ @Override
+ public InterfaceTypeSafeUnion setInterfaceE(
+ InterfaceTypeSafeUnion safeUnion, ArrayList<String> e) {
+ Log.d(TAG, "SERVER: setInterfaceE(" + e + ")");
+ safeUnion.e(e);
+
+ return safeUnion;
+ }
+
+ @Override
+ public InterfaceTypeSafeUnion setInterfaceF(
+ InterfaceTypeSafeUnion safeUnion, NativeHandle f) {
+ Log.d(TAG, "SERVER: setInterfaceF(" + f + ")");
+ safeUnion.f(f);
+
+ return safeUnion;
+ }
+
+ @Override
+ public InterfaceTypeSafeUnion setInterfaceG(
+ InterfaceTypeSafeUnion safeUnion, ArrayList<NativeHandle> g) {
+ Log.d(TAG, "SERVER: setInterfaceG(" + g + ")");
+ safeUnion.g(g);
+
+ return safeUnion;
+ }
+
+ @Override
+ public HandleTypeSafeUnion newHandleTypeSafeUnion() {
+ Log.d(TAG, "SERVER: newHandleTypeSafeUnion");
+ return new HandleTypeSafeUnion();
+ }
+
+ @Override
+ public HandleTypeSafeUnion setHandleA(HandleTypeSafeUnion safeUnion, NativeHandle a) {
+ Log.d(TAG, "SERVER: setHandleA(" + a + ")");
+ safeUnion.a(a);
+
+ return safeUnion;
+ }
+
+ @Override
+ public HandleTypeSafeUnion setHandleB(HandleTypeSafeUnion safeUnion, NativeHandle[] b) {
+ Log.d(TAG, "SERVER: setHandleB(" + b + ")");
+ safeUnion.b(b);
+
+ return safeUnion;
+ }
+
+ @Override
+ public HandleTypeSafeUnion setHandleC(HandleTypeSafeUnion safeUnion,
+ ArrayList<NativeHandle> c) {
+ Log.d(TAG, "SERVER: setHandleC(" + c + ")");
+ safeUnion.c(c);
+
+ return safeUnion;
+ }
+ }
+
+ class OtherInterface extends IOtherInterface.Stub {
+ @Override
+ public String concatTwoStrings(String a, String b) {
+ return a.concat(b);
+ }
+ }
+
private void server() throws RemoteException {
HwBinder.configureRpcThreadpool(1, true);
Baz baz = new Baz();
- baz.registerAsService("baz");
+ baz.registerAsService("default");
+
+ SafeUnion safeunionInterface = new SafeUnion();
+ safeunionInterface.registerAsService("default");
+
+ OtherInterface otherInterface = new OtherInterface();
+ otherInterface.registerAsService("default");
HwBinder.joinRpcThreadpool();
}
diff --git a/test/run_all_host_tests.sh b/test/run_all_host_tests.sh
index 442efd7..24e294e 100755
--- a/test/run_all_host_tests.sh
+++ b/test/run_all_host_tests.sh
@@ -8,11 +8,13 @@
hidl_export_test \
hidl_hash_test \
hidl_impl_test \
+ hidl_system_api_test \
android.hardware.tests.foo@1.0-vts.driver \
android.hardware.tests.foo@1.0-vts.profiler)
local RUN_TIME_TESTS=(\
libhidl-gen-utils_test \
+ libhidl-gen-host-utils_test \
hidl-gen-host_test \
)
@@ -41,4 +43,4 @@
fi
}
-run
\ No newline at end of file
+run
diff --git a/test/system_api_test/Android.bp b/test/system_api_test/Android.bp
new file mode 100644
index 0000000..fff313a
--- /dev/null
+++ b/test/system_api_test/Android.bp
@@ -0,0 +1,25 @@
+// 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.
+
+// hidl-generated libs should only depend on @SystemApi
+java_library {
+ name: "hidl_system_api_test",
+ sdk_version: "system_current",
+
+ static_libs: [
+ "android.hidl.base-V1.0-java",
+ "android.hidl.manager-V1.0-java",
+ "android.hardware.tests.baz-V1.0-java",
+ ],
+}
diff --git a/test/utils_test/main.cpp b/test/utils_test/main.cpp
index b2c8576..ee0556f 100644
--- a/test/utils_test/main.cpp
+++ b/test/utils_test/main.cpp
@@ -17,119 +17,15 @@
#define LOG_TAG "libhidl-gen-utils"
#include <hidl-util/FqInstance.h>
-#include <hidl-util/StringHelper.h>
#include <gtest/gtest.h>
#include <vector>
using ::android::FqInstance;
-using ::android::StringHelper;
+using ::android::FQName;
class LibHidlGenUtilsTest : public ::testing::Test {};
-TEST_F(LibHidlGenUtilsTest, EndsWithTest) {
- EXPECT_TRUE(StringHelper::EndsWith("", ""));
- EXPECT_TRUE(StringHelper::EndsWith("a", ""));
- EXPECT_TRUE(StringHelper::EndsWith("b", "b"));
- EXPECT_TRUE(StringHelper::EndsWith("ab", "b"));
- EXPECT_TRUE(StringHelper::EndsWith("ab", "ab"));
- EXPECT_TRUE(StringHelper::EndsWith("abcd", "bcd"));
- EXPECT_TRUE(StringHelper::EndsWith("abcd", "abcd"));
- EXPECT_TRUE(StringHelper::EndsWith("abcdefghijk", "ijk"));
- EXPECT_TRUE(StringHelper::EndsWith("abcdefghijk", "bcdefghijk"));
-
- EXPECT_FALSE(StringHelper::EndsWith("", "a"));
- EXPECT_FALSE(StringHelper::EndsWith("b", "a"));
- EXPECT_FALSE(StringHelper::EndsWith("abcd", "ab"));
-}
-
-TEST_F(LibHidlGenUtilsTest, StartsWithTest) {
- EXPECT_TRUE(StringHelper::StartsWith("", ""));
- EXPECT_TRUE(StringHelper::StartsWith("a", ""));
- EXPECT_TRUE(StringHelper::StartsWith("b", "b"));
- EXPECT_TRUE(StringHelper::StartsWith("ab", "a"));
- EXPECT_TRUE(StringHelper::StartsWith("ab", "ab"));
- EXPECT_TRUE(StringHelper::StartsWith("abcd", "abc"));
- EXPECT_TRUE(StringHelper::StartsWith("abcd", "abcd"));
- EXPECT_TRUE(StringHelper::StartsWith("abcdefghijk", "abc"));
- EXPECT_TRUE(StringHelper::StartsWith("abcdefghijk", "abcdefghij"));
-
- EXPECT_FALSE(StringHelper::StartsWith("", "a"));
- EXPECT_FALSE(StringHelper::StartsWith("b", "a"));
- EXPECT_FALSE(StringHelper::StartsWith("abcd", "cd"));
-}
-
-TEST_F(LibHidlGenUtilsTest, Trim) {
- EXPECT_EQ("", StringHelper::LTrim("", ""));
- EXPECT_EQ("", StringHelper::LTrim("", "a"));
- EXPECT_EQ("", StringHelper::LTrim("a", "a"));
- EXPECT_EQ("a", StringHelper::LTrim("a", ""));
- EXPECT_EQ("a", StringHelper::LTrim("a", "b"));
- EXPECT_EQ("a", StringHelper::LTrim("ba", "b"));
- EXPECT_EQ("f", StringHelper::LTrim("abcdef", "abcde"));
- EXPECT_EQ("cdef", StringHelper::LTrim("abcdef", "ab"));
- EXPECT_EQ("abcdef", StringHelper::LTrim("abcdef", ""));
-
- EXPECT_EQ("", StringHelper::RTrim("", ""));
- EXPECT_EQ("", StringHelper::RTrim("", "a"));
- EXPECT_EQ("", StringHelper::RTrim("a", "a"));
- EXPECT_EQ("a", StringHelper::RTrim("a", ""));
- EXPECT_EQ("a", StringHelper::RTrim("a", "b"));
- EXPECT_EQ("a", StringHelper::RTrim("ab", "b"));
- EXPECT_EQ("a", StringHelper::RTrim("abcdef", "bcdef"));
- EXPECT_EQ("abcd", StringHelper::RTrim("abcdef", "ef"));
- EXPECT_EQ("abcdef", StringHelper::RTrim("abcdef", ""));
-}
-
-TEST_F(LibHidlGenUtilsTest, TrimAll) {
- EXPECT_EQ("", StringHelper::LTrimAll("", ""));
- EXPECT_EQ("", StringHelper::LTrimAll("", "a"));
- EXPECT_EQ("", StringHelper::LTrimAll("", "ab"));
- EXPECT_EQ("", StringHelper::LTrimAll("a", "a"));
- EXPECT_EQ("", StringHelper::LTrimAll("aa", "a"));
- EXPECT_EQ("b", StringHelper::LTrimAll("b", "a"));
- EXPECT_EQ("b", StringHelper::LTrimAll("aaab", "a"));
- EXPECT_EQ("c", StringHelper::LTrimAll("ababc", "ab"));
- EXPECT_EQ("ac", StringHelper::LTrimAll("abac", "ab"));
-
- EXPECT_EQ("", StringHelper::RTrimAll("", ""));
- EXPECT_EQ("", StringHelper::RTrimAll("", "a"));
- EXPECT_EQ("", StringHelper::RTrimAll("", "ab"));
- EXPECT_EQ("", StringHelper::RTrimAll("a", "a"));
- EXPECT_EQ("", StringHelper::RTrimAll("aa", "a"));
- EXPECT_EQ("b", StringHelper::RTrimAll("b", "a"));
- EXPECT_EQ("b", StringHelper::RTrimAll("baaa", "a"));
- EXPECT_EQ("c", StringHelper::RTrimAll("cabab", "ab"));
- EXPECT_EQ("ca", StringHelper::RTrimAll("caba", "ba"));
-}
-
-TEST_F(LibHidlGenUtilsTest, SplitString) {
- std::vector<std::string> components;
-
- StringHelper::SplitString("", '.', &components);
- EXPECT_EQ(std::vector<std::string>({""}), components);
- StringHelper::SplitString("a.", '.', &components);
- EXPECT_EQ(std::vector<std::string>({"a", ""}), components);
- StringHelper::SplitString(".a", '.', &components);
- EXPECT_EQ(std::vector<std::string>({"", "a"}), components);
- StringHelper::SplitString("..", '.', &components);
- EXPECT_EQ(std::vector<std::string>({"", "", ""}), components);
- StringHelper::SplitString("asdf.asdf", '.', &components);
- EXPECT_EQ(std::vector<std::string>({"asdf", "asdf"}), components);
-}
-
-TEST_F(LibHidlGenUtilsTest, JoinStrings) {
- EXPECT_EQ("", StringHelper::JoinStrings({}, ""));
- EXPECT_EQ("", StringHelper::JoinStrings({}, "a"));
- EXPECT_EQ("a", StringHelper::JoinStrings({"a"}, ""));
- EXPECT_EQ("a,b", StringHelper::JoinStrings({"a", "b"}, ","));
- EXPECT_EQ("ab,", StringHelper::JoinStrings({"ab", ""}, ","));
- EXPECT_EQ(",ab", StringHelper::JoinStrings({"", "ab"}, ","));
- EXPECT_EQ("a.,b", StringHelper::JoinStrings({"a", "b"}, ".,"));
- EXPECT_EQ("a,b,c", StringHelper::JoinStrings({"a", "b", "c"}, ","));
- EXPECT_EQ("abc.,def.,ghi", StringHelper::JoinStrings({"abc", "def", "ghi"}, ".,"));
-}
-
TEST_F(LibHidlGenUtilsTest, FqInstance1) {
FqInstance e;
ASSERT_TRUE(e.setTo("android.hardware.foo@1.0::IFoo/instance"));
@@ -190,6 +86,36 @@
ASSERT_FALSE(e.hasInstance());
}
+TEST_F(LibHidlGenUtilsTest, FqInstanceSetToByComponent) {
+ FqInstance e;
+ ASSERT_TRUE(e.setTo("android.hardware.foo", 1, 0, "IFoo", "default"));
+ EXPECT_EQ("android.hardware.foo@1.0::IFoo/default", e.string());
+ ASSERT_TRUE(e.setTo("android.hardware.foo", 1, 0, "IFoo"));
+ EXPECT_EQ("android.hardware.foo@1.0::IFoo", e.string());
+ ASSERT_TRUE(e.setTo("android.hardware.foo", 1, 0));
+ EXPECT_EQ("android.hardware.foo@1.0", e.string());
+ ASSERT_TRUE(e.setTo(1, 0, "IFoo", "default"));
+ EXPECT_EQ("@1.0::IFoo/default", e.string());
+ ASSERT_TRUE(e.setTo(1, 0, "IFoo"));
+ EXPECT_EQ("@1.0::IFoo", e.string());
+ ASSERT_TRUE(e.setTo("IFoo", "default"));
+ EXPECT_EQ("IFoo/default", e.string());
+}
+
+TEST_F(LibHidlGenUtilsTest, FqDefaultVersion) {
+ FQName n;
+ FqInstance i;
+
+ ASSERT_TRUE(FQName::parse("IFoo.test", &n));
+ EXPECT_EQ((std::make_pair<size_t, size_t>(0u, 0u)), n.getVersion());
+ ASSERT_TRUE(i.setTo("IFoo.test"));
+ EXPECT_EQ((std::make_pair<size_t, size_t>(0u, 0u)), i.getVersion());
+ ASSERT_TRUE(FQName::parse("package@1.2::IFoo", &n));
+ EXPECT_EQ((std::make_pair<size_t, size_t>(1u, 2u)), n.getVersion());
+ ASSERT_TRUE(i.setTo("package@1.2::IFoo"));
+ EXPECT_EQ((std::make_pair<size_t, size_t>(1u, 2u)), i.getVersion());
+}
+
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
diff --git a/test/vendor/1.0/Android.bp b/test/vendor/1.0/Android.bp
index 8519fa5..4f8485b 100644
--- a/test/vendor/1.0/Android.bp
+++ b/test/vendor/1.0/Android.bp
@@ -1,5 +1,3 @@
-// This file is autogenerated by hidl-gen -Landroidbp.
-
hidl_interface {
name: "hidl.tests.vendor@1.0",
owner: "some-owner-name",
@@ -19,5 +17,8 @@
],
gen_java: true,
gen_java_constants: true,
+
+ // tests that license is copied
+ notice: "FAKE_NOTICE_FILE",
}
diff --git a/test/vendor/1.0/FAKE_NOTICE_FILE b/test/vendor/1.0/FAKE_NOTICE_FILE
new file mode 100644
index 0000000..68b43bf
--- /dev/null
+++ b/test/vendor/1.0/FAKE_NOTICE_FILE
@@ -0,0 +1 @@
+I am notifying you of something! Wheeee!
diff --git a/test/vendor/1.1/IVendor.hal b/test/vendor/1.1/IVendor.hal
index 437d79f..b574e33 100644
--- a/test/vendor/1.1/IVendor.hal
+++ b/test/vendor/1.1/IVendor.hal
@@ -23,5 +23,10 @@
import android.frameworks.displayservice@1.0;
interface IVendor extends @1.0::IVendor {
+ safe_union Test {
+ int64_t foo;
+ int32_t bar;
+ };
+
doAdditionalFunctionality();
};
diff --git a/test/vendor/Android.bp b/test/vendor/Android.bp
deleted file mode 100644
index dfcd349..0000000
--- a/test/vendor/Android.bp
+++ /dev/null
@@ -1,4 +0,0 @@
-hidl_package_root {
- name: "hidl.tests",
- path: "system/tools/hidl/test",
-}
diff --git a/update-makefiles-helper.sh b/update-makefiles-helper.sh
index 30f38a6..ff94187 100755
--- a/update-makefiles-helper.sh
+++ b/update-makefiles-helper.sh
@@ -68,6 +68,11 @@
# Where the first package root is the current one.
#
function do_makefiles_update() {
+ if ! command -v hidl-gen 1>/dev/null; then
+ echo "Cannot find hidl-gen, try lunching or making it ('m hidl-gen')?"
+ exit 1
+ fi
+
local owner=
if [[ "$1" = "-O" ]]; then
owner="$2"
diff --git a/utils/Android.bp b/utils/Android.bp
index 7d97c75..e9fd0c3 100644
--- a/utils/Android.bp
+++ b/utils/Android.bp
@@ -15,12 +15,11 @@
cc_library {
name: "libhidl-gen-utils",
host_supported: true,
+ recovery_available: true,
defaults: ["hidl-gen-defaults"],
srcs: [
"FQName.cpp",
- "Formatter.cpp",
"FqInstance.cpp",
- "StringHelper.cpp",
],
shared_libs: [
"libbase",
diff --git a/utils/FQName.cpp b/utils/FQName.cpp
index 8f56af8..efa835a 100644
--- a/utils/FQName.cpp
+++ b/utils/FQName.cpp
@@ -16,10 +16,9 @@
#include "FQName.h"
-#include "StringHelper.h"
-
#include <android-base/logging.h>
#include <android-base/parseint.h>
+#include <android-base/strings.h>
#include <iostream>
#include <regex>
#include <sstream>
@@ -31,53 +30,41 @@
namespace android {
-FQName::FQName()
- : mValid(false),
- mIsIdentifier(false) {
-}
-
-// TODO(b/73774955): delete
-FQName::FQName(const std::string &s)
- : mValid(false),
- mIsIdentifier(false) {
- (void)setTo(s);
-}
+FQName::FQName() : mIsIdentifier(false) {}
bool FQName::parse(const std::string& s, FQName* into) {
return into->setTo(s);
}
-FQName::FQName(
- const std::string &package,
- const std::string &version,
- const std::string &name,
- const std::string &valueName)
- : mValid(true),
- mIsIdentifier(false),
- mPackage(package),
- mName(name),
- mValueName(valueName) {
- CHECK(setVersion(version)) << version;
+FQName::FQName(const std::string& package, const std::string& version, const std::string& name,
+ const std::string& valueName) {
+ size_t majorVer, minorVer;
+ CHECK(parseVersion(version, &majorVer, &minorVer));
+ CHECK(setTo(package, majorVer, minorVer, name, valueName)) << string();
+}
- // Check if this is actually a valid fqName
+bool FQName::setTo(const std::string& package, size_t majorVer, size_t minorVer,
+ const std::string& name, const std::string& valueName) {
+ mPackage = package;
+ mMajor = majorVer;
+ mMinor = minorVer;
+ mName = name;
+ mValueName = valueName;
+
FQName other;
- CHECK(parse(this->string(), &other)) << this->string();
- CHECK((*this) == other) << this->string() << " " << other.string();
+ if (!parse(string(), &other)) return false;
+ if ((*this) != other) return false;
+ mIsIdentifier = other.isIdentifier();
+ return true;
}
FQName::FQName(const FQName& other)
- : mValid(other.mValid),
- mIsIdentifier(other.mIsIdentifier),
+ : mIsIdentifier(other.mIsIdentifier),
mPackage(other.mPackage),
mMajor(other.mMajor),
mMinor(other.mMinor),
mName(other.mName),
- mValueName(other.mValueName) {
-}
-
-bool FQName::isValid() const {
- return mValid;
-}
+ mValueName(other.mValueName) {}
bool FQName::isIdentifier() const {
return mIsIdentifier;
@@ -170,9 +157,7 @@
// package without version is not allowed.
CHECK(invalid || mPackage.empty() || !version().empty());
- // TODO(b/73774955): remove isValid and users
- // of old FQName constructors
- return mValid = !invalid;
+ return !invalid;
}
const std::string& FQName::package() const {
@@ -199,7 +184,6 @@
}
void FQName::clear() {
- mValid = true;
mIsIdentifier = false;
mPackage.clear();
clearVersion();
@@ -207,36 +191,47 @@
mValueName.clear();
}
-bool FQName::setVersion(const std::string& v) {
+void FQName::clearVersion(size_t* majorVer, size_t* minorVer) {
+ *majorVer = *minorVer = 0;
+}
+
+bool FQName::parseVersion(const std::string& majorStr, const std::string& minorStr,
+ size_t* majorVer, size_t* minorVer) {
+ bool versionParseSuccess = ::android::base::ParseUint(majorStr, majorVer) &&
+ ::android::base::ParseUint(minorStr, minorVer);
+ if (!versionParseSuccess) {
+ LOG(ERROR) << "numbers in " << majorStr << "." << minorStr << " are out of range.";
+ }
+ return versionParseSuccess;
+}
+
+bool FQName::parseVersion(const std::string& v, size_t* majorVer, size_t* minorVer) {
static const std::regex kREVer("(" RE_MAJOR ")[.](" RE_MINOR ")");
if (v.empty()) {
- clearVersion();
+ clearVersion(majorVer, minorVer);
return true;
}
std::smatch match;
if (!std::regex_match(v, match, kREVer)) {
- return mValid = false;
+ return false;
}
CHECK_EQ(match.size(), 3u);
- return parseVersion(match.str(1), match.str(2));
+ return parseVersion(match.str(1), match.str(2), majorVer, minorVer);
+}
+
+bool FQName::setVersion(const std::string& v) {
+ return parseVersion(v, &mMajor, &mMinor);
}
void FQName::clearVersion() {
- mMajor = mMinor = 0;
+ clearVersion(&mMajor, &mMinor);
}
bool FQName::parseVersion(const std::string& majorStr, const std::string& minorStr) {
- bool versionParseSuccess =
- ::android::base::ParseUint(majorStr, &mMajor) &&
- ::android::base::ParseUint(minorStr, &mMinor);
- if (!versionParseSuccess) {
- LOG(ERROR) << "numbers in " << majorStr << "." << minorStr << " are out of range.";
- mValid = false;
- }
- return versionParseSuccess;
+ return parseVersion(majorStr, minorStr, &mMajor, &mMinor);
}
const std::string& FQName::name() const {
@@ -278,8 +273,6 @@
}
std::string FQName::string() const {
- CHECK(mValid) << mPackage << atVersion() << mName;
-
std::string out;
out.append(mPackage);
out.append(atVersion());
@@ -380,13 +373,12 @@
getPackageAndVersionComponents(&components, true /* cpp_compatible */);
if (!mName.empty()) {
- std::vector<std::string> nameComponents;
- StringHelper::SplitString(mName, '.', &nameComponents);
+ std::vector<std::string> nameComponents = base::Split(mName, ".");
components.insert(components.end(), nameComponents.begin(), nameComponents.end());
}
- return StringHelper::JoinStrings(components, "_");
+ return base::Join(components, "_");
}
std::string FQName::cppNamespace() const {
@@ -394,26 +386,24 @@
getPackageAndVersionComponents(&components, true /* cpp_compatible */);
std::string out = "::";
- out += StringHelper::JoinStrings(components, "::");
+ out += base::Join(components, "::");
return out;
}
std::string FQName::cppLocalName() const {
- std::vector<std::string> components;
- StringHelper::SplitString(mName, '.', &components);
+ std::vector<std::string> components = base::Split(mName, ".");
- return StringHelper::JoinStrings(components, "::")
+ return base::Join(components, "::")
+ (mValueName.empty() ? "" : ("::" + mValueName));
}
std::string FQName::cppName() const {
std::string out = cppNamespace();
- std::vector<std::string> components;
- StringHelper::SplitString(name(), '.', &components);
+ std::vector<std::string> components = base::Split(name(), ".");
out += "::";
- out += StringHelper::JoinStrings(components, "::");
+ out += base::Join(components, "::");
if (!mValueName.empty()) {
out += "::" + mValueName;
}
@@ -425,7 +415,7 @@
std::vector<std::string> components;
getPackageAndVersionComponents(&components, true /* cpp_compatible */);
- return StringHelper::JoinStrings(components, ".");
+ return base::Join(components, ".");
}
std::string FQName::javaName() const {
@@ -434,7 +424,7 @@
}
void FQName::getPackageComponents(std::vector<std::string> *components) const {
- StringHelper::SplitString(package(), '.', components);
+ *components = base::Split(package(), ".");
}
void FQName::getPackageAndVersionComponents(
@@ -460,6 +450,10 @@
return mMajor > 0;
}
+std::pair<size_t, size_t> FQName::getVersion() const {
+ return {mMajor, mMinor};
+}
+
FQName FQName::withVersion(size_t major, size_t minor) const {
FQName ret(*this);
ret.mMajor = major;
@@ -519,8 +513,7 @@
std::vector<std::string> components;
getPackageComponents(&components);
- std::vector<std::string> inComponents;
- StringHelper::SplitString(package, '.', &inComponents);
+ std::vector<std::string> inComponents = base::Split(package, ".");
if (inComponents.size() > components.size()) {
return false;
diff --git a/utils/FqInstance.cpp b/utils/FqInstance.cpp
index 0b2b8f8..c0793f7 100644
--- a/utils/FqInstance.cpp
+++ b/utils/FqInstance.cpp
@@ -39,7 +39,7 @@
}
std::pair<size_t, size_t> FqInstance::getVersion() const {
- return {getMajorVersion(), getMinorVersion()};
+ return mFqName.getVersion();
}
bool FqInstance::hasVersion() const {
@@ -62,11 +62,7 @@
return !mInstance.empty();
}
-bool FqInstance::setTo(const std::string& s) {
- auto pos = s.find(INSTANCE_SEP);
- if (!mFqName.setTo(s.substr(0, pos))) return false;
- mInstance = pos == std::string::npos ? std::string{} : s.substr(pos + 1);
-
+bool FqInstance::isValid() const {
bool hasPkg = hasPackage();
bool hasVer = hasVersion();
bool hasIntf = hasInterface();
@@ -91,12 +87,19 @@
return !hasInst;
}
+bool FqInstance::setTo(const std::string& s) {
+ auto pos = s.find(INSTANCE_SEP);
+ if (!mFqName.setTo(s.substr(0, pos))) return false;
+ mInstance = pos == std::string::npos ? std::string{} : s.substr(pos + 1);
+
+ return isValid();
+}
+
bool FqInstance::setTo(const std::string& package, size_t majorVer, size_t minorVer,
const std::string& interface, const std::string& instance) {
- std::stringstream ss;
- ss << package << "@" << majorVer << "." << minorVer << "::" << interface << INSTANCE_SEP
- << instance;
- return setTo(ss.str());
+ if (!mFqName.setTo(package, majorVer, minorVer, interface)) return false;
+ mInstance = instance;
+ return isValid();
}
bool FqInstance::setTo(size_t majorVer, size_t minorVer, const std::string& interface,
@@ -105,7 +108,7 @@
}
bool FqInstance::setTo(const std::string& interface, const std::string& instance) {
- return setTo(interface + INSTANCE_SEP + instance);
+ return setTo(0u, 0u, interface, instance);
}
std::string FqInstance::string() const {
@@ -126,4 +129,8 @@
return !(*this == other);
}
+bool FqInstance::inPackage(const std::string& package) const {
+ return mFqName.inPackage(package);
+}
+
} // namespace android
diff --git a/utils/include/hidl-util/FQName.h b/utils/include/hidl-util/FQName.h
index 3e31431..416340a 100644
--- a/utils/include/hidl-util/FQName.h
+++ b/utils/include/hidl-util/FQName.h
@@ -28,19 +28,18 @@
explicit FQName();
- // TODO(b/73774955): delete
- explicit FQName(const std::string &s);
-
FQName(const std::string& package, const std::string& version, const std::string& name = "",
const std::string& valueName = "");
FQName(const FQName& other);
- bool isValid() const;
bool isIdentifier() const;
// Returns false if string isn't a valid FQName object.
__attribute__((warn_unused_result)) bool setTo(const std::string& s);
+ __attribute__((warn_unused_result)) bool setTo(const std::string& package, size_t majorVer,
+ size_t minorVer, const std::string& name = "",
+ const std::string& valueName = "");
void applyDefaults(
const std::string &defaultPackage,
@@ -55,6 +54,8 @@
std::string sanitizedVersion() const;
// Return true only if version is present.
bool hasVersion() const;
+ // Return pair of (major, minor) version. Defaults to 0, 0.
+ std::pair<size_t, size_t> getVersion() const;
FQName withVersion(size_t major, size_t minor) const;
@@ -225,9 +226,6 @@
FQName downRev() const;
private:
- // TODO(b/73774955): remove
- bool mValid;
-
bool mIsIdentifier;
std::string mPackage;
// mMajor == 0 means empty.
@@ -241,6 +239,15 @@
__attribute__((warn_unused_result)) bool setVersion(const std::string& v);
__attribute__((warn_unused_result)) bool parseVersion(const std::string& majorStr,
const std::string& minorStr);
+ __attribute__((warn_unused_result)) static bool parseVersion(const std::string& majorStr,
+ const std::string& minorStr,
+ size_t* majorVer,
+ size_t* minorVer);
+ __attribute__((warn_unused_result)) static bool parseVersion(const std::string& v,
+ size_t* majorVer,
+ size_t* minorVer);
+ static void clearVersion(size_t* majorVer, size_t* minorVer);
+
void clearVersion();
};
diff --git a/utils/include/hidl-util/FqInstance.h b/utils/include/hidl-util/FqInstance.h
index bdd0043..982bae0 100644
--- a/utils/include/hidl-util/FqInstance.h
+++ b/utils/include/hidl-util/FqInstance.h
@@ -48,6 +48,12 @@
bool hasInterface() const;
bool hasInstance() const;
+ // If this is android.hardware@1.0::IFoo
+ // package = "and" -> false
+ // package = "android" -> true
+ // package = "android.hardware@1.0" -> false
+ bool inPackage(const std::string& package) const;
+
// Return true if valid:
// android.hardware.foo@1.0::IFoo/instance
// @1.0::IFoo/instance
@@ -66,15 +72,21 @@
__attribute__((warn_unused_result)) bool setTo(const std::string& s);
// Convenience method for the following formats:
+ // android.hardware.foo@1.0
+ // android.hardware.foo@1.0::IFoo
// android.hardware.foo@1.0::IFoo/default
- // @1.0::IFoo/default
- // IFoo/default
__attribute__((warn_unused_result)) bool setTo(const std::string& package, size_t majorVer,
- size_t minorVer, const std::string& interface,
- const std::string& instance);
+ size_t minorVer,
+ const std::string& interface = "",
+ const std::string& instance = "");
+ // Convenience method for the following formats:
+ // @1.0::IFoo
+ // @1.0::IFoo/default
__attribute__((warn_unused_result)) bool setTo(size_t majorVer, size_t minorVer,
const std::string& interface,
- const std::string& instance);
+ const std::string& instance = "");
+ // Convenience method for the following formats:
+ // IFoo/default
__attribute__((warn_unused_result)) bool setTo(const std::string& interface,
const std::string& instance);
@@ -90,6 +102,9 @@
private:
FQName mFqName;
std::string mInstance;
+
+ // helper to setTo() to determine that the FqInstance is actually valid.
+ bool isValid() const;
};
} // namespace android