我是一个从未使用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"
?答案 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