SurfaceFlinge/InputFlinger 분석 - 안드로이드 화면 확대 후 정상 원리 분석

안녕하세요, 팬 여러분, 친구 여러분:
지난 이틀 동안 우연히 무료 창과 관련된 내수 작업을 하게 되었고, 방금 의심에 부딪혔습니다. 즉, 화면을 확대한 후에도 화면을 터치하면 여전히 정상적으로 문제.
여기에 이미지 설명 삽입

구체적인 의심 배경

의문점은 다음과 같습니다:
좌표는 화면에 대한 것이고, 버튼도 활동에 상대적입니다.활동 자체의 너비는 화면의 너비와 동일하지만 화면 크기는 조정됩니다.활동 및 보기는 여전히 화면의 너비.그런 다음 왜 화면 좌표를 클릭하여 활동을 확대할 때 버튼이 여전히 정상적으로 반응합니까?

질문 및 답변 좌표 추적:

좌표 전송 프로세스를 기억하십시오.
터치 이벤트의 좌표는 입력되어야 합니다.dispatcher -----> app

inputdispatcher 좌표 결정

그런 다음 먼저 inputDispatcher가 전달한 좌표를 결정합니다.inputDispatcher의 좌표는 실제로 dumpys를 통해 볼 수 있습니다.

  RecentQueue: length=10
    MotionEvent(deviceId=11, eventTime=37449374871000, source=TOUCHSCREEN | STYLUS, displayId=0, action=MOVE, actionButton=0x00000000, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, classification=NONE, edgeFlags=0x00000000, xPrecision=22.8, yPrecision=11.1, xCursorPosition=nan, yCursorPosition=nan, pointers=[0: (1011.9, 909.9)]), policyFlags=0x62000000, age=1525ms
    MotionEvent(deviceId=11, eventTime=37449382843000, source=TOUCHSCREEN | STYLUS, displayId=0, action=MOVE, actionButton=0x00000000, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, classification=NONE, edgeFlags=0x00000000, xPrecision=22.8, yPrecision=11.1, xCursorPosition=nan, yCursorPosition=nan, pointers=[0: (1011.9, 901.0)]), policyFlags=0x62000000, age=1517ms
    MotionEvent(deviceId=11, eventTime=37449390835000, source=TOUCHSCREEN | STYLUS, displayId=0, action=MOVE, actionButton=0x00000000, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, classification=NONE, edgeFlags=0x00000000, xPrecision=22.8, yPrecision=11.1, xCursorPosition=nan, yCursorPosition=nan, pointers=[0: (1011.9, 898.9)]), policyFlags=0x62000000, age=1509ms
    MotionEvent(deviceId=11, eventTime=37449470965000, source=TOUCHSCREEN | STYLUS, displayId=0, action=MOVE, actionButton=0x00000000, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, classification=NONE, edgeFlags=0x00000000, xPrecision=22.8, yPrecision=11.1, xCursorPosition=nan, yCursorPosition=nan, pointers=[0: (1011.9, 901.0)]), policyFlags=0x62000000, age=1429ms
    MotionEvent(deviceId=11, eventTime=37449478951000, source=TOUCHSCREEN | STYLUS, displayId=0, action=MOVE, actionButton=0x00000000, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, classification=NONE, edgeFlags=0x00000000, xPrecision=22.8, yPrecision=11.1, xCursorPosition=nan, yCursorPosition=nan, pointers=[0: (1011.9, 903.0)]), policyFlags=0x62000000, age=1421ms
    MotionEvent(deviceId=11, eventTime=37449486891000, source=TOUCHSCREEN | STYLUS, displayId=0, action=MOVE, actionButton=0x00000000, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, classification=NONE, edgeFlags=0x00000000, xPrecision=22.8, yPrecision=11.1, xCursorPosition=nan, yCursorPosition=nan, pointers=[0: (1011.9, 907.9)]), policyFlags=0x62000000, age=1413ms
    MotionEvent(deviceId=11, eventTime=37449599726000, source=TOUCHSCREEN | STYLUS, displayId=0, action=MOVE, actionButton=0x00000000, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, classification=NONE, edgeFlags=0x00000000, xPrecision=22.8, yPrecision=11.1, xCursorPosition=nan, yCursorPosition=nan, pointers=[0: (1011.9, 904.9)]), policyFlags=0x62000000, age=1300ms
    MotionEvent(deviceId=11, eventTime=37449607604000, source=TOUCHSCREEN | STYLUS, displayId=0, action=MOVE, actionButton=0x00000000, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, classification=NONE, edgeFlags=0x00000000, xPrecision=22.8, yPrecision=11.1, xCursorPosition=nan, yCursorPosition=nan, pointers=[0: (1011.9, 901.0)]), policyFlags=0x62000000, age=1292ms
    MotionEvent(deviceId=11, eventTime=37449615411000, source=TOUCHSCREEN | STYLUS, displayId=0, action=MOVE, actionButton=0x00000000, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, classification=NONE, edgeFlags=0x00000000, xPrecision=22.8, yPrecision=11.1, xCursorPosition=nan, yCursorPosition=nan, pointers=[0: (1011.9, 896.9)]), policyFlags=0x62000000, age=1284ms
    MotionEvent(deviceId=11, eventTime=37449783797000, source=TOUCHSCREEN | STYLUS, displayId=0, action=UP, actionButton=0x00000000, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, classification=NONE, edgeFlags=0x00000000, xPrecision=22.8, yPrecision=11.1, xCursorPosition=nan, yCursorPosition=nan, pointers=[0: (1011.9, 896.9)]), policyFlags=0x62000000, age=1116ms

이때 화면의 절대좌표에 속하는 좌표포인터=[0:(1011.9, 901.0)])는 이때 inputdispatcher가 전달되면 Activity의 View와 동일한 좌표로 변경되지 않음은 자명하다. 즉, 기본적으로 앱으로 전달되는 inputdispatcher는 여전히 화면의 절대 좌표라고 결론지을 수 있습니다.

앱 끝의 좌표가 결정됩니다.

일반적으로 여기에서 앱 측의 좌표를 디버깅하거나 로그를 인쇄할 수 있습니다.
여기에 이미지 설명 삽입

여기서 원래의 dispatchInputEvent에 중단점을 만들어 좌표가 1341, 1633이 된 것을 확인했습니다.

   private void dispatchInputEvent(int seq, InputEvent event) {
    
    
        mSeqMap.put(event.getSequenceNumber(), seq);
        onInputEvent(event);
    }

즉, 일단 좌표가 자바 레벨에 도달하면 실제로 활동과 함께 정상적인 좌표가 되었기 때문에 계속해서 앱 레벨을 추격할 수 밖에 없습니다. 여기에서 Ma Ge의 입력 항목에 설명이 있으므로
여기에 이미지 설명 삽입
NativeInputEventReceiver::consumeEvents 및 InputConsumer.consume 메서드에 초점을 맞춰 관련 입력 데이터를 읽고 마지막으로 MotionEvent가 무효 InputConsumer::initializeMotionEvent에 구성되어 있음을 확인했습니다.

void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage* msg) {
    
    
    uint32_t pointerCount = msg->body.motion.pointerCount;
    PointerProperties pointerProperties[pointerCount];
    PointerCoords pointerCoords[pointerCount];
    for (uint32_t i = 0; i < pointerCount; i++) {
    
    
        pointerProperties[i].copyFrom(msg->body.motion.pointers[i].properties);
        pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords);
        ALOGE("initializeMotionEvent: pointerCount x= %f y = %f" ,pointerCoords[i].getX(),pointerCoords[i].getY());
    }
		//这里是坐标变化的关键转换矩阵
    ui::Transform transform;
    transform.set({
    
    msg->body.motion.dsdx, msg->body.motion.dtdx, msg->body.motion.tx,
                   msg->body.motion.dtdy, msg->body.motion.dsdy, msg->body.motion.ty, 0, 0, 1});
    ui::Transform displayTransform;
    displayTransform.set({
    
    msg->body.motion.dsdxRaw, msg->body.motion.dtdxRaw,
                          msg->body.motion.txRaw, msg->body.motion.dtdyRaw,
                          msg->body.motion.dsdyRaw, msg->body.motion.tyRaw, 0, 0, 1});
    event->initialize(msg->body.motion.eventId, msg->body.motion.deviceId, msg->body.motion.source,
                      msg->body.motion.displayId, msg->body.motion.hmac, msg->body.motion.action,
                      msg->body.motion.actionButton, msg->body.motion.flags,
                      msg->body.motion.edgeFlags, msg->body.motion.metaState,
                      msg->body.motion.buttonState, msg->body.motion.classification, transform,
                      msg->body.motion.xPrecision, msg->body.motion.yPrecision,
                      msg->body.motion.xCursorPosition, msg->body.motion.yCursorPosition,
                      displayTransform, msg->body.motion.downTime, msg->body.motion.eventTime,
                      pointerCount, pointerProperties, pointerCoords);
    ALOGE("initializeMotionEvent:2  pointerCount x= %f y = %f" ,event->getX(0),event->getY(0));
}

관련 인쇄가 다음과 같이 여기에 추가됩니다.

06-15 23:40:24.413  1850  1850 E InputTransport: initializeMotionEvent: pointerCount x= 1045.942383 y = 930.961914
06-15 23:40:24.413  1850  1850 E InputTransport: initializeMotionEvent:2  pointerCount x= 1371.884766 y = 1693.923828

첫 번째 단계에서 소켓에서 받은 이벤트 좌표는 여전히 입력 디스패처와 동일하지만 event->initialize 메소드 이후에 다시 출력하면 변경된 것을 알 수 있으며, 실제 활동 좌표와 동일합니다.
사실 본질적인 이유는 getX 메서드가 실제로 해당 메서드를 호출하여 좌표 변환을 수행하고 반환하기 때문에 초기화 중에 해당 변환이 전송에 영향을 받기 때문입니다.

 /**
     * Get the X coordinate of the latest sample in this MotionEvent for pointer 'pointerIndex'.
     * Identical to calling getHistoricalX(pointerIndex, getHistorySize()).
     */
    inline float getX(size_t pointerIndex) const {
    
    
        return getAxisValue(AMOTION_EVENT_AXIS_X, pointerIndex);
    }
    float MotionEvent::getAxisValue(int32_t axis, size_t pointerIndex) const {
    
    
    return getHistoricalAxisValue(axis, pointerIndex, getHistorySize());
}

float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex,
                                          size_t historicalIndex) const {
    
    
    const PointerCoords& coords = *getHistoricalRawPointerCoords(pointerIndex, historicalIndex);
    //注意这个时候就是会有对应的mTransform进行影响,导致坐标和屏幕坐标产生差异
    return calculateTransformedAxisValue(axis, mSource, mTransform, coords);
}

위의 내용은 명확하므로 남은 질문은 이 mTransform의 출처는 어디입니까?
여기서 우리는 이와 같이 mTransform을 전달하기 위해 inputdispatcher로 돌아가야 합니다.

   // Publish the motion event.
                status = connection->inputPublisher
                                 .publishMotionEvent(dispatchEntry->seq,
                                                     dispatchEntry->resolvedEventId,
                                                     motionEntry.deviceId, motionEntry.source,
                                                     motionEntry.displayId, std::move(hmac),
                                                     dispatchEntry->resolvedAction,
                                                     motionEntry.actionButton,
                                                     dispatchEntry->resolvedFlags,
                                                     motionEntry.edgeFlags, motionEntry.metaState,
                                                     motionEntry.buttonState,
                                                     motionEntry.classification,
                                                     dispatchEntry->transform,//这里就是关键的transform也会传递
                                                     motionEntry.xPrecision, motionEntry.yPrecision,
                                                     motionEntry.xCursorPosition,
                                                     motionEntry.yCursorPosition,
                                                     dispatchEntry->rawTransform,
                                                     motionEntry.downTime, motionEntry.eventTime,
                                                     motionEntry.pointerCount,
                                                     motionEntry.pointerProperties, usingCoords);

이 변환은 dumpsys의 입력에도 표시됩니다.

      5: name='692067c com.example.myapplication11/com.example.myapplication11.MainActivity', id=163, displayId=0, inputConfig=0x0, alpha=1.00, frame=[360,84][1080,972], globalScale=1.000000, applicationInfo.name=ActivityRecord{
    
    f9088f2 u0 com.example.myapplication11/.MainActivity} t465}, applicationInfo.token=0x7079fae2c370, touchableRegion=[308,32][1133,1025], ownerPid=1850, ownerUid=10116, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTED
        transform (ROT_0) (SCALE TRANSLATE)
            2.0000  -0.0000  -720.0000
            -0.0000  2.0000  -168.0000
            0.0000  0.0000  1.0000

이 변환을 보면 대략적인 행렬이 2배로 확대되고 오프셋이 -720.0000, -168.0000인 것을 볼 수 있습니다.이 변환으로 인해 화면의 절대 좌표에서 활동의 절대 좌표로 변환됩니다.후 변환, 응답에 대한 정상적인 좌표로 활동을 얻을 수 있습니다.

그런 다음 질문이 다시 발생합니다. inputdispatcher의 변환은 어디에서 오는 것입니까?

하하, 이전 입력 주제 설명으로 돌아가겠습니다. 이 windowinfo 정보는 실제로 SurfaceFlinger에서 가져옵니다. 다음은 dumpsys SurfaceFlinger에 관련 정보가 있는지 살펴봅니다.

* Layer 0x71a7e2b523f0 (com.example.myapplication11/com.example.myapplication11.MainActivity#268)
      isSecure=false geomUsesSourceCrop=true geomBufferUsesDisplayInverseTransform=false geomLayerTransform (ROT_0) (SCALE TRANSLATE)
    0.5000  0.0000  360.0000
    0.0000  0.5000  84.0000
    0.0000  0.0000  1.0000

해당 윈도우 레이어를 찾은 후 행렬을 보았는데 이 행렬이 입력 행렬과 다른 것 같지만 연관이 있는 것 같은데 이 관계는 무엇일까요? ㅎㅎ 표면을 원래 0.5로 축소해서 표시하고 다시 2배로 확대해서 되돌리는 과정을 역과정으로 하는 수업입니다. surfaceflinger 행렬은 surfacecontrol 작업을 위한 스케일링 행렬입니다.

따라서 전체 링크는 이미 명확하며 요약은 다음과 같습니다.

여기에 이미지 설명 삽입

추천

출처blog.csdn.net/learnframework/article/details/131240264