Android7 U盘插拔链路源码全解析(六)广播分发与SystemUI响应
2026/6/26 1:49:52 网站建设 项目流程

系列目录:第一篇:全景图与调用链路概览 | 第二篇:内核层—USB驱动与uevent | 第三篇:Native层—vold与NetlinkManager | 第四篇:Framework层(上)—UsbHostManager | 第五篇:Framework层(下)—MountService |第六篇:广播分发与SystemUI响应| 第七篇:应用层—MediaScanner与SAF | 第八篇:实战调试与案例分析


一、引言

前面五篇我们走完了 Kernel → vold → UsbHostManager → MountService 的全程。到第五篇末尾,VOLUME_STATE_CHANGEDMEDIA_MOUNTED广播已经发出去了。

但这里有一个容易被忽略的事实:

广播发出去 ≠ 用户看到效果。

sendBroadcastAsUser()到通知栏弹出"U 盘已插入",中间还有 AMS 的广播调度、SystemUI 的注册接收、通知构建与展示三个关键环节。

本文聚焦这一"最后一公里"——广播如何分发、哪些应用会收到、SystemUI 如何展示通知。


二、广播分发全链路

2.1 ActivityManagerService 的广播入队

当 MountService 调用sendBroadcastAsUser()后,广播首先进入 AMS:

// ContextImpl → AMS 的跨进程调用publicfinalintbroadcastIntent(IApplicationThreadcaller,Intentintent,StringresolvedType,IIntentReceiverresultTo,intresultCode,StringresultData,BundleresultExtras,String[]requiredPermissions,intappOp,BundlebOptions,booleanserialized,booleansticky,intuserId){// 1. 权限检查enforceNotIsolatedCaller("broadcastIntent");synchronized(this){// 2. 校验 Intent 合法性intent=verifyBroadcastLocked(intent);// 3. 找到匹配的 BroadcastReceiverList<ResolveInfo>receivers=collectReceiverComponents(intent,resolvedType,callingUid,users);// 4. ★ 创建 BroadcastRecord 并入队BroadcastRecordr=newBroadcastRecord(queue,intent,...);// 5. ★ 加入广播队列queue.enqueueParallelBroadcastLocked(r);// 普通广播 → 并行队列// 6. ★ 触发调度queue.scheduleBroadcastsLocked();}}

MountService 发出的广播都是普通广播(非 ordered),走的是并行队列——所有接收者同时收到,无序。

2.2 广播投递到 App 进程

privatevoiddeliverToRegisteredReceiverLocked(BroadcastRecordr,BroadcastFilterfilter,booleanordered,intindex){// 1. 权限检查if(filter.requiredPermission!=null){if(checkComponentPermission(filter.requiredPermission,r.callingPid,r.callingUid,-1,true)!=PERMISSION_GRANTED){return;// 权限不足,跳过}}// 2. ★ 跨进程发送广播try{filter.receiverList.app.thread.scheduleRegisteredReceiver(filter.receiverList.receiver,r.intent,r.resultCode,r.resultData,r.resultExtras,r.ordered,r.initialSticky,r.userId);}catch(RemoteExceptione){// 进程挂了}}

三、接收方全景:谁会收到这些广播

接收者注册方式关注广播作用
SystemUI动态注册MEDIA_MOUNTED/MEDIA_UNMOUNTED通知栏展示
MediaProvider静态(manifest)MEDIA_MOUNTED/MEDIA_UNMOUNTEDMediaScanner 扫描
Settings动态 + 静态MEDIA_MOUNTED存储设置页面刷新
DocumentsUI静态(manifest)MEDIA_MOUNTEDSAF 文件选择器更新
第三方 App动态注册MEDIA_MOUNTED/USB_DEVICE_ATTACHED文件管理/设备管理

四、SystemUI 响应

4.1 方式一:StorageNotification(通知栏)

源码路径frameworks/base/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java

publicclassStorageNotificationextendsSystemUI{@Overridepublicvoidstart(){// ★ 动态注册广播接收者IntentFilterfilter=newIntentFilter();filter.addAction(Intent.ACTION_MEDIA_MOUNTED);filter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);filter.addAction(Intent.ACTION_MEDIA_CHECKING);filter.addAction(Intent.ACTION_MEDIA_BAD_REMOVAL);filter.addAction(Intent.ACTION_MEDIA_EJECT);filter.addDataScheme("file");mContext.registerReceiver(mReceiver,filter);}privatefinalBroadcastReceivermReceiver=newBroadcastReceiver(){@OverridepublicvoidonReceive(Contextcontext,Intentintent){Stringaction=intent.getAction();Uriuri=intent.getData();if(Intent.ACTION_MEDIA_MOUNTED.equals(action)){onMediaMounted(uri,intent);// ★ 显示通知}elseif(Intent.ACTION_MEDIA_UNMOUNTED.equals(action)){onMediaUnmounted(uri,intent);// 取消通知}elseif(Intent.ACTION_MEDIA_BAD_REMOVAL.equals(action)){onMediaBadRemoval(uri,intent);// 警告通知}}};}

五、广播时序总结

完整的时间线(以插入为例):

T=0ms Kernel: uevent KOBJ_ADD T≈50ms vold: NetlinkHandler 捕获 T≈100ms vold: Disk::create() + readPartitions() T≈150ms vold: PublicVolume::create() T≈200ms vold → MountService: {640 disk:8,0 8} T≈200ms vold → MountService: {650 public:8,1 0} T≈250ms MountService: mountVolume() → NDC: "volume mount public:8,1" T≈300ms vold: doMount() → mount(2) → FUSE 启动 T≈350ms vold → MountService: {651 public:8,1 2} (STATE_MOUNTED) T≈360ms MountService: 发送 VOLUME_STATE_CHANGED T≈360ms MountService: 发送 ACTION_MEDIA_MOUNTED T≈380ms SystemUI: StorageNotification 收到广播 → 显示通知 T≈450ms MediaScannerReceiver: 开始扫描文件

六、关键源码文件索引

frameworks/base/packages/SystemUI/ ├── src/com/android/systemui/usb/ │ └── StorageNotification.java ★ 通知栏 USB 通知 │ frameworks/base/services/core/java/com/android/server/am/ ├── BroadcastQueue.java ★ 广播队列管理 └── ActivityManagerService.java ★ 广播分发入口 frameworks/base/core/java/android/os/storage/ ├── StorageEventListener.java ★ Storage 事件监听接口 └── StorageManager.java ★ 公开 API

七、小结

本文拆解了 Android 7 中广播分发与 SystemUI 响应的完整流程:

  1. AMS 广播调度:MountService 发出的广播经过 AMS 的 BroadcastQueue 并行分发
  2. SystemUI 双重通知:StorageNotification(通知栏)+ StatusBarView(状态栏图标)
  3. 两种监听方式:BroadcastReceiver(广谱可靠) vs StorageEventListener(依赖 vold NDC 回调)
  4. 应用层接收:BroadcastReceiver 通过USB_DEVICE_ATTACHED/DETACHEDVOLUME_STATE_CHANGED广播感知 U 盘插拔

理解这些机制对于排查"U 盘图标不消失"或"通知栏无反应"等问题至关重要。下一篇我们将深入应用层,分析 MediaScanner 如何扫描 U 盘文件。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询