• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 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 ATRACE_TAG ATRACE_TAG_GRAPHICS
18 
19 //#define LOG_NDEBUG 1
20 #define LOG_TAG "GraphicsEnv"
21 
22 #include <graphicsenv/GraphicsEnv.h>
23 
24 #include <dlfcn.h>
25 #include <unistd.h>
26 
27 #include <android-base/file.h>
28 #include <android-base/properties.h>
29 #include <android-base/strings.h>
30 #include <android/dlext.h>
31 #include <binder/IServiceManager.h>
32 #include <graphicsenv/IGpuService.h>
33 #include <log/log.h>
34 #include <nativeloader/dlext_namespaces.h>
35 #include <sys/prctl.h>
36 #include <utils/Trace.h>
37 
38 #include <memory>
39 #include <string>
40 #include <thread>
41 
42 // TODO(b/159240322): Extend this to x86 ABI.
43 #if defined(__LP64__)
44 #define UPDATABLE_DRIVER_ABI "arm64-v8a"
45 #else
46 #define UPDATABLE_DRIVER_ABI "armeabi-v7a"
47 #endif // defined(__LP64__)
48 
49 // TODO(ianelliott@): Get the following from an ANGLE header:
50 #define CURRENT_ANGLE_API_VERSION 2 // Current API verion we are targetting
51 // Version-2 API:
52 typedef bool (*fpANGLEGetFeatureSupportUtilAPIVersion)(unsigned int* versionToUse);
53 typedef bool (*fpANGLEAndroidParseRulesString)(const char* rulesString, void** rulesHandle,
54                                                int* rulesVersion);
55 typedef bool (*fpANGLEGetSystemInfo)(void** handle);
56 typedef bool (*fpANGLEAddDeviceInfoToSystemInfo)(const char* deviceMfr, const char* deviceModel,
57                                                  void* handle);
58 typedef bool (*fpANGLEShouldBeUsedForApplication)(void* rulesHandle, int rulesVersion,
59                                                   void* systemInfoHandle, const char* appName);
60 typedef bool (*fpANGLEFreeRulesHandle)(void* handle);
61 typedef bool (*fpANGLEFreeSystemInfoHandle)(void* handle);
62 
63 namespace android {
64 
65 enum NativeLibrary {
66     LLNDK = 0,
67     VNDKSP = 1,
68 };
69 
70 static constexpr const char* kNativeLibrariesSystemConfigPath[] =
71         {"/apex/com.android.vndk.v{}/etc/llndk.libraries.{}.txt",
72          "/apex/com.android.vndk.v{}/etc/vndksp.libraries.{}.txt"};
73 
vndkVersionStr()74 static std::string vndkVersionStr() {
75 #ifdef __BIONIC__
76     return base::GetProperty("ro.vndk.version", "");
77 #endif
78     return "";
79 }
80 
insertVndkVersionStr(std::string * fileName)81 static void insertVndkVersionStr(std::string* fileName) {
82     LOG_ALWAYS_FATAL_IF(!fileName, "fileName should never be nullptr");
83     std::string version = vndkVersionStr();
84     size_t pos = fileName->find("{}");
85     while (pos != std::string::npos) {
86         fileName->replace(pos, 2, version);
87         pos = fileName->find("{}", pos + version.size());
88     }
89 }
90 
readConfig(const std::string & configFile,std::vector<std::string> * soNames)91 static bool readConfig(const std::string& configFile, std::vector<std::string>* soNames) {
92     // Read list of public native libraries from the config file.
93     std::string fileContent;
94     if (!base::ReadFileToString(configFile, &fileContent)) {
95         return false;
96     }
97 
98     std::vector<std::string> lines = base::Split(fileContent, "\n");
99 
100     for (auto& line : lines) {
101         auto trimmedLine = base::Trim(line);
102         if (!trimmedLine.empty()) {
103             soNames->push_back(trimmedLine);
104         }
105     }
106 
107     return true;
108 }
109 
getSystemNativeLibraries(NativeLibrary type)110 static const std::string getSystemNativeLibraries(NativeLibrary type) {
111     std::string nativeLibrariesSystemConfig = kNativeLibrariesSystemConfigPath[type];
112     insertVndkVersionStr(&nativeLibrariesSystemConfig);
113 
114     std::vector<std::string> soNames;
115     if (!readConfig(nativeLibrariesSystemConfig, &soNames)) {
116         ALOGE("Failed to retrieve library names from %s", nativeLibrariesSystemConfig.c_str());
117         return "";
118     }
119 
120     return base::Join(soNames, ':');
121 }
122 
getInstance()123 /*static*/ GraphicsEnv& GraphicsEnv::getInstance() {
124     static GraphicsEnv env;
125     return env;
126 }
127 
isDebuggable()128 bool GraphicsEnv::isDebuggable() {
129     // This flag determines if the application is marked debuggable
130     bool appDebuggable = prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) > 0;
131 
132     // This flag is set only in `debuggable` builds of the platform
133 #if defined(ANDROID_DEBUGGABLE)
134     bool platformDebuggable = true;
135 #else
136     bool platformDebuggable = false;
137 #endif
138 
139     ALOGV("GraphicsEnv::isDebuggable returning appDebuggable=%s || platformDebuggable=%s",
140           appDebuggable ? "true" : "false", platformDebuggable ? "true" : "false");
141 
142     return appDebuggable || platformDebuggable;
143 }
144 
setDriverPathAndSphalLibraries(const std::string path,const std::string sphalLibraries)145 void GraphicsEnv::setDriverPathAndSphalLibraries(const std::string path,
146                                                  const std::string sphalLibraries) {
147     if (!mDriverPath.empty() || !mSphalLibraries.empty()) {
148         ALOGV("ignoring attempt to change driver path from '%s' to '%s' or change sphal libraries "
149               "from '%s' to '%s'",
150               mDriverPath.c_str(), path.c_str(), mSphalLibraries.c_str(), sphalLibraries.c_str());
151         return;
152     }
153     ALOGV("setting driver path to '%s' and sphal libraries to '%s'", path.c_str(),
154           sphalLibraries.c_str());
155     mDriverPath = path;
156     mSphalLibraries = sphalLibraries;
157 }
158 
hintActivityLaunch()159 void GraphicsEnv::hintActivityLaunch() {
160     ATRACE_CALL();
161 
162     {
163         std::lock_guard<std::mutex> lock(mStatsLock);
164         if (mActivityLaunched) return;
165         mActivityLaunched = true;
166     }
167 
168     std::thread trySendGpuStatsThread([this]() {
169         // If there's already graphics driver preloaded in the process, just send
170         // the stats info to GpuStats directly through async binder.
171         std::lock_guard<std::mutex> lock(mStatsLock);
172         if (mGpuStats.glDriverToSend) {
173             mGpuStats.glDriverToSend = false;
174             sendGpuStatsLocked(GpuStatsInfo::Api::API_GL, true, mGpuStats.glDriverLoadingTime);
175         }
176         if (mGpuStats.vkDriverToSend) {
177             mGpuStats.vkDriverToSend = false;
178             sendGpuStatsLocked(GpuStatsInfo::Api::API_VK, true, mGpuStats.vkDriverLoadingTime);
179         }
180     });
181     trySendGpuStatsThread.detach();
182 }
183 
setGpuStats(const std::string & driverPackageName,const std::string & driverVersionName,uint64_t driverVersionCode,int64_t driverBuildTime,const std::string & appPackageName,const int vulkanVersion)184 void GraphicsEnv::setGpuStats(const std::string& driverPackageName,
185                               const std::string& driverVersionName, uint64_t driverVersionCode,
186                               int64_t driverBuildTime, const std::string& appPackageName,
187                               const int vulkanVersion) {
188     ATRACE_CALL();
189 
190     std::lock_guard<std::mutex> lock(mStatsLock);
191     ALOGV("setGpuStats:\n"
192           "\tdriverPackageName[%s]\n"
193           "\tdriverVersionName[%s]\n"
194           "\tdriverVersionCode[%" PRIu64 "]\n"
195           "\tdriverBuildTime[%" PRId64 "]\n"
196           "\tappPackageName[%s]\n"
197           "\tvulkanVersion[%d]\n",
198           driverPackageName.c_str(), driverVersionName.c_str(), driverVersionCode, driverBuildTime,
199           appPackageName.c_str(), vulkanVersion);
200 
201     mGpuStats.driverPackageName = driverPackageName;
202     mGpuStats.driverVersionName = driverVersionName;
203     mGpuStats.driverVersionCode = driverVersionCode;
204     mGpuStats.driverBuildTime = driverBuildTime;
205     mGpuStats.appPackageName = appPackageName;
206     mGpuStats.vulkanVersion = vulkanVersion;
207 }
208 
setDriverToLoad(GpuStatsInfo::Driver driver)209 void GraphicsEnv::setDriverToLoad(GpuStatsInfo::Driver driver) {
210     ATRACE_CALL();
211 
212     std::lock_guard<std::mutex> lock(mStatsLock);
213     switch (driver) {
214         case GpuStatsInfo::Driver::GL:
215         case GpuStatsInfo::Driver::GL_UPDATED:
216         case GpuStatsInfo::Driver::ANGLE: {
217             if (mGpuStats.glDriverToLoad == GpuStatsInfo::Driver::NONE ||
218                 mGpuStats.glDriverToLoad == GpuStatsInfo::Driver::GL) {
219                 mGpuStats.glDriverToLoad = driver;
220                 break;
221             }
222 
223             if (mGpuStats.glDriverFallback == GpuStatsInfo::Driver::NONE) {
224                 mGpuStats.glDriverFallback = driver;
225             }
226             break;
227         }
228         case GpuStatsInfo::Driver::VULKAN:
229         case GpuStatsInfo::Driver::VULKAN_UPDATED: {
230             if (mGpuStats.vkDriverToLoad == GpuStatsInfo::Driver::NONE ||
231                 mGpuStats.vkDriverToLoad == GpuStatsInfo::Driver::VULKAN) {
232                 mGpuStats.vkDriverToLoad = driver;
233                 break;
234             }
235 
236             if (mGpuStats.vkDriverFallback == GpuStatsInfo::Driver::NONE) {
237                 mGpuStats.vkDriverFallback = driver;
238             }
239             break;
240         }
241         default:
242             break;
243     }
244 }
245 
setDriverLoaded(GpuStatsInfo::Api api,bool isDriverLoaded,int64_t driverLoadingTime)246 void GraphicsEnv::setDriverLoaded(GpuStatsInfo::Api api, bool isDriverLoaded,
247                                   int64_t driverLoadingTime) {
248     ATRACE_CALL();
249 
250     std::lock_guard<std::mutex> lock(mStatsLock);
251     if (api == GpuStatsInfo::Api::API_GL) {
252         mGpuStats.glDriverToSend = true;
253         mGpuStats.glDriverLoadingTime = driverLoadingTime;
254     } else {
255         mGpuStats.vkDriverToSend = true;
256         mGpuStats.vkDriverLoadingTime = driverLoadingTime;
257     }
258 
259     sendGpuStatsLocked(api, isDriverLoaded, driverLoadingTime);
260 }
261 
getGpuService()262 static sp<IGpuService> getGpuService() {
263     static const sp<IBinder> binder = defaultServiceManager()->checkService(String16("gpu"));
264     if (!binder) {
265         ALOGE("Failed to get gpu service");
266         return nullptr;
267     }
268 
269     return interface_cast<IGpuService>(binder);
270 }
271 
readyToSendGpuStatsLocked()272 bool GraphicsEnv::readyToSendGpuStatsLocked() {
273     // Only send stats for processes having at least one activity launched and that process doesn't
274     // skip the GraphicsEnvironment setup.
275     return mActivityLaunched && !mGpuStats.appPackageName.empty();
276 }
277 
setTargetStats(const GpuStatsInfo::Stats stats,const uint64_t value)278 void GraphicsEnv::setTargetStats(const GpuStatsInfo::Stats stats, const uint64_t value) {
279     ATRACE_CALL();
280 
281     std::lock_guard<std::mutex> lock(mStatsLock);
282     if (!readyToSendGpuStatsLocked()) return;
283 
284     const sp<IGpuService> gpuService = getGpuService();
285     if (gpuService) {
286         gpuService->setTargetStats(mGpuStats.appPackageName, mGpuStats.driverVersionCode, stats,
287                                    value);
288     }
289 }
290 
sendGpuStatsLocked(GpuStatsInfo::Api api,bool isDriverLoaded,int64_t driverLoadingTime)291 void GraphicsEnv::sendGpuStatsLocked(GpuStatsInfo::Api api, bool isDriverLoaded,
292                                      int64_t driverLoadingTime) {
293     ATRACE_CALL();
294 
295     if (!readyToSendGpuStatsLocked()) return;
296 
297     ALOGV("sendGpuStats:\n"
298           "\tdriverPackageName[%s]\n"
299           "\tdriverVersionName[%s]\n"
300           "\tdriverVersionCode[%" PRIu64 "]\n"
301           "\tdriverBuildTime[%" PRId64 "]\n"
302           "\tappPackageName[%s]\n"
303           "\tvulkanVersion[%d]\n"
304           "\tapi[%d]\n"
305           "\tisDriverLoaded[%d]\n"
306           "\tdriverLoadingTime[%" PRId64 "]",
307           mGpuStats.driverPackageName.c_str(), mGpuStats.driverVersionName.c_str(),
308           mGpuStats.driverVersionCode, mGpuStats.driverBuildTime, mGpuStats.appPackageName.c_str(),
309           mGpuStats.vulkanVersion, static_cast<int32_t>(api), isDriverLoaded, driverLoadingTime);
310 
311     GpuStatsInfo::Driver driver = GpuStatsInfo::Driver::NONE;
312     bool isIntendedDriverLoaded = false;
313     if (api == GpuStatsInfo::Api::API_GL) {
314         driver = mGpuStats.glDriverToLoad;
315         isIntendedDriverLoaded =
316                 isDriverLoaded && (mGpuStats.glDriverFallback == GpuStatsInfo::Driver::NONE);
317     } else {
318         driver = mGpuStats.vkDriverToLoad;
319         isIntendedDriverLoaded =
320                 isDriverLoaded && (mGpuStats.vkDriverFallback == GpuStatsInfo::Driver::NONE);
321     }
322 
323     const sp<IGpuService> gpuService = getGpuService();
324     if (gpuService) {
325         gpuService->setGpuStats(mGpuStats.driverPackageName, mGpuStats.driverVersionName,
326                                 mGpuStats.driverVersionCode, mGpuStats.driverBuildTime,
327                                 mGpuStats.appPackageName, mGpuStats.vulkanVersion, driver,
328                                 isIntendedDriverLoaded, driverLoadingTime);
329     }
330 }
331 
setInjectLayersPrSetDumpable()332 bool GraphicsEnv::setInjectLayersPrSetDumpable() {
333     if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) {
334         return false;
335     }
336     return true;
337 }
338 
loadLibrary(std::string name)339 void* GraphicsEnv::loadLibrary(std::string name) {
340     const android_dlextinfo dlextinfo = {
341             .flags = ANDROID_DLEXT_USE_NAMESPACE,
342             .library_namespace = getAngleNamespace(),
343     };
344 
345     std::string libName = std::string("lib") + name + "_angle.so";
346 
347     void* so = android_dlopen_ext(libName.c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo);
348 
349     if (so) {
350         ALOGD("dlopen_ext from APK (%s) success at %p", libName.c_str(), so);
351         return so;
352     } else {
353         ALOGE("dlopen_ext(\"%s\") failed: %s", libName.c_str(), dlerror());
354     }
355 
356     return nullptr;
357 }
358 
shouldUseAngle(std::string appName)359 bool GraphicsEnv::shouldUseAngle(std::string appName) {
360     if (appName != mAngleAppName) {
361         // Make sure we are checking the app we were init'ed for
362         ALOGE("App name does not match: expected '%s', got '%s'", mAngleAppName.c_str(),
363               appName.c_str());
364         return false;
365     }
366 
367     return shouldUseAngle();
368 }
369 
shouldUseAngle()370 bool GraphicsEnv::shouldUseAngle() {
371     // Make sure we are init'ed
372     if (mAngleAppName.empty()) {
373         ALOGV("App name is empty. setAngleInfo() has not been called to enable ANGLE.");
374         return false;
375     }
376 
377     return (mUseAngle == YES) ? true : false;
378 }
379 
updateUseAngle()380 void GraphicsEnv::updateUseAngle() {
381     mUseAngle = NO;
382 
383     const char* ANGLE_PREFER_ANGLE = "angle";
384     const char* ANGLE_PREFER_NATIVE = "native";
385 
386     mUseAngle = NO;
387     if (mAngleDeveloperOptIn == ANGLE_PREFER_ANGLE) {
388         ALOGV("User set \"Developer Options\" to force the use of ANGLE");
389         mUseAngle = YES;
390     } else if (mAngleDeveloperOptIn == ANGLE_PREFER_NATIVE) {
391         ALOGV("User set \"Developer Options\" to force the use of Native");
392     } else {
393         ALOGV("User set invalid \"Developer Options\": '%s'", mAngleDeveloperOptIn.c_str());
394     }
395 }
396 
setAngleInfo(const std::string path,const std::string appName,const std::string developerOptIn,const std::vector<std::string> eglFeatures)397 void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName,
398                                const std::string developerOptIn,
399                                const std::vector<std::string> eglFeatures) {
400     if (mUseAngle != UNKNOWN) {
401         // We've already figured out an answer for this app, so just return.
402         ALOGV("Already evaluated the rules file for '%s': use ANGLE = %s", appName.c_str(),
403               (mUseAngle == YES) ? "true" : "false");
404         return;
405     }
406 
407     mAngleEglFeatures = std::move(eglFeatures);
408 
409     ALOGV("setting ANGLE path to '%s'", path.c_str());
410     mAnglePath = path;
411     ALOGV("setting ANGLE app name to '%s'", appName.c_str());
412     mAngleAppName = appName;
413     ALOGV("setting ANGLE application opt-in to '%s'", developerOptIn.c_str());
414     mAngleDeveloperOptIn = developerOptIn;
415 
416     // Update the current status of whether we should use ANGLE or not
417     updateUseAngle();
418 }
419 
setLayerPaths(NativeLoaderNamespace * appNamespace,const std::string layerPaths)420 void GraphicsEnv::setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths) {
421     if (mLayerPaths.empty()) {
422         mLayerPaths = layerPaths;
423         mAppNamespace = appNamespace;
424     } else {
425         ALOGV("Vulkan layer search path already set, not clobbering with '%s' for namespace %p'",
426               layerPaths.c_str(), appNamespace);
427     }
428 }
429 
getAppNamespace()430 NativeLoaderNamespace* GraphicsEnv::getAppNamespace() {
431     return mAppNamespace;
432 }
433 
getAngleAppName()434 std::string& GraphicsEnv::getAngleAppName() {
435     return mAngleAppName;
436 }
437 
getAngleEglFeatures()438 const std::vector<std::string>& GraphicsEnv::getAngleEglFeatures() {
439     return mAngleEglFeatures;
440 }
441 
getLayerPaths()442 const std::string& GraphicsEnv::getLayerPaths() {
443     return mLayerPaths;
444 }
445 
getDebugLayers()446 const std::string& GraphicsEnv::getDebugLayers() {
447     return mDebugLayers;
448 }
449 
getDebugLayersGLES()450 const std::string& GraphicsEnv::getDebugLayersGLES() {
451     return mDebugLayersGLES;
452 }
453 
setDebugLayers(const std::string layers)454 void GraphicsEnv::setDebugLayers(const std::string layers) {
455     mDebugLayers = layers;
456 }
457 
setDebugLayersGLES(const std::string layers)458 void GraphicsEnv::setDebugLayersGLES(const std::string layers) {
459     mDebugLayersGLES = layers;
460 }
461 
462 // Return true if all the required libraries from vndk and sphal namespace are
463 // linked to the updatable gfx driver namespace correctly.
linkDriverNamespaceLocked(android_namespace_t * vndkNamespace)464 bool GraphicsEnv::linkDriverNamespaceLocked(android_namespace_t* vndkNamespace) {
465     const std::string llndkLibraries = getSystemNativeLibraries(NativeLibrary::LLNDK);
466     if (llndkLibraries.empty()) {
467         return false;
468     }
469     if (!android_link_namespaces(mDriverNamespace, nullptr, llndkLibraries.c_str())) {
470         ALOGE("Failed to link default namespace[%s]", dlerror());
471         return false;
472     }
473 
474     const std::string vndkspLibraries = getSystemNativeLibraries(NativeLibrary::VNDKSP);
475     if (vndkspLibraries.empty()) {
476         return false;
477     }
478     if (!android_link_namespaces(mDriverNamespace, vndkNamespace, vndkspLibraries.c_str())) {
479         ALOGE("Failed to link vndk namespace[%s]", dlerror());
480         return false;
481     }
482 
483     if (mSphalLibraries.empty()) {
484         return true;
485     }
486 
487     // Make additional libraries in sphal to be accessible
488     auto sphalNamespace = android_get_exported_namespace("sphal");
489     if (!sphalNamespace) {
490         ALOGE("Depend on these libraries[%s] in sphal, but failed to get sphal namespace",
491               mSphalLibraries.c_str());
492         return false;
493     }
494 
495     if (!android_link_namespaces(mDriverNamespace, sphalNamespace, mSphalLibraries.c_str())) {
496         ALOGE("Failed to link sphal namespace[%s]", dlerror());
497         return false;
498     }
499 
500     return true;
501 }
502 
getDriverNamespace()503 android_namespace_t* GraphicsEnv::getDriverNamespace() {
504     std::lock_guard<std::mutex> lock(mNamespaceMutex);
505 
506     if (mDriverNamespace) {
507         return mDriverNamespace;
508     }
509 
510     if (mDriverPath.empty()) {
511         // For an application process, driver path is empty means this application is not opted in
512         // to use updatable driver. Application process doesn't have the ability to set up
513         // environment variables and hence before `getenv` call will return.
514         // For a process that is not an application process, if it's run from an environment,
515         // for example shell, where environment variables can be set, then it can opt into using
516         // udpatable driver by setting UPDATABLE_GFX_DRIVER to 1. By setting to 1 the developer
517         // driver will be used currently.
518         // TODO(b/159240322) Support the production updatable driver.
519         const char* id = getenv("UPDATABLE_GFX_DRIVER");
520         if (id == nullptr || std::strcmp(id, "1")) {
521             return nullptr;
522         }
523         const sp<IGpuService> gpuService = getGpuService();
524         if (!gpuService) {
525             return nullptr;
526         }
527         mDriverPath = gpuService->getUpdatableDriverPath();
528         if (mDriverPath.empty()) {
529             return nullptr;
530         }
531         mDriverPath.append(UPDATABLE_DRIVER_ABI);
532         ALOGI("Driver path is setup via UPDATABLE_GFX_DRIVER: %s", mDriverPath.c_str());
533     }
534 
535     auto vndkNamespace = android_get_exported_namespace("vndk");
536     if (!vndkNamespace) {
537         return nullptr;
538     }
539 
540     mDriverNamespace = android_create_namespace("gfx driver",
541                                                 mDriverPath.c_str(), // ld_library_path
542                                                 mDriverPath.c_str(), // default_library_path
543                                                 ANDROID_NAMESPACE_TYPE_ISOLATED,
544                                                 nullptr, // permitted_when_isolated_path
545                                                 nullptr);
546 
547     if (!linkDriverNamespaceLocked(vndkNamespace)) {
548         mDriverNamespace = nullptr;
549     }
550 
551     return mDriverNamespace;
552 }
553 
getDriverPath() const554 std::string GraphicsEnv::getDriverPath() const {
555     return mDriverPath;
556 }
557 
getAngleNamespace()558 android_namespace_t* GraphicsEnv::getAngleNamespace() {
559     std::lock_guard<std::mutex> lock(mNamespaceMutex);
560 
561     if (mAngleNamespace) {
562         return mAngleNamespace;
563     }
564 
565     if (mAnglePath.empty()) {
566         ALOGV("mAnglePath is empty, not creating ANGLE namespace");
567         return nullptr;
568     }
569 
570     mAngleNamespace = android_create_namespace("ANGLE",
571                                                nullptr,            // ld_library_path
572                                                mAnglePath.c_str(), // default_library_path
573                                                ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED,
574                                                nullptr, // permitted_when_isolated_path
575                                                nullptr);
576 
577     ALOGD_IF(!mAngleNamespace, "Could not create ANGLE namespace from default");
578 
579     return mAngleNamespace;
580 }
581 
582 } // namespace android
583