android UEventObserver的用法

    在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
 change@/devices/virtual/android_usb/android0
 ACTION=change
 DEVPATH=/devices/virtual/android_usb/android0
 SUBSYSTEM=android_usb
 USB_STATE=CONNECTED
 SEQNUM=1249
 change@/devices/virtual/android_usb/android0
 ACTION=change
 DEVPATH=/devices/virtual/android_usb/android0
 SUBSYSTEM=android_usb
 USB_STATE=CONFIGURED
 SEQNUM=1250
 change@/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             change
DEVPATH          /devices/virtual/android_usb/android0
SUBSYSTEM    android_usb
USB_STATE      CONNECTED
SEQNUM          1249

ACTION            change
DEVPATH         /devices/virtual/android_usb/android0
SUBSYSTEM    android_usb
USB_STATE     CONFIGURED

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

event.get("USB_STATE")  得到CONNECT

event.get("ACCESSORY") 为空

结束~




















你可能感兴趣的:(android UEventObserver的用法)