ART: Native bridge command-line parameter

Add a command-line parameter for the native bridge library, slight
refactor/cleanup.

Add run-test 115 to test the native bridge interface. Currently the
tests are black-listed for the target, as the setup for the test
is too complicated in the current infrastructure.

Change-Id: I6ccf19485e8c30b96e9f2fd5425278cb1ebd403f
diff --git a/runtime/native_bridge.cc b/runtime/native_bridge.cc
index de04a99..ad26ee4 100644
--- a/runtime/native_bridge.cc
+++ b/runtime/native_bridge.cc
@@ -35,7 +35,7 @@
 namespace art {
 
 // Is native-bridge support enabled?
-static constexpr bool kNativeBridgeEnabled = false;
+static constexpr bool kNativeBridgeEnabled = true;
 
 // Default library name for native-bridge.
 static constexpr const char* kDefaultNativeBridge = "libnativebridge.so";
@@ -55,9 +55,6 @@
 
 // ART interfaces to native-bridge.
 struct NativeBridgeArtCallbacks {
-  // Log utility, reserve unused.
-  int (*logger)(int prio, const char* tag, const char* fmt, ...);
-
   // Get shorty of a Java method. The shorty is supposed to be persistent in memory.
   //
   // Parameters:
@@ -190,71 +187,96 @@
 }
 
 NativeBridgeArtCallbacks NativeBridgeArtItf = {
-  nullptr,
   GetMethodShorty,
   GetNativeMethodCount,
   GetNativeMethods
 };
 
-bool NativeBridge::Init() {
+void NativeBridge::SetNativeBridgeLibraryString(std::string& native_bridge_library_string) {
+  native_bridge_library_string_ = native_bridge_library_string;
+  // TODO: when given an empty string, set initialized_ to true and available_ to false. This
+  //       change is dependent on the property removal in Initialize().
+}
+
+bool NativeBridge::Initialize() {
   if (!kNativeBridgeEnabled) {
     return false;
   }
 
   MutexLock mu(Thread::Current(), lock_);
 
-  if (!initialized_) {
-    const char* libnb_path = kDefaultNativeBridge;
+  if (initialized_) {
+    // Somebody did it before.
+    return available_;
+  }
+
+  available_ = false;
+
+  const char* libnb_path;
+
+  if (!native_bridge_library_string_.empty()) {
+    libnb_path = native_bridge_library_string_.c_str();
+  } else {
+    // TODO: Remove this once the frameworks side is completely implemented.
+
+    libnb_path = kDefaultNativeBridge;
 #ifdef HAVE_ANDROID_OS
     char prop_buf[PROP_VALUE_MAX];
     property_get(kPropEnableNativeBridge, prop_buf, "false");
-    if (strcmp(prop_buf, "true") != 0)
+    if (strcmp(prop_buf, "true") != 0) {
+      initialized_ = true;
       return false;
+    }
 
     // If prop persist.native.bridge set, overwrite the default name.
     int name_len = property_get(kPropNativeBridge, prop_buf, kDefaultNativeBridge);
     if (name_len > 0)
       libnb_path = prop_buf;
 #endif
-    void* handle = dlopen(libnb_path, RTLD_LAZY);
-    if (handle == nullptr)
-      return false;
-
-    callbacks_ = reinterpret_cast<NativeBridgeCallbacks*>(dlsym(handle,
-                                                                kNativeBridgeInterfaceSymbol));
-    if (callbacks_ == nullptr) {
-      dlclose(handle);
-      return false;
-    }
-
-    callbacks_->initialize(&NativeBridgeArtItf);
-    initialized_ = true;
   }
 
-  return initialized_;
+  void* handle = dlopen(libnb_path, RTLD_LAZY);
+  if (handle != nullptr) {
+    callbacks_ = reinterpret_cast<NativeBridgeCallbacks*>(dlsym(handle,
+                                                                kNativeBridgeInterfaceSymbol));
+
+    if (callbacks_ != nullptr) {
+      available_ = callbacks_->initialize(&NativeBridgeArtItf);
+    }
+
+    if (!available_) {
+      dlclose(handle);
+    }
+  }
+
+  initialized_ = true;
+
+  return available_;
 }
 
 void* NativeBridge::LoadLibrary(const char* libpath, int flag) {
-  if (Init())
+  if (Initialize())
     return callbacks_->loadLibrary(libpath, flag);
   return nullptr;
 }
 
 void* NativeBridge::GetTrampoline(void* handle, const char* name, const char* shorty,
                                   uint32_t len) {
-  if (Init())
+  if (Initialize())
     return callbacks_->getTrampoline(handle, name, shorty, len);
   return nullptr;
 }
 
 bool NativeBridge::IsSupported(const char* libpath) {
-  if (Init())
+  if (Initialize())
     return callbacks_->isSupported(libpath);
   return false;
 }
 
+bool NativeBridge::available_ = false;
 bool NativeBridge::initialized_ = false;
 Mutex NativeBridge::lock_("native bridge lock");
+std::string NativeBridge::native_bridge_library_string_ = "";
 NativeBridgeCallbacks* NativeBridge::callbacks_ = nullptr;
 
 };  // namespace art
diff --git a/runtime/native_bridge.h b/runtime/native_bridge.h
index dd895d2..3d20fe4 100644
--- a/runtime/native_bridge.h
+++ b/runtime/native_bridge.h
@@ -19,23 +19,38 @@
 
 #include "base/mutex.h"
 
+#include <string>
+
 namespace art {
 
 struct NativeBridgeCallbacks;
 
 class NativeBridge {
  public:
+  // Initialize the native bridge, if any. Should be called by Runtime::Init(). An empty string
+  // signals that we do not want to load a native bridge.
+  static void SetNativeBridgeLibraryString(std::string& native_bridge_library_string);
+
   // Load a shared library that is supported by the native-bridge.
   static void* LoadLibrary(const char* libpath, int flag);
   // Get a native-bridge trampoline for specified native method.
   static void* GetTrampoline(void* handle, const char* name, const char* shorty, uint32_t len);
   // True if native library is valid and is for an ABI that is supported by native-bridge.
-  static bool  IsSupported(const char* libpath);
+  static bool IsSupported(const char* libpath);
 
  private:
-  static bool  Init();
-  static bool  initialized_ GUARDED_BY(lock_);
+  static bool Initialize();
+
+  // The library name we are supposed to load.
+  static std::string native_bridge_library_string_;
+
+  // Whether we have already initialized (or tried to).
+  static bool initialized_ GUARDED_BY(lock_);
   static Mutex lock_;
+
+  // Whether a native bridge is available (loaded and ready).
+  static bool available_;
+
   static NativeBridgeCallbacks* callbacks_;
 };
 
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 8d0aff8..49f6585 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -596,6 +596,10 @@
         Usage("Unknown -Xverify option %s\n", verify_mode.c_str());
         return false;
       }
+    } else if (StartsWith(option, "-XX:NativeBridge=")) {
+      if (!ParseStringAfterChar(option, '=', &native_bridge_library_string_)) {
+        return false;
+      }
     } else if (StartsWith(option, "-ea") ||
                StartsWith(option, "-da") ||
                StartsWith(option, "-enableassertions") ||
diff --git a/runtime/parsed_options.h b/runtime/parsed_options.h
index 29d5494..668ed9e 100644
--- a/runtime/parsed_options.h
+++ b/runtime/parsed_options.h
@@ -45,6 +45,7 @@
   std::string image_;
   bool check_jni_;
   std::string jni_trace_;
+  std::string native_bridge_library_string_;
   CompilerCallbacks* compiler_callbacks_;
   bool is_zygote_;
   // TODO Change this to true when we want it on by default.
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index b7eae85..1cbf841 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -63,6 +63,7 @@
 #include "mirror/stack_trace_element.h"
 #include "mirror/throwable.h"
 #include "monitor.h"
+#include "native_bridge.h"
 #include "parsed_options.h"
 #include "oat_file.h"
 #include "quick/quick_method_frame_info.h"
@@ -718,6 +719,9 @@
   pre_allocated_OutOfMemoryError_ = self->GetException(NULL);
   self->ClearException();
 
+  // Look for a native bridge.
+  NativeBridge::SetNativeBridgeLibraryString(options->native_bridge_library_string_);
+
   VLOG(startup) << "Runtime::Init exiting";
   return true;
 }
diff --git a/test/115-native-bridge/expected.txt b/test/115-native-bridge/expected.txt
new file mode 100644
index 0000000..f852620
--- /dev/null
+++ b/test/115-native-bridge/expected.txt
@@ -0,0 +1,13 @@
+Ready for native bridge tests.
+Native bridge initialized.
+Checking for support.
+Getting trampoline.
+Getting trampoline.
+Getting trampoline.
+Getting trampoline.
+Getting trampoline.
+Getting trampoline.
+Getting trampoline.
+Getting trampoline.
+Getting trampoline.
+Getting trampoline.
diff --git a/test/115-native-bridge/info.txt b/test/115-native-bridge/info.txt
new file mode 100644
index 0000000..ccac7ae
--- /dev/null
+++ b/test/115-native-bridge/info.txt
@@ -0,0 +1 @@
+Test for the native bridge interface.
diff --git a/test/115-native-bridge/nativebridge.cc b/test/115-native-bridge/nativebridge.cc
new file mode 100644
index 0000000..bd3ae13
--- /dev/null
+++ b/test/115-native-bridge/nativebridge.cc
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+// A simple implementation of the native-bridge interface.
+
+#include <algorithm>
+#include <dlfcn.h>
+#include <vector>
+
+#include "jni.h"
+#include "stdio.h"
+#include "string.h"
+#include "unistd.h"
+
+#include "native_bridge.h"
+
+
+// Native bridge interfaces...
+
+struct NativeBridgeArtCallbacks {
+  const char* (*getMethodShorty)(JNIEnv* env, jmethodID mid);
+  int (*getNativeMethodCount)(JNIEnv* env, jclass clazz);
+  int (*getNativeMethods)(JNIEnv* env, jclass clazz, JNINativeMethod* methods,
+       uint32_t method_count);
+};
+
+struct NativeBridgeCallbacks {
+  bool (*initialize)(NativeBridgeArtCallbacks* art_cbs);
+  void* (*loadLibrary)(const char* libpath, int flag);
+  void* (*getTrampoline)(void* handle, const char* name, const char* shorty, uint32_t len);
+  bool (*isSupported)(const char* libpath);
+};
+
+
+
+static std::vector<void*> symbols;
+
+// NativeBridgeCallbacks implementations
+extern "C" bool native_bridge_initialize(NativeBridgeArtCallbacks* art_cbs) {
+  printf("Native bridge initialized.\n");
+  return true;
+}
+
+extern "C" void* native_bridge_loadLibrary(const char* libpath, int flag) {
+  size_t len = strlen(libpath);
+  char* tmp = new char[len + 10];
+  strncpy(tmp, libpath, len);
+  tmp[len - 3] = '2';
+  tmp[len - 2] = '.';
+  tmp[len - 1] = 's';
+  tmp[len] = 'o';
+  tmp[len + 1] = 0;
+  void* handle = dlopen(tmp, flag);
+  delete[] tmp;
+
+  if (handle == nullptr) {
+    printf("Handle = nullptr!\n");
+    printf("Was looking for %s.\n", libpath);
+    printf("Error = %s.\n", dlerror());
+    char cwd[1024];
+    if (getcwd(cwd, sizeof(cwd)) != nullptr) {
+      printf("Current working dir: %s\n", cwd);
+    }
+  }
+  return handle;
+}
+
+extern "C" void* native_bridge_getTrampoline(void* handle, const char* name, const char* shorty,
+                                             uint32_t len) {
+  printf("Getting trampoline.\n");
+
+  // The name here is actually the JNI name, so we can directly do the lookup.
+  void* sym = dlsym(handle, name);
+  if (sym != nullptr) {
+    symbols.push_back(sym);
+  }
+
+  // As libarttest is the same arch as the host, we can actually directly use the code and do not
+  // need to create a trampoline. :-)
+  return sym;
+}
+
+extern "C" bool native_bridge_isSupported(const char* libpath) {
+  printf("Checking for support.\n");
+
+  if (libpath == nullptr) {
+    return false;
+  }
+  // We don't want to hijack javacore. So we should get libarttest...
+  return strcmp(libpath, "libjavacore.so") != 0;
+}
+
+NativeBridgeCallbacks NativeBridgeItf {
+  .initialize = &native_bridge_initialize,
+  .loadLibrary = &native_bridge_loadLibrary,
+  .getTrampoline = &native_bridge_getTrampoline,
+  .isSupported = &native_bridge_isSupported
+};
+
+
+
diff --git a/test/115-native-bridge/run b/test/115-native-bridge/run
new file mode 100644
index 0000000..e475cd6
--- /dev/null
+++ b/test/115-native-bridge/run
@@ -0,0 +1,29 @@
+#!/bin/sh
+#
+# Copyright (C) 2012 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.
+
+ARGS=${@}
+
+# Use libnativebridgetest as a native bridge, start NativeBridgeMain (Main is JniTest main file).
+LIBPATH=$(echo ${ARGS} | sed -r 's/.*Djava.library.path=([^ ]*) .*/\1/')
+cp ${LIBPATH}/libnativebridgetest.so .
+touch libarttest.so
+cp ${LIBPATH}/libarttest.so libarttest2.so
+
+# pwd likely has /, so it's a pain to put that into a sed rule.
+LEFT=$(echo ${ARGS} | sed -r 's/-Djava.library.path.*//')
+RIGHT=$(echo ${ARGS} | sed -r 's/.*Djava.library.path[^ ]* //')
+MODARGS="${LEFT} -Djava.library.path=`pwd` ${RIGHT}"
+exec ${RUN} --runtime-option -XX:NativeBridge=libnativebridgetest.so ${MODARGS} NativeBridgeMain
diff --git a/test/115-native-bridge/src/NativeBridgeMain.java b/test/115-native-bridge/src/NativeBridgeMain.java
new file mode 100644
index 0000000..a531f92
--- /dev/null
+++ b/test/115-native-bridge/src/NativeBridgeMain.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2014 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 java.lang.reflect.Method;
+
+// This is named Main as it is a copy of JniTest, so that we can re-use the native implementations
+// from libarttest.
+class Main {
+    public static void main(String[] args) {
+        testFindClassOnAttachedNativeThread();
+        testFindFieldOnAttachedNativeThread();
+        testCallStaticVoidMethodOnSubClass();
+        testGetMirandaMethod();
+        testZeroLengthByteBuffers();
+        testByteMethod();
+        testShortMethod();
+        testBooleanMethod();
+        testCharMethod();
+    }
+
+    public static native void testFindClassOnAttachedNativeThread();
+
+    public static boolean testFindFieldOnAttachedNativeThreadField;
+
+    public static void testFindFieldOnAttachedNativeThread() {
+      testFindFieldOnAttachedNativeThreadNative();
+      if (!testFindFieldOnAttachedNativeThreadField) {
+            throw new AssertionError();
+        }
+    }
+
+    private static native void testFindFieldOnAttachedNativeThreadNative();
+
+    private static void testCallStaticVoidMethodOnSubClass() {
+        testCallStaticVoidMethodOnSubClassNative();
+        if (!testCallStaticVoidMethodOnSubClass_SuperClass.executed) {
+            throw new AssertionError();
+        }
+    }
+
+    private static native void testCallStaticVoidMethodOnSubClassNative();
+
+    private static class testCallStaticVoidMethodOnSubClass_SuperClass {
+        private static boolean executed = false;
+        private static void execute() {
+            executed = true;
+        }
+    }
+
+    private static class testCallStaticVoidMethodOnSubClass_SubClass
+        extends testCallStaticVoidMethodOnSubClass_SuperClass {
+    }
+
+    private static native Method testGetMirandaMethodNative();
+
+    private static void testGetMirandaMethod() {
+        Method m = testGetMirandaMethodNative();
+        if (m.getDeclaringClass() != testGetMirandaMethod_MirandaInterface.class) {
+            throw new AssertionError();
+        }
+    }
+
+    private static native void testZeroLengthByteBuffers();
+
+    private static abstract class testGetMirandaMethod_MirandaAbstract implements testGetMirandaMethod_MirandaInterface {
+        public boolean inAbstract() {
+            return true;
+        }
+    }
+
+    private static interface testGetMirandaMethod_MirandaInterface {
+        public boolean inInterface();
+    }
+
+    // Test sign-extension for values < 32b
+
+    native static byte byteMethod(byte b1, byte b2, byte b3, byte b4, byte b5, byte b6, byte b7,
+        byte b8, byte b9, byte b10);
+
+    public static void testByteMethod() {
+      byte returns[] = { 0, 1, 2, 127, -1, -2, -128 };
+      for (int i = 0; i < returns.length; i++) {
+        byte result = byteMethod((byte)i, (byte)2, (byte)(-3), (byte)4, (byte)(-5), (byte)6,
+            (byte)(-7), (byte)8, (byte)(-9), (byte)10);
+        if (returns[i] != result) {
+          System.out.println("Run " + i + " with " + returns[i] + " vs " + result);
+          throw new AssertionError();
+        }
+      }
+    }
+
+    native static short shortMethod(short s1, short s2, short s3, short s4, short s5, short s6, short s7,
+        short s8, short s9, short s10);
+
+    private static void testShortMethod() {
+      short returns[] = { 0, 1, 2, 127, 32767, -1, -2, -128, -32768 };
+      for (int i = 0; i < returns.length; i++) {
+        short result = shortMethod((short)i, (short)2, (short)(-3), (short)4, (short)(-5), (short)6,
+            (short)(-7), (short)8, (short)(-9), (short)10);
+        if (returns[i] != result) {
+          System.out.println("Run " + i + " with " + returns[i] + " vs " + result);
+          throw new AssertionError();
+        }
+      }
+    }
+
+    // Test zero-extension for values < 32b
+
+    native static boolean booleanMethod(boolean b1, boolean b2, boolean b3, boolean b4, boolean b5, boolean b6, boolean b7,
+        boolean b8, boolean b9, boolean b10);
+
+    public static void testBooleanMethod() {
+      if (booleanMethod(false, true, false, true, false, true, false, true, false, true)) {
+        throw new AssertionError();
+      }
+
+      if (!booleanMethod(true, true, false, true, false, true, false, true, false, true)) {
+        throw new AssertionError();
+      }
+    }
+
+    native static char charMethod(char c1, char c2, char c3, char c4, char c5, char c6, char c7,
+        char c8, char c9, char c10);
+
+    private static void testCharMethod() {
+      char returns[] = { (char)0, (char)1, (char)2, (char)127, (char)255, (char)256, (char)15000,
+          (char)34000 };
+      for (int i = 0; i < returns.length; i++) {
+        char result = charMethod((char)i, 'a', 'b', 'c', '0', '1', '2', (char)1234, (char)2345,
+            (char)3456);
+        if (returns[i] != result) {
+          System.out.println("Run " + i + " with " + (int)returns[i] + " vs " + (int)result);
+          throw new AssertionError();
+        }
+      }
+    }
+}
+
+public class NativeBridgeMain {
+    static public void main(String[] args) throws Exception {
+        System.out.println("Ready for native bridge tests.");
+
+        System.loadLibrary("arttest");
+
+        Main.main(null);
+    }
+}
diff --git a/test/Android.libnativebridgetest.mk b/test/Android.libnativebridgetest.mk
new file mode 100644
index 0000000..dd7255a
--- /dev/null
+++ b/test/Android.libnativebridgetest.mk
@@ -0,0 +1,87 @@
+#
+# Copyright (C) 2014 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include art/build/Android.common_build.mk
+
+LIBNATIVEBRIDGETEST_COMMON_SRC_FILES := \
+  115-native-bridge/nativebridge.cc
+
+ART_TARGET_LIBNATIVEBRIDGETEST_$(ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_TARGET_TEST_OUT)/$(TARGET_ARCH)/libnativebridgetest.so
+ifdef TARGET_2ND_ARCH
+  ART_TARGET_LIBNATIVEBRIDGETEST_$(2ND_ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_TARGET_TEST_OUT)/$(TARGET_2ND_ARCH)/libnativebridgetest.so
+endif
+
+# $(1): target or host
+define build-libnativebridgetest
+  ifneq ($(1),target)
+    ifneq ($(1),host)
+      $$(error expected target or host for argument 1, received $(1))
+    endif
+  endif
+
+  art_target_or_host := $(1)
+
+  include $(CLEAR_VARS)
+  LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
+  LOCAL_MODULE := libnativebridgetest
+  ifeq ($$(art_target_or_host),target)
+    LOCAL_MODULE_TAGS := tests
+  endif
+  LOCAL_SRC_FILES := $(LIBNATIVEBRIDGETEST_COMMON_SRC_FILES)
+  LOCAL_SHARED_LIBRARIES += libartd
+  LOCAL_C_INCLUDES += $(ART_C_INCLUDES) art/runtime
+  LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
+  LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.libnativebridgetest.mk
+  include external/libcxx/libcxx.mk
+  ifeq ($$(art_target_or_host),target)
+    $(call set-target-local-clang-vars)
+    $(call set-target-local-cflags-vars,debug)
+    LOCAL_SHARED_LIBRARIES += libdl libcutils
+    LOCAL_STATIC_LIBRARIES := libgtest
+    LOCAL_MULTILIB := both
+    LOCAL_MODULE_PATH_32 := $(ART_TARGET_TEST_OUT)/$(ART_TARGET_ARCH_32)
+    LOCAL_MODULE_PATH_64 := $(ART_TARGET_TEST_OUT)/$(ART_TARGET_ARCH_64)
+    LOCAL_MODULE_TARGET_ARCH := $(ART_SUPPORTED_ARCH)
+    include $(BUILD_SHARED_LIBRARY)
+  else # host
+    LOCAL_CLANG := $(ART_HOST_CLANG)
+    LOCAL_CFLAGS := $(ART_HOST_CFLAGS) $(ART_HOST_DEBUG_CFLAGS)
+    LOCAL_STATIC_LIBRARIES := libcutils
+    LOCAL_LDLIBS += -ldl -lpthread
+    ifeq ($(HOST_OS),linux)
+      LOCAL_LDLIBS += -lrt
+    endif
+    LOCAL_IS_HOST_MODULE := true
+    LOCAL_MULTILIB := both
+    include $(BUILD_HOST_SHARED_LIBRARY)
+  endif
+
+  # Clear locally used variables.
+  art_target_or_host :=
+endef
+
+ifeq ($(ART_BUILD_TARGET),true)
+  $(eval $(call build-libnativebridgetest,target))
+endif
+ifeq ($(ART_BUILD_HOST),true)
+  $(eval $(call build-libnativebridgetest,host))
+endif
+
+# Clear locally used variables.
+LOCAL_PATH :=
+LIBNATIVEBRIDGETEST_COMMON_SRC_FILES :=
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 78493dc..6fa5df1 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -40,6 +40,16 @@
   test-art-target-run-test$(2)-interpreter$(3)-$(1)64
 endef  # all-run-test-names
 
+# Subset of the above for target only.
+define all-run-test-target-names
+  test-art-target-run-test$(2)-default$(3)-$(1)32 \
+  test-art-target-run-test$(2)-optimizing$(3)-$(1)32 \
+  test-art-target-run-test$(2)-interpreter$(3)-$(1)32 \
+  test-art-target-run-test$(2)-default$(3)-$(1)64 \
+  test-art-target-run-test$(2)-optimizing$(3)-$(1)64 \
+  test-art-target-run-test$(2)-interpreter$(3)-$(1)64
+endef  # all-run-test-target-names
+
 # Tests that are timing sensitive and flaky on heavily loaded systems.
 TEST_ART_TIMING_SENSITIVE_RUN_TESTS := \
   053-wait-some \
@@ -120,6 +130,27 @@
 ART_TEST_KNOWN_BROKEN += $(foreach test, $(TEST_ART_BROKEN_GCSTRESS_RUN_TESTS), $(call all-run-test-names,$(test),-gcstress,-norelocate))
 ART_TEST_KNOWN_BROKEN += $(foreach test, $(TEST_ART_BROKEN_GCSTRESS_RUN_TESTS), $(call all-run-test-names,$(test),-gcstress,))
 
+# 115-native-bridge setup is complicated. Need to implement it correctly for the target.
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-target-names,115-native-bridge,,)
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-target-names,115-native-bridge,-trace,)
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-target-names,115-native-bridge,-gcverify,)
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-target-names,115-native-bridge,-gcstress,)
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-target-names,115-native-bridge,,-relocate)
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-target-names,115-native-bridge,-trace,-relocate)
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-target-names,115-native-bridge,-gcverify,-relocate)
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-target-names,115-native-bridge,-gcstress,-relocate)
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-target-names,115-native-bridge,,-norelocate)
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-target-names,115-native-bridge,-trace,-norelocate)
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-target-names,115-native-bridge,-gcverify,-norelocate)
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-target-names,115-native-bridge,-gcstress,-norelocate)
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-target-names,115-native-bridge,,-prebuild)
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-target-names,115-native-bridge,-trace,-prebuild)
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-target-names,115-native-bridge,-gcverify,-prebuild)
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-target-names,115-native-bridge,-gcstress,-prebuild)
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-target-names,115-native-bridge,,-no-prebuild)
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-target-names,115-native-bridge,-trace,-no-prebuild)
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-target-names,115-native-bridge,-gcverify,-no-prebuild)
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-target-names,115-native-bridge,-gcstress,-no-prebuild)
 
 # The path where build only targets will be output, e.g.
 # out/target/product/generic_x86_64/obj/PACKAGING/art-run-tests_intermediates/DATA
@@ -290,16 +321,24 @@
 TEST_ART_TARGET_SYNC_DEPS += $(ART_TARGET_TEST_OUT)/$(TARGET_2ND_ARCH)/libarttest.so
 endif
 
+# Also need libnativebridgetest.
+TEST_ART_TARGET_SYNC_DEPS += $(ART_TARGET_TEST_OUT)/$(TARGET_ARCH)/libnativebridgetest.so
+ifdef TARGET_2ND_ARCH
+TEST_ART_TARGET_SYNC_DEPS += $(ART_TARGET_TEST_OUT)/$(TARGET_2ND_ARCH)/libnativebridgetest.so
+endif
+
 # All tests require the host executables and the core images.
 ART_TEST_HOST_RUN_TEST_DEPENDENCIES := \
   $(ART_HOST_EXECUTABLES) \
   $(ART_HOST_OUT_SHARED_LIBRARIES)/libarttest$(ART_HOST_SHLIB_EXTENSION) \
+  $(ART_HOST_OUT_SHARED_LIBRARIES)/libnativebridgetest$(ART_HOST_SHLIB_EXTENSION) \
   $(ART_HOST_OUT_SHARED_LIBRARIES)/libjavacore$(ART_HOST_SHLIB_EXTENSION) \
   $(HOST_CORE_IMG_OUT)
 
 ifneq ($(HOST_PREFER_32_BIT),true)
 ART_TEST_HOST_RUN_TEST_DEPENDENCIES += \
   $(2ND_ART_HOST_OUT_SHARED_LIBRARIES)/libarttest$(ART_HOST_SHLIB_EXTENSION) \
+  $(2ND_ART_HOST_OUT_SHARED_LIBRARIES)/libnativebridgetest$(ART_HOST_SHLIB_EXTENSION) \
   $(2ND_ART_HOST_OUT_SHARED_LIBRARIES)/libjavacore$(ART_HOST_SHLIB_EXTENSION) \
   $(2ND_HOST_CORE_IMG_OUT)
 endif
@@ -831,6 +870,9 @@
 # include libarttest build rules.
 include $(LOCAL_PATH)/Android.libarttest.mk
 
+# Include libnativebridgetest build rules.
+include art/test/Android.libnativebridgetest.mk
+
 define-test-art-run-test :=
 define-test-art-run-test-group-rule :=
 define-test-art-run-test-group :=
diff --git a/test/etc/host-run-test-jar b/test/etc/host-run-test-jar
index d72e997..2241f85 100755
--- a/test/etc/host-run-test-jar
+++ b/test/etc/host-run-test-jar
@@ -24,6 +24,7 @@
 COMPILER_FLAGS=""
 BUILD_BOOT_OPT=""
 exe="${ANDROID_HOST_OUT}/bin/dalvikvm32"
+main="Main"
 
 while true; do
     if [ "x$1" = "x--quiet" ]; then
@@ -112,6 +113,12 @@
     fi
 done
 
+if [ "x$1" = "x" ] ; then
+  main="Main"
+else
+  main="$1"
+fi
+
 msg "------------------------------"
 
 export ANDROID_PRINTF_LOG=brief
@@ -171,7 +178,7 @@
 fi
 
 JNI_OPTS="-Xjnigreflimit:512 -Xcheck:jni"
-cmdline="$INVOKE_WITH $gdb $exe $gdbargs -XXlib:$LIB $JNI_OPTS $FLAGS $INT_OPTS $DEBUGGER_OPTS $BOOT_OPT -cp $DEX_LOCATION/$TEST_NAME.jar Main"
+cmdline="$INVOKE_WITH $gdb $exe $gdbargs -XXlib:$LIB $JNI_OPTS $FLAGS $INT_OPTS $DEBUGGER_OPTS $BOOT_OPT -cp $DEX_LOCATION/$TEST_NAME.jar $main"
 if [ "$DEV_MODE" = "y" ]; then
   if [ "$PREBUILD" = "y" ]; then
     echo "$mkdir_cmd && $prebuild_cmd && $cmdline"
diff --git a/test/run-test b/test/run-test
index 0e42efe..ae613d9 100755
--- a/test/run-test
+++ b/test/run-test
@@ -377,6 +377,9 @@
   file_size_limit=5120
 elif echo "$test_dir" | grep 083; then
   file_size_limit=5120
+elif echo "$test_dir" | grep 115; then
+# Native bridge test copies libarttest.so into its directory, which needs 2MB already.
+  file_size_limit=5120
 fi
 if ! ulimit -S "$file_size_limit"; then
    echo "ulimit file size setting failed"