1. 问题现象

​ adb用着用着就不好使了,然后出现黑屏,伴随着有时候串口也不好使。

2.应急补救措施

​ 测试同学如果遇到adb用着用着突然不好使了,请使用如下手顺首先恢复串口或者adb口好使,然后取一下相关日志给到开发。
![adb突然不好使应急措施]adb突然不好使应急措施.png

3.问题调查

​ 经过上面手顺发现是

  • 有一台车机是adbd服务挂掉了,通过start adbd重启adb服务之后就可以恢复正常使用了。导出tombstone文件,分析问题发生原因。
  • 有一台车是adb口的模式属性值被设置成host模式。

3.1 查看tombstone日志

为什么看tombstone日志呢,因为logcat中着实看不出什么问题来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'qti/msmnile_gvmq/msmnile_gvmq:9/PQ1A.190105.004/root07251158:userdebug/test-keys'
Revision: '0'
ABI: 'arm64'
pid: 6911, tid: 6911, name: cockpit.settings >>> com.gxatek.cockpit.settings <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x19
Cause: null pointer dereference // 空指针异常
x0 00000000000003e7 x1 0000000000000018 x2 0000000000000000 x3 0000000000000001
x4 0000000000000000 x5 0000007ff5c5b180 x6 64636e4c3c04ff3c x7 0000000000000000
x8 00000000000003e7 x9 0000000000007ffe x10 0000000000000000 x11 0000007258614c00
x12 0000000000000000 x13 0000000000000001 x14 0000007ff5c5af94 x15 0000000000000000
x16 0000007257e48080 x17 0000007257e40880 x18 0000000000000000 x19 0000007ff5c5b018
x20 0000007240f83d08 x21 0000007ff5c5afd0 x22 0000007258614c00 x23 00000000000010ef
x24 0000007257e40900 x25 0000007ff5c5afd8 x26 00000000000003e7 x27 0000007ff5c5af98
x28 0000007257f31048 x29 0000007ff5c5ae40
sp 0000007ff5c5ae00 lr 0000007257e408d0 pc 0000007257e48094

backtrace:
#00 pc 000000000054b094 /system/lib64/libart.so (ExecuteMterpImpl+30740)
// NestedScrollingChildHelper报空指针
#01 pc 00000000000f1d08 /system/framework/oat/arm64/ui-framework.vdex (android.support.v4.view.NestedScrollingChildHelper.isNestedScrollingEnabled)
#02 pc 0000000000252fc0 /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.2118865428+488)
#03 pc 0000000000258ab4 /system/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+216)
#04 pc 00000000002792a0 /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+940)
#05 pc 0000000000527754 /system/lib64/libart.so (MterpInvokeVirtualQuick+584)
#06 pc 000000000054ad94 /system/lib64/libart.so (ExecuteMterpImpl+29972)
#07 pc 000000000012dd58 /system/app/CarSettingHMI/oat/arm64/CarSettingHMI.vdex (android.support.v7.widget.RecyclerView.setNestedScrollingEnabled+8)
#08 pc 0000000000252fc0 /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.2118865428+488)
#09 pc 0000000000258ab4 /system/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+216)
#10 pc 00000000002792a0 /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+940)
#11 pc 0000000000527754 /system/lib64/libart.so (MterpInvokeVirtualQuick+584)
#12 pc 000000000054ad94 /system/lib64/libart.so (ExecuteMterpImpl+29972)
#13 pc 000000000012b302 /system/app/CarSettingHMI/oat/arm64/CarSettingHMI.vdex (android.support.v7.widget.RecyclerView.<init>+674)
#14 pc 0000000000252fc0 /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.2118865428+488)
#15 pc 0000000000258ab4 /system/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+216)
#16 pc 00000000002792a0 /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+940)
#17 pc 0000000000525a50 /system/lib64/libart.so (MterpInvokeDirect+296)
#18 pc 0000000000547114 /system/lib64/libart.so (ExecuteMterpImpl+14484)

......
// 在CarplayFragment中inflate创建Fragment布局
#41 pc 000000000017300c /system/app/CarSettingHMI/oat/arm64/CarSettingHMI.vdex (com.gxatek.cockpit.settings.view.fragment.internet.CarplayFragment.onCreateView+8)
#42 pc 0000000000252fc0 /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.2118865428+488)
#43 pc 0000000000514fa4 /system/lib64/libart.so (artQuickToInterpreterBridge+1020)
#44 pc 000000000055dafc /system/lib64/libart.so (art_quick_to_interpreter_bridge+92)

......
// 懒加载机制加载fragment
#68 pc 000000000015a276 /system/app/CarSettingHMI/oat/arm64/CarSettingHMI.vdex (com.gxatek.cockpit.settings.view.adapter.FragmentAdapter.finishUpdate+8)
#69 pc 0000000000252fc0 /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.2118865428+488)
#70 pc 0000000000258ab4 /system/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+216)
#71 pc 00000000002792a0 /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+940)
#72 pc 0000000000527754 /system/lib64/libart.so (MterpInvokeVirtualQuick+584)
#73 pc 000000000054ad94 /system/lib64/libart.so (ExecuteMterpImpl+29972)
#74 pc 000000000015e11c /system/app/CarSettingHMI/oat/arm64/CarSettingHMI.vdex (com.gxatek.cockpit.settings.view.custom.NoPreloadViewPager.populate+436)
#75 pc 0000000000252fc0 /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.2118865428+488)
#76 pc 0000000000258ab4 /system/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+216)
#77 pc 00000000002792a0 /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+940)
#78 pc 0000000000527754 /system/lib64/libart.so (MterpInvokeVirtualQuick+584)
#79 pc 000000000054ad94 /system/lib64/libart.so (ExecuteMterpImpl+29972)
#80 pc 000000000015e410 /system/app/CarSettingHMI/oat/arm64/CarSettingHMI.vdex (com.gxatek.cockpit.settings.view.custom.NoPreloadViewPager.setCurrentItemInternal+184)
#81 pc 0000000000252fc0 /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.2118865428+488)
#82 pc 0000000000258ab4 /system/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+216)
#83 pc 00000000002792a0 /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+940)
#84 pc 0000000000527754 /system/lib64/libart.so (MterpInvokeVirtualQuick+584)

......
// 点击item,切换到fragment
#98 pc 000000000013e91e /system/app/CarSettingHMI/oat/arm64/CarSettingHMI.vdex (com.gxatek.cockpit.settings.MainActivity.switchToFragment+16)
#99 pc 0000000000252fc0 /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.2118865428+488)
#100 pc 0000000000258ab4 /system/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+216)
#101 pc 00000000002792a0 /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+940)
#102 pc 0000000000525a50 /system/lib64/libart.so (MterpInvokeDirect+296)
#103 pc 0000000000547114 /system/lib64/libart.so (ExecuteMterpImpl+14484)
#104 pc 000000000013e4ae /system/app/CarSettingHMI/oat/arm64/CarSettingHMI.vdex (com.gxatek.cockpit.settings.MainActivity.onClick+94)
#105 pc 0000000000252fc0 /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.2118865428+488)
#106 pc 0000000000514fa4 /system/lib64/libart.so (artQuickToInterpreterBridge+1020)
#107 pc 000000000055dafc /system/lib64/libart.so (art_quick_to_interpreter_bridge+92)
#108 pc 0000000000c7dee4 /system/framework/arm64/boot-framework.oat (offset 0x3ce000) (android.view.View.performClick+148)
#109 pc 0000000000554988 /system/lib64/libart.so (art_quick_invoke_stub+584)
#110 pc 00000000000cf6c8 /system/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+200)
#111 pc 000000000027f2b4 /system/lib64/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+344)
#112 pc 00000000002792bc /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+968)
#113 pc 0000000000524da8 /system/lib64/libart.so (MterpInvokeSuper+1420)
#114 pc 0000000000547094 /system/lib64/libart.so (ExecuteMterpImpl+14356)
#115 pc 0000000000d5aa92 /system/framework/boot-framework.vdex (android.widget.CompoundButton.performClick+6)
#116 pc 0000000000252fc0 /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.2118865428+488)
#117 pc 0000000000514fa4 /system/lib64/libart.so (artQuickToInterpreterBridge+1020)
#118 pc 000000000055dafc /system/lib64/libart.so (art_quick_to_interpreter_bridge+92)
#119 pc 0000000000b83484 /system/framework/arm64/boot-framework.oat (offset 0x3ce000) (android.view.View$PerformClick.run+84)
#120 pc 0000000000aacccc /system/framework/arm64/boot-framework.oat (offset 0x3ce000) (android.os.Handler.dispatchMessage+76)
#121 pc 0000000000aafe30 /system/framework/arm64/boot-framework.oat (offset 0x3ce000) (android.os.Looper.loop+1264)
#122 pc 000000000087c378 /system/framework/arm64/boot-framework.oat (offset 0x3ce000) (android.app.ActivityThread.main+664)

从调用栈分析调度过程如下:

  1. 用户点击CarSettingHMI的界面某个item(最终调查到时carplayfragment)切换Fragment
  2. 懒加载加载carplayfragment
  3. 在递归加载RecycleView中子item的时候,NestedScrollingChildHelper处获得的时空指针
3.2 反编译CarSettingHMI.apk跟踪代码

从CarplayFragment开始看,当然也可以从更早时机开始看,但是前面都是正常的,就直接接近真相便捷一点。

1
2
3
4
// CarplayFragment.java
public View onCreateView(LayoutInflater paramLayoutInflater, ViewGroup paramViewGroup, Bundle paramBundle) {
return paramLayoutInflater.inflate(2131361842, paramViewGroup, false);
}

当加载CarplayFragment的时候,系统回调onCreateView取加载布局文件。此处无异常代码,继续跟踪

1
2
3
4
// RecyclerView.setNestedScrollingEnabled
public void setNestedScrollingEnabled(boolean paramBoolean){
getScrollingChildHelper().setNestedScrollingEnabled(paramBoolean);
}

看着setNestedScrollingEnabled()就是真相,前面的ScrollingChildHelper是null,然后调用报空指针异常。继续跟进。

1
2
3
4
5
6
private NestedScrollingChildHelper getScrollingChildHelper() {
if (this.mScrollingChildHelper == null) {
this.mScrollingChildHelper = new NestedScrollingChildHelper(this);
}
return this.mScrollingChildHelper;
}

此处看也是常规构建对象的方法,感觉也没有错,除了加锁可以防止,但是这个android.support.v7.widget支持包,是错也不应该我先发现,所有还是先从自身原因着手。

现在问题原因是找到了,就是:getScrollingChildHelper()返回了一个空对象,导致空指针异常。

3.3 猜测问题原因

感觉调查到上面在不改支持库的前提下就没辙了。不过细心看tombstone日志,发现调用栈是CarSettingHMI.vdex 中的代码。

1
2
3
#01 pc 00000000000f1d08  /system/framework/oat/arm64/ui-framework.vdex (android.support.v4.view.NestedScrollingChildHelper.isNestedScrollingEnabled)
......
#07 pc 000000000012dd58 /system/app/CarSettingHMI/oat/arm64/CarSettingHMI.vdex (android.support.v7.widget.RecyclerView.setNestedScrollingEnabled+8)

可以看到是ui-framework.vdex和CarSettingHMI.vdex,让我不由想到之前遇到过的System-UI应用方法调用的内存地址错位的问题。

于是顺着经验,开始验证猜想,首先点击设置系统设置应用的carplayfragment界面,现象:必崩;删掉包含CarSettingHMI.vdex和CarSettingHMI.odex的oat目录,然后在点击carplayfragment界面,就好使了。

3.4 临时解决办法
1
2
3
4
5
6
++ b/Feiyu/CarSettingHMI/Android.mk
@@ -17,6 +17,7 @@ LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_CERTIFICATE := platform
+LOCAL_DEX_PREOPT := false

取消优化项,在系统编译的时候,取消CarSettingHMI的优化项,让系统不生成CarSettingHMI.odex和CarSettingHMI.vdex文件。

1
2
3
4
5
6
7
8
临时解决办法手顺:
1、通过串口线进入Android系统
输入指令:dtach -a /tmp/android
2、通过串口打开ADB:先通过串口进入Android系统,再输入以下指令:
echo peripheral > /sys/devices/platform/soc/ee080200.usb-phy/role
3、getprop persist.vendor.usb.mode 查看是否是host,是host执行步骤4即可
4、setprop persist.vendor.usb.mode adb
5、/data/tombstones /data/system/dropbox /log

3.5 终极解决办法

建立maven仓库,或者artifactory仓库,让应用在Android Studio编译的时候,始终是最新的ui-framework和car-framework。然后在打开各个应用的预编译优化项。

4.回溯问题

上面一顿操作猛如虎,但是还没有回答为什么ADB口用着用着一会儿就用不了。

其实系统设置里面有个工程模式,工程模式里面有个usb口模式切换。当系统设置崩溃之后,再启动起来,usb口的模式自动切回模式的模式了。usb口默认模式是:host模式。

当工程模式崩溃之后,可以通过如下指令查看usb的模式

1
2
3
getprop persist.vendor.usb.mode
setprop persist.vendor.usb.mode host
setprop persist.vendor.usb.mode adb

参考文档:

1. Android Tombstone 分析