Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions changes/sdk/mr.3475.gl.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
- pr.413.gh.OpenXR-SDK-Source
---
Improvement: Loader: Code cleanup and robustness improvements.
10 changes: 10 additions & 0 deletions src/common/platform_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,16 @@ static inline std::string PlatformUtilsGetSecureEnv(const char* /* name */) {
return {};
}

static inline bool PlatformUtilsGetBoolSysProp(const char* name, bool default_value) {
bool result = default_value;
char value[PROP_VALUE_MAX] = {};
if (__system_property_get(name, value) != 0) {
result = (value[0] == 't');
}

return result;
}

// Intended to be only used as a fallback on Android, with a more open, "native" technique used in most cases
static inline bool PlatformGetGlobalRuntimeFileName(uint16_t major_version, std::string& file_name) {
// Prefix for the runtime JSON file name
Expand Down
489 changes: 376 additions & 113 deletions src/loader/android_utilities.cpp

Large diffs are not rendered by default.

15 changes: 14 additions & 1 deletion src/loader/android_utilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,20 @@ using wrap::android::content::Context;
*
* @return 0 on success, something else on failure.
*/
int getActiveRuntimeVirtualManifest(wrap::android::content::Context const &context, Json::Value &virtualManifest);
int getActiveRuntimeVirtualManifest(wrap::android::content::Context const &context, Json::Value &virtualManifest,
bool &systemBroker);

/*!
* 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<Json::Value> &virtualManifests, bool systemBroker);
} // namespace openxr_android

#endif // __ANDROID__
7 changes: 4 additions & 3 deletions src/loader/api_layer_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -422,9 +422,10 @@ XrResult ApiLayerInterface::LoadApiLayers(const std::string& openxr_command, uin
}

// Add this API layer to the vector
api_layer_interfaces.emplace_back(new ApiLayerInterface(manifest_file->LayerName(), layer_library, supported_extensions,
api_layer_info.getInstanceProcAddr,
api_layer_info.createApiLayerInstance));
std::unique_ptr<ApiLayerInterface> iface{new ApiLayerInterface(manifest_file->LayerName(), layer_library,
supported_extensions, api_layer_info.getInstanceProcAddr,
api_layer_info.createApiLayerInstance)};
api_layer_interfaces.emplace_back(std::move(iface));

// If we load one, clear all errors.
any_loaded = true;
Expand Down
9 changes: 8 additions & 1 deletion src/loader/loader_init_data.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <json/value.h>
#include <android/asset_manager_jni.h>
#include "android_utilities.h"
#include "manifest_file.hpp"
#endif // XR_USE_PLATFORM_ANDROID

#ifdef XR_KHR_LOADER_INIT_SUPPORT
Expand Down Expand Up @@ -84,7 +85,13 @@ class LoaderInitData {
XrResult InitializeLoaderInitData(const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo);

#ifdef XR_USE_PLATFORM_ANDROID
XrResult GetPlatformRuntimeVirtualManifest(Json::Value& out_manifest);

//! Modifies @p out_manifest and @p out_runtime_source only if returning successfully
XrResult GetPlatformRuntimeVirtualManifest(Json::Value& out_manifest, ManifestFileSource& out_runtime_source);

//! Modifies @p out_manifest only if returning successfully
XrResult GetPlatformApiLayerVirtualManifests(bool is_implicit, bool system_broker, std::vector<Json::Value>& out_manifest);

std::string GetAndroidNativeLibraryDir();
void* Android_Get_Asset_Manager();
#endif // XR_USE_PLATFORM_ANDROID
Expand Down
168 changes: 141 additions & 27 deletions src/loader/manifest_file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -638,10 +638,10 @@ void RuntimeManifestFile::CreateIfValid(const Json::Value &root_node, const std:
}

// Add this runtime manifest file
manifest_files.emplace_back(new RuntimeManifestFile(filename, lib_path));
std::unique_ptr<RuntimeManifestFile> manifest{new RuntimeManifestFile(filename, lib_path)};
manifest_files.emplace_back(std::move(manifest));

// Add any extensions to it after the fact.
// Handle any renamed functions
// Add any extensions to it after the fact, while handling any renamed functions
manifest_files.back()->ParseCommon(runtime_root_node);
}

Expand Down Expand Up @@ -682,7 +682,8 @@ XrResult RuntimeManifestFile::FindManifestFiles(const std::string &openxr_comman

#if defined(XR_KHR_LOADER_INIT_SUPPORT) && defined(XR_USE_PLATFORM_ANDROID)
Json::Value virtualManifest;
result = GetPlatformRuntimeVirtualManifest(virtualManifest);
ManifestFileSource runtimeSource = ManifestFileSource::FROM_JSON_MANIFEST;
result = GetPlatformRuntimeVirtualManifest(virtualManifest, runtimeSource);
if (XR_SUCCESS == result) {
RuntimeManifestFile::CreateIfValid(virtualManifest, "", manifest_files);
return result;
Expand Down Expand Up @@ -778,22 +779,10 @@ void ApiLayerManifestFile::AddManifestFilesAndroid(const std::string &openxr_com
}
#endif // defined(XR_USE_PLATFORM_ANDROID) && defined(XR_KHR_LOADER_INIT_SUPPORT)

void ApiLayerManifestFile::CreateIfValid(ManifestFileType type, const std::string &filename, std::istream &json_stream,
void ApiLayerManifestFile::CreateIfValid(ManifestFileType type, const std::string &filename, const Json::Value &root_node,
LibraryLocator locate_library,
std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files) {
std::ostringstream error_ss("ApiLayerManifestFile::CreateIfValid ");
Json::CharReaderBuilder builder;
std::string errors;
Json::Value root_node = Json::nullValue;
if (!Json::parseFromStream(builder, json_stream, &root_node, &errors) || !root_node.isObject()) {
error_ss << "failed to parse " << filename << ".";
if (!errors.empty()) {
error_ss << " (Error message: " << errors << ")";
}
error_ss << " Is it a valid layer manifest file?";
LoaderLogger::LogErrorMessage("", error_ss.str());
return;
}
JsonVersion file_version = {};
if (!ManifestFile::IsValidJson(root_node, file_version)) {
error_ss << "isValidJson indicates " << filename << " is not a valid manifest file.";
Expand All @@ -813,29 +802,72 @@ void ApiLayerManifestFile::CreateIfValid(ManifestFileType type, const std::strin
LoaderLogger::LogErrorMessage("", error_ss.str());
return;
}

// Figure out enabled state of implicit layers
if (MANIFEST_TYPE_IMPLICIT_API_LAYER == type) {
bool enabled = true;
// Implicit layers require the disable environment variable.
if (layer_root_node["disable_environment"].isNull() || !layer_root_node["disable_environment"].isString()) {
auto &disable_env_node = layer_root_node["disable_environment"];
if (disable_env_node.isNull() || !disable_env_node.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();
// Check if there's an enable environment variable provided: If so, it must be set in the environment.
auto &enable_env_node = layer_root_node["enable_environment"];
if (!enable_env_node.isNull() && enable_env_node.isString()) {
std::string env_var = enable_env_node.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();
std::string env_var = disable_env_node.asString();
// If the env var is set, disable the layer. Disable env var overrides enable above
if (PlatformUtilsGetEnvSet(env_var.c_str())) {
enabled = false;
}

#if defined(XR_OS_ANDROID)

// Implicit layers require the disable system property on Android.
auto &disable_prop_node = layer_root_node["disable_sys_prop"];
if (disable_prop_node.isNull() || !disable_prop_node.isString()) {
error_ss << "Implicit layer " << filename << " is missing \"disable_sys_prop\"";
LoaderLogger::LogErrorMessage("", error_ss.str());
return;
}

// Check if there's an system property to enable this API layer
auto &enable_prop_node = layer_root_node["enable_sys_prop"];
if (!enable_prop_node.isNull() && enable_prop_node.isString()) {
std::string enable_sys_prop = enable_prop_node.asString();
if (enable_sys_prop.empty()) {
error_ss << "Implicit layer " << filename << " has a present but empty \"enable_sys_prop\"";
LoaderLogger::LogErrorMessage("", error_ss.str());
return;
}
// TODO other validation on the enable_sys_prop?
// If it's not set to true, disable this layer
if (!PlatformUtilsGetBoolSysProp(enable_sys_prop.c_str(), true)) {
enabled = false;
}
}

std::string disable_sys_prop = disable_prop_node.asString();
if (disable_sys_prop.empty()) {
error_ss << "Implicit layer " << filename << " has a present but empty \"disable_sys_prop\"";
LoaderLogger::LogErrorMessage("", error_ss.str());
return;
}
// TODO other validation on the disable_sys_prop?
if (PlatformUtilsGetBoolSysProp(disable_sys_prop.c_str(), false)) {
enabled = false;
}
#endif

// Not enabled, so pretend like it isn't even there.
if (!enabled) {
error_ss << "Implicit layer " << filename << " is disabled";
Expand All @@ -856,7 +888,16 @@ void ApiLayerManifestFile::CreateIfValid(ManifestFileType type, const std::strin
return;
}

uint32_t implementation_version = atoi(layer_root_node["implementation_version"].asString().c_str());
uint32_t implementation_version = 0;
{
char *end_ptr;
implementation_version = strtol(layer_root_node["implementation_version"].asString().c_str(), &end_ptr, 10);
if (*end_ptr != '\0') {
std::ostringstream oss(error_ss.str());
oss << "layer " << filename << " has invalid implementation version.";
LoaderLogger::LogWarningMessage("", oss.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
Expand Down Expand Up @@ -887,13 +928,34 @@ void ApiLayerManifestFile::CreateIfValid(ManifestFileType type, const std::strin
}

// Add this layer manifest file
manifest_files.emplace_back(
new ApiLayerManifestFile(type, filename, layer_name, description, api_version, implementation_version, library_path));
std::unique_ptr<ApiLayerManifestFile> manifest{
new ApiLayerManifestFile(type, filename, layer_name, description, api_version, implementation_version, library_path)};
manifest_files.emplace_back(std::move(manifest));

// Add any extensions to it after the fact.
// Add any extensions to it after the fact, while handling 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<std::unique_ptr<ApiLayerManifestFile>> &manifest_files) {
std::ostringstream error_ss("ApiLayerManifestFile::CreateIfValid ");
Json::CharReaderBuilder builder;
std::string errors;
Json::Value root_node = Json::nullValue;
if (!Json::parseFromStream(builder, json_stream, &root_node, &errors) || !root_node.isObject()) {
error_ss << "failed to parse " << filename << ".";
if (!errors.empty()) {
error_ss << " (Error message: " << errors << ")";
}
error_ss << " Is it a valid layer manifest file?";
LoaderLogger::LogErrorMessage("", error_ss.str());
return;
}

CreateIfValid(type, filename, root_node, locate_library, manifest_files);
}

void ApiLayerManifestFile::CreateIfValid(ManifestFileType type, const std::string &filename,
std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files) {
std::ifstream json_stream(filename, std::ifstream::in);
Expand Down Expand Up @@ -950,6 +1012,24 @@ void ApiLayerManifestFile::PopulateApiLayerProperties(XrApiLayerProperties &prop
// Find all layer manifest files in the appropriate search paths/registries for the given type.
XrResult ApiLayerManifestFile::FindManifestFiles(const std::string &openxr_command, ManifestFileType type,
std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files) {
bool search_json_layer = true;
bool search_broker_layer = true;

#if defined(XR_KHR_LOADER_INIT_SUPPORT) && defined(XR_USE_PLATFORM_ANDROID)
Json::Value virtual_manifest;
bool system_broker = true;
ManifestFileSource runtime_source = ManifestFileSource::FROM_JSON_MANIFEST;
XrResult result = GetPlatformRuntimeVirtualManifest(virtual_manifest, runtime_source);
if (XR_SUCCESS == result) {
if (runtime_source == ManifestFileSource::FROM_INSTALLABLE_BROKER) {
system_broker = false;
search_json_layer = false;
}
} else {
search_broker_layer = false;
}
#endif // defined(XR_USE_PLATFORM_ANDROID) && defined(XR_KHR_LOADER_INIT_SUPPORT)

std::string relative_path;
std::string override_env_var;
std::string registry_location;
Expand Down Expand Up @@ -982,7 +1062,9 @@ XrResult ApiLayerManifestFile::FindManifestFiles(const std::string &openxr_comma

bool override_active = false;
std::vector<std::string> filenames;
ReadDataFilesInSearchPaths(override_env_var, relative_path, override_active, filenames);
if (search_json_layer) {
ReadDataFilesInSearchPaths(override_env_var, relative_path, override_active, filenames);
}

#ifdef XR_OS_WINDOWS
// Read the registry if the override wasn't active.
Expand All @@ -996,6 +1078,38 @@ XrResult ApiLayerManifestFile::FindManifestFiles(const std::string &openxr_comma
}

#if defined(XR_KHR_LOADER_INIT_SUPPORT) && defined(XR_USE_PLATFORM_ANDROID)
if (search_broker_layer) {
std::vector<Json::Value> virtual_manifests;
result = GetPlatformApiLayerVirtualManifests(type == ManifestFileType::MANIFEST_TYPE_IMPLICIT_API_LAYER, system_broker,
virtual_manifests);
if (XR_SUCCESS == result) {
std::string fnBase;
{
std::ostringstream oss{"_virtualManifest_"};
if (system_broker) {
oss << "systemBroker_";
} else {
oss << "installableBroker_";
}
if (type == ManifestFileType::MANIFEST_TYPE_IMPLICIT_API_LAYER) {
oss << "implicit.json";
} else {
oss << "explicit.json";
}
fnBase = oss.str();
}
const size_t n = virtual_manifests.size();
for (size_t i = 0; i < n; ++i) {
ApiLayerManifestFile::CreateIfValid(type, std::to_string(i) + fnBase, virtual_manifests[i],
&ApiLayerManifestFile::LocateLibraryInAssets, manifest_files);
}
} else {
LoaderLogger::LogInfoMessage(openxr_command,
"ApiLayerManifestFile::FindManifestFiles - failed to get virtual manifest files from "
"system/installable broker, likely not supported by current broker version.");
}
}

ApiLayerManifestFile::AddManifestFilesAndroid(openxr_command, type, manifest_files);
#endif // defined(XR_USE_PLATFORM_ANDROID) && defined(XR_KHR_LOADER_INIT_SUPPORT)

Expand Down
12 changes: 12 additions & 0 deletions src/loader/manifest_file.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@ enum ManifestFileType {
MANIFEST_TYPE_EXPLICIT_API_LAYER,
};

//! Where did the data for this manifest file (may be virtual) come from?
enum ManifestFileSource {
//! An actual json file on a file system
FROM_JSON_MANIFEST = 0,
//! The installable runtime broker on Android
FROM_INSTALLABLE_BROKER,
//! The system runtime broker on Android
FROM_SYSTEM_BROKER,
};

struct JsonVersion {
uint32_t major;
uint32_t minor;
Expand Down Expand Up @@ -99,6 +109,8 @@ class ApiLayerManifestFile : public ManifestFile {
const std::string &description, const JsonVersion &api_version, const uint32_t &implementation_version,
const std::string &library_path);

static void CreateIfValid(ManifestFileType type, const std::string &filename, const Json::Value &root_node,
LibraryLocator locate_library, std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files);
static void CreateIfValid(ManifestFileType type, const std::string &filename, std::istream &json_stream,
LibraryLocator locate_library, std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files);
static void CreateIfValid(ManifestFileType type, const std::string &filename,
Expand Down
Loading