From 6d031046eeb5e9f62b657df0695b752e1d0aa583 Mon Sep 17 00:00:00 2001 From: jgu21 Date: Wed, 10 Sep 2014 06:57:17 -0400 Subject: [PATCH] ART: Update for split native bridge initialization (cherry picked from commit a6da74e941d7cee498ac3880018a1d8dc953c6eb) (cherry picked from commit 7a536531791293441253cffb6e370ba1150eee96) Bug: 17671501 Change-Id: Id948e3ab22ac988d96f5d370bba8c3f86d08abff --- runtime/jni_internal.cc | 1 + runtime/native/dalvik_system_ZygoteHooks.cc | 6 ++-- runtime/native_bridge_art_interface.cc | 41 +++++++++++++++++++++++++++ runtime/native_bridge_art_interface.h | 14 +++++++--- runtime/runtime.cc | 25 +++++++++-------- runtime/runtime.h | 14 +--------- test/115-native-bridge/expected.txt | 1 + test/115-native-bridge/nativebridge.cc | 43 +++++++++++++++++++++++++++-- 8 files changed, 112 insertions(+), 33 deletions(-) diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc index 8e3680ce0..73effca15 100644 --- a/runtime/jni_internal.cc +++ b/runtime/jni_internal.cc @@ -43,6 +43,7 @@ #include "mirror/object_array-inl.h" #include "mirror/string-inl.h" #include "mirror/throwable.h" +#include "nativebridge/native_bridge.h" #include "parsed_options.h" #include "reflection.h" #include "runtime.h" diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc index c3b84e3b6..a4ef839ae 100644 --- a/runtime/native/dalvik_system_ZygoteHooks.cc +++ b/runtime/native/dalvik_system_ZygoteHooks.cc @@ -110,15 +110,17 @@ static void ZygoteHooks_nativePostForkChild(JNIEnv* env, jclass, jlong token, ji 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 453c92f49..cc446153c 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,42 @@ uint32_t GetNativeMethods(JNIEnv* env, jclass clazz, JNINativeMethod* methods, 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"; +#ifndef __APPLE__ // Mac OS does not support CLONE_NEWNS. + if (unshare(CLONE_NEWNS) == -1) { + LOG(WARNING) << "Could not create mount namespace."; + return; + } + android::PreInitializeNativeBridge(dir.c_str(), GetInstructionSetString(kRuntimeISA)); +#endif +} + +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 08735c895..42f0ed25e 100644 --- a/runtime/native_bridge_art_interface.h +++ b/runtime/native_bridge_art_interface.h @@ -19,15 +19,21 @@ #include #include +#include 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 5b24a1d59..0a3da84ca 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -146,8 +146,7 @@ Runtime::Runtime() 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() { @@ -425,18 +424,23 @@ bool Runtime::Start() { 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(); @@ -508,16 +512,16 @@ bool Runtime::InitZygote() { #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; } @@ -868,10 +872,7 @@ bool Runtime::Init(const RuntimeOptions& raw_options, bool ignore_unrecognized) // 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 4bf78a288..95ac56274 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" @@ -394,7 +393,7 @@ class Runtime { }; void PreZygoteFork(); bool InitZygote(); - void DidForkFromZygote(NativeBridgeAction action); + void DidForkFromZygote(JNIEnv* env, NativeBridgeAction action, const char* isa); const instrumentation::Instrumentation* GetInstrumentation() const { return &instrumentation_; @@ -643,17 +642,6 @@ class Runtime { // 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 808d968f6..a5eedc6a2 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 3acc643d9..442f99c48 100644 --- a/test/115-native-bridge/nativebridge.cc +++ b/test/115-native-bridge/nativebridge.cc @@ -207,7 +207,8 @@ static NativeBridgeMethod* find_native_bridge_method(const char *name) { } // 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 @@ extern "C" bool native_bridge_isSupported(const char* libpath) { 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 }; -- 2.11.0