blob: fa80e1ebf94cb32bb4c0e5734d696ca793f145cf [file] [log] [blame]
Calin Juravle4914fcd2014-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
17#include "nativebridge/native_bridge.h"
18
Andreas Gampecd2ef4c2014-08-19 22:31:31 -070019#include <cutils/log.h>
Calin Juravle4914fcd2014-08-11 16:11:59 +010020#include <dlfcn.h>
21#include <stdio.h>
Calin Juravle4914fcd2014-08-11 16:11:59 +010022
23
24namespace android {
25
Calin Juravle4914fcd2014-08-11 16:11:59 +010026// The symbol name exposed by native-bridge with the type of NativeBridgeCallbacks.
27static constexpr const char* kNativeBridgeInterfaceSymbol = "NativeBridgeItf";
28
Andreas Gampe41df6682014-09-02 21:17:03 -070029enum class NativeBridgeState {
30 kNotSetup, // Initial state.
31 kOpened, // After successful dlopen.
Andreas Gampef00de412014-09-09 21:46:14 -070032 // Temporary meaning: string copied. TODO: remove. b/17440362
Andreas Gampe41df6682014-09-02 21:17:03 -070033 kInitialized, // After successful initialization.
34 kClosed // Closed or errors.
35};
Calin Juravle4914fcd2014-08-11 16:11:59 +010036
Andreas Gampe41df6682014-09-02 21:17:03 -070037static const char* kNotSetupString = "kNotSetup";
38static const char* kOpenedString = "kOpened";
39static const char* kInitializedString = "kInitialized";
40static const char* kClosedString = "kClosed";
41
42static const char* GetNativeBridgeStateString(NativeBridgeState state) {
43 switch (state) {
44 case NativeBridgeState::kNotSetup:
45 return kNotSetupString;
46
47 case NativeBridgeState::kOpened:
48 return kOpenedString;
49
50 case NativeBridgeState::kInitialized:
51 return kInitializedString;
52
53 case NativeBridgeState::kClosed:
54 return kClosedString;
55 }
56}
57
58// Current state of the native bridge.
59static NativeBridgeState state = NativeBridgeState::kNotSetup;
60
Andreas Gampecd2ef4c2014-08-19 22:31:31 -070061// Whether we had an error at some point.
62static bool had_error = false;
Calin Juravle4914fcd2014-08-11 16:11:59 +010063
Andreas Gampef00de412014-09-09 21:46:14 -070064// Native bridge filename. TODO: Temporary, remove. b/17440362
65static const char* native_bridge_filename;
66
Andreas Gampe41df6682014-09-02 21:17:03 -070067// Handle of the loaded library.
68static void* native_bridge_handle = nullptr;
69// Pointer to the callbacks. Available as soon as LoadNativeBridge succeeds, but only initialized
70// later.
Calin Juravle4914fcd2014-08-11 16:11:59 +010071static NativeBridgeCallbacks* callbacks = nullptr;
Andreas Gampe41df6682014-09-02 21:17:03 -070072// Callbacks provided by the environment to the bridge. Passed to LoadNativeBridge.
Calin Juravle4914fcd2014-08-11 16:11:59 +010073static const NativeBridgeRuntimeCallbacks* runtime_callbacks = nullptr;
74
Andreas Gampecd2ef4c2014-08-19 22:31:31 -070075// Characters allowed in a native bridge filename. The first character must
76// be in [a-zA-Z] (expected 'l' for "libx"). The rest must be in [a-zA-Z0-9._-].
77static bool CharacterAllowed(char c, bool first) {
78 if (first) {
79 return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
80 } else {
81 return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') ||
82 (c == '.') || (c == '_') || (c == '-');
83 }
84}
85
86// We only allow simple names for the library. It is supposed to be a file in
87// /system/lib or /vendor/lib. Only allow a small range of characters, that is
88// names consisting of [a-zA-Z0-9._-] and starting with [a-zA-Z].
89bool NativeBridgeNameAcceptable(const char* nb_library_filename) {
90 const char* ptr = nb_library_filename;
91 if (*ptr == 0) {
92 // Emptry string. Allowed, means no native bridge.
93 return true;
94 } else {
95 // First character must be [a-zA-Z].
96 if (!CharacterAllowed(*ptr, true)) {
97 // Found an invalid fist character, don't accept.
98 ALOGE("Native bridge library %s has been rejected for first character %c", nb_library_filename, *ptr);
99 return false;
100 } else {
101 // For the rest, be more liberal.
102 ptr++;
103 while (*ptr != 0) {
104 if (!CharacterAllowed(*ptr, false)) {
105 // Found an invalid character, don't accept.
106 ALOGE("Native bridge library %s has been rejected for %c", nb_library_filename, *ptr);
107 return false;
108 }
109 ptr++;
110 }
111 }
112 return true;
113 }
114}
115
Andreas Gampe41df6682014-09-02 21:17:03 -0700116bool LoadNativeBridge(const char* nb_library_filename,
117 const NativeBridgeRuntimeCallbacks* runtime_cbs) {
118 // We expect only one place that calls LoadNativeBridge: Runtime::Init. At that point we are not
119 // multi-threaded, so we do not need locking here.
Calin Juravle4914fcd2014-08-11 16:11:59 +0100120
Andreas Gampe41df6682014-09-02 21:17:03 -0700121 if (state != NativeBridgeState::kNotSetup) {
Andreas Gampecd2ef4c2014-08-19 22:31:31 -0700122 // Setup has been called before. Ignore this call.
Andreas Gampe41df6682014-09-02 21:17:03 -0700123 ALOGW("Called LoadNativeBridge for an already set up native bridge. State is %s.",
124 GetNativeBridgeStateString(state));
Andreas Gampecd2ef4c2014-08-19 22:31:31 -0700125 // Note: counts as an error, even though the bridge may be functional.
126 had_error = true;
Andreas Gampecd2ef4c2014-08-19 22:31:31 -0700127 return false;
128 }
129
Andreas Gampe41df6682014-09-02 21:17:03 -0700130 if (nb_library_filename == nullptr || *nb_library_filename == 0) {
131 state = NativeBridgeState::kClosed;
132 return true;
133 } else {
134 if (!NativeBridgeNameAcceptable(nb_library_filename)) {
135 state = NativeBridgeState::kClosed;
Andreas Gampecd2ef4c2014-08-19 22:31:31 -0700136 had_error = true;
Andreas Gampe41df6682014-09-02 21:17:03 -0700137 } else {
Andreas Gampef00de412014-09-09 21:46:14 -0700138 // Save the name. TODO: Remove this, return to old flow. b/17440362
139 native_bridge_filename = nb_library_filename;
140 runtime_callbacks = runtime_cbs;
141 state = NativeBridgeState::kOpened;
142// // Try to open the library.
143// void* handle = dlopen(nb_library_filename, RTLD_LAZY);
144// if (handle != nullptr) {
145// callbacks = reinterpret_cast<NativeBridgeCallbacks*>(dlsym(handle,
146// kNativeBridgeInterfaceSymbol));
147// if (callbacks != nullptr) {
148// // Store the handle for later.
149// native_bridge_handle = handle;
150// } else {
151// dlclose(handle);
152// }
153// }
154//
155// // Two failure conditions: could not find library (dlopen failed), or could not find native
156// // bridge interface (dlsym failed). Both are an error and close the native bridge.
157// if (callbacks == nullptr) {
158// had_error = true;
159// state = NativeBridgeState::kClosed;
160// } else {
161// runtime_callbacks = runtime_cbs;
162// state = NativeBridgeState::kOpened;
163// }
Andreas Gampe41df6682014-09-02 21:17:03 -0700164 }
165 return state == NativeBridgeState::kOpened;
166 }
167}
168
169bool InitializeNativeBridge() {
170 // We expect only one place that calls InitializeNativeBridge: Runtime::DidForkFromZygote. At that
171 // point we are not multi-threaded, so we do not need locking here.
172
173 if (state == NativeBridgeState::kOpened) {
Andreas Gampef00de412014-09-09 21:46:14 -0700174 // Open and initialize. TODO: Temporary, remove. b/17440362
175 void* handle = dlopen(native_bridge_filename, RTLD_LAZY);
176 if (handle != nullptr) {
177 callbacks = reinterpret_cast<NativeBridgeCallbacks*>(dlsym(handle,
178 kNativeBridgeInterfaceSymbol));
179 if (callbacks != nullptr) {
180 if (callbacks->initialize(runtime_callbacks)) {
181 state = NativeBridgeState::kInitialized;
182 native_bridge_handle = handle;
183 } else {
184 callbacks = nullptr;
185 }
186 }
187
188 if (callbacks == nullptr) {
189 state = NativeBridgeState::kClosed;
190 had_error = true;
191 dlclose(handle);
192 }
Andreas Gampe41df6682014-09-02 21:17:03 -0700193 } else {
Andreas Gampe41df6682014-09-02 21:17:03 -0700194 state = NativeBridgeState::kClosed;
Andreas Gampef00de412014-09-09 21:46:14 -0700195 had_error = true;
Calin Juravle4914fcd2014-08-11 16:11:59 +0100196 }
Andreas Gampef00de412014-09-09 21:46:14 -0700197// // Try to initialize.
198// if (callbacks->initialize(runtime_callbacks)) {
199// state = NativeBridgeState::kInitialized;
200// } else {
201// // Unload the library.
202// dlclose(native_bridge_handle);
203// had_error = true;
204// state = NativeBridgeState::kClosed;
205// }
Andreas Gampecd2ef4c2014-08-19 22:31:31 -0700206 } else {
Andreas Gampecd2ef4c2014-08-19 22:31:31 -0700207 had_error = true;
Andreas Gampe41df6682014-09-02 21:17:03 -0700208 state = NativeBridgeState::kClosed;
Calin Juravle4914fcd2014-08-11 16:11:59 +0100209 }
210
Andreas Gampe41df6682014-09-02 21:17:03 -0700211 return state == NativeBridgeState::kInitialized;
212}
Calin Juravle4914fcd2014-08-11 16:11:59 +0100213
Andreas Gampe41df6682014-09-02 21:17:03 -0700214void UnloadNativeBridge() {
215 // We expect only one place that calls UnloadNativeBridge: Runtime::DidForkFromZygote. At that
216 // point we are not multi-threaded, so we do not need locking here.
217
218 switch(state) {
Andreas Gampef00de412014-09-09 21:46:14 -0700219 // case NativeBridgeState::kOpened: // TODO: Re-add this. b/17440362
Andreas Gampe41df6682014-09-02 21:17:03 -0700220 case NativeBridgeState::kInitialized:
221 // Unload.
222 dlclose(native_bridge_handle);
223 break;
224
225 case NativeBridgeState::kNotSetup:
226 // Not even set up. Error.
227 had_error = true;
228 break;
229
Andreas Gampef00de412014-09-09 21:46:14 -0700230 case NativeBridgeState::kOpened: // TODO: Remove this. b/17440362
Andreas Gampe41df6682014-09-02 21:17:03 -0700231 case NativeBridgeState::kClosed:
232 // Ignore.
233 break;
234 }
235
236 state = NativeBridgeState::kClosed;
Calin Juravle4914fcd2014-08-11 16:11:59 +0100237}
238
Andreas Gampecd2ef4c2014-08-19 22:31:31 -0700239bool NativeBridgeError() {
240 return had_error;
241}
242
243bool NativeBridgeAvailable() {
Andreas Gampe41df6682014-09-02 21:17:03 -0700244 return state == NativeBridgeState::kOpened || state == NativeBridgeState::kInitialized;
245}
246
247bool NativeBridgeInitialized() {
248 // Calls of this are supposed to happen in a state where the native bridge is stable, i.e., after
249 // Runtime::DidForkFromZygote. In that case we do not need a lock.
250 return state == NativeBridgeState::kInitialized;
Andreas Gampecd2ef4c2014-08-19 22:31:31 -0700251}
252
Calin Juravle4914fcd2014-08-11 16:11:59 +0100253void* NativeBridgeLoadLibrary(const char* libpath, int flag) {
Andreas Gampe41df6682014-09-02 21:17:03 -0700254 if (NativeBridgeInitialized()) {
Calin Juravle4914fcd2014-08-11 16:11:59 +0100255 return callbacks->loadLibrary(libpath, flag);
256 }
257 return nullptr;
258}
259
260void* NativeBridgeGetTrampoline(void* handle, const char* name, const char* shorty,
261 uint32_t len) {
Andreas Gampe41df6682014-09-02 21:17:03 -0700262 if (NativeBridgeInitialized()) {
Calin Juravle4914fcd2014-08-11 16:11:59 +0100263 return callbacks->getTrampoline(handle, name, shorty, len);
264 }
265 return nullptr;
266}
267
268bool NativeBridgeIsSupported(const char* libpath) {
Andreas Gampe41df6682014-09-02 21:17:03 -0700269 if (NativeBridgeInitialized()) {
Calin Juravle4914fcd2014-08-11 16:11:59 +0100270 return callbacks->isSupported(libpath);
271 }
272 return false;
273}
274
275}; // namespace android