前言

记录修改linphone-sdk-android过程,计划分为上、中、下三篇

本文是上篇,本篇仅记录下书问题2的初步排查过程,尽量描述排查问题过程中的思路与方向

余下两篇记录问题1、2的修改过程

背景

接上文编译linphone-sdk-android

项目中使用的linphone-sdk-android版本为4.5.x,使用过程中发现以下两个问题:

  1. 打开音频编解码G722、G729时,发起呼叫的INVITE SDP中,没有G722、G729的RTP MAP,当时以为是linphone的bug,后面看源码及查资料发现可能不是bug,这里先按下不表
  2. 使用sdk提供的JavaLogger输出日志时,伪代码:mFactory.getLoggingService().addListener(mAndroidLoggingService);,偶现JNI崩溃问题
    --------- beginning of crash
2022-04-11 14:16:22.350 1142-1430/? A/libc: Fatal signal 6 (SIGABRT), code -6 in tid 1430 (RealLinphonePro)
2022-04-11 14:16:22.441 3756-3756/? A/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
2022-04-11 14:16:22.442 3756-3756/? A/DEBUG: Build fingerprint: 'Android/rk3288/rk3288:7.1.2/NHG47K/builde03162201:userdebug/test-keys'
2022-04-11 14:16:22.444 3756-3756/? A/DEBUG: Revision: '0'
2022-04-11 14:16:22.446 3756-3756/? A/DEBUG: ABI: 'arm'
2022-04-11 14:16:22.447 3756-3756/? A/DEBUG: pid: 1142, tid: 1430, name: RealLinphonePro  >>> com.guodong.android.linphone <<<
2022-04-11 14:16:22.448 3756-3756/? A/DEBUG: signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
2022-04-11 14:16:22.454 3756-3756/? A/DEBUG: Abort message: 'art/runtime/indirect_reference_table.cc:80] JNI ERROR (app bug): accessed deleted WeakGlobal 0x21ab'
2022-04-11 14:16:22.456 3756-3756/? A/DEBUG:     r0 00000000  r1 00000596  r2 00000006  r3 00000008
2022-04-11 14:16:22.457 3756-3756/? A/DEBUG:     r4 89aff978  r5 00000006  r6 89aff920  r7 0000010c
2022-04-11 14:16:22.459 3756-3756/? A/DEBUG:     r8 00000043  r9 aaa7eef0  sl 0000000a  fp 89d04400
2022-04-11 14:16:22.461 3756-3756/? A/DEBUG:     ip 0000000b  sp 89afef88  lr ab175857  pc ab1780c0  cpsr 600b0010
2022-04-11 14:16:22.509 3756-3756/? A/DEBUG: backtrace:
2022-04-11 14:16:22.511 3756-3756/? A/DEBUG:     #00 pc 0004a0c0  /system/lib/libc.so (tgkill+12)
2022-04-11 14:16:22.512 3756-3756/? A/DEBUG:     #01 pc 00047853  /system/lib/libc.so (pthread_kill+34)
2022-04-11 14:16:22.514 3756-3756/? A/DEBUG:     #02 pc 0001d8b5  /system/lib/libc.so (raise+10)
2022-04-11 14:16:22.515 3756-3756/? A/DEBUG:     #03 pc 00019401  /system/lib/libc.so (__libc_android_abort+34)
2022-04-11 14:16:22.517 3756-3756/? A/DEBUG:     #04 pc 00017048  /system/lib/libc.so (abort+4)
2022-04-11 14:16:22.518 3756-3756/? A/DEBUG:     #05 pc 0031d8cd  /system/lib/libart.so (_ZN3art7Runtime5AbortEPKc+328)
2022-04-11 14:16:22.520 3756-3756/? A/DEBUG:     #06 pc 000b5503  /system/lib/libart.so (_ZN3art10LogMessageD2Ev+1134)
2022-04-11 14:16:22.521 3756-3756/? A/DEBUG:     #07 pc 001bd0ff  /system/lib/libart.so (_ZN3art22IndirectReferenceTable17AbortIfNoCheckJNIERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE+134)
2022-04-11 14:16:22.523 3756-3756/? A/DEBUG:     #08 pc 0023ecaf  /system/lib/libart.so (_ZNK3art22IndirectReferenceTable10GetCheckedEPv+250)
2022-04-11 14:16:22.525 3756-3756/? A/DEBUG:     #09 pc 0023c05b  /system/lib/libart.so (_ZN3art9JavaVMExt16DecodeWeakGlobalEPNS_6ThreadEPv+30)
2022-04-11 14:16:22.526 3756-3756/? A/DEBUG:     #10 pc 00337679  /system/lib/libart.so (_ZNK3art6Thread13DecodeJObjectEP8_jobject+164)
2022-04-11 14:16:22.528 3756-3756/? A/DEBUG:     #11 pc 00265843  /system/lib/libart.so (_ZN3art3JNI11NewLocalRefEP7_JNIEnvP8_jobject+406)
2022-04-11 14:16:22.530 3756-3756/? A/DEBUG:     #12 pc 0060eff9  /data/app/com.guodong.android.linphone-1/lib/arm/liblinphone.so (getLoggingService+88)
2022-04-11 14:16:22.531 3756-3756/? A/DEBUG:     #13 pc 0061a977  /data/app/com.guodong.android.linphone-1/lib/arm/liblinphone.so
2022-04-11 14:16:22.533 3756-3756/? A/DEBUG:     #14 pc 005ef911  /data/app/com.guodong.android.linphone-1/lib/arm/liblinphone.so
2022-04-11 14:16:22.535 3756-3756/? A/DEBUG:     #15 pc 00025437  /data/app/com.guodong.android.linphone-1/lib/arm/libbctoolbox.so (bctbx_logv+182)
2022-04-11 14:16:22.536 3756-3756/? A/DEBUG:     #16 pc 006f5061  /data/app/com.guodong.android.linphone-1/lib/arm/liblinphone.so
2022-04-11 14:16:22.538 3756-3756/? A/DEBUG:     #17 pc 006f51d9  /data/app/com.guodong.android.linphone-1/lib/arm/liblinphone.so (wake_lock_acquire+152)
2022-04-11 14:16:22.539 3756-3756/? A/DEBUG:     #18 pc 006601c5  /data/app/com.guodong.android.linphone-1/lib/arm/liblinphone.so
2022-04-11 14:16:22.541 3756-3756/? A/DEBUG:     #19 pc 00660b27  /data/app/com.guodong.android.linphone-1/lib/arm/liblinphone.so (belle_sip_client_transaction_init+138)
2022-04-11 14:16:22.542 3756-3756/? A/DEBUG:     #20 pc 006fb1d3  /data/app/com.guodong.android.linphone-1/lib/arm/liblinphone.so (belle_sip_nict_new+30)
2022-04-11 14:16:22.544 3756-3756/? A/DEBUG:     #21 pc 0065c3a7  /data/app/com.guodong.android.linphone-1/lib/arm/liblinphone.so (belle_sip_provider_create_client_transaction+46)
2022-04-11 14:16:22.546 3756-3756/? A/DEBUG:     #22 pc 0065dec3  /data/app/com.guodong.android.linphone-1/lib/arm/liblinphone.so
2022-04-11 14:16:22.547 3756-3756/? A/DEBUG:     #23 pc 0065daf7  /data/app/com.guodong.android.linphone-1/lib/arm/liblinphone.so (belle_sip_refresher_refresh+28)
2022-04-11 14:16:22.549 3756-3756/? A/DEBUG:     #24 pc 005fac23  /data/app/com.guodong.android.linphone-1/lib/arm/liblinphone.so (linphone_proxy_config_refresh_register+34)
2022-04-11 14:16:22.550 3756-3756/? A/DEBUG:     #25 pc 005e9fc5  /data/app/com.guodong.android.linphone-1/lib/arm/liblinphone.so (linphone_core_refresh_registers+40)
2022-04-11 14:16:22.552 3756-3756/? A/DEBUG:     #26 pc 019fc3bf  /data/app/com.guodong.android.linphone-1/oat/arm/base.odex (offset 0x18de000)
2022-04-11 14:16:23.096 227-255/? I/AudioFlinger: BUFFER TIMEOUT: remove(4099) from active list on thread 0xabd03e00

分析

问题2

通过崩溃日志第27行2022-04-11 14:16:22.530 3756-3756/? A/DEBUG: #12 pc 0060eff9 /data/app/com.guodong.android.linphone-1/lib/arm/liblinphone.so (getLoggingService+88)可以判断崩溃是在getLoggingService()这个方法里

如此需要先找到getLoggingService()方法的源码,先在Source Insight中搜索getLoggingService(),搜索一圈发现没有,猜想此方法应该是编译后自动生成的

在Ubuntu编译环境里找找,通过find命令查找包含getLoggingService文本的文件

$ cd linphone-sdk/build/
$ find . -type f | xargs grep "getLoggingService"
./WORK/android-armv7/Build/linphone/wrappers/java/src/linphone_jni.cc:JNIEXPORT jobject JNICALL getLoggingService(JNIEnv *env, LinphoneLoggingService *cptr, bool_t takeref) {./WORK/android-armv7/Build/linphone/wrappers/java/src/linphone_jni.cc:  jobject j_logService = getLoggingService(env, (LinphoneLoggingService *)logService, TRUE);
./WORK/android-armv7/Build/linphone/wrappers/java/src/linphone_jni.cc:  jobject jni_result = (jobject)getLoggingService(env, (LinphoneLoggingService *)linphone_logging_service_get(), TRUE);

找到了bingo~

打开linphone_jni.ccgetLoggingService()方法体如下:

JNIEXPORT jobject JNICALL getLoggingService(JNIEnv *env, LinphoneLoggingService *cptr, bool_t takeref) {jobject jobj = nullptr;if (cptr != nullptr) {void *up = belle_sip_object_data_get((belle_sip_object_t *)cptr, belle_sip_java_user_data_key);LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_factory_get_user_data(linphone_factory_get());if (!ljb) {ljb = new LinphoneJavaBindings(env);linphone_factory_set_user_data(linphone_factory_get(), ljb);}jclass linphone_logging_service_class = ljb->linphone_logging_service_class;jmethodID linphone_logging_service_constructor = ljb->linphone_logging_service_class_constructor;if (up == nullptr) {jobj = env->NewObject(linphone_logging_service_class, linphone_logging_service_constructor, (jlong)cptr);belle_sip_object_data_set((belle_sip_object_t *)cptr, belle_sip_java_user_data_key, (void*)env->NewWeakGlobalRef(jobj), nullptr);if (takeref)linphone_logging_service_ref(cptr);} else {jobj = env->NewLocalRef((jobject)up);if (jobj == nullptr) {// Delete weak ref ?env->DeleteWeakGlobalRef((jobject)up);// takes implicit local refjobj = env->NewObject(linphone_logging_service_class, linphone_logging_service_constructor, (jlong)cptr);belle_sip_object_data_set((belle_sip_object_t *)cptr, belle_sip_java_user_data_key, (void*)env->NewWeakGlobalRef(jobj), nullptr);if (takeref)linphone_logging_service_ref(cptr);}}}return jobj;
}

嗯,看起来没啥问题,也有判空处理,一时间摸不着头绪,先在getLoggingService()方法中加点日志输出看看吧

前面说linphone_jni.cc是自动生成的,现在需要找到自动生成linphone_jni.cc的代码,根据崩溃日志可以发现getLoggingService()linphone.so中,而源码中有liblinphone这个目录,先在这个目录下找找吧,通过find命令查找文件名中包含jni的文件

$ cd linphone-sdk/liblinphone/
$ find . -name *jni*
./coreapi/linphonecore_jni.cc
./tools/lpc2xml_jni.cc
./tools/xml2lpc_jni.cc
./tools/my_jni.h
./wrappers/java/jni.mustache

查找出来多个文件,既然linphone_jni.cc是自动生成的,所以可以确定.cc.h后缀的几个文件肯定不是,排除后只剩下这个jni.mustache文件,打开文件vim ./wrappers/java/jni.mustache注释第一行就是linphone_jni.cc,太棒了,找到自动生成的代码了

通过一些查看,并与linphone_jni.cc中的实现对比,锁定了以下代码即为自动生成的模板代码:

290 {{#objects}}
291 JNIEXPORT jobject JNICALL get{{className}}(JNIEnv *env, {{classCName}} *cptr, bool_t takeref) {292         jobject jobj = nullptr;
293
294         if (cptr != nullptr) {295                 void *up = belle_sip_object_data_get((belle_sip_object_t *)cptr, belle_sip_java_user_data_key);
296                 LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_factory_get_user_data(linphone_factory_get());
297                 if (!ljb) {298                         ljb = new LinphoneJavaBindings(env);
299                         linphone_factory_set_user_data(linphone_factory_get(), ljb);
300                 }
301
302                 jclass {{cPrefix}}_class = ljb->{{cPrefix}}_class;
303                 jmethodID {{cPrefix}}_constructor = ljb->{{cPrefix}}_class_constructor;
304
305                 if (up == nullptr) {306                         jobj = env->NewObject({{cPrefix}}_class, {{cPrefix}}_constructor, (jlong)cptr);
307                         belle_sip_object_data_set((belle_sip_object_t *)cptr, belle_sip_java_user_data_key, (void*)env->NewWeakGlobalRef(jobj), nullptr);
308                         if (takeref)
309                                 {{#refCountable}}{{cPrefix}}_ref(cptr);{{/refCountable}}
310                 } else {311                         jobj = env->NewLocalRef((jobject)up);
312                         if (jobj == nullptr) {313                                 // Delete weak ref ?
314                                 env->DeleteWeakGlobalRef((jobject)up);
315                                 // takes implicit local ref
316                                 jobj = env->NewObject({{cPrefix}}_class, {{cPrefix}}_constructor, (jlong)cptr);
317                                 belle_sip_object_data_set((belle_sip_object_t *)cptr, belle_sip_java_user_data_key, (void*)env->NewWeakGlobalRef(jobj), nullptr);
318                                 if (takeref)
319                                         {{#refCountable}}{{cPrefix}}_ref(cptr);{{/refCountable}}
320                         }
321                 }
322         }
323         return jobj;
324 }

这里linphone-sdk使用了mustache,还记得在上篇编译Linphone-SDK-Android中有安装pip3 install pystachepystachemustache的Python实现,mustache的语法比较简单,在github上看一眼文档,再跟着源码比着葫芦画瓢,应该就差不多了

好的,学习完mustache的语法,了解到高级用法可以传一个配置文件进行渲染,正好与jni.mustache同级目录中有个genwrapper.py文件,打开此文件,里面定义了很多类,其中有个Jni的类,里面有些字段与jni.mustache中的标签正好对应,就是它了

class Jni:def add_object(self, javaClass):if javaClass.className == 'Factory':returnobj = {'jniPrefix': self.jni_package,'jniPath': self.jni_path,'cPrefix': javaClass.cPrefix,'className': javaClass.className,'classCName': javaClass.cName,'classImplName': javaClass.classImplName,'refCountable': javaClass.refCountable,'notRefCountable': not javaClass.refCountable,}self.objects.append(obj)

happy~万事具备,现在可以修改源码,添加一些日志输出了

因为在jni.mustache中模板方法get{{className}}是可以生成多个以get开头的方法,现在需要判断{{className}}是不是等于LoggingService,而在mustache中没有发现比较字符串是否相同的语法,所以在genwrapper.pyJni类中新增一个isLoggingService字段表示是否是getLoggingService()方法

class Jni:def add_object(self, javaClass):if javaClass.className == 'Factory':returnobj = {'jniPrefix': self.jni_package,'jniPath': self.jni_path,'cPrefix': javaClass.cPrefix,'className': javaClass.className,'classCName': javaClass.cName,'classImplName': javaClass.classImplName,'refCountable': javaClass.refCountable,'notRefCountable': not javaClass.refCountable,'isLoggingService': javaClass.className == 'LoggingService',}self.objects.append(obj)

然后修改jni.mustache文件,增加日志,输出up指针指向的地址,up指针转成jobject后与NULLnullptr比较的结果,判断up是否已经被回收了

这里说一下代码的大概意思,up指针从belle_sip_object_data_get方法中通过belle_sip_java_user_data_key这个Key获取,可以简单理解为Java中的Map;如果up为空,则调用Java方法创建一个对象,将创建的Java对象通过NewWeakGlobalRef方法转换为全局弱引用,再通过belle_sip_object_data_set方法保存起来;如果up不为空,则强转为jobject,判断jobject是否为空,为空则删除全局弱引用,再创建保存

{{#objects}}
JNIEXPORT jobject JNICALL get{{className}}(JNIEnv *env, {{classCName}} *cptr, bool_t takeref) {jobject jobj = nullptr;if (cptr != nullptr) {void *up = belle_sip_object_data_get((belle_sip_object_t *)cptr, belle_sip_java_user_data_key);LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_factory_get_user_data(linphone_factory_get());if (!ljb) {ljb = new LinphoneJavaBindings(env);linphone_factory_set_user_data(linphone_factory_get(), ljb);}jclass {{cPrefix}}_class = ljb->{{cPrefix}}_class;jmethodID {{cPrefix}}_constructor = ljb->{{cPrefix}}_class_constructor;{{#isLoggingService}}#ifdef __ANDROID____android_log_print(ANDROID_LOG_DEBUG, "guodongAndroid", "up = %p", up);jobject temp_jobj1 = (jobject)up;jboolean up_available1 = env->IsSameObject(temp_jobj1, NULL);__android_log_print(ANDROID_LOG_DEBUG, "guodongAndroid", "up_available1 = %d", up_available1);jobject temp_jobj2 = (jobject)up;jboolean up_available2 = env->IsSameObject(temp_jobj2, nullptr);__android_log_print(ANDROID_LOG_DEBUG, "guodongAndroid", "up_available2 = %d", up_available2);#endif /* __ANDROID__ */{{/isLoggingService}}if (up == nullptr) {jobj = env->NewObject({{cPrefix}}_class, {{cPrefix}}_constructor, (jlong)cptr);belle_sip_object_data_set((belle_sip_object_t *)cptr, belle_sip_java_user_data_key, (void*)env->NewWeakGlobalRef(jobj), nullptr);if (takeref){{#refCountable}}{{cPrefix}}_ref(cptr);{{/refCountable}}} else {jobj = env->NewLocalRef((jobject)up);if (jobj == nullptr) {// Delete weak ref ?env->DeleteWeakGlobalRef((jobject)up);// takes implicit local refjobj = env->NewObject({{cPrefix}}_class, {{cPrefix}}_constructor, (jlong)cptr);belle_sip_object_data_set((belle_sip_object_t *)cptr, belle_sip_java_user_data_key, (void*)env->NewWeakGlobalRef(jobj), nullptr);if (takeref){{#refCountable}}{{cPrefix}}_ref(cptr);{{/refCountable}}}}}return jobj;
}

好的,修改完源码保存后,就可以编译了

$ cd linphone-sdk/build/
$ cmake --build . --parallel 8

等待编译完成,拷贝出来编译好的aar,放到Android Studio中运行,查看Logcat输出

修改linphone-sdk-android-上篇相关推荐

  1. 搭建Jenkins+Sonarqub+Mysql+Android(上篇)

    搭建Jenkins+Sonarqub+Mysql+Android(上篇) 本人阐述的是在Ubuntu16.04系统下搭建jenkins+sonarqub+mysql以实现对Android工程一键自动化 ...

  2. Linphone SDK 源码编译

    Linphone SDK 源码编译 一.环境准备 编译环境 系统:Ubuntu – 建议使用Ubuntu,其他的系统可能有某些依赖存在问题,编译报错 Android SDK r24.2 Android ...

  3. Linphone SDK 最新版移植 iOS版

    Linphone SDK 最新版移植 iOS版 主要集成了linphone的官网sdk,再结合官网的demo实现了简单的拨打sip电话功能,解决了网上linphone集成复杂,官网demo运行不了,官 ...

  4. Android SDK Android NDK 官方下载地址(zt)

    Android SDK Android NDK 官方下载地址 Android SDK 3.0 Windows http://dl.google.com/android/installer_r10-wi ...

  5. Error:Android Source Generator: [sdk] Android SDK is not specified.

    有时候使用intellij idea 带入android 项目,运行提示Error:Android Source Generator: [sdk] Android SDK is not specifi ...

  6. 如何修改eclipse 中Android的预览layout布局背景颜色

    如何修改eclipse 中Android的预览layout布局背景颜色 最近在学习有关于主题和style方面的东西,不知道自己搞了什么东西,layout文件在预览的时候背景颜色总是黑色的,但是运行出来 ...

  7. 修改React Native Android'默认字体颜色为黑色

    修改React Native Android'默认字体颜色为黑色 找到res/values/styles.xml文件插入代码 <style name="AppTheme" p ...

  8. 微信用户ios android比例,微信号可以修改了!Android 版正全量上线,iOS 也快了

    原标题:微信号可以修改了!Android 版正全量上线,iOS 也快了 被多次问到的微信号修改问题,终于在今天得到了解答. 微信刚刚发布公告:最新 Android 版微信已上线修改微信号的功能,iOS ...

  9. android Linphone SDK

    LinphoneLauncherActivity 是APP的入口组件,在这个组件里,它会启动LinphoneService这个后台服务,然后不断地判断这个后台服务是否已经启动完毕,如果已经启动完毕后, ...

  10. android studio修改配置文件夹(.android .gradle .AndroidStudio)位置

    Android studio安装之后一般默认在c:/user/userid(*****)/;(比如:c:/user/xiaohong/)其他软件在安装中要创建缓存文件夹,那么也会在这个目录创建,比如N ...

最新文章

  1. c+和python的区别-python和c先学哪个
  2. 将表数据生成Insert脚本
  3. ECCV 2012 CSK:《Exploiting the circulantstructure of tracking-by-detection with kernels》论文笔记
  4. Sublime Text3怎样在Deepin中配置CTags插件
  5. E2. Square-free division (hard version) dp + 质因子分解
  6. java iso-8859-1_如何在Java中的ISO-8859-1和UTF-8之间转换?
  7. javascript 创建ajax函数 四部曲
  8. 发表email所需要
  9. java中volatile关键字_Java中Volatile关键字详解
  10. 小米平板2wifi驱动下载_小米WiFi驱动官方下载_Xiaomi小米随身WiFi驱动官方最新版下载-华军软件园...
  11. 基于ENVI下的土地利用信息提取(三)
  12. P3376 (最大流 dinic)
  13. 超详细讲解。QT+OpenGL画出不同纹理面立方体(部分面可反色)
  14. 用python贴吧自动回帖_python基于selenium实现贴吧自动发帖
  15. ps图层模式详解带计算公式
  16. 特征工程中的数据标准化
  17. 舔狗日记-土味情话-每日一言三合一小程序源码下载带安装教程
  18. Hie with the Pie (状压 DP)
  19. webpack打包vue项目之后dist文件夹在本地跑起来
  20. 《Windows 8 权威指南》——1.4 易用性

热门文章

  1. 单/多因素协方差分析
  2. html下拉列表自动打开,HTML SELECT 标签自动显示下拉选项
  3. Lie to me 观后感
  4. css知识,解决超长49寸显示器DIV被压扁的问题。
  5. CapsNet入门系列之三:囊间动态路由算法
  6. 浏览器全屏显示设置方法
  7. Cocos creator常驻节点使用方式addPersistRootNode
  8. python空间复杂度是指_第16话:算法的空间复杂度
  9. 百度MIP技术 - MIP移动网页加速器
  10. JS(JavaScript)入门设置密码框中点击小眼睛显示隐藏所输入的密码!