After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 785406 - android: gstjniutils.c fails to find application class loader provider on Android 7.0
android: gstjniutils.c fails to find application class loader provider on And...
Status: RESOLVED DUPLICATE of bug 788270
Product: GStreamer
Classification: Platform
Component: cerbero
1.12.0
Other other
: Normal major
: git master
Assigned To: GStreamer Maintainers
GStreamer Maintainers
Depends on:
Blocks:
 
 
Reported: 2017-07-25 15:46 UTC by Jeremi Wójcicki
Modified: 2017-11-08 12:29 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
glib: Allow using RTLD_DEFAULT on 64bit Android (4.13 KB, patch)
2017-10-06 10:06 UTC, Justin Kim
none Details | Review

Description Jeremi Wójcicki 2017-07-25 15:46:44 UTC
On android 7.0 (Samsung Galaxy S8/S6) attempting to register androidmedia plugin fails in gstjniutils.c. Seems check_application_class_loader returns null:

07-25 17:20:44.953 23946 23946 I GStreamer+GST_PLUGIN_LOADING: 0:00:00.104817693 0x7ccf5ff600 gstplugin.c:225:gst_plugin_register_static registered static plugin "spandsp"
07-25 17:20:44.953 23946 23946 I GStreamer+GST_PLUGIN_LOADING: 0:00:00.104837116 0x7ccf5ff600 gstplugin.c:227:gst_plugin_register_static added static plugin "spandsp", result: 1
07-25 17:20:44.953 23946 23946 I GStreamer+GST_PLUGIN_LOADING: 0:00:00.105211347 0x7ccf5ff600 gstplugin.c:225:gst_plugin_register_static registered static plugin "sbc"
07-25 17:20:44.953 23946 23946 I GStreamer+GST_PLUGIN_LOADING: 0:00:00.105234270 0x7ccf5ff600 gstplugin.c:227:gst_plugin_register_static added static plugin "sbc", result: 1
07-25 17:20:44.954 23946 23946 E GStreamer+default: 0:00:00.105604731 0x7ccf5ff600 gstjniutils.c:671:initialize_classes Could not find application class loader provider
07-25 17:20:44.954 23946 23946 W GStreamer+GST_PLUGIN_LOADING: 0:00:00.105656693 0x7ccf5ff600 gstplugin.c:527:gst_plugin_register_func plugin "(NULL)" failed to initialise

For more info refer to this thread on gstreamer mailing list: http://gstreamer-devel.966125.n4.nabble.com/Hardware-decoder-availability-on-exynos-CPU-td4683878.html
Comment 1 Sebastian Dröge (slomo) 2017-07-26 06:41:25 UTC
What application is that, and can this be reproduced with any of the example applications too?

This specific error comes from:
https://cgit.freedesktop.org/gstreamer/gst-plugins-bad/tree/sys/androidmedia/gstjniutils.c#n590

Which is called from:
https://cgit.freedesktop.org/gstreamer/gst-plugins-bad/tree/sys/androidmedia/gstjniutils.c#n670

The symbol in question should be found, it's part of gstreamer_android-1.0.c.in:
https://cgit.freedesktop.org/gstreamer/cerbero/tree/data/ndk-build/gstreamer_android-1.0.c.in#n410

Can you check if it's available in your libgstreamer_android.so?


Maybe this is another case of Android breaking the dlopen/dlsym functionality in weird ways. Which ARM variant is this running on, 32 or 64 bit? See this part of the code for something that might be relevant:

https://git.gnome.org/browse/glib/tree/gmodule/gmodule-dl.c#n121

Maybe this fixed this misbehaviour now with Android 7, and now our workaround fails.
Comment 2 Jeremi Wójcicki 2017-07-26 08:23:34 UTC
Indeed, searching in gstreamer_android.so I have found the "check_application_class_loader" in a group like this (whitespaces disappeard after copypasting):

failed_getExceptionSummary_gst_amc_jni_call_long_method_gst_amc_jni_initialize_java_vm_getStackTrace_gst_amc_jni_call_static_byte_method_gst_amc_jni_get_static_float_field_gst_amc_jni_get_boolean_field_get_created_java_vms_pthread_key_create_n_vms_pthread_getspecific_exception_description_gst_amc_jni_get_short_field_check_application_class_loader_gst_amc_jni_call_static_char_method_load_java_module_exception_stacktrace_gst_amc_jni_get_static_boolean_field_printWriterCtor_create_java_vm_gst_amc_jni_attach_current_thread_set_autofocus_gst_ahc_src_unlock_PROP_DEVICE_get_capabilities__white_balance_to_enum__data_queue_item_free

Yes, this is a 64 bit device (however on android 6.0.1, also 64 bit it run well).
Comment 3 Sebastian Dröge (slomo) 2017-07-26 09:20:17 UTC
Someone would have to check the Android's libc/libdl code (it's all inside bionic) for changes around that, and then the workaround has to be updated.

Can you check if it works well with a 32 bit ARM binary on the same device with Android 7?


Also you can easily check if this is broken by just trying to use g_module_open(NULL) and then g_module_symbol() with some local, non-static symbol you have. If that fails, things are wrong.
Comment 4 Jeremi Wójcicki 2017-07-26 11:38:58 UTC
> Can you check if it works well with a 32 bit ARM binary on the same device with Android 7?

I do not know how to do that, can you give me some details?

> Also you can easily check if this is broken by just trying to use g_module_open(NULL) and then g_module_symbol() with some local, non-static symbol you have. If that fails, things are wrong.

Give me a few hours
Comment 5 Sebastian Dröge (slomo) 2017-07-26 11:49:03 UTC
(In reply to Jeremi Wójcicki from comment #4)
> > Can you check if it works well with a 32 bit ARM binary on the same device with Android 7?
> 
> I do not know how to do that, can you give me some details?

You could remove 'arm64-v8a' from the targeted ABIs (APP_ABI in Application.mk if you use ndk-build). And keep 'armeabi' 'armeabi-v7a' 'arm64-v8a' 'x86' 'x86_64'
Comment 6 Jeremi Wójcicki 2017-07-26 16:55:51 UTC
1. Using 32 bit ARM binary the problem still occurs

2. I have used a following code (correct me it its wrong, I do not have any experience with glib):

----------------

#include <gmodule.h>

void hello_fcn(){
    LOG_INFO("Hello function");
}

void g_module_test() {

    GModule *m;
    gpointer *ptr;

    m = g_module_open(NULL, G_MODULE_BIND_LOCAL);
    if (!m) {
        LOG_ERROR("module open - False");
    } else {
        LOG_ERROR("module open - True");
    }

    if (!g_module_symbol(m, "hello_fcn", ptr)) {
        LOG_ERROR("symbol - False");
    } else {
        LOG_ERROR("symbol - True");
    }


    hello_fcn();

}

-------------

I call g_module_test somewhere in gstreamer mainloop. Is this what you asked for?

The result is following:

07-26 18:29:46.051 28198-28275/org.freedesktop.gstreamer.tutorials.tutorial_3 E/GST_log: module open - True
07-26 18:29:46.051 28198-28275/org.freedesktop.gstreamer.tutorials.tutorial_3 E/GLib+GModule: g_module_symbol: assertion 'symbol != NULL' failed
07-26 18:29:46.051 28198-28275/org.freedesktop.gstreamer.tutorials.tutorial_3 E/GST_log: symbol - False
07-26 18:29:46.051 28198-28275/org.freedesktop.gstreamer.tutorials.tutorial_3 I/GST_log: Hello function
Comment 7 Sebastian Dröge (slomo) 2017-07-26 20:14:26 UTC
(In reply to Jeremi Wójcicki from comment #6
>     if (!g_module_symbol(m, "hello_fcn", ptr)) {

Almost:

gpointer ptr;
g_module_symbol(m, "hello_fcn", &ptr)

Then that assertion should disappear and we will know more :)
Comment 8 Jeremi Wójcicki 2017-07-26 22:29:31 UTC
My bad! I updated the code and here's the result:

07-27 00:26:03.051 3325-3542/org.freedesktop.gstreamer.tutorials.tutorial_3 E/GST_log: module open - True
07-27 00:26:03.052 3325-3542/org.freedesktop.gstreamer.tutorials.tutorial_3 E/GST_log: symbol - False
07-27 00:26:03.052 3325-3542/org.freedesktop.gstreamer.tutorials.tutorial_3 I/GST_log: Hello function

Just for reference I enclose the updated code:

void g_module_test() {
    GModule *m;
    gpointer ptr;
    m = g_module_open(NULL, G_MODULE_BIND_LOCAL);
    if (!m) {
        LOG_ERROR("module open - False");
    } else {
        LOG_ERROR("module open - True");
    }

    if (!g_module_symbol(m, "hello_fcn", &ptr)) {
        LOG_ERROR("symbol - False");
    } else {
        LOG_ERROR("symbol - True");
    }
    hello_fcn();
}
Comment 9 Sebastian Dröge (slomo) 2017-07-27 05:49:43 UTC
Thanks for confirming. So it's indeed the GModule code that fails to load anything from the NULL/self module on Android 7, most likely meaning that our workaround for bugs in previous Android versions breaks things now.
Comment 10 Jeremi Wójcicki 2017-08-28 08:08:27 UTC
Hi guys! Are there any news on this bug? Development of my application using gstreamer relies on resolution of this problem, so it is quite urgent to me... Are there plans to resolve it in the nearest future or should I look for some sort of workaround?
Comment 11 Sebastian Dröge (slomo) 2017-08-28 15:57:27 UTC
I'm busy with other things and don't have a device set up with 7.0 currently. Basically what is needed here is someone going through the relevant bionic code and check what has changed there between 6.x and 7.0, and then we have to find yet another workaround that hopefully works for all versions.
Comment 12 Jeremi Wójcicki 2017-08-30 11:08:44 UTC
Hmm... Even though I have a device I do not posses skills to fix that bug, as I have limited experience with gstreamer and no experience at all with glib. Possibly I'll try to work around the problem by terminating pipeline before decoding with appsink and try to natively use Android's MediaCodec to get the job done. I'll post on forum if I bump into gstreamer related problems while doing that. Any suggestions are welcome!
Comment 13 Sebastian Dröge (slomo) 2017-08-30 11:41:04 UTC
This is not really GLib or GStreamer related, just related to how dlopen() and dlsym() work on Android. And in this specific case how to get a symbol from the current process image.
Comment 14 Jeremi Wójcicki 2017-08-30 11:57:20 UTC
Ok. Give me a few days to investigate the topic, perhaps I could contribute to the solution of this issue.
Comment 15 Sebastian Dröge (slomo) 2017-08-30 12:35:26 UTC
Shout if you need help or pointers where to look :)
Comment 16 Jeremi Wójcicki 2017-09-05 08:43:06 UTC
OK, so following you intuition about dlopen() and dlsym() calls, I looked into changes that were introduced since Android 7.0. It seems we've pin-pointed the issue: for target APIs of 24(Nougat) and higher dynamic linking seems to be restricted (https://developer.android.com/about/versions/nougat/android-7.0-changes.html#ndk).

To verify that, I have actually downgraded my compile and target api to 21 and changed at the same time target to armeabi-v7a (64bit instruction set is supported api level 24 up). After the changes I could see the class loader and amc plugin properly registered!

My app begun crashing, tough, when I was touching samples received through appsink in another thread (which did not occur before). Its possible that I have some mixed 32 (gstreamer) and 64 (oculus mobile sdk) bit libs and hence the issue, and it should rather not be related to the main problem.

Now, what makes me wonder is that Android 7.0 changelog says that the NDK public libraries can still be dynamically linked. AMC and OpenMAX are public, aren't they? Is gstreamer dynamically linking to itself (gstreamer.so)? Perhaps somehow modifying this behavior could work as a quickfix to the issue. Otherwise, I guess, the approach to handling AMC and OMX by gstremer should be changed (I guess static library loading etc.).

That is all I have learnt about this issue. Anyhow, the workaround using the downgraded target api and using 32bit build seems to be OK for now. I'll post more if I find other related problems or solutions.
Comment 17 Sebastian Dröge (slomo) 2017-09-05 08:58:06 UTC
These changes are probably related, but more in an unintentional way. There is no problem here with dynamic linking and loading libraries at runtime, but it's the same API that is used. We only do static linking, except for public Android libraries but those are also not dynamically loaded at runtime (that is, not via dlopen(), etc).

What we do is to try to retrieve a symbol of the current process, not from a separate library. My guess is that somewhere related to the changes you list, they changed behaviour (unintentionally probably) to load symbols from the current process.
Comment 18 Sebastian Dröge (slomo) 2017-09-05 09:01:53 UTC
Code in question would be here btw: https://android.googlesource.com/platform/bionic.git/+/master

Maybe something relevant can be found in the GIT history. But what could also make sense is to write a simple, non-GStreamer/GLib example application that just tries to get a symbol from the current process via dlopen(). Show that it works pre-24 and not anymore, and file a bug in the Android bug tracker.
Comment 19 Justin Kim 2017-09-28 08:16:02 UTC
The problem is that 'dlsym' fails if it uses a handle which is created by 'dlopen(NULL)' on Android 64 bit. I am not sure if it is a correct way, but using RTLD_DEFAULT solves the problem. See https://bugzilla.gnome.org/show_bug.cgi?id=788270
Comment 20 Sebastian Dröge (slomo) 2017-09-28 09:10:57 UTC
Let's continue discussions there then

*** This bug has been marked as a duplicate of bug 788270 ***
Comment 21 Justin Kim 2017-10-06 10:06:03 UTC
Created attachment 361033 [details] [review]
glib: Allow using RTLD_DEFAULT on 64bit Android

I attached a backport patch here rather than creating another issue.
Comment 22 Justin Kim 2017-11-08 12:29:03 UTC
(In reply to Justin J. Kim from comment #21)
> I attached a backport patch here rather than creating another issue.

I created another issue; https://bugzilla.gnome.org/show_bug.cgi?id=790058