android SystemUI浅析之SystemUI启动流程

前言:最近在研究4.2的status bar 和navigation bar,想做一下总结,后来碰到一篇文章分享一下,至于4.2上的变化以及4.2上的总结,我会在后期补充上并且会一直修改和完善。参考http://blog.csdn.net/yihongyuelan

 

我们知道Android 4.0以后SystemUI同时适用于Phone和Tablet(TV),因此,对于Phone来说SystemUI指的是:StatusBar(状态栏)、NavigationBar(导航栏)。而对于Tablet或者是TV来说SystemUI指的是:CombinedBar(包括了StatusBar和NavigationBar)。

首先来看看SystemUI的代码位置,路径:SourceCode/frameworks/base/packages/SystemUI。

那么接下来怎么分析呢?打开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);  
}  

这里的startSystemUi()方法则在ServerThread的run()方法中被调用。这里提到SystemServer就不得不提及Android的启动流程,这里不会展开详细讨论具体的流程,只是简单的介绍一下大概流程,用以表明SystemServer所处的位置。

 

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

在这段代码中,通过AIDL的方式获取了WindowManager的对象wm,并调用其方法canStatusBarHide()来判断当前设备的类型,也就是说如果我们使用的Phone那么后续就会加载StatusBar和NivagationBar;而如果我们设备类型是Tablet(TV)之类的(可以在配置文档里面配置),就会加载CombiedBar。

        这里的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();  
}  

但这里我们发现canStatusBarHide()实际上是WindowManagerPolicy的对象调用的方法,而WindowManagerPolicy只是一个接口类,根据以往分析的经验可以知道,这里的WindowManagerPolicy对象所调用的canStatusBartHide()方法一定是其实现类中的方法。因此,继续通过open Implementation跳转,来到了PhoneWindownManager中:

public boolean canStatusBarHide() {  
    return mStatusBarCanHide;  
}  

继续查看mSatuBarCanHide的实现,如下所示:

// 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);  

这里通过shortSizeDp来判断当前设备的类型,如果当前屏幕的shortSizeDp<600dp,则系统会认为该设备是Phone反之则认为是Tablet。根据mStatusBarCanHide的值,设定StatusBar或者SystemBar(CombinedBar)的高度,以及是否显示NavigationBar。

        继续回到我们的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 

因为我的测试设备是Phone,那么现在SERVICE[0]中存放的就是com.android.systemui.statusbart.phone.PhoneStatusBar。查看以下代码:

final int N = SERVICES.length;  
mServices = new SystemUI[N];  
for (int i=0; i

这些方法会分别启动两个方法,这两个方法可以从log中知道,分别是PhoneStatusBar.start()和PowerUI.start()。而我们的目的是要弄清SystemUI的启动,因此现关注PhoneStatusBar.start()方法。

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);  
}  

这里的重心主要是在super.start()和addNavigationBar()上。目前市面上很多手机已经刷入了ICS,但是大多数是没有NavigationBar的,也就是说自己修改了源码,屏蔽了NavigationBar。继续跟踪super.start()方法,来到/SourceCode/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java的start()方法中,代码如下:

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

图2.2


 3.总结

        Android 4.0的SystemUI加载启动的过程大致就是这样,虽然看似简单,但这仅仅是个开始,master还是后面呢!!各家厂商根据自家的需求,需要定制SystemUI或者美化SystemUI,不同的平台(QCOM、MTK等等)也会有不同的修改,但大体框架是没有变的,无非是在原有基础上的修修改改或者增加一些自己的类等等。通过对Android源码框架性的理解,可以学习到很多设计上的知识(虽然自己还很欠缺)。通过这次分析,开始逐渐用StarUML来画时序图,这也是一个学习的过程。

你可能感兴趣的:(android)