【安卓13 源码】Input子系统(4)- InputReader 数据处理

1. 多指触控协议

多指触控协议有 2 种:

> A类: 处理无关联的接触: 用于直接发送原始数据; 
> B类: 处理跟踪识别类的接触: 通过事件slot发送相关联的独立接触更新。

B协议可以使用一个ID来标识触点,可以减少上报到用户空间的数据量,这个ID(ABS_MT_TRACKING_ID)可以有硬件提供或者从原始数据计算而得。而InputReader 就是处理这些数据

通过下列命令可以dump :adb shell getevent -tl

[    1029.903648] /dev/input/event1: EV_SYN       0004                 00000405            
[    1029.903648] /dev/input/event1: EV_SYN       0005                 35c02ec5            
[    1029.903648] /dev/input/event1: EV_ABS       ABS_MT_SLOT          00000000           
[    1029.903648] /dev/input/event1: EV_ABS       ABS_MT_POSITION_X    00000173             第一个手指X坐标
[    1029.903648] /dev/input/event1: EV_ABS       ABS_MT_SLOT          00000001            
[    1029.903648] /dev/input/event1: EV_ABS       ABS_MT_POSITION_X    00000321             第二个手指X坐标
[    1029.903648] /dev/input/event1: EV_SYN       SYN_REPORT           00000000             [    1031.902947] /dev/input/event1: EV_SYN       0004                 00000407            
[    1031.902947] /dev/input/event1: EV_SYN       0005                 35b8a020            
[    1031.902947] /dev/input/event1: EV_ABS       ABS_MT_SLOT          00000000            第一个手指有事件 
[    1031.902947] /dev/input/event1: EV_ABS       ABS_MT_TRACKING_ID   ffffffff            TRACKING_ID为-1代表第一个手指抬起消失
[    1031.902947] /dev/input/event1: EV_SYN       SYN_REPORT           00000000             
[    1032.024946] /dev/input/event1: EV_SYN       0004                 00000408            
[    1032.024946] /dev/input/event1: EV_SYN       0005                 016372d8            
[    1032.024946] /dev/input/event1: EV_ABS       ABS_MT_SLOT          00000001            第二个手指有事件  
[    1032.024946] /dev/input/event1: EV_ABS       ABS_MT_POSITION_Y    0000016c              第二个 Y坐标
[    1032.024946] /dev/input/event1: EV_SYN       SYN_REPORT           00000000             
[    1032.907686] /dev/input/event1: EV_SYN       0004                 00000408            
[    1032.907686] /dev/input/event1: EV_SYN       0005                 35ebac8c            
[    1032.907686] /dev/input/event1: EV_ABS       ABS_MT_TRACKING_ID   ffffffff            第二个手指消失抬起  
[    1032.907686] /dev/input/event1: EV_KEY       BTN_TOUCH            UP                  抬起
[    1032.907686] /dev/input/event1: EV_KEY       BTN_TOOL_FINGER      UP                  
[    1032.907686] /dev/input/event1: EV_SYN       SYN_REPORT           00000000   

其中分为 3 个类型,为 EV_SYN、EV_ABS 和 EV_KEY
0004:代表一个事件开始(不必要)
0005:代表一个事件开始(不必要)
SYN_REPORT:代表一个事件的结束 (必要)

ABS_MT_SLOT:
本质代表者不同手指,它的value代表手指id
 ABS_MT_TRACKING_ID:
类型B特有的,实际上,每个slot会和一个ID相对应,一个非负数的表示一次接触,-1表示这是一个无用的slot(或者理解为一次接触的结束) 。

BTN_TOUCH
触碰按键。其值是DOWN或者UP。

2. InputReader 处理触摸数据

/frameworks/native/services/inputflinger/reader/InputReader.cpp

InputReader 监听设备的数据,getEvents()是阻塞的,只有当有事件或者被wake才会被唤醒向下执行。

86  void InputReader::loopOnce() {
87      int32_t oldGeneration;
88      int32_t timeoutMillis;
89      bool inputDevicesChanged = false;
90      std::vector<InputDeviceInfo> inputDevices;
91      { // acquire lock
92          std::scoped_lock _l(mLock);
93  
94          oldGeneration = mGeneration;
95          timeoutMillis = -1;
96  
。。。。。
107  
// 1)从eventhub 中获取驱动上报的事件 getEvents
108      size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
109  
110      { // acquire lock
111          std::scoped_lock _l(mLock);
112          mReaderIsAliveCondition.notify_all();
113  
114          if (count) {
// 2)处理上报的数据:processEventsLocked
115              processEventsLocked(mEventBuffer, count);
116          }
117  
。。。。
// 3)观察者队列去flush,处理全部的事件:flush
147      mQueuedListener->flush();
148  }

// 1)从eventhub 中获取驱动上报的事件 getEvents

1461  size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
1462      ALOG_ASSERT(bufferSize >= 1);
1463  
1464      std::scoped_lock _l(mLock);
1465  
1466      struct input_event readBuffer[bufferSize];
1467  
1468      RawEvent* event = buffer;
1469      size_t capacity = bufferSize;
1470      bool awoken = false;
1471      for (;;) {
1472          nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);。。。。。。
1548          // Grab the next input event.
1549          bool deviceChanged = false;// 设置 mPendingEventCount 值,则满足下列条件
1550          while (mPendingEventIndex < mPendingEventCount) {
1551              const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];// 通过fd 获取到对应的 Device,创建对象为 std::make_unique<Device>(fd
1577              Device* device = getDeviceByFdLocked(eventItem.data.fd);1605              if (eventItem.events & EPOLLIN) {
// 读取对应fd 的数据
1606                  int32_t readSize =
1607                          read(device->fd, readBuffer, sizeof(struct input_event) * capacity);。。。。。
1621                  } else {
1622                      int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
1623  
1624                      size_t count = size_t(readSize) / sizeof(struct input_event);
1625                      for (size_t i = 0; i < count; i++) {
1626                          struct input_event& iev = readBuffer[i];
1627                          event->when = processEventTimestamp(iev);
1628                          event->readTime = systemTime(SYSTEM_TIME_MONOTONIC);
1629                          event->deviceId = deviceId;
// 将上报的type 和 code value 保存到 event  中,遍历所有然后退出
1630                          event->type = iev.type;
1631                          event->code = iev.code;
1632                          event->value = iev.value;
1633                          event += 1;
1634                          capacity -= 1;
1635                      }
1636                      if (capacity == 0) {
1637                          // The result buffer is full.  Reset the pending event index
1638                          // so we will try to read the device again on the next iteration.
1639                          mPendingEventIndex -= 1;
1640                          break;
1641                      }
1642                  }
。。。。。。
// 首先是epoll 监听底层的事件
1688          int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
1689  
1690          mLock.lock(); // reacquire lock after poll
。。。。。。。
1708          } else {
1709              // Some events occurred.
// 如果有事件的话 设置 mPendingEventCount 值
1710              mPendingEventCount = size_t(pollResult);
1711          }
1712      }
1713  
1714      // All done, return the number of events we read.
1715      return event - buffer;
1716  }

// 将上报的type 和 code value 保存到 event  中,遍历所有然后return退出,数据给到 processEventsLocked 处理。

// 2)处理上报的数据:processEventsLocked

  • processEventsLocked()函数中会遍历所有的事件,分别进行处理。其处理的事件类型分为四种:原始输入事件、设备加载事件、设备卸载事件及FINISHED_DEVICE_SCAN事件。

/frameworks/native/services/inputflinger/reader/InputReader.cpp

150  void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {// 遍历处理所有的事件 rawEvent 
151      for (const RawEvent* rawEvent = rawEvents; count;) {
152          int32_t type = rawEvent->type;
153          size_t batchSize = 1;
154          if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
// 获取到设备的id
155              int32_t deviceId = rawEvent->deviceId;
156              while (batchSize < count) {
157                  if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT ||
158                      rawEvent[batchSize].deviceId != deviceId) {
159                      break;
160                  }
161                  batchSize += 1;
162              }
163  #if DEBUG_RAW_EVENTS
164              ALOGD("BatchSize: %zu Count: %zu", batchSize, count);
165  #endif
// 处理事件 processEventsForDeviceLocked
166              processEventsForDeviceLocked(deviceId, rawEvent, batchSize);================
296  void InputReader::processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents,
297                                                 size_t count) {// 通过hubid 找到对应的 InputDevice
298      auto deviceIt = mDevices.find(eventHubId);
299      if (deviceIt == mDevices.end()) {
300          ALOGW("Discarding event for unknown eventHubId %d.", eventHubId);
301          return;
302      }
303  
304      std::shared_ptr<InputDevice>& device = deviceIt->second;
305      if (device->isIgnored()) {
306          // ALOGD("Discarding event for ignored deviceId %d.", deviceId);
307          return;
308      }
309  // 通过 InputDevice 去处理事件process
310      device->process(rawEvents, count);
311  }

// 通过 InputDevice 去处理事件process。

根据事件获得相应的设备类型,然后将事件交给相应的设备处理,给触摸设备相关的类去处理。

 /frameworks/native/services/inputflinger/reader/InputDevice.cpp

375  void InputDevice::process(const RawEvent* rawEvents, size_t count) {// 遍历所有的事件
381      for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {
382  #if DEBUG_RAW_EVENTS
383          ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%" PRId64,
384                rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value, rawEvent->when);
385  #endif
386  
387          if (mDropUntilNextSync) {
388              if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
389                  mDropUntilNextSync = false;
390  #if DEBUG_RAW_EVENTS
391                  ALOGD("Recovered from input event buffer overrun.");
392  #endif
393              } else {
394  #if DEBUG_RAW_EVENTS
395                  ALOGD("Dropped input event while waiting for next input sync.");
396  #endif
397              }
// 如果事件类型是 SYN_DROPPED,则drop 这个事件
398          } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
399              ALOGI("Detected input event buffer overrun for device %s.", getName().c_str());
400              mDropUntilNextSync = true;
401              reset(rawEvent->when);
402          } else {// 遍历所有的mapper 去处理 rawevent
403              for_each_mapper_in_subdevice(rawEvent->deviceId, [rawEvent](InputMapper& mapper) {
404                  mapper.process(rawEvent);
405              });
406          }
407          --count;
408      }
409  }========
// 遍历所有的mapper 去处理 rawevent
// 前面 addEventubDevice 的时候,将其MultiTouchInputMapper 增加到了mapper 中
195      inline void for_each_mapper_in_subdevice(int32_t eventHubDevice,
196                                               std::function<void(InputMapper&)> f) {
197          auto deviceIt = mDevices.find(eventHubDevice);
198          if (deviceIt != mDevices.end()) {
199              auto& devicePair = deviceIt->second;
200              auto& mappers = devicePair.second;
201              for (auto& mapperPtr : mappers) {
202                  f(*mapperPtr);
203              }
204          }
205      }

调用 MultiTouchInputMapper  的process 方法

/frameworks/native/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp

238  void MultiTouchInputMapper::process(const RawEvent* rawEvent) {// 2-1)TouchInputMapper 先进行处理 process
239      TouchInputMapper::process(rawEvent);
240  // 2-2)MultiTouchMotionAccumulator 处理rawEvent:process
241      mMultiTouchMotionAccumulator.process(rawEvent);
242  }

其实是先处理process,然后再去

// 2-2)MultiTouchMotionAccumulator 处理rawEvent:process

通过 MultiTouchMotionAccumulator.process处理了

85  void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) {
86      if (rawEvent->type == EV_ABS) {
87          bool newSlot = false;
。。。。。。。
105          } else {// mCurrentSlot 为当前的手指
106              Slot* slot = &mSlots[mCurrentSlot];
107              // If mUsingSlotsProtocol is true, it means the raw pointer has axis info of
108              // ABS_MT_TRACKING_ID and ABS_MT_SLOT, so driver should send a valid trackingId while
109              // updating the slot.
110              if (!mUsingSlotsProtocol) {
// 设置为true
111                  slot->mInUse = true;
112              }
113  
114              switch (rawEvent->code) {
// 设置对应的xy 轴值
115                  case ABS_MT_POSITION_X:
116                      slot->mAbsMTPositionX = rawEvent->value;
117                      warnIfNotInUse(*rawEvent, *slot);
118                      break;
119                  case ABS_MT_POSITION_Y:
120                      slot->mAbsMTPositionY = rawEvent->value;
121                      warnIfNotInUse(*rawEvent, *slot);
122                      break;
123                  case ABS_MT_TOUCH_MAJOR:
124                      slot->mAbsMTTouchMajor = rawEvent->value;
125                      break;
126                  case ABS_MT_TOUCH_MINOR:
127                      slot->mAbsMTTouchMinor = rawEvent->value;
128                      slot->mHaveAbsMTTouchMinor = true;
129                      break;
130                  case ABS_MT_WIDTH_MAJOR:
131                      slot->mAbsMTWidthMajor = rawEvent->value;
132                      break;
133                  case ABS_MT_WIDTH_MINOR:
134                      slot->mAbsMTWidthMinor = rawEvent->value;
135                      slot->mHaveAbsMTWidthMinor = true;
136                      break;
137                  case ABS_MT_ORIENTATION:
138                      slot->mAbsMTOrientation = rawEvent->value;
139                      break;// trackid 为手指数,表示第几个手指
140                  case ABS_MT_TRACKING_ID:
141                      if (mUsingSlotsProtocol && rawEvent->value < 0) {
142                          // The slot is no longer in use but it retains its previous contents,
143                          // which may be reused for subsequent touches.
144                          slot->mInUse = false;
145                      } else {
146                          slot->mInUse = true;
// 设置 mAbsMTTrackingId 
147                          slot->mAbsMTTrackingId = rawEvent->value;
148                      }
149                      break;
150                  case ABS_MT_PRESSURE:
151                      slot->mAbsMTPressure = rawEvent->value;
152                      break;
153                  case ABS_MT_DISTANCE:
154                      slot->mAbsMTDistance = rawEvent->value;
155                      break;
156                  case ABS_MT_TOOL_TYPE:
157                      slot->mAbsMTToolType = rawEvent->value;
158                      slot->mHaveAbsMTToolType = true;
159                      break;
160              }
161          }// 如果类型是结束的话,则设置 mCurrentSlot 增加1
162      } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) {
163          // MultiTouch Sync: The driver has returned all data for *one* of the pointers.
164          mCurrentSlot += 1;
165      }
166  }

// 2-1)TouchInputMapper 先进行处理 process

处理是上一次的结果,通过 MultiTouchMotionAccumulator.process处理了
/frameworks/native/services/inputflinger/reader/mapper/TouchInputMapper.cpp

1425  void TouchInputMapper::process(const RawEvent* rawEvent) {
1426      mCursorButtonAccumulator.process(rawEvent);
1427      mCursorScrollAccumulator.process(rawEvent);
1428      mTouchButtonAccumulator.process(rawEvent);
1429  // 如果事件是结束了的话,则执行sync
1430      if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
1431          sync(rawEvent->when, rawEvent->readTime);
1432      }
1433  }=========
1435  void TouchInputMapper::sync(nsecs_t when, nsecs_t readTime) {
1436      // Push a new state.
1437      mRawStatesPending.emplace_back();
1438  
1439      RawState& next = mRawStatesPending.back();
1440      next.clear();
1441      next.when = when;
1442      next.readTime = readTime;
1443  
1444      // Sync button state.
1445      next.buttonState =
1446              mTouchButtonAccumulator.getButtonState() | mCursorButtonAccumulator.getButtonState();
1447  
1448      // Sync scroll
1449      next.rawVScroll = mCursorScrollAccumulator.getRelativeVWheel();
1450      next.rawHScroll = mCursorScrollAccumulator.getRelativeHWheel();
1451      mCursorScrollAccumulator.finishSync();
1452  // 2-1-1)同步触摸事件 syncTouch
1454      syncTouch(when, &next);
1455  
1456      // The last RawState is the actually second to last, since we just added a new state
1457      const RawState& last =
1458              mRawStatesPending.size() == 1 ? mCurrentRawState : mRawStatesPending.rbegin()[1];
1459  
1460      // Assign pointer ids.
1461      if (!mHavePointerIds) {
1462          assignPointerIds(last, next);
1463      }
1464  // 打开开关会打印下列的log,对应的 pointerCount 手指数量
1465  #if DEBUG_RAW_EVENTS
1466      ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, "
1467            "hovering ids 0x%08x -> 0x%08x, canceled ids 0x%08x",
1468            last.rawPointerData.pointerCount, next.rawPointerData.pointerCount,
1469            last.rawPointerData.touchingIdBits.value, next.rawPointerData.touchingIdBits.value,
1470            last.rawPointerData.hoveringIdBits.value, next.rawPointerData.hoveringIdBits.value,
1471            next.rawPointerData.canceledIdBits.value);
1472  #endif
1473  
1474      if (!next.rawPointerData.touchingIdBits.isEmpty() &&
1475          !next.rawPointerData.hoveringIdBits.isEmpty() &&
1476          last.rawPointerData.hoveringIdBits != next.rawPointerData.hoveringIdBits) {
1477          ALOGI("Multi-touch contains some hovering ids 0x%08x",
1478                next.rawPointerData.hoveringIdBits.value);
1479      }
1480  // 2-1-2)处理触摸事件:processRawTouches
1481      processRawTouches(false /*timeout*/);
1482  }

input设备类型有很多种,以上只是触摸设备的inputmapper:MultiTouchInputMapper,还有下列几种

  • 键盘类设备:KeyboardInputMapper
  • 触摸屏设备:MultiTouchInputMapper或SingleTouchInputMapper
  • 鼠标类设备:CursorInputMapper

 // 2-1-1)同步触摸事件 syncTouch,调用的是子类的方法

/frameworks/native/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp

最大的手指的数量为  16 个

178  #define MAX_POINTERS 16
258  void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {
/// 获取的数量值为配置的值
259      size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();
260      size_t outCount = 0;
261      BitSet32 newPointerIdBits;
262      mHavePointerIds = true;
263  // 获取到对应的slot
264      for (size_t inIndex = 0; inIndex < inCount; inIndex++) {
265          const MultiTouchMotionAccumulator::Slot* inSlot =
266                  mMultiTouchMotionAccumulator.getSlot(inIndex);
267          if (!inSlot->isInUse()) {
268              continue;
269          }。。。。
// 如果超过最大18个手指,则break
283          if (outCount >= MAX_POINTERS) {
284  #if DEBUG_POINTERS
285              ALOGD("MultiTouch device %s emitted more than maximum of %d pointers; "
286                    "ignoring the rest.",
287                    getDeviceName().c_str(), MAX_POINTERS);
288  #endif
289              break; // too many fingers!
290          }
291  // 获取到 RawPointerData::Pointer,设置对应的手指的参数
292          RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[outCount];
// 设置xy 轴的值
293          outPointer.x = inSlot->getX();
294          outPointer.y = inSlot->getY();
295          outPointer.pressure = inSlot->getPressure();
296          outPointer.touchMajor = inSlot->getTouchMajor();
297          outPointer.touchMinor = inSlot->getTouchMinor();
298          outPointer.toolMajor = inSlot->getToolMajor();
299          outPointer.toolMinor = inSlot->getToolMinor();
300          outPointer.orientation = inSlot->getOrientation();
301          outPointer.distance = inSlot->getDistance();
302          outPointer.tiltX = 0;
303          outPointer.tiltY = 0;
304  
305          outPointer.toolType = inSlot->getToolType();
306          if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
307              outPointer.toolType = mTouchButtonAccumulator.getToolType();
308              if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
309                  outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
310              }
311          }。。。。
318          // Assign pointer id using tracking id if available.
319          if (mHavePointerIds) {
320              int32_t trackingId = inSlot->getTrackingId();
321              int32_t id = -1;
322              if (trackingId >= 0) {
323                  for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty();) {
324                      uint32_t n = idBits.clearFirstMarkedBit();
325                      if (mPointerTrackingIdMap[n] == trackingId) {
326                          id = n;
327                      }
328                  }
329  
330                  if (id < 0 && !mPointerIdBits.isFull()) {
331                      id = mPointerIdBits.markFirstUnmarkedBit();
332                      mPointerTrackingIdMap[id] = trackingId;
333                  }
334              }
335              if (id < 0) {
336                  mHavePointerIds = false;
337                  outState->rawPointerData.clearIdBits();
338                  newPointerIdBits.clear();
339              } else {
340                  outPointer.id = id;
341                  outState->rawPointerData.idToIndex[id] = outCount;
342                  outState->rawPointerData.markIdBit(id, isHovering);
343                  newPointerIdBits.markBit(id);
344              }
345          }
346          outCount += 1;
347      }
348  
349      outState->rawPointerData.pointerCount = outCount;
350      mPointerIdBits = newPointerIdBits;
351  
352      mMultiTouchMotionAccumulator.finishSync();
353  }

// 2-1-2)处理触摸事件:processRawTouches

//将RawState的数据复制到 mCurrentRawState 

1484  void TouchInputMapper::processRawTouches(bool timeout) {
1485      if (mDeviceMode == DeviceMode::DISABLED) {
1486          // Drop all input if the device is disabled.
1487          cancelTouch(mCurrentRawState.when, mCurrentRawState.readTime);
1488          mCurrentCookedState.clear();
1489          updateTouchSpots();
1490          return;
1491      }// 遍历所有的 RawState
1497      const size_t N = mRawStatesPending.size();
1498      size_t count;
1499      for (count = 0; count < N; count++) {
1500          const RawState& next = mRawStatesPending[count];1504          if (assignExternalStylusId(next, timeout)) {
1505              break;
1506          }
1507  
1508          // All ready to go.
1509          clearStylusDataPendingFlags();
//将RawState的数据复制到 mCurrentRawState 
1510          mCurrentRawState.copyFrom(next);
1511          if (mCurrentRawState.when < mLastRawState.when) {
1512              mCurrentRawState.when = mLastRawState.when;
1513              mCurrentRawState.readTime = mLastRawState.readTime;
1514          }// 处理这个数据并分发:cookAndDispatch
1515          cookAndDispatch(mCurrentRawState.when, mCurrentRawState.readTime);
1516      }

// 处理这个数据并分发:cookAndDispatch

1538  void TouchInputMapper::cookAndDispatch(nsecs_t when, nsecs_t readTime) {
1539      // Always start with a clean state.
1540      mCurrentCookedState.clear();
1541  
1542      // Apply stylus buttons to current raw state.
1543      applyExternalStylusButtonState(when);
1544  
1545      // Handle policy on initial down or hover events.
1546      bool initialDown = mLastRawState.rawPointerData.pointerCount == 0 &&
1547              mCurrentRawState.rawPointerData.pointerCount != 0;
1548  
1549      uint32_t policyFlags = 0;
1550      bool buttonsPressed = mCurrentRawState.buttonState & ~mLastRawState.buttonState;
1551      if (initialDown || buttonsPressed) {
1552          // If this is a touch screen, hide the pointer on an initial down.
1553          if (mDeviceMode == DeviceMode::DIRECT) {
1554              getContext()->fadePointer();
1555          }
1556  
1557          if (mParameters.wake) {
1558              policyFlags |= POLICY_FLAG_WAKE;
1559          }
1560      }
1564      if (consumeRawTouches(when, readTime, policyFlags)) {
1565          mCurrentRawState.rawPointerData.clear();
1566      }// 处理pointer 数据:cookPointerData
1571      cookPointerData();// 设备类型是 DIRECT        
1582      if (mDeviceMode == DeviceMode::POINTER) {
。。。。
1622      } else {
1623          updateTouchSpots();
1624  
1625          if (!mCurrentMotionAborted) {
1626              dispatchButtonRelease(when, readTime, policyFlags);
1627              dispatchHoverExit(when, readTime, policyFlags);
// 分发tounch 事件 dispatchTouches
1628              dispatchTouches(when, readTime, policyFlags);
1629              dispatchHoverEnterAndMove(when, readTime, policyFlags);
1630              dispatchButtonPress(when, readTime, policyFlags);
1631          }

// 处理pointer 数据:cookPointerData

2075  void TouchInputMapper::cookPointerData() {
// 设置按下手指的数量
2076      uint32_t currentPointerCount = mCurrentRawState.rawPointerData.pointerCount;
2077  
2078      mCurrentCookedState.cookedPointerData.clear();
2079      mCurrentCookedState.cookedPointerData.pointerCount = currentPointerCount;
2080      mCurrentCookedState.cookedPointerData.hoveringIdBits =
2081              mCurrentRawState.rawPointerData.hoveringIdBits;
2082      mCurrentCookedState.cookedPointerData.touchingIdBits =
2083              mCurrentRawState.rawPointerData.touchingIdBits;
2084      mCurrentCookedState.cookedPointerData.canceledIdBits =
2085              mCurrentRawState.rawPointerData.canceledIdBits;
。。。。
2095      for (uint32_t i = 0; i < currentPointerCount; i++) {
2096          const RawPointerData::Pointer& in = mCurrentRawState.rawPointerData.pointers[i];
2097  
2098          // Size
2099          float touchMajor, touchMinor, toolMajor, toolMinor, size;
2100          switch (mCalibration.sizeCalibration) {
2101              case Calibration::SizeCalibration::GEOMETRIC:
2102              case Calibration::SizeCalibration::DIAMETER:
2103              case Calibration::SizeCalibration::BOX:
2104              case Calibration::SizeCalibration::AREA:
。。。。
// 设置对应的touchMajor
2112                  } else if (mRawPointerAxes.touchMajor.valid) {
2113                      toolMajor = touchMajor = in.touchMajor;
2114                      toolMinor = touchMinor =
2115                              mRawPointerAxes.touchMinor.valid ? in.touchMinor : in.touchMajor;
2116                      size = mRawPointerAxes.touchMinor.valid ? avg(in.touchMajor, in.touchMinor)
2117                                                              : in.touchMajor;
.。。。。。
// 进行仿射变换 
2250          float xTransformed = in.x, yTransformed = in.y;
2251          mAffineTransform.applyTo(xTransformed, yTransformed);
2252          rotateAndScale(xTransformed, yTransformed);
。。。。。。// 将其数据保存到 mCurrentCookedState.cookedPointerData.pointerCoords
2302          // Write output coords.
2303          PointerCoords& out = mCurrentCookedState.cookedPointerData.pointerCoords[i];
2304          out.clear();
2305          out.setAxisValue(AMOTION_EVENT_AXIS_X, xTransformed);
2306          out.setAxisValue(AMOTION_EVENT_AXIS_Y, yTransformed);
2307          out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure);
2308          out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size);
2309          out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor);
2310          out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touchMinor);
2311          out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation);
2312          out.setAxisValue(AMOTION_EVENT_AXIS_TILT, tilt);
2313          out.setAxisValue(AMOTION_EVENT_AXIS_DISTANCE, distance);

// 分发tounch 事件 dispatchTouches

1904  void TouchInputMapper::dispatchTouches(nsecs_t when, nsecs_t readTime, uint32_t policyFlags) {
1905      BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits;
1906      BitSet32 lastIdBits = mLastCookedState.cookedPointerData.touchingIdBits;
1907      int32_t metaState = getContext()->getGlobalMetaState();
1908      int32_t buttonState = mCurrentCookedState.buttonState;
1909  
1910      if (currentIdBits == lastIdBits) {
。。。。。
1921      } else {// 判断是up,down还是move 事件
1924          BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value);
1925          BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value);
1926          BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value);
1927          BitSet32 dispatchedIdBits(lastIdBits.value);
1928  
1929          // Update last coordinates of pointers that have moved so that we observe the new
1930          // pointer positions at the same time as other pointers that have just gone up.
1931          bool moveNeeded =
1932                  updateMovedPointers(mCurrentCookedState.cookedPointerData.pointerProperties,
1933                                      mCurrentCookedState.cookedPointerData.pointerCoords,
1934                                      mCurrentCookedState.cookedPointerData.idToIndex,
1935                                      mLastCookedState.cookedPointerData.pointerProperties,
1936                                      mLastCookedState.cookedPointerData.pointerCoords,
1937                                      mLastCookedState.cookedPointerData.idToIndex, moveIdBits);
1938          if (buttonState != mLastCookedState.buttonState) {
1939              moveNeeded = true;
1940          }
1941  // 遍历所有的up 事件
1943          while (!upIdBits.isEmpty()) {
// 对应的up 的按钮:upId 
1944              uint32_t upId = upIdBits.clearFirstMarkedBit();
1945              bool isCanceled = mCurrentCookedState.cookedPointerData.canceledIdBits.hasBit(upId);
1946              if (isCanceled) {
1947                  ALOGI("Canceling pointer %d for the palm event was detected.", upId);
1948              }// up 的事件为 AMOTION_EVENT_ACTION_POINTER_UP,事件保存再 cookedPointerData.pointerCoords:走dispatchMotion 方法 
1949              dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0,
1950                             isCanceled ? AMOTION_EVENT_FLAG_CANCELED : 0, metaState, buttonState, 0,
1951                             mLastCookedState.cookedPointerData.pointerProperties,
1952                             mLastCookedState.cookedPointerData.pointerCoords,
1953                             mLastCookedState.cookedPointerData.idToIndex, dispatchedIdBits, upId,
1954                             mOrientedXPrecision, mOrientedYPrecision, mDownTime);
1955              dispatchedIdBits.clearBit(upId);
1956              mCurrentCookedState.cookedPointerData.canceledIdBits.clearBit(upId);
1957          }

// up 的事件为 AMOTION_EVENT_ACTION_POINTER_UP,事件保存再 cookedPointerData.pointerCoords:走dispatchMotion 方法 

3601  void TouchInputMapper::dispatchMotion(nsecs_t when, nsecs_t readTime, uint32_t policyFlags,
3602                                        uint32_t source, int32_t action, int32_t actionButton,
3603                                        int32_t flags, int32_t metaState, int32_t buttonState,
3604                                        int32_t edgeFlags, const PointerProperties* properties,
3605                                        const PointerCoords* coords, const uint32_t* idToIndex,
3606                                        BitSet32 idBits, int32_t changedId, float xPrecision,
3607                                        float yPrecision, nsecs_t downTime) {
3608      PointerCoords pointerCoords[MAX_POINTERS];
3609      PointerProperties pointerProperties[MAX_POINTERS];
3610      uint32_t pointerCount = 0;
3611      while (!idBits.isEmpty()) {
3612          uint32_t id = idBits.clearFirstMarkedBit();
3613          uint32_t index = idToIndex[id];
3614          pointerProperties[pointerCount].copyFrom(properties[index]);// 将数据保存到pointerCoords 中
3615          pointerCoords[pointerCount].copyFrom(coords[index]);
3616  // changedId 为up 的事件
3617          if (changedId >= 0 && id == uint32_t(changedId)) {
3618              action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
3619          }
3620  
3621          pointerCount += 1;
3622      }
3623  
3624      ALOG_ASSERT(pointerCount != 0);
3625  // 如果是单指的话,则将up事件更换为 AMOTION_EVENT_ACTION_UP
3626      if (changedId >= 0 && pointerCount == 1) {
3627          // Replace initial down and final up action.
3628          // We can compare the action without masking off the changed pointer index
3629          // because we know the index is 0.
3630          if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) {
3631              action = AMOTION_EVENT_ACTION_DOWN;
3632          } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) {
3633              if ((flags & AMOTION_EVENT_FLAG_CANCELED) != 0) {
3634                  action = AMOTION_EVENT_ACTION_CANCEL;
3635              } else {
3636                  action = AMOTION_EVENT_ACTION_UP;
3637              }
3638          } else {
3639              // Can't happen.
3640              ALOG_ASSERT(false);
3641          }
3642      }
。。。。。。。
3650      const int32_t displayId = getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE);
3651      const int32_t deviceId = getDeviceId();
3652      std::vector<TouchVideoFrame> frames = getDeviceContext().getVideoFrames();
3653      std::for_each(frames.begin(), frames.end(),
3654                    [this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); });// 创建了 NotifyMotionArgs 对象,pointerCoords 为对应保存的数据
3655      NotifyMotionArgs args(getContext()->getNextId(), when, readTime, deviceId, source, displayId,
3656                            policyFlags, action, actionButton, flags, metaState, buttonState,
3657                            MotionClassification::NONE, edgeFlags, pointerCount, pointerProperties,
3658                            pointerCoords, xPrecision, yPrecision, xCursorPosition, yCursorPosition,
3659                            downTime, std::move(frames));
3660      getListener()->notifyMotion(&args);
3661  }

NotifyMotionArgs  重点的参数:

deviceId:设备id

action:up还是什么其他事件 AMOTION_EVENT_ACTION_UP

actionButton: 为0

flags:0

pointerCount:手指的数量

pointerCoords:保存的数据,表示是 xy 坐标,压力值、major等值

xPrecision, yPrecision:与屏幕方向有关

xCursorPosition, yCursorPosition:都是无效的

notifymotion 通知到 InputDispatcher

/frameworks/native/services/inputflinger/reader/mapper/TouchInputMapper.cpp

3601  void TouchInputMapper::dispatchMotion(nsecs_t when, nsecs_t readTime, uint32_t policyFlags,
3602                                        uint32_t source, int32_t action, int32_t actionButton,
3603                                        int32_t flags, int32_t metaState, int32_t buttonState,
3604                                        int32_t edgeFlags, const PointerProperties* properties,
3605                                        const PointerCoords* coords, const uint32_t* idToIndex,
3606                                        BitSet32 idBits, int32_t changedId, float xPrecision,
3607                                        float yPrecision, nsecs_t downTime) {
3608      PointerCoords pointerCoords[MAX_POINTERS];
3609      PointerProperties pointerProperties[MAX_POINTERS];
3610      uint32_t pointerCount = 0;
3611      while (!idBits.isEmpty()) {
3612          uint32_t id = idBits.clearFirstMarkedBit();
3613          uint32_t index = idToIndex[id];
3614          pointerProperties[pointerCount].copyFrom(properties[index]);
3615          pointerCoords[pointerCount].copyFrom(coords[index]);
3616  
3617          if (changedId >= 0 && id == uint32_t(changedId)) {
3618              action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
3619          }
3620  
3621          pointerCount += 1;
3622      }
3623  
3624      ALOG_ASSERT(pointerCount != 0);
3625  // 如果是单指的话,则会将AMOTION_EVENT_ACTION_POINTER_UP设置为 AMOTION_EVENT_ACTION_UP
3626      if (changedId >= 0 && pointerCount == 1) {
3627          // Replace initial down and final up action.
3628          // We can compare the action without masking off the changed pointer index
3629          // because we know the index is 0.
3630          if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) {
3631              action = AMOTION_EVENT_ACTION_DOWN;
3632          } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) {
3633              if ((flags & AMOTION_EVENT_FLAG_CANCELED) != 0) {
3634                  action = AMOTION_EVENT_ACTION_CANCEL;
3635              } else {
3636                  action = AMOTION_EVENT_ACTION_UP;
3637              }
3638          } else {
3639              // Can't happen.
3640              ALOG_ASSERT(false);
3641          }
3642      }
3643      float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
3644      float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
3645      if (mDeviceMode == DeviceMode::POINTER) {
3646          auto [x, y] = getMouseCursorPosition();
3647          xCursorPosition = x;
3648          yCursorPosition = y;
3649      }
3650      const int32_t displayId = getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE);
3651      const int32_t deviceId = getDeviceId();
3652      std::vector<TouchVideoFrame> frames = getDeviceContext().getVideoFrames();
3653      std::for_each(frames.begin(), frames.end(),
3654                    [this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); });// 将所有的参数封装为 NotifyMotionArgs 
3655      NotifyMotionArgs args(getContext()->getNextId(), when, readTime, deviceId, source, displayId,
3656                            policyFlags, action, actionButton, flags, metaState, buttonState,
3657                            MotionClassification::NONE, edgeFlags, pointerCount, pointerProperties,
3658                            pointerCoords, xPrecision, yPrecision, xCursorPosition, yCursorPosition,
3659                            downTime, std::move(frames));// getListener 去通知到观察者
3660      getListener()->notifyMotion(&args);
3661  }

getListener 的实现为:

/frameworks/native/services/inputflinger/reader/mapper/InputMapper.h

TouchInputMapper 类继承了 InputMapper

// 这里获取到context,通过 mDeviceContext.getContext()
49      inline InputReaderContext* getContext() { return mDeviceContext.getContext(); }// 通过ceontext 获取到 Listener
51      inline InputListenerInterface* getListener() { return getContext()->getListener(); }

mDeviceContext 是在初始化  传入的

 /frameworks/native/services/inputflinger/reader/InputDevice.cpp

143  void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers) {
144      if (mDevices.find(eventHubId) != mDevices.end()) {
145          return;
146      }
147      std::unique_ptr<InputDeviceContext> contextPtr(new InputDeviceContext(*this, eventHubId));。。。。
204      // Touchscreens and touchpad devices.
205      if (classes.test(InputDeviceClass::TOUCH_MT)) {// contextPtr 是 InputDeviceContext 对象
206          mappers.push_back(std::make_unique<MultiTouchInputMapper>(*contextPtr));

所以 mDeviceContext 是 InputDeviceContext,再调用其 getContext 方法

/frameworks/native/services/inputflinger/reader/include/InputDevice.h

239  class InputDeviceContext {
240  public:
241      InputDeviceContext(InputDevice& device, int32_t eventHubId);
242      ~InputDeviceContext();
243  
244      inline InputReaderContext* getContext() { return mContext; }========
600  InputDeviceContext::InputDeviceContext(InputDevice& device, int32_t eventHubId)
601        : mDevice(device),// 为构造函数中传入的,即通过 InputDevice.getContext 获取
602          mContext(device.getContext()),
603          mEventHub(device.getContext()->getEventHub()),
604          mId(eventHubId),

// 为构造函数中传入的,即通过 InputDevice.getContext 获取

也是再 InputDevice 中传入的

44  class InputDevice {
45  public:
46      InputDevice(InputReaderContext* context, int32_t id, int32_t generation,
47                  const InputDeviceIdentifier& identifier);
48      ~InputDevice();
49  
50      inline InputReaderContext* getContext() { return mContext; }

mContext 为内部的类为 ContextImpl

/frameworks/native/services/inputflinger/reader/include/InputReader.h

124      class ContextImpl : public InputReaderContext {
125          InputReader* mReader;
126          IdGenerator mIdGenerator;
127  
128      public:
129          explicit ContextImpl(InputReader* reader);
130          // lock is already held by the input loop
131          void updateGlobalMetaState() NO_THREAD_SAFETY_ANALYSIS override;
132          int32_t getGlobalMetaState() NO_THREAD_SAFETY_ANALYSIS override;
133          void disableVirtualKeysUntil(nsecs_t time) REQUIRES(mReader->mLock) override;
134          bool shouldDropVirtualKey(nsecs_t now, int32_t keyCode, int32_t scanCode)
135                  REQUIRES(mReader->mLock) override;
136          void fadePointer() REQUIRES(mReader->mLock) override;
137          std::shared_ptr<PointerControllerInterface> getPointerController(int32_t deviceId)
138                  REQUIRES(mReader->mLock) override;
139          void requestTimeoutAtTime(nsecs_t when) REQUIRES(mReader->mLock) override;
140          int32_t bumpGeneration() NO_THREAD_SAFETY_ANALYSIS override;
141          void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices)
142                  REQUIRES(mReader->mLock) override;
143          void dispatchExternalStylusState(const StylusState& outState)
144                  REQUIRES(mReader->mLock) override;
145          InputReaderPolicyInterface* getPolicy() REQUIRES(mReader->mLock) override;
146          InputListenerInterface* getListener() REQUIRES(mReader->mLock) override;
147          EventHubInterface* getEventHub() REQUIRES(mReader->mLock) override;
148          int32_t getNextId() NO_THREAD_SAFETY_ANALYSIS override;
149          void updateLedMetaState(int32_t metaState) REQUIRES(mReader->mLock) override;
150          int32_t getLedMetaState() REQUIRES(mReader->mLock) REQUIRES(mLock) override;
151      } mContext;

综上:

InputReaderContext* getContext() 返回的对象是  InputReader 的 ContextImpl 

接着调用其 listener 的方法:

/frameworks/native/services/inputflinger/reader/InputReader.cpp

948  InputListenerInterface* InputReader::ContextImpl::getListener() {
// 获取到的是 对象
949      return mReader->mQueuedListener.get();
950  }======
43  InputReader::InputReader(std::shared_ptr<EventHubInterface> eventHub,
44                           const sp<InputReaderPolicyInterface>& policy,
// listener 传入的参数是 InputDispatcher
45                           const sp<InputListenerInterface>& listener)
46        : mContext(this),
47          mEventHub(eventHub),
48          mPolicy(policy),
49          mGlobalMetaState(0),
50          mLedMetaState(AMETA_NUM_LOCK_ON),
51          mGeneration(1),
52          mNextInputDeviceId(END_RESERVED_ID),
53          mDisableVirtualKeysTimeout(LLONG_MIN),
54          mNextTimeout(LLONG_MAX),
55          mConfigurationChangesToRefresh(0) {
56      mQueuedListener = new QueuedInputListener(listener);

所以是调用到 QueuedInputListener 的方法 notifyMotion

/frameworks/native/services/inputflinger/InputListener.cpp

315  QueuedInputListener::QueuedInputListener(const sp<InputListenerInterface>& innerListener) :
316          mInnerListener(innerListener) {
317  }337  void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
338      traceEvent(__func__, args->id);// 创建 NotifyMotionArgs 对象包装 args,将其保存到参数队列中
339      mArgsQueue.push_back(new NotifyMotionArgs(*args));
340  }========
// 最后需要调用flush,去统一派发
367  void QueuedInputListener::flush() {
368      size_t count = mArgsQueue.size();
369      for (size_t i = 0; i < count; i++) {
370          NotifyArgs* args = mArgsQueue[i];
371          args->notify(mInnerListener);
372          delete args;
373      }
374      mArgsQueue.clear();
375  }=======
// 然后调用观察者 InputDispatcher 去通知触摸事件 notifyMotion
191  void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {
192      listener->notifyMotion(this);
193  }

// 3)观察者队列去flush,处理全部的事件:flush

调用观察者 InputDispatcher 去通知触摸事件 notifyMotion

/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp

3817  void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
3818  #if DEBUG_INBOUND_EVENT_DETAILS// 会打印对应的log
3819      ALOGD("notifyMotion - id=%" PRIx32 " eventTime=%" PRId64 ", deviceId=%d, source=0x%x, "
3820            "displayId=%" PRId32 ", policyFlags=0x%x, "
3821            "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, "
3822            "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, xCursorPosition=%f, "
3823            "yCursorPosition=%f, downTime=%" PRId64,
3824            args->id, args->eventTime, args->deviceId, args->source, args->displayId,
3825            args->policyFlags, args->action, args->actionButton, args->flags, args->metaState,
3826            args->buttonState, args->edgeFlags, args->xPrecision, args->yPrecision,
3827            args->xCursorPosition, args->yCursorPosition, args->downTime);
3828      for (uint32_t i = 0; i < args->pointerCount; i++) {
3829          ALOGD("  Pointer %d: id=%d, toolType=%d, "
3830                "x=%f, y=%f, pressure=%f, size=%f, "
3831                "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, "
3832                "orientation=%f",
3833                i, args->pointerProperties[i].id, args->pointerProperties[i].toolType,
3834                args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
3835                args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
3836                args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
3837                args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
3838                args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
3839                args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
3840                args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
3841                args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
3842                args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
3843      }。。。。。
3885          // Just enqueue a new motion event.// 将args 封装为 MotionEntry 对象
3886          std::unique_ptr<MotionEntry> newEntry =
3887                  std::make_unique<MotionEntry>(args->id, args->eventTime, args->deviceId,
3888                                                args->source, args->displayId, policyFlags,
3889                                                args->action, args->actionButton, args->flags,
3890                                                args->metaState, args->buttonState,
3891                                                args->classification, args->edgeFlags,
3892                                                args->xPrecision, args->yPrecision,
3893                                                args->xCursorPosition, args->yCursorPosition,
3894                                                args->downTime, args->pointerCount,
3895                                                args->pointerProperties, args->pointerCoords, 0, 0);
3896  // 将其假如到处理的队列,然后唤醒 inputdispatcher 线程
3897          needWake = enqueueInboundEventLocked(std::move(newEntry));
3898          mLock.unlock();
3899      } // release lock
3900  
3901      if (needWake) {
3902          mLooper->wake();
3903      }
3904  }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/2616.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

VMware 虚拟机使用教程及 Kali Linux 安装指南

VMware 虚拟机使用教程及 Kali Linux 安装指南 在现代计算机科学与网络安全领域&#xff0c;虚拟化技术的应用越来越广泛。VMware 是一款功能强大的虚拟化软件&#xff0c;可以帮助用户在同一台物理机上运行多个操作系统。本文将详细介绍如何使用 VMware 虚拟机&#xff0c;并…

工业通信网关的各项功能解析-天拓四方

在工业自动化和智能制造的浪潮中&#xff0c;工业通信网关作为连接工业现场与互联网的重要桥梁&#xff0c;发挥着至关重要的作用。它不仅实现了不同网络协议之间的转换&#xff0c;还在数据采集、设备控制、网络管理等方面展现出强大的功能。 一、协议转换功能 工业通信网关…

用Python打造媒体管理播放器:从零到全功能GUI应用

背景 在日常生活中&#xff0c;我们经常需要管理和播放大量媒体文件。市面上的音频播放器可能功能单一&#xff0c;或者界面复杂。作为一名程序员&#xff0c;我决定使用Python自己打造一个简单yet强大的媒体管理播放器。 C:\pythoncode\new\playsong.py 全部代码 import os…

ubuntu 20.04 安装使用 nvidia gdrcopy

1&#xff0c;预备环境 首先安装 nvidia display driver &#xff0c;cuda toolkit 其次安装依赖工具 sudo apt install build-essential devscripts debhelper fakeroot pkg-config dkms 2&#xff0c;下载源码 git clone --recursive https://github.com/NVIDIA/gdrcopy.…

MongoDB简介

一.MongoDB相关概念 1.1.简介 MongoDB是一个开源&#xff0c;高性能&#xff0c;无模式的文档性数据库&#xff0c;当初的设计就是用于简化开发和方便扩展&#xff0c;是NoSQL数据库产品中的一种。是最像关系型数据库&#xff08;MySQL&#xff09;的非关系数据库。 它支持的…

Socket篇(学习前言)

目录 一、计算机网络 二、网络编程 三、网络编程三要素 1. IP地址 1.1. 简介 1.2. IP地址分为两大类 IPv4 IPv6 1.3. IP地址形式 1.4. DOS常用命令 1.5. 特殊IP地址 2. 端口 2.1. 简介 2.2. 端口号 2.3. 端口类型 周知端口 注册端口 动态端口 3. 协议 3.1. …

【专题】基于服务的体系结构

对于面向服务的体系结构&#xff08;Service-Oriented Architecture&#xff0c;SOA&#xff09;的几种定义&#xff1a; W3C&#xff1a;SOA是一种应用程序体系结构&#xff0c;在这种体系结构中&#xff0c;所有功能都定义为独立的服务&#xff0c;这些服务带有定义明确的可…

AMD显卡低负载看视频掉驱动(chrome edge浏览器) 高负载玩游戏却稳定 解决方法——关闭MPO

问题 折磨的开始是天下苦黄狗久矣&#xff0c;为了不再被讨乞丐的显存恶心&#xff0c;一怒之下购入了AMD显卡&#xff08;20GB显存确实爽 头一天就跑了3dmark验机&#xff0c;完美通过&#xff0c;玩游戏也没毛病 但是呢这厮是一点不省心&#xff0c;玩游戏没问题&#xff0c…

小容器拉动大市场 全面云原生化刻不容缓

毋庸置疑&#xff0c;容器技术的发展推动了云原生计算革命。当前&#xff0c;在云原生已经成为企业用云新常态的情况下&#xff0c;作为一项核心能力&#xff0c;容器管理与服务也成了检验云服务商的试金石。Omdia最新发布的《Omdia Universe: Cloud Container Management &…

一招帮你搞懂数据结构的插入、删除

目录 一、尾部插入&#xff08;添加&#xff09; 1.初始化 2.一个打印数组的函数 3.尾插 4.完整版 二、任意位置插入 1.流程图 2.任意插 3.完整版 三、指定数据删除 1.流程图 2. 删除&#xff08;首位查找到的元素&#xff09; 四、删除所有 思想 代码 五、有序…

二叉树相关算法

满二叉树&#xff1a;每层都是满的 完全二叉树&#xff1a;特殊的满二叉树&#xff0c;可以有一个子节点&#xff0c;但最后一层必须是从左到右排列&#xff0c;中间不能有空隙&#xff0c;强调除了最后一层外&#xff0c;其他层都是满的 一、dfs深度搜索 例题&#xff1a;求…

Sigrity Power SI VR noise Metrics check模式如何进行电源噪声耦合分析操作指导

SSigrity Power SI VR noise Metrics check模式如何进行电源噪声耦合分析操作指导 Sigrity Power SI的VR noise Metrics check模式本质上是用来评估和观测器件的电源网络的耦合对于信号的影响,输出S参数以及列出具体的贡献值。 以下图为例

OpenGL入门004——使用EBO绘制矩形

本节将利用EBO来绘制矩形 文章目录 一些概念EBO 实战简介utilswindowFactory.hRectangleModel.hRectangleModel.cpp main.cppCMakeLists.txt最终效果 一些概念 EBO 概述&#xff1a; Element Buffer Object 用于存储顶点的索引数据&#xff0c;以便在绘制图形时可以重用顶点数…

Qt 视口和窗口

Qt 视口和窗口 1、视口和窗口的定义与原理 绘图设备的物理坐标是基本的坐标系&#xff0c;通过 QPainter 的平移、旋转等变换可以得到更容易操作的逻辑坐标。 为了实现更方便的坐标&#xff0c;QPainter 还提供了视口 (Viewport)和窗口 (Window)坐标系&#xff0c;通过Q…

hunyuan-DiT模型部署指南

一、介绍 Hunyuan-DiT是由腾讯混元推出的扩散模型&#xff0c;支持中文和英文双语输入&#xff0c;其他开源模型相比&#xff0c;Hunyuan-DiT 在中文到图像生成方面树立了新的水平。 二、部署流程 环境要求&#xff1a; 所需的最小 GPU 内存为 11GB&#xff0c; 建议使用具…

Pytorch学习--神经网络--搭建小实战(手撕CIFAR 10 model structure)和 Sequential 的使用

一、Sequential 的使用方法 在手撕代码中进一步体现 torch.nn.Sequential 二、手撕 CIFAR 10 model structure 手撕代码&#xff1a; import torch from torch import nn from torch.nn import Conv2d, MaxPool2d, Flatten, Linear from torch.utils.tensorboard import Su…

硬件测试工程师之EMC项目-电磁干扰-谐波测试标准解析思维导图

1&#xff1a;链接上一篇文章 ​​​​​​​相关链接&#xff1a;https://blog.csdn.net/weixin_49492286/article/details/135210741 2&#xff1a;重新总结思维导图并进行深入解析EMC-谐波测试项目 本人重新再次总结这个EMC谐波的标准解析思维导图&#xff0c;并且附上相…

ArcGIS 地理信息系统 任意文件读取漏洞复现

0x01 产品简介 ArcGIS是由美国Esri公司研发的地理信息系统(GIS)软件,它整合了数据库、软件工程、人工智能、网络技术、云计算等主流的IT技术,旨在为用户提供一套完整的、开放的企业级GIS解决方案,它包含了一套带有用户界面组件的Windows桌面应用。可以实现从简单到复杂的…

安全合规:沃尔玛自养号测评技术搭建要点

沃尔玛自养号测评技术的搭建是一个复杂且需综合考量多方面因素的过程&#xff0c;以下是对其技术搭建的详细解析&#xff1a; 一、硬件与网络环境搭建 硬件参数伪装&#xff1a; 利用国外服务器在云端搭建安全终端&#xff0c;全面阻断沃尔玛平台对设备底层硬件参数的检测&a…

Ps:天空替换

Ps菜单&#xff1a;编辑/天空替换 Edit/Sky Replacement Ps菜单&#xff1a;选择/天空 Select/Sky 天空替换 Sky Replacement命令能够自动分析前景与天空&#xff0c;利用 Adobe Sensei 技术也大大减轻了制作蒙版的负担&#xff0c;可以直观、智能、快速地实现天空替换。 到目…