| /* | |
| * 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. | |
| */ | |
| #include "native_bridge_art_interface.h" | |
| #include <signal.h> | |
| #include "nativebridge/native_bridge.h" | |
| #include "art_method-inl.h" | |
| #include "base/logging.h" // For VLOG. | |
| #include "base/macros.h" | |
| #include "base/pointer_size.h" | |
| #include "dex/dex_file-inl.h" | |
| #include "jni/jni_internal.h" | |
| #include "mirror/class-inl.h" | |
| #include "scoped_thread_state_change-inl.h" | |
| #include "sigchain.h" | |
| namespace art HIDDEN { | |
| static const char* GetMethodShorty(JNIEnv* env, jmethodID mid) { | |
| ScopedObjectAccess soa(env); | |
| ArtMethod* m = jni::DecodeArtMethod(mid); | |
| return m->GetShorty(); | |
| } | |
| static uint32_t GetNativeMethodCount(JNIEnv* env, jclass clazz) { | |
| if (clazz == nullptr) { | |
| return 0; | |
| } | |
| ScopedObjectAccess soa(env); | |
| ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(clazz); | |
| uint32_t native_method_count = 0; | |
| for (auto& m : c->GetMethods(kRuntimePointerSize)) { | |
| native_method_count += m.IsNative() ? 1u : 0u; | |
| } | |
| return native_method_count; | |
| } | |
| static uint32_t GetNativeMethods(JNIEnv* env, jclass clazz, JNINativeMethod* methods, | |
| uint32_t method_count) { | |
| if ((clazz == nullptr) || (methods == nullptr)) { | |
| return 0; | |
| } | |
| ScopedObjectAccess soa(env); | |
| ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(clazz); | |
| uint32_t count = 0; | |
| for (auto& m : c->GetMethods(kRuntimePointerSize)) { | |
| if (m.IsNative()) { | |
| if (count < method_count) { | |
| methods[count].name = m.GetName(); | |
| methods[count].signature = m.GetShorty(); | |
| methods[count].fnPtr = m.GetEntryPointFromJni(); | |
| count++; | |
| } else { | |
| LOG(WARNING) << "Output native method array too small. Skipping " | |
| << m.PrettyMethod(); | |
| } | |
| } | |
| } | |
| 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 | |
| }; | |
| bool LoadNativeBridge(const std::string& native_bridge_library_filename) { | |
| VLOG(startup) << "Runtime::Setup native bridge library: " | |
| << (native_bridge_library_filename.empty() ? "(empty)" : native_bridge_library_filename); | |
| return android::LoadNativeBridge(native_bridge_library_filename.c_str(), | |
| &native_bridge_art_callbacks_); | |
| } | |
| void PreInitializeNativeBridge(const 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."; | |
| } | |
| android::PreInitializeNativeBridge(dir.c_str(), GetInstructionSetString(kRuntimeISA)); | |
| #else | |
| UNUSED(dir); | |
| #endif | |
| } | |
| void PreZygoteForkNativeBridge() { | |
| android::PreZygoteForkNativeBridge(); | |
| } | |
| void InitializeNativeBridge(JNIEnv* env, const char* instruction_set) { | |
| if (android::NativeBridgeInitialized()) { | |
| // This happens in apps forked from app-zygote, since native bridge | |
| // is initialized in the zygote. | |
| return; | |
| } | |
| if (android::InitializeNativeBridge(env, instruction_set)) { | |
| if (android::NativeBridgeGetVersion() >= 2U) { | |
| #ifdef _NSIG // Undefined on Apple, but we don't support running on Mac, anyways. | |
| // Managed signal handling support added in version 2. | |
| for (int signal = 0; signal < _NSIG; ++signal) { | |
| android::NativeBridgeSignalHandlerFn fn = android::NativeBridgeGetSignalHandler(signal); | |
| if (fn != nullptr) { | |
| sigset_t mask; | |
| sigfillset(&mask); | |
| SigchainAction sa = { | |
| .sc_sigaction = fn, | |
| .sc_mask = mask, | |
| // The native bridge signal might not return back to sigchain's handler. | |
| .sc_flags = SIGCHAIN_ALLOW_NORETURN, | |
| }; | |
| AddSpecialSignalHandlerFn(signal, &sa); | |
| } | |
| } | |
| #endif | |
| } | |
| } | |
| } | |
| void UnloadNativeBridge() { | |
| android::UnloadNativeBridge(); | |
| } | |
| } // namespace art |