blob: ad26ee4e9b982141ddbe7a09a9e91d8c7ae7c1fb [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?
Andreas Gampe855564b2014-07-25 02:32:19 -070038static constexpr bool kNativeBridgeEnabled = true;
Yong WU355383f2014-07-24 21:32:15 +080039
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 {
Yong WU355383f2014-07-24 21:32:15 +080058 // Get shorty of a Java method. The shorty is supposed to be persistent in memory.
59 //
60 // Parameters:
61 // env [IN] pointer to JNIenv.
62 // mid [IN] Java methodID.
63 // Returns:
64 // short descriptor for method.
65 const char* (*getMethodShorty)(JNIEnv* env, jmethodID mid);
66
67 // Get number of native methods for specified class.
68 //
69 // Parameters:
70 // env [IN] pointer to JNIenv.
71 // clazz [IN] Java class object.
72 // Returns:
73 // number of native methods.
74 int (*getNativeMethodCount)(JNIEnv* env, jclass clazz);
75
76 // Get at most 'method_count' native methods for specified class 'clazz'. Results are outputed
77 // via 'methods' [OUT]. The signature pointer in JNINativeMethod is reused as the method shorty.
78 //
79 // Parameters:
80 // env [IN] pointer to JNIenv.
81 // clazz [IN] Java class object.
82 // methods [OUT] array of method with the name, shorty, and fnPtr.
83 // method_count [IN] max number of elements in methods.
84 // Returns:
85 // number of method it actually wrote to methods.
86 int (*getNativeMethods)(JNIEnv* env, jclass clazz, JNINativeMethod* methods, uint32_t method_count);
87};
88
89// Native-bridge interfaces to ART
90struct NativeBridgeCallbacks {
91 // Initialize native-bridge. Native-bridge's internal implementation must ensure MT safety and
92 // that the native-bridge is initialized only once. Thus it is OK to call this interface for an
93 // already initialized native-bridge.
94 //
95 // Parameters:
96 // art_cbs [IN] the pointer to NativeBridgeArtCallbacks.
97 // Returns:
98 // true iff initialization was successful.
99 bool (*initialize)(NativeBridgeArtCallbacks* art_cbs);
100
101 // Load a shared library that is supported by the native-bridge.
102 //
103 // Parameters:
104 // libpath [IN] path to the shared library
105 // flag [IN] the stardard RTLD_XXX defined in bionic dlfcn.h
106 // Returns:
107 // The opaque handle of the shared library if sucessful, otherwise NULL
108 void* (*loadLibrary)(const char* libpath, int flag);
109
110 // Get a native-bridge trampoline for specified native method. The trampoline has same
111 // sigature as the native method.
112 //
113 // Parameters:
114 // handle [IN] the handle returned from loadLibrary
115 // shorty [IN] short descriptor of native method
116 // len [IN] length of shorty
117 // Returns:
118 // address of trampoline if successful, otherwise NULL
119 void* (*getTrampoline)(void* handle, const char* name, const char* shorty, uint32_t len);
120
121 // Check whether native library is valid and is for an ABI that is supported by native-bridge.
122 //
123 // Parameters:
124 // libpath [IN] path to the shared library
125 // Returns:
126 // TRUE if library is supported by native-bridge, FALSE otherwise
127 bool (*isSupported)(const char* libpath);
128};
129
130static const char* GetMethodShorty(JNIEnv* env, jmethodID mid) {
131 ScopedObjectAccess soa(env);
132 StackHandleScope<1> scope(soa.Self());
133 mirror::ArtMethod* m = soa.DecodeMethod(mid);
134 MethodHelper mh(scope.NewHandle(m));
135 return mh.GetShorty();
136}
137
138static int GetNativeMethodCount(JNIEnv* env, jclass clazz) {
139 if (clazz == nullptr)
140 return 0;
141
142 ScopedObjectAccess soa(env);
143 mirror::Class* c = soa.Decode<mirror::Class*>(clazz);
144
145 size_t method_count = 0;
146 for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
147 mirror::ArtMethod* m = c->GetDirectMethod(i);
148 if (m->IsNative())
149 method_count++;
150 }
151 for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
152 mirror::ArtMethod* m = c->GetVirtualMethod(i);
153 if (m->IsNative())
154 method_count++;
155 }
156 return method_count;
157}
158
159static int GetNativeMethods(JNIEnv* env, jclass clazz, JNINativeMethod* methods,
160 uint32_t method_count) {
161 if ((clazz == nullptr) || (methods == nullptr))
162 return 0;
163
164 ScopedObjectAccess soa(env);
165 mirror::Class* c = soa.Decode<mirror::Class*>(clazz);
166
167 size_t count = 0;
168 for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
169 mirror::ArtMethod* m = c->GetDirectMethod(i);
170 if (m->IsNative() && count < method_count) {
171 methods[count].name = m->GetName();
172 methods[count].signature = m->GetShorty();
173 methods[count].fnPtr = const_cast<void*>(m->GetNativeMethod());
174 count++;
175 }
176 }
177 for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
178 mirror::ArtMethod* m = c->GetVirtualMethod(i);
179 if (m->IsNative() && count < method_count) {
180 methods[count].name = m->GetName();
181 methods[count].signature = m->GetShorty();
182 methods[count].fnPtr = const_cast<void*>(m->GetNativeMethod());
183 count++;
184 }
185 }
186 return count;
187}
188
189NativeBridgeArtCallbacks NativeBridgeArtItf = {
Yong WU355383f2014-07-24 21:32:15 +0800190 GetMethodShorty,
191 GetNativeMethodCount,
192 GetNativeMethods
193};
194
Andreas Gampe855564b2014-07-25 02:32:19 -0700195void NativeBridge::SetNativeBridgeLibraryString(std::string& native_bridge_library_string) {
196 native_bridge_library_string_ = native_bridge_library_string;
197 // TODO: when given an empty string, set initialized_ to true and available_ to false. This
198 // change is dependent on the property removal in Initialize().
199}
200
201bool NativeBridge::Initialize() {
Yong WU355383f2014-07-24 21:32:15 +0800202 if (!kNativeBridgeEnabled) {
203 return false;
204 }
205
206 MutexLock mu(Thread::Current(), lock_);
207
Andreas Gampe855564b2014-07-25 02:32:19 -0700208 if (initialized_) {
209 // Somebody did it before.
210 return available_;
211 }
212
213 available_ = false;
214
215 const char* libnb_path;
216
217 if (!native_bridge_library_string_.empty()) {
218 libnb_path = native_bridge_library_string_.c_str();
219 } else {
220 // TODO: Remove this once the frameworks side is completely implemented.
221
222 libnb_path = kDefaultNativeBridge;
Yong WU355383f2014-07-24 21:32:15 +0800223#ifdef HAVE_ANDROID_OS
224 char prop_buf[PROP_VALUE_MAX];
225 property_get(kPropEnableNativeBridge, prop_buf, "false");
Andreas Gampe855564b2014-07-25 02:32:19 -0700226 if (strcmp(prop_buf, "true") != 0) {
227 initialized_ = true;
Yong WU355383f2014-07-24 21:32:15 +0800228 return false;
Andreas Gampe855564b2014-07-25 02:32:19 -0700229 }
Yong WU355383f2014-07-24 21:32:15 +0800230
231 // If prop persist.native.bridge set, overwrite the default name.
232 int name_len = property_get(kPropNativeBridge, prop_buf, kDefaultNativeBridge);
233 if (name_len > 0)
234 libnb_path = prop_buf;
235#endif
Yong WU355383f2014-07-24 21:32:15 +0800236 }
237
Andreas Gampe855564b2014-07-25 02:32:19 -0700238 void* handle = dlopen(libnb_path, RTLD_LAZY);
239 if (handle != nullptr) {
240 callbacks_ = reinterpret_cast<NativeBridgeCallbacks*>(dlsym(handle,
241 kNativeBridgeInterfaceSymbol));
242
243 if (callbacks_ != nullptr) {
244 available_ = callbacks_->initialize(&NativeBridgeArtItf);
245 }
246
247 if (!available_) {
248 dlclose(handle);
249 }
250 }
251
252 initialized_ = true;
253
254 return available_;
Yong WU355383f2014-07-24 21:32:15 +0800255}
256
257void* NativeBridge::LoadLibrary(const char* libpath, int flag) {
Andreas Gampe855564b2014-07-25 02:32:19 -0700258 if (Initialize())
Yong WU355383f2014-07-24 21:32:15 +0800259 return callbacks_->loadLibrary(libpath, flag);
260 return nullptr;
261}
262
263void* NativeBridge::GetTrampoline(void* handle, const char* name, const char* shorty,
264 uint32_t len) {
Andreas Gampe855564b2014-07-25 02:32:19 -0700265 if (Initialize())
Yong WU355383f2014-07-24 21:32:15 +0800266 return callbacks_->getTrampoline(handle, name, shorty, len);
267 return nullptr;
268}
269
270bool NativeBridge::IsSupported(const char* libpath) {
Andreas Gampe855564b2014-07-25 02:32:19 -0700271 if (Initialize())
Yong WU355383f2014-07-24 21:32:15 +0800272 return callbacks_->isSupported(libpath);
273 return false;
274}
275
Andreas Gampe855564b2014-07-25 02:32:19 -0700276bool NativeBridge::available_ = false;
Yong WU355383f2014-07-24 21:32:15 +0800277bool NativeBridge::initialized_ = false;
278Mutex NativeBridge::lock_("native bridge lock");
Andreas Gampe855564b2014-07-25 02:32:19 -0700279std::string NativeBridge::native_bridge_library_string_ = "";
Yong WU355383f2014-07-24 21:32:15 +0800280NativeBridgeCallbacks* NativeBridge::callbacks_ = nullptr;
281
282}; // namespace art