blob: 32b2d27db3ecded08edfcaccaf6d91365cdd2411 [file] [log] [blame]
Calin Juravle961ae122014-08-11 16:11:59 +01001/*
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
Mark Salyzyncfd5b082016-10-17 14:28:00 -070017#define LOG_TAG "nativebridge"
18
Calin Juravle961ae122014-08-11 16:11:59 +010019#include "nativebridge/native_bridge.h"
20
21#include <dlfcn.h>
jgu21ab0da5a2014-09-10 06:58:32 -040022#include <errno.h>
23#include <fcntl.h>
Calin Juravle961ae122014-08-11 16:11:59 +010024#include <stdio.h>
jgu21ab0da5a2014-09-10 06:58:32 -040025#include <sys/mount.h>
26#include <sys/stat.h>
Mark Salyzyncfd5b082016-10-17 14:28:00 -070027#include <unistd.h>
Calin Juravle961ae122014-08-11 16:11:59 +010028
Mark Salyzyn66ce3e02016-09-28 10:07:20 -070029#include <cstring>
30
31#include <android/log.h>
Calin Juravle961ae122014-08-11 16:11:59 +010032
33namespace android {
34
jgu21ab0da5a2014-09-10 06:58:32 -040035// Environment values required by the apps running with native bridge.
36struct NativeBridgeRuntimeValues {
37 const char* os_arch;
38 const char* cpu_abi;
39 const char* cpu_abi2;
40 const char* *supported_abis;
41 int32_t abi_count;
42};
43
Calin Juravle961ae122014-08-11 16:11:59 +010044// The symbol name exposed by native-bridge with the type of NativeBridgeCallbacks.
45static constexpr const char* kNativeBridgeInterfaceSymbol = "NativeBridgeItf";
46
Andreas Gampe035bd752014-09-02 21:17:03 -070047enum class NativeBridgeState {
48 kNotSetup, // Initial state.
49 kOpened, // After successful dlopen.
Calin Juravlef9d9e2a2014-10-17 13:45:39 +010050 kPreInitialized, // After successful pre-initialization.
Andreas Gampe035bd752014-09-02 21:17:03 -070051 kInitialized, // After successful initialization.
52 kClosed // Closed or errors.
53};
Calin Juravle961ae122014-08-11 16:11:59 +010054
Calin Juravlef9d9e2a2014-10-17 13:45:39 +010055static constexpr const char* kNotSetupString = "kNotSetup";
56static constexpr const char* kOpenedString = "kOpened";
57static constexpr const char* kPreInitializedString = "kPreInitialized";
58static constexpr const char* kInitializedString = "kInitialized";
59static constexpr const char* kClosedString = "kClosed";
Andreas Gampe035bd752014-09-02 21:17:03 -070060
61static const char* GetNativeBridgeStateString(NativeBridgeState state) {
62 switch (state) {
63 case NativeBridgeState::kNotSetup:
64 return kNotSetupString;
65
66 case NativeBridgeState::kOpened:
67 return kOpenedString;
68
Calin Juravlef9d9e2a2014-10-17 13:45:39 +010069 case NativeBridgeState::kPreInitialized:
70 return kPreInitializedString;
71
Andreas Gampe035bd752014-09-02 21:17:03 -070072 case NativeBridgeState::kInitialized:
73 return kInitializedString;
74
75 case NativeBridgeState::kClosed:
76 return kClosedString;
77 }
78}
79
80// Current state of the native bridge.
81static NativeBridgeState state = NativeBridgeState::kNotSetup;
82
Andreas Gampe049249c2014-08-19 22:31:31 -070083// Whether we had an error at some point.
84static bool had_error = false;
Calin Juravle961ae122014-08-11 16:11:59 +010085
Andreas Gampe035bd752014-09-02 21:17:03 -070086// Handle of the loaded library.
87static void* native_bridge_handle = nullptr;
88// Pointer to the callbacks. Available as soon as LoadNativeBridge succeeds, but only initialized
89// later.
Andreas Gampea6ac9ce2015-04-30 20:39:12 -070090static const NativeBridgeCallbacks* callbacks = nullptr;
Andreas Gampe035bd752014-09-02 21:17:03 -070091// Callbacks provided by the environment to the bridge. Passed to LoadNativeBridge.
Calin Juravle961ae122014-08-11 16:11:59 +010092static const NativeBridgeRuntimeCallbacks* runtime_callbacks = nullptr;
93
Calin Juravlef9d9e2a2014-10-17 13:45:39 +010094// The app's code cache directory.
95static char* app_code_cache_dir = nullptr;
96
97// Code cache directory (relative to the application private directory)
98// Ideally we'd like to call into framework to retrieve this name. However that's considered an
99// implementation detail and will require either hacks or consistent refactorings. We compromise
100// and hard code the directory name again here.
101static constexpr const char* kCodeCacheDir = "code_cache";
jgu21ab0da5a2014-09-10 06:58:32 -0400102
Andreas Gampea6ac9ce2015-04-30 20:39:12 -0700103static constexpr uint32_t kLibNativeBridgeVersion = 2;
jgu21ab0da5a2014-09-10 06:58:32 -0400104
Andreas Gampe049249c2014-08-19 22:31:31 -0700105// Characters allowed in a native bridge filename. The first character must
106// be in [a-zA-Z] (expected 'l' for "libx"). The rest must be in [a-zA-Z0-9._-].
107static bool CharacterAllowed(char c, bool first) {
108 if (first) {
109 return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
110 } else {
111 return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') ||
112 (c == '.') || (c == '_') || (c == '-');
113 }
114}
115
jgu21cef898f2015-07-02 12:02:11 +0800116static void ReleaseAppCodeCacheDir() {
117 if (app_code_cache_dir != nullptr) {
118 delete[] app_code_cache_dir;
119 app_code_cache_dir = nullptr;
120 }
121}
122
Andreas Gampe049249c2014-08-19 22:31:31 -0700123// We only allow simple names for the library. It is supposed to be a file in
124// /system/lib or /vendor/lib. Only allow a small range of characters, that is
125// names consisting of [a-zA-Z0-9._-] and starting with [a-zA-Z].
126bool NativeBridgeNameAcceptable(const char* nb_library_filename) {
127 const char* ptr = nb_library_filename;
128 if (*ptr == 0) {
129 // Emptry string. Allowed, means no native bridge.
130 return true;
131 } else {
132 // First character must be [a-zA-Z].
133 if (!CharacterAllowed(*ptr, true)) {
134 // Found an invalid fist character, don't accept.
Andreas Gampea6ac9ce2015-04-30 20:39:12 -0700135 ALOGE("Native bridge library %s has been rejected for first character %c",
136 nb_library_filename,
137 *ptr);
Andreas Gampe049249c2014-08-19 22:31:31 -0700138 return false;
139 } else {
140 // For the rest, be more liberal.
141 ptr++;
142 while (*ptr != 0) {
143 if (!CharacterAllowed(*ptr, false)) {
144 // Found an invalid character, don't accept.
145 ALOGE("Native bridge library %s has been rejected for %c", nb_library_filename, *ptr);
146 return false;
147 }
148 ptr++;
149 }
150 }
151 return true;
152 }
153}
154
Andreas Gampea6ac9ce2015-04-30 20:39:12 -0700155static bool VersionCheck(const NativeBridgeCallbacks* cb) {
156 // Libnativebridge is now designed to be forward-compatible. So only "0" is an unsupported
157 // version.
158 if (cb == nullptr || cb->version == 0) {
159 return false;
160 }
161
162 // If this is a v2+ bridge, it may not be forwards- or backwards-compatible. Check.
163 if (cb->version >= 2) {
164 if (!callbacks->isCompatibleWith(kLibNativeBridgeVersion)) {
165 // TODO: Scan which version is supported, and fall back to handle it.
166 return false;
167 }
168 }
169
170 return true;
jgu21ab0da5a2014-09-10 06:58:32 -0400171}
172
Calin Juravlef9d9e2a2014-10-17 13:45:39 +0100173static void CloseNativeBridge(bool with_error) {
174 state = NativeBridgeState::kClosed;
175 had_error |= with_error;
jgu21cef898f2015-07-02 12:02:11 +0800176 ReleaseAppCodeCacheDir();
Calin Juravlef9d9e2a2014-10-17 13:45:39 +0100177}
178
Andreas Gampe035bd752014-09-02 21:17:03 -0700179bool LoadNativeBridge(const char* nb_library_filename,
180 const NativeBridgeRuntimeCallbacks* runtime_cbs) {
181 // We expect only one place that calls LoadNativeBridge: Runtime::Init. At that point we are not
182 // multi-threaded, so we do not need locking here.
Calin Juravle961ae122014-08-11 16:11:59 +0100183
Andreas Gampe035bd752014-09-02 21:17:03 -0700184 if (state != NativeBridgeState::kNotSetup) {
Andreas Gampe049249c2014-08-19 22:31:31 -0700185 // Setup has been called before. Ignore this call.
jgu21ab0da5a2014-09-10 06:58:32 -0400186 if (nb_library_filename != nullptr) { // Avoids some log-spam for dalvikvm.
187 ALOGW("Called LoadNativeBridge for an already set up native bridge. State is %s.",
188 GetNativeBridgeStateString(state));
189 }
Andreas Gampe049249c2014-08-19 22:31:31 -0700190 // Note: counts as an error, even though the bridge may be functional.
191 had_error = true;
Andreas Gampe049249c2014-08-19 22:31:31 -0700192 return false;
193 }
194
Andreas Gampe035bd752014-09-02 21:17:03 -0700195 if (nb_library_filename == nullptr || *nb_library_filename == 0) {
Calin Juravlef9d9e2a2014-10-17 13:45:39 +0100196 CloseNativeBridge(false);
197 return false;
Andreas Gampe035bd752014-09-02 21:17:03 -0700198 } else {
199 if (!NativeBridgeNameAcceptable(nb_library_filename)) {
Calin Juravlef9d9e2a2014-10-17 13:45:39 +0100200 CloseNativeBridge(true);
Andreas Gampe035bd752014-09-02 21:17:03 -0700201 } else {
202 // Try to open the library.
203 void* handle = dlopen(nb_library_filename, RTLD_LAZY);
204 if (handle != nullptr) {
205 callbacks = reinterpret_cast<NativeBridgeCallbacks*>(dlsym(handle,
206 kNativeBridgeInterfaceSymbol));
207 if (callbacks != nullptr) {
jgu21ab0da5a2014-09-10 06:58:32 -0400208 if (VersionCheck(callbacks)) {
209 // Store the handle for later.
210 native_bridge_handle = handle;
211 } else {
212 callbacks = nullptr;
213 dlclose(handle);
214 ALOGW("Unsupported native bridge interface.");
215 }
Andreas Gampe035bd752014-09-02 21:17:03 -0700216 } else {
217 dlclose(handle);
218 }
219 }
220
221 // Two failure conditions: could not find library (dlopen failed), or could not find native
222 // bridge interface (dlsym failed). Both are an error and close the native bridge.
223 if (callbacks == nullptr) {
Calin Juravlef9d9e2a2014-10-17 13:45:39 +0100224 CloseNativeBridge(true);
Andreas Gampe035bd752014-09-02 21:17:03 -0700225 } else {
226 runtime_callbacks = runtime_cbs;
227 state = NativeBridgeState::kOpened;
228 }
229 }
230 return state == NativeBridgeState::kOpened;
231 }
232}
233
jgu21ab0da5a2014-09-10 06:58:32 -0400234#if defined(__arm__)
235static const char* kRuntimeISA = "arm";
236#elif defined(__aarch64__)
237static const char* kRuntimeISA = "arm64";
Douglas Leungd10e0172015-05-19 17:30:08 -0700238#elif defined(__mips__) && !defined(__LP64__)
jgu21ab0da5a2014-09-10 06:58:32 -0400239static const char* kRuntimeISA = "mips";
Douglas Leungd10e0172015-05-19 17:30:08 -0700240#elif defined(__mips__) && defined(__LP64__)
241static const char* kRuntimeISA = "mips64";
jgu21ab0da5a2014-09-10 06:58:32 -0400242#elif defined(__i386__)
243static const char* kRuntimeISA = "x86";
244#elif defined(__x86_64__)
245static const char* kRuntimeISA = "x86_64";
246#else
247static const char* kRuntimeISA = "unknown";
248#endif
249
250
251bool NeedsNativeBridge(const char* instruction_set) {
Andreas Gampe04054e22014-09-25 22:33:01 -0700252 if (instruction_set == nullptr) {
253 ALOGE("Null instruction set in NeedsNativeBridge.");
254 return false;
255 }
Andreas Gampe2f71cb22014-09-25 21:34:25 -0700256 return strncmp(instruction_set, kRuntimeISA, strlen(kRuntimeISA) + 1) != 0;
jgu21ab0da5a2014-09-10 06:58:32 -0400257}
258
Andreas Gampe4390a632014-09-24 18:53:26 -0700259#ifdef __APPLE__
260template<typename T> void UNUSED(const T&) {}
261#endif
262
Calin Juravlef9d9e2a2014-10-17 13:45:39 +0100263bool PreInitializeNativeBridge(const char* app_data_dir_in, const char* instruction_set) {
264 if (state != NativeBridgeState::kOpened) {
265 ALOGE("Invalid state: native bridge is expected to be opened.");
266 CloseNativeBridge(true);
267 return false;
jgu21ab0da5a2014-09-10 06:58:32 -0400268 }
269
Calin Juravlef9d9e2a2014-10-17 13:45:39 +0100270 if (app_data_dir_in == nullptr) {
271 ALOGE("Application private directory cannot be null.");
272 CloseNativeBridge(true);
273 return false;
274 }
275
276 // Create the path to the application code cache directory.
277 // The memory will be release after Initialization or when the native bridge is closed.
278 const size_t len = strlen(app_data_dir_in) + strlen(kCodeCacheDir) + 2; // '\0' + '/'
279 app_code_cache_dir = new char[len];
280 snprintf(app_code_cache_dir, len, "%s/%s", app_data_dir_in, kCodeCacheDir);
281
282 // Bind-mount /system/lib{,64}/<isa>/cpuinfo to /proc/cpuinfo.
283 // Failure is not fatal and will keep the native bridge in kPreInitialized.
284 state = NativeBridgeState::kPreInitialized;
jgu21ab0da5a2014-09-10 06:58:32 -0400285
Andreas Gampe962eb402014-09-24 16:36:17 -0700286#ifndef __APPLE__
jgu21ab0da5a2014-09-10 06:58:32 -0400287 if (instruction_set == nullptr) {
Calin Juravlef9d9e2a2014-10-17 13:45:39 +0100288 return true;
jgu21ab0da5a2014-09-10 06:58:32 -0400289 }
290 size_t isa_len = strlen(instruction_set);
291 if (isa_len > 10) {
292 // 10 is a loose upper bound on the currently known instruction sets (a tight bound is 7 for
293 // x86_64 [including the trailing \0]). This is so we don't have to change here if there will
294 // be another instruction set in the future.
Andreas Gampe2f71cb22014-09-25 21:34:25 -0700295 ALOGW("Instruction set %s is malformed, must be less than or equal to 10 characters.",
296 instruction_set);
Calin Juravlef9d9e2a2014-10-17 13:45:39 +0100297 return true;
jgu21ab0da5a2014-09-10 06:58:32 -0400298 }
299
Calin Juravlef9d9e2a2014-10-17 13:45:39 +0100300 // If the file does not exist, the mount command will fail,
301 // so we save the extra file existence check.
jgu21ab0da5a2014-09-10 06:58:32 -0400302 char cpuinfo_path[1024];
303
Elliott Hughes9b828ad2015-07-30 08:47:35 -0700304#if defined(__ANDROID__)
Andreas Gampe04054e22014-09-25 22:33:01 -0700305 snprintf(cpuinfo_path, sizeof(cpuinfo_path), "/system/lib"
jgu21ab0da5a2014-09-10 06:58:32 -0400306#ifdef __LP64__
Andreas Gampe04054e22014-09-25 22:33:01 -0700307 "64"
308#endif // __LP64__
309 "/%s/cpuinfo", instruction_set);
Elliott Hughes9b828ad2015-07-30 08:47:35 -0700310#else // !__ANDROID__
Andreas Gampe04054e22014-09-25 22:33:01 -0700311 // To be able to test on the host, we hardwire a relative path.
312 snprintf(cpuinfo_path, sizeof(cpuinfo_path), "./cpuinfo");
jgu21ab0da5a2014-09-10 06:58:32 -0400313#endif
jgu21ab0da5a2014-09-10 06:58:32 -0400314
315 // Bind-mount.
Andreas Gampe2f71cb22014-09-25 21:34:25 -0700316 if (TEMP_FAILURE_RETRY(mount(cpuinfo_path, // Source.
317 "/proc/cpuinfo", // Target.
318 nullptr, // FS type.
319 MS_BIND, // Mount flags: bind mount.
320 nullptr)) == -1) { // "Data."
Andreas Gampe04054e22014-09-25 22:33:01 -0700321 ALOGW("Failed to bind-mount %s as /proc/cpuinfo: %s", cpuinfo_path, strerror(errno));
jgu21ab0da5a2014-09-10 06:58:32 -0400322 }
Calin Juravlef9d9e2a2014-10-17 13:45:39 +0100323#else // __APPLE__
Andreas Gampe4390a632014-09-24 18:53:26 -0700324 UNUSED(instruction_set);
Andreas Gampe962eb402014-09-24 16:36:17 -0700325 ALOGW("Mac OS does not support bind-mounting. Host simulation of native bridge impossible.");
326#endif
Calin Juravlef9d9e2a2014-10-17 13:45:39 +0100327
328 return true;
jgu21ab0da5a2014-09-10 06:58:32 -0400329}
330
331static void SetCpuAbi(JNIEnv* env, jclass build_class, const char* field, const char* value) {
332 if (value != nullptr) {
333 jfieldID field_id = env->GetStaticFieldID(build_class, field, "Ljava/lang/String;");
334 if (field_id == nullptr) {
335 env->ExceptionClear();
336 ALOGW("Could not find %s field.", field);
337 return;
338 }
339
340 jstring str = env->NewStringUTF(value);
341 if (str == nullptr) {
342 env->ExceptionClear();
343 ALOGW("Could not create string %s.", value);
344 return;
345 }
346
347 env->SetStaticObjectField(build_class, field_id, str);
348 }
349}
350
jgu21ab0da5a2014-09-10 06:58:32 -0400351// Set up the environment for the bridged app.
Andreas Gampea6ac9ce2015-04-30 20:39:12 -0700352static void SetupEnvironment(const NativeBridgeCallbacks* callbacks, JNIEnv* env, const char* isa) {
jgu21ab0da5a2014-09-10 06:58:32 -0400353 // Need a JNIEnv* to do anything.
354 if (env == nullptr) {
355 ALOGW("No JNIEnv* to set up app environment.");
356 return;
357 }
358
359 // Query the bridge for environment values.
360 const struct NativeBridgeRuntimeValues* env_values = callbacks->getAppEnv(isa);
361 if (env_values == nullptr) {
362 return;
363 }
364
365 // Keep the JNIEnv clean.
366 jint success = env->PushLocalFrame(16); // That should be small and large enough.
367 if (success < 0) {
368 // Out of memory, really borked.
369 ALOGW("Out of memory while setting up app environment.");
370 env->ExceptionClear();
371 return;
372 }
373
374 // Reset CPU_ABI & CPU_ABI2 to values required by the apps running with native bridge.
375 if (env_values->cpu_abi != nullptr || env_values->cpu_abi2 != nullptr ||
376 env_values->abi_count >= 0) {
377 jclass bclass_id = env->FindClass("android/os/Build");
378 if (bclass_id != nullptr) {
379 SetCpuAbi(env, bclass_id, "CPU_ABI", env_values->cpu_abi);
380 SetCpuAbi(env, bclass_id, "CPU_ABI2", env_values->cpu_abi2);
jgu21ab0da5a2014-09-10 06:58:32 -0400381 } else {
382 // For example in a host test environment.
383 env->ExceptionClear();
384 ALOGW("Could not find Build class.");
385 }
386 }
387
388 if (env_values->os_arch != nullptr) {
389 jclass sclass_id = env->FindClass("java/lang/System");
390 if (sclass_id != nullptr) {
Narayan Kamath484c55b2015-02-10 15:33:36 +0000391 jmethodID set_prop_id = env->GetStaticMethodID(sclass_id, "setUnchangeableSystemProperty",
Calin Juravlec3eb4312014-10-01 17:29:19 +0100392 "(Ljava/lang/String;Ljava/lang/String;)V");
jgu21ab0da5a2014-09-10 06:58:32 -0400393 if (set_prop_id != nullptr) {
Calin Juravlec3eb4312014-10-01 17:29:19 +0100394 // Init os.arch to the value reqired by the apps running with native bridge.
395 env->CallStaticVoidMethod(sclass_id, set_prop_id, env->NewStringUTF("os.arch"),
jgu21ab0da5a2014-09-10 06:58:32 -0400396 env->NewStringUTF(env_values->os_arch));
397 } else {
398 env->ExceptionClear();
Narayan Kamath484c55b2015-02-10 15:33:36 +0000399 ALOGW("Could not find System#setUnchangeableSystemProperty.");
jgu21ab0da5a2014-09-10 06:58:32 -0400400 }
401 } else {
402 env->ExceptionClear();
403 ALOGW("Could not find System class.");
404 }
405 }
406
407 // Make it pristine again.
408 env->PopLocalFrame(nullptr);
409}
410
411bool InitializeNativeBridge(JNIEnv* env, const char* instruction_set) {
Andreas Gampe035bd752014-09-02 21:17:03 -0700412 // We expect only one place that calls InitializeNativeBridge: Runtime::DidForkFromZygote. At that
413 // point we are not multi-threaded, so we do not need locking here.
414
Calin Juravlef9d9e2a2014-10-17 13:45:39 +0100415 if (state == NativeBridgeState::kPreInitialized) {
416 // Check for code cache: if it doesn't exist try to create it.
417 struct stat st;
418 if (stat(app_code_cache_dir, &st) == -1) {
419 if (errno == ENOENT) {
420 if (mkdir(app_code_cache_dir, S_IRWXU | S_IRWXG | S_IXOTH) == -1) {
jgu21cef898f2015-07-02 12:02:11 +0800421 ALOGW("Cannot create code cache directory %s: %s.", app_code_cache_dir, strerror(errno));
422 ReleaseAppCodeCacheDir();
Calin Juravlef9d9e2a2014-10-17 13:45:39 +0100423 }
424 } else {
jgu21cef898f2015-07-02 12:02:11 +0800425 ALOGW("Cannot stat code cache directory %s: %s.", app_code_cache_dir, strerror(errno));
426 ReleaseAppCodeCacheDir();
Calin Juravlef9d9e2a2014-10-17 13:45:39 +0100427 }
428 } else if (!S_ISDIR(st.st_mode)) {
jgu21cef898f2015-07-02 12:02:11 +0800429 ALOGW("Code cache is not a directory %s.", app_code_cache_dir);
430 ReleaseAppCodeCacheDir();
Calin Juravlef9d9e2a2014-10-17 13:45:39 +0100431 }
432
433 // If we're still PreInitialized (dind't fail the code cache checks) try to initialize.
434 if (state == NativeBridgeState::kPreInitialized) {
435 if (callbacks->initialize(runtime_callbacks, app_code_cache_dir, instruction_set)) {
436 SetupEnvironment(callbacks, env, instruction_set);
437 state = NativeBridgeState::kInitialized;
438 // We no longer need the code cache path, release the memory.
jgu21cef898f2015-07-02 12:02:11 +0800439 ReleaseAppCodeCacheDir();
Calin Juravlef9d9e2a2014-10-17 13:45:39 +0100440 } else {
441 // Unload the library.
442 dlclose(native_bridge_handle);
443 CloseNativeBridge(true);
444 }
Calin Juravle961ae122014-08-11 16:11:59 +0100445 }
Andreas Gampe049249c2014-08-19 22:31:31 -0700446 } else {
Calin Juravlef9d9e2a2014-10-17 13:45:39 +0100447 CloseNativeBridge(true);
Calin Juravle961ae122014-08-11 16:11:59 +0100448 }
449
Andreas Gampe035bd752014-09-02 21:17:03 -0700450 return state == NativeBridgeState::kInitialized;
451}
Calin Juravle961ae122014-08-11 16:11:59 +0100452
Andreas Gampe035bd752014-09-02 21:17:03 -0700453void UnloadNativeBridge() {
454 // We expect only one place that calls UnloadNativeBridge: Runtime::DidForkFromZygote. At that
455 // point we are not multi-threaded, so we do not need locking here.
456
457 switch(state) {
458 case NativeBridgeState::kOpened:
Calin Juravlef9d9e2a2014-10-17 13:45:39 +0100459 case NativeBridgeState::kPreInitialized:
Andreas Gampe035bd752014-09-02 21:17:03 -0700460 case NativeBridgeState::kInitialized:
461 // Unload.
462 dlclose(native_bridge_handle);
Calin Juravlef9d9e2a2014-10-17 13:45:39 +0100463 CloseNativeBridge(false);
Andreas Gampe035bd752014-09-02 21:17:03 -0700464 break;
465
466 case NativeBridgeState::kNotSetup:
467 // Not even set up. Error.
Calin Juravlef9d9e2a2014-10-17 13:45:39 +0100468 CloseNativeBridge(true);
Andreas Gampe035bd752014-09-02 21:17:03 -0700469 break;
470
471 case NativeBridgeState::kClosed:
472 // Ignore.
473 break;
474 }
Calin Juravle961ae122014-08-11 16:11:59 +0100475}
476
Andreas Gampe049249c2014-08-19 22:31:31 -0700477bool NativeBridgeError() {
478 return had_error;
479}
480
481bool NativeBridgeAvailable() {
Calin Juravlef9d9e2a2014-10-17 13:45:39 +0100482 return state == NativeBridgeState::kOpened
483 || state == NativeBridgeState::kPreInitialized
484 || state == NativeBridgeState::kInitialized;
Andreas Gampe035bd752014-09-02 21:17:03 -0700485}
486
487bool NativeBridgeInitialized() {
488 // Calls of this are supposed to happen in a state where the native bridge is stable, i.e., after
489 // Runtime::DidForkFromZygote. In that case we do not need a lock.
490 return state == NativeBridgeState::kInitialized;
Andreas Gampe049249c2014-08-19 22:31:31 -0700491}
492
Calin Juravle961ae122014-08-11 16:11:59 +0100493void* NativeBridgeLoadLibrary(const char* libpath, int flag) {
Andreas Gampe035bd752014-09-02 21:17:03 -0700494 if (NativeBridgeInitialized()) {
Calin Juravle961ae122014-08-11 16:11:59 +0100495 return callbacks->loadLibrary(libpath, flag);
496 }
497 return nullptr;
498}
499
500void* NativeBridgeGetTrampoline(void* handle, const char* name, const char* shorty,
501 uint32_t len) {
Andreas Gampe035bd752014-09-02 21:17:03 -0700502 if (NativeBridgeInitialized()) {
Calin Juravle961ae122014-08-11 16:11:59 +0100503 return callbacks->getTrampoline(handle, name, shorty, len);
504 }
505 return nullptr;
506}
507
508bool NativeBridgeIsSupported(const char* libpath) {
Andreas Gampe035bd752014-09-02 21:17:03 -0700509 if (NativeBridgeInitialized()) {
Calin Juravle961ae122014-08-11 16:11:59 +0100510 return callbacks->isSupported(libpath);
511 }
512 return false;
513}
514
Andreas Gampea6ac9ce2015-04-30 20:39:12 -0700515uint32_t NativeBridgeGetVersion() {
516 if (NativeBridgeAvailable()) {
517 return callbacks->version;
518 }
519 return 0;
520}
521
522NativeBridgeSignalHandlerFn NativeBridgeGetSignalHandler(int signal) {
523 if (NativeBridgeInitialized() && callbacks->version >= 2) {
524 return callbacks->getSignalHandler(signal);
525 }
526 return nullptr;
527}
528
Calin Juravle961ae122014-08-11 16:11:59 +0100529}; // namespace android