Rootless GPU Debug
Add the ability to load GPU debug layers from the base
directory of debuggable applications.
This update concides with changes to framework/base to
control the enabling logic in GraphicsEnvironment.
This commit changes the Vulkan loader to:
* Scan an additional location for debug layers.
* Use the provided order of layers from GraphicsEnvironment,
overriding system properties.
* Use the first instance of a layer found, in the case of duplicates.
* Move layers paths and namespace to GraphicsEnv, removing vulkan_loader_data
Bug: 63708377
Test: Manual, CTS tests to follow
Change-Id: I38dc91bbc26671f5093ee1b12454fc024c0b5892
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 39b5829..f46e9f6 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -22,6 +22,7 @@
#include <log/log.h>
#include <nativeloader/dlext_namespaces.h>
+#include <nativeloader/native_loader.h>
// TODO(b/37049319) Get this from a header once one exists
extern "C" {
@@ -45,6 +46,32 @@
mDriverPath = path;
}
+void GraphicsEnv::setLayerPaths(android_namespace_t* appNamespace, const std::string layerPaths) {
+ if (mLayerPaths.empty()) {
+ mLayerPaths = layerPaths;
+ mAppNamespace = appNamespace;
+ } else {
+ ALOGV("Vulkan layer search path already set, not clobbering with '%s' for namespace %p'",
+ layerPaths.c_str(), appNamespace);
+ }
+}
+
+android_namespace_t* GraphicsEnv::getAppNamespace() {
+ return mAppNamespace;
+}
+
+const std::string GraphicsEnv::getLayerPaths(){
+ return mLayerPaths;
+}
+
+const std::string GraphicsEnv::getDebugLayers() {
+ return mDebugLayers;
+}
+
+void GraphicsEnv::setDebugLayers(const std::string layers) {
+ mDebugLayers = layers;
+}
+
android_namespace_t* GraphicsEnv::getDriverNamespace() {
static std::once_flag once;
std::call_once(once, [this]() {
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 7817076..213580c 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -35,10 +35,20 @@
void setDriverPath(const std::string path);
android_namespace_t* getDriverNamespace();
+ void setLayerPaths(android_namespace_t* appNamespace, const std::string layerPaths);
+ android_namespace_t* getAppNamespace();
+ const std::string getLayerPaths();
+
+ void setDebugLayers(const std::string layers);
+ const std::string getDebugLayers();
+
private:
GraphicsEnv() = default;
std::string mDriverPath;
+ std::string mDebugLayers;
+ std::string mLayerPaths;
android_namespace_t* mDriverNamespace = nullptr;
+ android_namespace_t* mAppNamespace = nullptr;
};
} // namespace android
diff --git a/vulkan/include/vulkan/vulkan_loader_data.h b/vulkan/include/vulkan/vulkan_loader_data.h
deleted file mode 100644
index 8ea4666..0000000
--- a/vulkan/include/vulkan/vulkan_loader_data.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef VULKAN_VULKAN_LOADER_DATA_H
-#define VULKAN_VULKAN_LOADER_DATA_H
-
-#include <string>
-
-struct android_namespace_t;
-
-namespace vulkan {
- struct LoaderData {
- std::string layer_path;
- android_namespace_t* app_namespace;
-
- __attribute__((visibility("default"))) static LoaderData& GetInstance();
- };
-}
-
-#endif
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index b55fa27..c9faf28 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -61,7 +61,6 @@
"layers_extensions.cpp",
"stubhal.cpp",
"swapchain.cpp",
- "vulkan_loader_data.cpp",
],
export_header_lib_headers: ["vulkan_headers"],
diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp
index d840786..673a066 100644
--- a/vulkan/libvulkan/api.cpp
+++ b/vulkan/libvulkan/api.cpp
@@ -29,14 +29,17 @@
#include <new>
#include <utility>
+#include <android-base/strings.h>
#include <cutils/properties.h>
#include <log/log.h>
#include <vulkan/vk_layer_interface.h>
+#include <graphicsenv/GraphicsEnv.h>
#include "api.h"
#include "driver.h"
#include "layers_extensions.h"
+
namespace vulkan {
namespace api {
@@ -121,15 +124,33 @@
if (!is_instance_ || !driver::Debuggable())
return;
- ParseDebugVulkanLayers();
- property_list(ParseDebugVulkanLayer, this);
+ GetLayersFromSettings();
- // sort by priorities
- auto& arr = implicit_layers_;
- std::sort(arr.elements, arr.elements + arr.count,
- [](const ImplicitLayer& a, const ImplicitLayer& b) {
- return (a.priority < b.priority);
- });
+ // If no layers specified via Settings, check legacy properties
+ if (implicit_layers_.count <= 0) {
+ ParseDebugVulkanLayers();
+ property_list(ParseDebugVulkanLayer, this);
+
+ // sort by priorities
+ auto& arr = implicit_layers_;
+ std::sort(arr.elements, arr.elements + arr.count,
+ [](const ImplicitLayer& a, const ImplicitLayer& b) {
+ return (a.priority < b.priority);
+ });
+ }
+ }
+
+ void GetLayersFromSettings() {
+ // These will only be available if conditions are met in GraphicsEnvironemnt
+ // gpu_debug_layers = layer1:layer2:layerN
+ const std::string layers = android::GraphicsEnv::getInstance().getDebugLayers();
+ if (!layers.empty()) {
+ ALOGV("Debug layer list: %s", layers.c_str());
+ std::vector<std::string> paths = android::base::Split(layers, ":");
+ for (uint32_t i = 0; i < paths.size(); i++) {
+ AddImplicitLayer(int(i), paths[i].c_str(), paths[i].length());
+ }
+ }
}
void ParseDebugVulkanLayers() {
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index 05856d3..3a59208 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -29,11 +29,10 @@
#include <android/dlext.h>
#include <android-base/strings.h>
#include <cutils/properties.h>
+#include <graphicsenv/GraphicsEnv.h>
#include <log/log.h>
#include <ziparchive/zip_archive.h>
-#include <vulkan/vulkan_loader_data.h>
-
// TODO(jessehall): The whole way we deal with extensions is pretty hokey, and
// not a good long-term solution. Having a hard-coded enum of extensions is
// bad, of course. Representing sets of extensions (requested, supported, etc.)
@@ -69,11 +68,16 @@
class LayerLibrary {
public:
- explicit LayerLibrary(const std::string& path)
- : path_(path), dlhandle_(nullptr), refcount_(0) {}
+ explicit LayerLibrary(const std::string& path,
+ const std::string& filename)
+ : path_(path),
+ filename_(filename),
+ dlhandle_(nullptr),
+ refcount_(0) {}
LayerLibrary(LayerLibrary&& other)
: path_(std::move(other.path_)),
+ filename_(std::move(other.filename_)),
dlhandle_(other.dlhandle_),
refcount_(other.refcount_) {
other.dlhandle_ = nullptr;
@@ -94,9 +98,14 @@
const char* gpa_name,
size_t gpa_name_len) const;
+ const std::string GetFilename() { return filename_; }
+
private:
const std::string path_;
+ // Track the filename alone so we can detect duplicates
+ const std::string filename_;
+
std::mutex mutex_;
void* dlhandle_;
size_t refcount_;
@@ -111,7 +120,7 @@
// any symbol dependencies will be resolved by system libraries. They
// can't safely use libc++_shared, for example. Which is one reason
// (among several) we only allow them in non-user builds.
- auto app_namespace = LoaderData::GetInstance().app_namespace;
+ auto app_namespace = android::GraphicsEnv::getInstance().getAppNamespace();
if (app_namespace &&
!android::base::StartsWith(path_, kSystemLayerLibraryDir)) {
android_dlextinfo dlextinfo = {};
@@ -305,8 +314,8 @@
std::vector<LayerLibrary> g_layer_libraries;
std::vector<Layer> g_instance_layers;
-void AddLayerLibrary(const std::string& path) {
- LayerLibrary library(path);
+void AddLayerLibrary(const std::string& path, const std::string& filename) {
+ LayerLibrary library(path + "/" + filename, filename);
if (!library.Open())
return;
@@ -398,7 +407,25 @@
ForEachFileInPath(path, [&](const std::string& filename) {
if (android::base::StartsWith(filename, "libVkLayer") &&
android::base::EndsWith(filename, ".so")) {
- AddLayerLibrary(path + "/" + filename);
+
+ // Check to ensure we haven't seen this layer already
+ // Let the first instance of the shared object be enumerated
+ // We're searching for layers in following order:
+ // 1. system path
+ // 2. libraryPermittedPath (if enabled)
+ // 3. libraryPath
+
+ bool duplicate = false;
+ for (auto& layer : g_layer_libraries) {
+ if (layer.GetFilename() == filename) {
+ ALOGV("Skipping duplicate layer %s in %s",
+ filename.c_str(), path.c_str());
+ duplicate = true;
+ }
+ }
+
+ if (!duplicate)
+ AddLayerLibrary(path, filename);
}
});
}
@@ -428,8 +455,8 @@
prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) {
DiscoverLayersInPathList(kSystemLayerLibraryDir);
}
- if (!LoaderData::GetInstance().layer_path.empty())
- DiscoverLayersInPathList(LoaderData::GetInstance().layer_path);
+ if (!android::GraphicsEnv::getInstance().getLayerPaths().empty())
+ DiscoverLayersInPathList(android::GraphicsEnv::getInstance().getLayerPaths());
}
uint32_t GetLayerCount() {
diff --git a/vulkan/libvulkan/vulkan_loader_data.cpp b/vulkan/libvulkan/vulkan_loader_data.cpp
deleted file mode 100644
index 0eda0af..0000000
--- a/vulkan/libvulkan/vulkan_loader_data.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <vulkan/vulkan_loader_data.h>
-
-using namespace vulkan;
-
-LoaderData& LoaderData::GetInstance() {
- static LoaderData loader_data = {};
- return loader_data;
-}