Skip to content

Commit fcaa61a

Browse files
dengkailquic-dengkail
authored andcommitted
OpenXR loader: add API layer discovery support.
1 parent 8270b15 commit fcaa61a

File tree

6 files changed

+430
-14
lines changed

6 files changed

+430
-14
lines changed

src/loader/android_utilities.cpp

Lines changed: 265 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,13 @@ constexpr auto SYSTEM_AUTHORITY = "org.khronos.openxr.system_runtime_broker";
3838
constexpr auto BASE_PATH = "openxr";
3939
constexpr auto ABI_PATH = "abi";
4040
constexpr auto RUNTIMES_PATH = "runtimes";
41+
constexpr auto API_LAYERS_PATH = "api_layers";
42+
constexpr auto IMP_LAYER = "implicit";
43+
constexpr auto EXP_LAYER = "explicit";
4144

4245
constexpr const char *getBrokerAuthority(bool systemBroker) { return systemBroker ? SYSTEM_AUTHORITY : AUTHORITY; }
46+
constexpr const char *getLayerTypePath(bool implicitLayer) { return implicitLayer ? IMP_LAYER : EXP_LAYER; }
47+
constexpr const char *getFunctionTypePath(bool runtimeFunctions) { return runtimeFunctions ? RUNTIMES_PATH : API_LAYERS_PATH; }
4348

4449
struct BaseColumns {
4550
/**
@@ -132,22 +137,27 @@ static constexpr auto TABLE_PATH = "functions";
132137
* runtime package and major version of OpenXR.
133138
*
134139
* @param systemBroker If the system runtime broker (instead of the installable one) should be queried.
140+
* @param runtimeFunctions If the runtime functions (instead of the API layer functions) should be queried.
135141
* @param majorVer The major version of OpenXR.
136142
* @param packageName The package name of the runtime.
137143
* @param abi The Android ABI name in use.
138144
* @return A content URI for the entire table: the function remapping for that runtime.
139145
*/
140-
static Uri makeContentUri(bool systemBroker, int majorVersion, std::string const &packageName, const char *abi) {
146+
static Uri makeContentUri(bool systemBroker, bool runtimeFunctions, int majorVersion, std::string const &packageName,
147+
const char *abi, std::string const &layerName) {
141148
auto builder = Uri_Builder::construct();
142149
builder.scheme("content")
143150
.authority(getBrokerAuthority(systemBroker))
144151
.appendPath(BASE_PATH)
145152
.appendPath(std::to_string(majorVersion))
146153
.appendPath(ABI_PATH)
147154
.appendPath(abi)
148-
.appendPath(RUNTIMES_PATH)
149-
.appendPath(packageName)
150-
.appendPath(TABLE_PATH);
155+
.appendPath(getFunctionTypePath(runtimeFunctions))
156+
.appendPath(packageName);
157+
if (!runtimeFunctions) {
158+
builder.appendPath(layerName);
159+
}
160+
builder.appendPath(TABLE_PATH);
151161
return builder.build();
152162
}
153163

@@ -164,6 +174,95 @@ struct Columns : BaseColumns {
164174
};
165175
} // namespace functions
166176

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

169268
static inline jni::Array<std::string> makeArray(std::initializer_list<const char *> &&list) {
@@ -221,7 +320,7 @@ static int populateFunctions(wrap::android::content::Context const &context, boo
221320
JsonManifestBuilder &builder) {
222321
jni::Array<std::string> projection = makeArray({functions::Columns::FUNCTION_NAME, functions::Columns::SYMBOL_NAME});
223322

224-
auto uri = functions::makeContentUri(systemBroker, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), packageName, ABI);
323+
auto uri = functions::makeContentUri(systemBroker, true, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), packageName, ABI, "");
225324
ALOGI("populateFunctions: Querying URI: %s", uri.toString().c_str());
226325

227326
Cursor cursor = context.getContentResolver().query(uri, projection);
@@ -245,11 +344,76 @@ static int populateFunctions(wrap::android::content::Context const &context, boo
245344
return 0;
246345
}
247346

248-
/// Get cursor for active runtime, parameterized by whether or not we use the system broker
249-
static bool getActiveRuntimeCursor(wrap::android::content::Context const &context, jni::Array<std::string> const &projection,
250-
bool systemBroker, Cursor &cursor) {
251-
auto uri = active_runtime::makeContentUri(systemBroker, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), ABI);
252-
ALOGI("getActiveRuntimeCursor: Querying URI: %s", uri.toString().c_str());
347+
static int populateApiLayerFunctions(wrap::android::content::Context const &context, bool systemBroker,
348+
const std::string &packageName, std::string const &layerName, Json::Value &rootNode) {
349+
jni::Array<std::string> projection = makeArray({functions::Columns::FUNCTION_NAME, functions::Columns::SYMBOL_NAME});
350+
351+
auto uri =
352+
functions::makeContentUri(systemBroker, false, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), packageName, ABI, layerName);
353+
ALOGI("populateApiLayerFunctions: Querying URI: %s", uri.toString().c_str());
354+
355+
Cursor cursor = context.getContentResolver().query(uri, projection);
356+
357+
if (cursor.isNull()) {
358+
ALOGE("Null cursor when querying content resolver for API layer functions.");
359+
return -1;
360+
}
361+
if (cursor.getCount() < 1) {
362+
ALOGE("Non-null but empty cursor when querying content resolver for API layer functions.");
363+
cursor.close();
364+
return -1;
365+
}
366+
auto functionIndex = cursor.getColumnIndex(functions::Columns::FUNCTION_NAME);
367+
auto symbolIndex = cursor.getColumnIndex(functions::Columns::SYMBOL_NAME);
368+
while (cursor.moveToNext()) {
369+
rootNode["api_layer"]["functions"][cursor.getString(functionIndex)] = cursor.getString(symbolIndex);
370+
ALOGE("function_name: %s, symbol_name: %s", cursor.getString(functionIndex).c_str(), cursor.getString(symbolIndex).c_str());
371+
}
372+
373+
cursor.close();
374+
return 0;
375+
}
376+
377+
static int populateApiLayerInstanceExtensions(wrap::android::content::Context const &context, bool systemBroker,
378+
const std::string &packageName, std::string const &layerName, Json::Value &rootNode) {
379+
jni::Array<std::string> projection = makeArray(
380+
{instance_extensions::Columns::INSTANCE_EXTENSION_NAMES, instance_extensions::Columns::INSTANCE_EXTENSION_VERSIONS});
381+
382+
auto uri =
383+
instance_extensions::makeContentUri(systemBroker, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), packageName, ABI, layerName);
384+
ALOGI("populateApiLayerInstanceExtensions: Querying URI: %s", uri.toString().c_str());
385+
386+
Cursor cursor = context.getContentResolver().query(uri, projection);
387+
388+
if (cursor.isNull()) {
389+
ALOGE("Null cursor when querying content resolver for API layer instance extensions.");
390+
return -1;
391+
}
392+
if (cursor.getCount() < 1) {
393+
ALOGE("Non-null but empty cursor when querying content resolver for API layer instance extensions.");
394+
cursor.close();
395+
return -1;
396+
}
397+
auto nameIndex = cursor.getColumnIndex(instance_extensions::Columns::INSTANCE_EXTENSION_NAMES);
398+
auto versionIndex = cursor.getColumnIndex(instance_extensions::Columns::INSTANCE_EXTENSION_VERSIONS);
399+
Json::Value extension(Json::objectValue);
400+
while (cursor.moveToNext()) {
401+
extension["name"] = cursor.getString(nameIndex);
402+
extension["extension_version"] = cursor.getString(versionIndex);
403+
rootNode["api_layer"]["instance_extensions"].append(extension);
404+
}
405+
406+
cursor.close();
407+
return 0;
408+
}
409+
410+
/// Get cursor for active runtime or API layer, parameterized by target type and whether or not we use the system broker
411+
static bool getCursor(wrap::android::content::Context const &context, jni::Array<std::string> const &projection,
412+
std::string const &targetType, bool systemBroker, Cursor &cursor) {
413+
auto uri = (targetType == RUNTIMES_PATH)
414+
? active_runtime::makeContentUri(systemBroker, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), ABI)
415+
: api_layer::makeContentUri(systemBroker, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), targetType, ABI);
416+
ALOGI("getCursor: Querying URI: %s", uri.toString().c_str());
253417
try {
254418
cursor = context.getContentResolver().query(uri, projection);
255419
} catch (const std::exception &e) {
@@ -272,17 +436,19 @@ static bool getActiveRuntimeCursor(wrap::android::content::Context const &contex
272436
return true;
273437
}
274438

439+
static void getRuntimePackageName(std::string packageName) { return; }
440+
275441
int getActiveRuntimeVirtualManifest(wrap::android::content::Context const &context, Json::Value &virtualManifest) {
276442
jni::Array<std::string> projection = makeArray({active_runtime::Columns::PACKAGE_NAME, active_runtime::Columns::NATIVE_LIB_DIR,
277443
active_runtime::Columns::SO_FILENAME, active_runtime::Columns::HAS_FUNCTIONS});
278444

279445
// First, try getting the installable broker's provider
280446
bool systemBroker = false;
281447
Cursor cursor;
282-
if (!getActiveRuntimeCursor(context, projection, systemBroker, cursor)) {
448+
if (!getCursor(context, projection, RUNTIMES_PATH, systemBroker, cursor)) {
283449
// OK, try the system broker as a fallback.
284450
systemBroker = true;
285-
getActiveRuntimeCursor(context, projection, systemBroker, cursor);
451+
getCursor(context, projection, RUNTIMES_PATH, systemBroker, cursor);
286452
}
287453

288454
if (cursor.isNull()) {
@@ -314,6 +480,93 @@ int getActiveRuntimeVirtualManifest(wrap::android::content::Context const &conte
314480
virtualManifest = builder.build();
315481
return 0;
316482
}
483+
484+
static bool populateApiLayerManifest(bool systemBroker, std::string layerType, wrap::android::content::Context const &context,
485+
Cursor &cursor, std::vector<Json::Value> &layerRootNode) {
486+
auto packageName = cursor.getString(cursor.getColumnIndex(api_layer::Columns::PACKAGE_NAME));
487+
auto fileFormatVersion = cursor.getString(cursor.getColumnIndex(api_layer::Columns::FILE_FORMAT_VERSION));
488+
auto name = cursor.getString(cursor.getColumnIndex(api_layer::Columns::NAME));
489+
auto libDir = cursor.getString(cursor.getColumnIndex(active_runtime::Columns::NATIVE_LIB_DIR));
490+
auto fileName = cursor.getString(cursor.getColumnIndex(api_layer::Columns::SO_FILENAME));
491+
auto apiVersion = cursor.getString(cursor.getColumnIndex(api_layer::Columns::API_VERSION));
492+
auto implementationVersion = cursor.getString(cursor.getColumnIndex(api_layer::Columns::IMPLEMENTATION_VERSION));
493+
auto description = cursor.getString(cursor.getColumnIndex(api_layer::Columns::DESCRIPTION));
494+
auto has_instance_extensions = cursor.getString(cursor.getColumnIndex(api_layer::Columns::HAS_INSTANCE_EXTENSIONS));
495+
auto has_functions = cursor.getString(cursor.getColumnIndex(api_layer::Columns::HAS_FUNCTIONS));
496+
497+
__android_log_print(ANDROID_LOG_INFO, TAG, "Got api layer: type: %s, name: %s, native lib dir: %s, fileName: %s",
498+
layerType.c_str(), name.c_str(), libDir.c_str(), fileName.c_str());
499+
500+
Json::Value rootNode(Json::objectValue);
501+
rootNode["file_format_version"] = fileFormatVersion;
502+
rootNode["api_layer"] = Json::objectValue;
503+
rootNode["api_layer"]["name"] = name;
504+
rootNode["api_layer"]["library_path"] = libDir + "/" + fileName;
505+
rootNode["api_layer"]["api_version"] = apiVersion;
506+
rootNode["api_layer"]["implementation_version"] = implementationVersion;
507+
rootNode["api_layer"]["description"] = description;
508+
if (has_functions == "true") {
509+
rootNode["api_layer"]["functions"] = Json::Value(Json::objectValue);
510+
populateApiLayerFunctions(context, systemBroker, packageName, name, rootNode);
511+
}
512+
if (has_instance_extensions == "true") {
513+
rootNode["api_layer"]["instance_extensions"] = Json::Value(Json::arrayValue);
514+
populateApiLayerInstanceExtensions(context, systemBroker, packageName, name, rootNode);
515+
}
516+
517+
layerRootNode.push_back(rootNode);
518+
519+
return true;
520+
}
521+
522+
static void enumerateApiLayerManifests(std::string layerType, wrap::android::content::Context const &context,
523+
jni::Array<std::string> &projection, std::vector<Json::Value> &virtualManifests) {
524+
Cursor cursor;
525+
526+
// First, try getting the installable broker's provider
527+
bool systemBroker = false;
528+
if (!getCursor(context, projection, layerType, systemBroker, cursor)) {
529+
// OK, try the system broker as a fallback.
530+
systemBroker = true;
531+
getCursor(context, projection, layerType, systemBroker, cursor);
532+
}
533+
534+
if (cursor.isNull()) {
535+
return;
536+
}
537+
cursor.moveToFirst();
538+
for (int i = 0; i < cursor.getCount(); ++i) {
539+
populateApiLayerManifest(systemBroker, layerType, context, cursor, virtualManifests);
540+
cursor.moveToNext();
541+
}
542+
543+
cursor.close();
544+
}
545+
546+
int getApiLayerVirtualManifests(std::string layerType, wrap::android::content::Context const &context,
547+
std::vector<Json::Value> &virtualManifests) {
548+
static bool hasQueryBroker = false;
549+
static std::vector<Json::Value> implicitLayerManifest;
550+
static std::vector<Json::Value> explicitLayerManifest;
551+
552+
__android_log_print(ANDROID_LOG_INFO, TAG, "Try to get %s API layer from broker!", layerType.c_str());
553+
if (!hasQueryBroker) {
554+
jni::Array<std::string> projection =
555+
makeArray({api_layer::Columns::PACKAGE_NAME, api_layer::Columns::FILE_FORMAT_VERSION, api_layer::Columns::NAME,
556+
api_layer::Columns::NATIVE_LIB_DIR, api_layer::Columns::SO_FILENAME, api_layer::Columns::API_VERSION,
557+
api_layer::Columns::IMPLEMENTATION_VERSION, api_layer::Columns::DESCRIPTION,
558+
api_layer::Columns::HAS_FUNCTIONS, api_layer::Columns::HAS_INSTANCE_EXTENSIONS});
559+
560+
enumerateApiLayerManifests(IMP_LAYER, context, projection, implicitLayerManifest);
561+
enumerateApiLayerManifests(EXP_LAYER, context, projection, explicitLayerManifest);
562+
563+
hasQueryBroker = true;
564+
}
565+
566+
virtualManifests = (layerType == IMP_LAYER) ? implicitLayerManifest : explicitLayerManifest;
567+
return 0;
568+
}
569+
317570
} // namespace openxr_android
318571

319572
#endif // __ANDROID__

src/loader/android_utilities.h

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

3244
#endif // __ANDROID__

0 commit comments

Comments
 (0)