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     return prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) > 0;
130 }
131 
setDriverPathAndSphalLibraries(const std::string path,const std::string sphalLibraries)132 void GraphicsEnv::setDriverPathAndSphalLibraries(const std::string path,
133                                                  const std::string sphalLibraries) {
134     if (!mDriverPath.empty() || !mSphalLibraries.empty()) {
135         ALOGV("ignoring attempt to change driver path from '%s' to '%s' or change sphal libraries "
136               "from '%s' to '%s'",
137               mDriverPath.c_str(), path.c_str(), mSphalLibraries.c_str(), sphalLibraries.c_str());
138         return;
139     }
140     ALOGV("setting driver path to '%s' and sphal libraries to '%s'", path.c_str(),
141           sphalLibraries.c_str());
142     mDriverPath = path;
143     mSphalLibraries = sphalLibraries;
144 }
145 
hintActivityLaunch()146 void GraphicsEnv::hintActivityLaunch() {
147     ATRACE_CALL();
148 
149     {
150         std::lock_guard<std::mutex> lock(mStatsLock);
151         if (mActivityLaunched) return;
152         mActivityLaunched = true;
153     }
154 
155     std::thread trySendGpuStatsThread([this]() {
156         // If there's already graphics driver preloaded in the process, just send
157         // the stats info to GpuStats directly through async binder.
158         std::lock_guard<std::mutex> lock(mStatsLock);
159         if (mGpuStats.glDriverToSend) {
160             mGpuStats.glDriverToSend = false;
161             sendGpuStatsLocked(GpuStatsInfo::Api::API_GL, true, mGpuStats.glDriverLoadingTime);
162         }
163         if (mGpuStats.vkDriverToSend) {
164             mGpuStats.vkDriverToSend = false;
165             sendGpuStatsLocked(GpuStatsInfo::Api::API_VK, true, mGpuStats.vkDriverLoadingTime);
166         }
167     });
168     trySendGpuStatsThread.detach();
169 }
170 
setGpuStats(const std::string & driverPackageName,const std::string & driverVersionName,uint64_t driverVersionCode,int64_t driverBuildTime,const std::string & appPackageName,const int vulkanVersion)171 void GraphicsEnv::setGpuStats(const std::string& driverPackageName,
172                               const std::string& driverVersionName, uint64_t driverVersionCode,
173                               int64_t driverBuildTime, const std::string& appPackageName,
174                               const int vulkanVersion) {
175     ATRACE_CALL();
176 
177     std::lock_guard<std::mutex> lock(mStatsLock);
178     ALOGV("setGpuStats:\n"
179           "\tdriverPackageName[%s]\n"
180           "\tdriverVersionName[%s]\n"
181           "\tdriverVersionCode[%" PRIu64 "]\n"
182           "\tdriverBuildTime[%" PRId64 "]\n"
183           "\tappPackageName[%s]\n"
184           "\tvulkanVersion[%d]\n",
185           driverPackageName.c_str(), driverVersionName.c_str(), driverVersionCode, driverBuildTime,
186           appPackageName.c_str(), vulkanVersion);
187 
188     mGpuStats.driverPackageName = driverPackageName;
189     mGpuStats.driverVersionName = driverVersionName;
190     mGpuStats.driverVersionCode = driverVersionCode;
191     mGpuStats.driverBuildTime = driverBuildTime;
192     mGpuStats.appPackageName = appPackageName;
193     mGpuStats.vulkanVersion = vulkanVersion;
194 }
195 
setDriverToLoad(GpuStatsInfo::Driver driver)196 void GraphicsEnv::setDriverToLoad(GpuStatsInfo::Driver driver) {
197     ATRACE_CALL();
198 
199     std::lock_guard<std::mutex> lock(mStatsLock);
200     switch (driver) {
201         case GpuStatsInfo::Driver::GL:
202         case GpuStatsInfo::Driver::GL_UPDATED:
203         case GpuStatsInfo::Driver::ANGLE: {
204             if (mGpuStats.glDriverToLoad == GpuStatsInfo::Driver::NONE ||
205                 mGpuStats.glDriverToLoad == GpuStatsInfo::Driver::GL) {
206                 mGpuStats.glDriverToLoad = driver;
207                 break;
208             }
209 
210             if (mGpuStats.glDriverFallback == GpuStatsInfo::Driver::NONE) {
211                 mGpuStats.glDriverFallback = driver;
212             }
213             break;
214         }
215         case GpuStatsInfo::Driver::VULKAN:
216         case GpuStatsInfo::Driver::VULKAN_UPDATED: {
217             if (mGpuStats.vkDriverToLoad == GpuStatsInfo::Driver::NONE ||
218                 mGpuStats.vkDriverToLoad == GpuStatsInfo::Driver::VULKAN) {
219                 mGpuStats.vkDriverToLoad = driver;
220                 break;
221             }
222 
223             if (mGpuStats.vkDriverFallback == GpuStatsInfo::Driver::NONE) {
224                 mGpuStats.vkDriverFallback = driver;
225             }
226             break;
227         }
228         default:
229             break;
230     }
231 }
232 
setDriverLoaded(GpuStatsInfo::Api api,bool isDriverLoaded,int64_t driverLoadingTime)233 void GraphicsEnv::setDriverLoaded(GpuStatsInfo::Api api, bool isDriverLoaded,
234                                   int64_t driverLoadingTime) {
235     ATRACE_CALL();
236 
237     std::lock_guard<std::mutex> lock(mStatsLock);
238     if (api == GpuStatsInfo::Api::API_GL) {
239         mGpuStats.glDriverToSend = true;
240         mGpuStats.glDriverLoadingTime = driverLoadingTime;
241     } else {
242         mGpuStats.vkDriverToSend = true;
243         mGpuStats.vkDriverLoadingTime = driverLoadingTime;
244     }
245 
246     sendGpuStatsLocked(api, isDriverLoaded, driverLoadingTime);
247 }
248 
getGpuService()249 static sp<IGpuService> getGpuService() {
250     static const sp<IBinder> binder = defaultServiceManager()->checkService(String16("gpu"));
251     if (!binder) {
252         ALOGE("Failed to get gpu service");
253         return nullptr;
254     }
255 
256     return interface_cast<IGpuService>(binder);
257 }
258 
readyToSendGpuStatsLocked()259 bool GraphicsEnv::readyToSendGpuStatsLocked() {
260     // Only send stats for processes having at least one activity launched and that process doesn't
261     // skip the GraphicsEnvironment setup.
262     return mActivityLaunched && !mGpuStats.appPackageName.empty();
263 }
264 
setTargetStats(const GpuStatsInfo::Stats stats,const uint64_t value)265 void GraphicsEnv::setTargetStats(const GpuStatsInfo::Stats stats, const uint64_t value) {
266     ATRACE_CALL();
267 
268     std::lock_guard<std::mutex> lock(mStatsLock);
269     if (!readyToSendGpuStatsLocked()) return;
270 
271     const sp<IGpuService> gpuService = getGpuService();
272     if (gpuService) {
273         gpuService->setTargetStats(mGpuStats.appPackageName, mGpuStats.driverVersionCode, stats,
274                                    value);
275     }
276 }
277 
sendGpuStatsLocked(GpuStatsInfo::Api api,bool isDriverLoaded,int64_t driverLoadingTime)278 void GraphicsEnv::sendGpuStatsLocked(GpuStatsInfo::Api api, bool isDriverLoaded,
279                                      int64_t driverLoadingTime) {
280     ATRACE_CALL();
281 
282     if (!readyToSendGpuStatsLocked()) return;
283 
284     ALOGV("sendGpuStats:\n"
285           "\tdriverPackageName[%s]\n"
286           "\tdriverVersionName[%s]\n"
287           "\tdriverVersionCode[%" PRIu64 "]\n"
288           "\tdriverBuildTime[%" PRId64 "]\n"
289           "\tappPackageName[%s]\n"
290           "\tvulkanVersion[%d]\n"
291           "\tapi[%d]\n"
292           "\tisDriverLoaded[%d]\n"
293           "\tdriverLoadingTime[%" PRId64 "]",
294           mGpuStats.driverPackageName.c_str(), mGpuStats.driverVersionName.c_str(),
295           mGpuStats.driverVersionCode, mGpuStats.driverBuildTime, mGpuStats.appPackageName.c_str(),
296           mGpuStats.vulkanVersion, static_cast<int32_t>(api), isDriverLoaded, driverLoadingTime);
297 
298     GpuStatsInfo::Driver driver = GpuStatsInfo::Driver::NONE;
299     bool isIntendedDriverLoaded = false;
300     if (api == GpuStatsInfo::Api::API_GL) {
301         driver = mGpuStats.glDriverToLoad;
302         isIntendedDriverLoaded =
303                 isDriverLoaded && (mGpuStats.glDriverFallback == GpuStatsInfo::Driver::NONE);
304     } else {
305         driver = mGpuStats.vkDriverToLoad;
306         isIntendedDriverLoaded =
307                 isDriverLoaded && (mGpuStats.vkDriverFallback == GpuStatsInfo::Driver::NONE);
308     }
309 
310     const sp<IGpuService> gpuService = getGpuService();
311     if (gpuService) {
312         gpuService->setGpuStats(mGpuStats.driverPackageName, mGpuStats.driverVersionName,
313                                 mGpuStats.driverVersionCode, mGpuStats.driverBuildTime,
314                                 mGpuStats.appPackageName, mGpuStats.vulkanVersion, driver,
315                                 isIntendedDriverLoaded, driverLoadingTime);
316     }
317 }
318 
setInjectLayersPrSetDumpable()319 bool GraphicsEnv::setInjectLayersPrSetDumpable() {
320     if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) {
321         return false;
322     }
323     return true;
324 }
325 
loadLibrary(std::string name)326 void* GraphicsEnv::loadLibrary(std::string name) {
327     const android_dlextinfo dlextinfo = {
328             .flags = ANDROID_DLEXT_USE_NAMESPACE,
329             .library_namespace = getAngleNamespace(),
330     };
331 
332     std::string libName = std::string("lib") + name + "_angle.so";
333 
334     void* so = android_dlopen_ext(libName.c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo);
335 
336     if (so) {
337         ALOGD("dlopen_ext from APK (%s) success at %p", libName.c_str(), so);
338         return so;
339     } else {
340         ALOGE("dlopen_ext(\"%s\") failed: %s", libName.c_str(), dlerror());
341     }
342 
343     return nullptr;
344 }
345 
shouldUseAngle(std::string appName)346 bool GraphicsEnv::shouldUseAngle(std::string appName) {
347     if (appName != mAngleAppName) {
348         // Make sure we are checking the app we were init'ed for
349         ALOGE("App name does not match: expected '%s', got '%s'", mAngleAppName.c_str(),
350               appName.c_str());
351         return false;
352     }
353 
354     return shouldUseAngle();
355 }
356 
shouldUseAngle()357 bool GraphicsEnv::shouldUseAngle() {
358     // Make sure we are init'ed
359     if (mAngleAppName.empty()) {
360         ALOGV("App name is empty. setAngleInfo() has not been called to enable ANGLE.");
361         return false;
362     }
363 
364     return (mUseAngle == YES) ? true : false;
365 }
366 
updateUseAngle()367 void GraphicsEnv::updateUseAngle() {
368     mUseAngle = NO;
369 
370     const char* ANGLE_PREFER_ANGLE = "angle";
371     const char* ANGLE_PREFER_NATIVE = "native";
372 
373     mUseAngle = NO;
374     if (mAngleDeveloperOptIn == ANGLE_PREFER_ANGLE) {
375         ALOGV("User set \"Developer Options\" to force the use of ANGLE");
376         mUseAngle = YES;
377     } else if (mAngleDeveloperOptIn == ANGLE_PREFER_NATIVE) {
378         ALOGV("User set \"Developer Options\" to force the use of Native");
379     } else {
380         ALOGV("User set invalid \"Developer Options\": '%s'", mAngleDeveloperOptIn.c_str());
381     }
382 }
383 
setAngleInfo(const std::string path,const std::string appName,const std::string developerOptIn,const std::vector<std::string> eglFeatures)384 void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName,
385                                const std::string developerOptIn,
386                                const std::vector<std::string> eglFeatures) {
387     if (mUseAngle != UNKNOWN) {
388         // We've already figured out an answer for this app, so just return.
389         ALOGV("Already evaluated the rules file for '%s': use ANGLE = %s", appName.c_str(),
390               (mUseAngle == YES) ? "true" : "false");
391         return;
392     }
393 
394     mAngleEglFeatures = std::move(eglFeatures);
395 
396     ALOGV("setting ANGLE path to '%s'", path.c_str());
397     mAnglePath = path;
398     ALOGV("setting ANGLE app name to '%s'", appName.c_str());
399     mAngleAppName = appName;
400     ALOGV("setting ANGLE application opt-in to '%s'", developerOptIn.c_str());
401     mAngleDeveloperOptIn = developerOptIn;
402 
403     // Update the current status of whether we should use ANGLE or not
404     updateUseAngle();
405 }
406 
setLayerPaths(NativeLoaderNamespace * appNamespace,const std::string layerPaths)407 void GraphicsEnv::setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths) {
408     if (mLayerPaths.empty()) {
409         mLayerPaths = layerPaths;
410         mAppNamespace = appNamespace;
411     } else {
412         ALOGV("Vulkan layer search path already set, not clobbering with '%s' for namespace %p'",
413               layerPaths.c_str(), appNamespace);
414     }
415 }
416 
getAppNamespace()417 NativeLoaderNamespace* GraphicsEnv::getAppNamespace() {
418     return mAppNamespace;
419 }
420 
getAngleAppName()421 std::string& GraphicsEnv::getAngleAppName() {
422     return mAngleAppName;
423 }
424 
getAngleEglFeatures()425 const std::vector<std::string>& GraphicsEnv::getAngleEglFeatures() {
426     return mAngleEglFeatures;
427 }
428 
getLayerPaths()429 const std::string& GraphicsEnv::getLayerPaths() {
430     return mLayerPaths;
431 }
432 
getDebugLayers()433 const std::string& GraphicsEnv::getDebugLayers() {
434     return mDebugLayers;
435 }
436 
getDebugLayersGLES()437 const std::string& GraphicsEnv::getDebugLayersGLES() {
438     return mDebugLayersGLES;
439 }
440 
setDebugLayers(const std::string layers)441 void GraphicsEnv::setDebugLayers(const std::string layers) {
442     mDebugLayers = layers;
443 }
444 
setDebugLayersGLES(const std::string layers)445 void GraphicsEnv::setDebugLayersGLES(const std::string layers) {
446     mDebugLayersGLES = layers;
447 }
448 
449 // Return true if all the required libraries from vndk and sphal namespace are
450 // linked to the updatable gfx driver namespace correctly.
linkDriverNamespaceLocked(android_namespace_t * vndkNamespace)451 bool GraphicsEnv::linkDriverNamespaceLocked(android_namespace_t* vndkNamespace) {
452     const std::string llndkLibraries = getSystemNativeLibraries(NativeLibrary::LLNDK);
453     if (llndkLibraries.empty()) {
454         return false;
455     }
456     if (!android_link_namespaces(mDriverNamespace, nullptr, llndkLibraries.c_str())) {
457         ALOGE("Failed to link default namespace[%s]", dlerror());
458         return false;
459     }
460 
461     const std::string vndkspLibraries = getSystemNativeLibraries(NativeLibrary::VNDKSP);
462     if (vndkspLibraries.empty()) {
463         return false;
464     }
465     if (!android_link_namespaces(mDriverNamespace, vndkNamespace, vndkspLibraries.c_str())) {
466         ALOGE("Failed to link vndk namespace[%s]", dlerror());
467         return false;
468     }
469 
470     if (mSphalLibraries.empty()) {
471         return true;
472     }
473 
474     // Make additional libraries in sphal to be accessible
475     auto sphalNamespace = android_get_exported_namespace("sphal");
476     if (!sphalNamespace) {
477         ALOGE("Depend on these libraries[%s] in sphal, but failed to get sphal namespace",
478               mSphalLibraries.c_str());
479         return false;
480     }
481 
482     if (!android_link_namespaces(mDriverNamespace, sphalNamespace, mSphalLibraries.c_str())) {
483         ALOGE("Failed to link sphal namespace[%s]", dlerror());
484         return false;
485     }
486 
487     return true;
488 }
489 
getDriverNamespace()490 android_namespace_t* GraphicsEnv::getDriverNamespace() {
491     std::lock_guard<std::mutex> lock(mNamespaceMutex);
492 
493     if (mDriverNamespace) {
494         return mDriverNamespace;
495     }
496 
497     if (mDriverPath.empty()) {
498         // For an application process, driver path is empty means this application is not opted in
499         // to use updatable driver. Application process doesn't have the ability to set up
500         // environment variables and hence before `getenv` call will return.
501         // For a process that is not an application process, if it's run from an environment,
502         // for example shell, where environment variables can be set, then it can opt into using
503         // udpatable driver by setting UPDATABLE_GFX_DRIVER to 1. By setting to 1 the developer
504         // driver will be used currently.
505         // TODO(b/159240322) Support the production updatable driver.
506         const char* id = getenv("UPDATABLE_GFX_DRIVER");
507         if (id == nullptr || std::strcmp(id, "1")) {
508             return nullptr;
509         }
510         const sp<IGpuService> gpuService = getGpuService();
511         if (!gpuService) {
512             return nullptr;
513         }
514         mDriverPath = gpuService->getUpdatableDriverPath();
515         if (mDriverPath.empty()) {
516             return nullptr;
517         }
518         mDriverPath.append(UPDATABLE_DRIVER_ABI);
519         ALOGI("Driver path is setup via UPDATABLE_GFX_DRIVER: %s", mDriverPath.c_str());
520     }
521 
522     auto vndkNamespace = android_get_exported_namespace("vndk");
523     if (!vndkNamespace) {
524         return nullptr;
525     }
526 
527     mDriverNamespace = android_create_namespace("gfx driver",
528                                                 mDriverPath.c_str(), // ld_library_path
529                                                 mDriverPath.c_str(), // default_library_path
530                                                 ANDROID_NAMESPACE_TYPE_ISOLATED,
531                                                 nullptr, // permitted_when_isolated_path
532                                                 nullptr);
533 
534     if (!linkDriverNamespaceLocked(vndkNamespace)) {
535         mDriverNamespace = nullptr;
536     }
537 
538     return mDriverNamespace;
539 }
540 
getDriverPath() const541 std::string GraphicsEnv::getDriverPath() const {
542     return mDriverPath;
543 }
544 
getAngleNamespace()545 android_namespace_t* GraphicsEnv::getAngleNamespace() {
546     std::lock_guard<std::mutex> lock(mNamespaceMutex);
547 
548     if (mAngleNamespace) {
549         return mAngleNamespace;
550     }
551 
552     if (mAnglePath.empty()) {
553         ALOGV("mAnglePath is empty, not creating ANGLE namespace");
554         return nullptr;
555     }
556 
557     mAngleNamespace = android_create_namespace("ANGLE",
558                                                nullptr,            // ld_library_path
559                                                mAnglePath.c_str(), // default_library_path
560                                                ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED,
561                                                nullptr, // permitted_when_isolated_path
562                                                nullptr);
563 
564     ALOGD_IF(!mAngleNamespace, "Could not create ANGLE namespace from default");
565 
566     return mAngleNamespace;
567 }
568 
569 } // namespace android
570