[Android] Input事件分发流程之InputDispatcher(3)

InputDispatcher线程

先看看notifyMotion方法,因为是从InputReader中传递过来的,并携带了NotifyMotionArgs实体

void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
		...
		// 日志输出
    ALOGD("notifyMotion - id=%" PRIx32 " eventTime=%" PRId64 ", deviceId=%d, source=0x%x, "
          "displayId=%" PRId32 ", policyFlags=0x%x, "
          "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, "
          "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, xCursorPosition=%f, "
          "yCursorPosition=%f, downTime=%" PRId64,
          args->id, args->eventTime, args->deviceId, args->source, args->displayId,
          args->policyFlags, args->action, args->actionButton, args->flags, args->metaState,
          args->buttonState, args->edgeFlags, args->xPrecision, args->yPrecision,
          args->xCursorPosition, args->yCursorPosition, args->downTime);
    for (uint32_t i = 0; i < args->pointerCount; i++) {
        ALOGD("  Pointer %d: id=%d, toolType=%d, "
              "x=%f, y=%f, pressure=%f, size=%f, "
              "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, "
              "orientation=%f",
              i, args->pointerProperties[i].id, args->pointerProperties[i].toolType,
              args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
              args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
              args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
              args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
              args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
              args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
              args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
              args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
              args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
    }
    ...
    bool needWake;
	   ...
        // Just enqueue a new motion event.
				// // 将传递过来的NotifyMotionArgs转换为MotionEntry对象
        std::unique_ptr<MotionEntry> newEntry =
                std::make_unique<MotionEntry>(args->id, args->eventTime, args->deviceId,
                                              args->source, args->displayId, policyFlags,
                                              args->action, args->actionButton, args->flags,
                                              args->metaState, args->buttonState,
                                              args->classification, args->edgeFlags,
                                              args->xPrecision, args->yPrecision,
                                              args->xCursorPosition, args->yCursorPosition,
                                              args->downTime, args->pointerCount,
                                              args->pointerProperties, args->pointerCoords, 0, 0);
				// 目的为了把needWake变为true
        needWake = enqueueInboundEventLocked(std::move(newEntry));
        mLock.unlock();
    } // release lock

    if (needWake) {
				// 初始化的时候就已经创建了一个单独的looper,这里通知looper中的线程唤醒
        mLooper->wake();
    }
}

好了,以上就是根据传递过来的NotifyMotionArgs对象,转换为MotionEntry对象,包含了EventEntry(存储的事件类型),并唤醒本身的looper线程,继续看看InputDispatcher中的线程

status_t InputDispatcher::start() {
    if (mThread) {
        return ALREADY_EXISTS;
    }
    mThread = std::make_unique<InputThread>(
            "InputDispatcher", [this]() { dispatchOnce(); }, [this]() { mLooper->wake(); });
    return OK;
}

以上就是创建了InputThread线程,线程名称为InputDispatcher,继续看看dispatchOnce

void InputDispatcher::dispatchOnce() {
    ...
    dispatchOnceInnerLocked(&nextWakeupTime);
    ...
    nsecs_t currentTime = now();
    int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
    mLooper->pollOnce(timeoutMillis);
}

具体看看dispatchOnceInnerLocked函数

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
	switch (mPendingEvent->type) {
       ...
        case EventEntry::Type::KEY: {
	           ...
            done = dispatchKeyLocked(currentTime, keyEntry, &dropReason, nextWakeupTime);
            break;
        }

        case EventEntry::Type::MOTION: {
	           ...
            done = dispatchMotionLocked(currentTime, motionEntry, &dropReason, nextWakeupTime);
            break;
        }
}

MotionEntry中保存了EventEntry,EventEntry中又保留了事件类型,根据传递类型属于MOTION,继续分析dispatchMotionLocked函数

		bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
		...

    if (isPointerEvent) {
        // Pointer event.  (eg. touchscreen)
        // 默认走这,找到一个合适的window:简言之就是遍历所有window,看触摸事件发生在哪个window上,找到该window
        // window/TouchMonitors和输入事件进行了绑定
        // TouchMonitors会有多个,代表了触摸到的所有window,每个有输入事件的window都有一个TouchMonitors
				// injectionResult返回为真代表可以往window注入事件
        injectionResult =
                findTouchedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime,
                                               &conflictingPointerActions);
    }
		...
		// 如果injectionResult不为SUCCESS,则返回false不做事件分发,不会丢掉此次事件,下次再处理
		if (injectionResult == InputEventInjectionResult::PENDING) {
        return false;
    }
		// 如果返回值属于权限不足,则不做事件分发,丢掉此次的事件
		if (injectionResult == InputEventInjectionResult::PERMISSION_DENIED) {
        ALOGW("Permission denied, dropping the motion (isPointer=%s)", toString(isPointerEvent));
        return true;
    }
		// 如果injectionResult不为SUCCESS,则返回true不做事件分发,丢掉此次的事件
		if (injectionResult != InputEventInjectionResult::SUCCEEDED) {
        CancelationOptions::Mode mode(isPointerEvent
                                              ? CancelationOptions::CANCEL_POINTER_EVENTS
                                              : CancelationOptions::CANCEL_NON_POINTER_EVENTS);
        CancelationOptions options(mode, "input event injection failed");
        synthesizeCancelationEventsForMonitorsLocked(options);
        return true;
    }
		// 事件分发,inputTargets代表了window窗口句柄,event是MotionEntry,属于InputDispatcher中单独封装的,包含了原始事件的转换
		dispatchEventLocked(currentTime, entry, inputTargets);

首先会调用findTouchedWindowTargetsLocked函数来遍历当前所有的window,找到发生输入事件的window,然后调用dispatchEventLocked分发TouchMonitors,也就是为每个window分发输入事件,先分析以下两个函数

  • findTouchedWindowTargetsLocked

    InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
            nsecs_t currentTime, const MotionEntry& entry, std::vector<InputTarget>& inputTargets,
            nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) {
    
    		bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN ||
                           maskedAction == AMOTION_EVENT_ACTION_SCROLL || isHoverAction);
        // true,接下来事件都会保存在tempTouchState中
    		// 处理新手势,按下,因为手势都是从按下开始的
        if (newGesture) {
            bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN;
            if (switchedDevice && tempTouchState.down && !down && !isHoverAction) {
                ALOGI("Dropping event because a pointer for a different device is already down "
                      "in display %" PRId32,
                      displayId);
                // TODO: test multiple simultaneous input streams.
                injectionResult = InputEventInjectionResult::FAILED;
                switchedDevice = false;
                wrongDevice = true;
                goto Failed;
            }
            tempTouchState.reset();
            tempTouchState.down = down;
            tempTouchState.deviceId = entry.deviceId;
            tempTouchState.source = entry.source;
            tempTouchState.displayId = displayId;
            isSplit = false;
        }
    		// 进入该分支
    		if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
            /* Case 1: New splittable pointer going down, or need target for hover or scroll. */
    
    				// 触摸时的坐标
            int32_t x;
            int32_t y;
            int32_t pointerIndex = getMotionEventActionPointerIndex(action);
            // 拿到点击事件的x,y
    				x = int32_t(entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_X));
            y = int32_t(entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y));
            // true
            bool isDown = maskedAction == AMOTION_EVENT_ACTION_DOWN;
            // 找到合适的window,WindowInfoHandle是一个代表应用程序窗口的结构体。
            // 它包含一个窗口句柄、应用程序进程的PID和UID、窗口视图的屏幕矩形、窗口是否可见等信息
            // 在找window的时候,会判断window是否有效,是否具有焦点,是否可见,若都满足,才会返回window
            // 事件信息都临时保存在tempTouchState中
            newTouchedWindowHandle =
                    findTouchedWindowAtLocked(displayId, x, y, &tempTouchState,
                                              isDown /*addOutsideTargets*/, true /*addPortalWindows*/);
    
            ...
            if (newTouchedWindowHandle != nullptr &&
                mBlockUntrustedTouchesMode != BlockUntrustedTouchesMode::DISABLED) {
                // 这个函数主要是处理遮挡window的情况,例如:
                // 计算目标窗口是否遮挡了当前窗口,如果是,则该触摸区域不能传递给当前窗口处理,需要传递给目标窗口处理;
                // 计算目标窗口是否遮挡了其他窗口,如果是,则需要递归地检查该窗口及其子窗口是否被遮挡;
                // 逐层向上检查父窗口是否遮挡当前窗口,如果遮挡,则该触摸区域不能传递给当前窗口处理
    						// 需要传递给遮挡窗口的子窗口(或底层窗口)处理;
                // 如果目标窗口与当前窗口重叠,则需要进行更精细的检查,以确定哪个窗口能够接收触摸事件。
                TouchOcclusionInfo occlusionInfo =
                        computeTouchOcclusionInfoLocked(newTouchedWindowHandle, x, y);
                if (!isTouchTrustedLocked(occlusionInfo)) {
                    if (DEBUG_TOUCH_OCCLUSION) {
                        ALOGD("Stack of obscuring windows during untrusted touch (%d, %d):", x, y);
                        for (const auto& log : occlusionInfo.debugInfo) {
                            ALOGD("%s", log.c_str());
                        }
                    }
                    onUntrustedTouchLocked(occlusionInfo.obscuringPackage);
                    if (mBlockUntrustedTouchesMode == BlockUntrustedTouchesMode::BLOCK) {
                        ALOGW("Dropping untrusted touch event due to %s/%d",
                              occlusionInfo.obscuringPackage.c_str(), occlusionInfo.obscuringUid);
                        newTouchedWindowHandle = nullptr;
                    }
                }
            }
    
            // selectResponsiveMonitorsLocked方法:用于从当前所有的TouchedMonitor中筛选出只响应当前触摸事件的手势监控器
            // TouchedMonitor,GestureMonitor
            // findTouchedGestureMonitorsLocked:用于查找指定屏幕上被触摸的手势监控器。
            // 该函数主要在处理触摸事件的分发过程中使用,以确定哪些手势监控器需要响应当前触摸事件
            // 1.获取指定屏幕上被触摸的所有窗口,以及它们的窗口类型和窗口句柄;
            // 2.逐个遍历所有窗口,针对每个手势监控器窗口,判断触摸坐标是否在窗口内部;
            // 3.如果触摸坐标在窗口内部,则将该手势监控器加入到结果列表中;
            // 4.最终将所有被触摸的手势监控器返回
            // 以上步骤获取到了所有被触摸的TouchedMonitor,然后存入了newGestureMonitors中
            // tempTouchState属于TouchState结构体,tempTouchState.portalWindows保存了触摸过的所有window
            const std::vector<TouchedMonitor> newGestureMonitors = isDown
                    ? selectResponsiveMonitorsLocked(
                              findTouchedGestureMonitorsLocked(displayId, tempTouchState.portalWindows))
                    : tempTouchState.gestureMonitors;
    
           ...
    
            if (newTouchedWindowHandle != nullptr) {
    						...
                // 将找到的窗口添加进tempTouchState(TouchState)
                tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
            }
            // 为true,保存newGestureMonitors(每个触摸过的window都有一个TouchMonitors)到tempTouchState中
            if (isDown) {
                tempTouchState.addGestureMonitors(newGestureMonitors);
            }
        }
    		// 检查是否具有手势监控器,检查所有窗口中是否有前景窗口(必须有一个,不然事件该分发到谁身上?)
    		bool hasGestureMonitor = !tempTouchState.gestureMonitors.empty();
        if (!haveForegroundWindow && !hasGestureMonitor) {
            ALOGI("Dropping event because there is no touched foreground window in display "
                  "%" PRId32 " or gesture monitor to receive it.",displayId);
            injectionResult = InputEventInjectionResult::FAILED;
            goto Failed;
        }
    
        // 赋予注入权限,后面还会检查uid是否一致
        injectionPermission = INJECTION_PERMISSION_GRANTED;	
    		// 检查都通过,可以往window注入事件了
        injectionResult = InputEventInjectionResult::SUCCEEDED;
    
        // 处理tempTouchState里所包含的所有window,如果发现InputTarget为空则会为这个window创建一个
    		// 保存了window的屏幕尺寸,密度,inputChannel等信息,代表了window的token
        for (const TouchedWindow& touchedWindow : tempTouchState.windows) {
            addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags,
                                  touchedWindow.pointerIds, inputTargets);
        }
    
        // 添加手势监视器,也就是将InputTarget中的inputChannel更新为monitor中的inputChannel
        for (const TouchedMonitor& touchedMonitor : tempTouchState.gestureMonitors) {
            addMonitoringTargetLocked(touchedMonitor.monitor, touchedMonitor.xOffset,
                                      touchedMonitor.yOffset, inputTargets);
        }
        tempTouchState.filterNonAsIsTouchWindows();
        //函数到这里就结束了,再往下就是failed代码块了
    
    		...
    		return injectionResult;
    }
    

    以上代码为判断是不是新手势 (从down按下开始),然后将触摸事件(哪块设备,哪块屏幕,是否属于down事件)保存到tempTouchState中,然后根据触摸的x,y坐标和displayId(哪块屏幕),去找到发生触摸事件的window(findTouchedWindowAtLocked函数),返回值就是WindowInfoHandle,代表着一个window,然后再去处理遮挡window的情况,如果发现目标窗口被父窗口遮挡了,那么事件会分发给父窗口,然后通过findTouchedGestureMonitorsLocked去找到手势监控器,因为每个触摸过的window都有一个手势监控器,将手势监控器和window窗体都保存到tempTouchState中,再检查window权限是否可以将事件注入到该window上,若权限通过,则遍历tempTouchState中保存的window将事件注入到该window上,再为每个Window创建InputTarget(代表输入事件的目标对象,代表了window窗口句柄),再将inputTarget保存到inputTargets集合中,然后遍历手势监控器,更新了一下inputChannel,先讲解以下函数:

    • findTouchedWindowAtLocked

      sp<WindowInfoHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, int32_t x,
                                                                      int32_t y, TouchState* touchState,
                                                                      bool addOutsideTargets,
                                                                      bool addPortalWindows,
                                                                      bool ignoreDragWindow) {
      
      		// 获取当前屏幕的所有window
          const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesLocked(displayId);
          // 遍历所有window
          for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
              ...
              const WindowInfo* windowInfo = windowHandle->getInfo();
              // window所在的屏幕是否和事件产生的屏幕一致
              if (windowInfo->displayId == displayId) {
                  auto flags = windowInfo->flags;
                  // window必须可见
                  if (windowInfo->visible) {
                      // NOT_TOUCHABLE如果带有这个flag,则点击事件会被穿透到下一层window,本身window无法响应
                      // 例如toast弹窗(系统窗口),就是无法响应事件的
                      // 用于表示应用程序窗口是否接收触摸事件
                      if (!flags.test(WindowInfo::Flag::NOT_TOUCHABLE)) {//not_touchable
                          // 判断是否具有焦点
                          bool isTouchModal = !flags.test(WindowInfo::Flag::NOT_FOCUSABLE) &&
                                  !flags.test(WindowInfo::Flag::NOT_TOUCH_MODAL);
                          // 如果一个应用程序窗口被设置为NOT_TOUCHABLE标志,则它的touchableRegion将为空,
                          // 此时windowInfo->touchableRegionContainsPoint(x, y)方法将始终返回false。
                          // 否则,如果窗口是可触摸的,则windowInfo->touchableRegionContainsPoint(x, y)方法将检查坐标点(x, y)是否在touchableRegion中,
                          // 如果是,则返回true,否则返回false。
                          // 可以使用此方法来检查用户点击的位置是否在window的可触摸区域内,以便在处理用户输入事件时选择正确的窗口。
                          if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
                              int32_t portalToDisplayId = windowInfo->portalToDisplayId;
                              if (portalToDisplayId != ADISPLAY_ID_NONE &&
                                  portalToDisplayId != displayId) {
                                  if (addPortalWindows) {
                                      // For the monitoring channels of the display.
                                      touchState->addPortalWindow(windowHandle);
                                  }
                                  return findTouchedWindowAtLocked(portalToDisplayId, x, y, touchState,
                                                                   addOutsideTargets, addPortalWindows);
                              }
                              // Found window.返回window
                              return windowHandle;
                          }
                      }
                      // 如果WindowInfo的Flag字段包含了WATCH_OUTSIDE_TOUCH标志,则表示此window关注用户是否在窗口外部发生触摸事件。
                      // 当用户在窗口外部发生触摸事件时,系统将保持此窗口的焦点(focus)状态,并将发送一个ACTION_OUTSIDE类型的MotionEvent事件给此窗口,
                      // 以通知此窗口发生了外部触摸事件,例如dialog
                      if (addOutsideTargets && flags.test(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH)) {
                          touchState->addOrUpdateWindow(windowHandle,
                                                        InputTarget::FLAG_DISPATCH_AS_OUTSIDE,
                                                        BitSet32(0));
                      }
                  }
              }
          }
          return nullptr;
      }
      

      简单说就是通过以下几步来找到window:

      1. 遍历当前屏幕所有窗口,检查窗口是否和触摸事件属于同一个屏幕,window是否可见
      2. 再检查是否带有NOT_TOUCHABLE这个标志和是否具有焦点,来决定当前window是消费此事件,如果不消费,会将事件交给下一个window
      3. 然后检查用户点击的位置是否在window的可触摸区域内

      返回的windowHandle对象就是窗口实体

    • findTouchedGestureMonitorsLocked

      这个方法主要是为了找到InputTarget,即手势监控器,里面保存了触摸事件,一个window对应了一个手势监控器

      std::vector<TouchedMonitor> InputDispatcher::findTouchedGestureMonitorsLocked(
              int32_t displayId, const std::vector<sp<WindowInfoHandle>>& portalWindows) const {
          std::vector<TouchedMonitor> touchedMonitors;
      
          std::vector<Monitor> monitors = getValueByKey(mGestureMonitorsByDisplay, displayId);
          addGestureMonitors(monitors, touchedMonitors);
          // 遍历所有窗口
          for (const sp<WindowInfoHandle>& portalWindow : portalWindows) {
              const WindowInfo* windowInfo = portalWindow->getInfo();
              //获取每个window的TouchedMonitor
              monitors = getValueByKey(mGestureMonitorsByDisplay, windowInfo->portalToDisplayId);
              // 将每个监视器(monitors)都存入touchedMonitors中
              addGestureMonitors(monitors, touchedMonitors, -windowInfo->frameLeft,
                                 -windowInfo->frameTop);
          }
          return touchedMonitors;
      }
      
    • addOrUpdateWindow

      void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle, int32_t targetFlags,
                                         BitSet32 pointerIds) {
          if (targetFlags & InputTarget::FLAG_SPLIT) {
              split = true;
          }
      
          for (size_t i = 0; i < windows.size(); i++) {
              TouchedWindow& touchedWindow = windows[i];
              if (touchedWindow.windowHandle == windowHandle) {
                  touchedWindow.targetFlags |= targetFlags;
                  if (targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) {
                      touchedWindow.targetFlags &= ~InputTarget::FLAG_DISPATCH_AS_IS;
                  }
                  touchedWindow.pointerIds.value |= pointerIds.value;
                  return;
              }
          }
      
          TouchedWindow touchedWindow;
          touchedWindow.windowHandle = windowHandle;
          touchedWindow.targetFlags = targetFlags;
          touchedWindow.pointerIds = pointerIds;
          windows.push_back(touchedWindow);
      }
      

      可以看出来就是更新当前window或者新增window到windows中,代码位于TouchState.cpp中

    • addWindowTargetLocked

      void InputDispatcher::addWindowTargetLocked(const sp<WindowInfoHandle>& windowHandle,
                                                  int32_t targetFlags, BitSet32 pointerIds,
                                                  std::vector<InputTarget>& inputTargets) {
          // 找到window的句柄,也就是当前window,是可能为空的
          std::vector<InputTarget>::iterator it =
                  std::find_if(inputTargets.begin(), inputTargets.end(),
                               [&windowHandle](const InputTarget& inputTarget) {
                                   return inputTarget.inputChannel->getConnectionToken() ==
                                           windowHandle->getToken();
                               });
      
          const WindowInfo* windowInfo = windowHandle->getInfo();
          // 如果该对象为空(InputTarget代表输入事件的目标对象,通常是触摸屏、按键或手柄等外部设备的桥梁对象)
          if (it == inputTargets.end()) {
              InputTarget inputTarget;
              std::shared_ptr<InputChannel> inputChannel =
                      getInputChannelLocked(windowHandle->getToken());
              ...
      			  // 创建inputTarget对象,保存window和屏幕信息
      				// 并将该对象保存到inputTargets集合中
              inputTarget.inputChannel = inputChannel;
              inputTarget.flags = targetFlags;
              inputTarget.globalScaleFactor = windowInfo->globalScaleFactor;
              inputTarget.displayOrientation = windowInfo->displayOrientation;
              inputTarget.displaySize =
                      int2(windowHandle->getInfo()->displayWidth, windowHandle->getInfo()->displayHeight);
              inputTargets.push_back(inputTarget);
              it = inputTargets.end() - 1;
          }
      
          ALOG_ASSERT(it->flags == targetFlags);
          ALOG_ASSERT(it->globalScaleFactor == windowInfo->globalScaleFactor);
      
          // 将pointerIds和window绑定,pointerIds就是手指id
          it->addPointers(pointerIds, windowInfo->transform);
      }
      

    至此,整个流程结束,目的都是为了找到window窗口,处理window窗口,返回injectionResult,若为true,代表窗口可以注入事件,所以继续看看下一个阶段步骤dispatchEventLocked

  • dispatchEventLocked

    此处进行事件分发,因为已经处理好了对应的window和权限相关

    void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
                                              std::shared_ptr<EventEntry> eventEntry,
                                              const std::vector<InputTarget>& inputTargets) {
    
       ...
        // 向系统发送一个用户活动的信号,以防止在事件分发的时候设备进入休眠模式
        pokeUserActivityLocked(*eventEntry);
    
        for (const InputTarget& inputTarget : inputTargets) {
            // 获得window连接
            sp<Connection> connection =
                    getConnectionLocked(inputTarget.inputChannel->getConnectionToken());
            if (connection != nullptr) {
                //准备分发事件
                prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget);
            } ...
        }
    }
    

    prepareDispatchCycleLocked函数中会调用enqueueDispatchEntriesLocked继续执行下一步逻辑

    void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
                                                       const sp<Connection>& connection,
                                                       std::shared_ptr<EventEntry> eventEntry,
        ...
        // 只有当事件输出队列为空的时候,才会开始分发
        bool wasEmpty = connection->outboundQueue.empty();
    
        // 生成DispatchEntry,再将**分发实体**存入outboundQueue队列中(输出的分发队列)
        enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
                                   InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
        enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
                                   InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
        enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
                                   InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
        enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
                                   InputTarget::FLAG_DISPATCH_AS_IS);
        enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
                                   InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
        enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
                                   InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
    
        // If the outbound queue was previously empty, start the dispatch cycle going.
        if (wasEmpty && !connection->outboundQueue.empty()) {
            // 开始分发事件
            startDispatchCycleLocked(currentTime, connection);
        }
    }
    

    需要继续分析一下enqueueDispatchEntryLockedstartDispatchCycleLocked

    • enqueueDispatchEntryLocked

      void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connection,
                                                       std::shared_ptr<EventEntry> eventEntry,
                                                       const InputTarget& inputTarget,
                                                       int32_t dispatchMode) {
      	  ...
          // 根据inputTarget里面的屏幕信息以及eventEntry,构建出一个DispatchEntry
          std::unique_ptr<DispatchEntry> dispatchEntry =
                  createDispatchEntry(inputTarget, eventEntry, inputTargetFlags);
      		dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN;
      		dispatchEntry->resolvedAction = motionEntry.action;
          dispatchEntry->resolvedEventId = motionEntry.id;
      		...
      		// 将分发实体存入outboundQueue队列中(输出的分发队列)
          connection->outboundQueue.push_back(dispatchEntry.release());
      
    • startDispatchCycleLocked

      void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
                                                     const sp<Connection>& connection) {//DispatchEntry
          ...
          // 开始分发DispatchEntry实体事件,outboundQueue保存了EventEntry和屏幕信息,也就是DispatchEntry实体
          while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.empty()) {
              // 获得dispatchEntry
              DispatchEntry* dispatchEntry = connection->outboundQueue.front();
              dispatchEntry->deliveryTime = currentTime;
              const std::chrono::nanoseconds timeout =
                      getDispatchingTimeoutLocked(connection->inputChannel->getConnectionToken());
      				// 设置超时相关
              dispatchEntry->timeoutTime = currentTime + timeout.count();
      
              // Publish the event.
              status_t status;
              // 从dispatchEntry拿到EventEntry
              const EventEntry& eventEntry = *(dispatchEntry->eventEntry);
              switch (eventEntry.type) {
                  ...
                  case EventEntry::Type::MOTION: {//主要关心这个case
                      // 转换为MotionEntry,父子关系
                      const MotionEntry& motionEntry = static_cast<const MotionEntry&>(eventEntry);
      								...
                      // Publish the motion event.
                      // 发布event事件,将一个输入事件(通常是一个运动事件)发送到指定的应用程序
                      // 将屏幕信息,屏幕id,实体序列号,动作源事件(down),event状态(按下等状态),位于屏幕的xy坐标
                      // 手指数量,屏幕方向,传递给应用程序
                      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,
                                                           motionEntry.xPrecision, motionEntry.yPrecision,
                                                           motionEntry.xCursorPosition,
                                                           motionEntry.yCursorPosition,
                                                           dispatchEntry->displayOrientation,
                                                           dispatchEntry->displaySize.x,
                                                           dispatchEntry->displaySize.y,
                                                           motionEntry.downTime, motionEntry.eventTime,
                                                           motionEntry.pointerCount,
                                                           motionEntry.pointerProperties, usingCoords);
                      break;
                  }
      						...
      }
      

      继续分析一下publishMotionEvent是怎么发送消息到上层的

      frameworks/native/libs/input/InputTransport.cpp

      // 屏幕信息,屏幕id,实体序列号,动作源事件(down),event状态(按下等状态),位于屏幕的xy坐标,手指数量,屏幕方向
      status_t InputPublisher::publishMotionEvent(
              uint32_t seq, int32_t eventId, int32_t deviceId, int32_t source, int32_t displayId,
              std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton, int32_t flags,
              int32_t edgeFlags, int32_t metaState, int32_t buttonState,
              MotionClassification classification, const ui::Transform& transform, float xPrecision,
              float yPrecision, float xCursorPosition, float yCursorPosition, uint32_t displayOrientation,
              int32_t displayWidth, int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime,
              uint32_t pointerCount, const PointerProperties* pointerProperties,
              const PointerCoords* pointerCoords) {
         ...
      
          // 将传递过来的信息DispatcherEntry转换为InputMessage对象
          // 传递过来的信息属于DispatchEntry对象里的内容,DispatchEntry对象也就是存在outbound队列中待分发的事件信息
          InputMessage msg;
          msg.header.type = InputMessage::Type::MOTION;
          msg.header.seq = seq;
          msg.body.motion.eventId = eventId;
          msg.body.motion.deviceId = deviceId;
          msg.body.motion.source = source;
          msg.body.motion.displayId = displayId;
          msg.body.motion.hmac = std::move(hmac);
          msg.body.motion.action = action;
          msg.body.motion.actionButton = actionButton;
          msg.body.motion.flags = flags;
          msg.body.motion.edgeFlags = edgeFlags;
          msg.body.motion.metaState = metaState;
          msg.body.motion.buttonState = buttonState;
          msg.body.motion.classification = classification;
          msg.body.motion.dsdx = transform.dsdx();
          msg.body.motion.dtdx = transform.dtdx();
          msg.body.motion.dtdy = transform.dtdy();
          msg.body.motion.dsdy = transform.dsdy();
          msg.body.motion.tx = transform.tx();
          msg.body.motion.ty = transform.ty();
          msg.body.motion.xPrecision = xPrecision;
          msg.body.motion.yPrecision = yPrecision;
          msg.body.motion.xCursorPosition = xCursorPosition;
          msg.body.motion.yCursorPosition = yCursorPosition;
          msg.body.motion.displayOrientation = displayOrientation;
          msg.body.motion.displayWidth = displayWidth;
          msg.body.motion.displayHeight = displayHeight;
          msg.body.motion.downTime = downTime;
          msg.body.motion.eventTime = eventTime;
          msg.body.motion.pointerCount = pointerCount;
          for (uint32_t i = 0; i < pointerCount; i++) {
              msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]);
              msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]);
          }
          // InputChannel 是用于实现输入事件通信的一种机制。
          // 它提供了一个简单且可靠的方式,让应用程序或系统进程可以与InputDispatcher.cpp进行通信
          // 向另一个端点发送消息。如果通道已满,则保证根本不会发送消息。在消费者发送完成信号后重试,表明它已从通道中消费了一些待处理的消息。
          // 成功返回OK。
          // 如果通道已满,则返回 WOULD_BLOCK。
          // 如果通道的对等点已关闭,则返回 DEAD_OBJECT。
          // 其他错误可能表示通道已损坏
          return mChannel->sendMessage(&msg);
      }
      

      以上就上将InputDispatcher中生产的对象DispatcherEntry转换为最后待发送的InputMessage对象,通过InputChannel发送到上层,socket形式,InputChannel会通过socket向远端的socket发送消息

      而InputChannel客户端会在activity的启动过程中会创建,在ViewRootImpl.java#setView中创建Java层的InputChannel对象mInputChannel(socket pair)并且创建了事件的监听new WindowInputEventReceiver(就会进入上层的事件分发)。而InputChannel服务端会保存到WindowState的mInputChannel。所以view事件分发就是客户端发给服务端的一个流程

      看看具体代码

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
            int userId) {
				// view测量,布局,绘制流程
				requestLayout();
				// 创建了客户端inputChannel
        InputChannel inputChannel = null;
        if ((mWindowAttributes.inputFeatures
               & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
              inputChannel = new InputChannel();
        }
				// inputChannel客户端和服务端已经创建完成
        // 底层会调用sendMessage发送事件给receiveMessage来收听事件
        // 然后就会将事件上报给WindowInputEventReceiver监听
       // 这里inputChannel还创建了事件的监听,由底层上报
       if (inputChannel != null) {
					...
           // 事件监听的实现,交给上层view分发事件
           mInputEventReceiver = new WindowInputEventReceiver(inputChannel,Looper.myLooper());
       }

}

你可能感兴趣的:(Android开发旅途,android,java,jvm,aosp)