|  | /* | 
|  | * 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" | 
|  | #include "base/macros.h" | 
|  | #include "dex_file-inl.h" | 
|  | #include "mirror/class-inl.h" | 
|  | #include "scoped_thread_state_change.h" | 
|  | #include "sigchain.h" | 
|  |  | 
|  | namespace art { | 
|  |  | 
|  | static const char* GetMethodShorty(JNIEnv* env, jmethodID mid) { | 
|  | ScopedObjectAccess soa(env); | 
|  | ArtMethod* m = soa.DecodeMethod(mid); | 
|  | return m->GetShorty(); | 
|  | } | 
|  |  | 
|  | static uint32_t GetNativeMethodCount(JNIEnv* env, jclass clazz) { | 
|  | if (clazz == nullptr) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | ScopedObjectAccess soa(env); | 
|  | mirror::Class* c = soa.Decode<mirror::Class*>(clazz); | 
|  |  | 
|  | uint32_t native_method_count = 0; | 
|  | for (auto& m : c->GetDirectMethods(sizeof(void*))) { | 
|  | native_method_count += m.IsNative() ? 1u : 0u; | 
|  | } | 
|  | for (auto& m : c->GetVirtualMethods(sizeof(void*))) { | 
|  | 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); | 
|  | mirror::Class* c = soa.Decode<mirror::Class*>(clazz); | 
|  |  | 
|  | uint32_t count = 0; | 
|  | for (auto& m : c->GetDirectMethods(sizeof(void*))) { | 
|  | 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 " << PrettyMethod(&m); | 
|  | } | 
|  | } | 
|  | } | 
|  | for (auto& m : c->GetVirtualMethods(sizeof(void*))) { | 
|  | 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 " << PrettyMethod(&m); | 
|  | } | 
|  | } | 
|  | } | 
|  | 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(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(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 InitializeNativeBridge(JNIEnv* env, const char* instruction_set) { | 
|  | 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) { | 
|  | SetSpecialSignalHandlerFn(signal, fn); | 
|  | } | 
|  | } | 
|  | #endif | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void UnloadNativeBridge() { | 
|  | android::UnloadNativeBridge(); | 
|  | } | 
|  |  | 
|  | }  // namespace art |