Merge "Update hidl-gen to generate full name for vts attributes."
diff --git a/AST.h b/AST.h
index ddba36c..f82a9ba 100644
--- a/AST.h
+++ b/AST.h
@@ -210,6 +210,7 @@
status_t generatePassthroughSource(Formatter &out) const;
+ status_t generateInterfaceSource(Formatter &out) const;
enum InstrumentationEvent {
SERVER_API_ENTRY = 0,
diff --git a/GenericBinder.cpp b/GenericBinder.cpp
index bf7f99e..170611e 100644
--- a/GenericBinder.cpp
+++ b/GenericBinder.cpp
@@ -93,7 +93,7 @@
bool isReader) const {
if (isReader) {
out << parcelObj
- << ".readStrongBinder());\n";
+ << ".readStrongBinder();\n";
} else {
out << parcelObj
<< ".writeStrongBinder("
diff --git a/Interface.cpp b/Interface.cpp
index 09959ae..d348101 100644
--- a/Interface.cpp
+++ b/Interface.cpp
@@ -131,6 +131,10 @@
return v;
}
+std::vector<const Interface *> Interface::superTypeChain() const {
+ return superType()->typeChain(); // should work even if superType is nullptr
+}
+
bool Interface::isInterface() const {
return true;
}
@@ -248,33 +252,12 @@
out.unindent();
out << "}\n\n";
} else {
+ out << "_hidl_err = "
+ << parcelObjDeref
+ << "writeStrongBinder("
+ << name
+ << "->toBinder());\n";
- out << "if (" << name << "->isRemote()) {\n";
- out.indent();
- out << "_hidl_err = ";
- out << parcelObjDeref
- << "writeStrongBinder("
- << fqName().cppNamespace()
- << "::IHw"
- << getBaseName()
- << "::asBinder(static_cast<"
- << fqName().cppNamespace()
- << "::IHw"
- << getBaseName()
- << "*>("
- << name << ".get()"
- << ")));\n";
- out.unindent();
- out << "} else {\n";
- out.indent();
- out << "_hidl_err = ";
- out << parcelObjDeref
- << "writeStrongBinder("
- << "new " << fqName().cppNamespace()
- << "::Bn" << getBaseName() << " "
- << "(" << name <<"));\n";
- out.unindent();
- out << "}\n";
handleError(out, mode);
}
}
diff --git a/Interface.h b/Interface.h
index ae7e032..135a69b 100644
--- a/Interface.h
+++ b/Interface.h
@@ -33,10 +33,14 @@
bool isInterface() const override;
bool isBinder() const override;
+ bool isRootType() const { return mSuperType == nullptr; }
const Interface *superType() const;
Method *lookupMethod(std::string name) const;
+ // Super type chain to root type.
+ // First element is superType().
+ std::vector<const Interface *> superTypeChain() const;
// Super type chain to root type, including myself.
// First element is this.
std::vector<const Interface *> typeChain() const;
diff --git a/generateCpp.cpp b/generateCpp.cpp
index 8e63349..69ded55 100644
--- a/generateCpp.cpp
+++ b/generateCpp.cpp
@@ -200,6 +200,8 @@
out.unindent();
out << "}\n\n";
out << "virtual bool isRemote() const override { return false; }\n\n";
+ out << "virtual ::android::sp<::android::hardware::IBinder> "
+ << "toBinder() override;\n\n";
bool haveCallbacks = false;
for (const auto &method : iface->methods()) {
const bool returnsValue = !method->results().empty();
@@ -266,6 +268,24 @@
}
}
+ if (!iface->isRootType()) {
+ out << "// cast static functions\n";
+ std::string childTypeExtra;
+ std::string childTypeResult = iface->getCppResultType(&childTypeExtra);
+ childTypeResult += childTypeExtra;
+
+ for (const Interface *superType : iface->superTypeChain()) {
+ std::string superTypeExtra;
+ out << "static "
+ << childTypeResult
+ << " castFrom("
+ << superType->getCppArgumentType(&superTypeExtra)
+ << " parent"
+ << superTypeExtra
+ << ");\n";
+ }
+ }
+
out << "\nstatic const ::android::String16 descriptor;\n\n";
out << "DECLARE_REGISTER_AND_GET_SERVICE(" << baseName << ")\n";
@@ -752,13 +772,15 @@
std::string ifaceName;
std::string baseName;
- bool isInterface = true;
+ const Interface *iface = nullptr;
+ bool isInterface;
if (!AST::isInterface(&ifaceName)) {
baseName = "types";
isInterface = false;
} else {
- const Interface *iface = mRootScope->getInterface();
+ iface = mRootScope->getInterface();
baseName = iface->getBaseName();
+ isInterface = true;
}
path.append(baseName);
@@ -792,6 +814,17 @@
out << "#include <" << prefix << "/Bp" << baseName << ".h>\n";
out << "#include <" << prefix << "/Bn" << baseName << ".h>\n";
out << "#include <" << prefix << "/Bs" << baseName << ".h>\n";
+
+ for (const Interface *superType : iface->superTypeChain()) {
+ std::vector<std::string> superPackageComponents;
+ superType->fqName().getPackageAndVersionComponents(&superPackageComponents, false /* cpp_compatible */);
+ std::string superPrefix;
+ for (const auto &component : superPackageComponents) {
+ superPrefix += component;
+ superPrefix += "/";
+ }
+ out << "#include <" << superPrefix << "/Bp" << superType->getBaseName() << ".h>\n";
+ }
} else {
out << "#include <" << prefix << "types.h>\n";
}
@@ -814,6 +847,10 @@
<< iface->fqName().string()
<< "\");\n\n";
+ err = generateInterfaceSource(out);
+ }
+
+ if (err == OK && isInterface) {
err = generateProxySource(out, baseName);
}
@@ -1520,7 +1557,7 @@
out << ifaceName << ".h>\n\n";
if (supportOneway) {
- out << "#include <hidl/SynchronizedQueue.h>\n";
+ out << "#include <hidl/TaskRunner.h>\n";
}
enterLeaveNamespace(out, true /* enter */);
@@ -1553,15 +1590,12 @@
out << "const sp<" << ifaceName << "> mImpl;\n";
if (supportOneway) {
- out << "SynchronizedQueue<std::function<void(void)>> mOnewayQueue;\n";
- out << "std::thread *mOnewayThread = nullptr;\n";
+ out << "::android::hardware::TaskRunner mOnewayQueue;\n";
out << "\n";
out << "::android::hardware::Return<void> addOnewayTask("
"std::function<void(void)>);\n\n";
-
- out << "static const int kOnewayQueueMaxSize = 3000;\n";
}
out.unindent();
@@ -1575,6 +1609,68 @@
return OK;
}
+status_t AST::generateInterfaceSource(Formatter &out) const {
+ const Interface *iface = mRootScope->getInterface();
+
+
+ // generate toBinder functions
+ out << "::android::sp<::android::hardware::IBinder> I"
+ << iface->getBaseName()
+ << "::toBinder() {\n";
+ out.indent();
+ out << "if (isRemote()) {\n";
+ out.indent();
+ out << "return ::android::hardware::IInterface::asBinder("
+ << "static_cast<IHw"
+ << iface->getBaseName()
+ << " *>(this));\n";
+ out.unindent();
+ out << "} else {\n";
+ out.indent();
+ out << "return new Bn" << iface->getBaseName() << "(this);\n";
+ out.unindent();
+ out << "}\n";
+ out.unindent();
+ out << "}\n\n";
+
+ // generate castFrom functions
+ if (!iface->isRootType()) {
+ std::string childTypeExtra;
+ std::string childTypeResult = iface->getCppResultType(&childTypeExtra);
+ childTypeResult += childTypeExtra;
+
+ for (const Interface *superType : iface->superTypeChain()) {
+ std::string superTypeExtra;
+ out << "// static \n"
+ << childTypeResult
+ << " I"
+ << iface->getBaseName()
+ << "::castFrom("
+ << superType->getCppArgumentType(&superTypeExtra)
+ << " parent"
+ << superTypeExtra
+ << ")";
+ out << " {\n";
+ out.indent();
+ out << "return ::android::hardware::castInterface<";
+ out << "I" << iface->getBaseName() << ", "
+ << superType->fqName().cppName() << ", "
+ << "Bp" << iface->getBaseName()
+ << ">(\n";
+ out.indent();
+ out.indent();
+ out << "parent, \""
+ << iface->fqName().string()
+ << "\");\n";
+ out.unindent();
+ out.unindent();
+ out.unindent();
+ out << "}\n\n";
+ }
+ }
+
+ return OK;
+}
status_t AST::generatePassthroughSource(Formatter &out) const {
const Interface *iface = mRootScope->getInterface();
@@ -1587,24 +1683,21 @@
<< klassName
<< "(const sp<"
<< iface->fullName()
- << "> impl) : mImpl(impl) {}\n\n";
+ << "> impl) : mImpl(impl) {";
+ if (iface->hasOnewayMethods()) {
+ out << "\n";
+ out.indentBlock([&] {
+ out << "mOnewayQueue.setLimit(3000 /* similar limit to binderized */);\n";
+ });
+ }
+ out << "}\n\n";
if (iface->hasOnewayMethods()) {
out << "::android::hardware::Return<void> "
<< klassName
<< "::addOnewayTask(std::function<void(void)> fun) {\n";
out.indent();
- out << "if (mOnewayThread == nullptr) {\n";
- out.indent();
- out << "mOnewayThread = new std::thread([this]() {\n";
- out.indent();
- out << "while(true) { (this->mOnewayQueue.wait_pop())(); }";
- out.unindent();
- out << "});\n";
- out.unindent();
- out << "}\n\n";
-
- out << "if (mOnewayQueue.size() > kOnewayQueueMaxSize) {\n";
+ out << "if (!mOnewayQueue.push(fun)) {\n";
out.indent();
out << "return ::android::hardware::Status::fromExceptionCode(\n";
out.indent();
@@ -1613,10 +1706,6 @@
out.unindent();
out.unindent();
out.unindent();
- out << "} else {\n";
- out.indent();
- out << "mOnewayQueue.push(fun);\n";
- out.unindent();
out << "}\n";
out << "return ::android::hardware::Status();\n";
diff --git a/test/Android.bp b/test/Android.bp
index 77c47f1..d01f152 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -15,6 +15,7 @@
"libutils",
"android.hardware.tests.foo@1.0",
"android.hardware.tests.bar@1.0",
+ "android.hardware.tests.inheritance@1.0",
"android.hardware.tests.pointer@1.0",
],
static_libs: ["libgtest"],
@@ -27,6 +28,7 @@
// included on a device.mk).
"android.hardware.tests.foo@1.0-impl",
"android.hardware.tests.bar@1.0-impl",
+ "android.hardware.tests.inheritance@1.0-impl",
"android.hardware.tests.pointer@1.0-impl",
],
diff --git a/test/java_test/Android.mk b/test/java_test/Android.mk
index 97a95ec..233030a 100644
--- a/test/java_test/Android.mk
+++ b/test/java_test/Android.mk
@@ -7,7 +7,8 @@
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_JAVA_LIBRARIES := \
android.hardware.tests.baz@1.0-java \
- android.hardware.tests.expression@1.0-java
+ android.hardware.tests.expression@1.0-java \
+ android.hardware.tests.inheritance@1.0-java
include $(BUILD_JAVA_LIBRARY)
@@ -38,7 +39,8 @@
libhwbinder \
libutils \
android.hardware.tests.baz@1.0 \
- android.hardware.tests.expression@1.0
+ android.hardware.tests.expression@1.0 \
+ android.hardware.tests.inheritance@1.0
LOCAL_STATIC_LIBRARIES := \
libgtest
diff --git a/test/main.cpp b/test/main.cpp
index 1032811..50bada6 100644
--- a/test/main.cpp
+++ b/test/main.cpp
@@ -4,6 +4,10 @@
#include <android/hardware/tests/foo/1.0/BnFoo.h>
#include <android/hardware/tests/foo/1.0/BnFooCallback.h>
#include <android/hardware/tests/bar/1.0/BnBar.h>
+#include <android/hardware/tests/inheritance/1.0/BnFetcher.h>
+#include <android/hardware/tests/inheritance/1.0/BnGrandparent.h>
+#include <android/hardware/tests/inheritance/1.0/BnParent.h>
+#include <android/hardware/tests/inheritance/1.0/BnChild.h>
#include <android/hardware/tests/pointer/1.0/BnGraph.h>
#include <android/hardware/tests/pointer/1.0/BnPointer.h>
@@ -36,7 +40,7 @@
#define EXPECT_OK(__ret__) EXPECT_TRUE(isOk(__ret__))
#define EXPECT_FAIL(__ret__) EXPECT_FALSE(isOk(__ret__))
-#define EXPECT_ARRAYEQ(__a1__, __a2__, __size__) EXPECT_TRUE(IsArrayEq(__a1__, __a2__, __size__))
+#define EXPECT_ARRAYEQ(__a1__, __a2__, __size__) EXPECT_TRUE(isArrayEqual(__a1__, __a2__, __size__))
// TODO uncomment this when kernel is patched with pointer changes.
//#define HIDL_RUN_POINTER_TESTS 1
@@ -62,6 +66,10 @@
using ::android::hardware::tests::foo::V1_0::ISimple;
using ::android::hardware::tests::bar::V1_0::IBar;
using ::android::hardware::tests::bar::V1_0::IHwBar;
+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::IPCThreadState;
@@ -159,7 +167,13 @@
}
class HidlEnvironmentBase : public ::testing::Environment {
+protected:
+ std::vector<pid_t> mPids;
+ const char * const serverNames[6] = {
+ "Child", "Fetcher", "Bar", "FooCallback", "Graph", "Pointer"
+ };
public:
+ sp<IFetcher> fetcher;
sp<IFoo> foo;
sp<IBar> bar;
sp<IFooCallback> fooCb;
@@ -170,6 +184,11 @@
void getServices() {
// getStub is true if we are in passthrough mode to skip checking
// binderized server, false for binderized mode.
+
+ fetcher = IFetcher::getService("fetcher", gMode == PASSTHROUGH /* getStub */);
+ ASSERT_NE(fetcher, nullptr);
+ ASSERT_EQ(fetcher->isRemote(), gMode == BINDERIZED);
+
foo = IFoo::getService("foo", gMode == PASSTHROUGH /* getStub */);
ASSERT_NE(foo, nullptr);
ASSERT_EQ(foo->isRemote(), gMode == BINDERIZED);
@@ -194,52 +213,55 @@
validationPointerInterface = IPointer::getService("pointer", true /* getStub */);
ASSERT_NE(validationPointerInterface, nullptr);
}
+
+ virtual void TearDown() {
+ // clean up by killing server processes.
+ ALOGI("Environment tear-down beginning...");
+ ALOGI("Killing servers...");
+ size_t i = 0;
+ for (pid_t pid : mPids) {
+ killServer(pid, serverNames[i++]);
+ }
+ ALOGI("Servers all killed.");
+ ALOGI("Environment tear-down complete.");
+ }
};
class PassthroughEnvironment : public HidlEnvironmentBase {
private:
- pid_t fooCallbackServerPid, barServerPid, graphServerPid, pointerServerPid;
-
virtual void SetUp() {
ALOGI("Environment setup beginning...");
+ // starts this even for passthrough mode.
+ // this is used in Bar's default implementation
+ mPids.push_back(forkServer<IChild>("child", serverNames[0]));
+ sleep(1);
getServices();
ALOGI("Environment setup complete.");
}
};
class BinderizedEnvironment : public HidlEnvironmentBase {
-private:
- pid_t fooCallbackServerPid, barServerPid, graphServerPid, pointerServerPid;
public:
virtual void SetUp() {
ALOGI("Environment setup beginning...");
- barServerPid = forkServer<IBar>("foo", "Bar");
- fooCallbackServerPid = forkServer<IFooCallback>("foo callback", "FooCallback");
- graphServerPid = forkServer<IGraph>("graph", "Graph");
- pointerServerPid = forkServer<IPointer>("pointer", "Pointer");
+ size_t i = 0;
+ mPids.push_back(forkServer<IChild>("child", serverNames[i++]));
+ mPids.push_back(forkServer<IFetcher>("fetcher", serverNames[i++]));
+ mPids.push_back(forkServer<IBar>("foo", serverNames[i++]));
+ mPids.push_back(forkServer<IFooCallback>("foo callback", serverNames[i++]));
+ mPids.push_back(forkServer<IGraph>("graph", serverNames[i++]));
+ mPids.push_back(forkServer<IPointer>("pointer", serverNames[i++]));
sleep(1);
-
getServices();
ALOGI("Environment setup complete.");
}
-
- virtual void TearDown() {
- // clean up by killing server processes.
- ALOGI("Environment tear-down beginning...");
- ALOGI("Killing servers...");
- killServer(barServerPid, "barServer");
- killServer(fooCallbackServerPid, "fooCallbackServer");
- killServer(graphServerPid, "graphServer");
- killServer(pointerServerPid, "pointerServer");
- ALOGI("Servers all killed.");
- ALOGI("Environment tear-down complete.");
- }
};
class HidlTest : public ::testing::Test {
public:
+ sp<IFetcher> fetcher;
sp<IFoo> foo;
sp<IBar> bar;
sp<IFooCallback> fooCb;
@@ -255,6 +277,7 @@
} else {
env = gPassthroughEnvironment;
}
+ fetcher = env->fetcher;
foo = env->foo;
bar = env->bar;
fooCb = env->fooCb;
@@ -683,6 +706,33 @@
}));
}
+TEST_F(HidlTest, FooStructEmbeddedHandleTest) {
+ EXPECT_OK(foo->createMyHandle([&](const auto &myHandle) {
+ EXPECT_EQ(myHandle.guard, 666);
+ EXPECT_EQ(myHandle.h->numInts, 10);
+ EXPECT_EQ(myHandle.h->numFds, 0);
+ int data[] = {2,3,5,7,11,13,17,19,21,23};
+ EXPECT_ARRAYEQ(myHandle.h->data, data, 10);
+ }));
+
+ EXPECT_OK(foo->closeHandles());
+}
+
+TEST_F(HidlTest, FooHandleVecTest) {
+ EXPECT_OK(foo->createHandles(3, [&](const auto &handles) {
+ EXPECT_EQ(handles.size(), 3ull);
+ int data[] = {2,3,5,7,11,13,17,19,21,23};
+ for (size_t i = 0; i < 3; i++) {
+ const native_handle_t *h = handles[i];
+ EXPECT_EQ(h->numInts, 10) << " for element " << i;
+ EXPECT_EQ(h->numFds, 0) << " for element " << i;
+ EXPECT_ARRAYEQ(h->data, data, 10);
+ }
+ }));
+
+ EXPECT_OK(foo->closeHandles());
+}
+
TEST_F(HidlTest, BarThisIsNewTest) {
// Now the tricky part, get access to the derived interface.
ALOGI("CLIENT call thisIsNew.");
@@ -690,6 +740,64 @@
ALOGI("CLIENT thisIsNew returned.");
}
+static void expectGoodChild(const sp<IChild> &child) {
+ ASSERT_NE(child.get(), nullptr);
+ EXPECT_OK(child->doGrandparent());
+ EXPECT_OK(child->doParent());
+ EXPECT_OK(child->doChild());
+}
+
+static void expectGoodParent(const sp<IParent> &parent) {
+ ASSERT_NE(parent.get(), nullptr);
+ EXPECT_OK(parent->doGrandparent());
+ EXPECT_OK(parent->doParent());
+ sp<IChild> child = IChild::castFrom(parent);
+ expectGoodChild(child);
+}
+
+static void expectGoodGrandparent(const sp<IGrandparent> &grandparent) {
+ ASSERT_NE(grandparent.get(), nullptr);
+ EXPECT_OK(grandparent->doGrandparent());
+ sp<IParent> parent = IParent::castFrom(grandparent);
+ expectGoodParent(parent);
+}
+
+TEST_F(HidlTest, InheritRemoteGrandparentTest) {
+ EXPECT_OK(fetcher->getGrandparent(true, [&](const sp<IGrandparent>& grandparent) {
+ expectGoodGrandparent(grandparent);
+ }));
+}
+
+TEST_F(HidlTest, InheritLocalGrandparentTest) {
+ EXPECT_OK(fetcher->getGrandparent(false, [&](const sp<IGrandparent>& grandparent) {
+ expectGoodGrandparent(grandparent);
+ }));
+}
+
+TEST_F(HidlTest, BarRemoteParentTest) {
+ EXPECT_OK(fetcher->getParent(true, [&](const sp<IParent>& parent) {
+ expectGoodParent(parent);
+ }));
+}
+
+TEST_F(HidlTest, BarLocalParentTest) {
+ EXPECT_OK(fetcher->getParent(false, [&](const sp<IParent>& parent) {
+ expectGoodParent(parent);
+ }));
+}
+
+TEST_F(HidlTest, InheritRemoteChildTest) {
+ EXPECT_OK(fetcher->getChild(true, [&](const sp<IChild>& child) {
+ expectGoodChild(child);
+ }));
+}
+
+TEST_F(HidlTest, InheritLocalChildTest) {
+ EXPECT_OK(fetcher->getChild(false, [&](const sp<IChild>& child) {
+ expectGoodChild(child);
+ }));
+}
+
TEST_F(HidlTest, TestArrayDimensionality) {
hidl_array<int, 2> oneDim;
hidl_array<int, 2, 3> twoDim;