• 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了。

  • 相关阅读:
    结构型模式上
    创建型模式下
    创建型模式中
    创建型模式上
    设计模式总述
    Java中事件机制
    UI常用控件
    UITextField和UIViewConteoller
    UIScrollView 和 UIPageControl
    分栏视图控制器
  • 原文地址:https://www.cnblogs.com/YYPapa/p/6850659.html
Copyright © 2020-2023  润新知