【Android】Android Framework系列--CarUsbHandler源码分析

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,然后调用UsbProfileGroupSettingsManagerdeviceAttachedForFixedHandler

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。该函数最终会调用到UsbDeviceHandlerResolverdoHandleResolveHandlers函数。

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的配置)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/166061.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Js中clientX/Y、offsetX/Y和screenX/Y之间区别

Js中client、offset和screen的区别 前言图文解说实例代码解说 前言 本文主要讲解JavaScript中clientX、clientY、offsetX、offsetY、screenX、screenY之间的区别。 图文解说 在上图中&#xff0c;有三个框&#xff0c;第一个为屏幕&#xff0c;第二个为浏览器大小&#xff0c…

ChatGPT最强?文心一言与ChatGPT对比

对于同一个问题我们分别对文心一言3.5和ChatGPT3.5输出回答&#xff0c;结果如下图&#xff0c;可以看到文心一言的回答更好&#xff0c;文心一言是由百度开发的人工智能语言模型&#xff0c;它的中文理解能力主要是基于百度强大的搜索引擎和自然语言处理技术。文心一言更加注重…

Linux下快速确定目标服务器支持哪些协议和密码套件

实现原理是利用TLS协议的特点和握手过程来进行测试和解析响应来确定目标服务器支持哪些TLS协议和密码套件。 在TLS握手过程中&#xff0c;客户端和服务器会协商并使用相同的TLS协议版本和密码套件来进行通信。通过发送特定的握手请求并分析响应&#xff0c;可以确定目标服务器…

图解API设计风格,看一眼就忘不了了!

点击下方“JavaEdge”&#xff0c;选择“设为星标” 第一时间关注技术干货&#xff01; 免责声明~ 任何文章不要过度深思&#xff01; 万事万物都经不起审视&#xff0c;因为世上没有同样的成长环境&#xff0c;也没有同样的认知水平&#xff0c;更「没有适用于所有人的解决方案…

轻松掌控财务,分析账户花销,明细记录支出情况

随着科技的发展&#xff0c;我们的生活变得越来越智能化。然而&#xff0c;对于许多忙碌的现代人来说&#xff0c;管理财务可能是一件令人头疼的事情。复杂的账单、花销、收入&#xff0c;这些可能会让你感到无从下手。但现在&#xff0c;我们有一个全新的解决方案——一款全新…

马斯克的SpaceX星舰又炸了!发射不久后失联自毁

就在几小时前&#xff0c;马斯克旗下SpaceX 发射了有史以来最强大的星舰&#xff0c;但在发射后不久发生爆炸。 在这次发射尝试中&#xff0c;星舰一二级成功进行了分离&#xff0c;但二级助推器和星舰都发生了快速意料之外的解体。在发射半小时后&#xff0c;SpaceX 宣布二级自…

nginx后端服务器在负载均衡调度中的状态

状态说明 down 状态说明当前的sever暂时不参与负载均衡

腾讯云轻量数据库测评和轻量数据库配置价格表

腾讯云轻量数据库测评&#xff0c;轻量数据库100%兼容MySQL 5.7和8.0&#xff0c;腾讯云提供1C1G20GB、1C1G40GB、1C2G80GB、2C4G120GB、2C8G240GB五种规格轻量数据库&#xff0c;腾讯云百科txybk.com分享腾讯云轻量数据库测评、轻量数据库详细介绍、特性、配置价格和常见问题解…

unordered_map,unordered_set模拟实现

目录 一 . 底层结构--哈希 1.直接定址法 2. 除留余数法 哈希桶 3. 一些定义 二 . 模拟实现哈希表 1.哈希表框架 ​编辑 2.插入 3.查找 4 . 删除 5.解决使用问题 6.完整代码 三 .实现unordered_map, unordered_set 1. 初步实现unordered_map, unordered_set 2.…

【C++】泛型编程 ⑦ ( 模板类常用用法 | 模板类声明 | 模板类调用 | 模板类作为函数参数 )

文章目录 一、类模板基础用法1、类模板声明定义2、类模板使用3、类模板做函数参数 二、完整代码示例1、代码示例2、执行结果 一、类模板基础用法 1、类模板声明定义 上一篇博客中 , 【C】泛型编程 ⑥ ( 类模板 | 类模板语法 | 代码示例 ) 讲解了模板类的基础语法 , 模板类声明如…

三菱PLC 模拟量输出模拟量转换功能块S_RTI(内嵌ST)

模拟量输出模拟量转换功能块S_RTI算法原理和公式介绍请参考下面文章链接: PLC模拟量输出 模拟量转换FC S_RTI-CSDN博客文章浏览阅读5.3k次,点赞2次,收藏11次。1、本文主要展示西门子博途模拟量输出转换的几种方法, 方法1:先展示下自编FC:计算公式如下:intput intput Rea…

实战项目:VB龟兔赛跑游戏+猜数字游戏

文章目录&#xff1a; 一&#xff1a;效果演示 二&#xff1a;实现思路 三&#xff1a;代码实现 form1 效果图 代码 form2 效果图 代码 form3 效果图 代码 一&#xff1a;效果演示 效果图◕‿◕✌✌✌ 代码下载 二&#xff1a;实现思路 窗口1&#xff1a;龟兔赛…

数据结构【DS】特殊二叉树

完全二叉树 叶子结点只能出现在最下层和次下层, 最下层的叶子结点集中在树的左部完全二叉树中, 度为1的节点数 0个或者1个【计算时可以用这个快速计算, 配合&#x1d45b;0&#x1d45b;21】若n为奇数&#xff0c;则分支节点每个都有左右孩子&#xff1b;若n为偶数&#xff0…

Python---return返回值

return返回值 返回值&#xff1a;很多函数在执行完毕后&#xff0c;会通过return关键字返回一个结果给 调用它的位置。 return 英 /rɪˈtɜːn/ n. 回来&#xff0c;返回&#xff1b; 思考&#xff1a;如果一个函数需要两个return (如下所示)&#xff0c;程序如何执行&…

C语言——1.入门须知

文章目录 1.C语言的简要概述1.1.C语言类比自然语言1.2.计算机语言的发展1.3.C语言在当今的地位1.4.C语言的优势和劣势1.4.1.C语言的优势1.4.2.C语言的劣势 2.C语言的应用场景3.C语言的学习路径3.1.学习目的3.2.学习路径3.3.学习资源3.3.1.推荐书籍3.3.2.推荐课程3.3.3.推荐题库…

Nodejs--Express框架使用

目录 一.概念 二.项目目录结构 三.app.js 四.项目需要的中间件 五.Mysql连接 六.日志配置 七.实体模型配置 八.统一结果封装 九.app.js的详细配置 十.自定义登录拦截器 十一.route路由配置 十二.controller处理 十二&#xff1a;静态页面&#xff1a; 十三&#xff…

男子遗失30万天价VERTU唐卡手机,警察2小时“光速”寻回

今天&#xff0c;一则“男子丢失30万元手机女子捡到一位老年机”的新闻迅速冲上热搜第一&#xff0c;引发全网热议。据宿城公安消息&#xff1a;近日&#xff0c;江苏省宿迁市市民王先生在购物时不慎失落了一部价值30万元的全球知名奢侈品VERTU手机&#xff0c;被民警2个多小时…

基于springboot实现家政服务管理平台项目【项目源码+论文说明】计算机毕业设计

摘要 随着家政服务行业的不断发展&#xff0c;家政服务在现实生活中的使用和普及&#xff0c;家政服务行业成为近年内出现的一个新行业&#xff0c;并且能够成为大众广为认可和接受的行为和选择。设计家政服务管理平台的目的就是借助计算机让复杂的销售操作变简单&#xff0c;…

链表的增删改查(python实现)

链表的增删改查 使用python实现链表的增删改查 增 add(val)&#xff1a;在头结点处增加&#xff0c;左插入append(val)&#xff1a;在尾结点处增加&#xff0c;右插入 删 remove_single(target)&#xff1a;删除值为target的第一个节点remove_all(target)&#xff1a;删除值为…

Linux僵尸进程

Linux僵尸进程 一、僵尸进程简介二、僵尸进程的危害三、避免僵尸进程的方法 一、僵尸进程简介 如果父进程比子进程先退出&#xff0c;子进程将被1号进程托管&#xff08;这也是一种让程序在后台运行的方法&#xff09;。如果子进程比父进程先退出&#xff0c;而父进程没有处理…
最新文章