当前位置: 首页 > news >正文

【在aosp中,那些情况下可以拉起蓝牙服务进程】

1. 背景

在我平时 对 车机 蓝牙的维护中, 经常遇到一个问题就是:

  1. 是谁打开了蓝牙?
  2. 是谁将蓝牙进程拉起来的?

这里有人会问, 打开蓝牙时, 不就把 蓝牙进程拉起来了呀,只要 搞清楚是谁打开的蓝牙,不就知道 进程是被谁拉起来的。为啥还要专门需要搞清楚,他俩的区别呢?

不知道小伙伴有没有遇到一种情况是, 蓝牙进程被拉起来了。 但是蓝牙并没有被打开。如果有遇到 这种情况,但是不知道为何的。 那你就不要着急划走,仔细听笨叔给你娓娓道来。 看完绝对有收获。

2. 蓝牙被打开的几种情况:

1. 系统侧

我们的系统中, 会在如下几种情况下自动打开蓝牙:

  1. BluetoothManagerService 中回去打开蓝牙:
    1. 上次下电前,蓝牙处于打开状态。 再次上电后 BluetoothManagerService 会帮我们再次打开蓝牙。否则不会自动开蓝牙
    2. 上电时,如果 没有获取到 车机蓝牙的名字 和 蓝牙mac地址, 这里也会去打开蓝牙, 但是 获取到之后,蓝牙进程就结束退出了
  2. 休眠唤醒后, car.server 中根据电源状态,会去根据,休眠前是否开蓝牙。来决定是否打开蓝牙。

1. BluetoothManagerService 中自动打开蓝牙

// service/java/com/android/server/bluetooth/BluetoothManagerService.javapublic void handleOnBootPhase() {if (DBG) {Log.d(TAG, "Bluetooth boot completed");}mAppOps = mContext.getSystemService(AppOpsManager.class);if (!isBluetoothAvailable()) {if (DBG) {Log.e(TAG, "enable(): not enabling - bluetooth not available");}return;}final boolean isBluetoothDisallowed = isBluetoothDisallowed();if (isBluetoothDisallowed) {return;}final boolean isSafeMode = mContext.getPackageManager().isSafeMode();if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()/*如果上次os 关机之前蓝牙是打开的*/ && !isSafeMode) {if (DBG) {Log.d(TAG, "Auto-enabling Bluetooth.");}// 这个地方就会自动 打开蓝牙sendEnableMsg(mQuietEnableExternal,BluetoothProtoEnums.ENABLE_DISABLE_REASON_SYSTEM_BOOT,mContext.getPackageName());} else if (!isNameAndAddressSet()) {if (DBG) {Log.d(TAG, "Getting adapter name and address");}// 如果 没有获取到 车机蓝牙的名字 和 蓝牙mac地址,  这里也会去打开蓝牙, 但是 获取到之后,蓝牙进程就结束退出了Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);mHandler.sendMessage(getMsg);}mBluetoothModeChangeHelper = new BluetoothModeChangeHelper(mContext);if (mBluetoothAirplaneModeListener != null) {mBluetoothAirplaneModeListener.start(mBluetoothModeChangeHelper);}registerForProvisioningStateChange();mBluetoothDeviceConfigListener = new BluetoothDeviceConfigListener(this, DBG, mContext);}

这里记录一下 上次下电前,处于打开蓝牙的状态。 并且本次开机也获取到蓝牙的名字和mac地址的日志:


01-01 21:11:57.149870  1742  1742 I BluetoothManagerService: BluetoothManagerService(): mAdapterIndex = 0, mDualAdapterMode = disabled# 这里已经加载成功加载了 蓝牙名字和 mac 地址
01-01 21:11:57.150666  1742  1742 D BluetoothManagerService: Loading stored name and address
01-01 21:11:57.150756  1742  1742 D BluetoothManagerService: Stored bluetooth Name=Mycar95812,Address=EC:A7:AD:23:7C:57# 上一次 掉电前 蓝牙是 打开状态。所以本次,上电依然保持原状。打开蓝牙
01-01 21:11:57.150803  1742  1742 D BluetoothManagerService: Bluetooth persisted state: 1
01-01 21:11:57.150813  1742  1742 D BluetoothManagerService: Startup: Bluetooth persisted state is ON.
01-01 21:11:57.151045  1742  1742 D BluetoothManagerService: Detected SystemUiUid: 10034
01-01 21:11:57.609194  1742  2028 D BluetoothManagerService: Trying to bind to profile: 2, while Bluetooth was disabled
01-01 21:11:57.770450  1742  1742 D BluetoothManagerService: Bluetooth boot completed
01-01 21:11:57.770639  1742  1742 D BluetoothManagerService: Auto-enabling Bluetooth.01-01 21:11:57.770788  1742  1978 D BluetoothManagerService: MESSAGE_ENABLE(0): mBluetooth = null
01-01 21:11:57.770850  1742  1978 D BluetoothManagerService: Persisting Bluetooth Setting: 1
01-01 21:11:57.771023  1742  1742 D BluetoothManagerService: Trying to bind to profile: 2, while Bluetooth was disabled# bind 蓝牙服务
01-01 21:11:57.771165  1742  1978 D BluetoothManagerService: Start binding to the Bluetooth service with intent=Intent { act=android.bluetooth.IBluetooth cmp=com.android.bluetooth/.btservice.AdapterService }# 此时system_sever 就会去 拉起一个 蓝牙进程,  2202 就是新进程的进程号
01-01 21:11:57.964464  1742  1910 I am_proc_start: [0,2202,1002,com.android.bluetooth,service,{com.android.bluetooth/com.android.bluetooth.btservice.AdapterService}]# -----蓝牙服务进程-------------01-01 21:11:58.073940  2202  2202 D BluetoothAdapterApp: Loading JNI Library
01-01 21:11:58.161035  2202  2202 D BluetoothAdapterApp: REFCOUNT: Constructed com.android.bluetooth.btservice.AdapterApp@9c3a925 Instance Count = 1
01-01 21:11:58.173296  2202  2202 D BluetoothAdapterApp: onCreate01-01 21:11:58.231689  2202  2202 D BluetoothAdapterService: onCreate()
01-01 21:11:58.372011  2202  2202 D BluetoothAdapterService: onBind()
01-01 21:11:58.420819  2202  2254 D BluetoothAdapterService: enable() - Enable called with quiet mode status =  false

2. car.server 中自动打开蓝牙

在 车机中, 冷启动打开蓝牙的逻辑只在 BluetoothManagerService 中处理。

那休眠唤醒后, 是否打开蓝牙。这个逻辑只在 car.server 中处理。 那 car.server 如何区分是冷启动还是 休眠唤醒呢?

  • 关键在 mUserManager.isUserUnlocked 的判断中。
    • 如果 是冷启动 mUserManager.isUserUnlocked 返回 false
    • 如果是 休眠再唤醒后, mUserManager.isUserUnlocked 返回 true

// service/src/com/android/car/bluetooth/BluetoothPowerPolicy.javaprivate final ICarPowerPolicyListener mPowerPolicyListener =new ICarPowerPolicyListener.Stub() {@Overridepublic void onPolicyChanged(CarPowerPolicy appliedPolicy,CarPowerPolicy accumulatedPolicy) {Slogf.d(TAG, "onPolicyChanged: " + appliedPolicy + " " + accumulatedPolicy);boolean isOn = accumulatedPolicy.isComponentEnabled(PowerComponent.BLUETOOTH);if (!mUserManager.isUserUnlocked(UserHandle.of(mUserId))) {if (DBG) {Slogf.d(TAG, "User %d is locked, ignoring bluetooth power change %s",mUserId, (isOn ? "on" : "off"));}return;}if (isOn) {if (isBluetoothPersistedOn()) { // 如果休眠时处于打开蓝牙的状态, 那么此时唤醒后,回去打开蓝牙enableBluetooth();}} else {// we'll turn off Bluetooth to disconnect devices and better the "off"// illusionif (DBG) {Slogf.d(TAG, "Car power policy turns off bluetooth."+ " Disable bluetooth adapter");}disableBluetooth();}}};private void enableBluetooth() {mBluetoothAdapter.enable();}private void disableBluetooth() {mBluetoothAdapter.disable();}
  • 这里可以看到, car.server 打开关闭蓝牙,操作和应用侧是一样的。
1. mUserManager.isUserUnlocked

单独领出来讲解一下这块内容:

  • 这段代码的作用是:在用户未解锁的情况下,忽略蓝牙电源状态的更改请求
if (!mUserManager.isUserUnlocked(UserHandle.of(mUserId))) {if (DBG) {Slogf.d(TAG, "User %d is locked, ignoring bluetooth power change %s",mUserId, (isOn ? "on" : "off"));}return;}
  • mUserManager.isUserUnlocked(...):判断指定用户是否已解锁(unlocked)

    • Android 系统中,每个用户的加密存储在设备刚启动时默认是锁定的,只有在用户输入密码(解锁设备)后,系统才会解锁该用户的数据。
  • UserHandle.of(mUserId):将用户 ID 包装成 UserHandle 对象。

  • !:取反,意思是“如果用户未解锁”。

这段代码逻辑可以总结为:

如果当前用户尚未解锁(即设备还在锁屏状态下),则忽略此次蓝牙开关请求,不做任何处理。
这是 Android 为了保护加密用户数据而设立的一种安全机制。

1. 背景解释

Android 从 Android 7.0(Nougat)开始引入了“文件加密”的机制,其中包括:

  • Direct Boot(直接启动)模式:设备启动后,在用户解锁前,系统处于一个限制状态,只有少数服务能运行。
  • 所有用户数据默认处于加密状态,直到用户解锁。

因此,在某些系统服务中,比如 Bluetooth、Wi-Fi 等,如果用户未解锁,尝试操作这些功能可能会被系统主动忽略或延迟处理


2.实际应用场景

假设手机/车机刚启动,系统还没输入锁屏密码。在这种状态下,蓝牙服务检测到用户未解锁,就会跳过蓝牙的开关逻辑,避免在“加密用户空间”尚未可用时执行敏感操作。

2. 上层 app 侧

app 侧打开蓝牙,这个情况就很多了。 不同的产品需求,上层 app 实现都不一样。 但是对于我们来说这个都很好筛。 我这里分享一下如何去筛这些东东。

1. app 侧打开蓝牙

app 打开蓝牙很简单,都是统一调用:BluetoothAdapter.enable();

我们来看看 应用侧调用完 enable 后,会有那些日志打印:


# 这里会 详细记录: 是 com.xxxx.xxx 应用,调用了 BluetoothAdapter.enable。 根据这个信息就能知道是谁打开了蓝牙
01-01 21:26:59.480246  1693  4049 D BluetoothManagerService: enable(com.xxxx.xxx):  mBluetooth =null mBinding = false mState = OFF mAdapterIndex = 0
01-01 21:26:59.488920  1693  1989 D BluetoothManagerService: MESSAGE_ENABLE(0): mBluetooth = null
01-01 21:26:59.489008  1693  1989 D BluetoothManagerService: Persisting Bluetooth Setting: 1
01-01 21:26:59.489355  1693  1989 D BluetoothManagerService: Start binding to the Bluetooth service with intent=Intent { act=android.bluetooth.IBluetooth cmp=com.android.bluetooth/.btservice.AdapterService }
01-01 21:26:59.503157  1693  4049 D BluetoothManagerService: enable returning# 此时创建了 4958 服务进程
01-01 21:26:59.548853  1693  1879 I am_proc_start: [0,4958,1002,com.android.bluetooth,service,{com.android.bluetooth/com.android.bluetooth.btservice.AdapterService}]#--------蓝牙服务进程---------
01-01 21:27:00.044515  4958  4958 D BluetoothAdapterApp: Loading JNI Library

3. 蓝牙进程被拉起的几种情况

首先, 第二章节中介绍的 蓝牙打开的几种情况中,肯定是可以拉起我们的蓝牙进程的。这个毋庸置疑。这里不是重点。

重点, 介绍一下。 通过 ps -aux 是可以看到蓝牙进程的, 但是此时蓝牙是没有打开的情况。

先看一下日志:


# 本次冷启动过后, 启动 BluetoothManagerService 服务
05-13 16:41:17.658908  1644  1644 I BluetoothManagerService: BluetoothManagerService(): mAdapterIndex = 0, mDualAdapterMode = disabled# 此时获取到了 蓝牙的名字和 mac 地址
05-13 16:41:17.659866  1644  1644 D BluetoothManagerService: Loading stored name and address
05-13 16:41:17.659985  1644  1644 D BluetoothManagerService: Stored bluetooth Name=Mycar27839,Address=EC:A7:AD:1D:F3:8A# 这里发现 上次下电之前蓝牙时关闭的, 所以此时 BluetoothManagerService 没有主动去打开蓝牙
05-13 16:41:17.660054  1644  1644 D BluetoothManagerService: Bluetooth persisted state: 0
05-13 16:41:17.660275  1644  1644 D BluetoothManagerService: Detected SystemUiUid: 10034
05-13 16:41:18.375452  1644  1644 D BluetoothManagerService: Bluetooth boot completed05-13 16:41:22.953491  1644  1812 I am_proc_start: [0,5385,1002,com.android.bluetooth,service,{com.android.bluetooth/com.android.bluetooth.avrcpcontroller.BluetoothMediaBrowserService}]# --------蓝牙进程起来了------------------
05-13 16:41:23.353795  5385  5385 D BluetoothAdapterApp: Loading JNI Library
  • 这里就让人很疑惑? 也没有 BluetoothManagerService: enable 这个log. 也看不出来是被那个应用拉起来的。
    • 那这个问题该如何 check?

我们可以从如下日志展开

05-13 16:41:22.953491  1644  1812 I am_proc_start: [0,5385,1002,com.android.bluetooth,service,{com.android.bluetooth/com.android.bluetooth.avrcpcontroller.BluetoothMediaBrowserService}]

1. am_proc_start 标签介绍

am_proc_start 标签的格式如下:

am_proc_start: [caller_uid, pid, uid, package_name, component_type, {component}]

1. 我们可以得出哪些结论?

1. 启动的是哪个进程?
  • 进程名是 com.android.bluetooth,对应 Bluetooth 模块。
2. 启动的组件是什么类型?
  • service 表示这是通过 Context.startService()bindService() 启动的一个 服务
3. 启动了哪个组件?
  • BluetoothMediaBrowserService 是一个完整类名,表明此服务 是负责蓝牙 AVRCP(媒体控制)相关的浏览器功能。
4. 启动者是谁?
  • caller_uid=0 通常意味着这是 系统进程(root) 发起的启动动作。

  • uid=1002 表示进程运行在 system 用户下,具备一定权限,通常是系统服务。


2.能不能判断是 Activity?

可以。am_proc_start 第五个字段明确告诉你组件类型:

类型字段值含义
activity是一个 Activity
service是一个 Service
broadcast是广播接收器
provider是一个 ContentProvider
unknown无法判断

所以在你的例子中,service 明确表示这个进程是为了运行某个 服务 而被启动的,而不是 Activity


3. 应用场景

通过监控 am_proc_start,我们可以实现:

  • 分析系统或 App 进程启动时机
  • 判断某个组件(服务、Activity)是否真正启动
  • 诊断系统启动过程中的服务依赖或错误
  • 逆向分析某个服务或功能何时、由谁触发启动

2. 那此时我们的蓝牙进程是被谁拉起来的?

思路如下:

  • 每一个被 system_server 来起来的进程,都会有如下日志打印
05-13 16:41:22.953491  1644  1812 I am_proc_start: [0,5385,1002,com.android.bluetooth,service,{com.android.bluetooth/com.android.bluetooth.avrcpcontroller.BluetoothMediaBrowserService}]

从上面的日志我们可以分析出如下信息:

字段序号字段值含义说明
00调用方的 UID,一般为 0 表示 system 进程启动的
15385该进程的 PID(Process ID)
21002启动该进程的用户 ID,代表系统用户(通常 system UID)
3com.android.bluetooth启动的应用包名
4service启动的组件类型,这里说明是一个 Service 被启动,非 Activity 或 BroadcastReceiver 等
5{com.android.bluetooth/com.android.bluetooth.avrcpcontroller.BluetoothMediaBrowserService}被启动的具体组件(格式为 {package/component})是一个具体的服务类

可以很明确的看到,当前蓝牙进程是因为 {com.android.bluetooth/com.android.bluetooth.avrcpcontroller.BluetoothMediaBrowserService} 服务被拉起来的。

service 表示这是通过 Context.startService()bindService() 启动的一个 服务

这个服务的拉起和 蓝牙音乐app 相关。 一般情况下蓝牙音乐app 为了实现蓝牙音乐的控制。需要 MediaBrowser 服务。

  • app 侧可以通过如下代码拉起 蓝牙的 BluetoothMediaBrowserService 服务。
/*** 连接媒体浏览器服务* 1、android-7(N版本) ~ android-9(P版本):* String package = "com.android.bluetooth";* String class = "com.android.bluetooth.a2dpsink.mbs.A2dpMediaBrowserService"* <p>* 2、Android10以上的版本服务包名和文件名分别为:* String package = "com.android.bluetooth";* String class = "com.android.bluetooth.avrcpcontroller.BluetoothMediaBrowserService"*/private void connectMediaBrowser() {//1.绑定服务,Android10以上的版本服务名称为ComponentName componentName = new ComponentName("com.android.bluetooth", "com.android.bluetooth.avrcpcontroller.BluetoothMediaBrowserService");// 2.创建MediaBrowsermMediaBrowser = new MediaBrowser(getContext(), componentName, connectionCallback, null);//3.连接MediaBrowsermMediaBrowser.connect();}

3. 此时我们的蓝牙可用吗?

此时我们的蓝牙 是否可用?

  • 我们知道我们的蓝牙进程此时是由 BluetoothMediaBrowserService 拉起来的。 而蓝牙如果功能上要使用,需要拉起 AdapterService 服务。所以此时蓝牙并没有打开。
  • 蓝牙没有被打开,那么对应的芯片的电也没有上。 hal进程中也没有对应的交互。协议栈也不会启动。

4.小结

看到这里,不知道 各位有没有学废啊?

  • 其实关键在于 对 am_proc_start 的理解。

// 蓝牙打开时:
01-01 21:11:57.964464  1742  1910 I am_proc_start: [0,2202,1002,com.android.bluetooth,service,{com.android.bluetooth/com.android.bluetooth.btservice.AdapterService}]// 蓝牙进程被拉起, 但是蓝牙没有被打开
05-13 16:41:22.953491  1644  1812 I am_proc_start: [0,5385,1002,com.android.bluetooth,service,{com.android.bluetooth/com.android.bluetooth.avrcpcontroller.BluetoothMediaBrowserService}]

相关文章:

  • 使用Frp搭建内网穿透,外网也可以访问本地电脑。
  • 第三十三节:特征检测与描述-Shi-Tomasi 角点检测
  • Linux》Ubuntu》安装Harbor 私有仓库
  • 自制操作系统(二、输入输出和shell的简易实现)
  • MySQL中表的增删改查(CRUD)
  • SQL练习(6/81)
  • Day11-苍穹外卖(数据统计篇)
  • 大规模CFD仿真计算中,SIMPLE或者PISO算法中加速压力场方程迭代求解
  • 股票配资平台开发如何判断交易策略是否可靠
  • 实例分割AI数据标注 ISAT自动标注工具使用方法
  • 【未】[启发式算法]含初始解要求的有:TS, GA, SA, DPSO
  • 计算机网络 : 网络基础
  • NAT转换和ICMP
  • AGI大模型(19):下载模型到本地之ModelScope(魔搭社区)
  • 运维实施31-NFS服务
  • 研华服务器ASMB-825主板无法识别PCIE-USB卡(笔记本)
  • 牛客网NC22222:超半的数
  • 【云实验】搭建个人网盘实验
  • leetcode0215. 数组中的第K个最大元素-medium
  • 1基·2台·3空间·6主体——蓝象智联解码可信数据空间的“数智密码”
  • 一条铺过11年时光的科学红毯,丈量上海科创的“长宽高”
  • 词条数量大幅扩充,《辞海》第八版启动编纂
  • 新修订的《餐饮业促进和经营管理办法》公布,商务部解读
  • 新版城市规划体检评估解读:把城市安全韧性摆在更加突出位置
  • 蒋圣龙突遭伤病出战世预赛存疑,国足生死战后防线严重减员
  • 龚正会见哥伦比亚总统佩特罗