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

Commit b2401203 authored by Jesse Hall's avatar Jesse Hall
Browse files

Load updated drivers using derived loader namespace

Bug: 33531483
Test: Launch vulkan apps w/ and w/o updated driver package
Change-Id: Ia73e1e33b637d6ffd96ea0480ed6d85b9f68dce3
parent bf8bc228
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@

#include <string>

struct android_namespace_t;

namespace android {

class GraphicsEnv {
@@ -31,10 +33,12 @@ public:
    // in the search path must have a '!' after the zip filename, e.g.
    //     /data/app/com.example.driver/base.apk!/lib/arm64-v8a
    void setDriverPath(const std::string path);
    android_namespace_t* getDriverNamespace();

private:
    GraphicsEnv() = default;
    std::string mDriverPath;
    android_namespace_t* mDriverNamespace = nullptr;
};

} // namespace android
+1 −0
Original line number Diff line number Diff line
@@ -96,6 +96,7 @@ cc_library_shared {
    ],

    shared_libs: [
        "libnativeloader",
        "libbinder",
        "libcutils",
        "libEGL",
+37 −0
Original line number Diff line number Diff line
@@ -18,7 +18,10 @@
#define LOG_TAG "GraphicsEnv"
#include <gui/GraphicsEnv.h>

#include <mutex>

#include <log/log.h>
#include <nativeloader/dlext_namespaces.h>

namespace android {

@@ -37,4 +40,38 @@ void GraphicsEnv::setDriverPath(const std::string path) {
    mDriverPath = path;
}

android_namespace_t* GraphicsEnv::getDriverNamespace() {
    static std::once_flag once;
    std::call_once(once, [this]() {
        // TODO; In the next version of Android, all graphics drivers will be
        // loaded into a custom namespace. To minimize risk for this release,
        // only updated drivers use a custom namespace.
        //
        // Additionally, the custom namespace will be
        // ANDROID_NAMESPACE_TYPE_ISOLATED, and will only have access to a
        // subset of the system.
        if (mDriverPath.empty())
            return;

        char defaultPath[PATH_MAX];
        android_get_LD_LIBRARY_PATH(defaultPath, sizeof(defaultPath));
        size_t defaultPathLen = strlen(defaultPath);

        std::string path;
        path.reserve(mDriverPath.size() + 1 + defaultPathLen);
        path.append(mDriverPath);
        path.push_back(':');
        path.append(defaultPath, defaultPathLen);

        mDriverNamespace = android_create_namespace(
                "gfx driver",
                nullptr,                    // ld_library_path
                path.c_str(),               // default_library_path
                ANDROID_NAMESPACE_TYPE_SHARED,
                nullptr,                    // permitted_when_isolated_path
                nullptr);                   // parent
    });
    return mDriverNamespace;
}

} // namespace android
+1 −0
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ cc_library_shared {
        "libziparchive",
    ],
    shared_libs: [
        "libgui",
        "libhardware",
        "libsync",
        "libbase",
+66 −4
Original line number Diff line number Diff line
@@ -21,10 +21,15 @@

#include <algorithm>
#include <array>
#include <dlfcn.h>
#include <new>

#include <log/log.h>

#include <android/dlext.h>
#include <cutils/properties.h>
#include <gui/GraphicsEnv.h>

#include "driver.h"
#include "stubhal.h"

@@ -126,17 +131,74 @@ class CreateInfoWrapper {

Hal Hal::hal_;

void* LoadLibrary(const android_dlextinfo& dlextinfo,
                  const char* subname,
                  int subname_len) {
    const char kLibFormat[] = "vulkan.%*s.so";
    char* name = static_cast<char*>(
        alloca(sizeof(kLibFormat) + static_cast<size_t>(subname_len)));
    sprintf(name, kLibFormat, subname_len, subname);
    return android_dlopen_ext(name, RTLD_LOCAL | RTLD_NOW, &dlextinfo);
}

const std::array<const char*, 2> HAL_SUBNAME_KEY_PROPERTIES = {{
    "ro.hardware." HWVULKAN_HARDWARE_MODULE_ID,
    "ro.board.platform",
}};

int LoadUpdatedDriver(const hw_module_t** module) {
    const android_dlextinfo dlextinfo = {
        .flags = ANDROID_DLEXT_USE_NAMESPACE,
        .library_namespace = android::GraphicsEnv::getInstance().getDriverNamespace(),
    };
    if (!dlextinfo.library_namespace)
        return -ENOENT;

    void* so = nullptr;
    char prop[PROPERTY_VALUE_MAX];
    for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
        int prop_len = property_get(key, prop, nullptr);
        if (prop_len > 0) {
            so = LoadLibrary(dlextinfo, prop, prop_len);
            if (so)
                break;
        }
    }
    if (!so)
        return -ENOENT;

    hw_module_t* hmi = static_cast<hw_module_t*>(dlsym(so, HAL_MODULE_INFO_SYM_AS_STR));
    if (!hmi) {
        ALOGE("couldn't find symbol '%s' in HAL library: %s", HAL_MODULE_INFO_SYM_AS_STR, dlerror());
        dlclose(so);
        return -EINVAL;
    }
    if (strcmp(hmi->id, HWVULKAN_HARDWARE_MODULE_ID) != 0) {
        ALOGE("HAL id '%s' != '%s'", hmi->id, HWVULKAN_HARDWARE_MODULE_ID);
        dlclose(so);
        return -EINVAL;
    }
    hmi->dso = so;
    *module = hmi;
    ALOGD("loaded updated driver");
    return 0;
}

bool Hal::Open() {
    ALOG_ASSERT(!hal_.dev_, "OpenHAL called more than once");

    // Use a stub device unless we successfully open a real HAL device.
    hal_.dev_ = &stubhal::kDevice;

    const hwvulkan_module_t* module;
    int result =
        hw_get_module("vulkan", reinterpret_cast<const hw_module_t**>(&module));
    int result;
    const hwvulkan_module_t* module = nullptr;

    result = LoadUpdatedDriver(reinterpret_cast<const hw_module_t**>(&module));
    if (result == -ENOENT) {
        result = hw_get_module(HWVULKAN_HARDWARE_MODULE_ID, reinterpret_cast<const hw_module_t**>(&module));
    }
    if (result != 0) {
        ALOGI("no Vulkan HAL present, using stub HAL");
        ALOGV("unable to load Vulkan HAL, using stub HAL (result=%d)", result);
        return true;
    }