blob: d0b516bf35387dd67c0521d52e6fcba9fc4fc0ab [file] [log] [blame]
Yong WU355383f2014-07-24 21:32:15 +08001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "native_bridge.h"
18
19#include <dlfcn.h>
20#include <stdio.h>
21#include "jni.h"
22
23#include "base/mutex.h"
24#include "mirror/art_method-inl.h"
25#include "mirror/class-inl.h"
26#include "scoped_thread_state_change.h"
27#include "ScopedLocalRef.h"
28#include "thread.h"
29
30#ifdef HAVE_ANDROID_OS
31#include "cutils/properties.h"
32#endif
33
34
35namespace art {
36
Yong WU355383f2014-07-24 21:32:15 +080037// The symbol name exposed by native-bridge with the type of NativeBridgeCallbacks.
38static constexpr const char* kNativeBridgeInterfaceSymbol = "NativeBridgeItf";
39
Ian Rogers68d8b422014-07-17 11:09:10 -070040// The library name we are supposed to load.
41static std::string native_bridge_library_string = "";
42
43// Whether a native bridge is available (loaded and ready).
44static bool available = false;
45// Whether we have already initialized (or tried to).
46static bool initialized = false;
47
48struct NativeBridgeCallbacks;
49static NativeBridgeCallbacks* callbacks = nullptr;
50
Yong WU355383f2014-07-24 21:32:15 +080051// ART interfaces to native-bridge.
52struct NativeBridgeArtCallbacks {
Yong WU355383f2014-07-24 21:32:15 +080053 // Get shorty of a Java method. The shorty is supposed to be persistent in memory.
54 //
55 // Parameters:
56 // env [IN] pointer to JNIenv.
57 // mid [IN] Java methodID.
58 // Returns:
59 // short descriptor for method.
60 const char* (*getMethodShorty)(JNIEnv* env, jmethodID mid);
61
62 // Get number of native methods for specified class.
63 //
64 // Parameters:
65 // env [IN] pointer to JNIenv.
66 // clazz [IN] Java class object.
67 // Returns:
68 // number of native methods.
Ian Rogers68d8b422014-07-17 11:09:10 -070069 uint32_t (*getNativeMethodCount)(JNIEnv* env, jclass clazz);
Yong WU355383f2014-07-24 21:32:15 +080070
71 // Get at most 'method_count' native methods for specified class 'clazz'. Results are outputed
72 // via 'methods' [OUT]. The signature pointer in JNINativeMethod is reused as the method shorty.
73 //
74 // Parameters:
75 // env [IN] pointer to JNIenv.
76 // clazz [IN] Java class object.
77 // methods [OUT] array of method with the name, shorty, and fnPtr.
78 // method_count [IN] max number of elements in methods.
79 // Returns:
80 // number of method it actually wrote to methods.
Ian Rogers68d8b422014-07-17 11:09:10 -070081 uint32_t (*getNativeMethods)(JNIEnv* env, jclass clazz, JNINativeMethod* methods,
82 uint32_t method_count);
Yong WU355383f2014-07-24 21:32:15 +080083};
84
85// Native-bridge interfaces to ART
86struct NativeBridgeCallbacks {
87 // Initialize native-bridge. Native-bridge's internal implementation must ensure MT safety and
88 // that the native-bridge is initialized only once. Thus it is OK to call this interface for an
89 // already initialized native-bridge.
90 //
91 // Parameters:
92 // art_cbs [IN] the pointer to NativeBridgeArtCallbacks.
93 // Returns:
94 // true iff initialization was successful.
95 bool (*initialize)(NativeBridgeArtCallbacks* art_cbs);
96
97 // Load a shared library that is supported by the native-bridge.
98 //
99 // Parameters:
100 // libpath [IN] path to the shared library
101 // flag [IN] the stardard RTLD_XXX defined in bionic dlfcn.h
102 // Returns:
103 // The opaque handle of the shared library if sucessful, otherwise NULL
104 void* (*loadLibrary)(const char* libpath, int flag);
105
106 // Get a native-bridge trampoline for specified native method. The trampoline has same
107 // sigature as the native method.
108 //
109 // Parameters:
110 // handle [IN] the handle returned from loadLibrary
111 // shorty [IN] short descriptor of native method
112 // len [IN] length of shorty
113 // Returns:
114 // address of trampoline if successful, otherwise NULL
115 void* (*getTrampoline)(void* handle, const char* name, const char* shorty, uint32_t len);
116
117 // Check whether native library is valid and is for an ABI that is supported by native-bridge.
118 //
119 // Parameters:
120 // libpath [IN] path to the shared library
121 // Returns:
122 // TRUE if library is supported by native-bridge, FALSE otherwise
123 bool (*isSupported)(const char* libpath);
124};
125
126static const char* GetMethodShorty(JNIEnv* env, jmethodID mid) {
127 ScopedObjectAccess soa(env);
128 StackHandleScope<1> scope(soa.Self());
129 mirror::ArtMethod* m = soa.DecodeMethod(mid);
130 MethodHelper mh(scope.NewHandle(m));
131 return mh.GetShorty();
132}
133
Ian Rogers68d8b422014-07-17 11:09:10 -0700134static uint32_t GetNativeMethodCount(JNIEnv* env, jclass clazz) {
Yong WU355383f2014-07-24 21:32:15 +0800135 if (clazz == nullptr)
136 return 0;
137
138 ScopedObjectAccess soa(env);
139 mirror::Class* c = soa.Decode<mirror::Class*>(clazz);
140
Ian Rogers68d8b422014-07-17 11:09:10 -0700141 uint32_t native_method_count = 0;
142 for (uint32_t i = 0; i < c->NumDirectMethods(); ++i) {
Yong WU355383f2014-07-24 21:32:15 +0800143 mirror::ArtMethod* m = c->GetDirectMethod(i);
Ian Rogers68d8b422014-07-17 11:09:10 -0700144 if (m->IsNative()) {
145 native_method_count++;
146 }
Yong WU355383f2014-07-24 21:32:15 +0800147 }
Ian Rogers68d8b422014-07-17 11:09:10 -0700148 for (uint32_t i = 0; i < c->NumVirtualMethods(); ++i) {
Yong WU355383f2014-07-24 21:32:15 +0800149 mirror::ArtMethod* m = c->GetVirtualMethod(i);
Ian Rogers68d8b422014-07-17 11:09:10 -0700150 if (m->IsNative()) {
151 native_method_count++;
152 }
Yong WU355383f2014-07-24 21:32:15 +0800153 }
Ian Rogers68d8b422014-07-17 11:09:10 -0700154 return native_method_count;
Yong WU355383f2014-07-24 21:32:15 +0800155}
156
Ian Rogers68d8b422014-07-17 11:09:10 -0700157static uint32_t GetNativeMethods(JNIEnv* env, jclass clazz, JNINativeMethod* methods,
158 uint32_t method_count) {
159 if ((clazz == nullptr) || (methods == nullptr)) {
Yong WU355383f2014-07-24 21:32:15 +0800160 return 0;
Ian Rogers68d8b422014-07-17 11:09:10 -0700161 }
Yong WU355383f2014-07-24 21:32:15 +0800162 ScopedObjectAccess soa(env);
163 mirror::Class* c = soa.Decode<mirror::Class*>(clazz);
164
Ian Rogers68d8b422014-07-17 11:09:10 -0700165 uint32_t count = 0;
166 for (uint32_t i = 0; i < c->NumDirectMethods(); ++i) {
Yong WU355383f2014-07-24 21:32:15 +0800167 mirror::ArtMethod* m = c->GetDirectMethod(i);
Ian Rogers68d8b422014-07-17 11:09:10 -0700168 if (m->IsNative()) {
169 if (count < method_count) {
170 methods[count].name = m->GetName();
171 methods[count].signature = m->GetShorty();
172 methods[count].fnPtr = const_cast<void*>(m->GetNativeMethod());
173 count++;
174 } else {
175 LOG(WARNING) << "Output native method array too small. Skipping " << PrettyMethod(m);
176 }
Yong WU355383f2014-07-24 21:32:15 +0800177 }
178 }
Ian Rogers68d8b422014-07-17 11:09:10 -0700179 for (uint32_t i = 0; i < c->NumVirtualMethods(); ++i) {
Yong WU355383f2014-07-24 21:32:15 +0800180 mirror::ArtMethod* m = c->GetVirtualMethod(i);
Ian Rogers68d8b422014-07-17 11:09:10 -0700181 if (m->IsNative()) {
182 if (count < method_count) {
183 methods[count].name = m->GetName();
184 methods[count].signature = m->GetShorty();
185 methods[count].fnPtr = const_cast<void*>(m->GetNativeMethod());
186 count++;
187 } else {
188 LOG(WARNING) << "Output native method array too small. Skipping " << PrettyMethod(m);
189 }
Yong WU355383f2014-07-24 21:32:15 +0800190 }
191 }
192 return count;
193}
194
Calin Juravle421b6462014-08-07 14:53:41 +0100195static NativeBridgeArtCallbacks NativeBridgeArtItf = {
Yong WU355383f2014-07-24 21:32:15 +0800196 GetMethodShorty,
197 GetNativeMethodCount,
198 GetNativeMethods
199};
200
Ian Rogers68d8b422014-07-17 11:09:10 -0700201void SetNativeBridgeLibraryString(const std::string& nb_library_string) {
Calin Juravle421b6462014-08-07 14:53:41 +0100202 // This is called when the runtime starts and nothing is working concurrently
203 // so we don't need a lock here.
204
Ian Rogers68d8b422014-07-17 11:09:10 -0700205 native_bridge_library_string = nb_library_string;
Calin Juravle421b6462014-08-07 14:53:41 +0100206
207 if (native_bridge_library_string.empty()) {
208 initialized = true;
209 available = false;
210 }
Andreas Gampe855564b2014-07-25 02:32:19 -0700211}
212
Calin Juravle421b6462014-08-07 14:53:41 +0100213static bool NativeBridgeInitialize() {
Ian Rogers68d8b422014-07-17 11:09:10 -0700214 // TODO: Missing annotalysis static lock ordering of DEFAULT_MUTEX_ACQUIRED, place lock into
215 // global order or remove.
216 static Mutex lock("native bridge lock");
217 MutexLock mu(Thread::Current(), lock);
Yong WU355383f2014-07-24 21:32:15 +0800218
Ian Rogers68d8b422014-07-17 11:09:10 -0700219 if (initialized) {
Andreas Gampe855564b2014-07-25 02:32:19 -0700220 // Somebody did it before.
Ian Rogers68d8b422014-07-17 11:09:10 -0700221 return available;
Andreas Gampe855564b2014-07-25 02:32:19 -0700222 }
223
Ian Rogers68d8b422014-07-17 11:09:10 -0700224 available = false;
Andreas Gampe855564b2014-07-25 02:32:19 -0700225
Calin Juravle421b6462014-08-07 14:53:41 +0100226 void* handle = dlopen(native_bridge_library_string.c_str(), RTLD_LAZY);
Andreas Gampe855564b2014-07-25 02:32:19 -0700227 if (handle != nullptr) {
Ian Rogers68d8b422014-07-17 11:09:10 -0700228 callbacks = reinterpret_cast<NativeBridgeCallbacks*>(dlsym(handle,
229 kNativeBridgeInterfaceSymbol));
Andreas Gampe855564b2014-07-25 02:32:19 -0700230
Ian Rogers68d8b422014-07-17 11:09:10 -0700231 if (callbacks != nullptr) {
232 available = callbacks->initialize(&NativeBridgeArtItf);
Andreas Gampe855564b2014-07-25 02:32:19 -0700233 }
234
Ian Rogers68d8b422014-07-17 11:09:10 -0700235 if (!available) {
Andreas Gampe855564b2014-07-25 02:32:19 -0700236 dlclose(handle);
237 }
238 }
239
Ian Rogers68d8b422014-07-17 11:09:10 -0700240 initialized = true;
Andreas Gampe855564b2014-07-25 02:32:19 -0700241
Ian Rogers68d8b422014-07-17 11:09:10 -0700242 return available;
Yong WU355383f2014-07-24 21:32:15 +0800243}
244
Ian Rogers68d8b422014-07-17 11:09:10 -0700245void* NativeBridgeLoadLibrary(const char* libpath, int flag) {
246 if (NativeBridgeInitialize()) {
247 return callbacks->loadLibrary(libpath, flag);
248 }
Yong WU355383f2014-07-24 21:32:15 +0800249 return nullptr;
250}
251
Ian Rogers68d8b422014-07-17 11:09:10 -0700252void* NativeBridgeGetTrampoline(void* handle, const char* name, const char* shorty,
Yong WU355383f2014-07-24 21:32:15 +0800253 uint32_t len) {
Ian Rogers68d8b422014-07-17 11:09:10 -0700254 if (NativeBridgeInitialize()) {
255 return callbacks->getTrampoline(handle, name, shorty, len);
256 }
Yong WU355383f2014-07-24 21:32:15 +0800257 return nullptr;
258}
259
Ian Rogers68d8b422014-07-17 11:09:10 -0700260bool NativeBridgeIsSupported(const char* libpath) {
261 if (NativeBridgeInitialize()) {
262 return callbacks->isSupported(libpath);
263 }
Yong WU355383f2014-07-24 21:32:15 +0800264 return false;
265}
266
Yong WU355383f2014-07-24 21:32:15 +0800267}; // namespace art