共享对象,符号,C / C ++库链接和加载

时间:2018-09-02 08:18:22

标签: android c++ android-ndk

背景

我是一个从未使用NDK进行编程的人。决不。以前,我曾经用C和C ++编写代码,但是那是那时。目前,我像其他许多人一样,全职使用Java编写Android Apps。

注意: 这个问题不是关于Android的,而是关于共享对象,C / C ++中的链接库,符号生成和类似。因此,您不需要Android专业知识来回答它。

第二,对于所有不熟悉NDK的人来说,它只是用于“交谈”作为共享对象(在基于Unix的Android(基于Unix)上存在)的本地C / C ++库的工具。


问题:

现在,在尝试用Android编写呼叫记录器应用程序时,经过3天的编程苦难,我发现了事实:

除非您准备好使用JNI,NDK,C / C ++等,否则根本无法使用标准框架Java API在Android上编写全功能的呼叫记录器。

从昨天晚上开始,我就这样做了。深入到代码的C / C ++部分,其他应用已经完成了一件事情来成功记录呼叫:利用libmedia.so,这是大多数供应商专有的库,市场上的Android设备访问某些媒体功能)。如果找不到,那么...我不明白this家伙做了什么:

int load(JNIEnv *env, jobject this) {
    void *handleLibMedia;
    void *handleLibUtils;
    int result = -1;
    lspr func = NULL;

//    pthread_t newthread = (pthread_t) thiz;
    pthread_t newthread = (pthread_t) thiz;

    handleLibMedia = dlopen("libmedia.so", RTLD_NOW | RTLD_GLOBAL);
    if (handleLibMedia != NULL) {
        func = dlsym(handleLibMedia, "_ZN7android11AudioSystem13setParametersEiRKNS_7String8E");
        if (func != NULL) {
//            result = func(env, thiz);
            result = 0;
        }
        audioSetParameters = (lasp) func;
    } else {
        result = -1;
    }

    handleLibUtils = dlopen("libutils.so", RTLD_NOW | RTLD_GLOBAL);
    if (handleLibUtils != NULL) {
        fstr = dlsym(handleLibUtils, "_ZN7android7String8C2EPKc");
        if (fstr == NULL) {
            result = -1;
        }
    } else {
        result = -1;
    }

    cmd = CM_D;

    int resultTh = pthread_create(&newthread, NULL, taskAudioSetParam, NULL);

//    dlclose(handleLibMedia);
//    dlclose(handleLibUtils);

    return result;
}

通过它,我得到一个大概的想法:它会检查名为 libmedia.so 的库,如果找不到它,它将尝试找到一个名为{{1 }}:

dlsym()

您可以看到吓人字符串func = dlsym(handleLibMedia, "_ZN7android11AudioSystem13setParametersEiRKNS_7String8E"); 您也可以在VLC Player的Android应用程序中找到它:

https://github.com/mstorsjo/vlc-android/blob/master/android-libs/libmedia.symbols

问题:

  • 什么是字符串/符号"_ZN7android11AudioSystem13setParametersEiRKNS_7String8E"
  • 这是什么pthread_t?
  • 我如何与JNI一起了解这一点?还是我在使用JNI进行编程时能够知道的最低要求和警告是什么?

2 个答案:

答案 0 :(得分:4)

_ZN7android11AudioSystem13setParametersEiRKNS_7String8E是函数的mangled name

android::AudioSystem::setParameters(int, android::String8 const&)

libmedia库显然是用C ++编写的,因此其功能名称已被修改。通常,您将让编译器处理插入代码以动态链接到该库,但是如果您希望避免对它的硬依赖性并在运行时加载它,则将需要使用错误的名称来从中加载符号。

一个快速的Google没有透露该功能的任何文档,但是我确实找到了一些旧的source code。但是请注意,该文件来自该存储库的当前master branch


pthread_t是POSIX线程库用来保存线程ID的类型。为什么用newthread的值初始化thiz,我不知道。以后对pthread_create的调用将覆盖该值,并且该变量永远不会在此之前用作对AutioSystem::setParameters的注释掉调用的参数。


关于第三个问题,这是一个非常广泛的话题。不过,不加载未记录的内部库将是一个很好的建议。

答案 1 :(得分:0)

测试了“这个家伙”(Victor D)的应用,并且没有双向记录。语音通话期间仅会录制麦克风,就像其他很多狗屎录制应用程序一样。选择“语音通信”或“语音下行链路”会产生俄语错误消息...有一个应用程序可以解决问题,而NLL APPS就是ACR。不幸的是,它是开源的。但是我很好奇他们是如何做到的。后者的软件包中有两个低级库,分别是libacr.so和libencoder.so。 Libacr.so具有不同的导出JNI函数来记录呼叫。 https://onlinedisassembler.com/odaweb/pKO4xRfF