xref: /aosp_15_r20/art/libnativebridge/native_bridge.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2014 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #define LOG_TAG "nativebridge"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include "nativebridge/native_bridge.h"
20*795d594fSAndroid Build Coastguard Worker 
21*795d594fSAndroid Build Coastguard Worker #include <dlfcn.h>
22*795d594fSAndroid Build Coastguard Worker #include <errno.h>
23*795d594fSAndroid Build Coastguard Worker #include <fcntl.h>
24*795d594fSAndroid Build Coastguard Worker #include <stdio.h>
25*795d594fSAndroid Build Coastguard Worker #include <sys/mount.h>
26*795d594fSAndroid Build Coastguard Worker #include <sys/stat.h>
27*795d594fSAndroid Build Coastguard Worker #include <unistd.h>
28*795d594fSAndroid Build Coastguard Worker 
29*795d594fSAndroid Build Coastguard Worker #include <cstring>
30*795d594fSAndroid Build Coastguard Worker 
31*795d594fSAndroid Build Coastguard Worker #include <android-base/macros.h>
32*795d594fSAndroid Build Coastguard Worker #include <log/log.h>
33*795d594fSAndroid Build Coastguard Worker 
34*795d594fSAndroid Build Coastguard Worker #ifdef ART_TARGET_ANDROID
35*795d594fSAndroid Build Coastguard Worker #include "nativeloader/dlext_namespaces.h"
36*795d594fSAndroid Build Coastguard Worker #endif
37*795d594fSAndroid Build Coastguard Worker 
38*795d594fSAndroid Build Coastguard Worker namespace android {
39*795d594fSAndroid Build Coastguard Worker 
40*795d594fSAndroid Build Coastguard Worker #ifdef __APPLE__
41*795d594fSAndroid Build Coastguard Worker template <typename T>
UNUSED(const T &)42*795d594fSAndroid Build Coastguard Worker void UNUSED(const T&) {}
43*795d594fSAndroid Build Coastguard Worker #endif
44*795d594fSAndroid Build Coastguard Worker 
45*795d594fSAndroid Build Coastguard Worker extern "C" {
46*795d594fSAndroid Build Coastguard Worker 
OpenSystemLibrary(const char * path,int flags)47*795d594fSAndroid Build Coastguard Worker void* OpenSystemLibrary(const char* path, int flags) {
48*795d594fSAndroid Build Coastguard Worker #ifdef ART_TARGET_ANDROID
49*795d594fSAndroid Build Coastguard Worker   // The system namespace is called "default" for binaries in /system and
50*795d594fSAndroid Build Coastguard Worker   // "system" for those in the Runtime APEX. Try "system" first since
51*795d594fSAndroid Build Coastguard Worker   // "default" always exists.
52*795d594fSAndroid Build Coastguard Worker   // TODO(b/185587109): Get rid of this error prone logic.
53*795d594fSAndroid Build Coastguard Worker   android_namespace_t* system_ns = android_get_exported_namespace("system");
54*795d594fSAndroid Build Coastguard Worker   if (system_ns == nullptr) {
55*795d594fSAndroid Build Coastguard Worker     system_ns = android_get_exported_namespace("default");
56*795d594fSAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(system_ns == nullptr,
57*795d594fSAndroid Build Coastguard Worker                         "Failed to get system namespace for loading %s", path);
58*795d594fSAndroid Build Coastguard Worker   }
59*795d594fSAndroid Build Coastguard Worker   const android_dlextinfo dlextinfo = {
60*795d594fSAndroid Build Coastguard Worker       .flags = ANDROID_DLEXT_USE_NAMESPACE,
61*795d594fSAndroid Build Coastguard Worker       .library_namespace = system_ns,
62*795d594fSAndroid Build Coastguard Worker   };
63*795d594fSAndroid Build Coastguard Worker   return android_dlopen_ext(path, flags, &dlextinfo);
64*795d594fSAndroid Build Coastguard Worker #else
65*795d594fSAndroid Build Coastguard Worker   return dlopen(path, flags);
66*795d594fSAndroid Build Coastguard Worker #endif
67*795d594fSAndroid Build Coastguard Worker }
68*795d594fSAndroid Build Coastguard Worker 
69*795d594fSAndroid Build Coastguard Worker // Environment values required by the apps running with native bridge.
70*795d594fSAndroid Build Coastguard Worker struct NativeBridgeRuntimeValues {
71*795d594fSAndroid Build Coastguard Worker     const char* os_arch;
72*795d594fSAndroid Build Coastguard Worker     const char* cpu_abi;
73*795d594fSAndroid Build Coastguard Worker     const char* cpu_abi2;
74*795d594fSAndroid Build Coastguard Worker     const char* *supported_abis;
75*795d594fSAndroid Build Coastguard Worker     int32_t abi_count;
76*795d594fSAndroid Build Coastguard Worker };
77*795d594fSAndroid Build Coastguard Worker 
78*795d594fSAndroid Build Coastguard Worker // The symbol name exposed by native-bridge with the type of NativeBridgeCallbacks.
79*795d594fSAndroid Build Coastguard Worker static constexpr const char* kNativeBridgeInterfaceSymbol = "NativeBridgeItf";
80*795d594fSAndroid Build Coastguard Worker 
81*795d594fSAndroid Build Coastguard Worker enum class NativeBridgeState {
82*795d594fSAndroid Build Coastguard Worker   kNotSetup,                        // Initial state.
83*795d594fSAndroid Build Coastguard Worker   kOpened,                          // After successful dlopen.
84*795d594fSAndroid Build Coastguard Worker   kPreInitialized,                  // After successful pre-initialization.
85*795d594fSAndroid Build Coastguard Worker   kInitialized,                     // After successful initialization.
86*795d594fSAndroid Build Coastguard Worker   kClosed                           // Closed or errors.
87*795d594fSAndroid Build Coastguard Worker };
88*795d594fSAndroid Build Coastguard Worker 
89*795d594fSAndroid Build Coastguard Worker static constexpr const char* kNotSetupString = "kNotSetup";
90*795d594fSAndroid Build Coastguard Worker static constexpr const char* kOpenedString = "kOpened";
91*795d594fSAndroid Build Coastguard Worker static constexpr const char* kPreInitializedString = "kPreInitialized";
92*795d594fSAndroid Build Coastguard Worker static constexpr const char* kInitializedString = "kInitialized";
93*795d594fSAndroid Build Coastguard Worker static constexpr const char* kClosedString = "kClosed";
94*795d594fSAndroid Build Coastguard Worker 
GetNativeBridgeStateString(NativeBridgeState state)95*795d594fSAndroid Build Coastguard Worker static const char* GetNativeBridgeStateString(NativeBridgeState state) {
96*795d594fSAndroid Build Coastguard Worker   switch (state) {
97*795d594fSAndroid Build Coastguard Worker     case NativeBridgeState::kNotSetup:
98*795d594fSAndroid Build Coastguard Worker       return kNotSetupString;
99*795d594fSAndroid Build Coastguard Worker 
100*795d594fSAndroid Build Coastguard Worker     case NativeBridgeState::kOpened:
101*795d594fSAndroid Build Coastguard Worker       return kOpenedString;
102*795d594fSAndroid Build Coastguard Worker 
103*795d594fSAndroid Build Coastguard Worker     case NativeBridgeState::kPreInitialized:
104*795d594fSAndroid Build Coastguard Worker       return kPreInitializedString;
105*795d594fSAndroid Build Coastguard Worker 
106*795d594fSAndroid Build Coastguard Worker     case NativeBridgeState::kInitialized:
107*795d594fSAndroid Build Coastguard Worker       return kInitializedString;
108*795d594fSAndroid Build Coastguard Worker 
109*795d594fSAndroid Build Coastguard Worker     case NativeBridgeState::kClosed:
110*795d594fSAndroid Build Coastguard Worker       return kClosedString;
111*795d594fSAndroid Build Coastguard Worker   }
112*795d594fSAndroid Build Coastguard Worker }
113*795d594fSAndroid Build Coastguard Worker 
114*795d594fSAndroid Build Coastguard Worker // Current state of the native bridge.
115*795d594fSAndroid Build Coastguard Worker static NativeBridgeState state = NativeBridgeState::kNotSetup;
116*795d594fSAndroid Build Coastguard Worker 
117*795d594fSAndroid Build Coastguard Worker // The version of NativeBridge implementation.
118*795d594fSAndroid Build Coastguard Worker // Different Nativebridge interface needs the service of different version of
119*795d594fSAndroid Build Coastguard Worker // Nativebridge implementation.
120*795d594fSAndroid Build Coastguard Worker // Used by isCompatibleWith() which is introduced in v2.
121*795d594fSAndroid Build Coastguard Worker enum NativeBridgeImplementationVersion {
122*795d594fSAndroid Build Coastguard Worker   // first version, not used.
123*795d594fSAndroid Build Coastguard Worker   DEFAULT_VERSION = 1,
124*795d594fSAndroid Build Coastguard Worker   // The version which signal semantic is introduced.
125*795d594fSAndroid Build Coastguard Worker   SIGNAL_VERSION = 2,
126*795d594fSAndroid Build Coastguard Worker   // The version which namespace semantic is introduced.
127*795d594fSAndroid Build Coastguard Worker   NAMESPACE_VERSION = 3,
128*795d594fSAndroid Build Coastguard Worker   // The version with vendor namespaces
129*795d594fSAndroid Build Coastguard Worker   VENDOR_NAMESPACE_VERSION = 4,
130*795d594fSAndroid Build Coastguard Worker   // The version with runtime namespaces
131*795d594fSAndroid Build Coastguard Worker   RUNTIME_NAMESPACE_VERSION = 5,
132*795d594fSAndroid Build Coastguard Worker   // The version with pre-zygote-fork hook to support app-zygotes.
133*795d594fSAndroid Build Coastguard Worker   PRE_ZYGOTE_FORK_VERSION = 6,
134*795d594fSAndroid Build Coastguard Worker   // The version with critical_native support
135*795d594fSAndroid Build Coastguard Worker   CRITICAL_NATIVE_SUPPORT_VERSION = 7,
136*795d594fSAndroid Build Coastguard Worker };
137*795d594fSAndroid Build Coastguard Worker 
138*795d594fSAndroid Build Coastguard Worker // Whether we had an error at some point.
139*795d594fSAndroid Build Coastguard Worker static bool had_error = false;
140*795d594fSAndroid Build Coastguard Worker 
141*795d594fSAndroid Build Coastguard Worker // Handle of the loaded library.
142*795d594fSAndroid Build Coastguard Worker static void* native_bridge_handle = nullptr;
143*795d594fSAndroid Build Coastguard Worker // Pointer to the callbacks. Available as soon as LoadNativeBridge succeeds, but only initialized
144*795d594fSAndroid Build Coastguard Worker // later.
145*795d594fSAndroid Build Coastguard Worker static const NativeBridgeCallbacks* callbacks = nullptr;
146*795d594fSAndroid Build Coastguard Worker // Callbacks provided by the environment to the bridge. Passed to LoadNativeBridge.
147*795d594fSAndroid Build Coastguard Worker static const NativeBridgeRuntimeCallbacks* runtime_callbacks = nullptr;
148*795d594fSAndroid Build Coastguard Worker 
149*795d594fSAndroid Build Coastguard Worker // The app's code cache directory.
150*795d594fSAndroid Build Coastguard Worker static char* app_code_cache_dir = nullptr;
151*795d594fSAndroid Build Coastguard Worker 
152*795d594fSAndroid Build Coastguard Worker // Code cache directory (relative to the application private directory)
153*795d594fSAndroid Build Coastguard Worker // Ideally we'd like to call into framework to retrieve this name. However that's considered an
154*795d594fSAndroid Build Coastguard Worker // implementation detail and will require either hacks or consistent refactorings. We compromise
155*795d594fSAndroid Build Coastguard Worker // and hard code the directory name again here.
156*795d594fSAndroid Build Coastguard Worker static constexpr const char* kCodeCacheDir = "code_cache";
157*795d594fSAndroid Build Coastguard Worker 
158*795d594fSAndroid Build Coastguard Worker // Characters allowed in a native bridge filename. The first character must
159*795d594fSAndroid Build Coastguard Worker // be in [a-zA-Z] (expected 'l' for "libx"). The rest must be in [a-zA-Z0-9._-].
CharacterAllowed(char c,bool first)160*795d594fSAndroid Build Coastguard Worker static bool CharacterAllowed(char c, bool first) {
161*795d594fSAndroid Build Coastguard Worker   if (first) {
162*795d594fSAndroid Build Coastguard Worker     return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
163*795d594fSAndroid Build Coastguard Worker   } else {
164*795d594fSAndroid Build Coastguard Worker     return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') ||
165*795d594fSAndroid Build Coastguard Worker            (c == '.') || (c == '_') || (c == '-');
166*795d594fSAndroid Build Coastguard Worker   }
167*795d594fSAndroid Build Coastguard Worker }
168*795d594fSAndroid Build Coastguard Worker 
ReleaseAppCodeCacheDir()169*795d594fSAndroid Build Coastguard Worker static void ReleaseAppCodeCacheDir() {
170*795d594fSAndroid Build Coastguard Worker   if (app_code_cache_dir != nullptr) {
171*795d594fSAndroid Build Coastguard Worker     delete[] app_code_cache_dir;
172*795d594fSAndroid Build Coastguard Worker     app_code_cache_dir = nullptr;
173*795d594fSAndroid Build Coastguard Worker   }
174*795d594fSAndroid Build Coastguard Worker }
175*795d594fSAndroid Build Coastguard Worker 
176*795d594fSAndroid Build Coastguard Worker // We only allow simple names for the library. It is supposed to be a file in
177*795d594fSAndroid Build Coastguard Worker // /system/lib or /vendor/lib. Only allow a small range of characters, that is
178*795d594fSAndroid Build Coastguard Worker // names consisting of [a-zA-Z0-9._-] and starting with [a-zA-Z].
NativeBridgeNameAcceptable(const char * nb_library_filename)179*795d594fSAndroid Build Coastguard Worker bool NativeBridgeNameAcceptable(const char* nb_library_filename) {
180*795d594fSAndroid Build Coastguard Worker   const char* ptr = nb_library_filename;
181*795d594fSAndroid Build Coastguard Worker   if (*ptr == 0) {
182*795d594fSAndroid Build Coastguard Worker     // Emptry string. Allowed, means no native bridge.
183*795d594fSAndroid Build Coastguard Worker     return true;
184*795d594fSAndroid Build Coastguard Worker   } else {
185*795d594fSAndroid Build Coastguard Worker     // First character must be [a-zA-Z].
186*795d594fSAndroid Build Coastguard Worker     if (!CharacterAllowed(*ptr, true))  {
187*795d594fSAndroid Build Coastguard Worker       // Found an invalid fist character, don't accept.
188*795d594fSAndroid Build Coastguard Worker       ALOGE("Native bridge library %s has been rejected for first character %c",
189*795d594fSAndroid Build Coastguard Worker             nb_library_filename,
190*795d594fSAndroid Build Coastguard Worker             *ptr);
191*795d594fSAndroid Build Coastguard Worker       return false;
192*795d594fSAndroid Build Coastguard Worker     } else {
193*795d594fSAndroid Build Coastguard Worker       // For the rest, be more liberal.
194*795d594fSAndroid Build Coastguard Worker       ptr++;
195*795d594fSAndroid Build Coastguard Worker       while (*ptr != 0) {
196*795d594fSAndroid Build Coastguard Worker         if (!CharacterAllowed(*ptr, false)) {
197*795d594fSAndroid Build Coastguard Worker           // Found an invalid character, don't accept.
198*795d594fSAndroid Build Coastguard Worker           ALOGE("Native bridge library %s has been rejected for %c", nb_library_filename, *ptr);
199*795d594fSAndroid Build Coastguard Worker           return false;
200*795d594fSAndroid Build Coastguard Worker         }
201*795d594fSAndroid Build Coastguard Worker         ptr++;
202*795d594fSAndroid Build Coastguard Worker       }
203*795d594fSAndroid Build Coastguard Worker     }
204*795d594fSAndroid Build Coastguard Worker     return true;
205*795d594fSAndroid Build Coastguard Worker   }
206*795d594fSAndroid Build Coastguard Worker }
207*795d594fSAndroid Build Coastguard Worker 
208*795d594fSAndroid Build Coastguard Worker // The policy of invoking Nativebridge changed in v3 with/without namespace.
209*795d594fSAndroid Build Coastguard Worker // Suggest Nativebridge implementation not maintain backward-compatible.
isCompatibleWith(const uint32_t version)210*795d594fSAndroid Build Coastguard Worker static bool isCompatibleWith(const uint32_t version) {
211*795d594fSAndroid Build Coastguard Worker   // Libnativebridge is now designed to be forward-compatible. So only "0" is an unsupported
212*795d594fSAndroid Build Coastguard Worker   // version.
213*795d594fSAndroid Build Coastguard Worker   if (callbacks == nullptr || callbacks->version == 0 || version == 0) {
214*795d594fSAndroid Build Coastguard Worker     return false;
215*795d594fSAndroid Build Coastguard Worker   }
216*795d594fSAndroid Build Coastguard Worker 
217*795d594fSAndroid Build Coastguard Worker   // If this is a v2+ bridge, it may not be forwards- or backwards-compatible. Check.
218*795d594fSAndroid Build Coastguard Worker   if (callbacks->version >= SIGNAL_VERSION) {
219*795d594fSAndroid Build Coastguard Worker     return callbacks->isCompatibleWith(version);
220*795d594fSAndroid Build Coastguard Worker   }
221*795d594fSAndroid Build Coastguard Worker 
222*795d594fSAndroid Build Coastguard Worker   return true;
223*795d594fSAndroid Build Coastguard Worker }
224*795d594fSAndroid Build Coastguard Worker 
CloseNativeBridge(bool with_error)225*795d594fSAndroid Build Coastguard Worker static void CloseNativeBridge(bool with_error) {
226*795d594fSAndroid Build Coastguard Worker   state = NativeBridgeState::kClosed;
227*795d594fSAndroid Build Coastguard Worker   had_error |= with_error;
228*795d594fSAndroid Build Coastguard Worker   ReleaseAppCodeCacheDir();
229*795d594fSAndroid Build Coastguard Worker }
230*795d594fSAndroid Build Coastguard Worker 
LoadNativeBridge(const char * nb_library_filename,const NativeBridgeRuntimeCallbacks * runtime_cbs)231*795d594fSAndroid Build Coastguard Worker bool LoadNativeBridge(const char* nb_library_filename,
232*795d594fSAndroid Build Coastguard Worker                       const NativeBridgeRuntimeCallbacks* runtime_cbs) {
233*795d594fSAndroid Build Coastguard Worker   // We expect only one place that calls LoadNativeBridge: Runtime::Init. At that point we are not
234*795d594fSAndroid Build Coastguard Worker   // multi-threaded, so we do not need locking here.
235*795d594fSAndroid Build Coastguard Worker 
236*795d594fSAndroid Build Coastguard Worker   if (state != NativeBridgeState::kNotSetup) {
237*795d594fSAndroid Build Coastguard Worker     // Setup has been called before. Ignore this call.
238*795d594fSAndroid Build Coastguard Worker     if (nb_library_filename != nullptr) {  // Avoids some log-spam for dalvikvm.
239*795d594fSAndroid Build Coastguard Worker       ALOGW("Called LoadNativeBridge for an already set up native bridge. State is %s.",
240*795d594fSAndroid Build Coastguard Worker             GetNativeBridgeStateString(state));
241*795d594fSAndroid Build Coastguard Worker     }
242*795d594fSAndroid Build Coastguard Worker     // Note: counts as an error, even though the bridge may be functional.
243*795d594fSAndroid Build Coastguard Worker     had_error = true;
244*795d594fSAndroid Build Coastguard Worker     return false;
245*795d594fSAndroid Build Coastguard Worker   }
246*795d594fSAndroid Build Coastguard Worker 
247*795d594fSAndroid Build Coastguard Worker   if (nb_library_filename == nullptr || *nb_library_filename == 0) {
248*795d594fSAndroid Build Coastguard Worker     CloseNativeBridge(false);
249*795d594fSAndroid Build Coastguard Worker     return false;
250*795d594fSAndroid Build Coastguard Worker   } else {
251*795d594fSAndroid Build Coastguard Worker     if (!NativeBridgeNameAcceptable(nb_library_filename)) {
252*795d594fSAndroid Build Coastguard Worker       CloseNativeBridge(true);
253*795d594fSAndroid Build Coastguard Worker     } else {
254*795d594fSAndroid Build Coastguard Worker       // Try to open the library. We assume this library is provided by the
255*795d594fSAndroid Build Coastguard Worker       // platform rather than the ART APEX itself, so use the system namespace
256*795d594fSAndroid Build Coastguard Worker       // to avoid requiring a static linker config link to it from the
257*795d594fSAndroid Build Coastguard Worker       // com_android_art namespace.
258*795d594fSAndroid Build Coastguard Worker       void* handle = OpenSystemLibrary(nb_library_filename, RTLD_LAZY);
259*795d594fSAndroid Build Coastguard Worker 
260*795d594fSAndroid Build Coastguard Worker       if (handle != nullptr) {
261*795d594fSAndroid Build Coastguard Worker         callbacks = reinterpret_cast<NativeBridgeCallbacks*>(dlsym(handle,
262*795d594fSAndroid Build Coastguard Worker                                                                    kNativeBridgeInterfaceSymbol));
263*795d594fSAndroid Build Coastguard Worker         if (callbacks != nullptr) {
264*795d594fSAndroid Build Coastguard Worker           if (isCompatibleWith(NAMESPACE_VERSION)) {
265*795d594fSAndroid Build Coastguard Worker             // Store the handle for later.
266*795d594fSAndroid Build Coastguard Worker             native_bridge_handle = handle;
267*795d594fSAndroid Build Coastguard Worker           } else {
268*795d594fSAndroid Build Coastguard Worker             ALOGW("Unsupported native bridge API in %s (is version %d not compatible with %d)",
269*795d594fSAndroid Build Coastguard Worker                   nb_library_filename, callbacks->version, NAMESPACE_VERSION);
270*795d594fSAndroid Build Coastguard Worker             callbacks = nullptr;
271*795d594fSAndroid Build Coastguard Worker             dlclose(handle);
272*795d594fSAndroid Build Coastguard Worker           }
273*795d594fSAndroid Build Coastguard Worker         } else {
274*795d594fSAndroid Build Coastguard Worker           dlclose(handle);
275*795d594fSAndroid Build Coastguard Worker           ALOGW("Unsupported native bridge API in %s: %s not found",
276*795d594fSAndroid Build Coastguard Worker                 nb_library_filename, kNativeBridgeInterfaceSymbol);
277*795d594fSAndroid Build Coastguard Worker         }
278*795d594fSAndroid Build Coastguard Worker       } else {
279*795d594fSAndroid Build Coastguard Worker         ALOGW("Failed to load native bridge implementation: %s", dlerror());
280*795d594fSAndroid Build Coastguard Worker       }
281*795d594fSAndroid Build Coastguard Worker 
282*795d594fSAndroid Build Coastguard Worker       // Two failure conditions: could not find library (dlopen failed), or could not find native
283*795d594fSAndroid Build Coastguard Worker       // bridge interface (dlsym failed). Both are an error and close the native bridge.
284*795d594fSAndroid Build Coastguard Worker       if (callbacks == nullptr) {
285*795d594fSAndroid Build Coastguard Worker         CloseNativeBridge(true);
286*795d594fSAndroid Build Coastguard Worker       } else {
287*795d594fSAndroid Build Coastguard Worker         runtime_callbacks = runtime_cbs;
288*795d594fSAndroid Build Coastguard Worker         state = NativeBridgeState::kOpened;
289*795d594fSAndroid Build Coastguard Worker       }
290*795d594fSAndroid Build Coastguard Worker     }
291*795d594fSAndroid Build Coastguard Worker     return state == NativeBridgeState::kOpened;
292*795d594fSAndroid Build Coastguard Worker   }
293*795d594fSAndroid Build Coastguard Worker }
294*795d594fSAndroid Build Coastguard Worker 
NeedsNativeBridge(const char * instruction_set)295*795d594fSAndroid Build Coastguard Worker bool NeedsNativeBridge(const char* instruction_set) {
296*795d594fSAndroid Build Coastguard Worker   if (instruction_set == nullptr) {
297*795d594fSAndroid Build Coastguard Worker     ALOGE("Null instruction set in NeedsNativeBridge.");
298*795d594fSAndroid Build Coastguard Worker     return false;
299*795d594fSAndroid Build Coastguard Worker   }
300*795d594fSAndroid Build Coastguard Worker   return strncmp(instruction_set, ABI_STRING, strlen(ABI_STRING) + 1) != 0;
301*795d594fSAndroid Build Coastguard Worker }
302*795d594fSAndroid Build Coastguard Worker 
303*795d594fSAndroid Build Coastguard Worker #ifndef __APPLE__
MountCpuinfo(const char * cpuinfo_path)304*795d594fSAndroid Build Coastguard Worker static bool MountCpuinfo(const char* cpuinfo_path) {
305*795d594fSAndroid Build Coastguard Worker   // If the file does not exist, the mount command will fail,
306*795d594fSAndroid Build Coastguard Worker   // so we save the extra file existence check.
307*795d594fSAndroid Build Coastguard Worker   if (TEMP_FAILURE_RETRY(mount(cpuinfo_path,        // Source.
308*795d594fSAndroid Build Coastguard Worker                                "/proc/cpuinfo",     // Target.
309*795d594fSAndroid Build Coastguard Worker                                nullptr,             // FS type.
310*795d594fSAndroid Build Coastguard Worker                                MS_BIND,             // Mount flags: bind mount.
311*795d594fSAndroid Build Coastguard Worker                                nullptr)) == -1) {   // "Data."
312*795d594fSAndroid Build Coastguard Worker     ALOGW("Failed to bind-mount %s as /proc/cpuinfo: %s", cpuinfo_path, strerror(errno));
313*795d594fSAndroid Build Coastguard Worker     return false;
314*795d594fSAndroid Build Coastguard Worker   }
315*795d594fSAndroid Build Coastguard Worker   return true;
316*795d594fSAndroid Build Coastguard Worker }
317*795d594fSAndroid Build Coastguard Worker #endif
318*795d594fSAndroid Build Coastguard Worker 
MountCpuinfoForInstructionSet(const char * instruction_set)319*795d594fSAndroid Build Coastguard Worker static void MountCpuinfoForInstructionSet(const char* instruction_set) {
320*795d594fSAndroid Build Coastguard Worker   if (instruction_set == nullptr) {
321*795d594fSAndroid Build Coastguard Worker     return;
322*795d594fSAndroid Build Coastguard Worker   }
323*795d594fSAndroid Build Coastguard Worker 
324*795d594fSAndroid Build Coastguard Worker   size_t isa_len = strlen(instruction_set);
325*795d594fSAndroid Build Coastguard Worker   if (isa_len > 10) {
326*795d594fSAndroid Build Coastguard Worker     // 10 is a loose upper bound on the currently known instruction sets (a tight bound is 7 for
327*795d594fSAndroid Build Coastguard Worker     // x86_64 [including the trailing \0]). This is so we don't have to change here if there will
328*795d594fSAndroid Build Coastguard Worker     // be another instruction set in the future.
329*795d594fSAndroid Build Coastguard Worker     ALOGW("Instruction set %s is malformed, must be less than or equal to 10 characters.",
330*795d594fSAndroid Build Coastguard Worker           instruction_set);
331*795d594fSAndroid Build Coastguard Worker     return;
332*795d594fSAndroid Build Coastguard Worker   }
333*795d594fSAndroid Build Coastguard Worker 
334*795d594fSAndroid Build Coastguard Worker #if defined(__APPLE__)
335*795d594fSAndroid Build Coastguard Worker   ALOGW("Mac OS does not support bind-mounting. Host simulation of native bridge impossible.");
336*795d594fSAndroid Build Coastguard Worker 
337*795d594fSAndroid Build Coastguard Worker #elif !defined(__ANDROID__)
338*795d594fSAndroid Build Coastguard Worker   // To be able to test on the host, we hardwire a relative path.
339*795d594fSAndroid Build Coastguard Worker   MountCpuinfo("./cpuinfo");
340*795d594fSAndroid Build Coastguard Worker 
341*795d594fSAndroid Build Coastguard Worker #else  // __ANDROID__
342*795d594fSAndroid Build Coastguard Worker   char cpuinfo_path[1024];
343*795d594fSAndroid Build Coastguard Worker 
344*795d594fSAndroid Build Coastguard Worker   // Bind-mount /system/etc/cpuinfo.<isa>.txt to /proc/cpuinfo.
345*795d594fSAndroid Build Coastguard Worker   snprintf(cpuinfo_path, sizeof(cpuinfo_path), "/system/etc/cpuinfo.%s.txt", instruction_set);
346*795d594fSAndroid Build Coastguard Worker   if (MountCpuinfo(cpuinfo_path)) {
347*795d594fSAndroid Build Coastguard Worker     return;
348*795d594fSAndroid Build Coastguard Worker   }
349*795d594fSAndroid Build Coastguard Worker 
350*795d594fSAndroid Build Coastguard Worker   // Bind-mount /system/lib{,64}/<isa>/cpuinfo to /proc/cpuinfo.
351*795d594fSAndroid Build Coastguard Worker   // TODO(b/179753190): remove when all implementations migrate to system/etc!
352*795d594fSAndroid Build Coastguard Worker #ifdef __LP64__
353*795d594fSAndroid Build Coastguard Worker   snprintf(cpuinfo_path, sizeof(cpuinfo_path), "/system/lib64/%s/cpuinfo", instruction_set);
354*795d594fSAndroid Build Coastguard Worker #else
355*795d594fSAndroid Build Coastguard Worker   snprintf(cpuinfo_path, sizeof(cpuinfo_path), "/system/lib/%s/cpuinfo", instruction_set);
356*795d594fSAndroid Build Coastguard Worker #endif  // __LP64__
357*795d594fSAndroid Build Coastguard Worker   MountCpuinfo(cpuinfo_path);
358*795d594fSAndroid Build Coastguard Worker 
359*795d594fSAndroid Build Coastguard Worker #endif
360*795d594fSAndroid Build Coastguard Worker }
361*795d594fSAndroid Build Coastguard Worker 
PreInitializeNativeBridge(const char * app_data_dir_in,const char * instruction_set)362*795d594fSAndroid Build Coastguard Worker bool PreInitializeNativeBridge(const char* app_data_dir_in, const char* instruction_set) {
363*795d594fSAndroid Build Coastguard Worker   if (state != NativeBridgeState::kOpened) {
364*795d594fSAndroid Build Coastguard Worker     ALOGE("Invalid state: native bridge is expected to be opened.");
365*795d594fSAndroid Build Coastguard Worker     CloseNativeBridge(true);
366*795d594fSAndroid Build Coastguard Worker     return false;
367*795d594fSAndroid Build Coastguard Worker   }
368*795d594fSAndroid Build Coastguard Worker 
369*795d594fSAndroid Build Coastguard Worker   if (app_data_dir_in != nullptr) {
370*795d594fSAndroid Build Coastguard Worker     // Create the path to the application code cache directory.
371*795d594fSAndroid Build Coastguard Worker     // The memory will be release after Initialization or when the native bridge is closed.
372*795d594fSAndroid Build Coastguard Worker     const size_t len = strlen(app_data_dir_in) + strlen(kCodeCacheDir) + 2;  // '\0' + '/'
373*795d594fSAndroid Build Coastguard Worker     app_code_cache_dir = new char[len];
374*795d594fSAndroid Build Coastguard Worker     snprintf(app_code_cache_dir, len, "%s/%s", app_data_dir_in, kCodeCacheDir);
375*795d594fSAndroid Build Coastguard Worker   } else {
376*795d594fSAndroid Build Coastguard Worker     ALOGW("Application private directory isn't available.");
377*795d594fSAndroid Build Coastguard Worker     app_code_cache_dir = nullptr;
378*795d594fSAndroid Build Coastguard Worker   }
379*795d594fSAndroid Build Coastguard Worker 
380*795d594fSAndroid Build Coastguard Worker   // Mount cpuinfo that corresponds to the instruction set.
381*795d594fSAndroid Build Coastguard Worker   // Failure is not fatal.
382*795d594fSAndroid Build Coastguard Worker   MountCpuinfoForInstructionSet(instruction_set);
383*795d594fSAndroid Build Coastguard Worker 
384*795d594fSAndroid Build Coastguard Worker   state = NativeBridgeState::kPreInitialized;
385*795d594fSAndroid Build Coastguard Worker   return true;
386*795d594fSAndroid Build Coastguard Worker }
387*795d594fSAndroid Build Coastguard Worker 
PreZygoteForkNativeBridge()388*795d594fSAndroid Build Coastguard Worker void PreZygoteForkNativeBridge() {
389*795d594fSAndroid Build Coastguard Worker   if (NativeBridgeInitialized()) {
390*795d594fSAndroid Build Coastguard Worker     if (isCompatibleWith(PRE_ZYGOTE_FORK_VERSION)) {
391*795d594fSAndroid Build Coastguard Worker       return callbacks->preZygoteFork();
392*795d594fSAndroid Build Coastguard Worker     } else {
393*795d594fSAndroid Build Coastguard Worker       ALOGE("not compatible with version %d, preZygoteFork() isn't invoked",
394*795d594fSAndroid Build Coastguard Worker             PRE_ZYGOTE_FORK_VERSION);
395*795d594fSAndroid Build Coastguard Worker     }
396*795d594fSAndroid Build Coastguard Worker   }
397*795d594fSAndroid Build Coastguard Worker }
398*795d594fSAndroid Build Coastguard Worker 
SetCpuAbi(JNIEnv * env,jclass build_class,const char * field,const char * value)399*795d594fSAndroid Build Coastguard Worker static void SetCpuAbi(JNIEnv* env, jclass build_class, const char* field, const char* value) {
400*795d594fSAndroid Build Coastguard Worker   if (value != nullptr) {
401*795d594fSAndroid Build Coastguard Worker     jfieldID field_id = env->GetStaticFieldID(build_class, field, "Ljava/lang/String;");
402*795d594fSAndroid Build Coastguard Worker     if (field_id == nullptr) {
403*795d594fSAndroid Build Coastguard Worker       env->ExceptionClear();
404*795d594fSAndroid Build Coastguard Worker       ALOGW("Could not find %s field.", field);
405*795d594fSAndroid Build Coastguard Worker       return;
406*795d594fSAndroid Build Coastguard Worker     }
407*795d594fSAndroid Build Coastguard Worker 
408*795d594fSAndroid Build Coastguard Worker     jstring str = env->NewStringUTF(value);
409*795d594fSAndroid Build Coastguard Worker     if (str == nullptr) {
410*795d594fSAndroid Build Coastguard Worker       env->ExceptionClear();
411*795d594fSAndroid Build Coastguard Worker       ALOGW("Could not create string %s.", value);
412*795d594fSAndroid Build Coastguard Worker       return;
413*795d594fSAndroid Build Coastguard Worker     }
414*795d594fSAndroid Build Coastguard Worker 
415*795d594fSAndroid Build Coastguard Worker     env->SetStaticObjectField(build_class, field_id, str);
416*795d594fSAndroid Build Coastguard Worker   }
417*795d594fSAndroid Build Coastguard Worker }
418*795d594fSAndroid Build Coastguard Worker 
419*795d594fSAndroid Build Coastguard Worker // Set up the environment for the bridged app.
SetupEnvironment(const NativeBridgeCallbacks * cbs,JNIEnv * env,const char * isa)420*795d594fSAndroid Build Coastguard Worker static void SetupEnvironment(const NativeBridgeCallbacks* cbs, JNIEnv* env, const char* isa) {
421*795d594fSAndroid Build Coastguard Worker   // Need a JNIEnv* to do anything.
422*795d594fSAndroid Build Coastguard Worker   if (env == nullptr) {
423*795d594fSAndroid Build Coastguard Worker     ALOGW("No JNIEnv* to set up app environment.");
424*795d594fSAndroid Build Coastguard Worker     return;
425*795d594fSAndroid Build Coastguard Worker   }
426*795d594fSAndroid Build Coastguard Worker 
427*795d594fSAndroid Build Coastguard Worker   // Query the bridge for environment values.
428*795d594fSAndroid Build Coastguard Worker   const struct NativeBridgeRuntimeValues* env_values = cbs->getAppEnv(isa);
429*795d594fSAndroid Build Coastguard Worker   if (env_values == nullptr) {
430*795d594fSAndroid Build Coastguard Worker     return;
431*795d594fSAndroid Build Coastguard Worker   }
432*795d594fSAndroid Build Coastguard Worker 
433*795d594fSAndroid Build Coastguard Worker   // Keep the JNIEnv clean.
434*795d594fSAndroid Build Coastguard Worker   jint success = env->PushLocalFrame(16);  // That should be small and large enough.
435*795d594fSAndroid Build Coastguard Worker   if (success < 0) {
436*795d594fSAndroid Build Coastguard Worker     // Out of memory, really borked.
437*795d594fSAndroid Build Coastguard Worker     ALOGW("Out of memory while setting up app environment.");
438*795d594fSAndroid Build Coastguard Worker     env->ExceptionClear();
439*795d594fSAndroid Build Coastguard Worker     return;
440*795d594fSAndroid Build Coastguard Worker   }
441*795d594fSAndroid Build Coastguard Worker 
442*795d594fSAndroid Build Coastguard Worker   // Reset CPU_ABI & CPU_ABI2 to values required by the apps running with native bridge.
443*795d594fSAndroid Build Coastguard Worker   if (env_values->cpu_abi != nullptr || env_values->cpu_abi2 != nullptr ||
444*795d594fSAndroid Build Coastguard Worker       env_values->abi_count >= 0) {
445*795d594fSAndroid Build Coastguard Worker     jclass bclass_id = env->FindClass("android/os/Build");
446*795d594fSAndroid Build Coastguard Worker     if (bclass_id != nullptr) {
447*795d594fSAndroid Build Coastguard Worker       SetCpuAbi(env, bclass_id, "CPU_ABI", env_values->cpu_abi);
448*795d594fSAndroid Build Coastguard Worker       SetCpuAbi(env, bclass_id, "CPU_ABI2", env_values->cpu_abi2);
449*795d594fSAndroid Build Coastguard Worker     } else {
450*795d594fSAndroid Build Coastguard Worker       // For example in a host test environment.
451*795d594fSAndroid Build Coastguard Worker       env->ExceptionClear();
452*795d594fSAndroid Build Coastguard Worker       ALOGW("Could not find Build class.");
453*795d594fSAndroid Build Coastguard Worker     }
454*795d594fSAndroid Build Coastguard Worker   }
455*795d594fSAndroid Build Coastguard Worker 
456*795d594fSAndroid Build Coastguard Worker   if (env_values->os_arch != nullptr) {
457*795d594fSAndroid Build Coastguard Worker     jclass sclass_id = env->FindClass("java/lang/System");
458*795d594fSAndroid Build Coastguard Worker     if (sclass_id != nullptr) {
459*795d594fSAndroid Build Coastguard Worker       jmethodID set_prop_id = env->GetStaticMethodID(sclass_id, "setUnchangeableSystemProperty",
460*795d594fSAndroid Build Coastguard Worker           "(Ljava/lang/String;Ljava/lang/String;)V");
461*795d594fSAndroid Build Coastguard Worker       if (set_prop_id != nullptr) {
462*795d594fSAndroid Build Coastguard Worker         // Init os.arch to the value reqired by the apps running with native bridge.
463*795d594fSAndroid Build Coastguard Worker         env->CallStaticVoidMethod(sclass_id, set_prop_id, env->NewStringUTF("os.arch"),
464*795d594fSAndroid Build Coastguard Worker             env->NewStringUTF(env_values->os_arch));
465*795d594fSAndroid Build Coastguard Worker       } else {
466*795d594fSAndroid Build Coastguard Worker         env->ExceptionClear();
467*795d594fSAndroid Build Coastguard Worker         ALOGW("Could not find System#setUnchangeableSystemProperty.");
468*795d594fSAndroid Build Coastguard Worker       }
469*795d594fSAndroid Build Coastguard Worker     } else {
470*795d594fSAndroid Build Coastguard Worker       env->ExceptionClear();
471*795d594fSAndroid Build Coastguard Worker       ALOGW("Could not find System class.");
472*795d594fSAndroid Build Coastguard Worker     }
473*795d594fSAndroid Build Coastguard Worker   }
474*795d594fSAndroid Build Coastguard Worker 
475*795d594fSAndroid Build Coastguard Worker   // Make it pristine again.
476*795d594fSAndroid Build Coastguard Worker   env->PopLocalFrame(nullptr);
477*795d594fSAndroid Build Coastguard Worker }
478*795d594fSAndroid Build Coastguard Worker 
InitializeNativeBridge(JNIEnv * env,const char * instruction_set)479*795d594fSAndroid Build Coastguard Worker bool InitializeNativeBridge(JNIEnv* env, const char* instruction_set) {
480*795d594fSAndroid Build Coastguard Worker   // We expect only one place that calls InitializeNativeBridge: Runtime::DidForkFromZygote. At that
481*795d594fSAndroid Build Coastguard Worker   // point we are not multi-threaded, so we do not need locking here.
482*795d594fSAndroid Build Coastguard Worker 
483*795d594fSAndroid Build Coastguard Worker   if (state == NativeBridgeState::kPreInitialized) {
484*795d594fSAndroid Build Coastguard Worker     if (app_code_cache_dir != nullptr) {
485*795d594fSAndroid Build Coastguard Worker       // Check for code cache: if it doesn't exist try to create it.
486*795d594fSAndroid Build Coastguard Worker       struct stat st;
487*795d594fSAndroid Build Coastguard Worker       if (stat(app_code_cache_dir, &st) == -1) {
488*795d594fSAndroid Build Coastguard Worker         if (errno == ENOENT) {
489*795d594fSAndroid Build Coastguard Worker           if (mkdir(app_code_cache_dir, S_IRWXU | S_IRWXG | S_IXOTH) == -1) {
490*795d594fSAndroid Build Coastguard Worker             ALOGW("Cannot create code cache directory %s: %s.",
491*795d594fSAndroid Build Coastguard Worker                   app_code_cache_dir, strerror(errno));
492*795d594fSAndroid Build Coastguard Worker             ReleaseAppCodeCacheDir();
493*795d594fSAndroid Build Coastguard Worker           }
494*795d594fSAndroid Build Coastguard Worker         } else {
495*795d594fSAndroid Build Coastguard Worker           ALOGW("Cannot stat code cache directory %s: %s.",
496*795d594fSAndroid Build Coastguard Worker                 app_code_cache_dir, strerror(errno));
497*795d594fSAndroid Build Coastguard Worker           ReleaseAppCodeCacheDir();
498*795d594fSAndroid Build Coastguard Worker         }
499*795d594fSAndroid Build Coastguard Worker       } else if (!S_ISDIR(st.st_mode)) {
500*795d594fSAndroid Build Coastguard Worker         ALOGW("Code cache is not a directory %s.", app_code_cache_dir);
501*795d594fSAndroid Build Coastguard Worker         ReleaseAppCodeCacheDir();
502*795d594fSAndroid Build Coastguard Worker       }
503*795d594fSAndroid Build Coastguard Worker     }
504*795d594fSAndroid Build Coastguard Worker 
505*795d594fSAndroid Build Coastguard Worker     // If we're still PreInitialized (didn't fail the code cache checks) try to initialize.
506*795d594fSAndroid Build Coastguard Worker     if (state == NativeBridgeState::kPreInitialized) {
507*795d594fSAndroid Build Coastguard Worker       if (callbacks->initialize(runtime_callbacks, app_code_cache_dir, instruction_set)) {
508*795d594fSAndroid Build Coastguard Worker         SetupEnvironment(callbacks, env, instruction_set);
509*795d594fSAndroid Build Coastguard Worker         state = NativeBridgeState::kInitialized;
510*795d594fSAndroid Build Coastguard Worker         // We no longer need the code cache path, release the memory.
511*795d594fSAndroid Build Coastguard Worker         ReleaseAppCodeCacheDir();
512*795d594fSAndroid Build Coastguard Worker       } else {
513*795d594fSAndroid Build Coastguard Worker         // Unload the library.
514*795d594fSAndroid Build Coastguard Worker         dlclose(native_bridge_handle);
515*795d594fSAndroid Build Coastguard Worker         CloseNativeBridge(true);
516*795d594fSAndroid Build Coastguard Worker       }
517*795d594fSAndroid Build Coastguard Worker     }
518*795d594fSAndroid Build Coastguard Worker   } else {
519*795d594fSAndroid Build Coastguard Worker     CloseNativeBridge(true);
520*795d594fSAndroid Build Coastguard Worker   }
521*795d594fSAndroid Build Coastguard Worker 
522*795d594fSAndroid Build Coastguard Worker   return state == NativeBridgeState::kInitialized;
523*795d594fSAndroid Build Coastguard Worker }
524*795d594fSAndroid Build Coastguard Worker 
UnloadNativeBridge()525*795d594fSAndroid Build Coastguard Worker void UnloadNativeBridge() {
526*795d594fSAndroid Build Coastguard Worker   // We expect only one place that calls UnloadNativeBridge: Runtime::DidForkFromZygote. At that
527*795d594fSAndroid Build Coastguard Worker   // point we are not multi-threaded, so we do not need locking here.
528*795d594fSAndroid Build Coastguard Worker 
529*795d594fSAndroid Build Coastguard Worker   switch (state) {
530*795d594fSAndroid Build Coastguard Worker     case NativeBridgeState::kOpened:
531*795d594fSAndroid Build Coastguard Worker     case NativeBridgeState::kPreInitialized:
532*795d594fSAndroid Build Coastguard Worker     case NativeBridgeState::kInitialized:
533*795d594fSAndroid Build Coastguard Worker       // Unload.
534*795d594fSAndroid Build Coastguard Worker       dlclose(native_bridge_handle);
535*795d594fSAndroid Build Coastguard Worker       CloseNativeBridge(false);
536*795d594fSAndroid Build Coastguard Worker       break;
537*795d594fSAndroid Build Coastguard Worker 
538*795d594fSAndroid Build Coastguard Worker     case NativeBridgeState::kNotSetup:
539*795d594fSAndroid Build Coastguard Worker       // Not even set up. Error.
540*795d594fSAndroid Build Coastguard Worker       CloseNativeBridge(true);
541*795d594fSAndroid Build Coastguard Worker       break;
542*795d594fSAndroid Build Coastguard Worker 
543*795d594fSAndroid Build Coastguard Worker     case NativeBridgeState::kClosed:
544*795d594fSAndroid Build Coastguard Worker       // Ignore.
545*795d594fSAndroid Build Coastguard Worker       break;
546*795d594fSAndroid Build Coastguard Worker   }
547*795d594fSAndroid Build Coastguard Worker }
548*795d594fSAndroid Build Coastguard Worker 
NativeBridgeError()549*795d594fSAndroid Build Coastguard Worker bool NativeBridgeError() {
550*795d594fSAndroid Build Coastguard Worker   return had_error;
551*795d594fSAndroid Build Coastguard Worker }
552*795d594fSAndroid Build Coastguard Worker 
NativeBridgeAvailable()553*795d594fSAndroid Build Coastguard Worker bool NativeBridgeAvailable() {
554*795d594fSAndroid Build Coastguard Worker   return state == NativeBridgeState::kOpened
555*795d594fSAndroid Build Coastguard Worker       || state == NativeBridgeState::kPreInitialized
556*795d594fSAndroid Build Coastguard Worker       || state == NativeBridgeState::kInitialized;
557*795d594fSAndroid Build Coastguard Worker }
558*795d594fSAndroid Build Coastguard Worker 
NativeBridgeInitialized()559*795d594fSAndroid Build Coastguard Worker bool NativeBridgeInitialized() {
560*795d594fSAndroid Build Coastguard Worker   // Calls of this are supposed to happen in a state where the native bridge is stable, i.e., after
561*795d594fSAndroid Build Coastguard Worker   // Runtime::DidForkFromZygote. In that case we do not need a lock.
562*795d594fSAndroid Build Coastguard Worker   return state == NativeBridgeState::kInitialized;
563*795d594fSAndroid Build Coastguard Worker }
564*795d594fSAndroid Build Coastguard Worker 
NativeBridgeLoadLibrary(const char * libpath,int flag)565*795d594fSAndroid Build Coastguard Worker void* NativeBridgeLoadLibrary(const char* libpath, int flag) {
566*795d594fSAndroid Build Coastguard Worker   if (NativeBridgeInitialized()) {
567*795d594fSAndroid Build Coastguard Worker     return callbacks->loadLibrary(libpath, flag);
568*795d594fSAndroid Build Coastguard Worker   }
569*795d594fSAndroid Build Coastguard Worker   return nullptr;
570*795d594fSAndroid Build Coastguard Worker }
571*795d594fSAndroid Build Coastguard Worker 
NativeBridgeGetTrampoline(void * handle,const char * name,const char * shorty,uint32_t len)572*795d594fSAndroid Build Coastguard Worker void* NativeBridgeGetTrampoline(void* handle, const char* name, const char* shorty,
573*795d594fSAndroid Build Coastguard Worker                                 uint32_t len) {
574*795d594fSAndroid Build Coastguard Worker   return NativeBridgeGetTrampoline2(handle, name, shorty, len, kJNICallTypeRegular);
575*795d594fSAndroid Build Coastguard Worker }
576*795d594fSAndroid Build Coastguard Worker 
NativeBridgeGetTrampoline2(void * handle,const char * name,const char * shorty,uint32_t len,JNICallType jni_call_type)577*795d594fSAndroid Build Coastguard Worker void* NativeBridgeGetTrampoline2(
578*795d594fSAndroid Build Coastguard Worker     void* handle, const char* name, const char* shorty, uint32_t len, JNICallType jni_call_type) {
579*795d594fSAndroid Build Coastguard Worker   if (!NativeBridgeInitialized()) {
580*795d594fSAndroid Build Coastguard Worker     return nullptr;
581*795d594fSAndroid Build Coastguard Worker   }
582*795d594fSAndroid Build Coastguard Worker 
583*795d594fSAndroid Build Coastguard Worker   // For version 1 isCompatibleWith is always true, even though the extensions
584*795d594fSAndroid Build Coastguard Worker   // are not supported, so we need to handle it separately.
585*795d594fSAndroid Build Coastguard Worker   if (callbacks != nullptr && callbacks->version == DEFAULT_VERSION) {
586*795d594fSAndroid Build Coastguard Worker     return callbacks->getTrampoline(handle, name, shorty, len);
587*795d594fSAndroid Build Coastguard Worker   }
588*795d594fSAndroid Build Coastguard Worker 
589*795d594fSAndroid Build Coastguard Worker   if (isCompatibleWith(CRITICAL_NATIVE_SUPPORT_VERSION)) {
590*795d594fSAndroid Build Coastguard Worker     return callbacks->getTrampolineWithJNICallType(handle, name, shorty, len, jni_call_type);
591*795d594fSAndroid Build Coastguard Worker   }
592*795d594fSAndroid Build Coastguard Worker 
593*795d594fSAndroid Build Coastguard Worker   return callbacks->getTrampoline(handle, name, shorty, len);
594*795d594fSAndroid Build Coastguard Worker }
595*795d594fSAndroid Build Coastguard Worker 
NativeBridgeGetTrampolineForFunctionPointer(const void * method,const char * shorty,uint32_t len,JNICallType jni_call_type)596*795d594fSAndroid Build Coastguard Worker void* NativeBridgeGetTrampolineForFunctionPointer(const void* method,
597*795d594fSAndroid Build Coastguard Worker                                                   const char* shorty,
598*795d594fSAndroid Build Coastguard Worker                                                   uint32_t len,
599*795d594fSAndroid Build Coastguard Worker                                                   JNICallType jni_call_type) {
600*795d594fSAndroid Build Coastguard Worker   if (!NativeBridgeInitialized()) {
601*795d594fSAndroid Build Coastguard Worker     return nullptr;
602*795d594fSAndroid Build Coastguard Worker   }
603*795d594fSAndroid Build Coastguard Worker 
604*795d594fSAndroid Build Coastguard Worker   if (isCompatibleWith(CRITICAL_NATIVE_SUPPORT_VERSION)) {
605*795d594fSAndroid Build Coastguard Worker     return callbacks->getTrampolineForFunctionPointer(method, shorty, len, jni_call_type);
606*795d594fSAndroid Build Coastguard Worker   } else {
607*795d594fSAndroid Build Coastguard Worker     ALOGE("not compatible with version %d, getTrampolineFnPtrWithJNICallType() isn't invoked",
608*795d594fSAndroid Build Coastguard Worker           CRITICAL_NATIVE_SUPPORT_VERSION);
609*795d594fSAndroid Build Coastguard Worker     return nullptr;
610*795d594fSAndroid Build Coastguard Worker   }
611*795d594fSAndroid Build Coastguard Worker }
612*795d594fSAndroid Build Coastguard Worker 
NativeBridgeIsSupported(const char * libpath)613*795d594fSAndroid Build Coastguard Worker bool NativeBridgeIsSupported(const char* libpath) {
614*795d594fSAndroid Build Coastguard Worker   if (NativeBridgeInitialized()) {
615*795d594fSAndroid Build Coastguard Worker     return callbacks->isSupported(libpath);
616*795d594fSAndroid Build Coastguard Worker   }
617*795d594fSAndroid Build Coastguard Worker   return false;
618*795d594fSAndroid Build Coastguard Worker }
619*795d594fSAndroid Build Coastguard Worker 
NativeBridgeGetVersion()620*795d594fSAndroid Build Coastguard Worker uint32_t NativeBridgeGetVersion() {
621*795d594fSAndroid Build Coastguard Worker   if (NativeBridgeAvailable()) {
622*795d594fSAndroid Build Coastguard Worker     return callbacks->version;
623*795d594fSAndroid Build Coastguard Worker   }
624*795d594fSAndroid Build Coastguard Worker   return 0;
625*795d594fSAndroid Build Coastguard Worker }
626*795d594fSAndroid Build Coastguard Worker 
NativeBridgeGetSignalHandler(int signal)627*795d594fSAndroid Build Coastguard Worker NativeBridgeSignalHandlerFn NativeBridgeGetSignalHandler(int signal) {
628*795d594fSAndroid Build Coastguard Worker   if (NativeBridgeInitialized()) {
629*795d594fSAndroid Build Coastguard Worker     if (isCompatibleWith(SIGNAL_VERSION)) {
630*795d594fSAndroid Build Coastguard Worker       return callbacks->getSignalHandler(signal);
631*795d594fSAndroid Build Coastguard Worker     } else {
632*795d594fSAndroid Build Coastguard Worker       ALOGE("not compatible with version %d, cannot get signal handler", SIGNAL_VERSION);
633*795d594fSAndroid Build Coastguard Worker     }
634*795d594fSAndroid Build Coastguard Worker   }
635*795d594fSAndroid Build Coastguard Worker   return nullptr;
636*795d594fSAndroid Build Coastguard Worker }
637*795d594fSAndroid Build Coastguard Worker 
NativeBridgeUnloadLibrary(void * handle)638*795d594fSAndroid Build Coastguard Worker int NativeBridgeUnloadLibrary(void* handle) {
639*795d594fSAndroid Build Coastguard Worker   if (NativeBridgeInitialized()) {
640*795d594fSAndroid Build Coastguard Worker     if (isCompatibleWith(NAMESPACE_VERSION)) {
641*795d594fSAndroid Build Coastguard Worker       return callbacks->unloadLibrary(handle);
642*795d594fSAndroid Build Coastguard Worker     } else {
643*795d594fSAndroid Build Coastguard Worker       ALOGE("not compatible with version %d, cannot unload library", NAMESPACE_VERSION);
644*795d594fSAndroid Build Coastguard Worker     }
645*795d594fSAndroid Build Coastguard Worker   }
646*795d594fSAndroid Build Coastguard Worker   return -1;
647*795d594fSAndroid Build Coastguard Worker }
648*795d594fSAndroid Build Coastguard Worker 
NativeBridgeGetError()649*795d594fSAndroid Build Coastguard Worker const char* NativeBridgeGetError() {
650*795d594fSAndroid Build Coastguard Worker   if (NativeBridgeInitialized()) {
651*795d594fSAndroid Build Coastguard Worker     if (isCompatibleWith(NAMESPACE_VERSION)) {
652*795d594fSAndroid Build Coastguard Worker       return callbacks->getError();
653*795d594fSAndroid Build Coastguard Worker     } else {
654*795d594fSAndroid Build Coastguard Worker       return "native bridge implementation is not compatible with version 3, cannot get message";
655*795d594fSAndroid Build Coastguard Worker     }
656*795d594fSAndroid Build Coastguard Worker   }
657*795d594fSAndroid Build Coastguard Worker   return "native bridge is not initialized";
658*795d594fSAndroid Build Coastguard Worker }
659*795d594fSAndroid Build Coastguard Worker 
NativeBridgeIsPathSupported(const char * path)660*795d594fSAndroid Build Coastguard Worker bool NativeBridgeIsPathSupported(const char* path) {
661*795d594fSAndroid Build Coastguard Worker   if (NativeBridgeInitialized()) {
662*795d594fSAndroid Build Coastguard Worker     if (isCompatibleWith(NAMESPACE_VERSION)) {
663*795d594fSAndroid Build Coastguard Worker       return callbacks->isPathSupported(path);
664*795d594fSAndroid Build Coastguard Worker     } else {
665*795d594fSAndroid Build Coastguard Worker       ALOGE("not compatible with version %d, cannot check via library path", NAMESPACE_VERSION);
666*795d594fSAndroid Build Coastguard Worker     }
667*795d594fSAndroid Build Coastguard Worker   }
668*795d594fSAndroid Build Coastguard Worker   return false;
669*795d594fSAndroid Build Coastguard Worker }
670*795d594fSAndroid Build Coastguard Worker 
NativeBridgeCreateNamespace(const char * name,const char * ld_library_path,const char * default_library_path,uint64_t type,const char * permitted_when_isolated_path,native_bridge_namespace_t * parent_ns)671*795d594fSAndroid Build Coastguard Worker native_bridge_namespace_t* NativeBridgeCreateNamespace(const char* name,
672*795d594fSAndroid Build Coastguard Worker                                                        const char* ld_library_path,
673*795d594fSAndroid Build Coastguard Worker                                                        const char* default_library_path,
674*795d594fSAndroid Build Coastguard Worker                                                        uint64_t type,
675*795d594fSAndroid Build Coastguard Worker                                                        const char* permitted_when_isolated_path,
676*795d594fSAndroid Build Coastguard Worker                                                        native_bridge_namespace_t* parent_ns) {
677*795d594fSAndroid Build Coastguard Worker   if (NativeBridgeInitialized()) {
678*795d594fSAndroid Build Coastguard Worker     if (isCompatibleWith(NAMESPACE_VERSION)) {
679*795d594fSAndroid Build Coastguard Worker       return callbacks->createNamespace(name,
680*795d594fSAndroid Build Coastguard Worker                                         ld_library_path,
681*795d594fSAndroid Build Coastguard Worker                                         default_library_path,
682*795d594fSAndroid Build Coastguard Worker                                         type,
683*795d594fSAndroid Build Coastguard Worker                                         permitted_when_isolated_path,
684*795d594fSAndroid Build Coastguard Worker                                         parent_ns);
685*795d594fSAndroid Build Coastguard Worker     } else {
686*795d594fSAndroid Build Coastguard Worker       ALOGE("not compatible with version %d, cannot create namespace %s", NAMESPACE_VERSION, name);
687*795d594fSAndroid Build Coastguard Worker     }
688*795d594fSAndroid Build Coastguard Worker   }
689*795d594fSAndroid Build Coastguard Worker 
690*795d594fSAndroid Build Coastguard Worker   return nullptr;
691*795d594fSAndroid Build Coastguard Worker }
692*795d594fSAndroid Build Coastguard Worker 
NativeBridgeLinkNamespaces(native_bridge_namespace_t * from,native_bridge_namespace_t * to,const char * shared_libs_sonames)693*795d594fSAndroid Build Coastguard Worker bool NativeBridgeLinkNamespaces(native_bridge_namespace_t* from, native_bridge_namespace_t* to,
694*795d594fSAndroid Build Coastguard Worker                                 const char* shared_libs_sonames) {
695*795d594fSAndroid Build Coastguard Worker   if (NativeBridgeInitialized()) {
696*795d594fSAndroid Build Coastguard Worker     if (isCompatibleWith(NAMESPACE_VERSION)) {
697*795d594fSAndroid Build Coastguard Worker       return callbacks->linkNamespaces(from, to, shared_libs_sonames);
698*795d594fSAndroid Build Coastguard Worker     } else {
699*795d594fSAndroid Build Coastguard Worker       ALOGE("not compatible with version %d, cannot init namespace", NAMESPACE_VERSION);
700*795d594fSAndroid Build Coastguard Worker     }
701*795d594fSAndroid Build Coastguard Worker   }
702*795d594fSAndroid Build Coastguard Worker 
703*795d594fSAndroid Build Coastguard Worker   return false;
704*795d594fSAndroid Build Coastguard Worker }
705*795d594fSAndroid Build Coastguard Worker 
NativeBridgeGetExportedNamespace(const char * name)706*795d594fSAndroid Build Coastguard Worker native_bridge_namespace_t* NativeBridgeGetExportedNamespace(const char* name) {
707*795d594fSAndroid Build Coastguard Worker   if (!NativeBridgeInitialized()) {
708*795d594fSAndroid Build Coastguard Worker     return nullptr;
709*795d594fSAndroid Build Coastguard Worker   }
710*795d594fSAndroid Build Coastguard Worker 
711*795d594fSAndroid Build Coastguard Worker   if (isCompatibleWith(RUNTIME_NAMESPACE_VERSION)) {
712*795d594fSAndroid Build Coastguard Worker     return callbacks->getExportedNamespace(name);
713*795d594fSAndroid Build Coastguard Worker   }
714*795d594fSAndroid Build Coastguard Worker 
715*795d594fSAndroid Build Coastguard Worker   // sphal is vendor namespace name -> use v4 callback in the case NB callbacks
716*795d594fSAndroid Build Coastguard Worker   // are not compatible with v5
717*795d594fSAndroid Build Coastguard Worker   if (isCompatibleWith(VENDOR_NAMESPACE_VERSION) && name != nullptr && strcmp("sphal", name) == 0) {
718*795d594fSAndroid Build Coastguard Worker     return callbacks->getVendorNamespace();
719*795d594fSAndroid Build Coastguard Worker   }
720*795d594fSAndroid Build Coastguard Worker 
721*795d594fSAndroid Build Coastguard Worker   return nullptr;
722*795d594fSAndroid Build Coastguard Worker }
723*795d594fSAndroid Build Coastguard Worker 
NativeBridgeLoadLibraryExt(const char * libpath,int flag,native_bridge_namespace_t * ns)724*795d594fSAndroid Build Coastguard Worker void* NativeBridgeLoadLibraryExt(const char* libpath, int flag, native_bridge_namespace_t* ns) {
725*795d594fSAndroid Build Coastguard Worker   if (NativeBridgeInitialized()) {
726*795d594fSAndroid Build Coastguard Worker     if (isCompatibleWith(NAMESPACE_VERSION)) {
727*795d594fSAndroid Build Coastguard Worker       return callbacks->loadLibraryExt(libpath, flag, ns);
728*795d594fSAndroid Build Coastguard Worker     } else {
729*795d594fSAndroid Build Coastguard Worker       ALOGE("not compatible with version %d, cannot load library in namespace", NAMESPACE_VERSION);
730*795d594fSAndroid Build Coastguard Worker     }
731*795d594fSAndroid Build Coastguard Worker   }
732*795d594fSAndroid Build Coastguard Worker   return nullptr;
733*795d594fSAndroid Build Coastguard Worker }
734*795d594fSAndroid Build Coastguard Worker 
735*795d594fSAndroid Build Coastguard Worker }  // extern "C"
736*795d594fSAndroid Build Coastguard Worker 
737*795d594fSAndroid Build Coastguard Worker }  // namespace android
738