diff options
Diffstat (limited to 'libs/graphicsenv/GraphicsEnv.cpp')
-rw-r--r-- | libs/graphicsenv/GraphicsEnv.cpp | 527 |
1 files changed, 472 insertions, 55 deletions
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 0d031edfc6..24b6c2d6de 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -14,20 +14,30 @@ * limitations under the License. */ +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + //#define LOG_NDEBUG 1 #define LOG_TAG "GraphicsEnv" + #include <graphicsenv/GraphicsEnv.h> #include <dlfcn.h> +#include <unistd.h> #include <android-base/file.h> #include <android-base/properties.h> #include <android-base/strings.h> #include <android/dlext.h> +#include <binder/IServiceManager.h> +#include <cutils/properties.h> +#include <graphicsenv/IGpuService.h> #include <log/log.h> #include <sys/prctl.h> +#include <utils/Trace.h> -#include <mutex> +#include <memory> +#include <string> +#include <thread> // TODO(b/37049319) Get this from a header once one exists extern "C" { @@ -45,6 +55,20 @@ enum { }; } +// TODO(ianelliott@): Get the following from an ANGLE header: +#define CURRENT_ANGLE_API_VERSION 2 // Current API verion we are targetting +// Version-2 API: +typedef bool (*fpANGLEGetFeatureSupportUtilAPIVersion)(unsigned int* versionToUse); +typedef bool (*fpANGLEAndroidParseRulesString)(const char* rulesString, void** rulesHandle, + int* rulesVersion); +typedef bool (*fpANGLEGetSystemInfo)(void** handle); +typedef bool (*fpANGLEAddDeviceInfoToSystemInfo)(const char* deviceMfr, const char* deviceModel, + void* handle); +typedef bool (*fpANGLEShouldBeUsedForApplication)(void* rulesHandle, int rulesVersion, + void* systemInfoHandle, const char* appName); +typedef bool (*fpANGLEFreeRulesHandle)(void* handle); +typedef bool (*fpANGLEFreeSystemInfoHandle)(void* handle); + namespace android { enum NativeLibrary { @@ -115,6 +139,14 @@ static const std::string getSystemNativeLibraries(NativeLibrary type) { return env; } +int GraphicsEnv::getCanLoadSystemLibraries() { + if (property_get_bool("ro.debuggable", false) && prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) { + // Return an integer value since this crosses library boundaries + return 1; + } + return 0; +} + void GraphicsEnv::setDriverPathAndSphalLibraries(const std::string path, const std::string sphalLibraries) { if (!mDriverPath.empty() || !mSphalLibraries.empty()) { @@ -129,6 +161,345 @@ void GraphicsEnv::setDriverPathAndSphalLibraries(const std::string path, mSphalLibraries = sphalLibraries; } +void GraphicsEnv::hintActivityLaunch() { + ATRACE_CALL(); + + std::thread trySendGpuStatsThread([this]() { + // If there's already graphics driver preloaded in the process, just send + // the stats info to GpuStats directly through async binder. + std::lock_guard<std::mutex> lock(mStatsLock); + if (mGpuStats.glDriverToSend) { + mGpuStats.glDriverToSend = false; + sendGpuStatsLocked(GraphicsEnv::Api::API_GL, true, mGpuStats.glDriverLoadingTime); + } + if (mGpuStats.vkDriverToSend) { + mGpuStats.vkDriverToSend = false; + sendGpuStatsLocked(GraphicsEnv::Api::API_VK, true, mGpuStats.vkDriverLoadingTime); + } + }); + trySendGpuStatsThread.detach(); +} + +void GraphicsEnv::setGpuStats(const std::string& driverPackageName, + const std::string& driverVersionName, uint64_t driverVersionCode, + int64_t driverBuildTime, const std::string& appPackageName, + const int vulkanVersion) { + ATRACE_CALL(); + + std::lock_guard<std::mutex> lock(mStatsLock); + ALOGV("setGpuStats:\n" + "\tdriverPackageName[%s]\n" + "\tdriverVersionName[%s]\n" + "\tdriverVersionCode[%" PRIu64 "]\n" + "\tdriverBuildTime[%" PRId64 "]\n" + "\tappPackageName[%s]\n" + "\tvulkanVersion[%d]\n", + driverPackageName.c_str(), driverVersionName.c_str(), driverVersionCode, driverBuildTime, + appPackageName.c_str(), vulkanVersion); + + mGpuStats.driverPackageName = driverPackageName; + mGpuStats.driverVersionName = driverVersionName; + mGpuStats.driverVersionCode = driverVersionCode; + mGpuStats.driverBuildTime = driverBuildTime; + mGpuStats.appPackageName = appPackageName; + mGpuStats.vulkanVersion = vulkanVersion; +} + +void GraphicsEnv::setDriverToLoad(GraphicsEnv::Driver driver) { + ATRACE_CALL(); + + std::lock_guard<std::mutex> lock(mStatsLock); + switch (driver) { + case GraphicsEnv::Driver::GL: + case GraphicsEnv::Driver::GL_UPDATED: + case GraphicsEnv::Driver::ANGLE: { + if (mGpuStats.glDriverToLoad == GraphicsEnv::Driver::NONE) { + mGpuStats.glDriverToLoad = driver; + break; + } + + if (mGpuStats.glDriverFallback == GraphicsEnv::Driver::NONE) { + mGpuStats.glDriverFallback = driver; + } + break; + } + case Driver::VULKAN: + case Driver::VULKAN_UPDATED: { + if (mGpuStats.vkDriverToLoad == GraphicsEnv::Driver::NONE) { + mGpuStats.vkDriverToLoad = driver; + break; + } + + if (mGpuStats.vkDriverFallback == GraphicsEnv::Driver::NONE) { + mGpuStats.vkDriverFallback = driver; + } + break; + } + default: + break; + } +} + +void GraphicsEnv::setDriverLoaded(GraphicsEnv::Api api, bool isDriverLoaded, + int64_t driverLoadingTime) { + ATRACE_CALL(); + + std::lock_guard<std::mutex> lock(mStatsLock); + const bool doNotSend = mGpuStats.appPackageName.empty(); + if (api == GraphicsEnv::Api::API_GL) { + if (doNotSend) mGpuStats.glDriverToSend = true; + mGpuStats.glDriverLoadingTime = driverLoadingTime; + } else { + if (doNotSend) mGpuStats.vkDriverToSend = true; + mGpuStats.vkDriverLoadingTime = driverLoadingTime; + } + + sendGpuStatsLocked(api, isDriverLoaded, driverLoadingTime); +} + +static sp<IGpuService> getGpuService() { + const sp<IBinder> binder = defaultServiceManager()->checkService(String16("gpu")); + if (!binder) { + ALOGE("Failed to get gpu service"); + return nullptr; + } + + return interface_cast<IGpuService>(binder); +} + +void GraphicsEnv::setCpuVulkanInUse() { + ATRACE_CALL(); + + // Use the same stats lock to protect getGpuService() as well. + std::lock_guard<std::mutex> lock(mStatsLock); + const sp<IGpuService> gpuService = getGpuService(); + if (gpuService) { + gpuService->setCpuVulkanInUse(mGpuStats.appPackageName, mGpuStats.driverVersionCode); + } +} + +void GraphicsEnv::sendGpuStatsLocked(GraphicsEnv::Api api, bool isDriverLoaded, + int64_t driverLoadingTime) { + ATRACE_CALL(); + + // Do not sendGpuStats for those skipping the GraphicsEnvironment setup + if (mGpuStats.appPackageName.empty()) return; + + ALOGV("sendGpuStats:\n" + "\tdriverPackageName[%s]\n" + "\tdriverVersionName[%s]\n" + "\tdriverVersionCode[%" PRIu64 "]\n" + "\tdriverBuildTime[%" PRId64 "]\n" + "\tappPackageName[%s]\n" + "\tvulkanVersion[%d]\n" + "\tapi[%d]\n" + "\tisDriverLoaded[%d]\n" + "\tdriverLoadingTime[%" PRId64 "]", + mGpuStats.driverPackageName.c_str(), mGpuStats.driverVersionName.c_str(), + mGpuStats.driverVersionCode, mGpuStats.driverBuildTime, mGpuStats.appPackageName.c_str(), + mGpuStats.vulkanVersion, static_cast<int32_t>(api), isDriverLoaded, driverLoadingTime); + + GraphicsEnv::Driver driver = GraphicsEnv::Driver::NONE; + bool isIntendedDriverLoaded = false; + if (api == GraphicsEnv::Api::API_GL) { + driver = mGpuStats.glDriverToLoad; + isIntendedDriverLoaded = + isDriverLoaded && (mGpuStats.glDriverFallback == GraphicsEnv::Driver::NONE); + } else { + driver = mGpuStats.vkDriverToLoad; + isIntendedDriverLoaded = + isDriverLoaded && (mGpuStats.vkDriverFallback == GraphicsEnv::Driver::NONE); + } + + const sp<IGpuService> gpuService = getGpuService(); + if (gpuService) { + gpuService->setGpuStats(mGpuStats.driverPackageName, mGpuStats.driverVersionName, + mGpuStats.driverVersionCode, mGpuStats.driverBuildTime, + mGpuStats.appPackageName, mGpuStats.vulkanVersion, driver, + isIntendedDriverLoaded, driverLoadingTime); + } +} + +void* GraphicsEnv::loadLibrary(std::string name) { + const android_dlextinfo dlextinfo = { + .flags = ANDROID_DLEXT_USE_NAMESPACE, + .library_namespace = getAngleNamespace(), + }; + + std::string libName = std::string("lib") + name + "_angle.so"; + + void* so = android_dlopen_ext(libName.c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo); + + if (so) { + ALOGD("dlopen_ext from APK (%s) success at %p", libName.c_str(), so); + return so; + } else { + ALOGE("dlopen_ext(\"%s\") failed: %s", libName.c_str(), dlerror()); + } + + return nullptr; +} + +bool GraphicsEnv::checkAngleRules(void* so) { + char manufacturer[PROPERTY_VALUE_MAX]; + char model[PROPERTY_VALUE_MAX]; + property_get("ro.product.manufacturer", manufacturer, "UNSET"); + property_get("ro.product.model", model, "UNSET"); + + auto ANGLEGetFeatureSupportUtilAPIVersion = + (fpANGLEGetFeatureSupportUtilAPIVersion)dlsym(so, + "ANGLEGetFeatureSupportUtilAPIVersion"); + + if (!ANGLEGetFeatureSupportUtilAPIVersion) { + ALOGW("Cannot find ANGLEGetFeatureSupportUtilAPIVersion function"); + return false; + } + + // Negotiate the interface version by requesting most recent known to the platform + unsigned int versionToUse = CURRENT_ANGLE_API_VERSION; + if (!(ANGLEGetFeatureSupportUtilAPIVersion)(&versionToUse)) { + ALOGW("Cannot use ANGLE feature-support library, it is older than supported by EGL, " + "requested version %u", + versionToUse); + return false; + } + + // Add and remove versions below as needed + bool useAngle = false; + switch (versionToUse) { + case 2: { + ALOGV("Using version %d of ANGLE feature-support library", versionToUse); + void* rulesHandle = nullptr; + int rulesVersion = 0; + void* systemInfoHandle = nullptr; + + // Get the symbols for the feature-support-utility library: +#define GET_SYMBOL(symbol) \ + fp##symbol symbol = (fp##symbol)dlsym(so, #symbol); \ + if (!symbol) { \ + ALOGW("Cannot find " #symbol " in ANGLE feature-support library"); \ + break; \ + } + GET_SYMBOL(ANGLEAndroidParseRulesString); + GET_SYMBOL(ANGLEGetSystemInfo); + GET_SYMBOL(ANGLEAddDeviceInfoToSystemInfo); + GET_SYMBOL(ANGLEShouldBeUsedForApplication); + GET_SYMBOL(ANGLEFreeRulesHandle); + GET_SYMBOL(ANGLEFreeSystemInfoHandle); + + // Parse the rules, obtain the SystemInfo, and evaluate the + // application against the rules: + if (!(ANGLEAndroidParseRulesString)(mRulesBuffer.data(), &rulesHandle, &rulesVersion)) { + ALOGW("ANGLE feature-support library cannot parse rules file"); + break; + } + if (!(ANGLEGetSystemInfo)(&systemInfoHandle)) { + ALOGW("ANGLE feature-support library cannot obtain SystemInfo"); + break; + } + if (!(ANGLEAddDeviceInfoToSystemInfo)(manufacturer, model, systemInfoHandle)) { + ALOGW("ANGLE feature-support library cannot add device info to SystemInfo"); + break; + } + useAngle = (ANGLEShouldBeUsedForApplication)(rulesHandle, rulesVersion, + systemInfoHandle, mAngleAppName.c_str()); + (ANGLEFreeRulesHandle)(rulesHandle); + (ANGLEFreeSystemInfoHandle)(systemInfoHandle); + } break; + + default: + ALOGW("Version %u of ANGLE feature-support library is NOT supported.", versionToUse); + } + + ALOGV("Close temporarily-loaded ANGLE opt-in/out logic"); + return useAngle; +} + +bool GraphicsEnv::shouldUseAngle(std::string appName) { + if (appName != mAngleAppName) { + // Make sure we are checking the app we were init'ed for + ALOGE("App name does not match: expected '%s', got '%s'", mAngleAppName.c_str(), + appName.c_str()); + return false; + } + + return shouldUseAngle(); +} + +bool GraphicsEnv::shouldUseAngle() { + // Make sure we are init'ed + if (mAngleAppName.empty()) { + ALOGV("App name is empty. setAngleInfo() has not been called to enable ANGLE."); + return false; + } + + return (mUseAngle == YES) ? true : false; +} + +void GraphicsEnv::updateUseAngle() { + mUseAngle = NO; + + const char* ANGLE_PREFER_ANGLE = "angle"; + const char* ANGLE_PREFER_NATIVE = "native"; + + if (mAngleDeveloperOptIn == ANGLE_PREFER_ANGLE) { + ALOGV("User set \"Developer Options\" to force the use of ANGLE"); + mUseAngle = YES; + } else if (mAngleDeveloperOptIn == ANGLE_PREFER_NATIVE) { + ALOGV("User set \"Developer Options\" to force the use of Native"); + mUseAngle = NO; + } else { + // The "Developer Options" value wasn't set to force the use of ANGLE. Need to temporarily + // load ANGLE and call the updatable opt-in/out logic: + void* featureSo = loadLibrary("feature_support"); + if (featureSo) { + ALOGV("loaded ANGLE's opt-in/out logic from namespace"); + mUseAngle = checkAngleRules(featureSo) ? YES : NO; + dlclose(featureSo); + featureSo = nullptr; + } else { + ALOGV("Could not load the ANGLE opt-in/out logic, cannot use ANGLE."); + } + } +} + +void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName, + const std::string developerOptIn, const int rulesFd, + const long rulesOffset, const long rulesLength) { + if (mUseAngle != UNKNOWN) { + // We've already figured out an answer for this app, so just return. + ALOGV("Already evaluated the rules file for '%s': use ANGLE = %s", appName.c_str(), + (mUseAngle == YES) ? "true" : "false"); + return; + } + + ALOGV("setting ANGLE path to '%s'", path.c_str()); + mAnglePath = path; + ALOGV("setting ANGLE app name to '%s'", appName.c_str()); + mAngleAppName = appName; + ALOGV("setting ANGLE application opt-in to '%s'", developerOptIn.c_str()); + mAngleDeveloperOptIn = developerOptIn; + + lseek(rulesFd, rulesOffset, SEEK_SET); + mRulesBuffer = std::vector<char>(rulesLength + 1); + ssize_t numBytesRead = read(rulesFd, mRulesBuffer.data(), rulesLength); + if (numBytesRead < 0) { + ALOGE("Cannot read rules file: numBytesRead = %zd", numBytesRead); + numBytesRead = 0; + } else if (numBytesRead == 0) { + ALOGW("Empty rules file"); + } + if (numBytesRead != rulesLength) { + ALOGW("Did not read all of the necessary bytes from the rules file." + "expected: %ld, got: %zd", + rulesLength, numBytesRead); + } + mRulesBuffer[numBytesRead] = '\0'; + + // Update the current status of whether we should use ANGLE or not + updateUseAngle(); +} + void GraphicsEnv::setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths) { if (mLayerPaths.empty()) { mLayerPaths = layerPaths; @@ -143,78 +514,124 @@ NativeLoaderNamespace* GraphicsEnv::getAppNamespace() { return mAppNamespace; } -const std::string GraphicsEnv::getLayerPaths(){ +std::string& GraphicsEnv::getAngleAppName() { + return mAngleAppName; +} + +const std::string& GraphicsEnv::getLayerPaths() { return mLayerPaths; } -const std::string GraphicsEnv::getDebugLayers() { +const std::string& GraphicsEnv::getDebugLayers() { return mDebugLayers; } +const std::string& GraphicsEnv::getDebugLayersGLES() { + return mDebugLayersGLES; +} + void GraphicsEnv::setDebugLayers(const std::string layers) { mDebugLayers = layers; } +void GraphicsEnv::setDebugLayersGLES(const std::string layers) { + mDebugLayersGLES = layers; +} + +// Return true if all the required libraries from vndk and sphal namespace are +// linked to the Game Driver namespace correctly. +bool GraphicsEnv::linkDriverNamespaceLocked(android_namespace_t* vndkNamespace) { + const std::string llndkLibraries = getSystemNativeLibraries(NativeLibrary::LLNDK); + if (llndkLibraries.empty()) { + return false; + } + if (!android_link_namespaces(mDriverNamespace, nullptr, llndkLibraries.c_str())) { + ALOGE("Failed to link default namespace[%s]", dlerror()); + return false; + } + + const std::string vndkspLibraries = getSystemNativeLibraries(NativeLibrary::VNDKSP); + if (vndkspLibraries.empty()) { + return false; + } + if (!android_link_namespaces(mDriverNamespace, vndkNamespace, vndkspLibraries.c_str())) { + ALOGE("Failed to link vndk namespace[%s]", dlerror()); + return false; + } + + if (mSphalLibraries.empty()) { + return true; + } + + // Make additional libraries in sphal to be accessible + auto sphalNamespace = android_get_exported_namespace("sphal"); + if (!sphalNamespace) { + ALOGE("Depend on these libraries[%s] in sphal, but failed to get sphal namespace", + mSphalLibraries.c_str()); + return false; + } + + if (!android_link_namespaces(mDriverNamespace, sphalNamespace, mSphalLibraries.c_str())) { + ALOGE("Failed to link sphal namespace[%s]", dlerror()); + return false; + } + + return true; +} + android_namespace_t* GraphicsEnv::getDriverNamespace() { - static std::once_flag once; - std::call_once(once, [this]() { - if (mDriverPath.empty()) return; - - auto vndkNamespace = android_get_exported_namespace("vndk"); - if (!vndkNamespace) return; - - mDriverNamespace = android_create_namespace("gfx driver", - mDriverPath.c_str(), // ld_library_path - mDriverPath.c_str(), // default_library_path - ANDROID_NAMESPACE_TYPE_ISOLATED, - nullptr, // permitted_when_isolated_path - nullptr); - - const std::string llndkLibraries = getSystemNativeLibraries(NativeLibrary::LLNDK); - if (llndkLibraries.empty()) { - mDriverNamespace = nullptr; - return; - } - if (!android_link_namespaces(mDriverNamespace, nullptr, llndkLibraries.c_str())) { - ALOGE("Failed to link default namespace[%s]", dlerror()); - mDriverNamespace = nullptr; - return; - } + std::lock_guard<std::mutex> lock(mNamespaceMutex); - const std::string vndkspLibraries = getSystemNativeLibraries(NativeLibrary::VNDKSP); - if (vndkspLibraries.empty()) { - mDriverNamespace = nullptr; - return; - } - if (!android_link_namespaces(mDriverNamespace, vndkNamespace, vndkspLibraries.c_str())) { - ALOGE("Failed to link vndk namespace[%s]", dlerror()); - mDriverNamespace = nullptr; - return; - } + if (mDriverNamespace) { + return mDriverNamespace; + } - if (mSphalLibraries.empty()) return; + if (mDriverPath.empty()) { + return nullptr; + } - // Make additional libraries in sphal to be accessible - auto sphalNamespace = android_get_exported_namespace("sphal"); - if (!sphalNamespace) { - ALOGE("Depend on these libraries[%s] in sphal, but failed to get sphal namespace", - mSphalLibraries.c_str()); - mDriverNamespace = nullptr; - return; - } + auto vndkNamespace = android_get_exported_namespace("vndk"); + if (!vndkNamespace) { + return nullptr; + } - if (!android_link_namespaces(mDriverNamespace, sphalNamespace, mSphalLibraries.c_str())) { - ALOGE("Failed to link sphal namespace[%s]", dlerror()); - mDriverNamespace = nullptr; - return; - } - }); + mDriverNamespace = android_create_namespace("gfx driver", + mDriverPath.c_str(), // ld_library_path + mDriverPath.c_str(), // default_library_path + ANDROID_NAMESPACE_TYPE_ISOLATED, + nullptr, // permitted_when_isolated_path + nullptr); + + if (!linkDriverNamespaceLocked(vndkNamespace)) { + mDriverNamespace = nullptr; + } return mDriverNamespace; } -} // namespace android +android_namespace_t* GraphicsEnv::getAngleNamespace() { + std::lock_guard<std::mutex> lock(mNamespaceMutex); -extern "C" android_namespace_t* android_getDriverNamespace() { - return android::GraphicsEnv::getInstance().getDriverNamespace(); + if (mAngleNamespace) { + return mAngleNamespace; + } + + if (mAnglePath.empty()) { + ALOGV("mAnglePath is empty, not creating ANGLE namespace"); + return nullptr; + } + + mAngleNamespace = android_create_namespace("ANGLE", + nullptr, // ld_library_path + mAnglePath.c_str(), // default_library_path + ANDROID_NAMESPACE_TYPE_SHARED | + ANDROID_NAMESPACE_TYPE_ISOLATED, + nullptr, // permitted_when_isolated_path + nullptr); + + ALOGD_IF(!mAngleNamespace, "Could not create ANGLE namespace from default"); + + return mAngleNamespace; } + +} // namespace android |