Merge "Add lint for compound types containing < 2 fields"
diff --git a/generateCpp.cpp b/generateCpp.cpp
index b160a11..cf8381e 100644
--- a/generateCpp.cpp
+++ b/generateCpp.cpp
@@ -1369,11 +1369,6 @@
 
         out.indent();
 
-        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();
-
         generateStubSourceForMethod(out, method, superInterface);
 
         out.unindent();
diff --git a/generateJava.cpp b/generateJava.cpp
index 577caf9..b0b002e 100644
--- a/generateJava.cpp
+++ b/generateJava.cpp
@@ -508,15 +508,6 @@
 
         out.indent();
 
-        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";
-            out << "_hidl_reply.send();\n";
-            out << "break;\n";
-        });
-
         if (method->isHidlReserved() && method->overridesJavaImpl(IMPL_STUB)) {
             method->javaImpl(IMPL_STUB, out);
             out.unindent();
diff --git a/test/hidl_test/hidl_test_client.cpp b/test/hidl_test/hidl_test_client.cpp
index 23b5f08..ac28d22 100644
--- a/test/hidl_test/hidl_test_client.cpp
+++ b/test/hidl_test/hidl_test_client.cpp
@@ -19,6 +19,7 @@
 #include <android/hardware/tests/bar/1.0/IBar.h>
 #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/BnHwBaz.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>
@@ -715,13 +716,6 @@
         [](const hidl_vec<hidl_string>& registered) { ASSERT_EQ(0, registered.size()); }));
 }
 
-TEST_F(HidlTest, RegisterSameInterfaceRepeatedly) {
-    for (size_t i = 0; i < 1000; i++) {
-        sp<IChild> child = new SimpleChild();
-        EXPECT_EQ(::android::OK, child->registerAsService());
-    }
-}
-
 TEST_F(HidlTest, SubInterfaceServiceRegistrationTest) {
     using ::android::hardware::interfacesEqual;
 
@@ -1882,6 +1876,58 @@
     EXPECT_OK(bar->thisIsNew());
 }
 
+TEST_F(HidlTest, TwowayMethodOnewayEnabledTest) {
+    using ::android::hardware::IBinder;
+    using ::android::hardware::Parcel;
+    using ::android::hardware::tests::baz::V1_0::BnHwBaz;
+
+    sp<IBinder> binder = ::android::hardware::toBinder(baz);
+
+    Parcel request, reply;
+    EXPECT_EQ(::android::OK, request.writeInterfaceToken(IBaz::descriptor));
+    EXPECT_EQ(::android::OK, request.writeInt64(1234));
+    // IBaz::doThatAndReturnSomething is two-way but we call it using FLAG_ONEWAY.
+    EXPECT_EQ(::android::OK, binder->transact(18 /*doThatAndReturnSomething*/, request, &reply,
+                                              IBinder::FLAG_ONEWAY));
+
+    ::android::hardware::Status status;
+    ::android::status_t readFromParcelStatus = ::android::hardware::readFromParcel(&status, reply);
+    if (mode == BINDERIZED) {
+        EXPECT_EQ(::android::NOT_ENOUGH_DATA, readFromParcelStatus);
+        EXPECT_EQ(::android::hardware::Status::EX_TRANSACTION_FAILED, status.exceptionCode());
+    } else {
+        EXPECT_EQ(666, reply.readInt32());
+    }
+
+    EXPECT_OK(baz->ping());  // still works
+}
+
+TEST_F(HidlTest, OnewayMethodOnewayDisabledTest) {
+    using ::android::hardware::IBinder;
+    using ::android::hardware::Parcel;
+    using ::android::hardware::tests::baz::V1_0::BnHwBaz;
+
+    sp<IBinder> binder = ::android::hardware::toBinder(baz);
+
+    Parcel request, reply;
+    EXPECT_EQ(::android::OK, request.writeInterfaceToken(IBaz::descriptor));
+    EXPECT_EQ(::android::OK, request.writeFloat(1.0f));
+    nsecs_t now = systemTime();
+    // IBaz::doThis is oneway but we call it without using FLAG_ONEWAY.
+    EXPECT_EQ(
+            // Expect OK because IPCThreadState::executeCommand for BR_TRANSACTION
+            // sends an empty reply for two-way transactions if the transaction itself
+            // did not send a reply.
+            ::android::OK,
+            binder->transact(17 /*doThis*/, request, &reply, 0 /* Not FLAG_ONEWAY */));
+    if (gHidlEnvironment->enableDelayMeasurementTests) {
+        // IBaz::doThis is oneway, should return instantly.
+        EXPECT_LT(systemTime() - now, ONEWAY_TOLERANCE_NS);
+    }
+
+    EXPECT_OK(baz->ping());  // still works
+}
+
 TEST_F(HidlTest, TrieSimpleTest) {
     trieInterface->newTrie([&](const TrieNode& trie) {
         trieInterface->addStrings(trie, {"a", "ba"}, [&](const TrieNode& trie) {
diff --git a/test/java_test/hidl_test_java_native.cpp b/test/java_test/hidl_test_java_native.cpp
index a7467d7..0fdc097 100644
--- a/test/java_test/hidl_test_java_native.cpp
+++ b/test/java_test/hidl_test_java_native.cpp
@@ -632,6 +632,46 @@
                 in, [&](const auto &out) { EXPECT_EQ(in, out); }));
 }
 
+TEST_F(HidlTest, TwowayMethodOnewayEnabledTest) {
+    using ::android::hardware::IBinder;
+    using ::android::hardware::Parcel;
+
+    sp<IBinder> binder = ::android::hardware::toBinder(baz);
+
+    Parcel request, reply;
+    EXPECT_EQ(::android::OK, request.writeInterfaceToken(IBaz::descriptor));
+    EXPECT_EQ(::android::OK, request.writeInt64(1234));
+    // IBaz::doThatAndReturnSomething is two-way but we call it using FLAG_ONEWAY.
+    EXPECT_EQ(::android::OK, binder->transact(18 /*doThatAndReturnSomething*/, request, &reply,
+                                              IBinder::FLAG_ONEWAY));
+
+    ::android::hardware::Status status;
+    EXPECT_EQ(::android::NOT_ENOUGH_DATA, ::android::hardware::readFromParcel(&status, reply));
+    EXPECT_EQ(::android::hardware::Status::EX_TRANSACTION_FAILED, status.exceptionCode());
+
+    EXPECT_OK(baz->ping());  // still works
+}
+
+TEST_F(HidlTest, OnewayMethodOnewayDisabledTest) {
+    using ::android::hardware::IBinder;
+    using ::android::hardware::Parcel;
+
+    sp<IBinder> binder = ::android::hardware::toBinder(baz);
+
+    Parcel request, reply;
+    EXPECT_EQ(::android::OK, request.writeInterfaceToken(IBaz::descriptor));
+    EXPECT_EQ(::android::OK, request.writeFloat(1.0f));
+    // IBaz::doThis is oneway but we call it without using FLAG_ONEWAY.
+    EXPECT_EQ(
+            // Expect UNKNOWN_ERROR because the JNI class JHwBinder always sets
+            // the reply to UNKNOWN_ERROR for two-way transactions if the
+            // transaction itself did not send a reply.
+            ::android::UNKNOWN_ERROR,
+            binder->transact(17 /*doThis*/, request, &reply, 0 /* Not FLAG_ONEWAY */));
+
+    EXPECT_OK(baz->ping());  // still works
+}
+
 TEST_F(HidlTest, SafeUnionNoInitTest) {
     EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& safeUnion) {
         EXPECT_EQ(LargeSafeUnion::hidl_discriminator::noinit, safeUnion.getDiscriminator());
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 0f1394c..0e278d9 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
@@ -30,6 +30,9 @@
 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.HwParcel;
+import android.os.IBinder;
+import android.os.IHwBinder;
 import android.os.NativeHandle;
 import android.os.RemoteException;
 import android.os.HidlSupport;
@@ -577,6 +580,46 @@
         }
 
         {
+            // Tests calling a two-way method with oneway enabled.
+            IHwBinder binder = proxy.asBinder();
+            HwParcel request = new HwParcel();
+            HwParcel reply = new HwParcel();
+
+            request.writeInterfaceToken(IBaz.kInterfaceName);
+            request.writeInt64(1234);
+            // IBaz::doThatAndReturnSomething is not oneway but we call it using FLAG_ONEWAY.
+            binder.transact(18 /*doThatAndReturnSomething*/, request, reply, IBinder.FLAG_ONEWAY);
+
+            try {
+                reply.verifySuccess();
+                // This should never run.
+                ExpectTrue(false);
+            } catch (Exception e) {
+                ExpectTrue(e instanceof RemoteException);
+            }
+
+            proxy.ping();
+        }
+
+        {
+            // Tests calling a oneway method with oneway disabled.
+            IHwBinder binder = proxy.asBinder();
+            HwParcel request = new HwParcel();
+            HwParcel reply = new HwParcel();
+
+            request.writeInterfaceToken(IBaz.kInterfaceName);
+            request.writeFloat(1.0f);
+            // IBaz::doThis is oneway but we call it without using FLAG_ONEWAY.
+            // This does not raise an exception because
+            // IPCThreadState::executeCommand for BR_TRANSACTION sends an empty
+            // reply for two-way transactions if the transaction itself did not
+            // send a reply.
+            binder.transact(17 /*doThis*/, request, reply, 0 /* Not FLAG_ONEWAY */);
+
+            proxy.ping();
+        }
+
+        {
             IBase.Foo foo = new IBase.Foo();
             foo.x = 1;