在分析Android MTP
之前,先介绍下UsbService
,它有何用呢?先看下源码中的注释
/**
* UsbService manages all USB related state, including both host and device support.
* Host related events and calls are delegated to UsbHostManager, and device related
* support is delegated to UsbDeviceManager.
*/
public class UsbService extends IUsbManager.Stub {}
注释其实已经对UsbService
解释的很清楚,但是如果需要明白具体是啥意思,我们需要一点USB
和MTP
的知识。 在USB
协议中,连接USB
的两端被称为USB Host
和USB Device
,而Android
设备既可以作为USB Host
端,也可以作为USB Device
端,因此UsbService
就是用来管理这两种情况的。从注释中可以看出,UsbService
用UsbDeviceManager
代理手机作为Usb Device
端的功能,而用UsbHostManager
代理手机作为Usb Host
端的功能。
而本文要分析的MTP
协议是构建于物理层USB
之上的,Usb Host
被称为Initiator
,Usb Device
被称为Responder
,Initiator
用来向Responder
发送操作请求,而Responder
用来响应请求。
那么,什么时候设备可以作为Usb Device
端,什么时候又可以作为Usb Host
端呢? 当手机连接电脑的时候,手机就是Usb Device
端,而当手机连接鼠标时,手机可以作为Usb Host
端。
那么今天我们要讨论的MTP
对应的情况是手机连接电脑,那么手机就是作为USB Device
端,那么我们的目光自然就要聚焦到UsbDeviceManager
这个类上。不过,在分析这个类之前,我们需要知道UsbService
是如何启动的。
从UsbService
的类声明就可以猜出它是一个系统服务,那么就是从SystemServer.java
中启动的
public final class SystemServer {
private static final String USB_SERVICE_CLASS =
"com.android.server.usb.UsbService$Lifecycle";
private void startOtherServices() {
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)
|| mPackageManager.hasSystemFeature(
PackageManager.FEATURE_USB_ACCESSORY)) {
mSystemServiceManager.startService(USB_SERVICE_CLASS);
traceEnd();
}
}
}
我们注意到,USB_SERVICE_CLASS
指的是UsbService
的一个内部类Lifecycle
,这个内部类实现了SystemService
接口,实现这个接口的子类表明是一个系统服务,并且用来接收各种生命周期回调,然而Lifecycle
并不似一个真正的系统服务,因为当发生生命周期回调的时候,调用的是UsbService
相应的方法,这就是一个典型的代理模式的应用,其实系统中很多服务都是这样设计的。
那么,我们来粗略看下SystemServiceManager
是如何启动这个系统服务的
/**
* Manages creating, starting, and other lifecycle events of
* {@link com.android.server.SystemService system services}.
*/
public class SystemServiceManager {
public SystemService startService(String className) {
final Class<SystemService> serviceClass;
try {
serviceClass = (Class<SystemService>)Class.forName(className);
} catch (ClassNotFoundException ex) {
// ...
}
return startService(serviceClass);
}
public <T extends SystemService> T startService(Class<T> serviceClass) {
try {
final String name = serviceClass.getName();
// Create the service.
// 判断是否是相同类型
if (!SystemService.class.isAssignableFrom(serviceClass)) {
throw new RuntimeException("Failed to create " + name
+ ": service must extend " + SystemService.class.getName());
}
final T service;
try {
// 获取有Context类型作为参数的构造函数
Constructor<T> constructor = serviceClass.getConstructor(Context.class);
// 创建对象
service = constructor.newInstance(mContext);
} catch (Exception ex) {
// ...
}
startService(service);
return service;
} finally {
// ...
}
}
// Services that should receive lifecycle events.
private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();
public void startService(@NonNull final SystemService service) {
// Register it.
// 保存在mServices中,以便这个系统服务能收到各种生命周期事件
mServices.add(service);
// Start it.
long time = SystemClock.elapsedRealtime();
try {
// 真正启动系统服务的地方
service.onStart();
} catch (RuntimeException ex) {
// ...
}
warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
}
}
首先调用的是UsbService$Lifecycle
的带Context
参数的构造函数创建Lifecycle
对象,然后调用这个对象的onStart()
方法。在分析这个onStart()
方法之前,在代码中有一点需要注意,在创建Lifecycle
对象后,用一个ArrayList
变量mService
保存了这个Lifecycle
对象,显而易见,mService
是用来保存各种系统服务(可能这个服务只是一个代理)。当时机得当,就可以统一调用各种服务的的声明周期,UsbService$Lifecycle
就回调了各种声明周期方法,在后面即将看到。
UsbService启动
那么,现在来看下UsbService$Lifecycle
的onStart()
方法吧
public class UsbService extends IUsbManager.Stub {
public static class Lifecycle extends SystemService {
// ...
@Override
public void onStart() {
// 创建UsbService对象
mUsbService = new UsbService(getContext());
// 向系统注册这个服务,以便其他Service和App能访问
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();
}
}
// ...
}
}
与我们分析相关的生命周期回调有两个,一个是onStart()
,在创建时候回调,一个是onBootPhase
是在系统启动阶段回调。 在onStart()
中首先创建了UsbService
对象,然后向系统注册了这个服务,那么接下来看下UsbService
的构造函数。
public class UsbService extends IUsbManager.Stub {
public UsbService(Context context) {
mContext = context;
# UsbService的启动
mUserManager = context.getSystemService(UserManager.class);
// 用户设置相关
mSettingsManager = new UsbSettingsManager(context);
// USB音频相关
mAlsaManager = new UsbAlsaManager(context);
final PackageManager pm = mContext.getPackageManager();
// 如果设备有作为Host端的feature,就创建UsbHostMananger对象
if (pm.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
mHostManager = new UsbHostManager(context, mAlsaManager, mSettingsManager);
}
// 从这里可以看出/sys/class/android_usb节点代表设备是否支持作为Device端的feature
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);
}
}
构造函数做了很多初始化工作,根据前面的介绍,我们需要把重点聚焦到UsbDeviceManager
的创建
public class UsbDeviceManager {
public UsbDeviceManager(Context context, UsbAlsaManager alsaManager,
UsbSettingsManager settingsManager) {
// 1. 初始化参数
mContext = context;
mUsbAlsaManager = alsaManager;
mSettingsManager = settingsManager;
mContentResolver = context.getContentResolver();
PackageManager pm = mContext.getPackageManager();
mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
// 用序列号初始化RNDIS以太网地址
initRndisAddress();
// 2. 读取OEM的配置
readOemUsbOverrideConfig();
// 3. 创建UsbHandler对象
// 这个Handler是真正为UsbDeviceManager做事的
mHandler = new UsbHandler(FgThread.get().getLooper());
if (nativeIsStartRequested()) {
if (DEBUG) Slog.d(TAG, "accessory attached at boot");
startAccessoryMode();
}
// 4. 根据情况创建DebuggingManager对象(与adb相关)
// ro.adb.secure代表adb是否授权,user版本上这个属性的值是1
boolean secureAdbEnabled = SystemProperties.getBoolean("ro.adb.secure", false);
// 是否经过加密
boolean dataEncrypted = "1".equals(SystemProperties.get("vold.decrypt"));
// 基本可以理解为User版本创建UsbDebuggingManager对象
if (secureAdbEnabled && !dataEncrypted) {
mDebuggingManager = new UsbDebuggingManager(context);
}
// 5. 注册各种广播监听器,利用UsbHandler来进行更新操作
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);
}
};
// 监听USB端口改变
mContext.registerReceiver(portReceiver,
new IntentFilter(UsbManager.ACTION_USB_PORT_CHANGED));
// 监听电量改变
mContext.registerReceiver(chargingReceiver,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
// 监听USB连接/断开
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));
}
}
虽然我分了这么多步,但是我们只分析和本文主题相关的第二步和第三步。
首先看下第②
步,这一步是读取OEM
厂商的需要覆盖USB
功能的配置。
private void readOemUsbOverrideConfig() {
// [bootmode]:[original USB mode]:[USB mode used]
String[] configList = mContext.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]));
}
}
}
}
}
}
是不是看的一头雾水,但是如果你理解com.android.internal.R.array.config_oemUsbModeOverride
数组每一项如何定义后就明白了
<!-- Array of OEM specific USB mode override config.
OEM can override a certain USB mode depending on ro.bootmode.
Specify an array of below items to set override rule.
[bootmode]:[original USB mode]:[USB mode used]-->
<integer-array translatable="false" name="config_oemUsbModeOverride">
</integer-array>
mOemModeMap
就是保存了这些数据,置于怎么保存数据我就不解释了,简单的用如下的json
格式表示如下
{
{bootmode:{original_usb_mode:{usb_mode_used}}},
{bootmode:{original_usb_mode:{usb_mode_used}}},
// ...
}
其实,我们可以注意到,这里其实没有保存任何数据,那么我为何还要把它提出来分析,因为这在我们做系统定制的时候也许有帮助的,而且在后面的分析中也涉及到mOemModeMap
,到时候我们再看下这些数据到底有何作用。
那么,现在我们接着看UsbDeviceManager
构造函数的第③
步,代码如下
mHandler = new UsbHandler(FgThread.get().getLooper());
UsbHandler
是真正为UsbDeviceManager
干活的家伙,这里我们需要注意,它使用的Looper
其实是HandlerThread
中的Looper
,这样一来UsbDeviceManager
就把所有工作放到了另外一个线程中处理了。
现在我们来看下UsbHandler
的构造函数吧
/**
* The persistent property which stores whether adb is enabled or not.
* May also contain vendor-specific default functions for testing purposes.
*/
private static final String USB_PERSISTENT_CONFIG_PROPERTY = "persist.sys.usb.config";
/**
* The non-persistent property which stores the current USB settings.
*/
private static final String USB_CONFIG_PROPERTY = "sys.usb.config";
/**
* The non-persistent property which stores the current USB actual state.
*/
private static final String USB_STATE_PROPERTY = "sys.usb.state";
/*
* 用于读取USB状态
*/
private static final String STATE_PATH = "/sys/class/android_usb/android0/state";
public UsbHandler(Looper looper) {
super(looper);
try {
// 1. 获取当前USB的设置,并与实际的USB状态相比较
if (isNormalBoot()) {
// 表示USB功能的当前设置
mCurrentFunctions = SystemProperties.get(USB_CONFIG_PROPERTY,
UsbManager.USB_FUNCTION_NONE);
// 表示USB功能的当前设置是否全部被应用
mCurrentFunctionsApplied = mCurrentFunctions.equals(
SystemProperties.get(USB_STATE_PROPERTY));
} else {
// ...
}
// 2. 检测adb是否开启
mAdbEnabled = UsbManager.containsFunction(
SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY),
UsbManager.USB_FUNCTION_ADB);
/*
* Previous versions can set persist config to mtp/ptp but it does not
* get reset on OTA. Reset the property here instead.
* 按照注释所说,跟OTA相关,具体的操作是移除persist.sys.usb.config属性中的ptp值
*/
String persisted = SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY);
if (UsbManager.containsFunction(persisted, UsbManager.USB_FUNCTION_PTP)
|| UsbManager.containsFunction(persisted, UsbManager.USB_FUNCTION_PTP)) {
SystemProperties.set(USB_PERSISTENT_CONFIG_PROPERTY,
UsbManager.removeFunction(UsbManager.removeFunction(persisted,
UsbManager.USB_FUNCTION_MTP), UsbManager.USB_FUNCTION_PTP));
}
// 3. 读取当前USB状态,并更新状态
String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
updateState(state);
// 注册Observer监听adb设置的改变,从而利用socket,开关adb
mContentResolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.ADB_ENABLED),
false, new AdbSettingsObserver());
// 4. 监听USB配置改变,从而利用mHandler更新状态
mUEventObserver.startObserving(USB_STATE_MATCH);
mUEventObserver.startObserving(ACCESSORY_START_MATCH);
} catch (Exception e) {
Slog.e(TAG, "Error initializing UsbHandler", e);
}
}
虽然代码比较简单,但是我列出了与MTP
分析相关的这几步用于分析。
第①
步,根据启动模式来为两个变量赋值,这里我们只考虑正常启动模式。mCurrentFunctions
代表USB功能的当前设置,mCurrentFunctionsApplied
表示USB功能的当前设置是否与实际功能相符。
sys.usb.config
属性如注释所说,代表当前USB
设置,什么意思呢? 例如,当我们在手机上设置USB
的模式为File transfer
,也就是MTP
模式的时候,sys.usb.config
的值一般为mtp, adb
,我们暂且不用关心为何有adb
属性,其实我们只要明白sys.usb.config
就代表了设置USB
模式时对应的值。
sys.usb.state
属性如注释所说,代表了USB
实际状态,什么意思呢?虽然用户设置USB
模式为MTP
,sys.usb.config
的值也变为了mtp, adb
,然而底层是否能设置成功呢?如果没有成功,那么sys.usb.state
的值可能就为none
,如果成功了,那么sys.usb.state
的值就与sys.usb.config
的值一样了。这就可以解释了为何在代码中去比较这两个属性的值,当这两个值相等的时候,就证明当前的USB
设置是成功的。
第②
步,检测abd
是否开启了,怎么判断的呢?首先读取persist.sys.usb.config
属性的值,然后判断这个值中是否包含adb
。
第③
步,读取USB
状态并更新,这算是一个USB
状态初始化操作。读取的节点是/sys/class/android_usb/android0/state
。现在我们看下更新操作
public class UsbDeviceManager {
private final class UsbHandler extends Handler {
public void updateState(String state) {
int connected, configured;
if ("DISCONNECTED".equals(state)) {
connected = 0;
configured = 0;
} else if ("CONNECTED".equals(state)) {
connected = 1;
configured = 0;
} else if ("CONFIGURED".equals(state)) {
connected = 1;
configured = 1;
} else {
Slog.e(TAG, "unknown state " + state);
return;
}
removeMessages(MSG_UPDATE_STATE);
Message msg = Message.obtain(this, MSG_UPDATE_STATE);
msg.arg1 = connected;
msg.arg2 = configured;
// debounce disconnects to avoid problems bringing up USB tethering
sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0);
}
}
}
从这个函数的实现中,我们可以发现,USB
的合理状态其实只有DISCONNECTED
, CONNECTED
, CONFIGURED
三个值。其实,当手机通过USB
连接电脑的时候,USB
状态就是从DISCONNECTED- > CONNECTED -> CONFIGURED
转换的。
我们现在分析的阶段为UsbService
的创建阶段,我们假设此时USB
还没有连接上,那么这里的变量connected
和configured
都为0。
最后发送了一个MSG_UPDATE_STATE
消息来处理USB
状态更新。
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE_STATE:
// 1. 保存了USB状态
mConnected = (msg.arg1 == 1);
mConfigured = (msg.arg2 == 1);
// 2. 更新下usb和adb通知
updateUsbNotification(false);
updateAdbNotification(false);
// 3. 如果已经启动完毕,就发送USB状态广播
if (mBootCompleted) {
updateUsbStateBroadcastIfNeeded(false);
}
// 3. USB的ACCESSORY功能相关操作
if (UsbManager.containsFunction(mCurrentFunctions,
UsbManager.USB_FUNCTION_ACCESSORY)) {
updateCurrentAccessory();
}
// 4. 启动完毕,但是USB没有连接上
if (mBootCompleted) {
if (!mConnected) {
// restore defaults when USB is disconnected
// 重置USB功能为none,adb
setEnabledFunctions(null, !mAdbEnabled, false);
}
// 与USB的AUDIO和MIDI相关的更新
updateUsbFunctions();
} else {
mPendingBootBroadcast = true;
}
break;
// ...
}
}
由于目前分析的阶段为UsbService
的onStart()
阶段,也就是创建阶段,这里其实只是简单的保存了USB
状态,再加上最后一行的mPendingBootBroadcast = true
代码。当系统启动完毕后,我们会再次看到这个消息的处理,到时候再来分析这里的代码逻辑。
第④
步,这一步非常重要,我们可以看下mUEventObserver
变量的赋值
/*
* Listens for uevent messages from the kernel to monitor the USB state
*/
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();
}
}
};
从注释中我们可以知道,这里是监听内核的消息,当我们把手机和电脑通过USB
连接上后,USB
状态就会改变,我们发现又是调用mHandler
的updateState()
方法,这个方法我们在前面分析过,这里不再重复。然而目前我们并不去分析手机连接电脑的情况,等我们把UsbService
分析完毕后,再来分析连接USB
的情况。
系统启动阶段
当系统启动完毕,就会执行UsbService.Lifecycle
对象的onBootPhase()
回调。
public class UsbService extends IUsbManager.Stub {
public static class Lifecycle extends SystemService {
// ...
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
mUsbService.systemReady();
} else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
mUsbService.bootCompleted();
}
}
}
}
这涉及到系统的启动几个阶段,PHASE_ACTIVITY_MANAGER_READY
代表ActivityManagerService
已就绪,PHASE_BOOT_COMPLETED
代表启动启动完毕。很显然,先是经历PHASE_ACTIVITY_MANAGER_READY
再经历PHASE_BOOT_COMPLETED
。
PHASE_ACTIVITY_MANAGER_READY阶段
先看下PHASE_ACTIVITY_MANAGER_READY
阶段的操作,调用的是systemRead()
函数
public void systemReady() {
mAlsaManager.systemReady();
if (mDeviceManager != null) {
mDeviceManager.systemReady();
}
if (mHostManager != null) {
mHostManager.systemReady();
}
if (mPortManager != null) {
mPortManager.systemReady();
}
}
我们这里只需要关心UsbDeviceManager
的systemRead()
函数
public void systemReady() {
if (DEBUG) Slog.d(TAG, "systemReady");
// 可以注意到mNotificationManager是在系统系统就绪阶段创建的,这就代表了这个阶段可以发送广播了
mNotificationManager = (NotificationManager)
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
// Ensure that the notification channels are set up
// TV相关
if (isTv()) {
// ...
}
// We do not show the USB notification if the primary volume supports mass storage.
// The legacy mass storage UI will be used instead.
// 如果主存储支持USB的mass storage功能,那么就不会显示USB通知
boolean massStorageSupported;
final StorageManager storageManager = StorageManager.from(mContext);
final StorageVolume primary = storageManager.getPrimaryVolume();
massStorageSupported = primary != null && primary.allowMassStorage();
mUseUsbNotification = !massStorageSupported && mContext.getResources().getBoolean(
com.android.internal.R.bool.config_usbChargingMessage);
// make sure the ADB_ENABLED setting value matches the current state
// 根据mAdbEnabled的值,来更新数据库的值
try {
Settings.Global.putInt(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.");
}
// 发送MSG_SYSTEM_READY消息
mHandler.sendEmptyMessage(MSG_SYSTEM_READY);
}
在这个函数中我们只关心最后发送的MSG_SYSTEM_READ
的消息,现在来看下这个消息的处理
public void handleMessage(Message msg) {
switch (msg.what) {
// ...
case MSG_SYSTEM_READY:
// 1. 如果USB连接上,就发送USB通知,通过这个通知,我们可以选择USB模式
updateUsbNotification(false);
// 2. 如果USB连接上,发送adb通知,可以通过这个通知打开开发者模式界面
updateAdbNotification(false);
// 3. 更新USB的AUIO和MIDI功能
updateUsbFunctions();
break;
// ...
}
}
与前面保持一致,我们假设现在手机还没有通过USB
连接到电脑,因此这里就不分析了。
PHASE_BOOT_COMPLETED阶段
那么再回到UsbService.Lifecycle
的onBootPhase()
回调,来看下PHASE_BOOT_COMPLETED
阶段的操作
public class UsbService extends IUsbManager.Stub {
public static class Lifecycle extends SystemService {
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
mUsbService.systemReady();
} else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
mUsbService.bootCompleted();
}
}
}
public void bootCompleted() {
if (mDeviceManager != null) {
mDeviceManager.bootCompleted();
}
}
}
在PHASE_BOOT_COMPLETED
阶段,调用的是UsbDeviceManager
对象的bootCompleted()
函数,看下这个函数的实现
public class UsbDeviceManager {
public void bootCompleted() {
mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED);
}
}
非常简单,就是发送了一个MSG_BOOT_COMPLETED
消息,接下来看下消息如何处理的
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_BOOT_COMPLETED:
// mBootCompleted代表系统是否已经启动完毕
mBootCompleted = true;
// 1. 如果usb状态改变就发送USB状态广播
if (mPendingBootBroadcast) {
updateUsbStateBroadcastIfNeeded(false);
mPendingBootBroadcast = false;
}
// 2. 设置USB功能为none
setEnabledFunctions(null, false, false);
// 与USB Accessory功能相关
if (mCurrentAccessory != null) {
getCurrentSettings().accessoryAttached(mCurrentAccessory);
}
// 与adb进程通信,弹出USB授权窗口,根据用户操作,决定是否开启adb
if (mDebuggingManager != null) {
mDebuggingManager.setAdbEnabled(mAdbEnabled);
}
break;
这里只关心前两步,第①
步,根据USB
状态是否改变来决定是否发送USB
状态广播。这里有个条件mPendingBootBroadcast
,还记得吗?在前面分析UsbService
的启动中这个变量被设置为true
。为了与前面分析保持一致,我们继续假设手机没有通过USB
和电脑连接,因此这里也不会发送广播。
再来看下处理MSG_BOOT_COMPLETED
消息的第②
步,这一步相当于重置USB功能,代码为setEnabledFunctions(null, false, false)
,注意这里参数。
/**
* Evaluates USB function policies and applies the change accordingly.
*/
private void setEnabledFunctions(String functions, boolean forceRestart,
boolean usbDataUnlocked) {
// 1. 如果数据锁定状态改变了就更新usb通知
if (usbDataUnlocked != mUsbDataUnlocked) {
mUsbDataUnlocked = usbDataUnlocked;
updateUsbNotification(false);
forceRestart = true;
}
// Try to set the enabled functions.
final String oldFunctions = mCurrentFunctions;
final boolean oldFunctionsApplied = mCurrentFunctionsApplied;
// 2. 尝试设置USB可用功能
if (trySetEnabledFunctions(functions, forceRestart)) {
return;
}
// Didn't work. Try to revert changes.
// We always reapply the policy in case certain constraints changed such as
// user restrictions independently of any other new functions we were
// trying to activate.
// 3. 到这一步表示设置USB新功能失败,那么就回退呗
if (oldFunctionsApplied && !oldFunctions.equals(functions)) {
Slog.e(TAG, "Failsafe 1: Restoring previous USB functions.");
if (trySetEnabledFunctions(oldFunctions, false)) {
return;
}
}
// Still didn't work. Try to restore the default functions.
// 4. 到这一步,表明回退都失败了,那么就恢复默认吧
Slog.e(TAG, "Failsafe 2: Restoring default USB functions.");
if (trySetEnabledFunctions(null, false)) {
return;
}
// Now we're desperate. Ignore the default functions.
// Try to get ADB working if enabled.
Slog.e(TAG, "Failsafe 3: Restoring empty function list (with ADB if enabled).");
// 5. 如果到这里,那么证明恢复默认都失败,握草,放弃吧,把USB功能设置为none(意思就是,我不玩了还不行吗)
if (trySetEnabledFunctions(UsbManager.USB_FUNCTION_NONE, false)) {
return;
}
// Ouch.
// 6. 到这一步应该不可能吧,加个Log压压惊!
Slog.e(TAG, "Unable to set any USB functions!");
}
第一步,根据参数的值,很显然这里的条件不成立。后面的几步呢,其实都是调用同一个函数,因此我们用第二步来分析这个函数
,注意传入的参数functions
为null
,forceRestart
为false
。
/*
* 参数functions代表需要设置给USB的功能,例如"mtp"
* 参数forceRestart代表USB功能是否强制重新设置
*/
private boolean trySetEnabledFunctions(String functions, boolean forceRestart) {
// 1. 如果功能为null,就获取默认的功能
if (functions == null || applyAdbFunction(functions)
.equals(UsbManager.USB_FUNCTION_NONE)) {
functions = getDefaultFunctions();
}
// 2. 根据情况决定是否增加adb组合
functions = applyAdbFunction(functions);
// 3. 使用运营商设置的参数,覆盖对应的功能。默认的是没有任何覆盖的。
String oemFunctions = applyOemOverrideFunction(functions);
// 非正常启动情况,设置一些属性
if (!isNormalBoot() && !mCurrentFunctions.equals(functions)) {
SystemProperties.set(getPersistProp(true), functions);
}
// 4. 根据条件判断是否设置USB新功能
if ((!functions.equals(oemFunctions) &&
(mCurrentOemFunctions == null ||
!mCurrentOemFunctions.equals(oemFunctions)))
|| !mCurrentFunctions.equals(functions)
|| !mCurrentFunctionsApplied
|| forceRestart) {
Slog.i(TAG, "Setting USB config to " + functions);
mCurrentFunctions = functions;
mCurrentOemFunctions = oemFunctions;
mCurrentFunctionsApplied = false;
// Kick the USB stack to close existing connections.
// 4.1. 设置sys.usb.config的属性值,这里指关闭已存在的的USB链接
setUsbConfig(UsbManager.USB_FUNCTION_NONE);
// 用1秒钟检测sys.usb.stat属性是否等于UsbManager.USB_FUNCTION_NONE
// 如果成功,代表前面的USB连接关闭成功,如果失败就直接返回
if (!waitForState(UsbManager.USB_FUNCTION_NONE)) {
Slog.e(TAG, "Failed to kick USB config");
return false;
}
// Set the new USB configuration.
// 4.2. 设置新的USB功能
setUsbConfig(oemFunctions);
// 4.3. 如果手机已经启动完毕,而且切换的功能中包含MTP/PTP,就发送广播
if (mBootCompleted
&& (UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_MTP)
|| UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_PTP))) {
// Start up dependent services.
updateUsbStateBroadcastIfNeeded(true);
}
// 用1秒钟检测sys.usb.stat属性是否等于oemFunctions
// 如果成功,代表USB功能切换成功,如果失败,直接返回
if (!waitForState(oemFunctions)) {
Slog.e(TAG, "Failed to switch USB config to " + functions);
return false;
}
mCurrentFunctionsApplied = true;
}
return true;
}
根据传入参数的值,很显然第①
步就会调用getDefaultFunctions()
来获取USB
默认的功能。
private String getDefaultFunctions() {
String func = SystemProperties.get(getPersistProp(true),
UsbManager.USB_FUNCTION_NONE);
// if ADB is enabled, reset functions to ADB
// else enable MTP as usual.
if (UsbManager.containsFunction(func, UsbManager.USB_FUNCTION_ADB)) {
// 这里为何不直接用一条语句return funcs;解决问题?
if (UsbManager.USB_FUNCTION_ADB.equals(func)) {
return UsbManager.USB_FUNCTION_ADB;
} else {
return func;
}
} else {
return UsbManager.USB_FUNCTION_MTP;
}
}
public static String getPersistProp(boolean functions) {
String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
// persist.sys.usb.config
String persistProp = USB_PERSISTENT_CONFIG_PROPERTY;
// 非正常模式启动的属性
if (!(bootMode.equals(NORMAL_BOOT) || bootMode.equals("unknown"))) {
if (functions) {
persistProp = "persist.sys.usb." + bootMode + ".func";
} else {
persistProp = "persist.sys.usb." + bootMode + ".config";
}
}
return persistProp;
}
我们假设手机的启动模式是正常启动模式,那么getPersistProp()
方法获取的就是persist.sys.usb.config
属性的值,这个值我们在前面提过一次,当初用这个属性值是用来判断是否要开启adb
,然而这里用这个属性值来决定USB
的默认功能。可以看出,如果这个属性值包含adb
,那么就会把这个属性值作为默认的USB
功能返回,否则USB
的默认功能就是mtp
。
接着看第②
步,这里是把adb
功能设置上去,以我手机为例,上一步,我们获取的默认的值是charging, adb
private String applyAdbFunction(String functions) {
// Do not pass null pointer to the UsbManager.
// There isnt a check there.
if (functions == null) {
functions = "";
}
boolean adbEnable = mAdbEnabled;
if (isStrictOpEnable()
&& (UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_MTP)
&& !mUsbDataUnlocked)) {
adbEnable = false;
}
if (adbEnable) {
functions = UsbManager.addFunction(functions, UsbManager.USB_FUNCTION_ADB);
} else {
functions = UsbManager.removeFunction(functions, UsbManager.USB_FUNCTION_ADB);
}
return functions;
}
// 与运营商认证相关
private boolean isStrictOpEnable() {
return SystemProperties.getBoolean("persist.vendor.strict_op_enable", false);
}
persist.vendor.strict_op_enable
这个属性呢,我稍微查了下,好像跟运营商入网认证有关系,我用的测试机,这个值是没有设置的,我们就暂时先不管这个值了。
mAdbEnabled
这个值在我们前面的分析中出现过,赋值代码如下
// 读取persist.sys.usb.config的值,看是否包含adb
mAdbEnabled = UsbManager.containsFunction(
SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY),
UsbManager.USB_FUNCTION_ADB);
mAdbEnabled
的值是根据persist.sys.usb.config
属性的值是否包含adb
来决定的,我的测试样机中这个属性的默认值是charging,adb
,很显然mAdbEnabled
的值为true
。
那么applyAdbFunction()
方法的返回值,其实就是与参数一样,是charging,adb
。
第③
步,使用OEM
的USB
功能覆盖原始的USB
功能。在前面的分析中我们说过,我们需要看下这个覆盖功能是如何使用的
private String applyOemOverrideFunction(String usbFunctions) {
if ((usbFunctions == null) || (mOemModeMap == null)) {
return usbFunctions;
}
String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
Slog.d(TAG, "applyOemOverride usbfunctions=" + usbFunctions + " bootmode=" + bootMode);
Map<String, Pair<String, String>> overridesMap =
mOemModeMap.get(bootMode);
// Check to ensure that the oem is not overriding in the normal
// boot mode
// 从条件可以看出,正常启动模式下,usb功能是不覆盖的
if (overridesMap != null && !(bootMode.equals(NORMAL_BOOT) ||
bootMode.equals("unknown"))) {
Pair<String, String> overrideFunctions =
overridesMap.get(usbFunctions);
if (overrideFunctions != null) {
Slog.d(TAG, "OEM USB override: " + usbFunctions
+ " ==> " + overrideFunctions.first
+ " persist across reboot "
+ overrideFunctions.second);
if (!overrideFunctions.second.equals("")) {
String newFunction;
if (mAdbEnabled) {
newFunction = UsbManager.addFunction(overrideFunctions.second,
UsbManager.USB_FUNCTION_ADB);
} else {
newFunction = overrideFunctions.second;
}
Slog.d(TAG, "OEM USB override persisting: " + newFunction + "in prop: "
+ UsbDeviceManager.getPersistProp(false));
SystemProperties.set(UsbDeviceManager.getPersistProp(false),
newFunction);
}
return overrideFunctions.first;
} else if (mAdbEnabled) {
String newFunction = UsbManager.addFunction(UsbManager.USB_FUNCTION_NONE,
UsbManager.USB_FUNCTION_ADB);
SystemProperties.set(UsbDeviceManager.getPersistProp(false),
newFunction);
} else {
SystemProperties.set(UsbDeviceManager.getPersistProp(false),
UsbManager.USB_FUNCTION_NONE);
}
}
// return passed in functions as is.
return usbFunctions;
}
原来这个运营商的USB
覆盖功能是针对非正常模式启动的情况,具体分析就不多说了,因为我们现在并不关心这种情况。
第④
步,这里的条件肯定是成立的,至少目前来看mCurrentFunctions
为null
,mCurrentFunctionsApplied
为false
。
那么,现在我们来好好看看这个USB
功能是如何设置上的,代码片段如下
// 4. 根据条件判断是否设置USB新功能
if ((!functions.equals(oemFunctions) &&
(mCurrentOemFunctions == null ||
!mCurrentOemFunctions.equals(oemFunctions)))
|| !mCurrentFunctions.equals(functions)
|| !mCurrentFunctionsApplied
|| forceRestart) {
Slog.i(TAG, "Setting USB config to " + functions);
mCurrentFunctions = functions;
mCurrentOemFunctions = oemFunctions;
mCurrentFunctionsApplied = false;
// Kick the USB stack to close existing connections.
// 4.1. 设置sys.usb.config的属性值,这里指关闭已存在的的USB链接
setUsbConfig(UsbManager.USB_FUNCTION_NONE);
// 用1秒钟检测sys.usb.stat属性是否等于UsbManager.USB_FUNCTION_NONE
// 如果成功,代表前面的USB连接关闭成功,如果失败就直接返回
if (!waitForState(UsbManager.USB_FUNCTION_NONE)) {
Slog.e(TAG, "Failed to kick USB config");
return false;
}
// Set the new USB configuration.
// 4.2. 设置新的USB功能
setUsbConfig(oemFunctions);
// 4.3. 如果手机已经启动完毕,而且切换的功能中包含MTP/PTP,就发送广播
if (mBootCompleted
&& (UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_MTP)
|| UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_PTP))) {
// Start up dependent services.
updateUsbStateBroadcastIfNeeded(true);
}
// 用1秒钟检测sys.usb.stat属性是否等于oemFunctions
// 如果成功,代表USB功能切换成功,如果失败,直接返回
if (!waitForState(oemFunctions)) {
Slog.e(TAG, "Failed to switch USB config to " + functions);
return false;
}
mCurrentFunctionsApplied = true;
}
纵观整体,我们可以发现setUsbConfig()
和waitForState()
是关键,而且waitForState()
方法决定了设置是否设置成功。
首先看下setUsbConfig()
是如何设置新功能的
private void setUsbConfig(String config) {
// 设置sys.usb.config属性的值
SystemProperties.set(USB_CONFIG_PROPERTY, config);
}
很简单,就是设置sys.usb.config
系统属性的值,这个属性我们在前面提到过,代表USB当前的设置。
然后再来看下waitForState()
方法
private boolean waitForState(String state) {
// wait for the transition to complete.
// give up after 1 second.
String value = null;
for (int i = 0; i < 20; i++) {
// 读取sys.usb.state属性值
value = SystemProperties.get(USB_STATE_PROPERTY);
if (state.equals(value)) return true;
SystemClock.sleep(50);
}
Slog.e(TAG, "waitForState(" + state + ") FAILED: got " + value);
return false;
}
原来是循环读取sys.usb.state
属性值,然后与sys.usb.config
属性值判断是否相等,从而决定是否设置成功,这与我们前面说的是一致的。
就这样完了吗?我们是不是感觉漏掉了什么细节?sys.usb.state
是何时设置成sys.usb.config
的值的? 其实这一步是在底层完成的。
由于我对底层的代码并不熟悉,因此我把项目中遇到的情况拿来这里对比分析下,当我们把USB
功能设置为mtp, adb
时候,下面代码就会做相应动作。
on property:sys.usb.config=mtp,adb && property:sys.usb.configfs=0
# 先写0
write /sys/class/android_usb/android0/enable 0
# 写序列号
write /sys/class/android_usb/android0/iSerial ${ro.serialno}
# 写vid, pid
write /sys/class/android_usb/android0/idVendor 05C6
write /sys/class/android_usb/android0/idProduct 9039
# 设置USB功能为mtp,adb
write /sys/class/android_usb/android0/functions mtp,adb
# 再写1启动功能
write /sys/class/android_usb/android0/enable 1
# 启动adb
start adbd
# 设置 sys.usb.state属性值为sys.usb.config的属性值
setprop sys.usb.state ${sys.usb.config}
这段代码的顺序很重要,因为涉及要调用的函数。这段代码实际做了三件事
- 启用mtp功能
- 开启adbd进程
- 设置系统属性
sys.usb.state
的值为sys.usb.config
的值
注意最后一步,我们在前面提到过sys.usb.state
为USB
的实际状态,sys.usb.config
为USB
的当前设置,这下你明白了吗?
底层USB
功能的切换必然导致USB
状态的改变,那么上层总该有个地方能知道这个改变吧?还记得UsbDeviceManager
的内部类UsbHandler
的构造函数中如下代码吗
mUEventObserver.startObserving(USB_STATE_MATCH);
mUEventObserver
就是用来监听内核的uevent message
的,从而监听USB状态的
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) {
// 发送USB状态改变广播
mHandler.updateState(state);
} else if ("START".equals(accessory)) {
if (DEBUG) Slog.d(TAG, "got accessory start");
startAccessoryMode();
}
}
};
当状态改变的时候,就会发送USB
通知,如果手机还没有与电脑通过USB
相连,那么这里也不会有USB
通知。
USB连接情况分析
至此,我们已经把UsbService
的整个启动流程分析完毕了,之前的分析都是假设手机没有与电脑相连。既然我们已经对UsbService
的整个启动流程有了初步的了解,那么我们就来挑战分析下手机通过USB
与电脑相连的情况。
那么我们该从哪里入手呢?当USB
建立连接的时候,USB
状态肯定会改变,上层哪个底层在检测这个状态呢?前面刚分析过,你应该还记得吧
/*
* Listens for uevent messages from the kernel to monitor the USB state
*/
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) {
// 更新USB状态
mHandler.updateState(state);
} else if ("START".equals(accessory)) {
if (DEBUG) Slog.d(TAG, "got accessory start");
startAccessoryMode();
}
}
};
OK,是时候刚一波正面了,我们来分析下更新USB
状态的流程
public void updateState(String state) {
int connected, configured;
if ("DISCONNECTED".equals(state)) {
connected = 0;
configured = 0;
} else if ("CONNECTED".equals(state)) {
connected = 1;
configured = 0;
} else if ("CONFIGURED".equals(state)) {
connected = 1;
configured = 1;
} else {
Slog.e(TAG, "unknown state " + state);
return;
}
removeMessages(MSG_UPDATE_STATE);
Message msg = Message.obtain(this, MSG_UPDATE_STATE);
msg.arg1 = connected;
msg.arg2 = configured;
// debounce disconnects to avoid problems bringing up USB tethering
sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0);
}
当我们把手机通过USB
连接到电脑时,会经历CONNECTED
到CONFIGURED
的状态改变,相应的参数也会改变,我们现在只分析CONFIGURED
状态的情况。现在来看下如何处理MSG_UPDATE_STATE
消息,
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE_STATE:
// 1. 保存了USB状态
mConnected = (msg.arg1 == 1);
mConfigured = (msg.arg2 == 1);
// 2. 更新下usb和adb通知
updateUsbNotification(false);
updateAdbNotification(false);
// 3. 如果已经启动完毕,就发送USB状态广播
if (mBootCompleted) {
updateUsbStateBroadcastIfNeeded(false);
}
// 3. USB的ACCESSORY功能相关操作
if (UsbManager.containsFunction(mCurrentFunctions,
UsbManager.USB_FUNCTION_ACCESSORY)) {
updateCurrentAccessory();
}
// 4. 启动完毕,但是USB没有连接上
if (mBootCompleted) {
if (!mConnected) {
// restore defaults when USB is disconnected
// 重置USB功能为none,adb
setEnabledFunctions(null, !mAdbEnabled, false);
}
// 与USB的AUDIO和MIDI相关的更新
updateUsbFunctions();
} else {
mPendingBootBroadcast = true;
}
break;
// ...
}
}
第①
步,保存这些参数,值都为true
。
第②
步,发送USB
和ADB
通知,如下图所示
第③
步发送USB
状态改变广播,因为手机已经通过USB
与电脑相连,因此USB
状态肯定改变了,那么自然就会发送USB
状态改变广播,我们看下实现
private void updateUsbStateBroadcastIfNeeded(boolean configChanged) {
// 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);
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() && mUsbDataUnlocked);
intent.putExtra(UsbManager.USB_CONFIG_CHANGED, configChanged);
if (mCurrentFunctions != null) {
String[] functions = mCurrentFunctions.split(",");
for (int i = 0; i < functions.length; i++) {
final String function = functions[i];
if (UsbManager.USB_FUNCTION_NONE.equals(function)) {
continue;
}
intent.putExtra(function, true);
}
}
// send broadcast intent only if the USB state has changed
// 如果usb状态没有改变并且配置也没有改变,就不发送广播
if (!isUsbStateChanged(intent) && !configChanged) {
if (DEBUG) {
Slog.d(TAG, "skip broadcasting " + intent + " extras: " + intent.getExtras());
}
return;
}
if (DEBUG) Slog.d(TAG, "broadcasting " + intent + " extras: " + intent.getExtras());
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
mBroadcastedIntent = intent;
}
那么,这个广播由谁来接收?跟MTP
又有什么关系呢?这就是下一篇的内容了。
总结
本文对UsbService
进行了一个整体性的分析,这为后面MTP
的分析打下基础。 不过在本片文章中还附带了adb
相关的东西,例如监听adb
的改变,开关adb
,如果有时间的话,我会单独开一篇文章来分析这个主题。