Clean up JNI dlsym lookup trampoline.

Make sure the GenericJniTrampoline recognizes the trampoline
in primary boot image oat file. Rename that trampoline, add
a test and flag some issues in the code.

Test: New test 178-app-image-native-method.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Test: testrunner.py --host -t 178-app-image-native-method
Bug: 112189621
Change-Id: I8f8cd11998af536fd3842dd4183a25f0367655a6
diff --git a/test/178-app-image-native-method/src/Main.java b/test/178-app-image-native-method/src/Main.java
new file mode 100644
index 0000000..d63d112
--- /dev/null
+++ b/test/178-app-image-native-method/src/Main.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2019 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.
+ */
+
+import dalvik.annotation.optimization.FastNative;
+import dalvik.annotation.optimization.CriticalNative;
+
+public class Main {
+
+  public static void main(String[] args) throws Exception {
+    System.loadLibrary(args[0]);
+
+    if (!checkAppImageLoaded()) {
+      System.out.println("AppImage not loaded.");
+    }
+    // To avoid going through resolution trampoline, make test classes visibly initialized.
+    new Test();
+    new TestFast();
+    new TestCritical();
+    new TestMissing();
+    new TestMissingFast();
+    new TestMissingCritical();
+    makeVisiblyInitialized();  // Make sure they are visibly initialized.
+
+    // FIXME: @FastNative and @CriticalNative fail a state check in artFindNativeMethod().
+    test();
+    // testFast();
+    // testCritical();
+    testMissing();
+    // testMissingFast();
+    // testMissingCritical();
+  }
+
+  static void test() {
+    System.out.println("test");
+    assertEquals(42, Test.nativeMethod(42));
+    assertEquals(42, Test.nativeMethodWithManyParameters(
+        11, 12L, 13.0f, 14.0d,
+        21, 22L, 23.0f, 24.0d,
+        31, 32L, 33.0f, 34.0d,
+        41, 42L, 43.0f, 44.0d,
+        51, 52L, 53.0f, 54.0d,
+        61, 62L, 63.0f, 64.0d,
+        71, 72L, 73.0f, 74.0d,
+        81, 82L, 83.0f, 84.0d));
+  }
+
+  static void testFast() {
+    System.out.println("testFast");
+    assertEquals(42, TestFast.nativeMethod(42));
+    assertEquals(42, TestFast.nativeMethodWithManyParameters(
+        11, 12L, 13.0f, 14.0d,
+        21, 22L, 23.0f, 24.0d,
+        31, 32L, 33.0f, 34.0d,
+        41, 42L, 43.0f, 44.0d,
+        51, 52L, 53.0f, 54.0d,
+        61, 62L, 63.0f, 64.0d,
+        71, 72L, 73.0f, 74.0d,
+        81, 82L, 83.0f, 84.0d));
+  }
+
+  static void testCritical() {
+    System.out.println("testCritical");
+    assertEquals(42, TestCritical.nativeMethod(42));
+    assertEquals(42, TestCritical.nativeMethodWithManyParameters(
+        11, 12L, 13.0f, 14.0d,
+        21, 22L, 23.0f, 24.0d,
+        31, 32L, 33.0f, 34.0d,
+        41, 42L, 43.0f, 44.0d,
+        51, 52L, 53.0f, 54.0d,
+        61, 62L, 63.0f, 64.0d,
+        71, 72L, 73.0f, 74.0d,
+        81, 82L, 83.0f, 84.0d));
+  }
+
+  static void testMissing() {
+    System.out.println("testMissing");
+
+    try {
+      TestMissing.nativeMethod(42);
+      throw new Error("UNREACHABLE");
+    } catch (LinkageError expected) {}
+
+    try {
+      TestMissing.nativeMethodWithManyParameters(
+          11, 12L, 13.0f, 14.0d,
+          21, 22L, 23.0f, 24.0d,
+          31, 32L, 33.0f, 34.0d,
+          41, 42L, 43.0f, 44.0d,
+          51, 52L, 53.0f, 54.0d,
+          61, 62L, 63.0f, 64.0d,
+          71, 72L, 73.0f, 74.0d,
+          81, 82L, 83.0f, 84.0d);
+      throw new Error("UNREACHABLE");
+    } catch (LinkageError expected) {}
+  }
+
+  static void testMissingFast() {
+    System.out.println("testMissingFast");
+
+    try {
+      TestMissingFast.nativeMethod(42);
+      throw new Error("UNREACHABLE");
+    } catch (LinkageError expected) {}
+
+    try {
+      TestMissingFast.nativeMethodWithManyParameters(
+          11, 12L, 13.0f, 14.0d,
+          21, 22L, 23.0f, 24.0d,
+          31, 32L, 33.0f, 34.0d,
+          41, 42L, 43.0f, 44.0d,
+          51, 52L, 53.0f, 54.0d,
+          61, 62L, 63.0f, 64.0d,
+          71, 72L, 73.0f, 74.0d,
+          81, 82L, 83.0f, 84.0d);
+      throw new Error("UNREACHABLE");
+    } catch (LinkageError expected) {}
+  }
+
+  static void testMissingCritical() {
+    System.out.println("testMissingCritical");
+
+    try {
+      TestMissingCritical.nativeMethod(42);
+      throw new Error("UNREACHABLE");
+    } catch (LinkageError expected) {}
+
+    try {
+      TestMissingCritical.nativeMethodWithManyParameters(
+          11, 12L, 13.0f, 14.0d,
+          21, 22L, 23.0f, 24.0d,
+          31, 32L, 33.0f, 34.0d,
+          41, 42L, 43.0f, 44.0d,
+          51, 52L, 53.0f, 54.0d,
+          61, 62L, 63.0f, 64.0d,
+          71, 72L, 73.0f, 74.0d,
+          81, 82L, 83.0f, 84.0d);
+      throw new Error("UNREACHABLE");
+    } catch (LinkageError expected) {}
+  }
+
+  static void assertEquals(int expected, int actual) {
+    if (expected != actual) {
+      throw new AssertionError("Expected " + expected + " got " + actual);
+    }
+  }
+
+  public static native boolean checkAppImageLoaded();
+  public static native void makeVisiblyInitialized();
+}
+
+class Test {
+  public static native int nativeMethod(int i);
+
+  public static native int nativeMethodWithManyParameters(
+      int i1, long l1, float f1, double d1,
+      int i2, long l2, float f2, double d2,
+      int i3, long l3, float f3, double d3,
+      int i4, long l4, float f4, double d4,
+      int i5, long l5, float f5, double d5,
+      int i6, long l6, float f6, double d6,
+      int i7, long l7, float f7, double d7,
+      int i8, long l8, float f8, double d8);
+}
+
+class TestFast {
+  @FastNative
+  public static native int nativeMethod(int i);
+
+  @FastNative
+  public static native int nativeMethodWithManyParameters(
+      int i1, long l1, float f1, double d1,
+      int i2, long l2, float f2, double d2,
+      int i3, long l3, float f3, double d3,
+      int i4, long l4, float f4, double d4,
+      int i5, long l5, float f5, double d5,
+      int i6, long l6, float f6, double d6,
+      int i7, long l7, float f7, double d7,
+      int i8, long l8, float f8, double d8);
+}
+
+class TestCritical {
+  @CriticalNative
+  public static native int nativeMethod(int i);
+
+  @CriticalNative
+  public static native int nativeMethodWithManyParameters(
+      int i1, long l1, float f1, double d1,
+      int i2, long l2, float f2, double d2,
+      int i3, long l3, float f3, double d3,
+      int i4, long l4, float f4, double d4,
+      int i5, long l5, float f5, double d5,
+      int i6, long l6, float f6, double d6,
+      int i7, long l7, float f7, double d7,
+      int i8, long l8, float f8, double d8);
+}
+
+class TestMissing {
+  public static native int nativeMethod(int i);
+
+  public static native int nativeMethodWithManyParameters(
+      int i1, long l1, float f1, double d1,
+      int i2, long l2, float f2, double d2,
+      int i3, long l3, float f3, double d3,
+      int i4, long l4, float f4, double d4,
+      int i5, long l5, float f5, double d5,
+      int i6, long l6, float f6, double d6,
+      int i7, long l7, float f7, double d7,
+      int i8, long l8, float f8, double d8);
+}
+
+class TestMissingFast {
+  @FastNative
+  public static native int nativeMethod(int i);
+
+  @FastNative
+  public static native int nativeMethodWithManyParameters(
+      int i1, long l1, float f1, double d1,
+      int i2, long l2, float f2, double d2,
+      int i3, long l3, float f3, double d3,
+      int i4, long l4, float f4, double d4,
+      int i5, long l5, float f5, double d5,
+      int i6, long l6, float f6, double d6,
+      int i7, long l7, float f7, double d7,
+      int i8, long l8, float f8, double d8);
+}
+
+class TestMissingCritical {
+  @CriticalNative
+  public static native int nativeMethod(int i);
+
+  @CriticalNative
+  public static native int nativeMethodWithManyParameters(
+      int i1, long l1, float f1, double d1,
+      int i2, long l2, float f2, double d2,
+      int i3, long l3, float f3, double d3,
+      int i4, long l4, float f4, double d4,
+      int i5, long l5, float f5, double d5,
+      int i6, long l6, float f6, double d6,
+      int i7, long l7, float f7, double d7,
+      int i8, long l8, float f8, double d8);
+}