Android NDK——監聽USB的連接與斷開

Mainctivity:主界面,功能是把監聽到的USB事件用Toast顯示出來
package com.wind.usb;

import com.wind.usb.UsbManager.OnUsbListener;
import com.wind.usb.UsbManager.UsbEvent;

import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends Activity {
    private UsbManager usbManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        usbManager = new UsbManager(usbListener);
        usbManager.startService();
    }

    private OnUsbListener usbListener = new OnUsbListener() {

        @Override
        public void onMessage(final String msg) {
            runOnUiThread(new Runnable() {

                @Override
                public void run() {
                    showToast(msg);
                }
            });
        }

        @Override
        public void onEven(UsbEvent even) {

        }
    };

    private void showToast(String msg) {
        Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
    }

    @Override
    protected void onDestroy() {
        usbManager.stopService();
        super.onDestroy();
    }
}
UsbManager:監聽USB事件的Java類,通過native方法與C層交互,實現監聽功能
package com.wind.usb;

public class UsbManager {
    private boolean isEventThreadStart = false;
    private OnUsbListener usbListener; //usb事件通知接口
    private EventThread eventThread; //usb事件監聽線程

    public UsbManager(OnUsbListener listener) {
        usbListener = listener;
    }

    /**
     * 開始監聽服務
     */
    public synchronized void  startService() {
        if(!isEventThreadStart) {
            eventThread = new EventThread();
            eventThread.start();
            isEventThreadStart = true;
        }
    }

    /**
     * 結束監聽服務
     */
    public synchronized void stopService() {
        eventThread.finish();
        isEventThreadStart = false;
    }

    /**
     * 本地方法,初始化監聽
     */
    private static native void nativeSetup();

    /**
     * 本地方法,監聽下一個usb事件
     * @param buffer
     * @return
     */
    private static native int nativeNext(byte[] buffer);

    static {
        System.loadLibrary("usb");
    }

    /**
     * usb狀態
     * 
     * @author Administrator
     *
     */
    public enum UsbEvent {
        CONNECT, DISCONNECT;
    }

    /**
     * usb狀態通知接口
     * 
     * @author Administrator
     *
     */
    public interface OnUsbListener {
        public void onEven(UsbEvent even);
        public void onMessage(String msg);
    }

    /**
     * usb監聽線程
     * 
     * @author Administrator
     *
     */
    private class EventThread extends Thread {
        private static final String USB_STATE_MATCH = "DEVPATH=/devices/virtual/android_usb/android0";

        private boolean runFlag = true;

        @Override
        public void run() {
            int len;
            byte[] buffer = new byte[1024];

            nativeSetup();
            while(runFlag) {
                len = nativeNext(buffer);
                if(len > 0) {
                    String msg = new String(buffer, 0, len);
                    if(msg.contains(USB_STATE_MATCH)) {
                        usbListener.onMessage(msg);
                    }
                }
            }
        }

        public void finish() {
            runFlag = false;
        }
    }
}
usb.cpp:USB事件監聽的核心邏輯所在,通過socket獲取usb事件,返回給Java層
#include <jni.h>

#include <string.h>
#include <unistd.h>
#include <poll.h>
#include <pthread.h>

#include <sys/socket.h>
#include <sys/un.h>
#include <sys/queue.h>
#include <linux/netlink.h>

LIST_HEAD(uevent_handler_head, uevent_handler) uevent_handler_list;
pthread_mutex_t uevent_handler_list_lock = PTHREAD_MUTEX_INITIALIZER;

struct uevent_handler {
    void (*handler)(void *data, const char *msg, int msg_len);
    void *handler_data;
    LIST_ENTRY(uevent_handler) list;
};

static int fd = -1;

//uevent初始化
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);
}

//初始化
void setup(JNIEnv* evn, jclass cls)
{
    if (!uevent_init()) {
        jclass c = evn->FindClass("java/lang/RuntimeException");
        evn->ThrowNew(c, "Unable to open socket for UEventObserver");
    }
}

//獲取下一次事件
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;
}

//獲取下一次事件並返回給java環境
jint next(JNIEnv* evn, jclass cls, jbyteArray jbuffer)
{
    int buf_sz = evn->GetArrayLength(jbuffer);
    char *buffer = (char*)evn->GetByteArrayElements(jbuffer, NULL);

    int length = uevent_next_event(buffer, buf_sz - 1);

    evn->ReleaseByteArrayElements(jbuffer, (jbyte*)buffer, 0);

    return length;
}

static JNINativeMethod methods[] = {
    {"nativeSetup", "()V", (void*)setup},
    {"nativeNext", "([B)I", (void*)next},
};

static bool registerNativeMethods(JNIEnv* evn) 
{
    jclass cls = evn->FindClass("com/wind/usb/UsbManager");
    if(cls == NULL) {
        return false;
    }

    int number = sizeof(methods) / sizeof(methods[0]);
    if(evn->RegisterNatives(cls, methods, number) < 0 ) {
        return false;
    }
    return true;
}

jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    JNIEnv* evn = NULL;
    if(vm->GetEnv((void**)&evn, JNI_VERSION_1_6)) {
        return -1;
    }

    if(!registerNativeMethods(evn)) {
        return -1;
    }

    return JNI_VERSION_1_6;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章