Android sensor 系統框架 (一)

来源:http://www.cnblogs.com/hackfun/archive/2017/08/09/7327320.html
-Advertisement-
Play Games

這幾天深入學習了Android sensor框架,以此博客記錄和分享分析過程,其中難免會有錯誤的地方,歡迎指出! 這裡主要分析KERNEL->HAL->JNI這3層的流程。主要從以下幾方面開始著手:(A) 驅動層向上提供了那些文件節點給系統層讀寫?(B) 系統層通過什麼方式訪問驅動層?(C) 如何統 ...



這幾天深入學習了Android sensor框架,以此博客記錄和分享分析過程,其中難免會有錯誤的地方,歡迎指出!

這裡主要分析KERNEL->HAL->JNI這3層的流程。主要從以下幾方面開始著手:
(A) 驅動層向上提供了那些文件節點給系統層讀寫?
(B) 系統層通過什麼方式訪問驅動層?
(C) 如何統一各種sensors的介面,生成.so庫?
(D) 如何載入訪問.so庫 (未寫,待續)
(E) 實現sensor service (未寫,待續)
(F) JNI介面 (未寫,待續)


(A) 驅動層向上提供了那些文件節點給系統層讀寫?
    關於linux基本驅動框架,不在本文範圍,這裡不再分析。學習過Linux驅動的都知道應用層要訪問內核驅動,都是通過open、
read、write等系統函數操作驅動註冊的文件節點進行的。這裡以n2dm g-sensor的驅動為例,找出這些文件節點。文件路徑:

    ./kernel/drivers/input/misc/n2dm.c

 1     static int n2dm_acc_probe(struct i2c_client *client,const struct i2c_device_id *id)
 2     {
 3         ......
 4         acc->input_dev->name = "accelerometer";
 5         err = input_register_device(acc->input_dev);   /* 生成 /dev/input/event2 */
 6         ......
 7         err = misc_register(&n2dm_acc_misc_device);    /* 生成 /sys/class/n2dm_acc */
 8         ......
 9         gsensor_class = class_create(THIS_MODULE,"xr-gsensor");
10         gsensor_cmd_dev = device_create(gsensor_class, NULL, 0, NULL, "device");
11         device_create_file(gsensor_cmd_dev, &dev_attr_gsensor);  /* 生成 /sys/class/xr-gsensor/device/gsensor */
12         device_create_file(gsensor_cmd_dev, &dev_attr_delay_acc); /* 生成 /sys/class/xr-gsensor/device/delay_acc */
13         
14         ......
15     }

 

    由以上代碼可知,這個驅動生成了/dev/input/event2、/sys/class/n2dm_acc、/sys/class/xr-gsensor/device/gsensor、
/sys/class/xr-gsensor/device/delay_acc這4個文件節點,其中/sys/class/n2dm_acc文件節點用不到,可以不用理會。其餘3
個文件節點的作用分別是:
1. /dev/input/event2:驅動通過這個文件節點上報輸入事件,如這個是g-sensor感測器,會上報x,y,z三軸事件,數據格式:

input_report_abs(acc->input_dev, ABS_X, xyz[0]);
input_report_abs(acc->input_dev, ABS_Y, xyz[1]);
input_report_abs(acc->input_dev, ABS_Z, xyz[2]);
input_sync(acc->input_dev);

 

2. /sys/class/xr-gsensor/device/gsensor數據格式:

    "1"     /* 使能g-sensor */
    "0"     /* 禁止g-sensor */

 

3. /sys/class/xr-gsensor/device/delay_acc數據格式:

    十進位數值  /* g-sensor 數據刷新頻率,時間ms */

 

(B) 系統層通過什麼方式訪問驅動層?

    系統層肯定是通過open、read、write、ioctl等函數讀寫文件節點的方式訪問驅動層,讀寫這些文件節點的代碼路徑在:

    vendor/sprd/open-source/libs/libsensors_sprd/

    這個目錄下是各種感測器,如:g-sensor、光感、陀螺儀等的系統訪問驅動的介面文件,這裡以g-sensor為例來分析,
文件路徑:

    vendor/sprd/open-source/libs/libsensors_sprd/Acc_Xr.cpp
    vendor/sprd/open-source/libs/libsensors_sprd/AccSensor.h
    vendor/sprd/open-source/libs/libsensors_sprd/InputEventReader.cpp
    vendor/sprd/open-source/libs/libsensors_sprd/InputEventReader.h
    vendor/sprd/open-source/libs/libsensors_sprd/sensors.cpp
    vendor/sprd/open-source/libs/libsensors_sprd/sensors.h

 

    其中,vendor/sprd/open-source/libs/libsensors_sprd/InputEventReader.cpp文件的作用是為事件讀取提供一個環形
緩衝區,vendor/sprd/open-source/libs/libsensors_sprd/sensors.cpp的作用是抽象所有的sensor為一個sensor hal。

AccSensor.h

 1     class AccSensor : public SensorBase {
 2     public:
 3                 AccSensor();
 4         virtual ~AccSensor();
 5     
 6     #ifndef ACC_NULL
 7         enum {
 8             Accelerometer = 0,
 9             numSensors
10         };
11     #else
12         static const int numSensors = 0;
13     #endif
14     
15         virtual int readEvents(sensors_event_t* data, int count);
16         virtual bool hasPendingEvents() const;
17         virtual int setDelay(int32_t handle, int64_t ns);
18         virtual int setEnable(int32_t handle, int enabled);
19         virtual int64_t getDelay(int32_t handle);
20         virtual int getEnable(int32_t handle);
21         virtual int populateSensorList(struct sensor_t *list);
22     private:
23         int mEnabled;
24         int64_t mDelay;
25         int mLayout;
26         InputEventCircularReader mInputReader;
27         sensors_event_t mPendingEvent;
28         bool mHasPendingEvent;
29         char input_sysfs_path[PATH_MAX];
30         int input_sysfs_path_len;
31     
32         int setInitialState();
33         SensorCoordinate mSensorCoordinate;
34     };

    AccSensor.h 文件定義了一個AccSensor類,派生於SensorBase,而Acc_Xr.cpp就是實現了這個類裡面的方法

    Acc_Xr.cpp

 1     AccSensor::AccSensor() :
 2         SensorBase(NULL, XR_ACC_INPUT_NAME),
 3             mEnabled(0), mDelay(-1), mInputReader(32), mHasPendingEvent(false),
 4             mSensorCoordinate()
 5     {
 6         ......
 7         mPendingEvent.sensor = ID_A;
 8         ......
 9     
10         strcpy(input_sysfs_path, XR_GSENSOR_DEVICE_NAME);
11         input_sysfs_path_len = strlen(input_sysfs_path);
12         ......
13         
14         /* AccSensor的構造函數主要做了:
15          * 1. 構造SensorBase,掃描所有的/dev/input/event*,並判斷該文件節點下是否存在一個名為XR_ACC_INPUT_NAME
16          *    (accelerometer)的輸入設備,我的設備是/dev/input/event2,如果存在,則返回該文件節點的fd
17          * 2. 獲得input_sysfs_path文件節點為XR_GSENSOR_DEVICE_NAME(/sys/class/xr-gsensor/device/)
18          * 3. 初始化一個環形緩衝區
19          * 4. 設置sensor類型ID_A
20          */
21     }    
22         
23     int AccSensor::setEnable(int32_t handle, int enabled) 
24     {
25         ......
26         if(enabled==1)
27         strcpy(enable,"1");                                                                                        
28         else if(enabled==0)                                                                                        
29         strcpy(enable,"0");                                                                                        
30         else 
31         strcpy(enable,"2");
32         ......
33         
34         /* 設置sensor狀態,1:使能,0:禁止 
35          * 把狀態值寫到文件節點:/sys/class/xr-gsensor/device/gsensor
36          */
37         strcpy(&input_sysfs_path[input_sysfs_path_len], "gsensor");
38         err = write_sys_attribute(input_sysfs_path, enable, 1);
39         ......
40         mEnabled &= ~(1);
41         mEnabled |= uint32_t(newState);
42         
43         ......
44     }
45 
46 
47     int AccSensor::setDelay(int32_t handle, int64_t delay_ns)
48     {
49         ......
50         ms = delay_ns / 1000000;
51         strcpy(&input_sysfs_path[input_sysfs_path_len], "delay_acc");
52         bytes = sprintf(buffer, "%d", ms);
53         write_sys_attribute(input_sysfs_path, buffer, bytes);
54         ......
55     }
56     
57     
58     int AccSensor::readEvents(sensors_event_t * data, int count)
59     {
60         ......
61         /* 從文件節點/dev/input/event2中讀取驅動層提交的事件,
62          * 並寫入環形隊列
63          */
64         ssize_t n = mInputReader.fill(data_fd);
65         ......
66         /* 從隊列中取出一個事件 */
67         while (count && mInputReader.readEvent(&event)) {
68             ......
69             /* 寫入到sensors_event_t緩衝區 */
70             *data++ = mPendingEvent;
71             count--;
72             numEventReceived++;
73             ......
74             /* 指向下一個事件 */
75             mInputReader.next();
76         }
77         
78         return numEventReceived;
79     }
80     
81     
82     int AccSensor::populateSensorList(struct sensor_t *list)
83     {
84         /* 把該sensor加入list鏈表 
85          * 所有的sensor都要加入到這個鏈表,以便統一管理
86          */
87         memcpy(list, sSensorList, sizeof(struct sensor_t) * numSensors);
88         return numSensors;
89     }

 

(C) 如何統一各種sensors的介面,生成.so庫?

    通過vendor/sprd/open-source/libs/libsensors_sprd/sensors.cpp 和
vendor/sprd/open-source/libs/libsensors_sprd/sensors.h 統一管理所有
sensor,抽象所有介面

    sensors.cpp

  1     static int sensors__get_sensors_list(struct sensors_module_t *module,
  2                          struct sensor_t const **list)
  3     {
  4         /* 獲取sensor鏈表首指針 */
  5         *list = sSensorList;
  6         /* 返回該sensor總數 */
  7         return numSensors;
  8     }
  9     
 10     static struct hw_module_methods_t sensors_module_methods = {
 11     open:   open_sensors
 12     };
 13 
 14     /* sensors.cpp最終的目的就是要構造這個結構體 */   
 15     struct sensors_module_t HAL_MODULE_INFO_SYM = {                                                                
 16             common:{
 17                     tag: HARDWARE_MODULE_TAG,                                                                      
 18                     version_major: 1,                                                                              
 19                     version_minor: 0,
 20                     /* 載入so庫時,是通過SENSORS_HARDWARE_MODULE_ID
 21                      * 找到這個結構體
 22                      */
 23                     id: SENSORS_HARDWARE_MODULE_ID,                                                                
 24                     name: "SPRD Sensor module",                                                                    
 25                     author: "Spreadtrum",
 26                     methods: &sensors_module_methods,                                                              
 27                     dso: 0,
 28                     reserved:{},                                                                                   
 29             },
 30             get_sensors_list:sensors__get_sensors_list,                                                            
 31     }; 
 32 
 33 
 34     sensors_poll_context_t::sensors_poll_context_t()
 35     {
 36         /* 實例化一個AccSensor類的對象 
 37          * 這個對象代表一個g-sensor
 38          */
 39         mSensors[acc] = new AccSensor();
 40         /* 獲得sensor索引 */
 41         numSensors +=
 42             mSensors[acc]->populateSensorList(sSensorList + numSensors);
 43         /* 讀取/dev/input/event2節點的fd */
 44         mPollFds[acc].fd = mSensors[acc]->getFd();
 45         /* 有數據輸入就產生POLLIN事件 */
 46         mPollFds[acc].events = POLLIN;
 47         mPollFds[acc].revents = 0;
 48         ......
 49         
 50         /* 實例化一個磁力計對象 */
 51         mSensors[ori] = new OriSensor();                                                                           
 52         numSensors +=                                                                                              
 53             mSensors[ori]->populateSensorList(sSensorList + numSensors);                                           
 54         mPollFds[ori].fd = mSensors[ori]->getFd();                                                                 
 55         mPollFds[ori].events = POLLIN;                                                                             
 56         mPollFds[ori].revents = 0;  
 57         
 58         /* 實例化一個光感對象 */  
 59         ......
 60         
 61         /* 以下創建的管道,感覺沒啥用,多餘的
 62          * 因為在activate中寫管道,在pollEvent中度管道,
 63          * 讀到消息後並沒有做什麼相關處理,有知道的兄弟
 64          * 麻煩指教一下,非常感謝!
 65          */
 66         int wakeFds[2];
 67         /* 創建一個管道 */
 68         int result = pipe(wakeFds);
 69         ALOGE_IF(result < 0, "error creating wake pipe (%s)", strerror(errno));
 70         fcntl(wakeFds[0], F_SETFL, O_NONBLOCK);
 71         fcntl(wakeFds[1], F_SETFL, O_NONBLOCK);
 72         /* 寫管道的fd */
 73         mWritePipeFd = wakeFds[1];
 74         
 75         /* 讀管道的fd */
 76         mPollFds[wake].fd = wakeFds[0];
 77         mPollFds[wake].events = POLLIN;
 78         mPollFds[wake].revents = 0;  
 79     }
 80     
 81     
 82     int sensors_poll_context_t::activate(int handle, int enabled)
 83     {
 84         /* 獲得sensor類型 */
 85         int drv = handleToDriver(handle);
 86         ......
 87         /* 使能該sensor,如:如果這是g-sensor,則調用的是
 88          * AccSensor::setEnable(int32_t handle, int enabled) 
 89          */
 90         err = mSensors[drv]->setEnable(handle, enabled);
 91         /* 往管道寫一個WAKE_MESSAGE消息 */
 92         const char wakeMessage(WAKE_MESSAGE);
 93         int result = write(mWritePipeFd, &wakeMessage, 1);
 94     }
 95 
 96 
 97     int sensors_poll_context_t::setDelay(int handle, int64_t ns)
 98     {
 99         ......
100         return setDelay_sub(handle, ns);
101     }
102     
103     int sensors_poll_context_t::setDelay_sub(int handle, int64_t ns)
104     {
105         /* 獲得sensor類型 */
106         int drv = handleToDriver(handle);
107         
108         /* 獲取sensor的狀態,使能還是禁止
109          * 如:如果這是g-sensor,則調用的是
110          * AccSensor::getEnable(int32_t handle)
111          */
112         int en = mSensors[drv]->getEnable(handle);
113         /* 獲取sensor的輸入事件頻率
114          * 如:如果這是g-sensor,則調用的是
115          * AccSensor::getDelay(int32_t handle) 
116          */
117         int64_t cur = mSensors[drv]->getDelay(handle);
118         ......
119         
120         /* 設置sensor的輸入事件頻率
121          * 如:如果這是g-sensor,則調用的是
122          * AccSensor::setDelay(int32_t handle, int64_t delay_ns)
123          */
124         err = mSensors[drv]->setDelay(handle, ns);  
125         ......
126     }
127     
128     
129     int sensors_poll_context_t::pollEvents(sensors_event_t * data, int count)
130     {
131         ......
132         do {
133             /* 輪詢讀各個sensor的輸入事件 */
134             for (int i = 0; count && i < numSensorDrivers; i++) {
135                 SensorBase *const sensor(mSensors[i]);
136                 ......
137                 /* 讀事件 */
138                 int nb = sensor->readEvents(data, count);
139                 ....
140                 count -= nb;
141                 nbEvents += nb;                                                                                
142                 data += nb; 
143             }
144             /* 還有事件沒讀完 */
145             if (count) { 
146                 do {
147                     /* 休眠等待事件輸入,如果超時則退出 */
148                     n = poll(mPollFds, numFds,
149                         nbEvents ? 0 : polltime);                                                                 
150                 } while (n < 0 && errno == EINTR);  
151                 
152                 if (mPollFds[wake].revents & POLLIN) {
153                     ......
154                     /* 從管道讀出msg,然而什麼都沒乾,why? */
155                     int result = read(mPollFds[wake].fd, &msg, 1);
156                     ......
157                 }
158             }
159        } while (n && count);
160          
161        return nbEvents;
162     }
163     
164     static int poll__activate(struct sensors_poll_device_t *dev,
165                   int handle, int enabled)
166     {
167         sensors_poll_context_t *ctx = (sensors_poll_context_t *) dev;
168         return ctx->activate(handle, enabled);
169     }
170     
171     static int poll__setDelay(struct sensors_poll_device_t *dev,
172                   int handle, int64_t ns)
173     {
174         sensors_poll_context_t *ctx = (sensors_poll_context_t *) dev;
175         return ctx->setDelay(handle, ns);
176     }
177     
178     static int poll__poll(struct sensors_poll_device_t *dev,
179                   sensors_event_t * data, int count)
180     {
181         sensors_poll_context_t *ctx = (sensors_poll_context_t *) dev;
182         return ctx->pollEvents(data, count);
183     }
184 
185 
186     /** Open a new instance of a sensor device using name */
187     static int open_sensors(const struct hw_module_t *module, const char *id,
188                 struct hw_device_t **device)
189     {
190         int status = -EINVAL;
191         sensors_poll_context_t *dev = new sensors_poll_context_t();
192     
193         memset(&dev->device, 0, sizeof(sensors_poll_device_t));
194         
195         /* 構造sensors_poll_context_t結構體 */
196         dev->device.common.tag = HARDWARE_DEVICE_TAG;
197         dev->device.common.version = 0;
198         dev->device.common.module = const_cast < hw_module_t * >(module);
199         dev->device.common.close = poll__close;
200         dev->device.activate = poll__activate;
201         dev->device.setDelay = poll__setDelay;
202         dev->device.poll = poll__poll;
203     
204         *device = &dev->device.common;
205         status = 0;
206     
207         return status;
208     }

 

    Android.mk

    

    ......
    LOCAL_MODULE := sensors.$(TARGET_BOARD_PLATFORM)  #這裡的TARGET_BOARD_PLATFORM是sc8830
    ......

 

mmm ./vendor/sprd/open-source/libs/libsensors_sprd -B
生成sensors.sc8830.so

這樣就實現了硬體和應用的分離,應用要訪問硬體是只要載入這個so庫就行了

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 有bug的代碼如下: 現象:第一次進入頁面,點擊保存(表單驗證是通過的);會列印兩個test; 該問題官方文檔中給出了幾種解決方案: 文檔地址(有牆):http://formvalidation.io/examples/form-submit-twice/ 參考文檔,我通過給submit按鈕綁定事件 ...
  • 例1 在sayHello()函數中定義並調用了sayAlert()函數;sayAlert()作為內層函數,可以訪問外層函數sayHello()中的text變數。 例2 例3 得到的結果:連續輸出3個"item3 undefined"解析:通過執行buildList函數,返回了一個result,那麼這 ...
  • 顯示具體時間時分秒: 重點大坑:修改時間預設展示格式,把fomat寫在locale中,網上很多資料說直接寫在daterangepicker屬性中,這樣是不生效的。 起止時間可以設置為具體年月日也可以生成當前日期(new Date() 或者 moment()【moment()方法為moment.js獲 ...
  • 可拓展性 HTML有廣泛的可擴展性機制,可用於以安全的方式添加語義: 作者可以使用class屬性來擴展元素,有效地創建自己的元素,同時使用最適用的現有的"real"HTML元素,這樣瀏覽器和其他不知道擴展的工具仍然可以很好地支持它。例如,微格式使用的策略。 作者可以在包括用於內聯客戶端腳本或伺服器端 ...
  • HorizontalScrollView水平滾動控制項 一、簡介 用法ScrollView大致相同 二、方法 1)HorizontalScrollView水平滾動控制項使用方法 1、在layout佈局文件的最外層建立一個HorizontalScrollView控制項 2、在HorizontalScroll ...
  • ScrollView垂直滾動控制項 一、簡介 二、方法 1)ScrollView垂直滾動控制項使用方法 1、在layout佈局文件的最外層建立一個ScrollView控制項 2、在ScrollView控制項中加入一個LinearLayout控制項,並且把它的orientation設置為vertical 3、在 ...
  • 進度條控制項基本使用 一、簡介 二、方法 1)進度條ProgressBar使用方法 1、在layout佈局文件中創建ProgressBar控制項 <ProgressBar style="?android:attr/progressBarStyleHorizontal" android:layout_wi ...
  • 時間對話框的使用 一、簡介 二、方法 1)顯示TimePickerDialog方法 1、新建TimePickerDialog對象 TimePickerDialog timeDialog=new TimePickerDialog(this, new MyTimeSetListener(), 13, 3 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...