OpenCL is not able to query a platform on an android device

Im using the Qualcomm OpenCL to optimize native C++ code in my android application. The linking in CMakeLists.txt is handled as follows:

add_library(opencl-lib SHARED IMPORTED)
set_target_properties( opencl-lib PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/libOpenCL.so)
target_link_libraries( demo opencl-lib )

My reproducible example:

#include <jni.h>
#include <string>
#include <iostream>
#include <vector>
#include <cmath>
#include <stdio.h>
#include <android/log.h>
#include "opencl-sdk/inc/CL/cl.h"
#include "opencl-sdk/inc/CL/opencl.h"

extern "C" JNIEXPORT jint JNICALL
Java_com_example_demo_MainActivity_getInt( JNIEnv* env, jobject /* this */) {
    cl_int err = 0;
    cl_uint num_platforms = 0;
    err = clGetPlatformIDs(0, NULL, &num_platforms);
    return 0;
}

The application crashes immediately after running it. I receive the following message in the Logcat:

libc, com.example.<app_name>, A Fatal signal 5 (SIGTRAP), code 1 (TRAP_BRKPT), fault addr 0x726e76a004 in tid 29952 (om.example.demo), pid 29952 (om.example.<app_name>)

It seems like OpenCL is not able to query a device at all.

When I comment everything in Java_com_example_demo_MainActivity_getInt() , I get a lot of type DEBUG logs, including

/data/app/~~6MgdG5XHBNcZSiF0nvJtPg==/com.example.demo-ZvGN17inQLVfZzeCRpFjJA==/base.apk!libOpenCL.so (clGetPlatformIDs+72) (BuildId: 4252b0a3fc7297cc93dfa7a31c208d1f)

Are there any work-arounds to this issue?

My guess is, that there is a problem with ld-android.so from /vendor/lib64/, which causes the app to crash at clGetPlatformIDs. I got the following log after the crash:

Fatal signal 5 (SIGTRAP), code 1 (TRAP_BRKPT), fault addr 0x726e6b1004 in tid 30364 (om.example.demo), pid 30364 (om.example.demo)
Cmdline: com.example.demo
pid: 30364, tid: 30364, name: om.example.demo  >>> com.example.demo <<<
#00 pc 0000000000001004  /data/app/~~bwptcAF2Mcxj1QrTS4VEAA==/com.example.demo-M6X_ed8wUlOuBtErB5lu1Q==/base.apk!ld-android.so (__loader_dlopen+4) (BuildId: daa6dd2d221674856cad38a0130d0b16)
#01 pc 00000000000010e0  /data/app/~~bwptcAF2Mcxj1QrTS4VEAA==/com.example.demo-M6X_ed8wUlOuBtErB5lu1Q==/base.apk!libdl_android.so (android_get_exported_namespace+12) (BuildId: a506d7cbefe663d77d99d39034bddf74)
#02 pc 0000000000001194  /data/app/~~bwptcAF2Mcxj1QrTS4VEAA==/com.example.demo-M6X_ed8wUlOuBtErB5lu1Q==/base.apk!libvndksupport.so (android_load_sphal_library+308) (BuildId: fa178c0474c2bbfb9380bc25fc0547ec)
#03 pc 0000000000021c70  /data/app/~~bwptcAF2Mcxj1QrTS4VEAA==/com.example.demo-M6X_ed8wUlOuBtErB5lu1Q==/base.apk!libOpenCL.so (clGetPlatformIDs+72) (BuildId: 4252b0a3fc7297cc93dfa7a31c208d1f)
#04 pc 0000000000005d30  /data/app/~~bwptcAF2Mcxj1QrTS4VEAA==/com.example.demo-M6X_ed8wUlOuBtErB5lu1Q==/base.apk!libdemo.so (Java_com_example_demo_MainActivity_getInt+32) (BuildId: a0b5246c34b8e042c29bfe224a864d949ab56d04)
#07 pc 0000000000000eac  /data/app/~~bwptcAF2Mcxj1QrTS4VEAA==/com.example.demo-M6X_ed8wUlOuBtErB5lu1Q==/base.apk (com.example.demo.MainActivity.onCreate$lambda$0+48)
#09 pc 0000000000000e1c  /data/app/~~bwptcAF2Mcxj1QrTS4VEAA==/com.example.demo-M6X_ed8wUlOuBtErB5lu1Q==/base.apk (com.example.demo.MainActivity.$r8$lambda$KC6AjQoJlmGj4vROYZUNl9WDJyU+0)
#11 pc 0000000000000dd4  /data/app/~~bwptcAF2Mcxj1QrTS4VEAA==/com.example.demo-M6X_ed8wUlOuBtErB5lu1Q==/base.apk (com.example.demo.MainActivity$$ExternalSyntheticLambda0.onClick+4)
#17 pc 00000000002e7432  /data/app/~~bwptcAF2Mcxj1QrTS4VEAA==/com.example.demo-M6X_ed8wUlOuBtErB5lu1Q==/base.apk (com.google.android.material.button.MaterialButton.performClick+22)

hi,

Try to compile with the 32 version. Some architecture do not have openCL 64.

Hi, thanks for your response. Im using a Samsung Tab S8 Ultra which has a 64-bit architecture. Using the 32 bit version won’t work here.

we can run 32 on 64 but not the inverse ;))

I receive ld: error: /Users/terdev/AndroidStudioProjects/demo/app/src/main/cpp/opencl-sdk/libOpenCL.so is incompatible with aarch64linux when using the 32-bit version of OpenCL.so

The general problem here is that ld-android is not able to load vendor drivers for OpenCL. I don’t know why this is the case, since OpenCL benchmarks work well on my device… I have contacted someone who works on GPU drivers at Qualcomm regarding this issue.

if the code you show is you C code. Why do you use extern “C”. This should be in the .h for JNI function declaration not in cpp code.

You declare the function that you call from java code in .h and the C code function implementation in .cpp

But if you have a libc error it means that at least one library is missing. You must copy it from your smartphonne to your android libs directorie.

it is the first time you try to run openCL on smartphonne ?

@terdev I meet similar issue, any suggestion?

@terdev I meet similar issue, and my OpenCL program can run smoothly on Meizu 16th (Adreno630), but it cannot run on Xiaomi Note9 (Adreno619) and Xiaomi 12Sultra (Adreno730), mainly because the OpenCL interface function clGetPlatformIDs cannot return a value. do you have a solution?Thanks

Hi, did any of you found a solution for this? I encounter the same issue where when packaging my android app with the OpenCL that provided with the android device (OpenCL3) leads to the same error from ld-android.so that fails in __loader_dlopen(), but when using some other OpenCL1.2 library I actually get past this issue and get stuck on failure to find any supporting devices of OpenCL on the phone (even when querying for CL_DEVICE_TYPE_ALL) , while benchmarking OpenCL with Benchgeek show results.

@atwork @Haiqing @DavdGao Sorry for the late response. The error was that I bundled libOpenCL.so into the APK as part of the build process. To exclude OpenCL from the APK, I set the build.gradle to:

android {
    ...
 
    packagingOptions {
        exclude 'jniLibs/arm64-v8a/libOpenCL.so'
    }

Hope that helps.

Thanks for the reply! I was hopeless to get any haha.
Now, a question regarding this solution, but if you need to use OpenCL but you exclude it from the packaging, how would your native code know where to load from the library?
Doing so leads me to get the
dlopen failed: library "libOpenCL.so" not found

Im not sure if you can link against native libraries on the device. Therefore I downloaded them from the device to a new jniLibs directory in my AndroidStudio project and linked against it. Something like:

set(VENDOR_LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/arm64-v8a)

add_library(opencl-lib SHARED IMPORTED)
set_target_properties( opencl-lib PROPERTIES IMPORTED_LOCATION ${VENDOR_LIB_DIR}/libOpenCL.so)

add_library( demo SHARED native-lib.cpp )
target_include_directories( demo PRIVATE ${CMAKE_SOURCE_DIR}/opencl-sdk/inc/CL )

target_link_libraries( demo opencl-lib )

Yes, that what I’ve assumed too, so because i couldn’t link vs the libOpenCL that is already on the device, I started downloading the libOpenCL from the device and then recursively downloaded all the other dependencies of libOpenCL, like libvndksupport, libld_android, ld-android and put all of them in the jniLibs to package with my build. Even after doing all that I was encountering the ld-android.so crash: .../lib/arm64/ld-android.so (__loader_dlopen+4), but it won’t let me exclude the libOpenCL from the packagingOption, it shouts for missing libOpenCL.
That’s why I didn’t understand how it worked for you if you excluded it from the packaging while your native code actually uses CL API calls

Can you share the relevant part of your Cmake file? What is the path from where you copied your libOpenCl.so?

I tried to use the library located in vendor/lib64, vendor/lib and also in system/lib64. Nothing worked.
I’m building with NDK and linking it directly to the OpenCL library in the following manner:
LOCAL_LDLIBS += -L$(EXTERNAL_PATH)/$(PLATFORM)/$(GPU)/lib/$(APP_ABI) -lOpenCL.

As I understand your way of linking the library, you are wrapping the libOpenCL with your own library opencl-lib and linking this to your program?

Below is a part in android-changes-for-ndk-developers.md:

Private API (Enforced for API level >= 24)

Native libraries must use only public API, and must not link against non-NDK platform libraries. Starting with API 24 this rule is enforced and applications are no longer able to load non-NDK platform libraries. The rule is enforced by the dynamic linker, so non-public libraries are not accessible regardless of the way code tries to load them: System.loadLibrary, DT_NEEDED entries, and direct calls to dlopen(3) will all work exactly the same.

Users should have a consistent app experience across updates, and developers shouldn‘t have to make emergency app updates to handle platform changes. For that reason, we recommend against using private C/C++ symbols. Private symbols aren’t tested as part of the Compatibility Test Suite (CTS) that all Android devices must pass. They may not exist, or they may behave differently. This makes apps that use them more likely to fail on specific devices, or on future releases — as many developers found when Android 6.0 Marshmallow switched from OpenSSL to BoringSSL.

In order to reduce the user impact of this transition, we‘ve identified a set of libraries that see significant use from Google Play’s most-installed apps, and that are feasible for us to support in the short term (including libandroid_runtime.so, libcutils.so, libcrypto.so, and libssl.so). In order to give you more time to transition, we will temporarily support these libraries; so if you see a warning that means your code will not work in a future release – please fix it now!

Hello. I am having the exactly same problem. Do you have any progress on this?

Yes!

What worked for me was to add into the android manifest file a specification for the app to load a vendor library. I did it in the following manner:

<application
    ......
    <uses-native-library android:name="libOpenCL.so"/>
    ......
</application>

In this manner I even didn’t have to package my app with the opencl library but instead the app would access the once provided by the vendor (QUALCOMM in my case).
I assume it accesses the file of public.libraries.txt in the vendor/lib64 to see what libraries are exposed

Has anyone of you found a solution? I’m facing the same issue.

I have copied all required .so files such as libcutils.so, libvndksupport.so, libc++.so, etc. to the jniLibs folder from the /system/lib64 path since libOpenCL.so requires all of these. But, after copying all the libaries, the app crashes at the stage where ld-android.so is called. I’m posting the backtrace here for more details:

2024-03-27 21:30:43.446 24682-24682 DEBUG pid-24682 A #00 pc 0000000000001004 /data/app/~~V_u95z6ithwbxixbJ3Hohw==/com.example.opencltest-v7w12XtotUmr12gJzEibDQ==/base.apk!ld-android.so (offset 0x4000) (__loader_android_link_namespaces+4) (BuildId: 61a1d0fafe0d2b0e25353dbbdfe73925)

2024-03-27 21:30:43.446 24682-24682 DEBUG pid-24682 A #01 pc 00000000000010e0 /data/app/~~V_u95z6ithwbxixbJ3Hohw==/com.example.opencltest-v7w12XtotUmr12gJzEibDQ==/base.apk!libdl_android.so (offset 0x28000) (android_get_exported_namespace+12) (BuildId: 9e8f737153187060d8176c2dbe0a2096)

2024-03-27 21:30:43.446 24682-24682 DEBUG pid-24682 A #02 pc 00000000000011a8 /data/app/~~V_u95z6ithwbxixbJ3Hohw==/com.example.opencltest-v7w12XtotUmr12gJzEibDQ==/base.apk!libvndksupport.so (offset 0x8000) (android_load_sphal_library+328) (BuildId: 3e0086769009296ad00fcff0e3d51a9a)

2024-03-27 21:30:43.446 24682-24682 DEBUG pid-24682 A #03 pc 00000000000221c0 /data/app/~~V_u95z6ithwbxixbJ3Hohw==/com.example.opencltest-v7w12XtotUmr12gJzEibDQ==/base.apk!libOpenCL.so (offset 0x620000) (clGetPlatformIDs+48) (BuildId: 94a79fb140b82c30bd6caa4a6114f5cf)

2024-03-27 21:30:43.446 24682-24682 DEBUG pid-24682 A #04 pc 000000000001dd1c /data/app/~~V_u95z6ithwbxixbJ3Hohw==/com.example.opencltest-v7w12XtotUmr12gJzEibDQ==/base.apk!libopencltest.so (offset 0x704000) (Java_com_example_opencltest_MainActivity_stringFromJNI+108) (BuildId: 16d3c8b48f4ad0eb7d0cd9363bd6e5f0725c622f)

Edit: Within some 15min of posting this, I found the working solution.

What worked:

Adding the exclude option in the build.gradle.kts(:app) + specifying native lib in the AndroidManifest.xml worked

If either of this is not done, it fails.

Background:

I was reading this forum thread from yesterday, but couldn’t find the solution. So, I decided to write this and check if someone responds, and just after posting it, I browsed through all the previous posts once again to see if I missed something. I found that one of the posts with the “exclude option” by the OP @terdev was marked as the solution, and another one by @atwork had said specifying “uses native lib” in the manifest helped solve it. Though I had tried both of those solutions individually, the first “exclude option” wasn’t tried properly with the new Kotlin format, and I had never tried using both the solutions together at the same time. On modifying the “exclude option” to comply with the new kotlin style after googling some more stuff, I was able to add this exclude option properly in addition to the “uses native lib” in the manifest file. And it finally worked without errors or crashes.

Summary:

For the build to succeed, we need to include a libOpenCL.so file and link it in the CMakeLists.txt to the target. But this .so shouldn’t be packaged, and it needs to be excluded by specifying it in the gradle file, but once it is excluded, we need to tell android to use the native library in the manifest file. This can be done by including the following 2 sections:

  1. Add this:
packaging {
jniLibs {

// Exclude a specific lib of all architectures
excludes += "/lib/**/libOpenCL.so"
}
}

under android {} in the build.gradle.kts(:app) file. Directly using the same solution in the post won’t work with Kotlin/the new versions, so we need this. Not sure why we have a lib instead of jniLibs here, but this was tested and found to be working as is.

  1. Add this:
 <uses-native-library android:name="libOpenCL.so"/>

under in the manifest file.

We don’t need to package all the transitive dependencies - such as libcutils, ld-android.so etc. with the app.