赞
踩
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, “”>。
然后第二步,读取了各种属性值(只考虑正常启动模式),如下。
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) { Slog.e(TAG, "Failsafe 1: Restoring previous USB functions."); if (trySetEnabledFunctions(oldFunctions, false)) { return; } } // 如果回退还是失败了,那么就设置usb功能为NONE if (trySetEnabledFunctions(UsbManager.FUNCTION_NONE, false)) { return; } // 如果设置NONE还是失败了,那么再试一次设置NONE if (trySetEnabledFunctions(UsbManager.FUNCTION_NONE, false)) { return; } // 如果走到这里,就表示异常了。 Slog.e(TAG, "Unable to set any USB functions!"); }
首先判断要设置的新的USB功能的数据是否是解锁状态,只有MTP和PTP模式的数据是解锁状态,这是为何你能在设置MTP或PTP模式后,在PC端能看到手机中的文件,然而这个文件只是手机内存中文件的映射,并不是文件本身。
然后处理数据解锁状态改变的情况,如果是,那么会更新状态,更新usb广播,然后最重要的是设置forceRestart变量的值为true,这个变量代表要强制重启usb功能。
最后,设置新usb功能。如果失败了,就回退。
现在来看下trySetEnabledFunctions()方法如何设置新功能。
private boolean trySetEnabledFunctions(long usbFunctions, boolean forceRestart) { // 1. 把新usb功能转化为字符串 String functions = null; // 如果新功能不是NONE,就转化 if (usbFunctions != UsbManager.FUNCTION_NONE) { functions = UsbManager.usbFunctionsToString(usbFunctions); } // 保存待设置的新usb功能 mCurrentFunctions = usbFunctions; // 如果转化后的功能为空,那么就从其它地方获取 if (functions == null || applyAdbFunction(functions) .equals(UsbManager.USB_FUNCTION_NONE)) { // 获取persist.sys.usb.config属性值 functions = getSystemProperty(getPersistProp(true), UsbManager.USB_FUNCTION_NONE); // 如果persist.sys.usb.config属性值还是为NONE if (functions.equals(UsbManager.USB_FUNCTION_NONE)) // 如果adb开启,返回adb,否则返回mtp functions = UsbManager.usbFunctionsToString(getChargingFunctions()); } // adb开启,就追加adb值,否则移除adb值 functions = applyAdbFunction(functions); // 2. 获取oem覆盖的usb功能 String oemFunctions = applyOemOverrideFunction(functions); // 处理非正常启动模式情况,忽略 if (!isNormalBoot() && !mCurrentFunctionsStr.equals(functions)) { setSystemProperty(getPersistProp(true), functions); } // 3. 设置新功能 if ((!functions.equals(oemFunctions) && !mCurrentOemFunctions.equals(oemFunctions)) || !mCurrentFunctionsStr.equals(functions) || !mCurrentFunctionsApplied || forceRestart) { Slog.i(TAG, "Setting USB config to " + functions); // 保存要设置新功能对应的字符串值 mCurrentFunctionsStr = functions; // 保存oem覆盖功能的字符串值 mCurrentOemFunctions = oemFunctions; mCurrentFunctionsApplied = false; // 先断开已经存在的usb连接 setUsbConfig(UsbManager.USB_FUNCTION_NONE); // 判断是否成功 if (!waitForState(UsbManager.USB_FUNCTION_NONE)) { Slog.e(TAG, "Failed to kick USB config"); return false; } // 设置新功能,注意,这里使用的是oem覆盖的功能 setUsbConfig(oemFunctions); // 如果新功能包含mtp或ptp,那么就要更新usb状态改变广播 // 广播接收者会映射主内存的文件到PC端 if (mBootCompleted && (containsFunction(functions, UsbManager.USB_FUNCTION_MTP) || containsFunction(functions, UsbManager.USB_FUNCTION_PTP))) { updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions)); } // 等待新功能设置完毕 if (!waitForState(oemFunctions)) { Slog.e(TAG, "Failed to switch USB config to " + functions); return false; } mCurrentFunctionsApplied = true; } return true; }
如果新设置的功能是MTP或PTP。
protected void updateUsbStateBroadcastIfNeeded(long functions) { // send a sticky broadcast containing current USB state Intent intent = new Intent(UsbManager.ACTION_USB_STATE); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND | Intent.FLAG_RECEIVER_FOREGROUND); // 保存了usb状态值 intent.putExtra(UsbManager.USB_CONNECTED, mConnected); intent.putExtra(UsbManager.USB_HOST_CONNECTED, mHostConnected); intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured); intent.putExtra(UsbManager.USB_DATA_UNLOCKED, isUsbTransferAllowed() && isUsbDataTransferActive(mCurrentFunctions)); // 保存了要设置的新功能的值,例如设置的是MTP,那么参数的key为mtp,值为true long remainingFunctions = functions; while (remainingFunctions != 0) { intent.putExtra(UsbManager.usbFunctionsToString( Long.highestOneBit(remainingFunctions)), true); remainingFunctions -= Long.highestOneBit(remainingFunctions); } // 如果状态没有改变,就不发送广播 if (!isUsbStateChanged(intent)) { return; } // 注意这里发送的是一个sticky广播 sendStickyBroadcast(intent); mBroadcastedIntent = intent;
来看这个setUsbConfig函数其中的处理吧
private void setUsbConfig(String config) {
// 设置sys.usb.config
setSystemProperty(USB_CONFIG_PROPERTY, config);
}
其中真滴就是通过设置sys.usb.config的属性值,还记得吗,在前面的分析中,也解释过这个属性值,它就是代表当前设置的usb功能,从这里就可以得到证明。
这其实也在提示我们,其实可以通过adb shell setprop命令设置这个属性,从而控制usb功能的切换。在实际的工作中,屡试不爽。
设置这个属性后如何判断设置成功了呢?这就是waitForState()所做的
private boolean waitForState(String state) {
String value = null;
for (int i = 0; i < 20; i++) {
// 获取sys.usb.stat值
value = getSystemProperty(USB_STATE_PROPERTY, "");
// 与刚才设置的sys.usb.config属性值相比较
if (state.equals(value)) return true;
SystemClock.sleep(50);
}
return false;
}
还记得吗?在前面的分析中,我也解释过sys.usb.state属性的作用,它代表usb实际的功能,从这里就可以得到验证。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。