Android4.2移植的debug之路——不明黑色光圈
Android 4.2的移植工作仍然进行中,目前遇到一个bug:在qemu上,android界面出来后,用鼠标点击屏幕时会有一个黑色的小光圈,这个光圈不会跟着鼠标移动,只有点击后再拖动它才会跟着动,如果我想启动某个应用程序,需要把该光圈拖到应用程序图标位置上,然后双击才能启动。上图:
一个让人措手不及的bug,从未见过,又找不到相关的资料,只能“始作俑者”了。这是驱动问题?还是android上层问题?都有可能!首先去查看logcat的输出信息,寻找是否有可疑的地方。最后看到这里比较像问题发生之处:
I/SystemServer(723): Input Method Service
I/EventHub(723): New device: id=1, fd=80, path='/dev/input/event0', name='ic1-keypad', classes=0x1, configuration='', keyLayout='/system/usr/keylayout/Generic.kl', keyCharacterMap='/system/usr/keychars/Generic.kcm', builtinKeyboard=true, usingSuspendBlockIoctl=true, usingClockIoctl=true
D/EventHub(723): No input device configuration file found for device 'ic1_dano_ts'.
I/EventHub(723): New device: id=2, fd=82, path='/dev/input/event1', name='ic1_dano_ts', classes=0x4, configuration='', keyLayout='', keyCharacterMap='', builtinKeyboard=false, usingSuspendBlockIoctl=true, usingClockIoctl=true
W/InputMethodManagerService(723): Couldn't create dir.: /data/system/inputmethod
I/InputReader(723): Device added: id=-1, name='Virtual', sources=0x00000301
I/InputReader(723):Touch device 'ic1_dano_ts' could not query the properties of its associated display.The device will be inoperable until the display size becomes available.
I/InputReader(723): Device added: id=2, name='ic1_dano_ts', sources=0x00002002
I/InputReader(723): Device added: id=0, name='ic1-keypad', sources=0x00000101
W/InputMethodManagerService(723): No IME selected. Choose the most applicable IME.
I/ActivityManager(723): Config changed: {1.0 ?mcc?mnc en_US ldltr sw272dp w438dp h247dp 160dpi smll land ?uimode ?night -touch -keyb/h/h -nav/h s.2}
I/InputReader(723): Reconfiguring input devices.changes=0x00000004
I/InputReader(723): Device reconfigured: id=2, name='ic1_dano_ts', size 480x272, orientation 0, mode 3, display id 0
上面的log显示,EventHub发现了两个设备节点/dev/input/event0和/dev/input/event1,分别对应按键输入和触摸屏输入,但是这一句:
I/InputReader(723):Touch device 'ic1_dano_ts' could not query the properties of its associated display.The device will be inoperable until the display size becomes available.
看起来像是触摸屏的参数没有设置好。所以当android上层的InputReader要去查询触摸屏设备的参数时就失败了,然后InputReader自己采用了默认的方法来设置触摸屏的参数:
I/InputReader(723): Device reconfigured: id=2, name='ic1_dano_ts', size 480x272, orientation 0, mode 3, display id 0
所以,我怀疑qemu中触摸屏的分辨率没有设置好,在驱动里面把它设置成480x272,可是问题还是没解决。回头去观察这个光圈的特点,感觉它好像把输入事件跟android的界面隔开了,输入事件全都被光圈接收,传不到光圈下面的android界面。那好,我就瞧瞧你这光圈是一个什么对象。android里面默认是把很多debug信息屏蔽的,我们可以手动把它们打开。既然想要知道光圈是什么对象,那么就要看究竟是谁接收了输入事件。所以把ActivityManagerService和WindowManagerService里面的debug信息打开,它们可以看到每个activity或者窗口的动作。如何打开debug信息?这里举例WindowManagerService,其它的对象方法相同。在WindowManagerService中把下面这些debug的宏赋值为true就行了。
static final String TAG = "WindowManager";
176static final boolean DEBUG = false;
177static final boolean DEBUG_ADD_REMOVE = false;
178static final boolean DEBUG_FOCUS = false;
179static final boolean DEBUG_ANIM = false;
180static final boolean DEBUG_LAYOUT = false;
181static final boolean DEBUG_RESIZE = false;
182static final boolean DEBUG_LAYERS = false;
183static final boolean DEBUG_INPUT = false;
184static final boolean DEBUG_INPUT_METHOD = false;
185static final boolean DEBUG_VISIBILITY = false;
186static final boolean DEBUG_WINDOW_MOVEMENT = false;
187static final boolean DEBUG_TOKEN_MOVEMENT = false;
188static final boolean DEBUG_ORIENTATION = false;
189static final boolean DEBUG_APP_ORIENTATION = false;
190static final boolean DEBUG_CONFIGURATION = false;
191static final boolean DEBUG_APP_TRANSITIONS = false;
192static final boolean DEBUG_STARTING_WINDOW = false;
193static final boolean DEBUG_REORDER = false;
194static final boolean DEBUG_WALLPAPER = false;
195static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER;
196static final boolean DEBUG_DRAG = false;
197static final boolean DEBUG_SCREEN_ON = false;
198static final boolean DEBUG_SCREENSHOT = false;
199static final boolean DEBUG_BOOT = false;
200static final boolean DEBUG_LAYOUT_REPEATS = true;
201static final boolean DEBUG_SURFACE_TRACE = false;
202static final boolean DEBUG_WINDOW_TRACE = false;
把debug信息打开后,用鼠标点击android界面时,竟然没有activty和window的动作信息输出,嚓,这是要闹那样!!看来想知道光圈是什么对象是不可能了,此路不通走别的。还有什么方法可以调试?既然事件接受的路径调试不了,还有事件的分发可以调试。在android中,InputDispatcher就是事件的分发器。把事件分发这条路径的debug信息打开,点击qemu界面时,有log输出,证明android是能收到点击事件。具体的log我没保存好,弄丢了,然后又不想重做镜像重启androd,所以这里就不把事件分发的log贴上来了。只有这些log也不能解决问题,有对比才有发现。所以我编了一个mips的镜像,在goldfish上启动,也把事件分发的debug信息打开,发现输出的log确实不一样。goldfish上输出的log是这样的:
D/InputReader(277): BatchSize: 4 Count: 4
D/InputReader(277): Input event: device=0 type=0x0003 code=0x0000 value=https://www.it610.com/article/0x0000006d when=716025815000
D/InputReader(277): Input event: device=0 type=0x0003 code=0x0001 value=0x00000149 when=716025843000
D/InputReader(277): Input event: device=0 type=0x0001 code=0x014a value=0x00000001 when=716025863000
D/InputReader(277): Input event: device=0 type=0x0000 code=0x0000 value=0x00000000 when=716025873000
D/InputReader(277): syncTouch: pointerCount 0 -> 1, touching ids 0x00000000 -> 0x80000000, hovering ids 0x00000000 -> 0x00000000
D/InputDispatcher(277): notifyMotion - eventTime=716025873000, deviceId=0, source=0x1002, policyFlags=0x0, action=0x0, flags=0x0, metaState=0x0, buttonState=0x0, edgeFlags=0x0, xPrecision=1.000000, yPrecision=1.000000, downTime=716025873000
D/InputDispatcher(277):Pointer 0: id=0, toolType=1, x=109.000000, y=329.000000, pressure=1.000000, size=0.000000, touchMajor=0.000000, touchMinor=0.000000, toolMajor=0.000000, toolMinor=0.000000, orientation=0.000000
D/InputDispatcher(277): Resetting ANR timeouts.
D/InputDispatcher(277): dispatchMotion - eventTime=716025873000, deviceId=0, source=0x1002, policyFlags=0x62000000, action=0x0, flags=0x0, metaState=0x0, buttonState=0x0, edgeFlags=0x0, xPrecision=1.000000, yPrecision=1.000000, downTime=716025873000
D/InputDispatcher(277):Pointer 0: id=0, toolType=1, x=109.000000, y=329.000000, pressure=1.000000, size=0.000000, touchMajor=0.000000, touchMinor=0.000000, toolMajor=0.000000, toolMinor=0.000000, orientation=0.000000
D/InputDispatcher(277): findTouchedWindow finished: injectionResult=0, injectionPermission=1, timeSpentWaitingForApplication=0.0ms
D/InputDispatcher(277): dispatchEventToCurrentInputTargets
D/InputDispatcher(277): channel '2c3a5020 com.android.launcher/com.android.launcher2.Launcher (server)' ~ prepareDispatchCycle - flags=0x00000105, xOffset=0.000000, yOffset=0.000000, scaleFactor=1.000000, pointerIds=0x80000000
D/InputDispatcher(277): channel '2c3a5020 com.android.launcher/com.android.launcher2.Launcher (server)' ~ startDispatchCycle
D/InputDispatcher(277): channel '2c4c2ac8 com.android.systemui.ImageWallpaper (server)' ~ prepareDispatchCycle - flags=0x00000102, xOffset=0.000000, yOffset=0.000000, scaleFactor=1.000000, pointerIds=0x0
D/InputDispatcher(277): channel '2c4c2ac8 com.android.systemui.ImageWallpaper (server)' ~ startDispatchCycle
D/InputDispatcher(277): Resetting ANR timeouts.
D/InputDispatcher(277): channel '2c3a5020 com.android.launcher/com.android.launcher2.Launcher (server)' ~ finishDispatchCycle - seq=31, handled=true
D/InputDispatcher(277): channel '2c3a5020 com.android.launcher/com.android.launcher2.Launcher (server)' ~ startDispatchCycle
D/InputDispatcher(277): channel '2c4c2ac8 com.android.systemui.ImageWallpaper (server)' ~ finishDispatchCycle - seq=32, handled=true
D/InputDispatcher(277): channel '2c4c2ac8 com.android.systemui.ImageWallpaper (server)' ~ startDispatchCycle
D/InputReader(277): BatchSize: 2 Count: 2
D/InputReader(277): Input event: device=0 type=0x0001 code=0x014a value=https://www.it610.com/article/0x00000000 when=716078927000
D/InputReader(277): Input event: device=0 type=0x0000 code=0x0000 value=0x00000000 when=716078960000
D/InputReader(277): syncTouch: pointerCount 1 -> 0, touching ids 0x80000000 -> 0x00000000, hovering ids 0x00000000 -> 0x00000000
D/InputDispatcher(277): notifyMotion - eventTime=716078960000, deviceId=0, source=0x1002, policyFlags=0x0, action=0x1, flags=0x0, metaState=0x0, buttonState=0x0, edgeFlags=0x0, xPrecision=1.000000, yPrecision=1.000000, downTime=716025873000
D/InputDispatcher(277):Pointer 0: id=0, toolType=1, x=109.000000, y=329.000000, pressure=1.000000, size=0.000000, touchMajor=0.000000, touchMinor=0.000000, toolMajor=0.000000, toolMinor=0.000000, orientation=0.000000
D/InputDispatcher(277): Resetting ANR timeouts.
D/InputDispatcher(277): dispatchMotion - eventTime=716078960000, deviceId=0, source=0x1002, policyFlags=0x42000000, action=0x1, flags=0x0, metaState=0x0, buttonState=0x0, edgeFlags=0x0, xPrecision=1.000000, yPrecision=1.000000, downTime=716025873000
D/InputDispatcher(277):Pointer 0: id=0, toolType=1, x=109.000000, y=329.000000, pressure=1.000000, size=0.000000, touchMajor=0.000000, touchMinor=0.000000, toolMajor=0.000000, toolMinor=0.000000, orientation=0.000000
D/InputDispatcher(277): findTouchedWindow finished: injectionResult=0, injectionPermission=1, timeSpentWaitingForApplication=0.0ms
D/InputDispatcher(277): dispatchEventToCurrentInputTargets
D/InputDispatcher(277): channel '2c3a5020 com.android.launcher/com.android.launcher2.Launcher (server)' ~ prepareDispatchCycle - flags=0x00000105, xOffset=0.000000, yOffset=0.000000, scaleFactor=1.000000, pointerIds=0x80000000
D/InputDispatcher(277): channel '2c3a5020 com.android.launcher/com.android.launcher2.Launcher (server)' ~ startDispatchCycle
D/InputDispatcher(277): channel '2c4c2ac8 com.android.systemui.ImageWallpaper (server)' ~ prepareDispatchCycle - flags=0x00000102, xOffset=0.000000, yOffset=0.000000, scaleFactor=1.000000, pointerIds=0x0
D/InputDispatcher(277): channel '2c4c2ac8 com.android.systemui.ImageWallpaper (server)' ~ startDispatchCycle
D/InputDispatcher(277): Resetting ANR timeouts.
D/InputDispatcher(277): channel '2c4c2ac8 com.android.systemui.ImageWallpaper (server)' ~ finishDispatchCycle - seq=34, handled=true
D/InputDispatcher(277): channel '2c4c2ac8 com.android.systemui.ImageWallpaper (server)' ~ startDispatchCycle
D/InputDispatcher(277): channel '2c3a5020 com.android.launcher/com.android.launcher2.Launcher (server)' ~ finishDispatchCycle - seq=33, handled=true
D/InputDispatcher(277): channel '2c3a5020 com.android.launcher/com.android.launcher2.Launcher (server)' ~ startDispatchCycle
各位看官看不到出现光圈时事件分发路径的log,没法对比,所以我这里直接解密吧。goldfish上输出的log是正常工作时的log,而跟出现光圈的log对比时,发现出现光圈时捕捉到的事件根本就不是触摸屏的事件,而是鼠标的事件。这里大家要弄明白,输入事件有3种:键盘事件、触摸屏事件、鼠标事件。显然,鼠标事件是在模拟器上才会有的,因为android真实设备还真没见过有用鼠标的。看来,系统是把鼠标输入事件跟触摸屏输入事件混淆了。回去看看第一次贴上的log,好像触摸屏设备真的没有配置好,因为键盘注册时会读取配置文件:
I/EventHub(723): New device: id=1, fd=80, path='/dev/input/event0', name='ic1-keypad', classes=0x1, configuration='', keyLayout='/system/usr/keylayout/Generic.kl', keyCharacterMap='/system/usr/keychars/Generic.kcm',
但是触摸屏的configuration、keyLayout和keyCharacterMap域都为空:
I/EventHub(723): New device: id=2, fd=82, path='/dev/input/event1', name='ic1_dano_ts', classes=0x4, configuration='', keyLayout='', keyCharacterMap='',
然后研究了一下EventHub里面读取配置文件的方式,发现是根据设备的名称去找配置文件的。在goldfish中是这样的:
I/EventHub(277): New device: id=1, fd=97, path='/dev/input/event0', name='qwerty2', classes=0x2d, configuration='/system/usr/idc/qwerty2.idc', keyLayout='/system/usr/keylayout/qwerty.kl', keyCharacterMap='/system/usr/keychars/qwerty2.kcm'
【Android4.2移植的debug之路——不明黑色光圈】设备的名称为qwerty2,就有对应的qwerty2.idc等文件,这些文件在frameworks/base/data/keyboards/下。所以根据我们触摸屏的设备名字为ic1_dano_ts,参照qwerty2的内容也弄了一个叫ic1_dano_ts.idc的文件,然后编译进去。额,竟然能正常工作了!!既然能正常工作了,所以其它两个域keyLayout和keyCharacterMap就没有再去研究了,如果有了解的看官,可以帮忙解释下。后来,翻了一下资料,发现在android4.0之后加入了一个叫hover的对象,该对象能捕捉鼠标的输入事件,黑色的光圈估计就是这货了!
好了,到这里,这个bug算是解掉了。
推荐阅读
- 热闹中的孤独
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 放屁有这三个特征的,请注意啦!这说明你的身体毒素太多
- 一个人的旅行,三亚
- 布丽吉特,人生绝对的赢家
- 慢慢的美丽
- 尽力
- 一个小故事,我的思考。
- 家乡的那条小河
- 《真与假的困惑》???|《真与假的困惑》??? ——致良知是一种伟大的力量