• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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 "nativeloader/native_loader.h"
18 #include <nativehelper/ScopedUtfChars.h>
19 
20 #include <dlfcn.h>
21 #ifdef __ANDROID__
22 #define LOG_TAG "libnativeloader"
23 #include "nativeloader/dlext_namespaces.h"
24 #include "cutils/properties.h"
25 #include "log/log.h"
26 #endif
27 #include "nativebridge/native_bridge.h"
28 
29 #include <algorithm>
30 #include <vector>
31 #include <string>
32 #include <mutex>
33 
34 #include <android-base/file.h>
35 #include <android-base/macros.h>
36 #include <android-base/strings.h>
37 
38 #define CHECK(predicate) LOG_ALWAYS_FATAL_IF(!(predicate),\
39                                              "%s:%d: %s CHECK '" #predicate "' failed.",\
40                                              __FILE__, __LINE__, __FUNCTION__)
41 
42 namespace android {
43 
44 #if defined(__ANDROID__)
45 class NativeLoaderNamespace {
46  public:
NativeLoaderNamespace()47   NativeLoaderNamespace()
48       : android_ns_(nullptr), native_bridge_ns_(nullptr) { }
49 
NativeLoaderNamespace(android_namespace_t * ns)50   explicit NativeLoaderNamespace(android_namespace_t* ns)
51       : android_ns_(ns), native_bridge_ns_(nullptr) { }
52 
NativeLoaderNamespace(native_bridge_namespace_t * ns)53   explicit NativeLoaderNamespace(native_bridge_namespace_t* ns)
54       : android_ns_(nullptr), native_bridge_ns_(ns) { }
55 
56   NativeLoaderNamespace(NativeLoaderNamespace&& that) = default;
57   NativeLoaderNamespace(const NativeLoaderNamespace& that) = default;
58 
59   NativeLoaderNamespace& operator=(const NativeLoaderNamespace& that) = default;
60 
get_android_ns() const61   android_namespace_t* get_android_ns() const {
62     CHECK(native_bridge_ns_ == nullptr);
63     return android_ns_;
64   }
65 
get_native_bridge_ns() const66   native_bridge_namespace_t* get_native_bridge_ns() const {
67     CHECK(android_ns_ == nullptr);
68     return native_bridge_ns_;
69   }
70 
is_android_namespace() const71   bool is_android_namespace() const {
72     return native_bridge_ns_ == nullptr;
73   }
74 
75  private:
76   // Only one of them can be not null
77   android_namespace_t* android_ns_;
78   native_bridge_namespace_t* native_bridge_ns_;
79 };
80 
81 static constexpr const char* kPublicNativeLibrariesSystemConfigPathFromRoot =
82                                   "/etc/public.libraries.txt";
83 static constexpr const char* kPublicNativeLibrariesVendorConfig =
84                                   "/vendor/etc/public.libraries.txt";
85 static constexpr const char* kLlndkNativeLibrariesSystemConfigPathFromRoot =
86                                   "/etc/llndk.libraries.txt";
87 static constexpr const char* kVndkspNativeLibrariesSystemConfigPathFromRoot =
88                                   "/etc/vndksp.libraries.txt";
89 
90 
91 // The device may be configured to have the vendor libraries loaded to a separate namespace.
92 // For historical reasons this namespace was named sphal but effectively it is intended
93 // to use to load vendor libraries to separate namespace with controlled interface between
94 // vendor and system namespaces.
95 static constexpr const char* kVendorNamespaceName = "sphal";
96 
97 static constexpr const char* kVndkNamespaceName = "vndk";
98 
99 static constexpr const char* kClassloaderNamespaceName = "classloader-namespace";
100 static constexpr const char* kVendorClassloaderNamespaceName = "vendor-classloader-namespace";
101 
102 // (http://b/27588281) This is a workaround for apps using custom classloaders and calling
103 // System.load() with an absolute path which is outside of the classloader library search path.
104 // This list includes all directories app is allowed to access this way.
105 static constexpr const char* kWhitelistedDirectories = "/data:/mnt/expand";
106 
is_debuggable()107 static bool is_debuggable() {
108   char debuggable[PROP_VALUE_MAX];
109   property_get("ro.debuggable", debuggable, "0");
110   return std::string(debuggable) == "1";
111 }
112 
113 class LibraryNamespaces {
114  public:
LibraryNamespaces()115   LibraryNamespaces() : initialized_(false) { }
116 
Create(JNIEnv * env,uint32_t target_sdk_version,jobject class_loader,bool is_shared,bool is_for_vendor,jstring java_library_path,jstring java_permitted_path,NativeLoaderNamespace * ns,std::string * error_msg)117   bool Create(JNIEnv* env,
118               uint32_t target_sdk_version,
119               jobject class_loader,
120               bool is_shared,
121               bool is_for_vendor,
122               jstring java_library_path,
123               jstring java_permitted_path,
124               NativeLoaderNamespace* ns,
125               std::string* error_msg) {
126     std::string library_path; // empty string by default.
127 
128     if (java_library_path != nullptr) {
129       ScopedUtfChars library_path_utf_chars(env, java_library_path);
130       library_path = library_path_utf_chars.c_str();
131     }
132 
133     // (http://b/27588281) This is a workaround for apps using custom
134     // classloaders and calling System.load() with an absolute path which
135     // is outside of the classloader library search path.
136     //
137     // This part effectively allows such a classloader to access anything
138     // under /data and /mnt/expand
139     std::string permitted_path = kWhitelistedDirectories;
140 
141     if (java_permitted_path != nullptr) {
142       ScopedUtfChars path(env, java_permitted_path);
143       if (path.c_str() != nullptr && path.size() > 0) {
144         permitted_path = permitted_path + ":" + path.c_str();
145       }
146     }
147 
148     if (!initialized_ && !InitPublicNamespace(library_path.c_str(), error_msg)) {
149       return false;
150     }
151 
152     bool found = FindNamespaceByClassLoader(env, class_loader, nullptr);
153 
154     LOG_ALWAYS_FATAL_IF(found,
155                         "There is already a namespace associated with this classloader");
156 
157     uint64_t namespace_type = ANDROID_NAMESPACE_TYPE_ISOLATED;
158     if (is_shared) {
159       namespace_type |= ANDROID_NAMESPACE_TYPE_SHARED;
160     }
161 
162     if (target_sdk_version < 24) {
163       namespace_type |= ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED;
164     }
165 
166     NativeLoaderNamespace parent_ns;
167     bool found_parent_namespace = FindParentNamespaceByClassLoader(env, class_loader, &parent_ns);
168 
169     bool is_native_bridge = false;
170 
171     if (found_parent_namespace) {
172       is_native_bridge = !parent_ns.is_android_namespace();
173     } else if (!library_path.empty()) {
174       is_native_bridge = NativeBridgeIsPathSupported(library_path.c_str());
175     }
176 
177     std::string system_exposed_libraries = system_public_libraries_;
178     const char* namespace_name = kClassloaderNamespaceName;
179     android_namespace_t* vndk_ns = nullptr;
180     if (is_for_vendor && !is_shared) {
181       LOG_FATAL_IF(is_native_bridge, "Unbundled vendor apk must not use translated architecture");
182 
183       // For vendor apks, give access to the vendor lib even though
184       // they are treated as unbundled; the libs and apks are still bundled
185       // together in the vendor partition.
186 #if defined(__LP64__)
187       std::string vendor_lib_path = "/vendor/lib64";
188 #else
189       std::string vendor_lib_path = "/vendor/lib";
190 #endif
191       library_path = library_path + ":" + vendor_lib_path.c_str();
192       permitted_path = permitted_path + ":" + vendor_lib_path.c_str();
193 
194       // Also give access to LLNDK libraries since they are available to vendors
195       system_exposed_libraries = system_exposed_libraries + ":" + system_llndk_libraries_.c_str();
196 
197       // Give access to VNDK-SP libraries from the 'vndk' namespace.
198       vndk_ns = android_get_exported_namespace(kVndkNamespaceName);
199       LOG_ALWAYS_FATAL_IF(vndk_ns == nullptr,
200                           "Cannot find \"%s\" namespace for vendor apks", kVndkNamespaceName);
201 
202       // Different name is useful for debugging
203       namespace_name = kVendorClassloaderNamespaceName;
204       ALOGD("classloader namespace configured for unbundled vendor apk. library_path=%s", library_path.c_str());
205     }
206 
207     NativeLoaderNamespace native_loader_ns;
208     if (!is_native_bridge) {
209       android_namespace_t* ns = android_create_namespace(namespace_name,
210                                                          nullptr,
211                                                          library_path.c_str(),
212                                                          namespace_type,
213                                                          permitted_path.c_str(),
214                                                          parent_ns.get_android_ns());
215       if (ns == nullptr) {
216         *error_msg = dlerror();
217         return false;
218       }
219 
220       // Note that when vendor_ns is not configured this function will return nullptr
221       // and it will result in linking vendor_public_libraries_ to the default namespace
222       // which is expected behavior in this case.
223       android_namespace_t* vendor_ns = android_get_exported_namespace(kVendorNamespaceName);
224 
225       if (!android_link_namespaces(ns, nullptr, system_exposed_libraries.c_str())) {
226         *error_msg = dlerror();
227         return false;
228       }
229 
230       if (vndk_ns != nullptr && !system_vndksp_libraries_.empty()) {
231         // vendor apks are allowed to use VNDK-SP libraries.
232         if (!android_link_namespaces(ns, vndk_ns, system_vndksp_libraries_.c_str())) {
233           *error_msg = dlerror();
234           return false;
235         }
236       }
237 
238       if (!vendor_public_libraries_.empty()) {
239         if (!android_link_namespaces(ns, vendor_ns, vendor_public_libraries_.c_str())) {
240           *error_msg = dlerror();
241           return false;
242         }
243       }
244 
245       native_loader_ns = NativeLoaderNamespace(ns);
246     } else {
247       native_bridge_namespace_t* ns = NativeBridgeCreateNamespace(namespace_name,
248                                                                   nullptr,
249                                                                   library_path.c_str(),
250                                                                   namespace_type,
251                                                                   permitted_path.c_str(),
252                                                                   parent_ns.get_native_bridge_ns());
253 
254       if (ns == nullptr) {
255         *error_msg = NativeBridgeGetError();
256         return false;
257       }
258 
259       native_bridge_namespace_t* vendor_ns = NativeBridgeGetVendorNamespace();
260 
261       if (!NativeBridgeLinkNamespaces(ns, nullptr, system_exposed_libraries.c_str())) {
262         *error_msg = NativeBridgeGetError();
263         return false;
264       }
265 
266       if (!vendor_public_libraries_.empty()) {
267         if (!NativeBridgeLinkNamespaces(ns, vendor_ns, vendor_public_libraries_.c_str())) {
268           *error_msg = NativeBridgeGetError();
269           return false;
270         }
271       }
272 
273       native_loader_ns = NativeLoaderNamespace(ns);
274     }
275 
276     namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), native_loader_ns));
277 
278     *ns = native_loader_ns;
279     return true;
280   }
281 
FindNamespaceByClassLoader(JNIEnv * env,jobject class_loader,NativeLoaderNamespace * ns)282   bool FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader, NativeLoaderNamespace* ns) {
283     auto it = std::find_if(namespaces_.begin(), namespaces_.end(),
284                 [&](const std::pair<jweak, NativeLoaderNamespace>& value) {
285                   return env->IsSameObject(value.first, class_loader);
286                 });
287     if (it != namespaces_.end()) {
288       if (ns != nullptr) {
289         *ns = it->second;
290       }
291 
292       return true;
293     }
294 
295     return false;
296   }
297 
Initialize()298   void Initialize() {
299     // Once public namespace is initialized there is no
300     // point in running this code - it will have no effect
301     // on the current list of public libraries.
302     if (initialized_) {
303       return;
304     }
305 
306     std::vector<std::string> sonames;
307     const char* android_root_env = getenv("ANDROID_ROOT");
308     std::string root_dir = android_root_env != nullptr ? android_root_env : "/system";
309     std::string public_native_libraries_system_config =
310             root_dir + kPublicNativeLibrariesSystemConfigPathFromRoot;
311     std::string llndk_native_libraries_system_config =
312             root_dir + kLlndkNativeLibrariesSystemConfigPathFromRoot;
313     std::string vndksp_native_libraries_system_config =
314             root_dir + kVndkspNativeLibrariesSystemConfigPathFromRoot;
315 
316     std::string error_msg;
317     LOG_ALWAYS_FATAL_IF(!ReadConfig(public_native_libraries_system_config, &sonames, &error_msg),
318                         "Error reading public native library list from \"%s\": %s",
319                         public_native_libraries_system_config.c_str(), error_msg.c_str());
320 
321     // For debuggable platform builds use ANDROID_ADDITIONAL_PUBLIC_LIBRARIES environment
322     // variable to add libraries to the list. This is intended for platform tests only.
323     if (is_debuggable()) {
324       const char* additional_libs = getenv("ANDROID_ADDITIONAL_PUBLIC_LIBRARIES");
325       if (additional_libs != nullptr && additional_libs[0] != '\0') {
326         std::vector<std::string> additional_libs_vector = base::Split(additional_libs, ":");
327         std::copy(additional_libs_vector.begin(),
328                   additional_libs_vector.end(),
329                   std::back_inserter(sonames));
330       }
331     }
332 
333     // android_init_namespaces() expects all the public libraries
334     // to be loaded so that they can be found by soname alone.
335     //
336     // TODO(dimitry): this is a bit misleading since we do not know
337     // if the vendor public library is going to be opened from /vendor/lib
338     // we might as well end up loading them from /system/lib
339     // For now we rely on CTS test to catch things like this but
340     // it should probably be addressed in the future.
341     for (const auto& soname : sonames) {
342       LOG_ALWAYS_FATAL_IF(dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE) == nullptr,
343                           "Error preloading public library %s: %s",
344                           soname.c_str(), dlerror());
345     }
346 
347     system_public_libraries_ = base::Join(sonames, ':');
348 
349     sonames.clear();
350     ReadConfig(kLlndkNativeLibrariesSystemConfigPathFromRoot, &sonames);
351     system_llndk_libraries_ = base::Join(sonames, ':');
352 
353     sonames.clear();
354     ReadConfig(kVndkspNativeLibrariesSystemConfigPathFromRoot, &sonames);
355     system_vndksp_libraries_ = base::Join(sonames, ':');
356 
357     sonames.clear();
358     // This file is optional, quietly ignore if the file does not exist.
359     ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames);
360 
361     vendor_public_libraries_ = base::Join(sonames, ':');
362   }
363 
Reset()364   void Reset() {
365     namespaces_.clear();
366   }
367 
368  private:
ReadConfig(const std::string & configFile,std::vector<std::string> * sonames,std::string * error_msg=nullptr)369   bool ReadConfig(const std::string& configFile, std::vector<std::string>* sonames,
370                   std::string* error_msg = nullptr) {
371     // Read list of public native libraries from the config file.
372     std::string file_content;
373     if(!base::ReadFileToString(configFile, &file_content)) {
374       if (error_msg) *error_msg = strerror(errno);
375       return false;
376     }
377 
378     std::vector<std::string> lines = base::Split(file_content, "\n");
379 
380     for (auto& line : lines) {
381       auto trimmed_line = base::Trim(line);
382       if (trimmed_line[0] == '#' || trimmed_line.empty()) {
383         continue;
384       }
385       size_t space_pos = trimmed_line.rfind(' ');
386       if (space_pos != std::string::npos) {
387         std::string type = trimmed_line.substr(space_pos + 1);
388         if (type != "32" && type != "64") {
389           if (error_msg) *error_msg = "Malformed line: " + line;
390           return false;
391         }
392 #if defined(__LP64__)
393         // Skip 32 bit public library.
394         if (type == "32") {
395           continue;
396         }
397 #else
398         // Skip 64 bit public library.
399         if (type == "64") {
400           continue;
401         }
402 #endif
403         trimmed_line.resize(space_pos);
404       }
405 
406       sonames->push_back(trimmed_line);
407     }
408 
409     return true;
410   }
411 
InitPublicNamespace(const char * library_path,std::string * error_msg)412   bool InitPublicNamespace(const char* library_path, std::string* error_msg) {
413     // Ask native bride if this apps library path should be handled by it
414     bool is_native_bridge = NativeBridgeIsPathSupported(library_path);
415 
416     // (http://b/25844435) - Some apps call dlopen from generated code (mono jited
417     // code is one example) unknown to linker in which  case linker uses anonymous
418     // namespace. The second argument specifies the search path for the anonymous
419     // namespace which is the library_path of the classloader.
420     initialized_ = android_init_anonymous_namespace(system_public_libraries_.c_str(),
421                                                     is_native_bridge ? nullptr : library_path);
422     if (!initialized_) {
423       *error_msg = dlerror();
424       return false;
425     }
426 
427     // and now initialize native bridge namespaces if necessary.
428     if (NativeBridgeInitialized()) {
429       initialized_ = NativeBridgeInitAnonymousNamespace(system_public_libraries_.c_str(),
430                                                         is_native_bridge ? library_path : nullptr);
431       if (!initialized_) {
432         *error_msg = NativeBridgeGetError();
433       }
434     }
435 
436     return initialized_;
437   }
438 
GetParentClassLoader(JNIEnv * env,jobject class_loader)439   jobject GetParentClassLoader(JNIEnv* env, jobject class_loader) {
440     jclass class_loader_class = env->FindClass("java/lang/ClassLoader");
441     jmethodID get_parent = env->GetMethodID(class_loader_class,
442                                             "getParent",
443                                             "()Ljava/lang/ClassLoader;");
444 
445     return env->CallObjectMethod(class_loader, get_parent);
446   }
447 
FindParentNamespaceByClassLoader(JNIEnv * env,jobject class_loader,NativeLoaderNamespace * ns)448   bool FindParentNamespaceByClassLoader(JNIEnv* env,
449                                         jobject class_loader,
450                                         NativeLoaderNamespace* ns) {
451     jobject parent_class_loader = GetParentClassLoader(env, class_loader);
452 
453     while (parent_class_loader != nullptr) {
454       if (FindNamespaceByClassLoader(env, parent_class_loader, ns)) {
455         return true;
456       }
457 
458       parent_class_loader = GetParentClassLoader(env, parent_class_loader);
459     }
460 
461     return false;
462   }
463 
464   bool initialized_;
465   std::vector<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
466   std::string system_public_libraries_;
467   std::string vendor_public_libraries_;
468   std::string system_llndk_libraries_;
469   std::string system_vndksp_libraries_;
470 
471   DISALLOW_COPY_AND_ASSIGN(LibraryNamespaces);
472 };
473 
474 static std::mutex g_namespaces_mutex;
475 static LibraryNamespaces* g_namespaces = new LibraryNamespaces;
476 #endif
477 
InitializeNativeLoader()478 void InitializeNativeLoader() {
479 #if defined(__ANDROID__)
480   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
481   g_namespaces->Initialize();
482 #endif
483 }
484 
ResetNativeLoader()485 void ResetNativeLoader() {
486 #if defined(__ANDROID__)
487   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
488   g_namespaces->Reset();
489 #endif
490 }
491 
CreateClassLoaderNamespace(JNIEnv * env,int32_t target_sdk_version,jobject class_loader,bool is_shared,bool is_for_vendor,jstring library_path,jstring permitted_path)492 jstring CreateClassLoaderNamespace(JNIEnv* env,
493                                    int32_t target_sdk_version,
494                                    jobject class_loader,
495                                    bool is_shared,
496                                    bool is_for_vendor,
497                                    jstring library_path,
498                                    jstring permitted_path) {
499 #if defined(__ANDROID__)
500   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
501 
502   std::string error_msg;
503   NativeLoaderNamespace ns;
504   bool success = g_namespaces->Create(env,
505                                       target_sdk_version,
506                                       class_loader,
507                                       is_shared,
508                                       is_for_vendor,
509                                       library_path,
510                                       permitted_path,
511                                       &ns,
512                                       &error_msg);
513   if (!success) {
514     return env->NewStringUTF(error_msg.c_str());
515   }
516 #else
517   UNUSED(env, target_sdk_version, class_loader, is_shared, is_for_vendor,
518          library_path, permitted_path);
519 #endif
520   return nullptr;
521 }
522 
OpenNativeLibrary(JNIEnv * env,int32_t target_sdk_version,const char * path,jobject class_loader,jstring library_path,bool * needs_native_bridge,std::string * error_msg)523 void* OpenNativeLibrary(JNIEnv* env,
524                         int32_t target_sdk_version,
525                         const char* path,
526                         jobject class_loader,
527                         jstring library_path,
528                         bool* needs_native_bridge,
529                         std::string* error_msg) {
530 #if defined(__ANDROID__)
531   UNUSED(target_sdk_version);
532   if (class_loader == nullptr) {
533     *needs_native_bridge = false;
534     return dlopen(path, RTLD_NOW);
535   }
536 
537   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
538   NativeLoaderNamespace ns;
539 
540   if (!g_namespaces->FindNamespaceByClassLoader(env, class_loader, &ns)) {
541     // This is the case where the classloader was not created by ApplicationLoaders
542     // In this case we create an isolated not-shared namespace for it.
543     if (!g_namespaces->Create(env,
544                               target_sdk_version,
545                               class_loader,
546                               false /* is_shared */,
547                               false /* is_for_vendor */,
548                               library_path,
549                               nullptr,
550                               &ns,
551                               error_msg)) {
552       return nullptr;
553     }
554   }
555 
556   if (ns.is_android_namespace()) {
557     android_dlextinfo extinfo;
558     extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
559     extinfo.library_namespace = ns.get_android_ns();
560 
561     void* handle = android_dlopen_ext(path, RTLD_NOW, &extinfo);
562     if (handle == nullptr) {
563       *error_msg = dlerror();
564     }
565     *needs_native_bridge = false;
566     return handle;
567   } else {
568     void* handle = NativeBridgeLoadLibraryExt(path, RTLD_NOW, ns.get_native_bridge_ns());
569     if (handle == nullptr) {
570       *error_msg = NativeBridgeGetError();
571     }
572     *needs_native_bridge = true;
573     return handle;
574   }
575 #else
576   UNUSED(env, target_sdk_version, class_loader, library_path);
577   *needs_native_bridge = false;
578   void* handle = dlopen(path, RTLD_NOW);
579   if (handle == nullptr) {
580     if (NativeBridgeIsSupported(path)) {
581       *needs_native_bridge = true;
582       handle = NativeBridgeLoadLibrary(path, RTLD_NOW);
583       if (handle == nullptr) {
584         *error_msg = NativeBridgeGetError();
585       }
586     } else {
587       *needs_native_bridge = false;
588       *error_msg = dlerror();
589     }
590   }
591   return handle;
592 #endif
593 }
594 
CloseNativeLibrary(void * handle,const bool needs_native_bridge)595 bool CloseNativeLibrary(void* handle, const bool needs_native_bridge) {
596     return needs_native_bridge ? NativeBridgeUnloadLibrary(handle) :
597                                  dlclose(handle);
598 }
599 
600 #if defined(__ANDROID__)
601 // native_bridge_namespaces are not supported for callers of this function.
602 // This function will return nullptr in the case when application is running
603 // on native bridge.
FindNamespaceByClassLoader(JNIEnv * env,jobject class_loader)604 android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
605   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
606   NativeLoaderNamespace ns;
607   if (g_namespaces->FindNamespaceByClassLoader(env, class_loader, &ns)) {
608     return ns.is_android_namespace() ? ns.get_android_ns() : nullptr;
609   }
610 
611   return nullptr;
612 }
613 #endif
614 
615 }; //  android namespace
616