SystemUI架构设计

目录

1、什么是SystemUI

2、SystemUI的模块划分

3、SystemUI架构图

SystemUI结构图

SystemUI类图

SystemUI启动流程

4、通知

通知所在的位置

通知的注册流程

通知从系统发送到SystemUI的流程

SystemUI中通知的处理流程 

SystemUI中通知的更新流

SystemUI中通知的添加流程 

 5、状态栏

状态栏结构图

状态栏类图

FragmentHostManager类图

CollapsedStatusBarFragment类图

状态栏的启动流程

信号的初始化流程

6、导航栏

导航栏结构图

导航栏类图

NavigationBarController类图

NavigationBarView类图

导航栏的初始化流程

7、快捷设置

快捷设置结构图

快捷设置类图

​编辑 QSTileHost类图

 快捷设置初始化流程

QSTileHost初始化

8、锁屏

锁屏结构图

锁屏类图

KeyguardViewMediator初始化流程时序图一

KeyguardViewMediator初始化流程时序图二

锁屏显示流程

1、什么是SystemUI

SystemUI(本文基于android10),顾名思义是系统为用户提供的系统级别的信息显示与交互的一套UI组件,所以其功能包罗万象。比如锁屏、状态栏、底部导航栏、最近使用App列表等,大部分功能相互独立,按需启动,后文会继续列出更多功能。在系统源码中,其位置为:frameworks/base/package/SystemUI。尽管从表现形式上看,SystemUI和普通的Android APP有较大的差别,但其本质和普通APP并没有什么差别,也是以apk的形式存在。下面通过图片的方式展示SystemUI有哪些东西。

 

 

 2、SystemUI的模块划分

 

 SystemUI的每一个子类,代表一个功能模块,下面简单的介绍几个,更详细的介绍,需要专门写文章来介绍。

1、Status bars(状态栏)

2、NotificationChannels(通知)

3、KeyguardViewMediator(锁屏)

4、Recents(最近任务面板)

5、VolumeUI(音量UI)

6、PowerUI(电量UI)

7、RingtonePlayer(铃声播放器)

8、PipUI(画中画UI)

9、BiometricDialogImpl(生物识别解锁功能,如指纹解锁、人脸解锁、虹膜解锁等)

3、SystemUI架构图

SystemUI结构图

 SystemUI类图

 SystemUI启动流程

    在android系统的启动流程中,会启动一个Zygote孵化器进程,用来孵化出新的进程,其中SystemService进程就是 被它孵化出来的,之后调用SystemService的run()方法初始化SystemService,初始化调用startOtherServices() ,接着调用startSystmeUI(),startSystmeUI()中会创建启动SystemUIService的intent,然后调用Context的startServiceAsUser(),这个方法里面会使用意图的方式开启 SystemUIService,在SystemUIService的onCreate()方法中调用SystemUIApplication的startServicesIfNeeded(),这个方加载实现SystemUI的模块的字符串列表,通过反射的方式创建这些模块,并调用它们的start()初始化数据,从而完成SystemUI的加载。

4、通知

通知所在的位置

通知的注册流程

    在StatusBar的start()方法中,会通过Dependency获取NotificationListener注册监听。调用NotificationListener的registerAsSystemService(),会调用NotificationListenerWithPlugins的registerAsSystemService(),会调用父类NotificationListenerService的registerAsSystemService(),在这个方法中,首先会创建NotificationListenerWrapper,然后获取NotificationManagerService这个系统服务,接着,调用它的registerListener()将NotificationListenerWrapper注册。这样当NotificationManagerService有通知的时候,会调用NotificationListenerWrapper的onNotificationPosted()方法将通知穿的给SystemUI。

通知从系统发送到SystemUI的流程

       APP通过notify()方法将通知发送给NotificationManager,然后NotificationManager通过AIDL的方式会调用NotificationManagerService的enqueueNotificationWithTag(),收到通知后,NotificationManagerService会对通知做一些兼容处理,比如通知图片的缩放,通知的排序,其中有一个方法需要注意的是在接下来调用的enqueueNotificationInternal(),在这个方法中会打印发送消息是的APP的包名、消息的id、消息。这样我们就可以判断消息是否成功发送到framework。接着会调用NotificationListeners的notifyPostedLocked()方法中遍历所有ManagedServiceInfo,将对象传入notifyPosted(),在这个方法中,会从ManagedServiceInfo上获取INotificationListener,就是注册到NotificationManagerService的NotificationListenerWrapper,然后调用NotificationListenerWrapper的onNotificationPosted()将通知信息和通知的排序快照发送到SystemUI中。

SystemUI中通知的处理流程 

    NotificationManagerService的内部类NotificationListeners调用NotificationListenerWrapper的onNotificationPosted()方法将通知发送给SystemUI,会通过MyHandler发出一个消息MSG_ON_NOTIFICATION_POSTED,接着NotificationListenerService的onNotificationPosted()被调用,其实调用的是NotificationListener,它在SystemUI中,是NotificationListenerService的子类。在这个方法中,会根据情况调用NotificationEntryManager的相关方法,实现删除、排序、更新、添加通知,拿添加来说,会调用NotificationEntryListener的实现类去添加通知

 SystemUI中通知的更新流

SystemUI中通知的添加流程 

       通知的添加是通过NotificationEntryManager的addNotification方法实现的,在这个方法中,会调用addNotificationInternal()实现通知的排序和视图填充,在这个方法中调用abortExistingInflation()方法判断这个通知的视图是否填充过,如果填充就终止填充任务。调用updateRanking()方法更新排名排序和过滤不需要显示的通知,里面的updateRankingAndSort()负责了更新排名排序,它排序的步骤是: 1.遍历mEntries消息列表,通过entry的key在mRankingMap中的mRankings查找有没有对应的Ranking, 如果有把它的数据复制给mTmpRanking,如果没有就跳过。 2.拷贝entry中之前的notification 3.获取Ranking的系统指定的组密钥(mOverrideGroupKey) 4.overrideGroupKey不相同,设置notification的overrideGroupKey,更新新旧NotificationEntry 5.更新排名信息 6.判断通知应是否在高优先级通知部分中,然后把结果设置给entry. updateRanking()方法中通filterAndSort()实现过滤排序: 1.过滤掉不需要显示的通知 2.将需要排序的通知添加到已经过的排序集合 3.排序。 排完序后,在addNotificationInternal()方法中会调用NotificationRowBinderImpl的inflateViews()对通知的视图进行填充,首先会会判断这个通知的视图是否存在,存在就更新,不存在就填充,填充是通过RowInflaterTask的inflate()方法实现的。接着在addNotificationInternal()方法中会调用abortExistingInflation()方法,在这个方法中,通过通知的key在mPendingNotifications(待处理的通知列表)和mNotificationData (当前需要显示的通知列表)中查找,如果有证明这个消息的布局填充过了,就会调用RowInflaterTask的abort方法取消填充任务。接着在addNotificationInternal()方法中会遍历所有的NotificationEntryListener调用onPendingEntryAdded()方法将通知分发出去。

 5、状态栏

状态栏结构图

状态栏类图

 FragmentHostManager类图

 CollapsedStatusBarFragment类图

状态栏的启动流程

       SystemUI在初始化的时候,通过反射的方式创建SystemBars,在它的start()方法中,会调用createStatusBarFromConfig(),会读取一个字符串,这个字符串是可以配置的,原生系统配置的是StatusBar,通过反射的方式加载stautsBar,并调用start()初始化,start()里面会createAndAddWindows()接着调用makeStatusBarView(),获取StatusBarWindowController,将mStatusBarWindow添加到WindowMananger中,实现窗口添加。在makeStatusBarView()创建一个SystemUI顶级布局,这个布局是super_status_bar,并且赋值给mStatusBarWindow,接下来在makeStatusBarView()方法中,会通过FragmentHostManager以事物方式将CollapsedStatusBarFragment填充到status_bar_container布局中,在CollapsedStatusBarFragment的onCreateView()方法中会填充一个status_bar的布局,它就是状态栏的布局,在onViewCreated()中,会陆续加载系统图标、电池、紧急密文和操作者名称等等。

信号的初始化流程

      在CollapsedStatusBarFragment的initEmergencyCryptkeeperText(),判断有没有紧急密文信息(NetworkController.hasEmergencyCryptKeeperText()),如果有,加载紧急密文信息布局,添加信号回调,如果没有移除载紧急密文信息布局。调用NetworkControllerImpl的addCallback()方法来添加回调,这个方法中,添加的Callback会设置观察者,设置飞行模式,设置是否有sim卡,然后WiFi信号控制器、以太网控信号制器、移动信号控制器会将Callback传入到它们的notifyListeners()方法中,notifyListeners()方法中会调用信号回调的setMobileDataIndicators()方法。是用来修改了状态,更新自己的图标,比如CollapsedStatusBarFragment实现了这个回调,会更新飞行模式的显示状态。

6、导航栏

导航栏结构图

 导航栏类图

 NavigationBarController类图

 NavigationBarView类图

 导航栏的初始化流程

     在StatusBar的makeStatusBarView方法中调用createNavigationBar();里面会调用NavigationBarFragment.create(),填充一个navigation_bar_window的布局它是一个帧布局,被windowManager添加,这个被填充的View会添加一个附加在windows上的监听,当监听方法被回调的时候,通过FragmentHostManager以事物的方式,将NavigationBarFragment添加到这个帧布局中。在onCreateView()中会填充navigation_bar布局,里面有一个NavigationBarInflaterView,其实所有界面初始工作是这个里面进行的。NavigationBarInflaterView的构造方法中,会创建两个布局填充器,一个是横布局填充器,一个是竖布局填充器。在onFinishInflate()调用inflateChildren()创建横竖两个布局,调用clearViews() 清除mButtonDispatchers数据,横竖两个布局的子View。调用getDefaultLayout()获取默认的配置字符串,这个字符串是配置NavigationBar的按钮信息。调用inflateLayout()把字符串切割分成三类,然后调用inflateButtons(),inflateButton(),createView()根据字符串加载不同布局,这样NavigationBar加载完成。

7、快捷设置

快捷设置结构图

 

快捷设置类图

 QSTileHost类图

 快捷设置初始化流程

      在StatusBar的makeStatusBarView()方法中调用createDefaultQSFragment(),使用fragmentHostManager以注入的方式创建QSFragment,填充帧布局qs_frame,在QSFragment的构造函数中,会传到一个初始化的QSTileHost,将它设置给QSFragment。QSTileHost的构造方法中会使用mainHandler post 一个 Runnable,run()方法中会TunerService的addTunable(),这个方法会回调QSTileHost的onTuningChanged(),这里面会调用loadTileSpecs读取配置字符串列表quick_settings_tiles_default,这里面配置的是默认显示tile。接着调用createTile(),它里面会调用QSFactoryImpl的createTile()根据字符串生成不同的Tile

QSTileHost初始化

 

8、锁屏

锁屏结构图

锁屏类图

 

KeyguardViewMediator初始化流程时序图一

       WakeLock计数机制(setReferenceCounted): 在创建了PowerManager.WakeLock 后,有两种机制,第一种是不计数锁机制,另一种是计数锁机制。这可以通过setReferenceCounted( boolean value) 来指定,默认为计数机制。这两种机制的区别在于,前者无论acquire() 了多少次,只要通过一次release() 即可解锁。而后者正真解锁是在(--count == 0 )的时候,同样当(count == 0) 的时候才会去申请加锁,其他情况下isHeld 状态是不会改变的。所以PowerManager.WakeLock 的计数机制并不是正真意义上的对每次请求进行申请/释放每一把锁,它只是对同一把锁被申请/释放的次数进行了统计。

 KeyguardViewMediator初始化流程时序图二

 

      SystemUI在初始化的时候,会通过SystemUIApplication的startServicesIfNeeded()创建KeyguardViewMediator实例,调用start()初始化。在start()中,setupLocked()方法中会注册开机广播和延时锁屏广播。获取锁屏声音和解锁声音,通过config_lockSoundVolumeDb来获取配置的锁屏/解锁的声音大小。 

锁屏显示流程

     锁屏的显示流程是从PhoneWindowManager调用systemBooted()方法开始的,它里面会调用bindKeyguard()方法,bindKeyguard()里面会调用KeyguardServiceDelegate的bindService()去绑定KeyguardService,KeyguardService的onCreate()中会调用SystemUIApplication的startServicesIfNeeded()初始化SystemUI,接着获取初始化的KeyguardViewMediator。当KeyguardServiceDelegate绑定KeyguardService成功后,会在onServiceConnected()方法中调用onSystemReady()告诉KeyguardService系统已经准备好了,然后KeyguardService会检查有没有控制锁屏的权限,如果没有报异常,如果有则会调用KeyguardViewMediator的onSystemReady()方法。发送SYSTEM_READY消息,调用handleSystemReady(),在这个方法中会调用WakeLock的acquire(),让上手机保持亮屏,直到显示锁屏界面为止。发送SHOW消息,调用handleShow()方法通知系统显示锁屏界面了,调用StatusBarKeyguardViewManager的show()根据实际情况,来显示锁屏页面还是锁屏密码页面。

如果大家觉得看网页不够方法,可以下载源文件,标题下面的PPTX文档

  • 13
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值