【安卓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.mzph.cn/diannao/59796.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows Server 怎么关闭IE增强安全配置(关闭IE弹窗)

首先第一步打开IE浏览器&#xff0c;根据下图所示&#xff0c;访问网页时会弹出警告窗口。 打开【控制面板】图标。查看方式改为小图标&#xff0c;打开【管理工具】 第五步进入【管理工具】页面后&#xff0c;找到并双击【服务器管理器】选项。 第六步在弹出的窗口中&#…

鸿萌数据迁移服务: 企业服务器整机在线热迁移, 实现不停机业务转移

天津鸿萌科贸发展有限公司从事数据安全服务二十余年&#xff0c;致力于为各领域客户提供专业的数据存储、数据恢复、数据备份、数据迁移等解决方案与服务&#xff0c;并针对企业面临的数据安全风险&#xff0c;提供专业的相关数据安全培训。 鸿萌数据迁移业务为众多企业顺利高效…

ChatGPT 新体验:AI 搜索功能与订阅支付指南

就在凌晨&#xff0c;在 ChatGPT 迎来两周岁生日之际&#xff0c;OpenAI 重磅发布了 ChatGPT 的全新人工智能搜索体验。 期待已久的时刻终于到来&#xff0c; ChatGPT 正式转型成为一款革命性的 AI 搜索引擎&#xff01; 先来看看 ChatGPT 搜索&#xff1a;这次不是简单的加个…

[JAVAEE] 面试题(四) - 多线程下使用ArrayList涉及到的线程安全问题及解决

目录 一. 多线程下使用ArrayList 1.1. 自行判断加锁 1.2 使用Collections.synchronizedList()套壳加锁 1.3 CopyOnWriteArrayList类 二. 总结 一. 多线程下使用ArrayList 多线程下使用ArrayList会涉及到线程安全问题, 例如: public static void main(String[] args) thro…

canal1.1.7使用canal-adapter进行mysql同步数据

重要的事情说前面&#xff0c;canal1.1.8需要jdk11以上&#xff0c;大家自行选择&#xff0c;我这由于项目原因只能使用1.1.7兼容版的 文章参考地址&#xff1a; canal 使用详解_canal使用-CSDN博客 使用canal.deployer-1.1.7和canal.adapter-1.1.7实现mysql数据同步_mysql更…

DevExpress中文教程 - 如何使用AI模型检查HTML编辑中的语法?

DevExpress .NET MAUI多平台应用UI组件库提供了用于Android和iOS移动开发的高性能UI组件&#xff0c;该组件库包括数据网格、图表、调度程序、数据编辑器、CollectionView和选项卡组件等。 目前许多开发人员正在寻找多种方法将AI添加到解决方案中&#xff08;这通常比想象的要…

【推荐】iptables学习宝典

链接&#xff1a; IPtables-朱双印博客 学习iptables的抗鼎之作&#xff0c;推荐。

二维数组和数组指针数组的关系

在深入理解指针end中&#xff0c;我在最后写了一长段代码 #include<stdio.h> void test1(int arr[][5], int x, int y) //void test1(int(*p)[5], int x, int y) {for (int i 0; i < x; i){for (int j 0; j < y; j){//printf("%d ", *(*(p i) j));p…

vue+websocket实现即时聊天平台

目录 1 什么是websocket 2 实现步骤 2.1 导入依赖 2.2 编写代码 1 什么是websocket WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。它主要用于在客户端和服务器之间建立持久的连接&#xff0c;允许实时数据交换。WebSocket 的设计目的是为了提高 Web 应用程序的…

【D3.js in Action 3 精译_038】4.2 D3 折线图的绘制方法及曲线插值处理

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一部分 D3.js 基础知识 第一章 D3.js 简介&#xff08;已完结&#xff09; 1.1 何为 D3.js&#xff1f;1.2 D3 生态系统——入门须知1.3 数据可视化最佳实践&#xff08;上&#xff09;1.3 数据可…

Git 的分支管理

一、分支介绍 1、分支是什么 Git作为一个分布式版本控制系统&#xff0c;提供了强大而灵活的分支管理功能&#xff0c;使得开发团队能够高效地协作开发、管理不同的功能和版本。 2、为什么有分支 一般情况下主分支&#xff08;master/main&#xff09;应始终保持可部署的状…

Linux环境基础和基础开发工具使用

文章目录 一、yum软件管理器1、包管理器2、yum3、apt4、安装源 二、编辑器vim1、各种模式2、打开时直接让光标定位到指定号3、&#xff01;加命令字符 三、命令模式1、i 进入插入模式2、**Shift :** 进入底行模式3、光标定位4、ZZ&#xff08;大写&#xff09;保存并退出vim5、…

【java】哈希<两数之和> 理解哈希

两数之和 题目描述&#xff1a; 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案&#xff0c;并且你不能使用两次相同的元素。 你…

【Linux】信号三部曲——产生、保存、处理

信号 1. 信号的概念2. 进程如何看待信号3. 信号的产生3.1. kill命令3.2. 终端按键3.2.1. 核心转储core dump3.2.2. OS如何知道键盘在输入数据 3.3. 系统调用3.3.1. kill3.3.2. raise3.3.3. abort 3.4. 软件条件3.4.1. SIGPIPE信号3.4.2. SIGALRM信号 3.5. 硬件异常3.5.1. 除零异…

Vue 计算属性和监听器

文章目录 一、计算属性1. 计算属性定义2. computed 比较 methods3. 计算属性完整写法 二、监听器1. 普通监听2. 添加额外配置项 一、计算属性 1. 计算属性定义 概念&#xff1a;基于现有的数据&#xff0c;计算出来的新属性&#xff0c;依赖的数据变化&#xff0c;自动重新计…

【计网】实现reactor反应堆模型 --- 框架搭建

没有一颗星&#xff0c; 会因为追求梦想而受伤&#xff0c; 当你真心渴望某样东西时&#xff0c; 整个宇宙都会来帮忙。 --- 保罗・戈埃罗 《牧羊少年奇幻之旅》--- 实现Reactor反应堆模型 1 前言2 框架搭建3 准备工作4 Reactor类的设计5 Connection连接接口6 回调方法 1 …

外包干了2年,快要废了。。。

先说一下自己的情况&#xff0c;普通本科毕业&#xff0c;在外包干了2年多的功能测试&#xff0c;这几年因为大环境不好&#xff0c;我整个人心惊胆战的&#xff0c;怕自己卷铺盖走人了&#xff0c;我感觉自己不能够在这样蹉跎下去了&#xff0c;长时间呆在一个舒适的环境真的会…

linux驱动-i2c子系统框架学习(2)

linux驱动-i2c子系统框架学习(1) 在这篇博客里面已经交代了i2c设备驱动层&#xff0c;主要的功能就是编写具体i2c的外设驱动&#xff0c;和创建设备接点给上层使用 &#xff0c;按之前学习的字符设备&#xff0c;有了设备节点&#xff0c;就可以对硬件操作了&#xff0c;在i2c…

Webserver(4.6)poll和epoll

目录 pollclient.cpoll.c epollepoll.cclient.c epoll的两种工作模式水平触发边沿触发 poll poll是对select的一个改进 select的缺点在于每次都需要将fd集合从用户态拷贝到内核态&#xff0c;开销很大。每次调用select都需要在内核遍历传递进来的所有fd&#xff0c;这个开销也…

Stable Diffusion的解读(一)

Stable Diffusion的解读&#xff08;一&#xff09; 文章目录 Stable Diffusion的解读&#xff08;一&#xff09;摘要Abstract一、机器学习部分1. Stable Diffusion的早期工作1.1 从编码器谈起1.2 第一条路线&#xff1a;VAE和DDPM1.3 第二条路线&#xff1a;VQVAE1.4 路线的交…