在android的framework中想要监听底层的uevent事件是一件很简单的事情,只要以下几个步骤即可,拿UsbDeviceManager.java为例子。

首先,创建一个UEventObserver类:

 

[cpp] view plaincopy
 
  1. private final UEventObserver mUEventObserver = new UEventObserver() {                                                                                        
  2.     @Override  
  3.     public void onUEvent(UEventObserver.UEvent event) {  
  4.         if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString());  
  5.   
  6.         String state = event.get("USB_STATE");  
  7.         String accessory = event.get("ACCESSORY");  
  8.         if (state != null) {  
  9.             mHandler.updateState(state);  
  10.         } else if ("START".equals(accessory)) {  
  11.             if (DEBUG) Slog.d(TAG, "got accessory start");  
  12.             startAccessoryMode();  
  13.         }  
  14.     }  
  15. };  

在这个类中要重写onUevent方法,在该方法中处理你得到的事件。

 

接着,调用startObserving方法即可:

 

[cpp] view plaincopy
 
  1. mUEventObserver.startObserving(USB_STATE_MATCH);                                                                                                 
  2. mUEventObserver.startObserving(ACCESSORY_START_MATCH);  


这里:

 

 

[cpp] view plaincopy
 
  1. private static final String USB_STATE_MATCH =                                                                                                                
  2.         "DEVPATH=/devices/virtual/android_usb/android0";  
  3. private static final String ACCESSORY_START_MATCH =                                                                                                          
  4.         "DEVPATH=/devices/virtual/misc/usb_accessory";  


这样就可以监听上述路径下的uevent事件了。是不是很简单!

 

而UEventObserver类的实现以及JNI层和HAL层的实现,代码量也很少,看起来很简洁。

先看startObserving方法:

 

[cpp] view plaincopy
 
  1. public final synchronized void startObserving(String match) {  
  2.     ensureThreadStarted();  
  3.     sThread.addObserver(match, this);  
  4. }  


首先确保线程已经启动起来了,如果是第一次进来,肯定要启动线程了:

 

 

[cpp] view plaincopy
 
  1. private static final synchronized void ensureThreadStarted() {  
  2.     if (sThreadStarted == false) {  
  3.         sThread = new UEventThread();                                                                                                                        
  4.         sThread.start();  
  5.         sThreadStarted = true;  
  6.     }  
  7. }  


这个线程是单例模式,一个进程只启动一个就行了。

 

得到线程实例后,调用addObserver:

 

[cpp] view plaincopy
 
  1. public void addObserver(String match, UEventObserver observer) {  
  2.     synchronized(mObservers) {  
  3.         mObservers.add(match);  
  4.         mObservers.add(observer);  
  5.     }  
  6. }         


把路径和UEventObserver实例保存到ArrayList中,因为一个进程可能有多个UEventObserver实例的。

 

这时候uevent线程已经运行起来了:

 

[cpp] view plaincopy
 
  1. public void run() {  
  2.     native_setup();  
  3.   
  4.     byte[] buffer = new byte[1024];  
  5.     int len;  
  6.     while (true) {  
  7.         len = next_event(buffer);  
  8.         if (len > 0) {  
  9.             String bufferStr = new String(buffer, 0, len);  // easier to search a String  
  10.             synchronized (mObservers) {  
  11.                 for (int i = 0; i < mObservers.size(); i += 2) {  
  12.                     if (bufferStr.indexOf((String)mObservers.get(i)) != -1) {  
  13.                         ((UEventObserver)mObservers.get(i+1))  
  14.                                 .onUEvent(new UEvent(bufferStr));  
  15.                     }  
  16.                 }  
  17.             }  
  18.         }  
  19.     }  
  20. }  


native_setup和next_event是JNI方法,他们分别调用HAL层的uevent_init和uevent_next_event方法:

 

 

[cpp] view plaincopy
 
  1. int uevent_init()  
  2. {  
  3.     struct sockaddr_nl addr;  
  4.     int sz = 64*1024;  
  5.     int s;  
  6.   
  7.     memset(&addr, 0, sizeof(addr));  
  8.     addr.nl_family = AF_NETLINK;  
  9.     addr.nl_pid = getpid();  
  10.     addr.nl_groups = 0xffffffff;  
  11.   
  12.     s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);  
  13.     if(s < 0)  
  14.         return 0;  
  15.   
  16.     setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));  
  17.   
  18.     if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {  
  19.         close(s);  
  20.         return 0;  
  21.     }  
  22.   
  23.     fd = s;                                                                                                                                                      
  24.     return (fd > 0);  
  25. }  

 

[cpp] view plaincopy
 
  1. int uevent_next_event(char* buffer, int buffer_length)  
  2. {  
  3.     while (1) {  
  4.         struct pollfd fds;  
  5.         int nr;  
  6.   
  7.         fds.fd = fd;  
  8.         fds.events = POLLIN;  
  9.         fds.revents = 0;  
  10.         nr = poll(&fds, 1, -1);  
  11.   
  12.         if(nr > 0 && fds.revents == POLLIN) {  
  13.             int count = recv(fd, buffer, buffer_length, 0);  
  14.             if (count > 0) {  
  15.                 struct uevent_handler *h;  
  16.                 pthread_mutex_lock(&uevent_handler_list_lock);  
  17.                 LIST_FOREACH(h, &uevent_handler_list, list)  
  18.                     h->handler(h->handler_data, buffer, buffer_length);  
  19.                 pthread_mutex_unlock(&uevent_handler_list_lock);  
  20.   
  21.                 return count;  
  22.             }  
  23.         }  
  24.     }  
  25.   
  26.     // won't get here  
  27.     return 0;  
  28. }  

监听到内核有uevent消息后,调用recv,把数据放到buffer中,至于uevent_handler_list队列,是为空的,因为没有调用到uevent_add_native_handler函数。内核的uevent数据格式是怎样的呢,比如插入usb连接电脑时候收到的log:

 

 

[cpp] view plaincopy
 
  1. ACTION=change  
  2. DEVPATH=/devices/virtual/android_usb/android0  
  3. SUBSYSTEM=android_usb  
  4. USB_STATE=CONNECTED  
  5. SEQNUM=1249  
  6. change@/devices/virtual/android_usb/android0  
  7. ACTION=change  
  8. DEVPATH=/devices/virtual/android_usb/android0  
  9. SUBSYSTEM=android_usb  
  10. USB_STATE=CONNECTED  
  11. SEQNUM=1249  
  12. change@/devices/virtual/android_usb/android0  
  13. ACTION=change  
  14. DEVPATH=/devices/virtual/android_usb/android0  
  15. SUBSYSTEM=android_usb  
  16. USB_STATE=CONFIGURED  
  17. SEQNUM=1250  
  18. change@/devices/virtual/android_usb/android0  
  19. ACTION=change  
  20. DEVPATH=/devices/virtual/android_usb/android0  
  21. SUBSYSTEM=android_usb  
  22. USB_STATE=CONFIGURED  
  23. SEQNUM=1250  


framework的线程得到buffer数据后,用bufferStr.indexOf判断数据是否包含自己想要监控的路径,如果有,则回调onUEvent方法,并new一个自己的UEvent对象,把数据解析好,以便onUEvent更好更快的得到数据:

 

 

[cpp] view plaincopy
 
  1. static public class UEvent {  
  2.     // collection of key=value pairs parsed from the uevent message  
  3.     public HashMap<String,String> mMap = new HashMap<String,String>();  
  4.   
  5.     public UEvent(String message) {  
  6.         int offset = 0;  
  7.         int length = message.length();  
  8.   
  9.         while (offset < length) {  
  10.             int equals = message.indexOf('=', offset);  
  11.             int at = message.indexOf(0, offset);  
  12.             if (at < 0) break;  
  13.   
  14.             if (equals > offset && equals < at) {  
  15.                 // key is before the equals sign, and value is after  
  16.                 mMap.put(message.substring(offset, equals),  
  17.                         message.substring(equals + 1, at));  
  18.             }  
  19.   
  20.             offset = at + 1;  
  21.         }  
  22.     }  
  23.   
  24.     public String get(String key) {  
  25.         return mMap.get(key);  
  26.     }  
  27.   
  28.     public String get(String key, String defaultValue) {  
  29.         String result = mMap.get(key);  
  30.         return (result == null ? defaultValue : result);  
  31.     }  
  32.                                                                                                                                                              
  33.     public String toString() {  
  34.         return mMap.toString();  
  35.     }  
  36. }  


放到哈希表中的数据格式为:

 

[cpp] view plaincopy
 
  1. ACTION             change  
  2. DEVPATH          /devices/virtual/android_usb/android0  
  3. SUBSYSTEM    android_usb  
  4. USB_STATE      CONNECTED  
  5. SEQNUM          1249  
  6.   
  7. ACTION            change  
  8. DEVPATH         /devices/virtual/android_usb/android0  
  9. SUBSYSTEM    android_usb  
  10. USB_STATE     CONFIGURED  

这样根据索引很容易取出想要的数据。比如前面的onUEvent中:

event.get("USB_STATE")  得到CONNECT

event.get("ACCESSORY") 为空

结束~