當前位置:首頁 » 安卓系統 » androiduevent

androiduevent

發布時間: 2024-08-21 13:06:57

1. android sensor怎樣創建設備節點

在Android中,由於沒有mdev和udev,所以它沒有辦法動態的生成設備節點,那麼它是如何做的呢?

我們可以在system/core/init/下的init.c和devices.c中找到答案:

init.c中

在Android中,沒有獨立的類似於udev或者mdev的用戶程序,這個功能集成到了init中做了。代碼見:system/core/init/init.c文件,如下:

if (ufds[0].revents == POLLIN)

handle_device_fd(device_fd);

其中handle_device_fd(device_fd)函數在system/core/init/devices.c中實現,參數device_fd 由函數device_init()->open_uevent_socket()->socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT)函數調用返回。

函數handle_device_fd(device_fd)中,根據傳進來的device_fd參數,調用recv(fd, msg, UEVENT_MSG_LEN, 0)函數,將內核探測到的設備並通過NETLINK機制傳過來的socket描述符轉化成消息。接著調用parse_event(msg, &uevent);函數將消息翻譯成uevent事件,並將改事件傳遞給handle_device_event(&uevent)函數。

handle_device_event(&uevent)函數中,依據參數uevent->subsystem類型創建dev下的相應目錄,如:/dev/graphics。緊接著根據uevent->action是"add"還是"remove"來實現設備節點的創建與刪除。如果uevent->action是"add",則調用make_device(devpath, block, uevent->major, uevent->minor)函數生成設備節點。如果uevent->action是"remove",則調用unlink(devpath)對設備節點進行刪除。

2. 怎樣在烏班圖系統中新建70-android-usb.rules文件

你需要這么做下,udev的文件系統需要添加這個uevent的rule: 基於uevent驅動載入機制,需要再/etc/udev/rules.d/51-android.rules文件,內容如下 SUBSYSTEM=="usb", SYSFS{idVendor}=="18d1", MODE="0666" 同時chmod修改777許可權。

3. vivo x9怎麼查電池壽命

vivo X9手機不能查詢電池壽命的。
vivo手機電池壽命一般為2-3年,使用手機的習慣也會影響電池的壽命。隨著手機的充電次數增加,電池的實際容量會減少,所以建議在手機提示電量低時再充電,充電的時候盡量不要使用手機。

4. Ubuntu下連接Android手機為什麼沒有反應或者說linux怎樣連接Android手機來使用U盤

這個恩一般我記得連接Android的操作系統你得給usb添加一個驅動到/etc/udev/下面哦。ubuntu現在是基於uevent驅動的熱插拔機制。

基於uevent驅動載入機制,需要再/etc/udev/rules.d/51-android.rules文件,內容如下SUBSYSTEM=="usb", SYSFS{idVendor}=="18d1", MODE="0666"同時chmod修改777許可權。供usb驅動使用

5. android耳機插拔監聽做不了全局注冊嗎

1. 耳機檢測的硬體原理
一般的耳機檢測包含普通的耳機檢測和帶mic的耳機檢測兩種,這兩種耳機統稱為Headset,而對於不帶mic的耳機,一般稱之為Headphone。

對於Headset裝置的插入檢測,一般通過Jack即耳機插座來完成,大致的原理是使用帶檢測機械結構的耳機插座,將檢測腳連到可GPIO中斷上,當耳機插入時,耳機插頭的金屬會碰到檢測腳,使得檢測腳的電平產生變化,從而引起中斷。這樣就可以在中斷處理函數中讀取GPIO的的值,進一步判斷出耳機是插入還是拔出。

而對於Headset是否帶mic的檢測,需要通過codec附加的micbias電流的功能。

Android耳機插拔可以有兩個機制實現:

1. InputEvent

2. UEvent

其中UEvent是Android系統默認的耳機插拔機制,所以這里代碼是基於UEvent實現的,對於InputEvent機制只是大概看了看,並沒有具體實現。

1.1 兩種機制的切換
Android默認提供了兩種解決方法,那麼一定也提供了兩種方式的切換,這個提供切換的設置名為config_useDevInputEventForAudioJack( When true use the linux /dev/input/event subsystem to detect the switch changes on the headphone/microphone jack. When false use the older uevent framework),對Android源代碼進行全局搜索,可以看到它在frameworks/base/core/res/res/values/config.xml中,默認為false,即不使用InputEvent方式,另外在源碼包的廠商相關的文件夾中也找到了相關的設置,如下:

/android/4.2/device/asus/flo/overlay/frameworks/base/core/res/res/values/config.xml

false

/android/4.2/device/samsung/manta/overlay/frameworks/base/core/res/res/values/config.xml

True

可以看到有些廠商的確是使用了InputEvent的方式來進行耳機檢測。具體對這個變數的修改是在device下還是frameworks下我想應該都可以,device下可能更好。violet源碼device/mstar/mstarnike/overlay/frameworks/base/core/res/res/values/config.xml 中,沒有對config_useDevInputEventForAudioJack 設置。

1.2 Android耳機插撥檢測流程

2 InputEvent
2.1 Framework層對InputEvent的處理機制
InputEvent的處理主要在frameworks/base/services/java/com/android/server/input/

InputManagerService.java中。在InputManagerService構造函數中,通過如下函數,

mUseDevInputEventForAudioJack = context.getResources().

getBoolean(R.bool.config_useDevInputEventForAudioJack);

判斷當前是否通過InputEvent實現耳機插拔檢測。

當Android得到InputEvent後,會調用InputManagerService.java中notifySwitch的函數,進而轉至WiredAccessoryManager.java文件中的notifyWiredAccessoryChanged函數,之後的流程就和UEvent相同了,在後續會講到。

2.2 Kernel層的處理機制
Kernel層對耳機插拔InputEvent處理主要是通過input_report_key/input_report_switch(include/linux/input.h)來實現,而在實際使用中,ASOC已經為我們封裝好了相應Jack介面函數,只要符合規范就可以拿來使用。下面列出幾個常用的介面函數(/sound/soc/soc-jack.c)。

int snd_soc_jack_new(structsnd_soc_codec *codec,

const char *id, int type, struct snd_soc_jack *jack)

生成一個新的jack對象,定義其被檢測的類型,即可能插入的設備類型。一般定義為SND_JACK_HEADSET,其餘也可以根據介面支持種類添加SND_JACK_LINEOUT,SND_JACK_AVOUT等。

這個函數中調用了snd_jack_new,而在snd_jack_new中可以看到調用 input_allocate_device()分配了input device,就可以在後續產生input event了。

int snd_soc_jack_add_pins(structsnd_soc_jack *jack, int count, struct snd_soc_jack_pin *pins)

將之前定義好的pins加入dapm widgets中,方便dapm統一管理。這一步和InputEvent沒有一定聯系,可以不調用,主要是可以將耳機插座定義為widgets加入dapm進行省電管理。

viod snd_soc_jack_report(structsnd_soc_jack *jack, int status, int mask)

匯報jack插拔狀態,主要完成以下兩個工作:

 a) 根據插入拔出狀態更新前面通過snd_soc_jack_add_pins加入的dapm pin的狀態,對其進行上電下電管理。

b) 調用snd_jack_report,在其中通過input_report_key/input_report_switch來向上層匯報input event。

基於上面的函數,可以用以下做法來實現基於InputEvent機制的耳機插拔檢測:

a) snd_soc_jack_new 創建jack對象

b) snd_soc_jack_add_pins將其加入到dapm wigets中

c) 通過request irq申請耳機插拔中斷,在中斷處理函數中通過檢測線高低電平判斷耳機是插入還是拔出,通過讀取codec寄存器來判斷是headset還是headphone

d) 根據判斷結果調用snd_soc_jack_report發送InputEvent

此外,ASOC還提供了一個封裝好的函數來實現上述c)和d)步驟的功能:

int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,

struct snd_soc_jack_gpio *gpios)

該函數通過標准GPIO驅動申請GPIO及GPIO對應中斷,並提供了統一的中斷處理函數來匯報事件。此函數只適用於耳機中斷接至GPIO且GPIO驅動為Linux標准驅動的情況下,並且不支持mic檢測。

3. UEvent
3.1 Switch 基本原理
Switch是Android引進的新的驅動,目的是用於檢測一些開關量,比如檢測耳機插入、檢測 USB 設備插入等。Switch在sysfs文件系統中創建相應entry,用戶可以通過sysfs與之交互; 此外還可以通過uevent機制與之交互, 從而檢測switch狀態。

3.1.1 Switch的實現
Switch class在Android中實現為一個mole,可動態載入;而具體的switch gpio則是基於 platform device框架。代碼在drivers\switch\switch_class.c和drivers\switch\switch_gpio.c中。其中switch_class.c實現了一個switch class,而switch_gpio.c則是這個class中的一個device,即針對gpio的一個switch設備。

switch_class.c文件創建了一個switch_class,實現了內核的switch機制,提供支持函數供其他switch device驅動調用。

static int __init switch_class_init(void){

return create_switch_class(); }

static void __exit switch_class_exit(void){

class_destroy(switch_class); }

mole_init(switch_class_init);

mole_exit(switch_class_exit);

init函數調用create_switch_class->class_create創建switch_class設備類。相對應 exit則是銷毀這個設備類。

該文件導出兩個函數供其他switch設備驅動調用,分別是注冊switch設備switch_dev_register和注銷switch_dev_unregister(drivers/switch/switch_class.c)。

int switch_dev_register(struct switch_dev *sdev)

{

int ret;

if (!switch_class) {

ret = create_switch_class();

if (ret < 0)

return ret;

}

sdev->index = atomic_inc_return(&device_count);

sdev->dev = device_create(switch_class, NULL,

MKDEV(0, sdev->index), NULL, sdev->name);

if (IS_ERR(sdev->dev))

return PTR_ERR(sdev->dev);ret = device_create_file(sdev->dev, &dev_attr_state);

if (ret < 0)

goto err_create_file_1;

ret = device_create_file(sdev->dev, &dev_attr_name);

if (ret < 0)

goto err_create_file_2;dev_set_drvdata(sdev->dev, sdev);

sdev->state = 0;

return 0;

err_create_file_2:

device_remove_file(sdev->dev, &dev_attr_state);

err_create_file_1:

device_destroy(switch_class, MKDEV(0, sdev->index));

printk(KERN_ERR "switch: Failed to register driver %s\n", sdev->name);return ret;

}

EXPORT_SYMBOL_GPL(switch_dev_register);void switch_dev_unregister(struct switch_dev *sdev)

{

device_remove_file(sdev->dev, &dev_attr_name);

device_remove_file(sdev->dev, &dev_attr_state);

dev_set_drvdata(sdev->dev, NULL);

device_destroy(switch_class, MKDEV(0, sdev->index));

}

EXPORT_SYMBOL_GPL(switch_dev_unregister);

然後是兩個sysfs操作函數(state_show和name_show),分別用於輸出switch device的name和state。當用戶讀取sysfs中對應的switch entry(/sys/class/switch/<dev_name>/name和/sys/class/switch/<dev_name>/state)時候,系統會自動調用這兩個函數向用戶返回switch設備的名稱和狀態。

static ssize_t state_show(struct device *dev, struct device_attribute *attr, char *buf)

{

struct switch_dev *sdev = (struct switch_dev *)dev_get_drvdata(dev);

if (sdev->print_state) {

int ret = sdev->print_state(sdev, buf);

if (ret >= 0)

return ret;

}

return sprintf(buf, "%d\n", sdev->state);

}static ssize_t name_show(struct device *dev, struct device_attribute *attr,

char *buf)

{

struct switch_dev *sdev = (struct switch_dev *)dev_get_drvdata(dev);

if (sdev->print_name) {

int ret = sdev->print_name(sdev, buf);

if (ret >= 0)

return ret;

}

return sprintf(buf, "%s\n", sdev->name);

}

可見,這兩個函數就是直接調用對應的switch_dev中的print_state和print_name函數;如果沒有定義這兩個函數,則調用sprintf把信息列印到buf緩沖區里。

最後是 switch_set_state 函數,該函數是內核內部使用,並不為用戶調用,它完成的功能主要是兩件事: 調用name_show和state_show輸出switch設備名稱和狀態至sysfs文件系統;發送uevent通知用戶switch device的信息(名稱和狀態) 。

switch_gpio.c文件基於switch class實現了一個gpio的switch設備驅動,其實現的原理如下: 基於platform device/driver框架,在probe函數中完成初始化,包括獲取gpio的使用許可權,設置gpio方向為輸入,注冊switch_dev設備,為gpio分配中斷,指定中斷服務程序,初始化一個gpio_switch_work工作,最後讀取gpio初始狀態。

當 GPIO 引腳狀態發生變化時,則會觸發中斷,在中斷服務程序中調用schele_work,這個被schele的work即前面初始化的gpio_switch_work,最後這個work被執行,在gpio_switch_work函數中讀取當前gpio電平,調用 switch_set_state更新sysfs並通過 uevent通知上層應用。

這個設備驅動只實現了print_state函數:switch_gpio_print_state,沒有實現 print_name函數。當gpio_switch_work執行的時候,裡面調用switch_set_state->switch_gpio_print_state輸出GPIO狀態到 sysfs。

3.1.2 Switch模塊的用戶介面
sysfs文件為sys/class/switch/<dev_name>/name, sys/class/switch/<dev_name>/state,uevent環境變數為SWITCH_NAME=<name>, SWITCH_STATE=<state>。sysfs文件系統和uevent機制。

UEvent機制比較簡單,它基於switch driver,switch driver會在Android建立耳機插拔的目錄/sys/devices/virtual/switch/h2w,在此目錄下有個設備結點名為state,driver通過更新state的值,從而通知Android上層耳機狀態的改變。

3.2 Framework層對UEvent的處理機制
Android在frameworks/base/services/java/com/android/server/WiredAccessoryManager. java中實現針對UEvent的機制。

在這個文件中,從UEventObserver中繼承了類WiredAccessoryObserver,在makeObservedUEventList中將要觀察的事件加入到UEvent系統中:

if(!mUseDevInputEventForAudioJack)

{

uei = new UEventInfo(NAME_H2W,BIT_HEADSET, BIT_HEADSET_NO_MIC);

……

}

可以看到,只有當不使用InputEvent時才添加UEvent事件,NAME_H2W就是headphone對應的switch driver的名字。BIT_HEADSET和BIT_HEADSET_NO_MIC是state結點的兩個值,分別表示有mic和無mic的耳機。

當UEvent事件到來時,類WiredAccessoryObserver中重載的onUEvent函數會被回調,從而調用updateStateLocked(devPath,name, state) ,其中state的值就是通過/sys/devices/virtual/switch/h2w/state結點來獲得。

最後,程序會進入setDeviceStateLocked函數中處理,在setDeviceStateLocked中根據state的值設置device,然後調用mAudioManager.setWiredDeviceConnectionState,最後進入AudioPolicyManagerBase::setDeviceConnectionState。

3.3 Kernel層的機制
前面說過,基於UEvent的耳機檢測機制需要實現一隻switch driver,它會建立一個用於耳機插拔檢測的目錄/sys/devices/virtual/switch/h2w,在此目錄下有個設備結點名為state,switch driver通過更新state的值,從而通知Android上層耳機狀態的改變。

switch driver的目錄在Linux kernel的drivers/staging/android/switch目錄下,可以從目錄名稱中看到這只driver是為了Android專門產生的。在switch目錄下有兩個已有文件,switch_class.c是switch driver的內部實現,它提供了switch driver所需的一些API;switch_gpio.c是一個例子,它實現了一個基於GPIO中斷的switch driver。

另外,在drivers/switch目錄下也有同樣的文件,不同之處是兩者在Android下生成的結點的位置不同,如果要按照drivers/switch目錄下的switch driver來實現,需要更改WiredAccessoryManager.java文件。

下面講講如何添加switch driver。添加switch driver很簡單,可以仿照switch_gpio.c,大致步驟如下:

 a) 在drivers/staging/android/switch目錄下新建一個platform driver,其中包含一個全局變數struct switch_dev sdev,即要注冊的switch device。

b) 在platformdriver的probe函數中調用switch_dev_register將前面的sdev注冊到系統中。

c) 申請用於耳機檢測的中斷處理函數。對於耳機插拔來說,由於用戶的插拔快慢等可能產生多次中斷,所以一般是在中斷處理函數中實現一個延時工作隊列,即INIT_DELAYED_WORK,在隊列的回調函數中來進行實際判斷。

d) 當中斷發生後,通過switch_set_state設置state節點的值,這個值要和WiredAccessoryManager.java文件中定義的一致,可參看BIT_HEADSET和BIT_HEADSET_NO_MIC的定義。目前是0表示無耳機插入,1表示帶Mic的耳機,2表示不帶Mic的耳機。switch_set_state這個函數調用了kobject_uevent_env/kobject_uevent,這兩個函數就是kernel通過uevent來通知user space的核心函數了。

6. android uevent 怎麼獲取

Device Year Class 的主要功能是根據 CPU核數、時鍾頻率 以及 內存大小 對設備進行分級。代碼很簡單,只包含兩個類: DeviceInfo-> 獲取設備參數, YearClass-> 根據參數進行分級。 下表是 Facebook 公司提供的分級標准,其中Year欄表示分級結果。 Year Cores Clock RAM 2008 1 528MHz 192MB 2009 n/a 600MHz 290MB 2010 n/a 1.0GHz 512MB 2011 2 1.2GHz 1GB 2012 4 1.5GHz 1.5GB 2013 n/a 2.0GHz 2GB 2014 n/a >2GHz >2GB 關於輸出年份的計算方法可以參考源碼,本文只把一些比較常用的功能抽取出來做一個簡要介紹。 獲取 CPU 核數 我們都知道,Linux 中的設備都是以文件的形式存在,CPU 也不例外,因此 CPU 的文件個數就等價與核數。 Android 的 CPU 設備文件位於/sys/devices/system/cpu/目錄,文件名的的格式為cpu\d+。 ? 1 2 3 4 5 6 7 8 9 10 root@generic_x86_64:/sys/devices/system/cpu # ls <b>cpu0</b> cpufreq cpuidle kernel_max modalias offline online possible power present uevent 統計一下文件個數便可以獲得 CPU 核數。 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 public static int getNumberOfCPUCores() { if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) { // Gingerbread doesn't support giving a single application access to both cores, but a // handful of devices (Atrix 4G and Droid X2 for example) were released with a al-core // chipset and Gingerbread; that can let an app in the background run without impacting // the foreground application. But for our purposes, it makes them single core. return 1; } int cores; try { cores = new File("/sys/devices/system/cpu/").listFiles(CPU_FILTER).length; } catch (SecurityException e) { cores = DEVICEINFO_UNKNOWN; } catch (NullPointerException e) { cores = DEVICEINFO_UNKNOWN; } return cores; } private static final FileFilter CPU_FILTER = new FileFilter() { @Override public boolean accept(File pathname) { String path = pathname.getName(); //regex is slow, so checking char by char. if (path.startsWith("cpu")) { for (int i = 3; i < path.length(); i++) { if (path.charAt(i) < '0' path.charAt(i) > '9') { return false; } } return true; } return false; } }; 回到頂部 獲取時鍾頻率 獲取時鍾頻率需要讀取系統文件 -/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq或者/proc/cpuinfo。 我的 Android 模擬器中並沒有cpuinfo_max_freq文件,因此只能讀取/proc/cpuinfo。 /proc/cpuinfo包含了很多 cpu 數據。 ? processor : 0 vendor_id : GenuineIntel cpu family : 6 model : 70 model name : Intel(R) Core(TM) i7-4770HQ CPU @ 2.20GHz stepping : 1 cpu MHz : 0.000 cache size : 1024 KB fdiv_bug : no hlt_bug : no f00f_bug : no coma_bug : no fpu : yes fpu_exception : yes cpuid level : 4 wp : yes 代碼如下: public static int getCPUMaxFreqKHz() { int maxFreq = DEVICEINFO_UNKNOWN; try { for (int i = 0; i < getNumberOfCPUCores(); i++) { String filename = "/sys/devices/system/cpu/cpu" + i + "/cpufreq/cpuinfo_max_freq"; File cpuInfoMaxFreqFile = new File(filename); if (cpuInfoMaxFreqFile.exists()) { byte[] buffer = new byte[128]; FileInputStream stream = new FileInputStream(cpuInfoMaxFreqFile); try { stream.read(buffer); int endIndex = 0; //Trim the first number out of the byte buffer. while (buffer[endIndex] >= '0' && buffer[endIndex] <= '9' && endIndex < buffer.length) endIndex++; String str = new String(buffer, 0, endIndex); Integer freqBound = Integer.parseInt(str); if (freqBound > maxFreq) maxFreq = freqBound; } catch (NumberFormatException e) { //Fall through and use /proc/cpuinfo. } finally { stream.close(); } } } if (maxFreq == DEVICEINFO_UNKNOWN) { FileInputStream stream = new FileInputStream("/proc/cpuinfo"); try { int freqBound = parseFileForValue("cpu MHz", stream); freqBound *= 1000; //MHz -> kHz if (freqBound > maxFreq) maxFreq = freqBound; } finally { stream.close(); } } } catch (IOException e) { maxFreq = DEVICEINFO_UNKNOWN; //Fall through and return unknown. } return maxFreq; } 回到頂部 獲取內存大小 如果 SDK 版本大於等於JELLY_BEAN,可以通過ActivityManager來獲取內從大小。 ? ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo(); ActivityManager am = (ActivityManager) c.getSystemService(Context.ACTIVITY_SERVICE); am.getMemoryInfo(memInfo); 如果版本低於JELLY_BEAN,則只能讀取系統文件了。 ? FileInputStream stream = new FileInputStream("/proc/meminfo"); totalMem = parseFileForValue("MemTotal", stream); 完整代碼如下: @TargetApi(Build.VERSION_CODES.JELLY_BEAN) public static long getTotalMemory(Context c) { // memInfo.totalMem not supported in pre-Jelly Bean APIs. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo(); ActivityManager am = (ActivityManager) c.getSystemService(Context.ACTIVITY_SERVICE); am.getMemoryInfo(memInfo); if (memInfo != null) { return memInfo.totalMem; } else { return DEVICEINFO_UNKNOWN; } } else { long totalMem = DEVICEINFO_UNKNOWN; try { FileInputStream stream = new FileInputStream("/proc/meminfo"); try { totalMem = parseFileForValue("MemTotal", stream); totalMem *= 1024; } finally { stream.close(); } } catch (IOException e) { } return totalMem; } }

熱點內容
壓縮包改直鏈 發布:2024-11-25 08:34:33 瀏覽:610
安卓機的照片如何傳送到蘋果機上 發布:2024-11-25 08:32:48 瀏覽:916
手游伺服器怎麼找ip 發布:2024-11-25 08:23:10 瀏覽:751
c語言名次 發布:2024-11-25 08:04:22 瀏覽:55
新浪雲伺服器登錄 發布:2024-11-25 08:04:21 瀏覽:853
工控機伺服器電腦的區別 發布:2024-11-25 08:04:21 瀏覽:513
Python對比matlab 發布:2024-11-25 07:45:58 瀏覽:307
ovt機頂盒管理員密碼多少 發布:2024-11-25 07:45:58 瀏覽:377
win10與linux雙系統 發布:2024-11-25 07:40:05 瀏覽:658
網易我的世界4d皮膚伺服器 發布:2024-11-25 07:38:36 瀏覽:944