diff --git a/src/loader/android_utilities.cpp b/src/loader/android_utilities.cpp index 9a3ad76c..dd121abd 100644 --- a/src/loader/android_utilities.cpp +++ b/src/loader/android_utilities.cpp @@ -38,8 +38,13 @@ constexpr auto SYSTEM_AUTHORITY = "org.khronos.openxr.system_runtime_broker"; constexpr auto BASE_PATH = "openxr"; constexpr auto ABI_PATH = "abi"; constexpr auto RUNTIMES_PATH = "runtimes"; +constexpr auto API_LAYERS_PATH = "api_layers"; +constexpr auto IMP_LAYER = "implicit"; +constexpr auto EXP_LAYER = "explicit"; constexpr const char *getBrokerAuthority(bool systemBroker) { return systemBroker ? SYSTEM_AUTHORITY : AUTHORITY; } +constexpr const char *getLayerTypePath(bool implicitLayer) { return implicitLayer ? IMP_LAYER : EXP_LAYER; } +constexpr const char *getFunctionTypePath(bool runtimeFunctions) { return runtimeFunctions ? RUNTIMES_PATH : API_LAYERS_PATH; } struct BaseColumns { /** @@ -132,12 +137,14 @@ static constexpr auto TABLE_PATH = "functions"; * runtime package and major version of OpenXR. * * @param systemBroker If the system runtime broker (instead of the installable one) should be queried. + * @param runtimeFunctions If the runtime functions (instead of the API layer functions) should be queried. * @param majorVer The major version of OpenXR. * @param packageName The package name of the runtime. * @param abi The Android ABI name in use. * @return A content URI for the entire table: the function remapping for that runtime. */ -static Uri makeContentUri(bool systemBroker, int majorVersion, std::string const &packageName, const char *abi) { +static Uri makeContentUri(bool systemBroker, bool runtimeFunctions, int majorVersion, std::string const &packageName, + const char *abi, std::string const &layerName) { auto builder = Uri_Builder::construct(); builder.scheme("content") .authority(getBrokerAuthority(systemBroker)) @@ -145,9 +152,12 @@ static Uri makeContentUri(bool systemBroker, int majorVersion, std::string const .appendPath(std::to_string(majorVersion)) .appendPath(ABI_PATH) .appendPath(abi) - .appendPath(RUNTIMES_PATH) - .appendPath(packageName) - .appendPath(TABLE_PATH); + .appendPath(getFunctionTypePath(runtimeFunctions)) + .appendPath(packageName); + if (!runtimeFunctions) { + builder.appendPath(layerName); + } + builder.appendPath(TABLE_PATH); return builder.build(); } @@ -164,6 +174,95 @@ struct Columns : BaseColumns { }; } // namespace functions +namespace instance_extensions { +/** + * Final path component to this URI. + */ +static constexpr auto TABLE_PATH = "instance_extensions"; + +/** + * Create a content URI for querying all rows of the instance extensions supported by a given + * API layer. + * + * @param systemBroker If the system runtime broker (instead of the installable one) should be queried. + * @param majorVer The major version of OpenXR. + * @param packageName The package name of the runtime. + * @param abi The Android ABI name in use. + * @param layerName The API layer name. + * @return A content URI for the entire table: the function remapping for that runtime. + */ +static Uri makeContentUri(bool systemBroker, int majorVersion, std::string const &packageName, const char *abi, + std::string const &layerName) { + auto builder = Uri_Builder::construct(); + builder.scheme("content") + .authority(getBrokerAuthority(systemBroker)) + .appendPath(BASE_PATH) + .appendPath(std::to_string(majorVersion)) + .appendPath(ABI_PATH) + .appendPath(abi) + .appendPath(API_LAYERS_PATH) + .appendPath(packageName) + .appendPath(layerName) + .appendPath(TABLE_PATH); + return builder.build(); +} +struct Columns : BaseColumns { + /** + * Constant for the INSTANCE_EXTENSION_NAMES column name + */ + static constexpr auto INSTANCE_EXTENSION_NAMES = "instance_extension_names"; + + /** + * Constant for the INSTANCE_EXTENSION_VERSIONS column name + */ + static constexpr auto INSTANCE_EXTENSION_VERSIONS = "instance_extension_versions"; +}; +} // namespace instance_extensions + +namespace api_layer { +/** + * Final path component to this URI. + */ + +/** + * Create a content URI for querying all rows of the implicit/explicit API layer data for a given + * runtime package and major version of OpenXR. + * + * @param systemBroker If the system runtime broker (instead of the installable one) should be queried. + * @param majorVer The major version of OpenXR. + * @param layerType The layer type of the API layer. + * @param abi The Android ABI name in use. + * @return A content URI for the entire table: the function remapping for that runtime. + */ +static Uri makeContentUri(bool systemBroker, int majorVersion, std::string const &layerType, const char *abi) { + auto builder = Uri_Builder::construct(); + builder.scheme("content") + .authority(getBrokerAuthority(systemBroker)) + .appendPath(BASE_PATH) + .appendPath(std::to_string(majorVersion)) + .appendPath(ABI_PATH) + .appendPath(abi) + .appendPath(API_LAYERS_PATH) + .appendPath(getLayerTypePath(layerType == IMP_LAYER)); + return builder.build(); +} +struct Columns : BaseColumns { + // implicit or explicit + static constexpr auto PACKAGE_NAME = "package_name"; + static constexpr auto FILE_FORMAT_VERSION = "file_format_version"; + static constexpr auto NAME = "name"; + static constexpr auto NATIVE_LIB_DIR = "native_lib_dir"; + static constexpr auto SO_FILENAME = "so_filename"; + static constexpr auto API_VERSION = "api_version"; + static constexpr auto IMPLEMENTATION_VERSION = "implementation_version"; + static constexpr auto DESCRIPTION = "description"; + static constexpr auto DISABLE_ENVIRONMENT = "disable_environment"; + static constexpr auto ENABLE_ENVIRONMENT = "enable_environment"; + static constexpr auto HAS_FUNCTIONS = "has_functions"; + static constexpr auto HAS_INSTANCE_EXTENSIONS = "has_instance_extensions"; +}; +} // namespace api_layer + } // namespace static inline jni::Array makeArray(std::initializer_list &&list) { @@ -221,7 +320,7 @@ static int populateFunctions(wrap::android::content::Context const &context, boo JsonManifestBuilder &builder) { jni::Array projection = makeArray({functions::Columns::FUNCTION_NAME, functions::Columns::SYMBOL_NAME}); - auto uri = functions::makeContentUri(systemBroker, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), packageName, ABI); + auto uri = functions::makeContentUri(systemBroker, true, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), packageName, ABI, ""); ALOGI("populateFunctions: Querying URI: %s", uri.toString().c_str()); Cursor cursor = context.getContentResolver().query(uri, projection); @@ -245,11 +344,75 @@ static int populateFunctions(wrap::android::content::Context const &context, boo return 0; } -/// Get cursor for active runtime, parameterized by whether or not we use the system broker -static bool getActiveRuntimeCursor(wrap::android::content::Context const &context, jni::Array const &projection, - bool systemBroker, Cursor &cursor) { - auto uri = active_runtime::makeContentUri(systemBroker, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), ABI); - ALOGI("getActiveRuntimeCursor: Querying URI: %s", uri.toString().c_str()); +static int populateApiLayerFunctions(wrap::android::content::Context const &context, bool systemBroker, + const std::string &packageName, std::string const &layerName, Json::Value &rootNode) { + jni::Array projection = makeArray({functions::Columns::FUNCTION_NAME, functions::Columns::SYMBOL_NAME}); + + auto uri = + functions::makeContentUri(systemBroker, false, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), packageName, ABI, layerName); + ALOGI("populateApiLayerFunctions: Querying URI: %s", uri.toString().c_str()); + + Cursor cursor = context.getContentResolver().query(uri, projection); + + if (cursor.isNull()) { + ALOGE("Null cursor when querying content resolver for API layer functions."); + return -1; + } + if (cursor.getCount() < 1) { + ALOGE("Non-null but empty cursor when querying content resolver for API layer functions."); + cursor.close(); + return -1; + } + auto functionIndex = cursor.getColumnIndex(functions::Columns::FUNCTION_NAME); + auto symbolIndex = cursor.getColumnIndex(functions::Columns::SYMBOL_NAME); + while (cursor.moveToNext()) { + rootNode["api_layer"]["functions"][cursor.getString(functionIndex)] = cursor.getString(symbolIndex); + } + + cursor.close(); + return 0; +} + +static int populateApiLayerInstanceExtensions(wrap::android::content::Context const &context, bool systemBroker, + const std::string &packageName, std::string const &layerName, Json::Value &rootNode) { + jni::Array projection = makeArray( + {instance_extensions::Columns::INSTANCE_EXTENSION_NAMES, instance_extensions::Columns::INSTANCE_EXTENSION_VERSIONS}); + + auto uri = + instance_extensions::makeContentUri(systemBroker, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), packageName, ABI, layerName); + ALOGI("populateApiLayerInstanceExtensions: Querying URI: %s", uri.toString().c_str()); + + Cursor cursor = context.getContentResolver().query(uri, projection); + + if (cursor.isNull()) { + ALOGE("Null cursor when querying content resolver for API layer instance extensions."); + return -1; + } + if (cursor.getCount() < 1) { + ALOGE("Non-null but empty cursor when querying content resolver for API layer instance extensions."); + cursor.close(); + return -1; + } + auto nameIndex = cursor.getColumnIndex(instance_extensions::Columns::INSTANCE_EXTENSION_NAMES); + auto versionIndex = cursor.getColumnIndex(instance_extensions::Columns::INSTANCE_EXTENSION_VERSIONS); + Json::Value extension(Json::objectValue); + while (cursor.moveToNext()) { + extension["name"] = cursor.getString(nameIndex); + extension["extension_version"] = cursor.getString(versionIndex); + rootNode["api_layer"]["instance_extensions"].append(extension); + } + + cursor.close(); + return 0; +} + +/// Get cursor for active runtime or API layer, parameterized by target type and whether or not we use the system broker +static bool getCursor(wrap::android::content::Context const &context, jni::Array const &projection, + std::string const &targetType, bool systemBroker, Cursor &cursor) { + auto uri = (targetType == RUNTIMES_PATH) + ? active_runtime::makeContentUri(systemBroker, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), ABI) + : api_layer::makeContentUri(systemBroker, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), targetType, ABI); + ALOGI("getCursor: Querying URI: %s", uri.toString().c_str()); try { cursor = context.getContentResolver().query(uri, projection); } catch (const std::exception &e) { @@ -279,10 +442,10 @@ int getActiveRuntimeVirtualManifest(wrap::android::content::Context const &conte // First, try getting the installable broker's provider bool systemBroker = false; Cursor cursor; - if (!getActiveRuntimeCursor(context, projection, systemBroker, cursor)) { + if (!getCursor(context, projection, RUNTIMES_PATH, systemBroker, cursor)) { // OK, try the system broker as a fallback. systemBroker = true; - getActiveRuntimeCursor(context, projection, systemBroker, cursor); + getCursor(context, projection, RUNTIMES_PATH, systemBroker, cursor); } if (cursor.isNull()) { @@ -314,6 +477,93 @@ int getActiveRuntimeVirtualManifest(wrap::android::content::Context const &conte virtualManifest = builder.build(); return 0; } + +static bool populateApiLayerManifest(bool systemBroker, std::string layerType, wrap::android::content::Context const &context, + Cursor &cursor, std::vector &layerRootNode) { + auto packageName = cursor.getString(cursor.getColumnIndex(api_layer::Columns::PACKAGE_NAME)); + auto fileFormatVersion = cursor.getString(cursor.getColumnIndex(api_layer::Columns::FILE_FORMAT_VERSION)); + auto name = cursor.getString(cursor.getColumnIndex(api_layer::Columns::NAME)); + auto libDir = cursor.getString(cursor.getColumnIndex(active_runtime::Columns::NATIVE_LIB_DIR)); + auto fileName = cursor.getString(cursor.getColumnIndex(api_layer::Columns::SO_FILENAME)); + auto apiVersion = cursor.getString(cursor.getColumnIndex(api_layer::Columns::API_VERSION)); + auto implementationVersion = cursor.getString(cursor.getColumnIndex(api_layer::Columns::IMPLEMENTATION_VERSION)); + auto description = cursor.getString(cursor.getColumnIndex(api_layer::Columns::DESCRIPTION)); + auto has_instance_extensions = cursor.getString(cursor.getColumnIndex(api_layer::Columns::HAS_INSTANCE_EXTENSIONS)); + auto has_functions = cursor.getString(cursor.getColumnIndex(api_layer::Columns::HAS_FUNCTIONS)); + + __android_log_print(ANDROID_LOG_INFO, TAG, "Got api layer: type: %s, name: %s, native lib dir: %s, fileName: %s", + layerType.c_str(), name.c_str(), libDir.c_str(), fileName.c_str()); + + Json::Value rootNode(Json::objectValue); + rootNode["file_format_version"] = fileFormatVersion; + rootNode["api_layer"] = Json::objectValue; + rootNode["api_layer"]["name"] = name; + rootNode["api_layer"]["library_path"] = libDir + "/" + fileName; + rootNode["api_layer"]["api_version"] = apiVersion; + rootNode["api_layer"]["implementation_version"] = implementationVersion; + rootNode["api_layer"]["description"] = description; + if (has_functions == "true") { + rootNode["api_layer"]["functions"] = Json::Value(Json::objectValue); + populateApiLayerFunctions(context, systemBroker, packageName, name, rootNode); + } + if (has_instance_extensions == "true") { + rootNode["api_layer"]["instance_extensions"] = Json::Value(Json::arrayValue); + populateApiLayerInstanceExtensions(context, systemBroker, packageName, name, rootNode); + } + + layerRootNode.push_back(rootNode); + + return true; +} + +static void enumerateApiLayerManifests(std::string layerType, wrap::android::content::Context const &context, + jni::Array &projection, std::vector &virtualManifests) { + Cursor cursor; + + // First, try getting the installable broker's provider + bool systemBroker = false; + if (!getCursor(context, projection, layerType, systemBroker, cursor)) { + // OK, try the system broker as a fallback. + systemBroker = true; + getCursor(context, projection, layerType, systemBroker, cursor); + } + + if (cursor.isNull()) { + return; + } + cursor.moveToFirst(); + for (int i = 0; i < cursor.getCount(); ++i) { + populateApiLayerManifest(systemBroker, layerType, context, cursor, virtualManifests); + cursor.moveToNext(); + } + + cursor.close(); +} + +int getApiLayerVirtualManifests(std::string layerType, wrap::android::content::Context const &context, + std::vector &virtualManifests) { + static bool hasQueryBroker = false; + static std::vector implicitLayerManifest; + static std::vector explicitLayerManifest; + + __android_log_print(ANDROID_LOG_INFO, TAG, "Try to get %s API layer from broker!", layerType.c_str()); + if (!hasQueryBroker) { + jni::Array projection = + makeArray({api_layer::Columns::PACKAGE_NAME, api_layer::Columns::FILE_FORMAT_VERSION, api_layer::Columns::NAME, + api_layer::Columns::NATIVE_LIB_DIR, api_layer::Columns::SO_FILENAME, api_layer::Columns::API_VERSION, + api_layer::Columns::IMPLEMENTATION_VERSION, api_layer::Columns::DESCRIPTION, + api_layer::Columns::HAS_FUNCTIONS, api_layer::Columns::HAS_INSTANCE_EXTENSIONS}); + + enumerateApiLayerManifests(IMP_LAYER, context, projection, implicitLayerManifest); + enumerateApiLayerManifests(EXP_LAYER, context, projection, explicitLayerManifest); + + hasQueryBroker = true; + } + + virtualManifests = (layerType == IMP_LAYER) ? implicitLayerManifest : explicitLayerManifest; + return 0; +} + } // namespace openxr_android #endif // __ANDROID__ diff --git a/src/loader/android_utilities.h b/src/loader/android_utilities.h index f66c9bf1..3356fd95 100644 --- a/src/loader/android_utilities.h +++ b/src/loader/android_utilities.h @@ -27,6 +27,18 @@ using wrap::android::content::Context; * @return 0 on success, something else on failure. */ int getActiveRuntimeVirtualManifest(wrap::android::content::Context const &context, Json::Value &virtualManifest); + +/*! + * Find the implicit/explicit API layers on the system, and return a constructed JSON object representing it. + * + * @param type An String to indicate layer type of API layers, implicit or explicit. + * @param context An Android context, preferably an Activity Context. + * @param[out] virtualManifest The Json::Value to fill with the virtual manifest. + * + * @return 0 on success, something else on failure. + */ +int getApiLayerVirtualManifests(std::string layerType, wrap::android::content::Context const &context, + std::vector &virtualManifests); } // namespace openxr_android #endif // __ANDROID__ diff --git a/src/loader/manifest_file.cpp b/src/loader/manifest_file.cpp index 0683bc16..23b9606d 100644 --- a/src/loader/manifest_file.cpp +++ b/src/loader/manifest_file.cpp @@ -755,6 +755,120 @@ void ApiLayerManifestFile::AddManifestFilesAndroid(ManifestFileType type, } #endif // XR_USE_PLATFORM_ANDROID +void ApiLayerManifestFile::CreateIfValid(ManifestFileType type, const Json::Value &root_node, const std::string &filename, + std::vector> &manifest_files) { + std::ostringstream error_ss("ApiLayerManifestFile::CreateIfValid "); + JsonVersion file_version = {}; + if (!ManifestFile::IsValidJson(root_node, file_version)) { + error_ss << "isValidJson indicates " << filename << " is not a valid manifest file."; + LoaderLogger::LogErrorMessage("", error_ss.str()); + return; + } + + Json::Value layer_root_node = root_node["api_layer"]; + + // The API Layer manifest file needs the "api_layer" root as well as other sub-nodes. + // If any of those aren't there, fail. + if (layer_root_node.isNull() || layer_root_node["name"].isNull() || !layer_root_node["name"].isString() || + layer_root_node["api_version"].isNull() || !layer_root_node["api_version"].isString() || + layer_root_node["library_path"].isNull() || !layer_root_node["library_path"].isString() || + layer_root_node["implementation_version"].isNull() || !layer_root_node["implementation_version"].isString()) { + error_ss << filename << " is missing required fields. Verify all proper fields exist."; + LoaderLogger::LogErrorMessage("", error_ss.str()); + return; + } + if (MANIFEST_TYPE_IMPLICIT_API_LAYER == type) { + bool enabled = true; +#if !defined(XR_OS_ANDROID) + // Implicit layers require the disable environment variable. + if (layer_root_node["disable_environment"].isNull() || !layer_root_node["disable_environment"].isString()) { + error_ss << "Implicit layer " << filename << " is missing \"disable_environment\""; + LoaderLogger::LogErrorMessage("", error_ss.str()); + return; + } + // Check if there's an enable environment variable provided + if (!layer_root_node["enable_environment"].isNull() && layer_root_node["enable_environment"].isString()) { + std::string env_var = layer_root_node["enable_environment"].asString(); + // If it's not set in the environment, disable the layer + if (!PlatformUtilsGetEnvSet(env_var.c_str())) { + enabled = false; + } + } + // Check for the disable environment variable, which must be provided in the JSON + std::string env_var = layer_root_node["disable_environment"].asString(); + // If the env var is set, disable the layer. Disable env var overrides enable above + if (PlatformUtilsGetEnvSet(env_var.c_str())) { + enabled = false; + } +#endif + + // Not enabled, so pretend like it isn't even there. + if (!enabled) { + error_ss << "Implicit layer " << filename << " is disabled"; + LoaderLogger::LogInfoMessage("", error_ss.str()); + return; + } + } + std::string layer_name = layer_root_node["name"].asString(); + std::string api_version_string = layer_root_node["api_version"].asString(); + JsonVersion api_version = {}; + const int num_fields = sscanf(api_version_string.c_str(), "%u.%u", &api_version.major, &api_version.minor); + api_version.patch = 0; + + if ((num_fields != 2) || (api_version.major == 0 && api_version.minor == 0) || + api_version.major > XR_VERSION_MAJOR(XR_CURRENT_API_VERSION)) { + error_ss << "layer " << filename << " has invalid API Version. Skipping layer."; + LoaderLogger::LogWarningMessage("", error_ss.str()); + return; + } + + char *end_ptr; + uint32_t implementation_version = strtol(layer_root_node["implementation_version"].asString().c_str(), &end_ptr, 10); + if (*end_ptr != '\0') { + error_ss << "layer " << filename << " has invalid implementation version."; + LoaderLogger::LogWarningMessage("", error_ss.str()); + } + + std::string library_path = layer_root_node["library_path"].asString(); + + // If the library_path variable has no directory symbol, it's just a file name and should be accessible on the + // global library path. + if (library_path.find('\\') != std::string::npos || library_path.find('/') != std::string::npos) { + // If the library_path is an absolute path, just use that if it exists + if (FileSysUtilsIsAbsolutePath(library_path)) { + if (!FileSysUtilsPathExists(library_path)) { + error_ss << filename << " library " << library_path << " does not appear to exist"; + LoaderLogger::LogErrorMessage("", error_ss.str()); + return; + } + } else { + // Otherwise, treat the library path as a relative path based on the JSON file. + std::string combined_path; + std::string file_parent; + if (!FileSysUtilsGetParentPath(filename, file_parent) || + !FileSysUtilsCombinePaths(file_parent, library_path, combined_path) || !FileSysUtilsPathExists(combined_path)) { + error_ss << filename << " library " << combined_path << " does not appear to exist"; + LoaderLogger::LogErrorMessage("", error_ss.str()); + return; + } + library_path = combined_path; + } + } + + std::string description; + if (!layer_root_node["description"].isNull() && layer_root_node["description"].isString()) { + description = layer_root_node["description"].asString(); + } + + // Add this layer manifest file + manifest_files.emplace_back( + new ApiLayerManifestFile(type, filename, layer_name, description, api_version, implementation_version, library_path)); + + // Add any extensions to it after the fact. + // Handle any renamed functions + manifest_files.back()->ParseCommon(layer_root_node); +} + void ApiLayerManifestFile::CreateIfValid(ManifestFileType type, const std::string &filename, std::istream &json_stream, LibraryLocator locate_library, std::vector> &manifest_files) { @@ -868,6 +982,7 @@ void ApiLayerManifestFile::CreateIfValid(ManifestFileType type, const std::strin new ApiLayerManifestFile(type, filename, layer_name, description, api_version, implementation_version, library_path)); // Add any extensions to it after the fact. + // Handle any renamed functions manifest_files.back()->ParseCommon(layer_root_node); } @@ -975,5 +1090,19 @@ XrResult ApiLayerManifestFile::FindManifestFiles(ManifestFileType type, ApiLayerManifestFile::AddManifestFilesAndroid(type, manifest_files); #endif // XR_USE_PLATFORM_ANDROID +#if defined(XR_KHR_LOADER_INIT_SUPPORT) + std::vector virtualManifests; + std::string layerType = (type == ManifestFileType::MANIFEST_TYPE_IMPLICIT_API_LAYER) ? "implicit" : "explicit"; + XrResult result = GetPlatformApiLayerVirtualManifests(layerType, virtualManifests); + if (XR_SUCCESS == result) { + for (int i = 0; i < virtualManifests.size(); ++i) { + ApiLayerManifestFile::CreateIfValid(type, virtualManifests[i], "virtual manifest", manifest_files); + } + } else { + LoaderLogger::LogErrorMessage("", "ApiLayerManifestFile::FindManifestFiles - faile to get virtual manifest files."); + assert(0); + } +#endif // XR_KHR_LOADER_INIT_SUPPORT + return XR_SUCCESS; } diff --git a/src/loader/manifest_file.hpp b/src/loader/manifest_file.hpp index 46b842c6..b1c04655 100644 --- a/src/loader/manifest_file.hpp +++ b/src/loader/manifest_file.hpp @@ -99,6 +99,8 @@ class ApiLayerManifestFile : public ManifestFile { static void CreateIfValid(ManifestFileType type, const std::string &filename, std::istream &json_stream, LibraryLocator locate_library, std::vector> &manifest_files); + static void CreateIfValid(ManifestFileType type, const Json::Value &root_node, const std::string &filename, + std::vector> &manifest_files); static void CreateIfValid(ManifestFileType type, const std::string &filename, std::vector> &manifest_files); /// @return false if we could not find the library. diff --git a/src/loader/runtime_interface.cpp b/src/loader/runtime_interface.cpp index 8312b15b..3aade3ff 100644 --- a/src/loader/runtime_interface.cpp +++ b/src/loader/runtime_interface.cpp @@ -139,8 +139,6 @@ std::string GetAndroidNativeLibraryDir() { return LoaderInitData::instance()._na void* Android_Get_Asset_Manager() { return LoaderInitData::instance()._android_asset_manager; } -#endif // XR_KHR_LOADER_INIT_SUPPORT - #ifdef XR_USE_PLATFORM_ANDROID XrResult GetPlatformRuntimeVirtualManifest(Json::Value& out_manifest) { using wrap::android::content::Context; @@ -159,8 +157,29 @@ XrResult GetPlatformRuntimeVirtualManifest(Json::Value& out_manifest) { out_manifest = virtualManifest; return XR_SUCCESS; } + +XrResult GetPlatformApiLayerVirtualManifests(std::string type, std::vector& out_manifest) { + using wrap::android::content::Context; + auto& initData = LoaderInitData::instance(); + if (!initData.initialized()) { + return XR_ERROR_INITIALIZATION_FAILED; + } + auto context = Context(reinterpret_cast(initData.getData().applicationContext)); + if (context.isNull()) { + return XR_ERROR_INITIALIZATION_FAILED; + } + std::vector virtualManifests; + if (0 != openxr_android::getApiLayerVirtualManifests(type, context, virtualManifests)) { + return XR_ERROR_INITIALIZATION_FAILED; + } + out_manifest = virtualManifests; + return XR_SUCCESS; +} + #endif // XR_USE_PLATFORM_ANDROID +#endif // XR_KHR_LOADER_INIT_SUPPORT + XrResult RuntimeInterface::TryLoadingSingleRuntime(const std::string& openxr_command, std::unique_ptr& manifest_file) { LoaderPlatformLibraryHandle runtime_library = LoaderPlatformLibraryOpen(manifest_file->LibraryPath()); diff --git a/src/loader/runtime_interface.hpp b/src/loader/runtime_interface.hpp index 8d55ec67..3bc159db 100644 --- a/src/loader/runtime_interface.hpp +++ b/src/loader/runtime_interface.hpp @@ -31,6 +31,7 @@ class Value; //! Initialize loader, where required. XrResult InitializeLoader(const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo); XrResult GetPlatformRuntimeVirtualManifest(Json::Value& out_manifest); +XrResult GetPlatformApiLayerVirtualManifests(std::string type, std::vector& out_manifest); std::string GetAndroidNativeLibraryDir(); void* Android_Get_Asset_Manager(); #endif