android calls third party so Libraries

Keywords: Android Linker Java

First of all, we need to know whether the so Library of the third party is written according to jni standard. If so, it's easy to write a native call directly. If not, it will be more troublesome. We must encapsulate the functions in this so Library in the call, and get to the point below.

Assuming that the library is placed under / system/vendor/lib, named libtest.so, the method we call is get_status. I list how to call app and framewok on the third party, respectively.

First, the third-party app calls, the core here is to use the dlopen function, then use dlsym to find the function, and finally call the function. This is still a company's predecessor taught me, really do not understand c.....

//Define LOGE Printing
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
//Define a pointer function. I don't pass parameters here. You can add parameters here if you want.
typedef int (*CAC_FUNC)();
//Define the path of a so Library
#define LIB_CACULATE_PATH "/system/vendor/lib/libtest.so"
Java_com_flycom_jnitest_MainActivity_intFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    LOGD("cac_func: %s","Java_com_flycom_jnitest_MainActivity_intFromJNI");
    void *handle;
    char *error;
    int r;
    CAC_FUNC cac_func = NULL;
    handle=dlopen(LIB_CACULATE_PATH,RTLD_LAZY);

    LOGD("cac_func: %s","handle");
    if (!handle) {
        LOGD("cac_func2: %s","EXIT_FAILURE");
        exit(EXIT_FAILURE);
    }
    //Clear up previous errors
    dlerror();
    //Get a function
    LOGD("cac_func2: %s","get_status");
    *(void **) (&cac_func) = dlsym(handle, "get_status");
   
    if ((error = dlerror()) != NULL)  {
        LOGD("cac_func: %s","error");
        exit(EXIT_FAILURE);
    }
   //Call this function
    r =  (*cac_func)();

    LOGD("cac_func: %d\n", r);
    //Close dynamic link libraries
    dlclose(handle);
    return r;

}

Then use System. load Library to load your own library and write a native call.

 static {
        System.loadLibrary("native-lib");
 }
 public native int intFromJNI();

Now let's talk about the pits we encountered.

This error occurred during the call, and the God on the Internet solved it, mainly because there was no permission.

E/linker: library "/system/vendor/lib/libkphproxy.so" ("/vendor/lib/libkphproxy.so") needed or dlopened by "/data/app/com.flycom.jnitest-mKVoy6YOwxW_DNa_RgRhMQ==/lib/arm/libnative-lib.so" is not accessible for the namespace: [name="classloader-namespace", ld_library_paths="", default_library_paths="/data/app/com.flycom.jnitest-mKVoy6YOwxW_DNa_RgRhMQ==/lib/arm:/data/app/com.flycom.jnitest-mKVoy6YOwxW_DNa_RgRhMQ==/base.apk!/lib/armeabi-v7a", permitted_paths="/data:/mnt/expand:/data/data/com.flycom.jnitest"]

In framework/vendor/etc directory, public.libraries.txt, from the name of this file, you can probably know the meaning of it. If not, you can create a new one, add the name of so library you call, note that it must be the full name, such as my libtest.so. There is also this file under the system/et folder, of course, for the so Library of system/lib. If you want to access the so Library of system/lib, Please add it here.

Next, let's talk about adding to the framework layer, such as com_android_server_SystemServer.cpp.

The call to jni is the same.

static void android_server_SystemServer_startHidlServices(JNIEnv* env, jobject /* clazz */) {
    using ::android::frameworks::schedulerservice::V1_0::ISchedulingPolicyService;
    using ::android::frameworks::schedulerservice::V1_0::implementation::SchedulingPolicyService;
    using ::android::frameworks::sensorservice::V1_0::ISensorManager;
    using ::android::frameworks::sensorservice::V1_0::implementation::SensorManager;
    using ::android::hardware::configureRpcThreadpool;

    status_t err;

    configureRpcThreadpool(5, false /* callerWillJoin */);

    JavaVM *vm;
    LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Cannot get Java VM");

    sp<ISensorManager> sensorService = new SensorManager(vm);
    err = sensorService->registerAsService();
    ALOGE_IF(err != OK, "Cannot register %s: %d", ISensorManager::descriptor, err);

    sp<ISchedulingPolicyService> schedulingService = new SchedulingPolicyService();
    err = schedulingService->registerAsService();
    ALOGE_IF(err != OK, "Cannot register %s: %d", ISchedulingPolicyService::descriptor, err);
}
//The name here is taken at will.
static jint android_server_SystemServer_verifyStatus(JNIEnv*, jobject /* clazz */) {
	LOGD("cac_func2: %s","Java_com_flycom_jnitest_MainActivity_intFromJNI");
    
  LOGD("cac_func: %s","Java_com_flycom_jnitest_MainActivity_intFromJNI");
    void *handle;
    char *error;
    int r;
    CAC_FUNC cac_func = NULL;
    handle=dlopen(LIB_CACULATE_PATH,RTLD_LAZY);

    LOGD("cac_func: %s","handle");
    if (!handle) {
        LOGD("cac_func2: %s","EXIT_FAILURE");
        exit(EXIT_FAILURE);
    }
    //Clear up previous errors
    dlerror();
    //Get a function
    LOGD("cac_func2: %s","get_status");
    *(void **) (&cac_func) = dlsym(handle, "get_status");
   
    if ((error = dlerror()) != NULL)  {
        LOGD("cac_func: %s","error");
        exit(EXIT_FAILURE);
    }
   //Call this function
    r =  (*cac_func)();

    LOGD("cac_func: %d\n", r);
    //Close dynamic link libraries
    dlclose(handle);
    return r;
}

There are many pits encountered here. Note that the function must be registered, otherwise no method can be found. The first parameter is easy to understand with the third parameter. The key second parameter "() I", which is in parentheses, is the passed parameter. My method has no return value, so it is empty. The latter "I" represents the return type of int, which can be found online.

/*
 * JNI registration.
 */
static const JNINativeMethod gMethods[] = {
    /* name, signature, funcPtr */
    { "startSensorService", "()V", (void*) android_server_SystemServer_startSensorService },
    { "startHidlServices", "()V", (void*) android_server_SystemServer_startHidlServices },
	{ "verifyStatus", "()I", (void*) android_server_SystemServer_verifyStatus },
};

Calls here do not require permissions from public.libraries.txt. Then there is a more exotic problem, that is, I call the same function in the framework woke layer, and the result is different from that of app. This problem has troubled me for a day. Finally, the merchants who provided so libraries were asked, only to find that it was a matter of authority.

Call in app has added permissions, but not in system_server. Add access permissions in device/mediatek/sepolicy/bsp/non_plat/system_server.te file

allow system_server tkcore_admin_device:chr_file  { ioctl read write open };
Finally, the call succeeded...


Posted by hasitha on Thu, 09 May 2019 17:12:39 -0700