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;
private EventThread eventThread;
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;
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;
}
}
}
return 0;
}
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;
}