InputFlinger崩溃问题分析报告

【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 scroll
    next->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了。

 

posted @ 2017-05-13 22:17  YYPapa  阅读(970)  评论(0编辑  收藏  举报