Android核心程序之SystemUI - (一)开篇
UI是实现用户交互的重要途径之一,而Android中一个重要的UI元素就是SystemUI,本文分析基于Android 5.1,分析SystemUI的启动及运行过程。
SystemUI源代码所在路径为:
frameworks/base/packages/SystemUI
查看AndroidManifest.xml,整理软件实现思路。
包名为
com.android.systemuipackage="com.android.systemui"
分配的userID为
android.uid.systemuiandroid:sharedUserId="android.uid.systemui"
标明此应用为系统核心App
coreApp="true"
接下来是一系列的权限声明,包括
Networking and telephony,Physical hardware,ActivityManager,WindowManager,DreamManager,Alarm clocks,Keyguard,Recents,Wifi Display,Screen Capturing等方面的权限。接下来看 <application></application>中的内容:
此应用不会轻易被kill,并且会自动启动
android:persistent="true"
用户数据不可清除
android:allowClearUserData="false"
启用硬件加速
android:hardwareAccelerated="true"
设置系统进程
android:process="com.android.systemui"
其他属性为常规属性,很多app都会有,在此不再赘述。
接下来是分析SystemUI的重点,看下都涉及到了哪些activity,service和receiver。
activity:
.usb.UsbStorageActivitycom.android.internal.app.ExternalMediaFormatActivity.recent.RecentsActivity.recents.RecentsActivity.usb.UsbConfirmActivity.usb.UsbPermissionActivity.usb.UsbResolverActivity.usb.UsbAccessoryUriActivity.usb.UsbDebuggingActivity.net.NetworkOverLimitActivity.media.MediaProjectionPermissionActivity.DessertCase.egg.LLandActivity.Somnambulator.settings.BrightnessDialog
service:
SystemUIService.screenshot.TakeScreenshotService.LoadAverageService.ImageWallpaper.DessertCaseDream.keyguard.KeyguardService.doze.DozeService
receiver:
.BootReceiver.qs.tiles.HotspotTile$APChangedReceiver.recent.RecentsPreloadReceiver.recents.RecentsUserEventProxyReceiver
众多activity中并没有LAUNCHER,也就是说SystemUI是没有启动界面的。
SystemUI的启动
既然SystemUI没有启动界面,也无需人为启动,那么SystemUI是怎么启动起来的呢?接下来就将对这个问题进行说明。
- 在service中有一个SystemUIService,这就是入口。那么这个SystemUIService又是怎么启动的呢?要找到答案,就要考虑到这是一个系统app,自然会在系统完成初始化以后启动,那么利用Source Insight在frameworks/base中看看有没有。
从结果来看,在SystemService貌似有什么线索。打开SystemService.java(frameworks/base/services/java/com/android/server/),以下代码就展现在眼前了。
static final void startSystemUi(Context context) {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.android.systemui",
"com.android.systemui.SystemUIService"));
//Slog.d(TAG, "Starting service: " + intent);
context.startServiceAsUser(intent, UserHandle.OWNER);
}在代码中可以看到SystemUIService被启动了起来,那么哪里调用了这个方法呢?在此类中继续查找,又发现如下代码:
mActivityManagerService.systemReady(new Runnable() {
@Override
public void run() {
Slog.i(TAG, "Making services ready");
mSystemServiceManager.startBootPhase(SystemService.PHASE_ACTIVITY_MANAGER_READY); try {
mActivityManagerService.startObservingNativeCrashes();
} catch (Throwable e) {
reportWtf("observing native crashes", e);
} Slog.i(TAG, "WebViewFactory preparation");
WebViewFactory.prepareWebViewInSystemServer(); try {
startSystemUi(context);
} catch (Throwable e) {
reportWtf("starting System UI", e);
}
...
}
}由代码可知,ActivityManagerService调用了
systemReady()方法,也就是系统就绪就会调用run()方法。那么会在何时执行到此处呢?再往上探索,发现上述代码位于startOtherServices()方法中,那么还是那个问题,何时调用startOtherServices()方法。再往上探索,发现startOtherServices()位于一个run()方法中private void run() {
···
// Start services.
try {
startBootstrapServices();
startCoreServices();
startOtherServices();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
}
···
}
再往上追一追,最终找到了这个类的开始:
public static void main(String[] args) {
new SystemServer().run();
}嗯,这是···,很熟悉嘛。
至于SystemService则是由Zygote启动的,在此就不多追溯了。
至此,SystemServer已经启动,那么在SystemServer里面又做了什么事情呢?SystemUIService的初始化
在SystemUIService中,主要代码就一个
onCreate()方法,来看看他做了啥:@Override
public void onCreate() {
super.onCreate();
((SystemUIApplication) getApplication()).startServicesIfNeeded();
}转型为SystemUIApplication并且调用
startServicesIfNeeded()方法。那么接下来去看看startServicesIfNeeded()方法做了些什么。public void startServicesIfNeeded() {
if (mServicesStarted) {
return;
} if (!mBootCompleted) {
// check to see if maybe it was already completed long before we began
// see ActivityManagerService.finishBooting()
if ("1".equals(SystemProperties.get("sys.boot_completed"))) {
mBootCompleted = true;
if (DEBUG) Log.v(TAG, "BOOT_COMPLETED was already sent");
}
} Log.v(TAG, "Starting SystemUI services.");
final int N = SERVICES.length;
for (int i=0; i<N; i++) {
Class<?> cl = SERVICES[i];
if (DEBUG) Log.d(TAG, "loading: " + cl);
try {
mServices[i] = (SystemUI)cl.newInstance();
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InstantiationException ex) {
throw new RuntimeException(ex);
}
mServices[i].mContext = this;
mServices[i].mComponents = mComponents;
if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
mServices[i].start(); if (mBootCompleted) {
mServices[i].onBootCompleted();
}
}
mServicesStarted = true;
}根据代码中涉及到的mServices,追溯其来源:
private final SystemUI[] mServices = new SystemUI[SERVICES.length];
再往上,得到SERVICES的由来:private final Class<?>[] SERVICES = new Class[] {
com.android.systemui.keyguard.KeyguardViewMediator.class,
com.android.systemui.recent.Recents.class,
com.android.systemui.volume.VolumeUI.class,
com.android.systemui.statusbar.SystemBars.class,
com.android.systemui.usb.StorageNotification.class,
com.android.systemui.power.PowerUI.class,
com.android.systemui.media.RingtonePlayer.class
};在这里定义了很多System Panel,这里叫做SERVICES,并非真正的services,运行在SystemUIService中的子服务。此时再来回头看
onCreate()方法:@Override
public void onCreate() {
super.onCreate();
// Set the application theme that is inherited by all services. Note that setting the
// application theme in the manifest does only work for activities. Keep this in sync with
// the theme set there.
setTheme(R.style.systemui_theme); IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (mBootCompleted) return; if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received");
unregisterReceiver(this);
mBootCompleted = true;
if (mServicesStarted) {
final int N = mServices.length;
for (int i = 0; i < N; i++) {
mServices[i].onBootCompleted();
}
}
}
}, filter);
}在onCreate()方法中,注册了广播接收器,用于接收开机完成的广播,并将开机完成的状态传递给每个SERVICE。
经过以上代码的追溯,可知:
mServices[i] = (SystemUI)cl.newInstance();//实例化子服务,并将其存储于mService[i]中。
mServices[i].mContext = this;//设置mService[i]的Context
mServices[i].mComponents = mComponents;//设置mService[i]的Components
mServices[i].start();//运行mService[i]
至此,SystemUIService的启动就已完成,伴随着SystemUIService的完成,SystemUI的核心service也就启动了,SystemUIService的使命也就完成了,接下来的事情就交由各个子服务去完成了。
以上属于个人体验心得总结,若有不足之处,还望不吝赐教,欢迎批评指正,共同进步
Android核心程序之SystemUI - (一)开篇的更多相关文章
- Android核心分析之二十Android应用程序框架之无边界设计意图
Android应用程序框架1 无边界设计理念 Android的应用框架的外特性空间的描述在SDK文档(http://androidappdocs.appspot.com/guide/topics/fu ...
- Qt on Android 核心编程
Qt on Android 核心编程(最好看的Qt编程书!CSDN博主foruok倾力奉献!) 安晓辉 著 ISBN 978-7-121-24457-5 2015年1月出版 定价:65.00元 4 ...
- 使用jQuery Mobile + PhoneGap 开发Android应用程序(转)
使用jQuery Mobile + PhoneGap 开发Android应用程序(转) 一.简介 jQuery Mobile是jQuery在手机上和平板设备上的版本.jQuery Mobile 不仅给 ...
- Unity开发Android应用程序:调用安卓应用程序功能
开发环境: Eclipse3.4 + adt12 + jdk6 + AndroidSDK2.2 Unity3.4 + windows7 测试设备: HTC Desire HD 本文要涉及到的几个重点问 ...
- Android核心分析之二十二Android应用框架之Activity
3 Activity设计框架 3.1 外特性空间的Activity 我们先来看看,android应用开发人员接触的外特性空间中的Activity,对于AMS来讲,这个Activity就是客服端的 ...
- Android核心分析之二十一Android应用框架之AndroidApplication
Android Application Android提供给开发程序员的概念空间中Application只是一个松散的表征概念,没有多少实质上的表征.在Android实际空间中看不到实际意义上的应用程 ...
- 一、Android应用程序的基本原理(Fundamentals [,fʌndə'mentlz])
Android 应用程序以java作为编程语言.Android SDK工具把代码连同数据.资源文件一起编译成一个以.apk为后缀(suffix)的android 程序存档(archive)文件包.在一 ...
- Android平台程序崩溃的类型及原因列举
Android平台程序崩溃大家都应该遇到过,force close和ANR应该是大家遇到较多的. 这里把Android平台程序崩溃的各种类型做一个简述和原因列举. 1.ANR(可见ANR): 发生场景 ...
- Android应用程序线程消息循环模型分析
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6905587 我们知道,Android应用程序是 ...
随机推荐
- SIGAI机器学习第十五集 支持向量机2
讲授线性分类器,分类间隔,线性可分的支持向量机原问题与对偶问题,线性不可分的支持向量机原问题与对偶问题,核映射与核函数,多分类问题,libsvm的使用,实际应用 大纲: SVM求解面临的问题 SMO算 ...
- IDEA八条配置修改
IDEA版本:IntelliJ IDEA 2019.2.1 x64 八条配置修改: 自动编译开关 忽略大小写开关 智能导包开关 悬浮提示开关 取消单行显示tabs的操作 项目文件编码 滚轴修改字体大小 ...
- 棋盘n皇后问题-递归
题目:在n*n的棋盘上,放n个皇后,互不攻击(不可在同行/列/对角线) 分析:将棋盘抽象成一个一维数组[0,1,2......,n*n-1],x=~~(i/n)取整,y=i%n; de ...
- Mysql开启慢查询命令
; 查询: SHOW VARIABLES LIKE '%slow_query_log%'; 结果:
- 学习。NET三周心得
目前为止 学习.NET已经快一个月了,有刚开始的不懂,到中途懵懂.再到现在的简懂 ,感觉自己迷了好多天,学习程序员跟学其他的程序还不同,其他的有固定格式,而.NET则固定很少 ,一直在用方法连接前后台 ...
- 51nod P1354 选数字 题解
每日一题 day8 打卡 Analysis 背包+离散化 这题是我们一次模拟赛的T2,结果我的暴力全TLE了. 关键是如果将两个因数的乘积离散化在因数数组中之后等于这个乘积本身,说明a[j]*in离散 ...
- 四十.创建Redis集群 管理集群
环境准备 准备 6台(51-56) redis服务器 以默认配置运行redis服务即可 一.创建Redis集群 1.启用集群功能( 51-56 都要配置) ]# netstat -antupl ...
- 使用 Java 创建聊天客户端-2
1.项目截图 java聊天核心代码: MyJavaChatClient ================================================================ ...
- learning scala type alise
How to use type alias to name a Tuple2 pair into a domain type called CartItem type CartItem[Donut, ...
- 在docker容器中编译hadoop 3.1.0
在docker容器中编译hadoop 3.1.0 优点:docker安装好之后可以一键部署编译环境,不用担心各种库不兼容等问题,编译失败率低. Hadoop 3.1.0 的源代码目录下有一个 `sta ...