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 ([email protected]=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, [email protected]=0xae9a0908, count=0, [email protected]=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 ([email protected]=0xae9a0800, [email protected]=0xae9a0908, [email protected]=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, [email protected]=<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了。

时间: 2024-10-14 12:34:43

InputFlinger崩溃问题分析报告的相关文章

iOS崩溃日志分析-b

1名词解释 1.1. UUID 一个字符串,在iOS上每个可执行文件或库文件都包含至少一个UUID,目的是为了唯一识别这个文件. 1.2. dwarfdump 苹果提供的命令行工具,其中一些功能就是查看可执行文件或库文件的UUID.示例: dwarfdump --uuid 应用名称.app/应用名称 dwarfdump --uuid 应用名称.dSYM 1.3. symbolicatecrash 苹果提供的命令行工具,可以将crash日志符号化为可读的堆栈信息.XCode6/XCode7版本中,

爱奇艺、优酷、腾讯视频竞品分析报告2016(一)

1 背景 1.1 行业背景 1.1.1 移动端网民规模过半,使用时长份额超PC端 2016年1月22日,中国互联网络信息中心 (CNNIC)发布第37次<中国互联网络发展状况统计报告>,报告显示,网民的上网设备正在向手机端集中,手机成为拉动网民规模增长的主要因素.截至2015年12月,我国手机网民规模达6.20亿,有90.1%的网民通过手机上网. 图 1  2013Q1~2015Q3在线视频移动端和PC端有效使用时长份额对比 根据艾瑞网民行为监测系统iUserTracker及mUserTrac

后台数据管理分析报告.V.1.1

后台数据管理分析报告 负责人:姜敏 合伙人:任小风.贺丽霞 项目分析目标 1.项目目标:把APP后台建造完成 2.课上留的作业完成并放在博客园 3.要创建并连接数据库 4.在R中读出

中华英才网竞品分析报告2016

中华英才网竞品分析报告 1 背景 1.1 行业背景 1) 网民增速不断提升,移动端网民规模过半. 2016年1月22日,中国互联网络信息中心 (CNNIC)发布第37次<中国互联网络发展状况统计报告>.截至2015年12月,中国网民规模达6.88亿, 半数中国人已接入互联网. 其中,2015年新增网民3951万人,增长率为6.1%,较2014年提升1.1个百分点,网民规模增速有所提升. 图 1  2011-2018年中国整体网民数量及增长趋势 <报告>同时显示,网民的上网设备正在向

《亿人帮》与《新米公益》竞品分析报告(简要版)

<亿人帮>与<新米公益>竞品分析报告(简要版) --白斌 [email protected] iOS. APP版本皆为最新版 2016.12.12 竞品选择:<新米公益> 理由:都是互联网+公益,项目模式相同,两款APP均在2015年第二季度上线,SWOT四方面两者几乎是同样的起点.下面从产品的五个层次对二者进行分析并提出建议 一.战略层: 1.产品比较 产品名称 志愿者参与方式 slogan <新米公益> 走路.早起.答题 不止更好的自己 <亿人帮&

你的竞品分析报告是否有深入思考

竞品分析应该是一个长期且深入的工作.既要观察竞品的演变过程,又要能对竞品做深入的分析. 分析竞品的目的无非是,竞品是否能给到我们借鉴的作用?而竞品的迭代,也无外乎两个,用户想要的(需求),产品想要的(价值). 一. 我是怎么做竞品分析的? 首先,我做竞品的方法,一般包括以下两种.并行. 1 .选定要观察的竞品.然后,定期观察竞品是否有迭代,迭代的内容记录下来.如果有特别重要的变更,发出来进行讨论.每个月汇总一次竞品观察,邮件发送到要知悉的人. 2 .每次选择一款竞品深入地体验,做到大部分的用户流

“找出水王”分析报告

“找出水王”分析报告 一.题目要求 三人行设计了一个灌水论坛.信息学院的学生都喜欢在上面交流灌水,传说在论坛上有一个“水王”,他不但喜欢发帖,还会回复其他ID发的每个帖子.坊间风闻该“水王”发帖数目超过了帖子数目的一半. 如果你有一张当前论坛的帖子(包括回帖)列表,其中帖子的作者的ID也在其中,你能快速的找到这个传说中的水王吗? 二.设计思路 1.水王的发帖数超过所有人的一半,这个是个重要信息. 2.这个就和开心消消乐一样,一对一对的把不同的id消去,剩下的一定就是水王的id. 3.因为水王的i

国际软件设计文档——测试分析报告

1 引言 1.1 编写目的 说明这份测试分析报告的具体编写目的,指出预期的阅读范围. 1.2 背景 说明: 被测试软件系统的名称: 该软件的任务提出者.开发者.用户及安装此软件的计算中心,指出测试环境与实际运行环境 之间可能存在的差异以及这些差异对测试结果的影响. 1.3 定义 列出本文件中用到的专问术语的定义和外文首字母组词的原词组. 1.4 参考资料 列出要用到的参考资料,如: a.  本项目的经核准的计划任务书或合同.上级机关的批文: b.  属于本项目的其他已发表的文件: c.  本文件

08年写的感染类病毒分析报告

贴这个呢,有点不好意思,但是也是加分项.1分也是分. 这里要做一个简单介绍. 这篇报告呢: 1.分析的病毒样本是感染型的.但是呢,它同时又是个后门型的,比较有意思. 2.这篇也算是代码级的分析,毕竟用了ollydbg嘛,F7跟了,还手动把壳脱了.大牛别笑话我啊. 3.我本人倾向于应用.做过三年的CERT的工作,对于一般的病毒啊啥的还能应付. 4.对病毒了解的话呢,要求对整个系统有个比较系统的了解,所以呢,一般的应用问题,即使没遇到过,也是可以通过思考解决的.这点请注意. 这篇文章是当年张晓兵经理