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