android9.0 UsbService源码解析

Posted ……蓦然回首

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android9.0 UsbService源码解析相关的知识,希望对你有一定的参考价值。

文章目录


前言

USBManager作为一接口类,客户端,当然要有一个服务端来支持工作,这个服务就是UsbService。我这里先从他的启动开始分析,其主体还是按照Usb协议行事,所以了解了Usb协议之后,在看着里面的逻辑会豁然开朗。

来看这个服务罢,这里以MTP传输模式为例,因为这个比较常用。


一、服务启动

UsbService是一个系统服务,它在system_server进程中创建并注册的。

private static final String USB_SERVICE_CLASS =
        "com.android.server.usb.UsbService$Lifecycle";
             
private void startOtherServices() 
    // ...
     
    mSystemServiceManager.startService(USB_SERVICE_CLASS);
     
    // ...  

SystemServiceManager通过反射创建UsbService$Lifecycle对象(Lifecycle是UsbService的一个内部类),然后加入到List集合中,最后调用Lifcycle对象的onStart方法。

SystemServiceManager保存了各种服务,并且会把系统启动的各个阶段告诉服务,我们可以看看UsbService$Lifecycle的各种生命周期回调。

public class UsbService extends IUsbManager.Stub 
  
    public static class Lifecycle extends SystemService 
     
        // 服务创建阶段
        @Override
        public void onStart() 
             
            mUsbService = new UsbService(getContext());
            publishBinderService(Context.USB_SERVICE, mUsbService);
        
         
        // 响应系统启动阶段
        @Override
        public void onBootPhase(int phase) 
            if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) 
                // 系统就绪阶段
                mUsbService.systemReady();
             else if (phase == SystemService.PHASE_BOOT_COMPLETED) 
                // 系统启动完毕
                mUsbService.bootCompleted();
            
               
    

可以看到,一个服务会经过创建阶段,系统就绪阶段,系统启动完毕阶段。接下来,分为三部分来分析UsbService的启动过程。

二、服务创建

在服务创建阶段,首先创建了UsbService一个对象,由于UsbService是一个Binder对象,然后就把这个服务发布到ServiceManager。发布这个服务后,客户端就可以访问这个服务。

现在来看下UsbService的构造函数

public UsbService(Context context) 
    mContext = context;
 
    mUserManager = context.getSystemService(UserManager.class);
    mSettingsManager = new UsbSettingsManager(context);
    mAlsaManager = new UsbAlsaManager(context);
 
    final PackageManager pm = mContext.getPackageManager();
    if (pm.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) 
        mHostManager = new UsbHostManager(context, mAlsaManager, mSettingsManager);
    
    if (new File("/sys/class/android_usb").exists()) 
        mDeviceManager = new UsbDeviceManager(context, mAlsaManager, mSettingsManager);
    
    if (mHostManager != null || mDeviceManager != null) 
        mPortManager = new UsbPortManager(context);
    
 
    onSwitchUser(UserHandle.USER_SYSTEM);
 
    BroadcastReceiver receiver = new BroadcastReceiver() 
        @Override
        public void onReceive(Context context, Intent intent) 
            final String action = intent.getAction();
            if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
                    .equals(action)) 
                if (mDeviceManager != null) 
                    mDeviceManager.updateUserRestrictions();
                
            
        
    ;
 
    final IntentFilter filter = new IntentFilter();
    filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
    filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
    mContext.registerReceiver(receiver, filter, null, null);

在构造函数中,与MTP相关的主要代码就是创建UsbDeviceManager对象。

MTP模式下,Android设备是作为Device端,UsbDeviceManager就是用来处理Device端的事务。

现在来看下UsbDeviceManager的构造函数做了什么

public UsbDeviceManager(Context context, UsbAlsaManager alsaManager,
        UsbSettingsManager settingsManager) 
    mContext = context;
    mContentResolver = context.getContentResolver();
    PackageManager pm = mContext.getPackageManager();
    mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
    initRndisAddress();
 
    、、、
 
 
    //初始化mHandler
    if (halNotPresent) 
        /**
         * Initialze the legacy UsbHandler
         */
        mHandler = new UsbHandlerLegacy(FgThread.get().getLooper(), mContext, this,
                mDebuggingManager, alsaManager, settingsManager);
     else 
        /**
         * Initialize HAL based UsbHandler
         */
        mHandler = new UsbHandlerHal(FgThread.get().getLooper(), mContext, this,
                mDebuggingManager, alsaManager, settingsManager);
    
 
    if (nativeIsStartRequested()) 
        if (DEBUG) Slog.d(TAG, "accessory attached at boot");
        startAccessoryMode();
    
 
    //下面是注册各个广播
    BroadcastReceiver portReceiver = new BroadcastReceiver() 
        @Override
        public void onReceive(Context context, Intent intent) 
            UsbPort port = intent.getParcelableExtra(UsbManager.EXTRA_PORT);
            UsbPortStatus status = intent.getParcelableExtra(UsbManager.EXTRA_PORT_STATUS);
            mHandler.updateHostState(port, status);
        
    ;
 
    BroadcastReceiver chargingReceiver = new BroadcastReceiver() 
        @Override
        public void onReceive(Context context, Intent intent) 
            int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
            boolean usbCharging = chargePlug == BatteryManager.BATTERY_PLUGGED_USB;
            mHandler.sendMessage(MSG_UPDATE_CHARGING_STATE, usbCharging);
        
    ;
 
    BroadcastReceiver hostReceiver = new BroadcastReceiver() 
        @Override
        public void onReceive(Context context, Intent intent) 
            Iterator devices = ((UsbManager) context.getSystemService(Context.USB_SERVICE))
                    .getDeviceList().entrySet().iterator();
            if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) 
                mHandler.sendMessage(MSG_UPDATE_HOST_STATE, devices, true);
             else 
                mHandler.sendMessage(MSG_UPDATE_HOST_STATE, devices, false);
            
        
    ;
 
    BroadcastReceiver languageChangedReceiver = new BroadcastReceiver() 
        @Override
        public void onReceive(Context context, Intent intent) 
            mHandler.sendEmptyMessage(MSG_LOCALE_CHANGED);
        
    ;
 
    mContext.registerReceiver(portReceiver,
            new IntentFilter(UsbManager.ACTION_USB_PORT_CHANGED));
    mContext.registerReceiver(chargingReceiver,
            new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
 
    IntentFilter filter =
            new IntentFilter(UsbManager.ACTION_USB_DEVICE_ATTACHED);
    filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
    mContext.registerReceiver(hostReceiver, filter);
 
    mContext.registerReceiver(languageChangedReceiver,
            new IntentFilter(Intent.ACTION_LOCALE_CHANGED));
 
    //监听状态改变
    // Watch for USB configuration changes
    mUEventObserver = new UsbUEventObserver();
    mUEventObserver.startObserving(USB_STATE_MATCH);
    mUEventObserver.startObserving(ACCESSORY_START_MATCH);
 
    // register observer to listen for settings changes
    mContentResolver.registerContentObserver(
            Settings.Global.getUriFor(Settings.Global.ADB_ENABLED),
            false, new AdbSettingsObserver());

UsbDeviceManager的构造函数做了三件事。

第一件事,初始化mHandler对象。,mHandler的初始化使用的是UsbHandlerLegacy对象或者是UsbHandlerHal取决于是否有该模式的hal层支持。

第二事,注册了各种广播接收器,例如端口变化,语言变化,等等。这里我把关于充电的广播接收器代码展示出来了。当我们把手机通过USB线连接到电脑端的时候,手机会充电,并且手机上会出现一个关于USB充电的通知。打开这个关于USB的通知,我们就可以切换USB的功能,例如MTP, PTP,等等。

第三件事,通过Linux Uevent机制监听USB状态变换。当手机通过USB线连接电脑时,USB状态会从DISCONNECTED变为CONNECTED,再变为CONFIGURED。当状态改变会处理usb状态更新操作,这个过程在后面会分析到。

这里目前不看hal层,先来看看UsbHandlerLegacy对象的创建。

UsbHandlerLegacy(Looper looper, Context context, UsbDeviceManager deviceManager,
        UsbAlsaManager alsaManager, UsbSettingsManager settingsManager) 
    // 父类构造函数初始化了一些参数
    super(looper, context, deviceManager, alsaManager, settingsManager);
    try 
        // 1. 读取oem覆盖配置
        readOemUsbOverrideConfig(context);
         
        // 2. 读取各种属性的值
        // 2.1 正常模式,读取的是persist.sys.usb.config属性的值
        mCurrentOemFunctions = getSystemProperty(getPersistProp(false),
                UsbManager.USB_FUNCTION_NONE);
                 
        // ro.bootmode属性的值为normal或unknown,就表示正常启动
        if (isNormalBoot()) 
            // 2.2 读取sys.usb.config属性的值,这个属性表示当前设置的usb功能
            mCurrentFunctionsStr = getSystemProperty(USB_CONFIG_PROPERTY,
                    UsbManager.USB_FUNCTION_NONE);
            // 2.3 比较sys.usb.config属性与sys.usb.state属性的值
            // sys.usb.state属性表示usb的实际功能
            // 如果两个属性相等,表示usb设置的功能都起效了
            mCurrentFunctionsApplied = mCurrentFunctionsStr.equals(
                    getSystemProperty(USB_STATE_PROPERTY, UsbManager.USB_FUNCTION_NONE));
         else 
             mCurrentFunctionsStr = getSystemProperty(getPersistProp(true),
                    UsbManager.USB_FUNCTION_NONE);
             mCurrentFunctionsApplied = getSystemProperty(USB_CONFIG_PROPERTY,
                    UsbManager.USB_FUNCTION_NONE).equals(
                    getSystemProperty(USB_STATE_PROPERTY, UsbManager.USB_FUNCTION_NONE));
        
         
        // mCurrentFunctions代表当前要设置的usb功能,初始值为0
        mCurrentFunctions = UsbManager.FUNCTION_NONE;
        mCurrentUsbFunctionsReceived = true;
         
        // 3. 读取一次usb状态,然后做一次更新操作
        String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
        updateState(state);
     catch (Exception e) 
        Slog.e(TAG, "Error initializing UsbHandler", e);
    

UsbHandlerLegacy的构造函数大致分为三步。首先看第一步,读取oem厂商的关于usb功能的覆盖配置。

private void readOemUsbOverrideConfig(Context context) 
    // 数组每一项的格式为[bootmode]:[original USB mode]:[USB mode used]
    String[] configList = context.getResources().getStringArray(
            com.android.internal.R.array.config_oemUsbModeOverride);
 
    if (configList != null) 
        for (String config : configList) 
            String[] items = config.split(":");
            if (items.length == 3 || items.length == 4) 
                if (mOemModeMap == null) 
                    mOemModeMap = new HashMap<>();
                
                HashMap<String, Pair<String, String>> overrideMap =
                        mOemModeMap.get(items[0]);
                if (overrideMap == null) 
                    overrideMap = new HashMap<>();
                    mOemModeMap.put(items[0], overrideMap);
                
 
                // Favoring the first combination if duplicate exists
                if (!overrideMap.containsKey(items[1])) 
                    if (items.length == 3) 
                        overrideMap.put(items[1], new Pair<>(items[2], ""));
                     else 
                        overrideMap.put(items[1], new Pair<>(items[2], items[3]));
                    
                
            
        
    

读取的是config_oemUsbModeOverride数组,然后保存到mOemModeMap中。数组每一项的格式为[bootmode]:[original USB mode]:[USB mode used],保存的格式可以大致描述为HashMap<bootmode, HashMap<original_usb_mode, Pair<usb_mode_used, “”>。

然后第二步,读取了各种属性值(只考虑正常启动模式),如下。

  1. mCurrentOemFunctions的值是persist.sys.usb.config属性的值。按照源码注释,这个属性值存储了adb的开启状态(如果开启了adb,那么这个值会包含adb字符串)。另外,源码注释说这个属性也可以运营商定制的一些功能,但是只用于测试目的。

2.mCurrentFunctionsStr的值是sys.usb.config属性值。这个属性表示当前设置的usb功能的值。在日常工作中,我们可以通过adb shell命令设置这个属性值来切换usb功能,例如adb shell setprop sys.usb.config mtp,adb可以切换到mtp功能。

3.如果通过sys.usb.config属性切换功能成功,那么sys.usb.state属性值就与sys.usb.config属性值一样。也就是说sys.usb.state代表usb的实际功能的值。所以,可以通过比较这两个属性值来判断usb所有功能是否切换成功,如果成功了,mCurrentFunctionsApplied的值为1,否则为0。

第三步,读取了当前usb状态,并且做了一次更新操作。更新操作会发送相关通知,以及发送广播,但是现在处理服务创建阶段,这个操作都无法执行,因此这里不做分析。但是当处理系统就绪阶段或系统启动完毕阶段,就可以做相应的操作,在后面的分析中可以看到。

三、系统就绪

根据前面的代码,在系统就绪阶段,会调用UsbService的systemRead()方法,然后转到UsbDeviceManager的systemRead()方法

public void systemReady() 
    // 注册一个关于屏幕状态的回调,有两个方法
    LocalServices.getService(ActivityTaskManagerInternal.class).registerScreenObserver(this);
 
    mHandler.sendEmptyMessage(MSG_SYSTEM_READY);

首先注册了一个关于屏幕的回调,这个回调用于处理在安全锁屏下,设置usb的功能。但是这个功能好像处于开发阶段,只能通过adb shell命令操作,通过输入adb shell svc usb可以查看使用帮助。

接下来,发送了一个消息MSG_SYSTEM_READY,我们来看下这个消息是如何处理的

case MSG_SYSTEM_READY:
    // 获取到notification服务接口
    mNotificationManager = (NotificationManager)
            mContext.getSystemService(Context.NOTIFICATION_SERVICE);
 
    // 向adb service注册一个回调,用于状态adb相关的状态
    LocalServices.getService(
            AdbManagerInternal.class).registerTransport(new AdbTransport(this));
 
    // Ensure that the notification channels are set up
    if (isTv()) 
        // ...
    
    // 设置系统就绪的标志位
    mSystemReady = true;
    // 此时系统还没有启动完成,这里没有做任何事
    // 这应该是历史原因造成的代码冗余
    finishBoot();
    break;

四、系统启动完毕

现在来看下最后一个阶段,系统启动完毕阶段。根据前面的代码,会调用UsbService的bootcompleted()方法,然后调用UsbDeviceManager的bootcompleted()方法。

public void bootCompleted() 
    mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED);

只是发送了一条消息,看下消息如何处理的。

case MSG_BOOT_COMPLETED:
    // 设置系统启动完成的标志
    mBootCompleted = true;
    finishBoot();
    break;

很简单,设置了一个启动标志,然后就调用finishBoot()方法完成最后的任务

protected void finishBoot() 
    if (mBootCompleted && mCurrentUsbFunctionsReceived && mSystemReady) 
        // mPendingBootBroadcast是在服务创建阶段设置的
        if (mPendingBootBroadcast) 
            // 1. 发送/更新usb状态改变的广播
            updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions));
            mPendingBootBroadcast = false;
        
        if (!mScreenLocked
                && mScreenUnlockedFunctions != UsbManager.FUNCTION_NONE) 
            // 这个功能还是处于调试阶段,不分析
            setScreenUnlockedFunctions();
         else 
            // 2. 设置USB功能为NONE
            setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
        
        // 关于Accessory功能
        if (mCurrentAccessory != null) 
            mUsbDeviceManager.getCurrentSettings().accessoryAttached(mCurrentAccessory);
        
         
        //这个应该是debug调试时会用到的adb相关的功能。
        if (mDebuggingManager != null) 
            mDebuggingManager.setAdbEnabled(mAdbEnabled);
        
 
        //确保设置值与当前状态值匹配,对于adb。
        // make sure the ADB_ENABLED setting value matches the current state
        try 
            putGlobalSettings(mContentResolver, Settings.Global.ADB_ENABLED,
                    mAdbEnabled ? 1 : 0);
         catch (SecurityException e) 
            // If UserManager.DISALLOW_DEBUGGING_FEATURES is on, that this setting can't
            // be changed.
            Slog.d(TAG, "ADB_ENABLED is restricted.");
        
        // 3. 如果手机已经连接电脑就发送usb通知,通过这个通知,可以选择usb模式
        updateUsbNotification(false);
        // 4. 如果adb已经开启,并且手机已经连接电脑,就发送adb通知
        updateAdbNotification(false);
        // 关于MIDI功能
        updateUsbFunctions();
    

如果现在手机没有通过USB线连接电脑,那么第一步的发送USB状态广播,第三步的USB通知,第四步adb通知,都无法执行。唯一能执行的就是第二步,设置USB功能为NONE。

OK,现在终于到最关键的一步,设置USB功能,它调用的是setEnabledFunctions()方法。这个方法本身是一想抽象方法,在我的项目中,实现类为UsbHandlerLegacy。

protected void setEnabledFunctions(long usbFunctions, boolean forceRestart) 
    // 判断数据是否解锁,只有MTP和PTP的数据是解锁的
    boolean usbDataUnlocked = isUsbDataTransferActive(usbFunctions);
     
    // 处理数据解锁状态改变的情况
    if (usbDataUnlocked != mUsbDataUnlocked) 
        // 更新数据解锁状态
        mUsbDataUnlocked = usbDataUnlocked;
        // 更新usb通知
        updateUsbNotification(false);
        // forceRestart设置为true,表示需要强制重启usb功能
        forceRestart = true;
    
     
    // 在设置新usb功能前,先保存旧的状态,以免设置新功能失败,还可以恢复
    final long oldFunctions = mCurrentFunctions;
    final boolean oldFunctionsApplied = mCurrentFunctionsApplied;
     
    // 尝试设置usb新功能
    if (trySetEnabledFunctions(usbFunctions, forceRestart)) 
        return;
    
 
    // 如果到这里,就表示新功能设置失败,那么就回退之前的状态
    if (oldFunctionsApplied && oldFunctions != usbFunctions) 以上是关于android9.0 UsbService源码解析的主要内容,如果未能解决你的问题,请参考以下文章

android9.0 UsbService源码解析

android9.0 UsbManager源码解析

android9.0 UsbManager源码解析

android9.0 UsbManager源码解析

Android9.0源码学习-Sensor Framework

高通Android9.0源码兼容不同项目编译环境