2025-02-17

  “消息”一詞最早出現於《易經》:“日中則昃,月盈則食,天地盈虛,與時消息。“意思是說,太陽到瞭中午就要逐漸西斜,月亮圓瞭就逐漸虧缺,天地間的事物,或豐盈或虛弱,都隨著時間的推移而變化,有時消減,有時滋長。由此可見,中國古代就把客觀世界的變化,把它們的發生、發展和結局,把它們的枯榮、聚散、沉浮、升降、興衰、動靜、得失等等變化中的事實稱之為”消息“。———-摘自度娘。
         因此,在此處我們所要學習的消息也是有這樣的一種產生,發展和結束的過程。而產生就是指當硬件接受到人的觸摸的情況之下,通過中斷將消息上報,從而我們能夠通過上層的線程得到這個消息,而具體是如何處理的都將通過線程內部或者線程間的調用完成,最後通過分發線程將消息分發出去供消費者去消耗。
        在深入學習之前我們先要思考如下幾個問題:
        1 消息是如何讓系統得到的?
        2 消息是如何被系統讀取和處理的?
        3 應用程序開發者是如何利用消息的?
1     首先kernel中我們會使用下面的函數來上報事件。(linux/input.h)
設置:
    1227     unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
    1228     unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
    1229     unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
    1230     unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];
上報:
    1474 static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
    1475 {
    1476     input_event(dev, EV_KEY, code, !!value);
    1477 }
    1478
    1479 static inline void input_report_rel(struct input_dev *dev, unsigned int code, int value)
    1480 {
    1481     input_event(dev, EV_REL, code, value);
    1482 }
    1483
    1484 static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)
    1485 {
    1486     input_event(dev, EV_ABS, code, value);
    1487 }
其中調用的input_event函數如下:
     347 void input_event(struct input_dev *dev,
     348          unsigned int type, unsigned int code, int value)
     349 {
     350     unsigned long flags;
     351
     352     if (is_event_supported(type, dev->evbit, EV_MAX)) {
     353
     354         spin_lock_irqsave(&dev->event_lock, flags);
     355         add_input_randomness(type, code, value);
     356         input_handle_event(dev, type, code, value);
     357         spin_unlock_irqrestore(&dev->event_lock, flags);
     358     }
     359 }
     360 EXPORT_SYMBOL(input_event);
此處的input_handle_event()會調用到input_pass_event()函數
      77 static void input_pass_event(struct input_dev *dev,
      78                  unsigned int type, unsigned int code, int value)
      79 {
      80     struct input_handler *handler;
      81     struct input_handle *handle;
      82
      83     rcu_read_lock();
      84
      85     handle = rcu_dereference(dev->grab);
      86     if (handle)
      87         handle->handler->event(handle, type, code, value);
      88     else {
      89         bool filtered = false;
      90
      91         list_for_each_entry_rcu(handle, &dev->h_list, d_node) {
      92             if (!handle->open)
      93                 continue;
      94
      95             handler = handle->handler;
      96             if (!handler->filter) {
      97                 if (filtered)
      98                     break;
      99
     100                 handler->event(handle, type, code, value);
     101
     102             } else if (handler->filter(handle, type, code, value))
     103                 filtered = true;
     104         }
     105     }
     106
     107     rcu_read_unlock();
     108 }
上面的handler就是函數evdev_handler()。定義在evdev.c文件中。在evdev_init()中通過調用input_register_handler(&ev_handler)的註冊完成瞭input_dev和evdev_handler的關聯。並且調用瞭evdev_event()函數完成瞭對evdev_pass_event()將數據存放在buffer中。代碼如下:
 59 static void evdev_pass_event(struct evdev_client *client,
  60                  struct input_event *event)
  61 {
  62     /* Interrupts are disabled, just acquire the lock. */
  63     spin_lock(&client->buffer_lock);
  64
  65     wake_lock_timeout(&client->wake_lock, 5 * HZ);
  66     client->buffer[client->head++] = *event;
  67     client->head &= client->bufsize – 1;
  68
  69     if (unlikely(client->head == client->tail)) {
  70         /*
  71          * This effectively "drops" all unconsumed events, leaving
  72          * EV_SYN/SYN_DROPPED plus the newest event in the queue.
  73          */
  74         client->tail = (client->head – 2) & (client->bufsize – 1);
  75
  76         client->buffer[client->tail].time = event->time;
  77         client->buffer[client->tail].type = EV_SYN;
  78         client->buffer[client->tail].code = SYN_DROPPED;
  79         client->buffer[client->tail].value = 0;
  80
  81         client->packet_head = client->tail;
  82     }
  83
  84     if (event->type == EV_SYN && event->code == SYN_REPORT) {
  85         client->packet_head = client->head;
  86         kill_fasync(&client->fasync, SIGIO, POLL_IN);
  87     }
  88
  89     spin_unlock(&client->buffer_lock);
  90 }
      在底層設備的註冊和分配工作也就大體上完成瞭。此時我們需要考慮如何讀取數據的問題瞭。在kernel部分的讀取先暫時不做介紹。
      這樣我們就能夠完成對觸摸屏的設置。這些我們在前面的文章中描述過。
2  在frameworks層數據的讀取過程
        首先我們需要瞭解最重要的一個環節就是EventHub。它是系統中所有事件的中央處理站。它管理所有系統中可以識別的輸入設備的輸入事件。另外,當設備增加和刪除時,EventHub將產生相應的輸入事件給系統。以下是在EventHub.cpp文件中的getEvents函數中打開設備的代碼。主要調用瞭scanDevicesLocked().
     
0569
        if (mNeedToScanDevices) {
0570
            mNeedToScanDevices = false;
0571
            scanDevicesLocked();
0572
            mNeedToSendFinishedDeviceScan = true;
0573
        }
而scanDevicesLocked()函數的代碼如下:
static const char *DEVICE_PATH = "/dev/input";
0801
void EventHub::scanDevicesLocked() {
0802
    status_t res = scanDirLocked(DEVICE_PATH);
0803
    if(res < 0) {
0804
        LOGE("scan dir failed for %s\n", DEVICE_PATH);
0805
    }
0806
} 接著往下調用:
1270
status_t EventHub::scanDirLocked(const char *dirname)
1271
{
1272
    char devname[PATH_MAX];
1273
    char *filename;
1274
    DIR *dir;
1275
    struct dirent *de;
1276
    dir = opendir(dirname);
1277
    if(dir == NULL)
1278
        return -1;
1279
    strcpy(devname, dirname);
1280
    filename = devname + strlen(devname);
1281
    *filename++ = '/';
1282
    while((de = readdir(dir))) {
1283
        if(de->d_name[0] == '.' &&
1284
           (de->d_name[1] == '\0' ||
1285
            (de->d_name[1] == '.' && de->d_name[2] == '\0')))
1286
            continue;
1287
        strcpy(filename, de->d_name);
1288
        openDeviceLocked(devname);
1289
    }
1290
    closedir(dir);
1291
    return 0;
1292
}

摘自 曹太強的專欄

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *