阅读Android 4.0源码也有一段时间了,这次是针对SystemUI的一个学习过程。本文只是对SystemUI分析的一个开始——启动流程的分析,网上有很多关于2.3的SystemUI的分析,可4.0与2.3的差别还是很大的,为了给自己留下笔记同时也方便大家学习和探讨,遂写此文,后续将有更多关于SystemUI的分析,敬请关注。
转载请注明出处:http://blog.csdn.net/yihongyuelan
1.初始SystemUI
什么是SystemUI?你或许会觉得这个问题很幼稚,界面上的布局UI显示?系统的UI?如果你是这么想的,那么就大错特错了。我们知道Android 4.0 ICS同时适用于Phone和Tablet(TV),因此,对于Phone来说SystemUI指的是:StatusBar(状态栏)、NavigationBar(导航栏)。而对于Tablet或者是TV来说SystemUI指的是:CombinedBar(包括了StatusBar和NavigationBar)。注:关于Android 4.0的UI介绍请参考这篇文章。
根据上面的介绍,我想大家应该知道SystemUI的具体作用了吧!也就是说我们的Phone的信号,蓝牙标志,Wifi标志等等这些状态显示标志都会在StatusBar上显示。当我们的设备开机后,首先需要给用户呈现的就是各种界面同时也包括了我们的SystemUI,因此对于整个Android系统来说,SystemUI都有举足轻重的作用,那接下来就来看看它的启动流程吧!
2.启动流程
这里只是单单的分析启动流程,实际上SystemUI启动过程中涉及到很多东西的调用,这里暂时不分支去介绍,后续会有相关文章的详细分析。那么对于这种分析我还是将自己的分析思路写出来,而不是直接展现已经分析好的结果,当然结果会在最后展示出来。这样做一方面有利于锻炼自己的分析能力,另一方面各位看官也可以找出分析中的利与弊从而更好的取舍。
首先来看看SystemUI的代码位置,路径:SourceCode/frameworks/base/packages/SystemUI;其次看看它的代码梗概:
图 2.1
在Android 4.0中,Google整合了Phone和Tablet(TV)的SystemUI,也就说可以根据设备的类型自动匹配相应的SystemUI。这一点是在Android 2.3中是没有的。那么接下来怎么分析呢?打开AndroidManifest.xml可以看到:
... ...
根据以上代码我们可以发现这其中注册了很多Service,同时也包括了广播。但这里我们只关注SystemUIService,这才是本文的主旨啊。那么首先要找到SystemUIService是如何启动的。对于Service的启动,在我以前的博文中已有提到,这里就不多说了,不外乎startService(intent)和bindService(intent),它们都是以intent为对象,那intent的声明也需要SystemUIService啊,因此我们可以据此搜索关键词"SystemUIService"。
经过漫长的搜索和比对之后发现,原来,SystemUIService是在SystemServer.java中被启动的,如下所示:
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.startService(intent);
}
Android的启动分为内核启动、Android启动、launcher启动,我们的SystemServer就处于Android启动中,以下是大致流程图:
init->ServiceManager->Zygote->SystemServer->... ...
在SystemServer中,初始化了Android系统中的Java层服务,如PowerManagerService、WindowManagerService等等,当然也包括了SystemUIService,它们通过ServiceManager的addService()方法,添加到ServiceManager的管理中。实际上,根据后面的分析这里add了一个很重要的StatusBarManagerService。这个Service在后面会用到的。
既然到这里SystemUIService已经启动,那么我们就继续跟踪该Service吧。
1).首先查看其onCreate()方法,如下:
public void onCreate() {
// Pick status bar or system bar.
IWindowManager wm = IWindowManager.Stub.asInterface(
ServiceManager.getService(Context.WINDOW_SERVICE));
try {
SERVICES[0] = wm.canStatusBarHide()//根据wm.canStatusBarHide()判断设备类型
? R.string.config_statusBarComponent
: R.string.config_systemBarComponent;
} catch (RemoteException e) {
Slog.w(TAG, "Failing checking whether status bar can hide", e);
}
final int N = SERVICES.length;
mServices = new SystemUI[N];
for (int i=0; i
这里的canStatusBarHide()方法的具体实现是在:frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java。为什么会是这里呢?我们在Eclipse中导入源码之后,找到SystemUIService.java中的wm.canStatusBarHide()方法,通过open Implementation直接跳转到WindowsManagerService中:
public boolean canStatusBarHide() {
return mPolicy.canStatusBarHide();
}
public boolean canStatusBarHide() {
return mStatusBarCanHide;
}
// Determine whether the status bar can hide based on the size
// of the screen. We assume sizes > 600dp are tablets where we
// will use the system bar.
int shortSizeDp = shortSize
* DisplayMetrics.DENSITY_DEFAULT
/ DisplayMetrics.DENSITY_DEVICE;
mStatusBarCanHide = shortSizeDp < 600;
mStatusBarHeight = mContext.getResources().getDimensionPixelSize(
mStatusBarCanHide
? com.android.internal.R.dimen.status_bar_height
: com.android.internal.R.dimen.system_bar_height);
mHasNavigationBar = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_showNavigationBar);
继续回到我们的SystemUIService.java的onCreate()方法中,根据前面对canStatusBarHide()的判断,SERVICE[0]中将存放R.string.config_statusBarComponent或者R.string.config_systemBarComponent。它们的值具体是:
com.android.systemui.statusbar.phone.PhoneStatusBar
com.android.systemui.statusbar.tablet.TabletStatusBar
final int N = SERVICES.length;
mServices = new SystemUI[N];
for (int i=0; i
log信息:
06-04 13:23:15.379: DEBUG/SystemUIService(396): loading: class com.android.systemui.statusbar.phone.PhoneStatusBar
06-04 13:23:16.739: DEBUG/SystemUIService(396): loading: class com.android.systemui.power.PowerUI
来到PhoneStatusBar.start()方法中,位于:SourceCode/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java,代码如下:
@Override
public void start() {
mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay();
mWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService(Context.WINDOW_SERVICE));
super.start(); // calls makeStatusBarView()
addNavigationBar();
//addIntruderView();
// Lastly, call to the icon policy to install/update all the icons.
mIconPolicy = new PhoneStatusBarPolicy(mContext);
}
public void start() {
// First set up our views and stuff.
View sb = makeStatusBarView();
// Connect in to the status bar manager service
StatusBarIconList iconList = new StatusBarIconList();
ArrayList notificationKeys = new ArrayList();
ArrayList notifications = new ArrayList();
mCommandQueue = new CommandQueue(this, iconList);
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
int[] switches = new int[7];
ArrayList binders = new ArrayList();
try {
mBarService.registerStatusBar(mCommandQueue, iconList, notificationKeys, notifications,
switches, binders);
} catch (RemoteException ex) {
// If the system process isn't there we're doomed anyway.
}
disable(switches[0]);
setSystemUiVisibility(switches[1]);
topAppWindowChanged(switches[2] != 0);
// StatusBarManagerService has a back up of IME token and it's restored here.
setImeWindowStatus(binders.get(0), switches[3], switches[4]);
setHardKeyboardStatus(switches[5] != 0, switches[6] != 0);
// Set up the initial icon state
int N = iconList.size();
int viewIndex = 0;
for (int i=0; i在这里,完成了SystemUI的整个初始化以及设置过程,并最终呈现到界面上。在StatusBar中的start()方法主要完成了以下几个工作:首先获取需要在StatusBar上显示的各种icons。然后初始化一些属性。最后通过WindowManager的addView方法将StatusBar显示出来。分析到这里可能有人会问了,明明说分析的是SystemUI的嘛,怎么最后变成StatusBar了呢?如果你硬要说我跑题那我也没有办法,回过头去看看addNavigationBar(),你会发现和StatusBar的加载几乎一致,因此没必要再详述了。
如果细心阅读了的朋友肯定会发现这句代码:
mBarService = IStatusBarService.Stub.asInterface(ServiceManager.getService(Context.STATUS_BAR_SERVICE));
这不正是我们前面add的StatusBarManagerSerivce吗?这里通过AIDL的方式来获取它的对象。
整个代码执行的时序图如图2.2所示:
图 2.2
3.总结
Android 4.0的SystemUI加载启动的过程大致就是这样,虽然看似简单,但这仅仅是个开始,master还是后面呢!!各家厂商根据自家的需求,需要定制SystemUI或者美化SystemUI,不同的平台(QCOM、MTK等等)也会有不同的修改,但大体框架是没有变的,无非是在原有基础上的修修改改或者增加一些自己的类等等。通过对Android源码框架性的理解,可以学习到很多设计上的知识(虽然自己还很欠缺)。通过这次分析,开始逐渐用StarUML来画时序图,这也是一个学习的过程。