Android Framework系列–CarUsbHandler源码分析
- 本文基于Android12源码。
CarUsbHandler是Android Car提供的服务之一,其用车载USB连接的场景。
车载USB有其特殊应用场景,比如AndroidAuto、CarLife等。而Android的做法是在其原有的USB服务上,扩展了专门针对CarUSB的Service。
进而言之,整个Android Car服务( /packages/services/Car),也是基于这种Extend的想法建立的。
那么CarUsbHandler主要做了哪些事呢?
- Set CarUsbHandler as the USB handling component。USBHostManager(android usbservice)收到设备连接通知时,会优先交给USB handling component进行处理。
- 弹出View,让用户选择处理事件的应用。
- 开机CarUsbHandler 服务启动后,自检当前有无设备连接。如果有符合要求的设备,则弹出View,让用户选择处理事件的应用。
因为车载的AndroidAuto、Carplay、Carlife、USB相关应用一般会由厂商重新开发。所以使用CarUsbHandler的场合并不多。
CarUsbHandler源码分析
USB handling component的设置与处理
源码路径位于 packages/services/Car/car-usb-handler/,属于Application Service。
在AndroidManifest.xml中,定义了启动Activity、Service、接收的广播、以及交互的应用(queries字段,这里理解为找到处理action最匹配的应用。)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
package="android.car.usb.handler">
<queries>
<intent>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
</intent>
</queries>
<application
android:label="@string/app_name"
android:icon="@drawable/ic_launcher"
android:directBootAware="true">
<activity android:name=".UsbHostManagementActivity"
android:theme="@android:style/Theme.DeviceDefault.Dialog"
android:launchMode="standard">
<meta-data
android:name="distractionOptimized"
android:value="true"/>
</activity>
<service android:name=".BootUsbService"
android:exported="false"
android:singleUser="true">
</service>
<receiver android:name=".BootUsbScanner"
android:directBootAware="true">
<intent-filter>
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED"/>
</intent-filter>
</receiver>
</application>
</manifest>
上面说过,CarUsbHandler的任务之一是Set CarUsbHandler as the USB handling component。为了完成这个任务,CarUsbHandler通过overlay方式复写了相关系统配置。
packages/services/Car/car_product/overlay/frameworks/base/core/res/res/values/config.xml
<!-- Set CarUsbHandler as the USB handling component by default -->
<string name="config_UsbDeviceConnectionHandling_component">android.car.usb.handler/android.car.usb.handler.UsbHostManagementActivity</string>
UsbHostManager在启动时,会根据这个属性设置其 USB handling component。
// frameworks/base/services/usb/java/com/android/server/usb/UsbHostManager.java
public UsbHostManager(Context context, UsbAlsaManager alsaManager,
UsbPermissionManager permissionManager) {
// 读取config_UsbDeviceConnectionHandling_component配置
String deviceConnectionHandler = context.getResources().getString(
com.android.internal.R.string.config_UsbDeviceConnectionHandling_component);
if (!TextUtils.isEmpty(deviceConnectionHandler)) {
// 设置USB handling component
setUsbDeviceConnectionHandler(ComponentName.unflattenFromString(
deviceConnectionHandler));
}
}
public void setUsbDeviceConnectionHandler(@Nullable ComponentName usbDeviceConnectionHandler) {
synchronized (mHandlerLock) {
mUsbDeviceConnectionHandler = usbDeviceConnectionHandler;
}
}
private @Nullable ComponentName getUsbDeviceConnectionHandler() {
synchronized (mHandlerLock) {
return mUsbDeviceConnectionHandler;
}
}
然后当车机处于Host模式下,有设备插入的时候,会触发UsbHostManager的usbDeviceAdded函数。
/* Called from JNI in monitorUsbHostBus() to report new USB devices
Returns true if successful, i.e. the USB Audio device descriptors are
correctly parsed and the unique device is added to the audio device list.
*/
@SuppressWarnings("unused")
private boolean usbDeviceAdded(String deviceAddress, int deviceClass, int deviceSubclass,
byte[] descriptors) {
if (DEBUG) {
Slog.d(TAG, "usbDeviceAdded(" + deviceAddress + ") - start");
}
synchronized (mLock) {
UsbDevice.Builder newDeviceBuilder = parser.toAndroidUsbDeviceBuilder();
if (newDeviceBuilder == null) {
Slog.e(TAG, "Couldn't create UsbDevice object.");
} else {
// It is fine to call this only for the current user as all broadcasts are
// sent to all profiles of the user and the dialogs should only show once.
ComponentName usbDeviceConnectionHandler = getUsbDeviceConnectionHandler();
if (usbDeviceConnectionHandler == null) {
} else {
getCurrentUserSettings().deviceAttachedForFixedHandler(newDevice,
usbDeviceConnectionHandler);
}
}
}
return true;
}
通过getUsbDeviceConnectionHandler得到上面设置的USB handling component,然后调用UsbProfileGroupSettingsManager的deviceAttachedForFixedHandler。
public void deviceAttachedForFixedHandler(UsbDevice device, ComponentName component) {
final Intent intent = createDeviceAttachedIntent(device);
// Send broadcast to running activity with registered intent
mContext.sendBroadcastAsUser(intent, UserHandle.of(ActivityManager.getCurrentUser()));
ApplicationInfo appInfo;
try {
// Fixed handlers are always for parent user
appInfo = mPackageManager.getApplicationInfoAsUser(component.getPackageName(), 0,
mParentUser.getIdentifier());
} catch (NameNotFoundException e) {
}
Intent activityIntent = new Intent(intent);
activityIntent.setComponent(component);
try {
// 启动USB handling component,也就是
// android.car.usb.handler.UsbHostManagementActivity
mContext.startActivityAsUser(activityIntent, mParentUser);
} catch (ActivityNotFoundException e) {
Slog.e(TAG, "unable to start activity " + activityIntent);
}
}
首先发送广播,告知相关注册者这次事件。然后启动USB handling component,也就是android.car.usb.handler.UsbHostManagementActivity这个Activity。
CarUsbHandler c启动后的处理
Host模式下,USB接入后。通过USB handling component,启动CarUsbHandler相关的CarUsbHandler。即UsbHostManagementActivity
源码路径packages/services/Car/car-usb-handler/src/android/car/usb/handler/
public class UsbHostManagementActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.usb_host);
mUsbHandlersDialog = findViewById(R.id.usb_handlers_dialog);
mHandlersList = findViewById(R.id.usb_handlers_list);
mHandlerTitle = findViewById(R.id.usb_handler_heading);
mListAdapter = new HandlersAdapter(this);
mHandlersList.setAdapter(mListAdapter);
mHandlersList.setOnItemClickListener(mHandlerClickListener);
mController = new UsbHostController(this, new UsbCallbacks());
mPackageManager = getPackageManager();
}
}
UsbHostManagementActivity启动开始走生命周期,onCreate阶段初始化相关对象。画面相关的内容这里就pass了。重点关注处理逻辑的部分UsbHostController这个对象。
public UsbHostController(Context context, UsbHostControllerCallbacks callbacks) {
mContext = context;
mCallback = callbacks;
mHandler = new UsbHostControllerHandler(Looper.myLooper());
mUsbSettingsStorage = new UsbSettingsStorage(context);
mUsbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
mUsbResolver = new UsbDeviceHandlerResolver(mUsbManager, mContext, this);
IntentFilter filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
context.registerReceiver(mUsbBroadcastReceiver, filter);
}
UsbHostController创建了UsbHostControllerHandler,起了一个Handler用来postmessage专门处理事件。注册接收ACTION_USB_DEVICE_ATTACHED和ACTION_USB_DEVICE_DETACHED这两个广播。
回到UsbHostManagementActivity 这个对象,接下来走到onResume的流程。
public void onResume() {
super.onResume();
UserManager userManager = getSystemService(UserManager.class);
if (userManager.isUserUnlocked() || getUserId() == UserHandle.USER_SYSTEM) {
processDevice();
} else {
}
}
}
用户已解锁,或者以System用户运行的情况下,调用processDevice。
private void processDevice() {
UsbDevice connectedDevice = getDevice();
if (connectedDevice != null) {
mController.processDevice(connectedDevice);
} else {
finish();
}
}
private UsbDevice getDevice() {
if (!UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(getIntent().getAction())) {
return null;
}
return (UsbDevice) getIntent().getParcelableExtra(UsbManager.EXTRA_DEVICE);
}
首先取得当前接入的UsbDevice,如果没有的话。则直接finish掉自己。否则调用UsbHostControllerHandler的processDevice进行处理。
/**
* Processes device new device.
* <p>
* It will load existing settings or resolve supported handlers.
*/
public void processDevice(UsbDevice device) {
// 查找用于处理这个Device的配置内容。
UsbDeviceSettings settings = mUsbSettingsStorage.getSettings(device);
if (settings == null) {
// 首次是找不到的。所以请求“解决这个Device”
resolveDevice(device);
} else {
}
}
首次弹出时,没有选择谁可以处理这个USBDevice。所以settings为空。接下来调用resolveDevice尝试去处理这个USBDevice。该函数最终会调用到UsbDeviceHandlerResolver的doHandleResolveHandlers函数。
private void doHandleResolveHandlers(UsbDevice device) {
Intent intent = createDeviceAttachedIntent(device);
List<UsbHandlerPackage> matches = getDeviceMatches(device, intent, false);
if (LOCAL_LOGD) {
Log.d(TAG, "matches size: " + matches.size());
}
List<UsbDeviceSettings> settings = new ArrayList<>();
for (UsbHandlerPackage pkg : matches) {
settings.add(createSettings(device, pkg));
}
UsbDeviceConnection devConnection = UsbUtil.openConnection(mUsbManager, device);
if (devConnection != null && AoapInterface.isSupported(mContext, device, devConnection)) {
for (UsbHandlerPackage pkg : getDeviceMatches(device, intent, true)) {
if (mAoapServiceManager.isDeviceSupported(device, pkg.mAoapService)) {
settings.add(createSettings(device, pkg));
}
}
}
// 回调函数,添加到View上。
deviceProbingComplete(device, settings);
}
// 这个函数通过PMS查找,可以处理该Inten(入参)的应用有哪些。
private List<UsbHandlerPackage> getDeviceMatches(
UsbDevice device, Intent intent, boolean forAoap) {
return matches;
}
通过getDeviceMatches查找到,可以处理Device事件的应用有哪些。然后添加到自己的Setting里面,然后调用deviceProbingComplete往View上添加显示的内容(内容大体就是可以处理这个Device事件的Component是谁),如果找到的应用list为空,deviceProbingComplete会将UsbHostManagementActivity finish掉(如果过程很快,会闪一下)
回到UsbHostManagementActivity,此时该Activity中的View上就显示了,点击view选择处理这个事件的应用(component)
private final AdapterView.OnItemClickListener mHandlerClickListener =
new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, final View view, int position, long id) {
UsbDeviceSettings settings = (UsbDeviceSettings) parent.getItemAtPosition(position);
settings.setDefaultHandler(true);
mController.applyDeviceSettings(settings);
}
};
调用UsbHostController的applyDeviceSettings
public void applyDeviceSettings(UsbDeviceSettings settings) {
mUsbSettingsStorage.saveSettings(settings);
Message msg = mHandler.obtainMessage();
msg.obj =
new UsbHostControllerHandlerDispatchData(
getActiveDevice(), settings, DISPATCH_RETRY_ATTEMPTS, false);
msg.what = UsbHostControllerHandler.MSG_DEVICE_DISPATCH;
msg.sendToTarget();
}
转到handler中,然后会调用到 UsbDeviceHandlerResolver的dispatch函数。在这个函数里,对于Device类型最一些判断(是否是Aoap模式,这个模式用于AndroidAuto),然后通过调用startActivity,把Device连接事件交给目标component处理。
/**
* Dispatches device to component.
*/
public boolean dispatch(UsbDevice device, ComponentName component, boolean inAoap,
StartAoapFailureListener failureListener) {
ActivityInfo activityInfo;
try {
activityInfo = mPackageManager.getActivityInfo(component, PackageManager.GET_META_DATA);
} catch (NameNotFoundException e) {
Log.e(TAG, "Activity not found: " + component);
return false;
}
Intent intent = createDeviceAttachedIntent(device);
if (inAoap) {
//
}
intent.setComponent(component);
mUsbManager.grantPermission(device, activityInfo.applicationInfo.uid);
mContext.startActivity(intent);
mHandler.requestCompleteDeviceDispatch();
return true;
}
CarUsbHandler自启动的处理
CarUsbHandler属于android.car.usb.handler这个package,其对应的Service源码是BootUsbService。会在开机阶段接收到广播后启动。
<service android:name=".BootUsbService"
android:exported="false"
android:singleUser="true">
</service>
<receiver android:name=".BootUsbScanner"
android:directBootAware="true">
<intent-filter>
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED"/>
</intent-filter>
</receiver>
public class BootUsbService extends Service {
@Override
public Binder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
mDeviceList = intent.getParcelableArrayListExtra(USB_DEVICE_LIST_KEY);
processDevices();
return START_NOT_STICKY;
}
private void processDevices() {
for (UsbDevice device : mDeviceList) {
Log.d(TAG, "Processing device: " + device.getProductName());
handle(this, device);
}
stopSelf();
}
private void handle(Context context, UsbDevice device) {
Intent manageDevice = new Intent(context, UsbHostManagementActivity.class);
manageDevice.setAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
manageDevice.putExtra(UsbManager.EXTRA_DEVICE, device);
manageDevice.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivityAsUser(manageDevice, UserHandle.CURRENT);
}
}
onBind返回空,无法通过BindService连接到这个服务(不给外部使用)。其自启动后,其实也是启动UsbHostManagementActivity这个Activity。后续的流程,就跟跟上面通过UsbHostManagere启动UsbHostManagementActivity基本上一样了。
综上,CarUsbHandler的用途大体上就是选择哪个应用来处理接入的Device(Host模式下)。如果没有使用到它的话,可以直接将其剪裁掉(不打包,或者去掉config_UsbDeviceConnectionHandling_component的配置)。