ART: Update for split native bridge initialization

Change-Id: I0b93da93251c6b4638de786bf98cf99df07c3fc2
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index c3c8c25..e469126 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -111,15 +111,17 @@
   thread->InitAfterFork();
   EnableDebugFeatures(debug_flags);
 
-  Runtime::NativeBridgeAction action = Runtime::NativeBridgeAction::kUnload;
   if (instruction_set != nullptr) {
     ScopedUtfChars isa_string(env, instruction_set);
     InstructionSet isa = GetInstructionSetFromString(isa_string.c_str());
+    Runtime::NativeBridgeAction action = Runtime::NativeBridgeAction::kUnload;
     if (isa != kNone && isa != kRuntimeISA) {
       action = Runtime::NativeBridgeAction::kInitialize;
     }
+    Runtime::Current()->DidForkFromZygote(env, action, isa_string.c_str());
+  } else {
+    Runtime::Current()->DidForkFromZygote(env, Runtime::NativeBridgeAction::kUnload, nullptr);
   }
-  Runtime::Current()->DidForkFromZygote(action);
 }
 
 static JNINativeMethod gMethods[] = {
diff --git a/runtime/native_bridge_art_interface.cc b/runtime/native_bridge_art_interface.cc
index 453c92f..fcd11ed 100644
--- a/runtime/native_bridge_art_interface.cc
+++ b/runtime/native_bridge_art_interface.cc
@@ -16,6 +16,9 @@
 
 #include "native_bridge_art_interface.h"
 
+#include "nativebridge/native_bridge.h"
+
+#include "base/logging.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/class-inl.h"
 #include "scoped_thread_state_change.h"
@@ -91,4 +94,40 @@
   return count;
 }
 
+// Native bridge library runtime callbacks. They represent the runtime interface to native bridge.
+//
+// The interface is expected to expose the following methods:
+// getMethodShorty(): in the case of native method calling JNI native function CallXXXXMethodY(),
+//   native bridge calls back to VM for the shorty of the method so that it can prepare based on
+//   host calling convention.
+// getNativeMethodCount() and getNativeMethods(): in case of JNI function UnregisterNatives(),
+//   native bridge can call back to get all native methods of specified class so that all
+//   corresponding trampolines can be destroyed.
+static android::NativeBridgeRuntimeCallbacks native_bridge_art_callbacks_ {
+  GetMethodShorty, GetNativeMethodCount, GetNativeMethods
+};
+
+void LoadNativeBridge(std::string& native_bridge_library_filename) {
+  android::LoadNativeBridge(native_bridge_library_filename.c_str(), &native_bridge_art_callbacks_);
+  VLOG(startup) << "Runtime::Setup native bridge library: "
+      << (native_bridge_library_filename.empty() ? "(empty)" : native_bridge_library_filename);
+}
+
+void PreInitializeNativeBridge(std::string dir) {
+  VLOG(startup) << "Runtime::Pre-initialize native bridge";
+  if (unshare(CLONE_NEWNS) == -1) {
+    LOG(WARNING) << "Could not create mount namespace.";
+    return;
+  }
+  android::PreInitializeNativeBridge(dir.c_str(), GetInstructionSetString(kRuntimeISA));
+}
+
+void InitializeNativeBridge(JNIEnv* env, const char* instruction_set) {
+  android::InitializeNativeBridge(env, instruction_set);
+}
+
+void UnloadNativeBridge() {
+  android::UnloadNativeBridge();
+}
+
 };  // namespace art
diff --git a/runtime/native_bridge_art_interface.h b/runtime/native_bridge_art_interface.h
index 08735c8..42f0ed2 100644
--- a/runtime/native_bridge_art_interface.h
+++ b/runtime/native_bridge_art_interface.h
@@ -19,15 +19,21 @@
 
 #include <jni.h>
 #include <stdint.h>
+#include <string>
 
 namespace art {
 
-const char* GetMethodShorty(JNIEnv* env, jmethodID mid);
+// Mirror libnativebridge interface. Done to have the ART callbacks out of line, and not require
+// the system/core header file in other files.
 
-uint32_t GetNativeMethodCount(JNIEnv* env, jclass clazz);
+void LoadNativeBridge(std::string& native_bridge_library_filename);
 
-uint32_t GetNativeMethods(JNIEnv* env, jclass clazz, JNINativeMethod* methods,
-                          uint32_t method_count);
+// This is mostly for testing purposes, as in a full system this is called by Zygote code.
+void PreInitializeNativeBridge(std::string dir);
+
+void InitializeNativeBridge(JNIEnv* env, const char* instruction_set);
+
+void UnloadNativeBridge();
 
 };  // namespace art
 
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 9b24bec..0edf116 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -143,8 +143,7 @@
       target_sdk_version_(0),
       implicit_null_checks_(false),
       implicit_so_checks_(false),
-      implicit_suspend_checks_(false),
-      native_bridge_art_callbacks_({GetMethodShorty, GetNativeMethodCount, GetNativeMethods}) {
+      implicit_suspend_checks_(false) {
 }
 
 Runtime::~Runtime() {
@@ -418,18 +417,23 @@
 
   Thread::FinishStartup();
 
+  system_class_loader_ = CreateSystemClassLoader();
+
   if (is_zygote_) {
     if (!InitZygote()) {
       return false;
     }
   } else {
-    DidForkFromZygote(NativeBridgeAction::kInitialize);
+    bool have_native_bridge = !native_bridge_library_filename_.empty();
+    if (have_native_bridge) {
+      PreInitializeNativeBridge(".");
+    }
+    DidForkFromZygote(self->GetJniEnv(), have_native_bridge ? NativeBridgeAction::kInitialize :
+        NativeBridgeAction::kUnload, GetInstructionSetString(kRuntimeISA));
   }
 
   StartDaemonThreads();
 
-  system_class_loader_ = CreateSystemClassLoader();
-
   {
     ScopedObjectAccess soa(self);
     self->GetJniEnv()->locals.AssertEmpty();
@@ -501,16 +505,16 @@
 #endif
 }
 
-void Runtime::DidForkFromZygote(NativeBridgeAction action) {
+void Runtime::DidForkFromZygote(JNIEnv* env, NativeBridgeAction action, const char* isa) {
   is_zygote_ = false;
 
   switch (action) {
     case NativeBridgeAction::kUnload:
-      android::UnloadNativeBridge();
+      UnloadNativeBridge();
       break;
 
     case NativeBridgeAction::kInitialize:
-      android::InitializeNativeBridge();
+      InitializeNativeBridge(env, isa);
       break;
   }
 
@@ -870,10 +874,7 @@
   //   DidForkFromZygote(kInitialize) -> try to initialize any native bridge given.
   //   No-op wrt native bridge.
   native_bridge_library_filename_ = options->native_bridge_library_filename_;
-  android::LoadNativeBridge(native_bridge_library_filename_.c_str(), &native_bridge_art_callbacks_);
-  VLOG(startup) << "Runtime::Setup native bridge library: "
-                << (native_bridge_library_filename_.empty() ?
-                    "(empty)" : native_bridge_library_filename_);
+  LoadNativeBridge(native_bridge_library_filename_);
 
   VLOG(startup) << "Runtime::Init exiting";
   return true;
diff --git a/runtime/runtime.h b/runtime/runtime.h
index cfb1abc..9a8235d 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -32,7 +32,6 @@
 #include "instrumentation.h"
 #include "instruction_set.h"
 #include "jobject_comparator.h"
-#include "nativebridge/native_bridge.h"
 #include "object_callbacks.h"
 #include "offsets.h"
 #include "profiler_options.h"
@@ -398,7 +397,7 @@
   };
   void PreZygoteFork();
   bool InitZygote();
-  void DidForkFromZygote(NativeBridgeAction action);
+  void DidForkFromZygote(JNIEnv* env, NativeBridgeAction action, const char* isa);
 
   const instrumentation::Instrumentation* GetInstrumentation() const {
     return &instrumentation_;
@@ -648,17 +647,6 @@
   // the native bridge to load it and then gets the trampoline for the entry to native activity.
   std::string native_bridge_library_filename_;
 
-  // Native bridge library runtime callbacks. They represent the runtime interface to native bridge.
-  //
-  // The interface is expected to expose the following methods:
-  // getMethodShorty(): in the case of native method calling JNI native function CallXXXXMethodY(),
-  //   native bridge calls back to VM for the shorty of the method so that it can prepare based on
-  //   host calling convention.
-  // getNativeMethodCount() and getNativeMethods(): in case of JNI function UnregisterNatives(),
-  //   native bridge can call back to get all native methods of specified class so that all
-  //   corresponding trampolines can be destroyed.
-  android::NativeBridgeRuntimeCallbacks native_bridge_art_callbacks_;
-
   DISALLOW_COPY_AND_ASSIGN(Runtime);
 };
 
diff --git a/test/115-native-bridge/expected.txt b/test/115-native-bridge/expected.txt
index 808d968..a5eedc6 100644
--- a/test/115-native-bridge/expected.txt
+++ b/test/115-native-bridge/expected.txt
@@ -1,4 +1,5 @@
 Native bridge initialized.
+Checking for getEnvValues.
 Ready for native bridge tests.
 Checking for support.
 Getting trampoline for JNI_OnLoad with shorty (null).
diff --git a/test/115-native-bridge/nativebridge.cc b/test/115-native-bridge/nativebridge.cc
index 3acc643..442f99c 100644
--- a/test/115-native-bridge/nativebridge.cc
+++ b/test/115-native-bridge/nativebridge.cc
@@ -207,7 +207,8 @@
 }
 
 // NativeBridgeCallbacks implementations
-extern "C" bool native_bridge_initialize(const android::NativeBridgeRuntimeCallbacks* art_cbs) {
+extern "C" bool native_bridge_initialize(const android::NativeBridgeRuntimeCallbacks* art_cbs,
+                                         const char* private_dir, const char* isa) {
   if (art_cbs != nullptr) {
     gNativeBridgeArtCallbacks = art_cbs;
     printf("Native bridge initialized.\n");
@@ -263,11 +264,49 @@
   return strcmp(libpath, "libjavacore.so") != 0;
 }
 
+namespace android {
+
+// Environment values required by the apps running with native bridge.
+struct NativeBridgeRuntimeValues {
+  const char* os_arch;
+  const char* cpu_abi;
+  const char* cpu_abi2;
+  const char* *supported_abis;
+  int32_t abi_count;
+};
+
+}  // namespace android
+
+const char* supported_abis[] = {
+    "supported1", "supported2", "supported3"
+};
+
+const struct android::NativeBridgeRuntimeValues nb_env {
+    .os_arch = "os.arch",
+    .cpu_abi = "cpu_abi",
+    .cpu_abi2 = "cpu_abi2",
+    .supported_abis = supported_abis,
+    .abi_count = 3
+};
+
+extern "C" const struct android::NativeBridgeRuntimeValues* native_bridge_getAppEnv(
+    const char* abi) {
+  printf("Checking for getEnvValues.\n");
+
+  if (abi == nullptr) {
+    return nullptr;
+  }
+
+  return &nb_env;
+}
+
 // "NativeBridgeItf" is effectively an API (it is the name of the symbol that will be loaded
 // by the native bridge library).
 android::NativeBridgeCallbacks NativeBridgeItf {
+  .version = 1,
   .initialize = &native_bridge_initialize,
   .loadLibrary = &native_bridge_loadLibrary,
   .getTrampoline = &native_bridge_getTrampoline,
-  .isSupported = &native_bridge_isSupported
+  .isSupported = &native_bridge_isSupported,
+  .getAppEnv = &native_bridge_getAppEnv
 };