@@ -38,8 +38,12 @@ constexpr auto SYSTEM_AUTHORITY = "org.khronos.openxr.system_runtime_broker";
3838constexpr auto BASE_PATH = " openxr" ;
3939constexpr auto ABI_PATH = " abi" ;
4040constexpr auto RUNTIMES_PATH = " runtimes" ;
41+ constexpr auto API_LAYERS_PATH = " api_layer" ;
42+ constexpr auto IMP_LAYER = " implicit" ;
43+ constexpr auto EXP_LAYER = " explicit" ;
4144
4245constexpr const char *getBrokerAuthority (bool systemBroker) { return systemBroker ? SYSTEM_AUTHORITY : AUTHORITY; }
46+ constexpr const char *getLayerTypePath (bool isImplicitLayer) { return isImplicitLayer ? IMP_LAYER : EXP_LAYER; }
4347
4448struct BaseColumns {
4549 /* *
@@ -164,6 +168,51 @@ struct Columns : BaseColumns {
164168};
165169} // namespace functions
166170
171+ namespace api_layer {
172+ /* *
173+ * Final path component to this URI.
174+ */
175+
176+ /* *
177+ * Create a content URI for querying all rows of the implicit/explicit API layer data for a given
178+ * runtime package and major version of OpenXR.
179+ *
180+ * @param systemBroker If the system runtime broker (instead of the installable one) should be queried.
181+ * @param majorVer The major version of OpenXR.
182+ * @param layerType The layer type of the API layer.
183+ * @param abi The Android ABI name in use.
184+ * @return A content URI for the entire table: the function remapping for that runtime.
185+ */
186+ static Uri makeContentUri (bool systemBroker, int majorVersion, std::string const &layerType, const char *abi) {
187+ auto builder = Uri_Builder::construct ();
188+ builder.scheme (" content" )
189+ .authority (getBrokerAuthority (systemBroker))
190+ .appendPath (BASE_PATH)
191+ .appendPath (std::to_string (majorVersion))
192+ .appendPath (ABI_PATH)
193+ .appendPath (abi)
194+ .appendPath (API_LAYERS_PATH)
195+ .appendPath (getLayerTypePath (layerType == IMP_LAYER));
196+ return builder.build ();
197+ }
198+ struct Columns : BaseColumns {
199+ // implicit or explicit
200+ static constexpr auto FILE_FORMAT_VERSION = " file_format_version" ;
201+ static constexpr auto NAME = " name" ;
202+ static constexpr auto NATIVE_LIB_DIR = " native_lib_dir" ;
203+ static constexpr auto SO_FILENAME = " so_filename" ;
204+ static constexpr auto API_VERSION = " api_version" ;
205+ static constexpr auto IMPLEMENTATION_VERSION = " implementation_version" ;
206+ static constexpr auto DESCRIPTION = " description" ;
207+ static constexpr auto ENABLE_ENVIRONMENT = " enable_environment" ;
208+ static constexpr auto DISABLE_ENVIRONMENT = " disable_environment" ;
209+ static constexpr auto FUNCTIONS = " functions" ;
210+ // extensions names will be combined like "extension1&extension2"
211+ static constexpr auto INSTANCE_EXTENSION_NAMES = " instance_extension_names" ;
212+ static constexpr auto INSTANCE_EXTENSION_VERSIONS = " instance_extension_versions" ;
213+ };
214+ } // namespace api_layer
215+
167216} // namespace
168217
169218static inline jni::Array<std::string> makeArray (std::initializer_list<const char *> &&list) {
@@ -245,11 +294,13 @@ static int populateFunctions(wrap::android::content::Context const &context, boo
245294 return 0 ;
246295}
247296
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 ());
297+ // / Get cursor for active runtime or API layer, parameterized by target type and whether or not we use the system broker
298+ static bool getCursor (wrap::android::content::Context const &context, jni::Array<std::string> const &projection,
299+ std::string const &targetType, bool systemBroker, Cursor &cursor) {
300+ auto uri = (targetType == RUNTIMES_PATH)
301+ ? active_runtime::makeContentUri (systemBroker, XR_VERSION_MAJOR (XR_CURRENT_API_VERSION), ABI)
302+ : api_layer::makeContentUri (systemBroker, XR_VERSION_MAJOR (XR_CURRENT_API_VERSION), targetType, ABI);
303+ ALOGI (" getCursor: Querying URI: %s" , uri.toString ().c_str ());
253304 try {
254305 cursor = context.getContentResolver ().query (uri, projection);
255306 } catch (const std::exception &e) {
@@ -279,10 +330,10 @@ int getActiveRuntimeVirtualManifest(wrap::android::content::Context const &conte
279330 // First, try getting the installable broker's provider
280331 bool systemBroker = false ;
281332 Cursor cursor;
282- if (!getActiveRuntimeCursor (context, projection, systemBroker, cursor)) {
333+ if (!getCursor (context, projection, RUNTIMES_PATH , systemBroker, cursor)) {
283334 // OK, try the system broker as a fallback.
284335 systemBroker = true ;
285- getActiveRuntimeCursor (context, projection, systemBroker, cursor);
336+ getCursor (context, projection, RUNTIMES_PATH , systemBroker, cursor);
286337 }
287338
288339 if (cursor.isNull ()) {
@@ -314,6 +365,134 @@ int getActiveRuntimeVirtualManifest(wrap::android::content::Context const &conte
314365 virtualManifest = builder.build ();
315366 return 0 ;
316367}
368+
369+ static bool populateApiLayerManifest (std::string layerType, Cursor &cursor, std::vector<Json::Value> &layerRootNode) {
370+ auto fileFormatVersion = cursor.getString (cursor.getColumnIndex (api_layer::Columns::FILE_FORMAT_VERSION));
371+ auto name = cursor.getString (cursor.getColumnIndex (api_layer::Columns::NAME));
372+ auto libDir = cursor.getString (cursor.getColumnIndex (active_runtime::Columns::NATIVE_LIB_DIR));
373+ auto fileName = cursor.getString (cursor.getColumnIndex (api_layer::Columns::SO_FILENAME));
374+ auto apiVersion = cursor.getString (cursor.getColumnIndex (api_layer::Columns::API_VERSION));
375+ auto imllementationVersion = cursor.getString (cursor.getColumnIndex (api_layer::Columns::IMPLEMENTATION_VERSION));
376+ auto description = cursor.getString (cursor.getColumnIndex (api_layer::Columns::DESCRIPTION));
377+ auto disableEnv = cursor.getString (cursor.getColumnIndex (api_layer::Columns::DISABLE_ENVIRONMENT));
378+ auto enableEnv = cursor.getString (cursor.getColumnIndex (api_layer::Columns::ENABLE_ENVIRONMENT));
379+ auto extensionNames = cursor.getString (cursor.getColumnIndex (api_layer::Columns::INSTANCE_EXTENSION_NAMES));
380+ auto extensionVersions = cursor.getString (cursor.getColumnIndex (api_layer::Columns::INSTANCE_EXTENSION_VERSIONS));
381+ auto functions = cursor.getString (cursor.getColumnIndex (api_layer::Columns::FUNCTIONS));
382+
383+ __android_log_print (ANDROID_LOG_INFO, TAG, " Got api layer: type: %s, name: %s, native lib dir: %s, fileName: %s, functions: %s" ,
384+ layerType.c_str (), name.c_str (), libDir.c_str (), fileName.c_str (), functions.c_str ());
385+
386+ Json::Value rootNode (Json::objectValue);
387+ rootNode[" file_format_version" ] = fileFormatVersion;
388+ rootNode[" api_layer" ] = Json::objectValue;
389+ rootNode[" api_layer" ][" name" ] = name;
390+ rootNode[" api_layer" ][" library_path" ] = libDir + " /" + fileName;
391+ rootNode[" api_layer" ][" api_version" ] = apiVersion;
392+ rootNode[" api_layer" ][" implementation_version" ] = imllementationVersion;
393+ rootNode[" api_layer" ][" description" ] = description;
394+ rootNode[" api_layer" ][" disable_environment" ] = disableEnv;
395+ rootNode[" api_layer" ][" enable_environment" ] = enableEnv;
396+
397+ rootNode[" api_layer" ][" instance_extensions" ] = Json::Value (Json::arrayValue);
398+ std::vector<std::string> nameVec;
399+ std::vector<std::string> versionVec;
400+ // extract extension names
401+ std::istringstream issNames (extensionNames);
402+ std::string item;
403+ while (std::getline (issNames, item, ' &' )) {
404+ nameVec.push_back (item);
405+ }
406+ // extract extension versions
407+ std::istringstream issVersions (extensionVersions);
408+ while (std::getline (issVersions, item, ' &' )) {
409+ versionVec.push_back (item);
410+ }
411+
412+ Json::Value extension (Json::objectValue);
413+ if (nameVec.size () == versionVec.size ()) {
414+ for (int i = 0 ; i < nameVec.size (); ++i) {
415+ extension[" name" ] = nameVec[i];
416+ extension[" extension_version" ] = versionVec[i];
417+ rootNode[" api_layer" ][" instance_extensions" ].append (extension);
418+ __android_log_print (ANDROID_LOG_INFO, TAG, " extension name: %s, extension version: %s" , nameVec[i].c_str (),
419+ versionVec[i].c_str ());
420+ }
421+ } else {
422+ __android_log_print (ANDROID_LOG_INFO, TAG, " api layer extension name not match extension version!" );
423+ }
424+
425+ std::vector<std::string> functionNameVec;
426+ std::vector<std::string> symbolVec;
427+ std::istringstream issFunctions (functions);
428+ while (std::getline (issFunctions, item, ' &' )) {
429+ std::size_t pos = item.find (' :' );
430+ if (pos != item.npos ) {
431+ functionNameVec.push_back (item.substr (0 , pos));
432+ symbolVec.push_back (item.substr (pos + 1 , item.size ()));
433+ }
434+ }
435+
436+ rootNode[" api_layer" ][" functions" ] = Json::Value (Json::objectValue);
437+ if (functions != " None" ) {
438+ for (int i = 0 ; i < functionNameVec.size (); ++i) {
439+ rootNode[" api_layer" ][" functions" ][functionNameVec[i]] = symbolVec[i];
440+ __android_log_print (ANDROID_LOG_INFO, TAG, " function name: %s, symbol: %s" , functionNameVec[i].c_str (),
441+ symbolVec[i].c_str ());
442+ }
443+ } else {
444+ __android_log_print (ANDROID_LOG_INFO, TAG, " functions field not existed!" );
445+ }
446+
447+ layerRootNode.push_back (rootNode);
448+
449+ return true ;
450+ }
451+
452+ static bool getApiLayerCursor (std::string layerType, wrap::android::content::Context const &context,
453+ jni::Array<std::string> &projection, std::vector<Json::Value> &virtualManifests) {
454+ Cursor cursor;
455+
456+ getCursor (context, projection, layerType, false , cursor);
457+ if (cursor.isNull ()) {
458+ return false ;
459+ }
460+
461+ cursor.moveToFirst ();
462+ for (int i = 0 ; i < cursor.getCount (); ++i) {
463+ populateApiLayerManifest (layerType, cursor, virtualManifests);
464+ cursor.moveToNext ();
465+ }
466+ cursor.close ();
467+
468+ return true ;
469+ }
470+
471+ int getApiLayerVirtualManifests (std::string layerType, wrap::android::content::Context const &context,
472+ std::vector<Json::Value> &virtualManifests) {
473+ static bool hasQueryBroker = false ;
474+ static std::vector<Json::Value> implicitLayerManifest;
475+ static std::vector<Json::Value> explicitLayerManifest;
476+
477+ __android_log_print (ANDROID_LOG_INFO, TAG, " Try to get %s API layer from broker!" , layerType.c_str ());
478+ if (!hasQueryBroker) {
479+ jni::Array<std::string> projection =
480+ makeArray ({api_layer::Columns::FILE_FORMAT_VERSION, api_layer::Columns::NAME, api_layer::Columns::NATIVE_LIB_DIR,
481+ api_layer::Columns::SO_FILENAME, api_layer::Columns::API_VERSION, api_layer::Columns::IMPLEMENTATION_VERSION,
482+ api_layer::Columns::DESCRIPTION, api_layer::Columns::ENABLE_ENVIRONMENT,
483+ api_layer::Columns::DISABLE_ENVIRONMENT, api_layer::Columns::FUNCTIONS,
484+ api_layer::Columns::INSTANCE_EXTENSION_NAMES, api_layer::Columns::INSTANCE_EXTENSION_VERSIONS});
485+
486+ getApiLayerCursor (IMP_LAYER, context, projection, implicitLayerManifest);
487+ getApiLayerCursor (EXP_LAYER, context, projection, explicitLayerManifest);
488+
489+ hasQueryBroker = true ;
490+ }
491+
492+ virtualManifests = (layerType == IMP_LAYER) ? implicitLayerManifest : explicitLayerManifest;
493+ return 0 ;
494+ }
495+
317496} // namespace openxr_android
318497
319498#endif // __ANDROID__
0 commit comments