Skip to content

Commit e83f35e

Browse files
quic-dengkailrpavlik
authored andcommitted
OpenXR loader: add helpers for API layer broker discovery
1 parent 4dd29bc commit e83f35e

File tree

2 files changed

+282
-0
lines changed

2 files changed

+282
-0
lines changed

src/loader/android_utilities.cpp

Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,12 @@ constexpr auto SYSTEM_AUTHORITY = "org.khronos.openxr.system_runtime_broker";
3636
constexpr auto BASE_PATH = "openxr";
3737
constexpr auto ABI_PATH = "abi";
3838
constexpr auto RUNTIMES_PATH = "runtimes";
39+
constexpr auto API_LAYERS_PATH = "api_layers";
40+
constexpr auto IMP_LAYER = "implicit";
41+
constexpr auto EXP_LAYER = "explicit";
3942

4043
constexpr const char *getBrokerAuthority(bool systemBroker) { return systemBroker ? SYSTEM_AUTHORITY : AUTHORITY; }
44+
constexpr const char *getLayerTypePath(bool implicitLayer) { return implicitLayer ? IMP_LAYER : EXP_LAYER; }
4145

4246
struct BaseColumns {
4347
/**
@@ -148,6 +152,33 @@ static Uri makeRuntimeContentUri(bool systemBroker, int majorVersion, std::strin
148152
return builder.build();
149153
}
150154

155+
/**
156+
* Create a content URI for querying all rows of the API Layer function remapping data for a given
157+
* runtime package, major version of OpenXR, and layer name,
158+
*
159+
* @param systemBroker If the system runtime broker (instead of the installable one) should be queried.
160+
* @param majorVer The major version of OpenXR.
161+
* @param packageName The package name of the runtime.
162+
* @param abi The Android ABI name in use.
163+
* @param layerName The name of the API layer.
164+
* @return A content URI for the entire table: the function remapping for that runtime and layer.
165+
*/
166+
static Uri makeLayerContentUri(bool systemBroker, int majorVersion, std::string const &packageName, const char *abi,
167+
std::string const &layerName) {
168+
auto builder = Uri_Builder::construct();
169+
builder.scheme("content")
170+
.authority(getBrokerAuthority(systemBroker))
171+
.appendPath(BASE_PATH)
172+
.appendPath(std::to_string(majorVersion))
173+
.appendPath(ABI_PATH)
174+
.appendPath(abi)
175+
.appendPath(API_LAYERS_PATH)
176+
.appendPath(packageName)
177+
.appendPath(layerName)
178+
.appendPath(TABLE_PATH);
179+
return builder.build();
180+
}
181+
151182
struct Columns : BaseColumns {
152183
/**
153184
* Constant for the FUNCTION_NAME column name
@@ -161,6 +192,94 @@ struct Columns : BaseColumns {
161192
};
162193
} // namespace functions
163194

195+
namespace instance_extensions {
196+
/**
197+
* Final path component to this URI.
198+
*/
199+
static constexpr auto TABLE_PATH = "instance_extensions";
200+
201+
/**
202+
* Create a content URI for querying all rows of the instance extensions supported by a given
203+
* API layer.
204+
*
205+
* @param systemBroker If the system runtime broker (instead of the installable one) should be queried.
206+
* @param majorVer The major version of OpenXR.
207+
* @param packageName The package name of the runtime.
208+
* @param abi The Android ABI name in use.
209+
* @param layerName The API layer name.
210+
* @return A content URI for the entire table: the function remapping for that runtime.
211+
*/
212+
static Uri makeContentUri(bool systemBroker, int majorVersion, std::string const &packageName, const char *abi,
213+
std::string const &layerName) {
214+
auto builder = Uri_Builder::construct();
215+
builder.scheme("content")
216+
.authority(getBrokerAuthority(systemBroker))
217+
.appendPath(BASE_PATH)
218+
.appendPath(std::to_string(majorVersion))
219+
.appendPath(ABI_PATH)
220+
.appendPath(abi)
221+
.appendPath(API_LAYERS_PATH)
222+
.appendPath(packageName)
223+
.appendPath(layerName)
224+
.appendPath(TABLE_PATH);
225+
return builder.build();
226+
}
227+
struct Columns : BaseColumns {
228+
/**
229+
* Constant for the INSTANCE_EXTENSION_NAMES column name
230+
*/
231+
static constexpr auto INSTANCE_EXTENSION_NAMES = "instance_extension_names";
232+
233+
/**
234+
* Constant for the INSTANCE_EXTENSION_VERSIONS column name
235+
*/
236+
static constexpr auto INSTANCE_EXTENSION_VERSIONS = "instance_extension_versions";
237+
};
238+
} // namespace instance_extensions
239+
240+
namespace api_layer {
241+
242+
/**
243+
* Create a content URI for querying all rows of the implicit/explicit API layer data for a given
244+
* runtime package and major version of OpenXR.
245+
*
246+
* @param systemBroker If the system runtime broker (instead of the installable one) should be queried.
247+
* @param majorVer The major version of OpenXR.
248+
* @param layerType The layer type of the API layer.
249+
* @param abi The Android ABI name in use.
250+
* @return A content URI for the entire table: the API layers for that runtime.
251+
*/
252+
static Uri makeContentUri(bool systemBroker, int majorVersion, std::string const &layerType, const char *abi) {
253+
auto builder = Uri_Builder::construct();
254+
builder.scheme("content")
255+
.authority(getBrokerAuthority(systemBroker))
256+
.appendPath(BASE_PATH)
257+
.appendPath(std::to_string(majorVersion))
258+
.appendPath(ABI_PATH)
259+
.appendPath(abi)
260+
.appendPath(API_LAYERS_PATH)
261+
.appendPath(getLayerTypePath(layerType == IMP_LAYER));
262+
return builder.build();
263+
}
264+
struct Columns : BaseColumns {
265+
// implicit or explicit
266+
static constexpr auto PACKAGE_NAME = "package_name";
267+
static constexpr auto FILE_FORMAT_VERSION = "file_format_version";
268+
static constexpr auto NAME = "name";
269+
static constexpr auto NATIVE_LIB_DIR = "native_lib_dir";
270+
static constexpr auto SO_FILENAME = "so_filename";
271+
static constexpr auto API_VERSION = "api_version";
272+
static constexpr auto IMPLEMENTATION_VERSION = "implementation_version";
273+
static constexpr auto DESCRIPTION = "description";
274+
static constexpr auto DISABLE_ENVIRONMENT = "disable_environment";
275+
static constexpr auto ENABLE_ENVIRONMENT = "enable_environment";
276+
static constexpr auto DISABLE_SYS_PROP = "disable_sys_prop";
277+
static constexpr auto ENABLE_SYS_PROP = "enable_sys_prop";
278+
static constexpr auto HAS_FUNCTIONS = "has_functions";
279+
static constexpr auto HAS_INSTANCE_EXTENSIONS = "has_instance_extensions";
280+
};
281+
} // namespace api_layer
282+
164283
} // namespace
165284

166285
static inline jni::Array<std::string> makeArray(std::initializer_list<const char *> &&list) {
@@ -332,6 +451,157 @@ int getActiveRuntimeVirtualManifest(wrap::android::content::Context const &conte
332451
cursor.close();
333452
return -1;
334453
}
454+
455+
static int populateApiLayerFunctions(wrap::android::content::Context const &context, bool systemBroker,
456+
const std::string &packageName, std::string const &layerName, Json::Value &rootNode) {
457+
const jni::Array<std::string> projection = makeArray({functions::Columns::FUNCTION_NAME, functions::Columns::SYMBOL_NAME});
458+
459+
auto uri = functions::makeLayerContentUri(systemBroker, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), packageName, ABI, layerName);
460+
ALOGI("populateApiLayerFunctions: Querying URI: %s", uri.toString().c_str());
461+
462+
Cursor cursor;
463+
if (!getCursor(context, projection, uri, systemBroker, "API layer functions", cursor)) {
464+
return -1;
465+
}
466+
467+
auto functionIndex = cursor.getColumnIndex(functions::Columns::FUNCTION_NAME);
468+
auto symbolIndex = cursor.getColumnIndex(functions::Columns::SYMBOL_NAME);
469+
while (cursor.moveToNext()) {
470+
rootNode["api_layer"]["functions"][cursor.getString(functionIndex)] = cursor.getString(symbolIndex);
471+
}
472+
473+
cursor.close();
474+
return 0;
475+
}
476+
477+
static int populateApiLayerInstanceExtensions(wrap::android::content::Context const &context, bool systemBroker,
478+
const std::string &packageName, std::string const &layerName, Json::Value &rootNode) {
479+
const jni::Array<std::string> projection = makeArray(
480+
{instance_extensions::Columns::INSTANCE_EXTENSION_NAMES, instance_extensions::Columns::INSTANCE_EXTENSION_VERSIONS});
481+
482+
auto uri =
483+
instance_extensions::makeContentUri(systemBroker, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), packageName, ABI, layerName);
484+
ALOGI("populateApiLayerInstanceExtensions: Querying URI: %s", uri.toString().c_str());
485+
486+
Cursor cursor;
487+
if (!getCursor(context, projection, uri, systemBroker, "API layer instance extensions", cursor)) {
488+
return -1;
489+
}
490+
491+
auto nameIndex = cursor.getColumnIndex(instance_extensions::Columns::INSTANCE_EXTENSION_NAMES);
492+
auto versionIndex = cursor.getColumnIndex(instance_extensions::Columns::INSTANCE_EXTENSION_VERSIONS);
493+
Json::Value extension(Json::objectValue);
494+
while (cursor.moveToNext()) {
495+
extension["name"] = cursor.getString(nameIndex);
496+
extension["extension_version"] = cursor.getString(versionIndex);
497+
rootNode["api_layer"]["instance_extensions"].append(extension);
498+
}
499+
500+
cursor.close();
501+
return 0;
502+
}
503+
504+
/// Get cursor for API layers, parameterized by whether or not we use the system broker
505+
static bool getApiLayerCursor(wrap::android::content::Context const &context, jni::Array<std::string> const &projection,
506+
std::string const &targetType, bool systemBroker, Cursor &cursor) {
507+
auto uri = api_layer::makeContentUri(systemBroker, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), targetType, ABI);
508+
ALOGI("getApiLayerCursor: Querying URI: %s", uri.toString().c_str());
509+
return getCursor(context, projection, uri, systemBroker, "API Layer", cursor);
510+
}
511+
512+
static Json::Value makeApiLayerManifest(bool systemBroker, std::string layerType, wrap::android::content::Context const &context,
513+
Cursor &cursor) {
514+
auto packageName = cursor.getString(cursor.getColumnIndex(api_layer::Columns::PACKAGE_NAME));
515+
auto fileFormatVersion = cursor.getString(cursor.getColumnIndex(api_layer::Columns::FILE_FORMAT_VERSION));
516+
auto name = cursor.getString(cursor.getColumnIndex(api_layer::Columns::NAME));
517+
auto libDir = cursor.getString(cursor.getColumnIndex(active_runtime::Columns::NATIVE_LIB_DIR));
518+
auto fileName = cursor.getString(cursor.getColumnIndex(api_layer::Columns::SO_FILENAME));
519+
auto apiVersion = cursor.getString(cursor.getColumnIndex(api_layer::Columns::API_VERSION));
520+
auto implementationVersion = cursor.getString(cursor.getColumnIndex(api_layer::Columns::IMPLEMENTATION_VERSION));
521+
auto description = cursor.getString(cursor.getColumnIndex(api_layer::Columns::DESCRIPTION));
522+
auto disable_environment = cursor.getString(cursor.getColumnIndex(api_layer::Columns::DISABLE_ENVIRONMENT));
523+
auto enable_environment = cursor.getString(cursor.getColumnIndex(api_layer::Columns::ENABLE_ENVIRONMENT));
524+
auto disable_sys_prop = cursor.getString(cursor.getColumnIndex(api_layer::Columns::DISABLE_SYS_PROP));
525+
auto enable_sys_prop = cursor.getString(cursor.getColumnIndex(api_layer::Columns::ENABLE_SYS_PROP));
526+
auto has_instance_extensions = cursor.getString(cursor.getColumnIndex(api_layer::Columns::HAS_INSTANCE_EXTENSIONS));
527+
auto has_functions = cursor.getString(cursor.getColumnIndex(api_layer::Columns::HAS_FUNCTIONS));
528+
529+
ALOGI("Got api layer: type: %s, name: %s, native lib dir: %s, fileName: %s", layerType.c_str(), name.c_str(), libDir.c_str(),
530+
fileName.c_str());
531+
532+
Json::Value rootNode(Json::objectValue);
533+
rootNode["file_format_version"] = fileFormatVersion;
534+
rootNode["api_layer"] = Json::objectValue;
535+
rootNode["api_layer"]["name"] = name;
536+
rootNode["api_layer"]["library_path"] = libDir + "/" + fileName;
537+
rootNode["api_layer"]["api_version"] = apiVersion;
538+
rootNode["api_layer"]["implementation_version"] = implementationVersion;
539+
rootNode["api_layer"]["description"] = description;
540+
rootNode["api_layer"]["disable_environment"] = disable_environment;
541+
rootNode["api_layer"]["enable_environment"] = enable_environment;
542+
rootNode["api_layer"]["disable_sys_prop"] = disable_sys_prop;
543+
rootNode["api_layer"]["enable_sys_prop"] = enable_sys_prop;
544+
if (has_functions == "true") {
545+
rootNode["api_layer"]["functions"] = Json::Value(Json::objectValue);
546+
populateApiLayerFunctions(context, systemBroker, packageName, name, rootNode);
547+
}
548+
if (has_instance_extensions == "true") {
549+
rootNode["api_layer"]["instance_extensions"] = Json::Value(Json::arrayValue);
550+
populateApiLayerInstanceExtensions(context, systemBroker, packageName, name, rootNode);
551+
}
552+
553+
return rootNode;
554+
}
555+
556+
static int enumerateApiLayerManifests(std::string layerType, wrap::android::content::Context const &context,
557+
const jni::Array<std::string> &projection, std::vector<Json::Value> &virtualManifests,
558+
bool systemBroker) {
559+
Cursor cursor;
560+
561+
if (!getApiLayerCursor(context, projection, layerType, systemBroker, cursor)) {
562+
return -1;
563+
}
564+
565+
cursor.moveToFirst();
566+
const int32_t n = cursor.getCount();
567+
virtualManifests.reserve(virtualManifests.size() + n);
568+
569+
for (int32_t i = 0; i < n; ++i) {
570+
virtualManifests.emplace_back(makeApiLayerManifest(systemBroker, layerType, context, cursor));
571+
cursor.moveToNext();
572+
}
573+
574+
cursor.close();
575+
return 0;
576+
}
577+
578+
int getApiLayerVirtualManifests(std::string layerType, wrap::android::content::Context const &context,
579+
std::vector<Json::Value> &virtualManifests, bool systemBroker) {
580+
ALOGI("Try to get %s API layer from broker", layerType.c_str());
581+
const jni::Array<std::string> projection = makeArray(
582+
{api_layer::Columns::PACKAGE_NAME, api_layer::Columns::FILE_FORMAT_VERSION, api_layer::Columns::NAME,
583+
api_layer::Columns::NATIVE_LIB_DIR, api_layer::Columns::SO_FILENAME, api_layer::Columns::API_VERSION,
584+
api_layer::Columns::IMPLEMENTATION_VERSION, api_layer::Columns::DESCRIPTION, api_layer::Columns::DISABLE_ENVIRONMENT,
585+
api_layer::Columns::ENABLE_ENVIRONMENT, api_layer::Columns::DISABLE_SYS_PROP, api_layer::Columns::ENABLE_SYS_PROP,
586+
api_layer::Columns::HAS_FUNCTIONS, api_layer::Columns::HAS_INSTANCE_EXTENSIONS});
587+
588+
if (layerType == IMP_LAYER) {
589+
std::vector<Json::Value> implicitLayerManifest;
590+
if (0 != enumerateApiLayerManifests(IMP_LAYER, context, projection, implicitLayerManifest, systemBroker)) {
591+
return -1;
592+
}
593+
virtualManifests = std::move(implicitLayerManifest);
594+
} else {
595+
std::vector<Json::Value> explicitLayerManifest;
596+
if (0 != enumerateApiLayerManifests(EXP_LAYER, context, projection, explicitLayerManifest, systemBroker)) {
597+
return -1;
598+
}
599+
virtualManifests = std::move(explicitLayerManifest);
600+
}
601+
602+
return 0;
603+
}
604+
335605
} // namespace openxr_android
336606

337607
#endif // __ANDROID__

src/loader/android_utilities.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,18 @@ using wrap::android::content::Context;
2828
*/
2929
int getActiveRuntimeVirtualManifest(wrap::android::content::Context const &context, Json::Value &virtualManifest,
3030
bool &systemBroker);
31+
32+
/*!
33+
* Find the implicit/explicit API layers on the system, and return a constructed JSON object representing it.
34+
*
35+
* @param type An String to indicate layer type of API layers, implicit or explicit.
36+
* @param context An Android context, preferably an Activity Context.
37+
* @param[out] virtualManifest The Json::Value to fill with the virtual manifest.
38+
*
39+
* @return 0 on success, something else on failure.
40+
*/
41+
int getApiLayerVirtualManifests(std::string layerType, wrap::android::content::Context const &context,
42+
std::vector<Json::Value> &virtualManifests, bool systemBroker);
3143
} // namespace openxr_android
3244

3345
#endif // __ANDROID__

0 commit comments

Comments
 (0)