【NE现场】

DEBUG : pid: 2034, tid: 3409, name: InputReader >>> system_server <<<
DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x6fa1bc44
DEBUG : r0 4c37003b r1 746e6658 r2 718a8178 r3 6fa1bc40
DEBUG : r4 9de8234c r5 9fd0e884 r6 9de823c4 r7 9de822e0
DEBUG : r8 9fd0e88c r9 00000000 sl 00000420 fp 9de822e0
DEBUG : ip 9fd0e818 sp 9dcbe7c0 lr 9de82354 pc b6bed43a cpsr a0070030
DEBUG :
DEBUG : backtrace:
DEBUG : #00 pc 0002b43a /system/lib/libinputflinger.so (android::RawPointerData::copyFrom(android::RawPointerData const&)+99)
DEBUG : #01 pc 00030ff9 /system/lib/libinputflinger.so (android::TouchInputMapper::processRawTouches(bool)+136)
DEBUG : #02 pc 000315a1 /system/lib/libinputflinger.so (android::MultiTouchInputMapper::process(android::RawEvent const*)+6)
DEBUG : #03 pc 0002a75b /system/lib/libinputflinger.so (android::InputDevice::process(android::RawEvent const*, unsigned int)+106)
DEBUG : #04 pc 0002a7b7 /system/lib/libinputflinger.so (android::InputReader::processEventsForDeviceLocked(int, android::RawEvent const*, unsigned int)+70)
DEBUG : #05 pc 0002a9c3 /system/lib/libinputflinger.so (android::InputReader::processEventsLocked(android::RawEvent const*, unsigned int)+50)
DEBUG : #06 pc 0002aad7 /system/lib/libinputflinger.so (android::InputReader::loopOnce()+182)
DEBUG : #07 pc 000274a3 /system/lib/libinputflinger.so (android::InputReaderThread::threadLoop()+8)
DEBUG : #08 pc 0001006d /system/lib/libutils.so (android::Thread::_threadLoop(void*)+112)
DEBUG : #09 pc 0005fbef /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+70)
DEBUG : #10 pc 0003f54f /system/lib/libc.so (__pthread_start(void*)+30)
DEBUG : #11 pc 00019c2f /system/lib/libc.so (__start_thread+6)

这个问题在多个机型上出现过且概率较高。

由于每次调用栈都一样,且都是system_server的InputRead线程Crash,

且每次都是系统启动的时,Input系统初始化的时候挂掉的。

【问题分析】

用gdb分析core:

(gdb) bt
#0  0xb6ba45b8 in android::RawPointerData::copyFrom (this=this@entry=0xa9c88ae0, other=...) at frameworks/native/services/inputflinger/InputReader.cpp:1534
#1  0xb6baa17c in copyFrom (other=..., this=0xa9c88ad8) at frameworks/native/services/inputflinger/InputReader.h:1410
#2  android::TouchInputMapper::processRawTouches (this=0xa9c88800, timeout=<optimized out>) at frameworks/native/services/inputflinger/InputReader.cpp:3986
#3  0xb6baa724 in android::MultiTouchInputMapper::process (this=0xa9c88800, rawEvent=0xae9a0a58) at frameworks/native/services/inputflinger/InputReader.cpp:6488
#4  0xb6ba38dc in android::InputDevice::process (this=0x9df57bc0, rawEvents=rawEvents@entry=0xae9a0908, count=0, count@entry=15) at frameworks/native/services/inputflinger/InputReader.cpp:1065
#5  0xb6ba393a in android::InputReader::processEventsForDeviceLocked (this=0xae9a0800, deviceId=6, rawEvents=0xae9a0908, count=15) at frameworks/native/services/inputflinger/InputReader.cpp:523
#6  0xb6ba3b46 in android::InputReader::processEventsLocked (this=this@entry=0xae9a0800, rawEvents=rawEvents@entry=0xae9a0908, count=count@entry=15)at frameworks/native/services/inputflinger/InputReader.cpp:358
#7  0xb6ba3c5a in android::InputReader::loopOnce (this=0xae9a0800) at frameworks/native/services/inputflinger/InputReader.cpp:307
#8  0xb6ba0624 in android::InputReaderThread::threadLoop (this=<optimized out>) at frameworks/native/services/inputflinger/InputReader.cpp:919
#9  0xb6f2f06e in android::Thread::_threadLoop (user=0x9dfcde40) at system/core/libutils/Threads.cpp:758
#10 0xb6e58d48 in android::AndroidRuntime::javaThreadShell (args=<optimized out>) at frameworks/base/core/jni/AndroidRuntime.cpp:1215
#11 0xb6d07550 in __pthread_start (arg=0x9dbba930, arg@entry=<error reading variable: value has been optimized out>) at bionic/libc/bionic/pthread_create.cpp:199
#12 0xb6ce1c30 in __start_thread (fn=<optimized out>, arg=<optimized out>) at bionic/libc/bionic/clone.cpp:41
#13 0x00000000 in ?? ()

查看源码,崩溃的地方是:

void RawPointerData::copyFrom(const RawPointerData& other) {pointerCount = other.pointerCount;hoveringIdBits = other.hoveringIdBits;touchingIdBits = other.touchingIdBits;for (uint32_t i = 0; i < pointerCount; i++) {pointers[i] = other.pointers[i];int id = pointers[i].id;
        idToIndex[id] = other.idToIndex[id];}
}

这里挂掉,要么是other值有问题,要么是id值有问题。

(gdb) p &other
$95 = (const android::RawPointerData *) 0x9ea21c18(gdb) p id
$96 = 1953391990

显然,是id值异常了。

这个问题在同样一个模块高概率出现,说明很可能这部分逻辑有问题,所以得分析代码流程。

走到它的上一级函数,查看这个other及id是怎么来的:

void TouchInputMapper::processRawTouches(bool timeout) {...const size_t N = mRawStatesPending.size();size_t count;for(count = 0; count < N; count++) {const RawState& next = mRawStatesPending[count];...
        mCurrentRawState.copyFrom(next);if (mCurrentRawState.when < mLastRawState.when) {mCurrentRawState.when = mLastRawState.when;}cookAndDispatch(mCurrentRawState.when);}

是从mRawStatesPending里面来的。继续往上推导,看这个mRawStatesPending是怎么来的:

void TouchInputMapper::sync(nsecs_t when) {const RawState* last = mRawStatesPending.isEmpty() ?&mCurrentRawState : &mRawStatesPending.top();// Push a new state.
    mRawStatesPending.push();RawState* next = &mRawStatesPending.editTop();next->clear();next->when = when;// Sync button state.next->buttonState = mTouchButtonAccumulator.getButtonState()| mCursorButtonAccumulator.getButtonState();// Sync scrollnext->rawVScroll = mCursorScrollAccumulator.getRelativeVWheel();next->rawHScroll = mCursorScrollAccumulator.getRelativeHWheel();mCursorScrollAccumulator.finishSync();// Sync touch
    syncTouch(when, next);// Assign pointer ids.if (!mHavePointerIds) {assignPointerIds(last, next);}...processRawTouches(false /*timeout*/);
}

mRawStatesPending是个缓冲区,这里先调用push来获取一个RawState,并调用clear()来初始化RawState。

然后调用syncTouch()来对新的RawState赋值,crash的RawState就是这个新构建的RawState。

要看这个新的RawState如何被构建的,那得看syncTouch()的实现:

void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();size_t outCount = 0;BitSet32 newPointerIdBits;for (size_t inIndex = 0; inIndex < inCount; inIndex++) {const MultiTouchMotionAccumulator::Slot* inSlot =mMultiTouchMotionAccumulator.getSlot(inIndex);if (!inSlot->isInUse()) {continue;}...RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[outCount];outPointer.x = inSlot->getX();outPointer.y = inSlot->getY();outPointer.pressure = inSlot->getPressure();outPointer.touchMajor = inSlot->getTouchMajor();outPointer.touchMinor = inSlot->getTouchMinor();outPointer.toolMajor = inSlot->getToolMajor();outPointer.toolMinor = inSlot->getToolMinor();outPointer.orientation = inSlot->getOrientation();outPointer.distance = inSlot->getDistance();outPointer.tiltX = 0;outPointer.tiltY = 0;outPointer.toolType = inSlot->getToolType();...bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE&& (mTouchButtonAccumulator.isHovering()|| (mRawPointerAxes.pressure.valid && inSlot->getPressure() <= 0));outPointer.isHovering = isHovering;// Assign pointer id using tracking id if available.mHavePointerIds = true;int32_t trackingId = inSlot->getTrackingId();int32_t id = -1;if (trackingId >= 0) {for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) {uint32_t n = idBits.clearFirstMarkedBit();if (mPointerTrackingIdMap[n] == trackingId) {id = n;}}if (id < 0 && !mPointerIdBits.isFull()) {id = mPointerIdBits.markFirstUnmarkedBit();mPointerTrackingIdMap[id] = trackingId;}}if (id < 0) {mHavePointerIds = false;outState->rawPointerData.clearIdBits();newPointerIdBits.clear();} else {outPointer.id = id;outState->rawPointerData.idToIndex[id] = outCount;outState->rawPointerData.markIdBit(id, isHovering);newPointerIdBits.markBit(id);}outCount += 1;}outState->rawPointerData.pointerCount = outCount;mPointerIdBits = newPointerIdBits;mMultiTouchMotionAccumulator.finishSync();
}

出问题的Pointer的具体值就是在这里赋值的,

从mMultiTouchMotionAccumulator里找到isInUse为true的时候就把对应slot里的内容拷贝给pointer里。

注意,我们关注的的id也是这里赋值的。

通过GDB对比mMultiTouchMotionAccumulator和最终Crash时候的Pointer.

(gdb) p mMultiTouchMotionAccumulator.mSlotCount
$71 = 10(gdb) p *(android::MultiTouchMotionAccumulator::Slot *) (0x9ed3fa00+sizeof(android::MultiTouchMotionAccumulator::Slot)*0)
$81 = {mInUse = true, mHaveAbsMTTouchMinor = false, mHaveAbsMTWidthMinor = false, mHaveAbsMTToolType = false, mAbsMTPositionX = 0, mAbsMTPositionY = 0, mAbsMTTouchMajor = 11, mAbsMTTouchMinor = 0, mAbsMTWidthMajor = 0, mAbsMTWidthMinor = 0, mAbsMTOrientation = 0, mAbsMTTrackingId = -1, mAbsMTPressure = 0, mAbsMTDistance = 0, mAbsMTToolType = 0
}
(gdb) p *(android::MultiTouchMotionAccumulator::Slot *) (0x9ed3fa00+sizeof(android::MultiTouchMotionAccumulator::Slot)*1)
$82 = {mInUse = true, mHaveAbsMTTouchMinor = false, mHaveAbsMTWidthMinor = false, mHaveAbsMTToolType = false, mAbsMTPositionX = 483, mAbsMTPositionY = 115, mAbsMTTouchMajor = 8, mAbsMTTouchMinor = 0, mAbsMTWidthMajor = 0, mAbsMTWidthMinor = 0, mAbsMTOrientation = 0, mAbsMTTrackingId = -1, mAbsMTPressure = 0, mAbsMTDistance = 0, mAbsMTToolType = 0
}
(gdb) p *(android::MultiTouchMotionAccumulator::Slot *) (0x9ed3fa00+sizeof(android::MultiTouchMotionAccumulator::Slot)*2)
$83 = {mInUse = true, mHaveAbsMTTouchMinor = false, mHaveAbsMTWidthMinor = false, mHaveAbsMTToolType = false, mAbsMTPositionX = 0, mAbsMTPositionY = 207, mAbsMTTouchMajor = 10, mAbsMTTouchMinor = 0, mAbsMTWidthMajor = 0, mAbsMTWidthMinor = 0, mAbsMTOrientation = 0, mAbsMTTrackingId = -1, mAbsMTPressure = 0, mAbsMTDistance = 0, mAbsMTToolType = 0
}
(gdb) p *(android::MultiTouchMotionAccumulator::Slot *) (0x9ed3fa00+sizeof(android::MultiTouchMotionAccumulator::Slot)*3)
$84 = {mInUse = true, mHaveAbsMTTouchMinor = false, mHaveAbsMTWidthMinor = false, mHaveAbsMTToolType = false, mAbsMTPositionX = 641, mAbsMTPositionY = 579, mAbsMTTouchMajor = 9, mAbsMTTouchMinor = 0, mAbsMTWidthMajor = 0, mAbsMTWidthMinor = 0, mAbsMTOrientation = 0, mAbsMTTrackingId = -1, mAbsMTPressure = 0, mAbsMTDistance = 0, mAbsMTToolType = 0
}
(gdb) p *(android::MultiTouchMotionAccumulator::Slot *) (0x9ed3fa00+sizeof(android::MultiTouchMotionAccumulator::Slot)*4)
$85 = {mInUse = true, mHaveAbsMTTouchMinor = false, mHaveAbsMTWidthMinor = false, mHaveAbsMTToolType = false, mAbsMTPositionX = 435, mAbsMTPositionY = 493, mAbsMTTouchMajor = 7, mAbsMTTouchMinor = 0, mAbsMTWidthMajor = 0, mAbsMTWidthMinor = 0, mAbsMTOrientation = 0, mAbsMTTrackingId = -1, mAbsMTPressure = 0, mAbsMTDistance = 0, mAbsMTToolType = 0
}
(gdb) p *(android::MultiTouchMotionAccumulator::Slot *) (0x9ed3fa00+sizeof(android::MultiTouchMotionAccumulator::Slot)*5)
$86 = {mInUse = true, mHaveAbsMTTouchMinor = false, mHaveAbsMTWidthMinor = false, mHaveAbsMTToolType = false, mAbsMTPositionX = 0, mAbsMTPositionY = 20, mAbsMTTouchMajor = 0, mAbsMTTouchMinor = 0, mAbsMTWidthMajor = 0, mAbsMTWidthMinor = 0, mAbsMTOrientation = 0, mAbsMTTrackingId = -1, mAbsMTPressure = 0, mAbsMTDistance = 0, mAbsMTToolType = 0
}
(gdb) p *(android::MultiTouchMotionAccumulator::Slot *) (0x9ed3fa00+sizeof(android::MultiTouchMotionAccumulator::Slot)*6)
$87 = {mInUse = true, mHaveAbsMTTouchMinor = false, mHaveAbsMTWidthMinor = false, mHaveAbsMTToolType = false, mAbsMTPositionX = 598, mAbsMTPositionY = 870, mAbsMTTouchMajor = 3, mAbsMTTouchMinor = 0, mAbsMTWidthMajor = 0, mAbsMTWidthMinor = 0, mAbsMTOrientation = 0, mAbsMTTrackingId = 71, mAbsMTPressure = 0, mAbsMTDistance = 0, mAbsMTToolType = 0
}
(gdb) p *(android::MultiTouchMotionAccumulator::Slot *) (0x9ed3fa00+sizeof(android::MultiTouchMotionAccumulator::Slot)*7)
$97 = {mInUse = false, mHaveAbsMTTouchMinor = false, mHaveAbsMTWidthMinor = false, mHaveAbsMTToolType = false, mAbsMTPositionX = 0, mAbsMTPositionY = 0, mAbsMTTouchMajor = 0, mAbsMTTouchMinor = 0, mAbsMTWidthMajor = 0, mAbsMTWidthMinor = 0, mAbsMTOrientation = 0, mAbsMTTrackingId = -1, mAbsMTPressure = 0, mAbsMTDistance = 0, mAbsMTToolType = 0
}
(gdb) p *(android::MultiTouchMotionAccumulator::Slot *) (0x9ed3fa00+sizeof(android::MultiTouchMotionAccumulator::Slot)*8)
$98 = {mInUse = false, mHaveAbsMTTouchMinor = false, mHaveAbsMTWidthMinor = false, mHaveAbsMTToolType = false, mAbsMTPositionX = 0, mAbsMTPositionY = 0, mAbsMTTouchMajor = 0, mAbsMTTouchMinor = 0, mAbsMTWidthMajor = 0, mAbsMTWidthMinor = 0, mAbsMTOrientation = 0, mAbsMTTrackingId = -1, mAbsMTPressure = 0, mAbsMTDistance = 0, mAbsMTToolType = 0
}
(gdb) p *(android::MultiTouchMotionAccumulator::Slot *) (0x9ed3fa00+sizeof(android::MultiTouchMotionAccumulator::Slot)*9)
$99 = {mInUse = false, mHaveAbsMTTouchMinor = false, mHaveAbsMTWidthMinor = false, mHaveAbsMTToolType = false, mAbsMTPositionX = 0, mAbsMTPositionY = 0, mAbsMTTouchMajor = 0, mAbsMTTouchMinor = 0, mAbsMTWidthMajor = 0, mAbsMTWidthMinor = 0, mAbsMTOrientation = 0, mAbsMTTrackingId = -1, mAbsMTPressure = 0, mAbsMTDistance = 0, mAbsMTToolType = 0
}

可以看出,一共有10个slot,其中前7个是mInUse=true的。

对应Pointer的数据如下:

 $89 = (const android::RawPointerData &) @0x9ea21c18: {pointerCount = 7, pointers = {{id = 0, x = 0, y = 0, pressure = 0, touchMajor = 11, touchMinor = 11, toolMajor = 0, toolMinor = 0, orientation = 0, distance = 0, tiltX = 0, tiltY = 0, toolType = 1, isHovering = false}, {
      id = 1953391990, x = 483, y = 115, pressure = 0, touchMajor = 8, touchMinor = 8, toolMajor = 0, toolMinor = 0, orientation = 0, distance = 0, tiltX = 0, tiltY = 0, toolType = 1, isHovering = false}, {id = 0, x = 0, y = 207, pressure = 0, touchMajor = 10, touchMinor = 10, toolMajor = 0, toolMinor = 0, orientation = 0, distance = 0, tiltX = 0, tiltY = 0, toolType = 1, isHovering = false}, {id = 0, x = 641, y = 579, pressure = 0, touchMajor = 9, touchMinor = 9, toolMajor = 0, toolMinor = 0, orientation = 0, distance = 0, tiltX = 0, tiltY = 0, toolType = 1, isHovering = false}, {id = 0, x = 435, y = 493, pressure = 0, touchMajor = 7, touchMinor = 7, toolMajor = 0, toolMinor = 0, orientation = 0, distance = 0, tiltX = 0, tiltY = 0, toolType = 1, isHovering = false}, {id = 0, x = 0, y = 20, pressure = 0, touchMajor = 0, touchMinor = 0, toolMajor = 0, toolMinor = 0, orientation = 0, distance = 0, tiltX = 0, tiltY = 0, toolType = 1, isHovering = false}, {id = 0, x = 598, y = 870, pressure = 0, touchMajor = 3, touchMinor = 3, toolMajor = 0, toolMinor = 0, orientation = 0, distance = 0, tiltX = 0, tiltY = 0, toolType = 1, isHovering = false}, ...}}, hoveringIdBits = {value = 0}, touchingIdBits = {value = 2147483648}, idToIndex = {6, 0 <repeats 31 times>}
}

发现有效数据pointerCount刚好是7个,且数据也是非常相近。除了第二个Pinter里的id值,这个id值就是crash时的1953391990。

所以得重点看这个id是怎么来的,简化MultiTouchInputMapper::syncTouch():

void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();size_t outCount = 0;BitSet32 newPointerIdBits;for (size_t inIndex = 0; inIndex < inCount; inIndex++) {const MultiTouchMotionAccumulator::Slot* inSlot =mMultiTouchMotionAccumulator.getSlot(inIndex);if (!inSlot->isInUse()) {continue;}...// Assign pointer id using tracking id if available.mHavePointerIds = true;int32_t trackingId = inSlot->getTrackingId();int32_t id = -1;if (trackingId >= 0) {for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) {uint32_t n = idBits.clearFirstMarkedBit();if (mPointerTrackingIdMap[n] == trackingId) {id = n;}}if (id < 0 && !mPointerIdBits.isFull()) {id = mPointerIdBits.markFirstUnmarkedBit();mPointerTrackingIdMap[id] = trackingId;}}if (id < 0) {
            mHavePointerIds = false;outState->rawPointerData.clearIdBits();newPointerIdBits.clear();} else {outPointer.id = id;outState->rawPointerData.idToIndex[id] = outCount;outState->rawPointerData.markIdBit(id, isHovering);newPointerIdBits.markBit(id);}outCount += 1;}outState->rawPointerData.pointerCount = outCount;mPointerIdBits = newPointerIdBits;mMultiTouchMotionAccumulator.finishSync();
}

从代码中可以看出,当我们trackingId为负值时,这里不会更新id值!

而我们从其上一级函数的语义可以看出来,这里的outState里的初始值都是无效的。

而我们mMultiTouchMotionAccumulator的前6个trackingId都是-1,也就是说前6个都不会更新id。

对比SingleTouchInputMapper::syncTouch()里是有对id赋初值的。

void SingleTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {...RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[0];
        outPointer.id = 0;outPointer.x = mSingleTouchMotionAccumulator.getAbsoluteX();outPointer.y = mSingleTouchMotionAccumulator.getAbsoluteY();outPointer.pressure = mSingleTouchMotionAccumulator.getAbsolutePressure();outPointer.touchMajor = 0;...outPointer.isHovering = isHovering;}
}

很可能就是这里的问题了,看起来是Android原生问题。为此去查Android的gerrit,发现确实有在这里做了修改。

【解决方案】

https://android-review.googlesource.com/#/c/174790/

只不过它的改法不是简单的赋初值,它的逻辑如下:

void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();size_t outCount = 0;BitSet32 newPointerIdBits; bool needRecomputePointerIds = false;for (size_t inIndex = 0; inIndex < inCount; inIndex++) {const MultiTouchMotionAccumulator::Slot* inSlot =mMultiTouchMotionAccumulator.getSlot(inIndex);if (!inSlot->isInUse()) {continue;}...// Assign pointer id using tracking id if available.mHavePointerIds = true;int32_t trackingId = inSlot->getTrackingId();int32_t id = -1;if (trackingId >= 0) {for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) {uint32_t n = idBits.clearFirstMarkedBit();if (mPointerTrackingIdMap[n] == trackingId) {id = n;}}if (id < 0 && !mPointerIdBits.isFull()) {id = mPointerIdBits.markFirstUnmarkedBit();mPointerTrackingIdMap[id] = trackingId;}}if (id < 0) {
             needRecomputePointerIds = true;//mHavePointerIds = false;outState->rawPointerData.clearIdBits();newPointerIdBits.clear();} else {outPointer.id = id;outState->rawPointerData.idToIndex[id] = outCount;outState->rawPointerData.markIdBit(id, isHovering);newPointerIdBits.markBit(id);}outCount += 1;}    if (needRecomputePointerIds) {        mHavePointerIds = false;
    }outState->rawPointerData.pointerCount = outCount;mPointerIdBits = newPointerIdBits;mMultiTouchMotionAccumulator.finishSync();
}

原先的逻辑里,最后一个slot的id>0,mHavePointerIds值就是true。

修改后的逻辑是,只要有一个id<0也就是trackingId为负数,则mHavePointerIds值是false。

对应我们的case,最后一个slot,其trackingId是74,这里对应的mHavePointerIds就是true了。

而如果按照修改后的逻辑,这里mHavePointerIds应该就是false了。

这个mHavePointerIds有啥用呢?

void TouchInputMapper::sync(nsecs_t when) {const RawState* last = mRawStatesPending.isEmpty() ?&mCurrentRawState : &mRawStatesPending.top();// Push a new state.
    mRawStatesPending.push();RawState* next = &mRawStatesPending.editTop();next->clear();next->when = when;...// Sync touch
    syncTouch(when, next);// Assign pointer ids.if (!mHavePointerIds) {assignPointerIds(last, next);}...processRawTouches(false /*timeout*/);
}

syncTouch()后会判断mHavePointerIds,如果是false,则重新分配id。

这样就不会出现crash了。

转载于:https://www.cnblogs.com/YYPapa/p/6850659.html

InputFlinger崩溃问题分析报告相关推荐

  1. 用哪种语言写的应用漏洞最严重?六大主流语言代码漏洞分析报告出炉

    来源:机器之心 本文约1600字,建议阅读5分钟 静态代码分析安全公司 Veracode 近日发布了一份应用程序分析报告,结果发现比起 JavaScript 和 Python 等语言,C++ 和 PH ...

  2. Countly 19.02.1 发布,实时移动和 web 分析报告平台

    百度智能云 云生态狂欢季 热门云产品1折起>>>   实时移动和 web 分析报告平台 Countly 19.02.1 发布了. 新版更新内容主要有: 新特性 [前端] 根据路由名称 ...

  3. [译] APT分析报告:04.Kraken - 新型无文件APT攻击利用Windows错误报告服务逃避检测

    这是作者新开的一个专栏,主要翻译国外知名的安全厂商APT报告文章,了解它们的安全技术,学习它们溯源APT组织的方法,希望对您有所帮助.前文分享了APT组织Fin7 / Carbanak的Tirion恶 ...

  4. 日本福岛核电站事故分析报告

    日本福岛核电站事故分析报告 论软件工程管理常见问题 事件回顾: 当地时间3月11日14时46分,日本发生里氏9级地震,震中位于宫城县以东的太平洋海域,震源深度20公里.地震引发的10米浪高大海啸随后横 ...

  5. 2020年上半年教育舆情新闻热点事件案例分析报告合集

    ​回顾2020年上半年发生的教育舆情新闻热点事件,发现其中在网上引发舆论热议的事件可不少,如广州方圆小学哮喘女孩反转事件.高考舆情热点事件.教师岗位顶替等.这里蚁坊软件有挑选了2020年上半年热议度高 ...

  6. android afw模式,[HUAWEI-TITANC328]手机加密功能开启后,工作区中添加超级备份手机不断重启的分析报告...

    工作区中添加超级备份手机不断重启的分析报告 [华为反馈] [TIT-AL00C328B120_AFW_必现]创建工作空间后升级系统,升级失败,手机循环重启. 通过分析log发现,实际上这个问题与OTA ...

  7. iOS崩溃日志分析-b

    1名词解释 1.1. UUID 一个字符串,在iOS上每个可执行文件或库文件都包含至少一个UUID,目的是为了唯一识别这个文件. 1.2. dwarfdump 苹果提供的命令行工具,其中一些功能就是查 ...

  8. 全战三国战斗结束卡住_新一代显卡杀手!《三国:全面战争》PC性能分析报告...

    <三国:全面战争(Total War: Three Kingdoms)>将于本周四(5月23日)正式发售,本作采用"Warscape Engine"引擎制作,并使用了D ...

  9. iOS线上APP崩溃(Crash)分析

    这两周一直在研究如何追踪线上的bug,如何快速分析出程序到底崩溃在什么地方,从底层了解Crash是如何产生的.如何传递的.以及是如何分析出来的.虽然项目组并没有对这些要求很严格,但是作为一个高级开发人 ...

最新文章

  1. python学习笔记(二)---编辑工具sublimeText3运行python
  2. Java多态-如何理解父类引用指向子类对象
  3. Silverlight 置于悬浮层之下 背景透明的方法
  4. kinect 录制彩色和深度视频
  5. Python 3.9.0a6 已可用于测试
  6. 【网络教程】Windows字体发虚,字体不清晰怎么办?
  7. 个人简历表格 会计简历模板 个人简历模板手机版
  8. TensorFlow-gpu安装和测试(TensorFlow-gpu1.14+Cuda10)
  9. 海贼王热血航线服务器维护4月,航海王热血航线4月29日停服公告一览
  10. 澳门上葡京综合度假村冬季献礼迎佳节
  11. LiveQing流媒体RTMP推流服务-如何获直播流地址 HLS/HTTP-FLV/WS-FLV/WebRTC/RTMP视频流地址
  12. 标签云打印/微信小程序蓝牙标签打印开放平台功能
  13. 对金融基础知识的小总结
  14. ANSYS经典界面保存单元解和节点解
  15. ps切出来的图片导出来只有一张是png格式的其他全是jpg格式,怎么样让所有的切片变成png格式。
  16. matlab振动仿真实例小论文,《基于Matlab_Simulink的机械振动仿真研究》-毕业论文.doc...
  17. 前端面试官问Promise,怎样回答拿高分
  18. 国考省考行测:年均增长率,等速率增长率问题
  19. 64位Win7环境下,C#无法打开osk.exe解决方法
  20. 论文代理发表一般有什么技巧

热门文章

  1. 应用软件(E-MAIL-FTP-WEB)
  2. [Linux学习]Linux下进程通讯之共享内存
  3. C++ unique
  4. SDNU 1209.磊磊的随机数
  5. Python 实现整数线性规划:分枝定界法(Branch and Bound)
  6. 实力封装:Unity打包AssetBundle(大结局)
  7. 一张图,看清人体触碰禁区
  8. C# 写入和读出文本文件
  9. 利用Javadoc工具生成api文档
  10. virus.win32.parite.H病毒的查杀方法