本篇只分析SystemUI的加载过程和SystemUI的其中的一个模块StatusBar的小模块NavigationBar,以Android6.0代码进行分析
1 2 3 4 5 6 7 8 9 10 11 |
|
跟StatusBar相关的服务为SystemUIService
,我们查看SystemUIService
源码
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
分析SystemUIService
代码,可以知道SystemUI主要做了两件事
获取Application
对象加载SystemUI相关的类,这个等下分析SystemUIApplication
代码可以知道 dump
打印SystenUISerice
运行过程中相关的堆栈信息
那么SystemUIService
又是哪里开始启动的呢?竟然SystemUIService是个服务,那么启动服务要么就是startService
要么就是bindService进行启动,其启动方式则需要通过Intent来传入类名或者包名,因此在源码中搜索SystemUIService可以对比发现,它在
frameworks\base\services\java\com\android\server\SystemServer.java中进行启动
?
1 2 3 4 5 6 7 |
|
在SystemServer的run方法中startOtherServices来启动SystemUIService服务,至于SystemServer则涉及到Android的启动流程,其大概流程为
?
1 2 |
|
SystemServer中会初始化一些Android的java层的服务,如ActivityManagerService、WindowManagerService等
这里SystemUI的加载过程就到此告一段落了,下面分析StatusBar的加载流程
上面讲到在SystemUIService的onCreate中获取SystemUIApplication对象来初始化SystemUI相关的类,这些类里面就包括了StatusBar相关的类,我们查看SystemUIApplication类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
在SystemUIApplication的onCreate中主要做了
设置主题(这个会影响其SystemUI的界面显示效果) 注册开机广播,设置标志位
SystemUIService中的onCreate启动了这个方法,我们着重分析这个方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
|
这个方法中,首先判断mServicesStarted
标志为来判断SystemUI相关的服务是否启动,同时根据系统配置文件来检查ActivityManagerService是否finishBooting,然后通过类加载机制来初始化SERVICES数组里面相关的类加入mServices中,然后start
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
从mServices和SERVICES的定义可以发现SERVICES是一组包含全路径的相关的类,这些类包含一些我们常见的TunerService(定制状态栏服务)、
KeyguardViewMediator(锁屏相关)、Recents(近期任务)、VolumeUI(音量条)、SystemBars(状态栏)、StorageNotification(通知栏)、PowerUI(电源相关)、RingtonePlayer(铃声播放相关)类,它们都是继承与SystemUI抽象类,现在只分析StatusBar相关的SystemBars类
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
|
我们先从start方法开始分析
?
1 2 3 4 5 6 7 8 |
|
这里实例化ServiceMonitor类start,继续分析ServiceMonitor
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
ServiceMOnitor是一个监听Settings.Secure.BAR_SERVICE_COMPONENT是否改变的类,在start中通过监听系统系统时应用的变化来启动服务
?
1 2 3 4 5 6 7 8 9 |
|
应用装载时,通过Handler发送MSG_PACKAGE_INTENT消息事件,我们查看Handler消息回调
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
|
当我们SystemUI应用检测到有新应用装载时,会发送MSG_START_SERVICE消息来启动服务,我们接着分析Handler的回调MSG_START_SERVICE消息
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
首先从ContentProvider数据库中取得包名,如果没有启动,则回调CallBaback的onNoService服务,否则发送MSG_CONTINUE_START_SERVICE消息启动服务
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
至此可以知道,当远程服务没有启动时,会回调SystemBar的onNoService
函数,我们回到SystemBar,分析onNoService
函数
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
上面分析可以得知,当远程服务没有启动时,首先从xml文件读取要启动的类名,我们来查看这个xml文件
res\values\config.xml
?
1 2 3 |
|
从上面可以知道,最终程序会加载PhoneStatusBar这个类,接下来分析PhoneStatusBar
首先我们从上面分析得知,当实例化PhoneStatusBar类后会调用start方法,我们就从PhoneStatusBar的start方法开始分析
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
|
我们接着分析PhoneStatusBar父类的BaseStatusBar的start方法
start
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
|
BaseStatusBar关于StatusBar相关的最主要是调用了
createAndAddWindows
方法,我们看下这个方法的定义
?
1 2 3 4 5 |
|
这是一个抽象方法,也就是说,它会回调到子类的createAndAddWindows的实现方法中,我们重新回到PhoneStatusBar中,找到createAndAddWindows的方法实现
createAndAddWindows
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 |
|
因为这块涉及的太广,所以接下来只分析StatusBar相关的一块,以导航栏为例进行讲解,我们重新回到PhoneStatusBar的start方法中,找到导航栏这块,发现它是调用
addNavigationBar
函数,所以我们查看这个函数:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
我们根据上面的注释来进行分析,主要内容有
1. 导航栏布局的创建
2. 导航栏布局分析及加载
3. 导航栏LayoutParams分析
导航栏布局的创建
在PhoneStatusBar的makeStatusBarView方法中,我们可以看到导航栏是怎么创建的
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
|
首先由mWindowManagerService的hasNavigationBar来决定是否显示导航栏,同时通过加载navigation_bar(多窗口加载navigation_bar_float_window)布局来显示导航栏,我们来查看hasNavigationBar方法,因为mWidnwoManagerService是IWindowManagerService由PhoneWindowManager进行调用:
frameworks\base\service\core\java\com\android\server\PhoneWindowManager.java
PhoneWindowManager
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
从framework\base\core\res\res\valuse\config.xml中获取mHashNavigationBar的值
?
1 2 3 |
|
然后从系统配置位置中取qemu.hw.mainkeys的值,所以这里给我们提供了一个隐藏状态栏的新思路,除了在createAndAddWindows中注释掉addNavigationBar函数外,我们也可以通过修改framework下的config.xml的config_showNavigationBar的值和修改系统配置文件的值来达到隐藏状态栏的目的
导航栏布局分析及加载
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
导航栏布局的确切显示在prepareNavigationBarView中的mNavigationBarView.reorient();来决定,我们查看reorient方法
reorient
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
导航栏的显示由屏幕的方向来决定,而导航栏有两种不同的显示方式,横向显示和竖向显示,我们可以从mRotatedViews进行追查到
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
布局加载完成后,会回调onFinishInflate方法,在这方法中对屏幕的几个方向初始化4个导航栏view,其中0和180为横向布局,90和270为纵向布局,我们可以从导航栏(NavigationBarView)布局文件中可以看出
res\layout\navigation_bar.xml和res\layout\navigation_bar
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
|
所以说,当我们的需求为0或者90度方向,要想导航栏纵向显示,我们只需要修改成导航栏纵向布局即可,当然我们也可以按需求来隐藏某些导航栏按键(布局中设置某些控件为gone)
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
导航栏LayoutParams分析
我们回到PhoneStatusBar的addNavigationBar继续分析最后一个导航栏的LayoutParameters,它决定了导航栏在窗体上的显示位置
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
上面的LayoutParames决定了导航栏在窗体的大小(受父布局影响)和显示的位置效果,当我们的需求如果要把导航栏显示在屏幕的右边时,我们可以在上面代码中加上下面一句
1 |
|
SystemUI包含了太多内容,本篇只是分析了SystemUI的加载流程,同时初步的分析了StatusBar中一个小模块NavigationBar,后续会针对SystemUI的其他模块进行分析。