您的位置:首页 > 移动开发 > Android开发

Android USB相关流程解析(android4.4)

2014-12-24 15:08 134 查看
前言:

对于USB的一些常量属性,比如:UsbManager.
USB_FUNCTION_RNDIS(USB的模式)等,现在也是一个比较模糊的概念,只能具体问题具体分析,我们重点说的是类结构,与USB整个框架(仅限于framework层)的逻辑。本来想画一张流程图呢。画来画去好像都跟实际情况有出入。就只能用文字叙述了。

一、调用:

我们从最常见与USB相关的界面说起。当手机连接电脑时,有如下界面:



这个界面是设置里面的一个界面,源码就不贴了,核心代码

获取 UsbManager类的对象:

mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);


切换USB连接的模式。比如上图中的,把USB设置为仅充电:

function = UsbManager.USB_FUNCTION_CHARGE_ONLY;
mUsbManager.setCurrentFunction(function, true);


(在android系统源码中的路径:\frameworks\base\core\java\android\hardware\usb\UsbManager.java)
下面我们就围绕这两行代码进行分析。

二、UsbManager 如何获得的

1、首先,android 启动的时候会加载SystemServer.java(路径:\frameworks\base\services\java\com\android\server\SystemServer.java),在SystemServer 类中,调用

initAndLoop()方法加载各种服务,USB相关的核心代码

public void initAndLoop() {
 ......
               UsbService usb = null;
 ......
                try {
                    Slog.i(TAG, "USB Service");
                    // Manage USB host and device support
                    usb = new UsbService(context);
                    ServiceManager.addService(Context.USB_SERVICE, usb);
                } catch (Throwable e) {
                    reportWtf("starting UsbService", e);
                }

.....
}
可以看到SystemServer类中加载的USB相关的服务是 UsbServeice (路径:\frameworks\base\services\java\com\android\server\usb\UsbService.java)

我们这里记着:SystemServer类 中在initAndLoop()方法中,把UsbServeice 加到了 ServiceManager中。

2、其次,我们看ContextImpl.java (路径:\frameworks\base\core\java\android\app\ContextImpl.java

static{
...
        registerService(USB_SERVICE, new ServiceFetcher() {
                public Object createService(ContextImpl ctx) {
                    IBinder b = ServiceManager.getService(USB_SERVICE);
                    return new UsbManager(ctx, IUsbManager.Stub.asInterface(b));
                }});
...
}


registerService()方法的代码:

private static void registerService(String serviceName, ServiceFetcher fetcher) {
        if (!(fetcher instanceof StaticServiceFetcher)) {
            fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
        }
        SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
    }
SYSTEM_SERVICE_MAP 对象

private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP =
            new HashMap<String, ServiceFetcher>();


由上我们看到,ContextImpl 类中有一个static 块,从ServiceManager 把usbService取出来,然后注册到ContextImpl类中,其实是放到你个HashMap中。

我们在上文“调用”中执行的代码,

mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
这句是在Activity中调用的,而Activity中都有一个关联的ContextImpl 对象,ContextImpl 是对Context的实现类,当在Activity中调用getSystemService(),其实调用的就是ContextImpl类中的getSystemService()。 这个ContextImpl 与Activity的关系我就不说了,可以看下源码,或者网上搜索,比如 http://www.cnblogs.com/android100/p/Android-Context.html 中就有相关的说明。

我们看下ContextImpl类中的getSystemService()

@Override
    public Object getSystemService(String name) {
        ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
        return fetcher == null ? null : fetcher.getService(this);
    }


好吧,其实就是从HashMap中把UsbManager取出来了。

三、UsbManager 的使用

我们先分析下整个USB的类结构了。
首先,我们来一个大体的概念。UsbManager类里面引用了一个UsbService的对象,而UsbService里面又引用了UsbDeviceManager与UsbHostManager的对象,而UsbDeviceManager与UsbHostManager中又分别引用了UsbSettingsManager的对象,而UsbDeviceManager中又引用了UsbDebuggingManager类的对象。大体情况如下图:



这里所说的类的路径都在android 系统源码\frameworks\base\services\java\com\android\server\usb 目录下。

这里插一句:USB分两种模式(这里所说的模式是针对于手机与其所连接的设备所扮演的角色,而我们通篇说的模式是USB选择的功能,如仅充电,PTP,MTP,大容量存储)

usb host 模式:举一例,手机插上键盘之类的外设,手机充当host角色,而UsbHostManager就是跟这个模式相关的,来管理外接设备。

usb Accessory模式:举一例,手机连上电脑,电脑充当host角色,手机是电脑的附件。而UsbDeviceManager就是跟这个模式相关的。而我们通篇都是针对于这种模式来讲解的。

从上图,我们可以清晰的看出类之间的引用关系,接着我回到我们的主题

我们在上文“调用”中执行的代码,

function = UsbManager.USB_FUNCTION_CHARGE_ONLY;
mUsbManager.setCurrentFunction(function, true);
是设置USB为仅充电模式。那么这句调用是如何执行的呢。先看setCurrentFunction()方法
public void setCurrentFunction(String function, boolean makeDefault) {
        try {
            mService.setCurrentFunction(function, makeDefault);
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in setCurrentFunction", e);
        }
    }


这里面的mService就是UsbService的对象,看下UsbService中的setCurrentFunction()方法

@Override
    public void setCurrentFunction(String function, boolean makeDefault) {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
        if (mDeviceManager != null) {
            mDeviceManager.setCurrentFunctions(function, makeDefault);
        } else {
            throw new IllegalStateException("USB device mode not supported");
        }
    }


private UsbDeviceManager mDeviceManager;


其实调用的是UsbDeviceManager 中的setCurrentFunctions()方法

public void setCurrentFunctions(String functions, boolean makeDefault) {
        if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ") default: " + makeDefault);
        mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions, makeDefault);
    }


这里又通过handler机制发送MSG_SET_CURRENT_FUNCTIONS 消息来处理的。我们看下这个消息的处理

@Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                ......
                case MSG_SET_CURRENT_FUNCTIONS:
                    String functions = (String)msg.obj;
                    boolean makeDefault = (msg.arg1 == 1);
                    setEnabledFunctions(functions, makeDefault);
                    break;
    
            }
        }


setEnabledFunctions()方法:

private void setEnabledFunctions(String functions, boolean makeDefault) {
            if (DEBUG) Slog.d(TAG, "setEnabledFunctions " + functions
                    + " makeDefault: " + makeDefault);

            // Do not update persystent.sys.usb.config if the device is booted up
            // with OEM specific mode.
            if (functions != null && makeDefault && !needsOemUsbOverride()) {

                if (mAdbEnabled) {
                    functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
                } else {
                    functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB);
                }
                if (!mDefaultFunctions.equals(functions)) {
                    mInUsbSetting = true;
                    if (!setUsbConfig("none")) {
                        Slog.e(TAG, "Failed to disable USB");
                        // revert to previous configuration if we fail
                        setUsbConfig(mCurrentFunctions);
                        mInUsbSetting = false;
                        return;
                    }
                    // setting this property will also change the current USB state
                    // via a property trigger
                    SystemProperties.set("persist.sys.usb.config", functions);
                    if (waitForState(functions)) {
                        mCurrentFunctions = functions;
                        mDefaultFunctions = functions;
                    } else {
                        Slog.e(TAG, "Failed to switch persistent USB config to " + functions);
                        // revert to previous configuration if we fail
                        SystemProperties.set("persist.sys.usb.config", mDefaultFunctions);
                    }
                    mInUsbSetting = false;
                }
            } else {
                boolean rndisTetherSetting = UsbManager.USB_FUNCTION_RNDIS.equals(functions);
                if (functions == null) {
                    functions = mDefaultFunctions;
                }

                // Override with bootmode specific usb mode if needed
                functions = processOemUsbOverride(functions);

                if (mAdbEnabled) {
                    functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
                } else {
                    functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB);
                }
                if (!mCurrentFunctions.equals(functions) || rndisTetherSetting) {
                    if (rndisTetherSetting && containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_RNDIS)) {
                        functions = mCurrentFunctions;
                    }
                    mInUsbSetting = true;
                    if (!setUsbConfig("none")) {
                        Slog.e(TAG, "Failed to disable USB");
                        // revert to previous configuration if we fail
                        setUsbConfig(mCurrentFunctions);
                        mInUsbSetting = false;
                        return;
                    }
                    if (setUsbConfig(functions)) {
                        mCurrentFunctions = functions;
                    } else {
                        Slog.e(TAG, "Failed to switch USB config to " + functions);
                        // revert to previous configuration if we fail
                        setUsbConfig(mCurrentFunctions);
                    }
                    mInUsbSetting = false;
                }
            }
我们看下三个判断条件:

functions != null:设置的USB功能不为空;而当传如的参数为null的话,就是恢复默认功能。

makeDefault:“如果函数应设置为新的默认功能,makeDefault为true。“根据以上代码,当makeDefault为true的时候,会把mDefaultFunctions这个全局变量改为你这次的设置,这个全局变量的作用是,而当你断开连接时,或者传入参数functions为null的情况下,会用这个全局变量来设置USB功能。

needsOemUsbOverride():是否用厂商的属性覆盖。

知道了这三个判断条件,就能很清楚的看到其实执行到这里,就是把functions 写入到了系统属性中,推测kernel会监听这个属性,来改变USB功能。
....
SystemProperties.set("persist.sys.usb.config", functions);
.....


private boolean setUsbConfig(String config) {
            if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")");
            // set the new configuration
            SystemProperties.set("sys.usb.config", config);
            return waitForState(config);
        }
好了,从应用层调用,一直追溯到这里,就知道了USB是模式切换是怎么实现的了,其实就是到最后,就是把要设置USB当前的模式写入到系统属性文件中。

四、USB查上电脑或者断开,上层会做些什么。

核心的类就是UsbDeviceManager类了。当插上或者断开USB的时候,这个类会监听底层上报的事件,然后上层根据这个事件来做一系列的动作。至于如何监听的,就是UEventObserver类了,UEventObserver是androidJava层利用uevent与获取Kernel层状态变化的机制,这里我们可以看到使用前必须先初始化一个新的UEventObserver类来处理事件,实现函数onUEvent,这是一个回调函数,之后我们会看到他是怎么被调用的

上代码:

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();
            }
        }
    };


private final class UsbHandler extends Handler {
 ......
      public UsbHandler(Looper looper) {
            super(looper);
            try {
               .....
                mUEventObserver.startObserving(USB_STATE_MATCH);
                mUEventObserver.startObserving(ACCESSORY_START_MATCH);
              .....
            } catch (Exception e) {
                Slog.e(TAG, "Error initializing UsbHandler", e);
            }
        }
}
UsbHandler 是UsbDeviceManager中的一个内部类,设置一个UEventObserver监听Usb连接断开的状态,然后通过Handler机制来让上层做一系列的动作,如:弹出通知栏(Notification),或者发送UsbManager.ACTION_USB_STATE 的广播等。

接着就要说UEventObserver机制了,上述代码中:

1、调用startObserving()启动,传入的参数是标记事件的,就是一个Key。

mUEventObserver.startObserving(USB_STATE_MATCH);
                mUEventObserver.startObserving(ACCESSORY_START_MATCH);
2、UEventObserver类中的startObserving()方法

public final void startObserving(String match) {
        if (match == null || match.isEmpty()) {
            throw new IllegalArgumentException("match substring must be non-empty");
        }

        final UEventThread t = getThread();
        t.addObserver(match, this);
    }
3、getThread()方法

private static UEventThread getThread() {
        synchronized (UEventObserver.class) {
            if (sThread == null) {
                sThread = new UEventThread();
                sThread.start();
            }
            return sThread;
        }
    }


4、上面getThread就是new了一个UEventThread 对象。看一下UEventThread

private static final class UEventThread extends Thread {
        private final ArrayList<Object> mKeysAndObservers = new ArrayList<Object>();

        private final ArrayList<UEventObserver> mTempObserversToSignal =
                new ArrayList<UEventObserver>();

        public UEventThread() {
            super("UEventObserver");
        }

        @Override
        public void run() {
            nativeSetup();

            while (true) {
                String message = nativeWaitForNextEvent();
                if (message != null) {
                    if (DEBUG) {
                        Log.d(TAG, message);
                    }
                    sendEvent(message);
                }
            }
        }

        private void sendEvent(String message) {
            synchronized (mKeysAndObservers) {
                final int N = mKeysAndObservers.size();
                for (int i = 0; i < N; i += 2) {
                    final String key = (String)mKeysAndObservers.get(i);
                    if (message.contains(key)) {
                        final UEventObserver observer =
                                (UEventObserver)mKeysAndObservers.get(i + 1);
                        mTempObserversToSignal.add(observer);
                    }
                }
            }

            if (!mTempObserversToSignal.isEmpty()) {
                final UEvent event = new UEvent(message);
                final int N = mTempObserversToSignal.size();
                for (int i = 0; i < N; i++) {
                    final UEventObserver observer = mTempObserversToSignal.get(i);
                    observer.onUEvent(event);
                }
                mTempObserversToSignal.clear();
            }
        }

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

        /** Removes every key/value pair where value=observer from mObservers */
        public void removeObserver(UEventObserver observer) {
            synchronized (mKeysAndObservers) {
                for (int i = 0; i < mKeysAndObservers.size(); ) {
                    if (mKeysAndObservers.get(i + 1) == observer) {
                        mKeysAndObservers.remove(i + 1);
                        final String match = (String)mKeysAndObservers.remove(i);
                        nativeRemoveMatch(match);
                    } else {
                        i += 2;
                    }
                }
            }
        }
    }


分析第1、2步,首先获取UEventThread的一个对象,然后启动,之后调用addObserver()把键值对放入一个集合中。线程启动当然是执行Run()方法了,Run()方法中是一个死循环来等待消息,然后调用 sendEvent(message)发送出去,这个发送就是回调onUEvent(UEvent event)。就是mUEventObserver实现的方法。

Run()方法,调用了两个native方法(JNI),我们来分析一下:

nativeSetup();
  nativeWaitForNextEvent();
UEventObserver中所有的JNI调用的方法所在的文件是android_os_UEventObserver.cpp

路径:\frameworks\base\core\jni\android_os_UEventObserver.cpp

static void nativeSetup(JNIEnv *env, jclass clazz) {
    if (!uevent_init()) {
        jniThrowException(env, "java/lang/RuntimeException",
                "Unable to open socket for UEventObserver");
    }
}


static jstring nativeWaitForNextEvent(JNIEnv *env, jclass clazz) {
    char buffer[1024];

    for (;;) {
        int length = uevent_next_event(buffer, sizeof(buffer) - 1);
        if (length <= 0) {
            return NULL;
        }
        buffer[length] = '\0';

        ALOGV("Received uevent message: %s", buffer);

        if (isMatch(buffer, length)) {
            // Assume the message is ASCII.
            jchar message[length];
            for (int i = 0; i < length; i++) {
                message[i] = buffer[i];
            }
            return env->NewString(message, length);
        }
    }
}


看到这两个JNI方法的调用,很明显的看出来,nativeSetup();主要调用的是uevent_init() ;而nativeWaitForNextEvent()主要调用的是uevent_next_event()方法,这两个方法是在在uevent.c 中,android_os_UEventObserver.cpp是通过#include "hardware_legacy/uevent.h" 来载入的。路径:\hardware\libhardware_legacy\uevent\uevent.c

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);
}
会创建一个socket ,定义内核事件向用户态通知(NETLINK_KOBJECT_UEVENT),返回返回一个fd

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;
}


是用Linux poll 机制,等待事件的通知,有数据来的话接收到buffer里,然后返回。(到这一层我已经有些说不明白了,如果说错的话,请指正。)

总结一下:底层通过Poll与socket获取消息,然后到上层android_os_UEventObserver.cpp 类中,然后到UEventObserver中,UEventObserver回调UsbDeviceManager类中mUEventObserver实现的函数onUEvent,然后上层做处理,无论是发通知,或者发广播。

5、编译android源码默认开启USB调试模式

当android源码编译时,会执行\build\tools\post_process_props.py (Python语言)文件来配置属性,有一段代码是这样的:

if prop.get("ro.debuggable") == "1":
    val = prop.get("persist.sys.usb.config")
    if val == "":
      val = "adb"
    else:
      val = val + ",adb"
    prop.put("persist.sys.usb.config", val)
如果ro.debuggable 值为1的话,就在属性里增加adb,就是开启USB调试模式

所以,你可以在你的属性配置文件里配置这个属性为1就行了。

比如我的配置文件prod_xxxxxx.mk中

#Add for adb debug open 
PRODUCT_PROPERTY_OVERRIDES += \
    ro.debuggable=1


到此,USB相关的逻辑部分就分析到这里。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: