I want to use the ASI SDK (prebuilt binary) in an Android application. I am using Android Studio 2.1.3 on Windows 10 with the gradle "experimental plugin" and Android NDK r12b.
My JNI test method that calls a basic SDK function looks as follows:
#include <jni.h>
#include <stdio.h>
#include <ASICamera2.h>
JNIEXPORT jstring JNICALL
Java_at_wana_androguide_MainActivity_getMsgFromJni(JNIEnv *env, jobject instance)
{
char str[512];
int numCams = ASIGetNumOfConnectedCameras();
snprintf(str, sizeof(str), "Connected cameras: %d", numCams);
return env->NewStringUTF(str);
}
The build.gradle
for the app
module looks like this:
apply plugin: 'com.android.model.application'
model {
android {
compileSdkVersion 24
buildToolsVersion "24.0.2"
defaultConfig {
applicationId "at.wana.androguide"
minSdkVersion.apiLevel 19
targetSdkVersion.apiLevel 24
versionCode 1
versionName "0.1"
}
buildTypes {
release {
minifyEnabled false
proguardFiles.add(file('proguard-android.txt'))
}
}
ndk {
moduleName "hello-android-jni"
abiFilters.add("arm64-v8a")
abiFilters.add("x86")
stl "gnustl_static"
}
sources {
main {
jni {
dependencies {
library "ASISDK" linkage "static"
project ":usb" linkage "shared"
}
}
}
}
}
repositories {
libs(PrebuiltLibraries) {
ASISDK {
headers.srcDir "src/main/jni/drivers/ASI/include"
binaries.withType(StaticLibraryBinary) {
staticLibraryFile = file("src/main/jni/drivers/ASI/lib/${targetPlatform.getName()}/libASICamera2.a")
}
}
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:24.2.0'
compile 'com.squareup:otto:1.3.8'
}
Since the ASI SDK depends on libusb
, I also added the libusb
sources as a separate module and imported is as a dependency into the app
module. This is the build.gradle
file for the libusb
module (called "usb"):
apply plugin: "com.android.model.native"
model {
android {
compileSdkVersion 24
buildToolsVersion "24.0.2"
ndk {
moduleName "usb"
CFlags.add("-I${file("src/main/jni")}".toString())
CFlags.add("-I${file("src/main/jni/os")}".toString())
ldLibs.addAll(["log"])
}
}
}
Problem:
This code builds OK, but when I run it in Genymotion (x86), Android 5, it crashes with a runtime exception:
java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "stderr" referenced by "libhello-android-jni.so"..
I tried adding supc++
and/or stdc++
to ldFlags
, I tried changing the filename extension to cpp
and back to c
, and I already tried setting the platformVersion
to 19 or even 9 in the build.gradle files, but this only resulted in a compile time error saying that stderr
is not defined:
C:\Users\greuff\Documents\devel\AndroGuide\app\src\main\jni\drivers\ASI\lib\x86\libASICamera2.a(ASICamera2.o):ASICamera2.cpp:function ASIGetNumOfConnectedCameras: error: undefined reference to 'stderr' collect2.exe: error: ld returned 1 exit status
Curiously, this error only occurs for the x86
platform target.
I read that stderr
etc were removed from Android NDK Headers at a certain point in time because they became real functions in libc
, but I'm not quite sure how to solve this problem since setting platformVersion
to a lower value (as suggested in some questions) did not help. I would be very grateful for pointers in the right direction.
Turns out I was chasing the wrong thing. The ASI SDK was statically compiled against the glibc which contains stderr
as globally available symbols, whereas bionic (the Android libc) doesn't contain them.
All I had to do was to undefine stderr
and created it myself as a linker symbol, so the linker can find it:
#include <jni.h>
#include <stdio.h>
#include <ASICamera2.h>
#undef stderr
FILE *stderr = &__sF[2];
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With