@@ -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,52 @@ struct Columns : BaseColumns {
164168};
165169} // namespace functions
166170
171+ namespace api_layer {
172+ /* *
173+ * Final path component to this URI.
174+ */
175+
176+
177+ /* *
178+ * Create a content URI for querying all rows of the implicit/explicit API layer data for a given
179+ * runtime package and major version of OpenXR.
180+ *
181+ * @param systemBroker If the system runtime broker (instead of the installable one) should be queried.
182+ * @param majorVer The major version of OpenXR.
183+ * @param layerType The layer type of the API layer.
184+ * @param abi The Android ABI name in use.
185+ * @return A content URI for the entire table: the function remapping for that runtime.
186+ */
187+ static Uri makeContentUri (bool systemBroker, int majorVersion, std::string const &layerType, const char *abi) {
188+ auto builder = Uri_Builder::construct ();
189+ builder.scheme (" content" )
190+ .authority (getBrokerAuthority (systemBroker))
191+ .appendPath (BASE_PATH)
192+ .appendPath (std::to_string (majorVersion))
193+ .appendPath (ABI_PATH)
194+ .appendPath (abi)
195+ .appendPath (API_LAYERS_PATH)
196+ .appendPath (getLayerTypePath (layerType == IMP_LAYER));
197+ return builder.build ();
198+ }
199+ struct Columns : BaseColumns {
200+ // implicit or explicit
201+ static constexpr auto FILE_FORMAT_VERSION = " file_format_version" ;
202+ static constexpr auto NAME = " name" ;
203+ static constexpr auto NATIVE_LIB_DIR = " native_lib_dir" ;
204+ static constexpr auto SO_FILENAME = " so_filename" ;
205+ static constexpr auto API_VERSION = " api_version" ;
206+ static constexpr auto IMPLEMENTATION_VERSION = " implementation_version" ;
207+ static constexpr auto DESCRIPTION = " description" ;
208+ static constexpr auto ENABLE_ENVIRONMENT = " enable_environment" ;
209+ static constexpr auto DISABLE_ENVIRONMENT = " disable_environment" ;
210+ static constexpr auto FUNCTIONS = " functions" ;
211+ // extensions names will be combined like "extension1&extension2"
212+ static constexpr auto INSTANCE_EXTENSION_NAMES = " instance_extension_names" ;
213+ static constexpr auto INSTANCE_EXTENSION_VERSIONS = " instance_extension_versions" ;
214+ };
215+ } // namespace api_layer
216+
167217} // namespace
168218
169219static inline jni::Array<std::string> makeArray (std::initializer_list<const char *> &&list) {
@@ -245,11 +295,12 @@ static int populateFunctions(wrap::android::content::Context const &context, boo
245295 return 0 ;
246296}
247297
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 ());
298+ // / Get cursor for active runtime or API layer, parameterized by target type and whether or not we use the system broker
299+ static bool getCursor (wrap::android::content::Context const &context, jni::Array<std::string> const &projection,
300+ std::string const &targetType, bool systemBroker, Cursor &cursor) {
301+ auto uri = (targetType == RUNTIMES_PATH) ? 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,138 @@ 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+
387+ Json::Value rootNode (Json::objectValue);
388+ rootNode[" file_format_version" ] = fileFormatVersion;
389+ rootNode[" api_layer" ] = Json::objectValue;
390+ rootNode[" api_layer" ][" name" ] = name;
391+ rootNode[" api_layer" ][" library_path" ] = libDir + " /" + fileName;
392+ rootNode[" api_layer" ][" api_version" ] = apiVersion;
393+ rootNode[" api_layer" ][" implementation_version" ] = imllementationVersion;
394+ rootNode[" api_layer" ][" description" ] = description;
395+ rootNode[" api_layer" ][" disable_environment" ] = disableEnv;
396+ rootNode[" api_layer" ][" enable_environment" ] = enableEnv;
397+
398+ rootNode[" api_layer" ][" instance_extensions" ] = Json::Value (Json::arrayValue);
399+ std::vector<std::string> nameVec;
400+ std::vector<std::string> versionVec;
401+ // extract extension names
402+ std::istringstream issNames (extensionNames);
403+ std::string item;
404+ while (std::getline (issNames, item, ' &' )) {
405+ nameVec.push_back (item);
406+ }
407+ // extract extension versions
408+ std::istringstream issVersions (extensionVersions);
409+ while (std::getline (issVersions, item, ' &' )) {
410+ versionVec.push_back (item);
411+ }
412+
413+ Json::Value extension (Json::objectValue);
414+ if (nameVec.size () == versionVec.size ()){
415+ for (int i = 0 ; i < nameVec.size ();++i){
416+ extension[" name" ] = nameVec[i];
417+ extension[" extension_version" ] = versionVec[i];
418+ rootNode[" api_layer" ][" instance_extensions" ].append (extension);
419+ __android_log_print (ANDROID_LOG_INFO, TAG, " extension name: %s, extension version: %s" ,
420+ nameVec[i].c_str (), versionVec[i].c_str ());
421+ }
422+ }
423+ else {
424+ __android_log_print (ANDROID_LOG_INFO, TAG, " api layer extension name not match extension version!" );
425+ }
426+
427+ std::vector<std::string> functionNameVec;
428+ std::vector<std::string> symbolVec;
429+ std::istringstream issFunctions (functions);
430+ while (std::getline (issFunctions, item, ' &' )) {
431+ std::size_t pos = item.find (' :' );
432+ if (pos != item.npos ) {
433+ functionNameVec.push_back (item.substr (0 , pos));
434+ symbolVec.push_back (item.substr (pos+1 , item.size ()));
435+ }
436+ }
437+
438+ rootNode[" api_layer" ][" functions" ] = Json::Value (Json::objectValue);
439+ if (functions != " None" ) {
440+ for (int i = 0 ; i < functionNameVec.size (); ++i) {
441+ rootNode[" api_layer" ][" functions" ][functionNameVec[i]] = symbolVec[i];
442+ __android_log_print (ANDROID_LOG_INFO, TAG, " function name: %s, symbol: %s" ,
443+ functionNameVec[i].c_str (), symbolVec[i].c_str ());
444+ }
445+ } else {
446+ __android_log_print (ANDROID_LOG_INFO, TAG, " functions field not existed!" );
447+ }
448+
449+ layerRootNode.push_back (rootNode);
450+
451+ return true ;
452+ }
453+
454+ static bool getApiLayerCursor (std::string layerType, wrap::android::content::Context const &context,
455+ jni::Array<std::string> &projection,
456+ std::vector<Json::Value> &virtualManifests) {
457+ Cursor cursor;
458+
459+ getCursor (context, projection, layerType, false , cursor);
460+ if (cursor.isNull ()) {
461+ return false ;
462+ }
463+
464+ cursor.moveToFirst ();
465+ for (int i = 0 ; i < cursor.getCount (); ++i){
466+ populateApiLayerManifest (layerType, cursor, virtualManifests);
467+ cursor.moveToNext ();
468+ }
469+ cursor.close ();
470+
471+ return true ;
472+ }
473+
474+ int getApiLayerVirtualManifests (std::string layerType, wrap::android::content::Context const &context,
475+ std::vector<Json::Value> &virtualManifests) {
476+ static bool hasQueryBroker = false ;
477+ static std::vector<Json::Value> implicitLayerManifest;
478+ static std::vector<Json::Value> explicitLayerManifest;
479+
480+ __android_log_print (ANDROID_LOG_INFO, TAG, " Try to get %s API layer from broker!" , layerType.c_str ());
481+ if (!hasQueryBroker){
482+ jni::Array<std::string> projection = makeArray ({api_layer::Columns::FILE_FORMAT_VERSION, api_layer::Columns::NAME,
483+ api_layer::Columns::NATIVE_LIB_DIR, api_layer::Columns::SO_FILENAME,
484+ api_layer::Columns::API_VERSION, api_layer::Columns::IMPLEMENTATION_VERSION,
485+ api_layer::Columns::DESCRIPTION, api_layer::Columns::ENABLE_ENVIRONMENT,
486+ api_layer::Columns::DISABLE_ENVIRONMENT, api_layer::Columns::FUNCTIONS,
487+ api_layer::Columns::INSTANCE_EXTENSION_NAMES,
488+ api_layer::Columns::INSTANCE_EXTENSION_VERSIONS});
489+
490+ getApiLayerCursor (IMP_LAYER, context, projection, implicitLayerManifest);
491+ getApiLayerCursor (EXP_LAYER, context, projection, explicitLayerManifest);
492+
493+ hasQueryBroker= true ;
494+ }
495+
496+ virtualManifests = (layerType == IMP_LAYER) ? implicitLayerManifest : explicitLayerManifest;
497+ return 0 ;
498+ }
499+
317500} // namespace openxr_android
318501
319502#endif // __ANDROID__
0 commit comments