Android7 U盘插拔链路源码全解析(六)广播分发与SystemUI响应

Android7 U盘插拔链路源码全解析(六)广播分发与SystemUI响应 系列目录第一篇全景图与调用链路概览 | 第二篇内核层—USB驱动与uevent | 第三篇Native层—vold与NetlinkManager | 第四篇Framework层(上)—UsbHostManager | 第五篇Framework层(下)—MountService |第六篇广播分发与SystemUI响应| 第七篇应用层—MediaScanner与SAF | 第八篇实战调试与案例分析一、引言前面五篇我们走完了 Kernel → vold → UsbHostManager → MountService 的全程。到第五篇末尾VOLUME_STATE_CHANGED和MEDIA_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 合法性intentverifyBroadcastLocked(intent);// 3. 找到匹配的 BroadcastReceiverListResolveInforeceiverscollectReceiverComponents(intent,resolvedType,callingUid,users);// 4. ★ 创建 BroadcastRecord 并入队BroadcastRecordrnewBroadcastRecord(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静态manifestMEDIA_MOUNTED/MEDIA_UNMOUNTEDMediaScanner 扫描Settings动态 静态MEDIA_MOUNTED存储设置页面刷新DocumentsUI静态manifestMEDIA_MOUNTEDSAF 文件选择器更新第三方 App动态注册MEDIA_MOUNTED/USB_DEVICE_ATTACHED文件管理/设备管理四、SystemUI 响应4.1 方式一StorageNotification通知栏源码路径frameworks/base/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.javapublicclassStorageNotificationextendsSystemUI{Overridepublicvoidstart(){// ★ 动态注册广播接收者IntentFilterfilternewIntentFilter();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);}privatefinalBroadcastReceivermReceivernewBroadcastReceiver(){OverridepublicvoidonReceive(Contextcontext,Intentintent){Stringactionintent.getAction();Uriuriintent.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);// 警告通知}}};}五、广播时序总结完整的时间线以插入为例T0ms 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 响应的完整流程AMS 广播调度MountService 发出的广播经过 AMS 的 BroadcastQueue 并行分发SystemUI 双重通知StorageNotification通知栏 StatusBarView状态栏图标两种监听方式BroadcastReceiver广谱可靠 vs StorageEventListener依赖 vold NDC 回调应用层接收BroadcastReceiver 通过USB_DEVICE_ATTACHED/DETACHED和VOLUME_STATE_CHANGED广播感知 U 盘插拔理解这些机制对于排查U 盘图标不消失或通知栏无反应等问题至关重要。下一篇我们将深入应用层分析 MediaScanner 如何扫描 U 盘文件。