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;