Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1a7eb59c authored by Jesse Hall's avatar Jesse Hall
Browse files

libvulkan: Discover layer libraries in entire search path

Previously we only searched the unpacked native library path for layer
libraries. Now we search all directories in the dynamic linker's
search path, including unpacked libraries in the APK itself.

Bug: 28213888
Change-Id: I37772fd90f705592ae1725c7c8603b0174e6b133
parent 12cb94a8
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
@@ -49,7 +49,8 @@ LOCAL_SRC_FILES := \
	vulkan_loader_data.cpp
	vulkan_loader_data.cpp
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk


LOCAL_SHARED_LIBRARIES := libhardware liblog libsync libutils libcutils
LOCAL_STATIC_LIBRARIES := libziparchive
LOCAL_SHARED_LIBRARIES := libhardware libsync libbase liblog libutils libcutils libz


LOCAL_MODULE := libvulkan
LOCAL_MODULE := libvulkan
include $(BUILD_SHARED_LIBRARY)
include $(BUILD_SHARED_LIBRARY)
+104 −52
Original line number Original line Diff line number Diff line
@@ -14,9 +14,8 @@
 * limitations under the License.
 * limitations under the License.
 */
 */


// #define LOG_NDEBUG 0

#include "layers_extensions.h"
#include "layers_extensions.h"

#include <alloca.h>
#include <alloca.h>
#include <dirent.h>
#include <dirent.h>
#include <dlfcn.h>
#include <dlfcn.h>
@@ -25,7 +24,12 @@
#include <string>
#include <string>
#include <string.h>
#include <string.h>
#include <vector>
#include <vector>

#include <android-base/strings.h>
#include <cutils/properties.h>
#include <log/log.h>
#include <log/log.h>
#include <ziparchive/zip_archive.h>

#include <vulkan/vulkan_loader_data.h>
#include <vulkan/vulkan_loader_data.h>


// TODO(jessehall): The whole way we deal with extensions is pretty hokey, and
// TODO(jessehall): The whole way we deal with extensions is pretty hokey, and
@@ -59,6 +63,8 @@ struct Layer {


namespace {
namespace {


const char kSystemLayerLibraryDir[] = "/data/local/debug/vulkan";

class LayerLibrary {
class LayerLibrary {
   public:
   public:
    LayerLibrary(const std::string& path)
    LayerLibrary(const std::string& path)
@@ -96,10 +102,9 @@ class LayerLibrary {


bool LayerLibrary::Open() {
bool LayerLibrary::Open() {
    std::lock_guard<std::mutex> lock(mutex_);
    std::lock_guard<std::mutex> lock(mutex_);

    if (refcount_++ == 0) {
    if (refcount_++ == 0) {
        ALOGV("opening layer library '%s'", path_.c_str());
        dlhandle_ = dlopen(path_.c_str(), RTLD_NOW | RTLD_LOCAL);
        dlhandle_ = dlopen(path_.c_str(), RTLD_NOW | RTLD_LOCAL);
        ALOGV("Opening library %s", path_.c_str());
        if (!dlhandle_) {
        if (!dlhandle_) {
            ALOGE("failed to load layer library '%s': %s", path_.c_str(),
            ALOGE("failed to load layer library '%s': %s", path_.c_str(),
                  dlerror());
                  dlerror());
@@ -107,19 +112,16 @@ bool LayerLibrary::Open() {
            return false;
            return false;
        }
        }
    }
    }
    ALOGV("Refcount on activate is %zu", refcount_);
    return true;
    return true;
}
}


void LayerLibrary::Close() {
void LayerLibrary::Close() {
    std::lock_guard<std::mutex> lock(mutex_);
    std::lock_guard<std::mutex> lock(mutex_);

    if (--refcount_ == 0) {
    if (--refcount_ == 0) {
        ALOGV("Closing library %s", path_.c_str());
        ALOGV("closing layer library '%s'", path_.c_str());
        dlclose(dlhandle_);
        dlclose(dlhandle_);
        dlhandle_ = nullptr;
        dlhandle_ = nullptr;
    }
    }
    ALOGV("Refcount on destruction is %zu", refcount_);
}
}


bool LayerLibrary::EnumerateLayers(size_t library_idx,
bool LayerLibrary::EnumerateLayers(size_t library_idx,
@@ -131,7 +133,7 @@ bool LayerLibrary::EnumerateLayers(size_t library_idx,
        reinterpret_cast<PFN_vkEnumerateInstanceExtensionProperties>(
        reinterpret_cast<PFN_vkEnumerateInstanceExtensionProperties>(
            dlsym(dlhandle_, "vkEnumerateInstanceExtensionProperties"));
            dlsym(dlhandle_, "vkEnumerateInstanceExtensionProperties"));
    if (!enumerate_instance_layers || !enumerate_instance_extensions) {
    if (!enumerate_instance_layers || !enumerate_instance_extensions) {
        ALOGV("layer library '%s' misses some instance enumeraion functions",
        ALOGE("layer library '%s' missing some instance enumeration functions",
              path_.c_str());
              path_.c_str());
        return false;
        return false;
    }
    }
@@ -150,7 +152,7 @@ bool LayerLibrary::EnumerateLayers(size_t library_idx,
    VkResult result = enumerate_instance_layers(&num_instance_layers, nullptr);
    VkResult result = enumerate_instance_layers(&num_instance_layers, nullptr);
    if (result != VK_SUCCESS || !num_instance_layers) {
    if (result != VK_SUCCESS || !num_instance_layers) {
        if (result != VK_SUCCESS) {
        if (result != VK_SUCCESS) {
            ALOGW(
            ALOGE(
                "vkEnumerateInstanceLayerProperties failed for library '%s': "
                "vkEnumerateInstanceLayerProperties failed for library '%s': "
                "%d",
                "%d",
                path_.c_str(), result);
                path_.c_str(), result);
@@ -161,7 +163,7 @@ bool LayerLibrary::EnumerateLayers(size_t library_idx,
        result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers,
        result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers,
                                         nullptr);
                                         nullptr);
        if (result != VK_SUCCESS) {
        if (result != VK_SUCCESS) {
            ALOGW(
            ALOGE(
                "vkEnumerateDeviceLayerProperties failed for library '%s': %d",
                "vkEnumerateDeviceLayerProperties failed for library '%s': %d",
                path_.c_str(), result);
                path_.c_str(), result);
            return false;
            return false;
@@ -173,7 +175,7 @@ bool LayerLibrary::EnumerateLayers(size_t library_idx,
        (num_instance_layers + num_device_layers) * sizeof(VkLayerProperties)));
        (num_instance_layers + num_device_layers) * sizeof(VkLayerProperties)));
    result = enumerate_instance_layers(&num_instance_layers, properties);
    result = enumerate_instance_layers(&num_instance_layers, properties);
    if (result != VK_SUCCESS) {
    if (result != VK_SUCCESS) {
        ALOGW("vkEnumerateInstanceLayerProperties failed for library '%s': %d",
        ALOGE("vkEnumerateInstanceLayerProperties failed for library '%s': %d",
              path_.c_str(), result);
              path_.c_str(), result);
        return false;
        return false;
    }
    }
@@ -181,7 +183,7 @@ bool LayerLibrary::EnumerateLayers(size_t library_idx,
        result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers,
        result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers,
                                         properties + num_instance_layers);
                                         properties + num_instance_layers);
        if (result != VK_SUCCESS) {
        if (result != VK_SUCCESS) {
            ALOGW(
            ALOGE(
                "vkEnumerateDeviceLayerProperties failed for library '%s': %d",
                "vkEnumerateDeviceLayerProperties failed for library '%s': %d",
                path_.c_str(), result);
                path_.c_str(), result);
            return false;
            return false;
@@ -203,9 +205,9 @@ bool LayerLibrary::EnumerateLayers(size_t library_idx,
        result =
        result =
            enumerate_instance_extensions(props.layerName, &count, nullptr);
            enumerate_instance_extensions(props.layerName, &count, nullptr);
        if (result != VK_SUCCESS) {
        if (result != VK_SUCCESS) {
            ALOGW(
            ALOGE(
                "vkEnumerateInstanceExtensionProperties(%s) failed for library "
                "vkEnumerateInstanceExtensionProperties(\"%s\") failed for "
                "'%s': %d",
                "library '%s': %d",
                props.layerName, path_.c_str(), result);
                props.layerName, path_.c_str(), result);
            instance_layers.resize(prev_num_instance_layers);
            instance_layers.resize(prev_num_instance_layers);
            return false;
            return false;
@@ -214,9 +216,9 @@ bool LayerLibrary::EnumerateLayers(size_t library_idx,
        result = enumerate_instance_extensions(
        result = enumerate_instance_extensions(
            props.layerName, &count, layer.instance_extensions.data());
            props.layerName, &count, layer.instance_extensions.data());
        if (result != VK_SUCCESS) {
        if (result != VK_SUCCESS) {
            ALOGW(
            ALOGE(
                "vkEnumerateInstanceExtensionProperties(%s) failed for library "
                "vkEnumerateInstanceExtensionProperties(\"%s\") failed for "
                "'%s': %d",
                "library '%s': %d",
                props.layerName, path_.c_str(), result);
                props.layerName, path_.c_str(), result);
            instance_layers.resize(prev_num_instance_layers);
            instance_layers.resize(prev_num_instance_layers);
            return false;
            return false;
@@ -234,8 +236,8 @@ bool LayerLibrary::EnumerateLayers(size_t library_idx,
            result = enumerate_device_extensions(
            result = enumerate_device_extensions(
                VK_NULL_HANDLE, props.layerName, &count, nullptr);
                VK_NULL_HANDLE, props.layerName, &count, nullptr);
            if (result != VK_SUCCESS) {
            if (result != VK_SUCCESS) {
                ALOGW(
                ALOGE(
                    "vkEnumerateDeviceExtensionProperties(%s) failed for "
                    "vkEnumerateDeviceExtensionProperties(\"%s\") failed for "
                    "library '%s': %d",
                    "library '%s': %d",
                    props.layerName, path_.c_str(), result);
                    props.layerName, path_.c_str(), result);
                instance_layers.resize(prev_num_instance_layers);
                instance_layers.resize(prev_num_instance_layers);
@@ -246,8 +248,8 @@ bool LayerLibrary::EnumerateLayers(size_t library_idx,
                VK_NULL_HANDLE, props.layerName, &count,
                VK_NULL_HANDLE, props.layerName, &count,
                layer.device_extensions.data());
                layer.device_extensions.data());
            if (result != VK_SUCCESS) {
            if (result != VK_SUCCESS) {
                ALOGW(
                ALOGE(
                    "vkEnumerateDeviceExtensionProperties(%s) failed for "
                    "vkEnumerateDeviceExtensionProperties(\"%s\") failed for "
                    "library '%s': %d",
                    "library '%s': %d",
                    props.layerName, path_.c_str(), result);
                    props.layerName, path_.c_str(), result);
                instance_layers.resize(prev_num_instance_layers);
                instance_layers.resize(prev_num_instance_layers);
@@ -256,8 +258,9 @@ bool LayerLibrary::EnumerateLayers(size_t library_idx,
        }
        }


        instance_layers.push_back(layer);
        instance_layers.push_back(layer);
        ALOGV("  added %s layer '%s'",
        ALOGD("added %s layer '%s' from library '%s'",
              (layer.is_global) ? "global" : "instance", props.layerName);
              (layer.is_global) ? "global" : "instance", props.layerName,
              path_.c_str());
    }
    }


    return true;
    return true;
@@ -280,12 +283,12 @@ void* LayerLibrary::GetGPA(const Layer& layer,
    return gpa;
    return gpa;
}
}


// ----------------------------------------------------------------------------

std::vector<LayerLibrary> g_layer_libraries;
std::vector<LayerLibrary> g_layer_libraries;
std::vector<Layer> g_instance_layers;
std::vector<Layer> g_instance_layers;


void AddLayerLibrary(const std::string& path) {
void AddLayerLibrary(const std::string& path) {
    ALOGV("examining layer library '%s'", path.c_str());

    LayerLibrary library(path);
    LayerLibrary library(path);
    if (!library.Open())
    if (!library.Open())
        return;
        return;
@@ -300,34 +303,81 @@ void AddLayerLibrary(const std::string& path) {
    g_layer_libraries.emplace_back(std::move(library));
    g_layer_libraries.emplace_back(std::move(library));
}
}


void DiscoverLayersInDirectory(const std::string& dir_path) {
template <typename Functor>
    ALOGV("looking for layers in '%s'", dir_path.c_str());
void ForEachFileInDir(const std::string& dirname, Functor functor) {

    auto dir_deleter = [](DIR* handle) { closedir(handle); };
    DIR* directory = opendir(dir_path.c_str());
    std::unique_ptr<DIR, decltype(dir_deleter)> dir(opendir(dirname.c_str()),
    if (!directory) {
                                                    dir_deleter);
    if (!dir) {
        // It's normal for some search directories to not exist, especially
        // /data/local/debug/vulkan.
        int err = errno;
        int err = errno;
        ALOGV_IF(err != ENOENT, "failed to open layer directory '%s': %s (%d)",
        ALOGW_IF(err != ENOENT, "failed to open layer directory '%s': %s",
                 dir_path.c_str(), strerror(err), err);
                 dirname.c_str(), strerror(err));
        return;
        return;
    }
    }

    ALOGD("searching for layers in '%s'", dirname.c_str());
    std::string path;
    dirent* entry;
    path.reserve(dir_path.size() + 20);
    while ((entry = readdir(dir.get())) != nullptr)
    path.append(dir_path);
        functor(entry->d_name);
    path.append("/");

    struct dirent* entry;
    while ((entry = readdir(directory))) {
        size_t libname_len = strlen(entry->d_name);
        if (strncmp(entry->d_name, "libVkLayer", 10) != 0 ||
            strncmp(entry->d_name + libname_len - 3, ".so", 3) != 0)
            continue;
        path.append(entry->d_name);
        AddLayerLibrary(path);
        path.resize(dir_path.size() + 1);
}
}


    closedir(directory);
template <typename Functor>
void ForEachFileInZip(const std::string& zipname,
                      const std::string& dir_in_zip,
                      Functor functor) {
    int32_t err;
    ZipArchiveHandle zip = nullptr;
    if ((err = OpenArchive(zipname.c_str(), &zip)) != 0) {
        ALOGE("failed to open apk '%s': %d", zipname.c_str(), err);
        return;
    }
    std::string prefix(dir_in_zip + "/");
    const ZipString prefix_str(prefix.c_str());
    void* iter_cookie = nullptr;
    if ((err = StartIteration(zip, &iter_cookie, &prefix_str, nullptr)) != 0) {
        ALOGE("failed to iterate entries in apk '%s': %d", zipname.c_str(),
              err);
        CloseArchive(zip);
        return;
    }
    ALOGD("searching for layers in '%s!/%s'", zipname.c_str(),
          dir_in_zip.c_str());
    ZipEntry entry;
    ZipString name;
    while (Next(iter_cookie, &entry, &name) == 0) {
        std::string filename(
            reinterpret_cast<const char*>(name.name) + prefix.length(),
            name.name_length - prefix.length());
        // only enumerate direct entries of the directory, not subdirectories
        if (filename.find('/') == filename.npos)
            functor(filename);
    }
    EndIteration(iter_cookie);
    CloseArchive(zip);
}

template <typename Functor>
void ForEachFileInPath(const std::string& path, Functor functor) {
    size_t zip_pos = path.find("!/");
    if (zip_pos == std::string::npos) {
        ForEachFileInDir(path, functor);
    } else {
        ForEachFileInZip(path.substr(0, zip_pos), path.substr(zip_pos + 2),
                         functor);
    }
}

void DiscoverLayersInPathList(const std::string& pathstr) {
    std::vector<std::string> paths = android::base::Split(pathstr, ":");
    for (const auto& path : paths) {
        ForEachFileInPath(path, [&](const std::string& filename) {
            if (android::base::StartsWith(filename, "libVkLayer") &&
                android::base::EndsWith(filename, ".so")) {
                AddLayerLibrary(path + "/" + filename);
            }
        });
    }
}
}


const VkExtensionProperties* FindExtension(
const VkExtensionProperties* FindExtension(
@@ -350,10 +400,12 @@ void* GetLayerGetProcAddr(const Layer& layer,
}  // anonymous namespace
}  // anonymous namespace


void DiscoverLayers() {
void DiscoverLayers() {
    if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0))
    if (property_get_bool("ro.debuggable", false) &&
        DiscoverLayersInDirectory("/data/local/debug/vulkan");
        prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) {
        DiscoverLayersInPathList(kSystemLayerLibraryDir);
    }
    if (!LoaderData::GetInstance().layer_path.empty())
    if (!LoaderData::GetInstance().layer_path.empty())
        DiscoverLayersInDirectory(LoaderData::GetInstance().layer_path.c_str());
        DiscoverLayersInPathList(LoaderData::GetInstance().layer_path);
}
}


uint32_t GetLayerCount() {
uint32_t GetLayerCount() {