blob: de04a99d64f46c93569a4b3ed35ace2fc45c915c [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
37// Is native-bridge support enabled?
38static constexpr bool kNativeBridgeEnabled = false;
39
40// Default library name for native-bridge.
41static constexpr const char* kDefaultNativeBridge = "libnativebridge.so";
42
43#ifdef HAVE_ANDROID_OS
44// TODO: This will be removed once we have native-bridge command-line arguments.
45
46// Property that defines the library name of native-bridge.
47static constexpr const char* kPropNativeBridge = "persist.native.bridge";
48
49// Property that enables native-bridge.
50static constexpr const char* kPropEnableNativeBridge = "persist.enable.native.bridge";
51#endif
52
53// The symbol name exposed by native-bridge with the type of NativeBridgeCallbacks.
54static constexpr const char* kNativeBridgeInterfaceSymbol = "NativeBridgeItf";
55
56// ART interfaces to native-bridge.
57struct NativeBridgeArtCallbacks {
58 // Log utility, reserve unused.
59 int (*logger)(int prio, const char* tag, const char* fmt, ...);
60
61 // Get shorty of a Java method. The shorty is supposed to be persistent in memory.
62 //
63 // Parameters:
64 // env [IN] pointer to JNIenv.
65 // mid [IN] Java methodID.
66 // Returns:
67 // short descriptor for method.
68 const char* (*getMethodShorty)(JNIEnv* env, jmethodID mid);
69
70 // Get number of native methods for specified class.
71 //
72 // Parameters:
73 // env [IN] pointer to JNIenv.
74 // clazz [IN] Java class object.
75 // Returns:
76 // number of native methods.
77 int (*getNativeMethodCount)(JNIEnv* env, jclass clazz);
78
79 // Get at most 'method_count' native methods for specified class 'clazz'. Results are outputed
80 // via 'methods' [OUT]. The signature pointer in JNINativeMethod is reused as the method shorty.
81 //
82 // Parameters:
83 // env [IN] pointer to JNIenv.
84 // clazz [IN] Java class object.
85 // methods [OUT] array of method with the name, shorty, and fnPtr.
86 // method_count [IN] max number of elements in methods.
87 // Returns:
88 // number of method it actually wrote to methods.
89 int (*getNativeMethods)(JNIEnv* env, jclass clazz, JNINativeMethod* methods, uint32_t method_count);
90};
91
92// Native-bridge interfaces to ART
93struct NativeBridgeCallbacks {
94 // Initialize native-bridge. Native-bridge's internal implementation must ensure MT safety and
95 // that the native-bridge is initialized only once. Thus it is OK to call this interface for an
96 // already initialized native-bridge.
97 //
98 // Parameters:
99 // art_cbs [IN] the pointer to NativeBridgeArtCallbacks.
100 // Returns:
101 // true iff initialization was successful.
102 bool (*initialize)(NativeBridgeArtCallbacks* art_cbs);
103
104 // Load a shared library that is supported by the native-bridge.
105 //
106 // Parameters:
107 // libpath [IN] path to the shared library
108 // flag [IN] the stardard RTLD_XXX defined in bionic dlfcn.h
109 // Returns:
110 // The opaque handle of the shared library if sucessful, otherwise NULL
111 void* (*loadLibrary)(const char* libpath, int flag);
112
113 // Get a native-bridge trampoline for specified native method. The trampoline has same
114 // sigature as the native method.
115 //
116 // Parameters:
117 // handle [IN] the handle returned from loadLibrary
118 // shorty [IN] short descriptor of native method
119 // len [IN] length of shorty
120 // Returns:
121 // address of trampoline if successful, otherwise NULL
122 void* (*getTrampoline)(void* handle, const char* name, const char* shorty, uint32_t len);
123
124 // Check whether native library is valid and is for an ABI that is supported by native-bridge.
125 //
126 // Parameters:
127 // libpath [IN] path to the shared library
128 // Returns:
129 // TRUE if library is supported by native-bridge, FALSE otherwise
130 bool (*isSupported)(const char* libpath);
131};
132
133static const char* GetMethodShorty(JNIEnv* env, jmethodID mid) {
134 ScopedObjectAccess soa(env);
135 StackHandleScope<1> scope(soa.Self());
136 mirror::ArtMethod* m = soa.DecodeMethod(mid);
137 MethodHelper mh(scope.NewHandle(m));
138 return mh.GetShorty();
139}
140
141static int GetNativeMethodCount(JNIEnv* env, jclass clazz) {
142 if (clazz == nullptr)
143 return 0;
144
145 ScopedObjectAccess soa(env);
146 mirror::Class* c = soa.Decode<mirror::Class*>(clazz);
147
148 size_t method_count = 0;
149 for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
150 mirror::ArtMethod* m = c->GetDirectMethod(i);
151 if (m->IsNative())
152 method_count++;
153 }
154 for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
155 mirror::ArtMethod* m = c->GetVirtualMethod(i);
156 if (m->IsNative())
157 method_count++;
158 }
159 return method_count;
160}
161
162static int GetNativeMethods(JNIEnv* env, jclass clazz, JNINativeMethod* methods,
163 uint32_t method_count) {
164 if ((clazz == nullptr) || (methods == nullptr))
165 return 0;
166
167 ScopedObjectAccess soa(env);
168 mirror::Class* c = soa.Decode<mirror::Class*>(clazz);
169
170 size_t count = 0;
171 for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
172 mirror::ArtMethod* m = c->GetDirectMethod(i);
173 if (m->IsNative() && count < method_count) {
174 methods[count].name = m->GetName();
175 methods[count].signature = m->GetShorty();
176 methods[count].fnPtr = const_cast<void*>(m->GetNativeMethod());
177 count++;
178 }
179 }
180 for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
181 mirror::ArtMethod* m = c->GetVirtualMethod(i);
182 if (m->IsNative() && 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 }
188 }
189 return count;
190}
191
192NativeBridgeArtCallbacks NativeBridgeArtItf = {
193 nullptr,
194 GetMethodShorty,
195 GetNativeMethodCount,
196 GetNativeMethods
197};
198
199bool NativeBridge::Init() {
200 if (!kNativeBridgeEnabled) {
201 return false;
202 }
203
204 MutexLock mu(Thread::Current(), lock_);
205
206 if (!initialized_) {
207 const char* libnb_path = kDefaultNativeBridge;
208#ifdef HAVE_ANDROID_OS
209 char prop_buf[PROP_VALUE_MAX];
210 property_get(kPropEnableNativeBridge, prop_buf, "false");
211 if (strcmp(prop_buf, "true") != 0)
212 return false;
213
214 // If prop persist.native.bridge set, overwrite the default name.
215 int name_len = property_get(kPropNativeBridge, prop_buf, kDefaultNativeBridge);
216 if (name_len > 0)
217 libnb_path = prop_buf;
218#endif
219 void* handle = dlopen(libnb_path, RTLD_LAZY);
220 if (handle == nullptr)
221 return false;
222
223 callbacks_ = reinterpret_cast<NativeBridgeCallbacks*>(dlsym(handle,
224 kNativeBridgeInterfaceSymbol));
225 if (callbacks_ == nullptr) {
226 dlclose(handle);
227 return false;
228 }
229
230 callbacks_->initialize(&NativeBridgeArtItf);
231 initialized_ = true;
232 }
233
234 return initialized_;
235}
236
237void* NativeBridge::LoadLibrary(const char* libpath, int flag) {
238 if (Init())
239 return callbacks_->loadLibrary(libpath, flag);
240 return nullptr;
241}
242
243void* NativeBridge::GetTrampoline(void* handle, const char* name, const char* shorty,
244 uint32_t len) {
245 if (Init())
246 return callbacks_->getTrampoline(handle, name, shorty, len);
247 return nullptr;
248}
249
250bool NativeBridge::IsSupported(const char* libpath) {
251 if (Init())
252 return callbacks_->isSupported(libpath);
253 return false;
254}
255
256bool NativeBridge::initialized_ = false;
257Mutex NativeBridge::lock_("native bridge lock");
258NativeBridgeCallbacks* NativeBridge::callbacks_ = nullptr;
259
260}; // namespace art