Merge "Fix update-makefile-helpers."
diff --git a/CompoundType.cpp b/CompoundType.cpp
index 332bada..19b1896 100644
--- a/CompoundType.cpp
+++ b/CompoundType.cpp
@@ -582,15 +582,15 @@
             out.sIf("otherObject == null", [&] {
                 out << "return false;\n";
             }).endl();
-            // Class is final, so we only need to check instanceof, not getClass
-            out.sIf("!(otherObject instanceof " + fullJavaName() + ")", [&] {
+            // Though class is final, we use getClass instead of instanceof to be explicit.
+            out.sIf("otherObject.getClass() != " + fullJavaName() + ".class", [&] {
                 out << "return false;\n";
             }).endl();
             out << fullJavaName() << " other = (" << fullJavaName() << ")otherObject;\n";
             for (const auto &field : *mFields) {
-                std::string condition = field->type().isScalar()
+                std::string condition = (field->type().isScalar() || field->type().isEnum())
                     ? "this." + field->name() + " != other." + field->name()
-                    : ("!java.util.Objects.deepEquals(this." + field->name()
+                    : ("!android.os.HidlSupport.deepEquals(this." + field->name()
                             + ", other." + field->name() + ")");
                 out.sIf(condition, [&] {
                     out << "return false;\n";
@@ -609,17 +609,7 @@
                         out << ", \n";
                     }
                     first = false;
-                    if (field->type().isArray()) {
-                        const ArrayType &type = static_cast<const ArrayType &>(field->type());
-                        if (type.countDimensions() == 1 &&
-                            type.getElementType()->resolveToScalarType() != nullptr) {
-                            out << "java.util.Arrays.hashCode(this." << field->name() << ")";
-                        } else {
-                            out << "java.util.Arrays.deepHashCode(this." << field->name() << ")";
-                        }
-                    } else {
-                        out << "this." << field->name();
-                    }
+                    out << "android.os.HidlSupport.deepHashCode(this." << field->name() << ")";
                 }
             });
             out << ");\n";
diff --git a/generateCpp.cpp b/generateCpp.cpp
index 178b705..a89a567 100644
--- a/generateCpp.cpp
+++ b/generateCpp.cpp
@@ -187,13 +187,8 @@
         //     }
         // }
 
-        out.sFor("bool tried = false; "
-                 "!getStub && (vintfHwbinder || (vintfEmpty && !tried)); "
-                 "tried = true", [&] {
-
-            // Because this is a for loop, a "continue" statement means
-            // setting tried, and hence "break" for vintfEmpty and
-            // "retry" for vintfHwBinder
+        out << "bool tried = false;\n";
+        out.sWhile("!getStub && (vintfHwbinder || (vintfEmpty && !tried))", [&] {
 
             out.sIf("tried", [&] {
                 // sleep only after the first trial.
@@ -201,6 +196,8 @@
                     << "sleep(1);\n";
             }).endl();
 
+            out << "tried = true;\n";
+
             out << "const ::android::sp<::android::hidl::manager::V1_0::IServiceManager> sm\n";
             out.indent(2, [&] {
                 out << "= ::android::hardware::defaultServiceManager();\n";
@@ -225,10 +222,10 @@
             });
 
             out.sIf("!ret.isOk()", [&] {
-                // hwservicemanager fails
+                // hwservicemanager fails, may be security issue
                 out << "ALOGE(\"getService: defaultServiceManager()->get returns %s\", "
                     << "ret.description().c_str());\n"
-                    << "continue;\n";
+                    << "break;\n";
             }).endl();
 
             out << "iface = " << interfaceName << "::castFrom(ret);\n";
diff --git a/generateJava.cpp b/generateJava.cpp
index 36cef4e..3d6e781 100644
--- a/generateJava.cpp
+++ b/generateJava.cpp
@@ -139,8 +139,6 @@
 
     out << "package " << mPackage.javaPackage() << ";\n\n";
 
-    out << "import android.os.RemoteException;\n\n";
-
     out.setNamespace(mPackage.javaPackage() + ".");
 
     const Interface *superType = iface->superType();
@@ -199,7 +197,7 @@
 
     out << "public static "
         << ifaceName
-        << " getService(String serviceName) throws RemoteException {\n";
+        << " getService(String serviceName) throws android.os.RemoteException {\n";
 
     out.indent();
 
@@ -215,7 +213,7 @@
 
     out << "public static "
         << ifaceName
-        << " getService() throws RemoteException {\n";
+        << " getService() throws android.os.RemoteException {\n";
 
     out.indent();
 
@@ -280,7 +278,7 @@
 
         out << ")\n";
         out.indent();
-        out << "throws RemoteException;\n";
+        out << "throws android.os.RemoteException;\n";
         out.unindent();
     }
 
@@ -308,7 +306,7 @@
     out.block([&] {
         out.sTry([&] {
             out << "return this.interfaceDescriptor() + \"@Proxy\";\n";
-        }).sCatch("RemoteException ex", [&] {
+        }).sCatch("android.os.RemoteException ex", [&] {
             out << "/* ignored; handled below. */\n";
         }).endl();
         out << "return \"[class or subclass of \" + "
@@ -357,7 +355,7 @@
         out << ")\n";
         out.indent();
         out.indent();
-        out << "throws RemoteException {\n";
+        out << "throws android.os.RemoteException {\n";
         out.unindent();
 
         if (method->isHidlReserved() && method->overridesJavaImpl(IMPL_PROXY)) {
@@ -497,7 +495,7 @@
     out.unindent();
     out << "}\n\n";
 
-    out << "public void registerAsService(String serviceName) throws RemoteException {\n";
+    out << "public void registerAsService(String serviceName) throws android.os.RemoteException {\n";
     out.indent();
 
     out << "registerService(serviceName);\n";
@@ -518,7 +516,7 @@
         << "int _hidl_flags)\n";
     out.indent();
     out.indent();
-    out << "throws RemoteException {\n";
+    out << "throws android.os.RemoteException {\n";
     out.unindent();
 
     out << "switch (_hidl_code) {\n";
diff --git a/main.cpp b/main.cpp
index bdecb4c..95cebc3 100644
--- a/main.cpp
+++ b/main.cpp
@@ -761,6 +761,8 @@
                     out << "\"" << pathPrefix << fqName.getInterfaceStubName() << ".h\",\n";
                     out << "\"" << pathPrefix << fqName.getInterfaceProxyName() << ".h\",\n";
                     out << "\"" << pathPrefix << fqName.getInterfacePassthroughName() << ".h\",\n";
+                } else {
+                    out << "\"" << pathPrefix << "hwtypes.h\",\n";
                 }
             });
 
diff --git a/test/Android.mk b/test/Android.mk
index 61a13f1..9e88602 100644
--- a/test/Android.mk
+++ b/test/Android.mk
@@ -15,6 +15,13 @@
 #
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
+LOCAL_MODULE := hidl_test_helper
+LOCAL_MODULE_CLASS := NATIVE_TESTS
+LOCAL_SRC_FILES := hidl_test_helper
+
+include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
 LOCAL_MODULE := hidl_test
 LOCAL_MODULE_CLASS := NATIVE_TESTS
 LOCAL_SRC_FILES := hidl_test
@@ -22,7 +29,8 @@
     hidl_test_client                            \
     hidl_test_servers                           \
     hidl_test_client_32                         \
-    hidl_test_servers_32
+    hidl_test_servers_32                        \
+    hidl_test_helper
 
 include $(BUILD_PREBUILT)
 
diff --git a/test/hidl_test b/test/hidl_test
index a91acae..53f4828 100644
--- a/test/hidl_test
+++ b/test/hidl_test
@@ -1,95 +1,9 @@
-CLIENT_PATH64='/data/nativetest64/hidl_test_client/hidl_test_client'
-CLIENT_PATH32='/data/nativetest/hidl_test_client/hidl_test_client'
-SERVER_PATH64='/data/nativetest64/hidl_test_servers/hidl_test_servers'
-SERVER_PATH32='/data/nativetest/hidl_test_servers/hidl_test_servers'
+source /data/nativetest64/hidl_test_helper
 
-function usage() {
-    echo "runs hidl_test"
-    echo "\t -h help"
-    echo "\t -c [CLIENT64_SERVER64 | CLIENT32_SERVER32 | CLIENT64_SERVER32 | CLIENT32_SERVER64] configures whether to run 32-bit or 64-bit versions of the servers and client"
-}
-
-failed_test_cases=()
-
-function run_test() {
-    if [ $1 -eq 32 ]; then
-        CLIENT_PATH=$CLIENT_PATH32
-    else
-        CLIENT_PATH=$CLIENT_PATH64
-    fi
-
-    if [ $2 -eq 32 ]; then
-        SERVER_PATH=$SERVER_PATH32
-    else
-        SERVER_PATH=$SERVER_PATH64
-    fi
-
-    echo "Running $1-bit client with $2-bit servers"
-    $SERVER_PATH &
-    sleep 1
-    SERVER_PID=$!
-    $CLIENT_PATH
-    if [ $? -ne 0 ]; then
-        failed_test_cases+=("$1-bit client with $2-bit servers")
-    fi
-    kill $SERVER_PID
-}
-
-if [ $# -eq 0 ]; then
-    for i in 32 64
-        do
-            for j in 32 64
-                do
-                    run_test $i $j
-                done
-        done
-    count_failed_tests=${#failed_test_cases[@]}
-    echo "*********************************************************"
-    echo "    hidl_test Final Summary:\n"
-    if [ $count_failed_tests -gt 0 ]; then
-        echo "    hidl_test failed for the following cases:\n\t"
-        for each in "${failed_test_cases[@]}"
-            do
-                echo "\t$each"
-            done
-    else
-        echo "    hidl_test passed for all cases!"
-    fi
-    echo "*********************************************************"
-    exit 0
-fi
-
-while getopts hc: opt;
-do
-    case $opt in
-        h)
-            usage
-            exit 0
-            ;;
-        c)
-            case $OPTARG in
-                CLIENT64_SERVER64)
-                    run_test 64 64
-                    ;;
-                CLIENT32_SERVER32)
-                    run_test 32 32
-                    ;;
-                CLIENT64_SERVER32)
-                    run_test 64 32
-                    ;;
-                CLIENT32_SERVER64)
-                    run_test 32 64
-                    ;;
-                *)
-                    echo "Error: unknown config value \"$OPTARG\""
-                    exit 1
-                    ;;
-            esac
-            ;;
-        *)
-            echo "Error: unknown param \"$opt\""
-            usage
-            exit 1
-            ;;
-    esac
-done
+run_all_tests \
+    "/data/nativetest/hidl_test_servers/hidl_test_servers" \
+    "/data/nativetest64/hidl_test_servers/hidl_test_servers" \
+    "/data/nativetest/hidl_test_client/hidl_test_client" \
+    "/data/nativetest64/hidl_test_client/hidl_test_client" \
+    "hidl_test" \
+    "$@"
diff --git a/test/hidl_test_helper b/test/hidl_test_helper
new file mode 100644
index 0000000..eb54358
--- /dev/null
+++ b/test/hidl_test_helper
@@ -0,0 +1,128 @@
+function usage() {
+    echo "runs $TEST_NAME"
+    echo "\t -h help"
+    echo "\t -c [CLIENT64_SERVER64 | CLIENT32_SERVER32 | CLIENT64_SERVER32 | CLIENT32_SERVER64] configures whether to run 32-bit or 64-bit versions of the servers and client"
+}
+
+failed_test_cases=()
+
+function run_test() {
+    if [ $1 -eq 32 ]; then
+        CLIENT_PATH=$CLIENT_PATH32
+    else
+        CLIENT_PATH=$CLIENT_PATH64
+    fi
+
+    if [ $2 -eq 32 ]; then
+        SERVER_PATH=$SERVER_PATH32
+    else
+        SERVER_PATH=$SERVER_PATH64
+    fi
+
+    echo "Running $1-bit client with $2-bit servers"
+    $SERVER_PATH &
+    sleep 1
+    SERVER_PID=$!
+    $CLIENT_PATH
+    if [ $? -ne 0 ]; then
+        failed_test_cases+=("$1-bit client with $2-bit servers")
+    fi
+    kill $SERVER_PID
+}
+
+function check_env() {
+    if [ -z ${TEST_NAME+x} ]; then
+        echo "TEST_NAME is unset";
+        exit 1
+    fi
+
+    if [ -z ${CLIENT_PATH32+x} ]; then
+        echo "CLIENT_PATH32 is unset";
+        exit 1
+    fi
+
+    if [ -z ${CLIENT_PATH64+x} ]; then
+        echo "CLIENT_PATH64 is unset";
+        exit 1
+    fi
+
+    if [ -z ${SERVER_PATH32+x} ]; then
+        echo "SERVER_PATH32 is unset";
+        exit 1
+    fi
+
+    if [ -z ${SERVER_PATH64+x} ]; then
+        echo "SERVER_PATH64 is unset";
+        exit 1
+    fi
+}
+
+#usage: run_all_tests server_path32 server_path64 client_path32 client_path64 test_name [-h/-c config]
+function run_all_tests() {
+    SERVER_PATH32=$1
+    SERVER_PATH64=$2
+    CLIENT_PATH32=$3
+    CLIENT_PATH64=$4
+    TEST_NAME=$5
+    check_env
+    shift 5
+
+    if [ $# -eq 0 ]; then
+        for i in 32 64
+            do
+                for j in 32 64
+                    do
+                        run_test $i $j
+                    done
+            done
+        count_failed_tests=${#failed_test_cases[@]}
+        echo "*********************************************************"
+        echo "    $TEST_NAME Final Summary:\n"
+        if [ $count_failed_tests -gt 0 ]; then
+            echo "    $TEST_NAME failed for the following cases:\n\t"
+            for each in "${failed_test_cases[@]}"
+                do
+                    echo "\t$each"
+                done
+        else
+            echo "    $TEST_NAME passed for all cases!"
+        fi
+        echo "*********************************************************"
+    fi
+
+    while getopts hc: opt;
+    do
+        case $opt in
+            h)
+                usage
+                exit 0
+                ;;
+            c)
+                case $OPTARG in
+                    CLIENT64_SERVER64)
+                        run_test 64 64
+                        ;;
+                    CLIENT32_SERVER32)
+                        run_test 32 32
+                        ;;
+                    CLIENT64_SERVER32)
+                        run_test 64 32
+                        ;;
+                    CLIENT32_SERVER64)
+                        run_test 32 64
+                        ;;
+                    *)
+                        echo "Error: unknown config value \"$OPTARG\""
+                        exit 1
+                        ;;
+                esac
+                ;;
+            *)
+                echo "Error: unknown param \"$opt\""
+                usage
+                exit 1
+                ;;
+        esac
+    done
+    exit ${#failed_test_cases[@]}
+}
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 c7b5951..87c4676 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
@@ -22,6 +22,7 @@
 import android.hardware.tests.baz.V1_0.IBazCallback;
 import android.os.HwBinder;
 import android.os.RemoteException;
+import android.os.HidlSupport;
 import android.util.Log;
 
 import java.util.ArrayList;
@@ -96,6 +97,10 @@
         throw new RuntimeException();
     }
 
+    private void ExpectFalse(boolean x) {
+        ExpectTrue(!x);
+    }
+
     private void Expect(String result, String s) {
         if (result.equals(s)) {
             return;
@@ -174,7 +179,60 @@
         return "positively huge!";
     }
 
+    private void ExpectDeepEq(Object l, Object r) {
+        ExpectTrue(HidlSupport.deepEquals(l, r));
+        ExpectTrue(HidlSupport.deepHashCode(l) == HidlSupport.deepHashCode(r));
+    }
+
+    private void ExpectDeepNe(Object l, Object r) {
+        ExpectTrue(!HidlSupport.deepEquals(l, r));
+    }
+
     private void client() throws RemoteException {
+
+        ExpectDeepEq(null, null);
+        ExpectDeepNe(null, new String());
+        ExpectDeepNe(new String(), null);
+        ExpectDeepEq(new String(), new String());
+        ExpectDeepEq("hey", "hey");
+
+        ExpectDeepEq(new int[]{1,2}, new int[]{1,2});
+        ExpectDeepNe(new int[]{1,2}, new int[]{1,3});
+        ExpectDeepNe(new int[]{1,2}, new int[]{1,2,3});
+        ExpectDeepEq(new int[][]{{1,2},{3,4}}, new int[][]{{1,2},{3,4}});
+        ExpectDeepNe(new int[][]{{1,2},{3,4}}, new int[][]{{1,2},{3,5}});
+        ExpectDeepNe(new int[][]{{1,2},{3,4}}, new int[][]{{1,2,3},{4,5,6}});
+        ExpectDeepNe(new int[][]{{1,2},{3,4}}, new int[][]{{1,2},{3,4,5}});
+
+        ExpectDeepEq(new Integer[]{1,2}, new Integer[]{1,2});
+        ExpectDeepNe(new Integer[]{1,2}, new Integer[]{1,3});
+        ExpectDeepNe(new Integer[]{1,2}, new Integer[]{1,2,3});
+        ExpectDeepEq(new Integer[][]{{1,2},{3,4}}, new Integer[][]{{1,2},{3,4}});
+        ExpectDeepNe(new Integer[][]{{1,2},{3,4}}, new Integer[][]{{1,2},{3,5}});
+        ExpectDeepNe(new Integer[][]{{1,2},{3,4}}, new Integer[][]{{1,2,3},{4,5,6}});
+        ExpectDeepNe(new Integer[][]{{1,2},{3,4}}, new Integer[][]{{1,2},{3,4,5}});
+
+        ExpectDeepEq(new ArrayList(Arrays.asList(1, 2)),
+                     new ArrayList(Arrays.asList(1, 2)));
+        ExpectDeepNe(new ArrayList(Arrays.asList(1, 2)),
+                     new ArrayList(Arrays.asList(1, 2, 3)));
+
+        ExpectDeepEq(new ArrayList(Arrays.asList(new int[]{1,2}, new int[]{3,4})),
+                     new ArrayList(Arrays.asList(new int[]{1,2}, new int[]{3,4})));
+        ExpectDeepNe(new ArrayList(Arrays.asList(new int[]{1,2}, new int[]{3,4})),
+                     new ArrayList(Arrays.asList(new int[]{1,2}, new int[]{3,5})));
+
+        ExpectDeepEq(new ArrayList(Arrays.asList(new Integer[]{1,2}, new Integer[]{3,4})),
+                     new ArrayList(Arrays.asList(new Integer[]{1,2}, new Integer[]{3,4})));
+        ExpectDeepNe(new ArrayList(Arrays.asList(new Integer[]{1,2}, new Integer[]{3,4})),
+                     new ArrayList(Arrays.asList(new Integer[]{1,2}, new Integer[]{3,5})));
+
+        ExpectDeepEq(new ArrayList[]{new ArrayList(Arrays.asList(1,2)),
+                                     new ArrayList(Arrays.asList(3,4))},
+                     new ArrayList[]{new ArrayList(Arrays.asList(1,2)),
+                                     new ArrayList(Arrays.asList(3,4))});
+
+
         {
             // Test access through base interface binder.
             IBase baseProxy = IBase.getService("baz");
@@ -312,13 +370,7 @@
             }
 
             IBase.VectorOfArray out = proxy.someMethodWithVectorOfArray(in);
-            /*
-             * TODO(b/36454147) Switch to .equals once the bug is fixed.
-             */
-            ExpectTrue(expectedOut.addresses.size() == out.addresses.size());
-            for  (int i = 0; i < n; ++i) {
-                ExpectTrue(java.util.Objects.deepEquals(out.addresses.get(i), expectedOut.addresses.get(i)));
-            }
+            ExpectTrue(out.equals(expectedOut));
         }
 
         {