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

首先,创建一个UEventObserver类:

    private final UEventObserver mUEventObserver = new UEventObserver() {                                                                                              @Override        public void onUEvent(UEventObserver.UEvent event) {            if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString());            String state = event.get("USB_STATE");            String accessory = event.get("ACCESSORY");            if (state != null) {                mHandler.updateState(state);            } else if ("START".equals(accessory)) {                if (DEBUG) Slog.d(TAG, "got accessory start");                startAccessoryMode();            }        }    };
在这个类中要重写onUevent方法,在该方法中处理你得到的事件。

接着,调用startObserving方法即可:

                mUEventObserver.startObserving(USB_STATE_MATCH);                                                                                                               mUEventObserver.startObserving(ACCESSORY_START_MATCH);

这里:

    private static final String USB_STATE_MATCH =                                                                                                                          "DEVPATH=/devices/virtual/android_usb/android0";    private static final String ACCESSORY_START_MATCH =                                                                                                                    "DEVPATH=/devices/virtual/misc/usb_accessory";

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

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

先看startObserving方法:

    public final synchronized void startObserving(String match) {        ensureThreadStarted();        sThread.addObserver(match, this);    }

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

    private static final synchronized void ensureThreadStarted() {        if (sThreadStarted == false) {            sThread = new UEventThread();                                                                                                                                  sThread.start();            sThreadStarted = true;        }    }

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

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

        public void addObserver(String match, UEventObserver observer) {            synchronized(mObservers) {                mObservers.add(match);                mObservers.add(observer);            }        }       

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

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

        public void run() {            native_setup();            byte[] buffer = new byte[1024];            int len;            while (true) {                len = next_event(buffer);                if (len > 0) {                    String bufferStr = new String(buffer, 0, len);  // easier to search a String                    synchronized (mObservers) {                        for (int i = 0; i < mObservers.size(); i += 2) {                            if (bufferStr.indexOf((String)mObservers.get(i)) != -1) {                                ((UEventObserver)mObservers.get(i+1))                                        .onUEvent(new UEvent(bufferStr));                            }                        }                    }                }            }        }

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

int uevent_init(){    struct sockaddr_nl addr;    int sz = 64*1024;    int s;    memset(&addr, 0, sizeof(addr));    addr.nl_family = AF_NETLINK;    addr.nl_pid = getpid();    addr.nl_groups = 0xffffffff;    s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);    if(s < 0)        return 0;    setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {        close(s);        return 0;    }    fd = s;                                                                                                                                                        return (fd > 0);}

int uevent_next_event(char* buffer, int buffer_length){    while (1) {        struct pollfd fds;        int nr;        fds.fd = fd;        fds.events = POLLIN;        fds.revents = 0;        nr = poll(&fds, 1, -1);        if(nr > 0 && fds.revents == POLLIN) {            int count = recv(fd, buffer, buffer_length, 0);            if (count > 0) {                struct uevent_handler *h;                pthread_mutex_lock(&uevent_handler_list_lock);                LIST_FOREACH(h, &uevent_handler_list, list)                    h->handler(h->handler_data, buffer, buffer_length);                pthread_mutex_unlock(&uevent_handler_list_lock);                return count;            }        }    }    // won't get here    return 0;}
监听到内核有uevent消息后,调用recv,把数据放到buffer中,至于uevent_handler_list队列,是为空的,因为没有调用到uevent_add_native_handler函数。内核的uevent数据格式是怎样的呢,比如插入usb连接电脑时候收到的log:

 ACTION=change DEVPATH=/devices/virtual/android_usb/android0 SUBSYSTEM=android_usb USB_STATE=CONNECTED SEQNUM=1249 [email protected]/devices/virtual/android_usb/android0 ACTION=change DEVPATH=/devices/virtual/android_usb/android0 SUBSYSTEM=android_usb USB_STATE=CONNECTED SEQNUM=1249 [email protected]/devices/virtual/android_usb/android0 ACTION=change DEVPATH=/devices/virtual/android_usb/android0 SUBSYSTEM=android_usb USB_STATE=CONFIGURED SEQNUM=1250 [email protected]/devices/virtual/android_usb/android0 ACTION=change DEVPATH=/devices/virtual/android_usb/android0 SUBSYSTEM=android_usb USB_STATE=CONFIGURED SEQNUM=1250

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

    static public class UEvent {        // collection of key=value pairs parsed from the uevent message        public HashMap<String,String> mMap = new HashMap<String,String>();        public UEvent(String message) {            int offset = 0;            int length = message.length();            while (offset < length) {                int equals = message.indexOf('=', offset);                int at = message.indexOf(0, offset);                if (at < 0) break;                if (equals > offset && equals < at) {                    // key is before the equals sign, and value is after                    mMap.put(message.substring(offset, equals),                            message.substring(equals + 1, at));                }                offset = at + 1;            }        }        public String get(String key) {            return mMap.get(key);        }        public String get(String key, String defaultValue) {            String result = mMap.get(key);            return (result == null ? defaultValue : result);        }                                                                                                                                                                       public String toString() {            return mMap.toString();        }    }

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

ACTION             changeDEVPATH          /devices/virtual/android_usb/android0SUBSYSTEM    android_usbUSB_STATE      CONNECTEDSEQNUM          1249ACTION            changeDEVPATH         /devices/virtual/android_usb/android0SUBSYSTEM    android_usbUSB_STATE     CONFIGURED

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

event.get("USB_STATE") 得到CONNECT

event.get("ACCESSORY") 为空

结束~




















更多相关文章

  1. 谈谈 View 绘制流程
  2. android很的意思的事情,关于Input…
  3. Android(安卓)面试整理
  4. Android音视频处理之MediaExtractor
  5. Ubuntu 编译Android若干错误及解决方法(转)
  6. Android(安卓)MediaPlayer基本使用方式
  7. [Android] IntentInjector
  8. Android中结合OrmLite for android组件对SQLite的CRUD(增删改查)
  9. Android(安卓)读取内存文件返回byte数组

随机推荐

  1. android surfaceview里onTouchEvent 画图
  2. 绑定服务后台播放音频的简单示例
  3. 常用命令(Linux、Android、adb)
  4. 新浪微博开放平台开发-android客户端(1)
  5. android设备中的临时文件夹在哪里?
  6. Android程序自动化打包
  7. Android 相关 - R无法引用
  8. 使用Android调用SOAP Webservice时连接被
  9. 2015年年终总结--迷茫中前进
  10. 这些片段在Android编程中很有用