SystemUI启动流程及主体布局介绍

本文将基于Android 6.0代码,分析systemUI的启动加载流程,对systemUI几处关键的视图的布局及功能进行介绍。

一. SystemUI主体框架启动流程

android设备上电,引导程序引导进入boot(通常是uboot),加载initramfs、kernel镜像,启动kernel后,进入用户态程序。第一个用户空间程序是init, PID固定是1.
init的基本功能有:

  • 管理设备
  • 解析并处理Android启动脚本init.rc
  • 实时维护这个init.rc中的服务,包括加载 Zygote

而在Zygote中将启动SystemServer组件。

本文将从SystemServer开始分析。
SystemServer 名为系统服务进程,负责启动 Android 系统的关键服务。
其入口是SystemServer.main():

/**
     * The main entry point from zygote.
     */
    public static void main(String[] args) {
        new SystemServer().run();
    }

可以看到main()中生成了SystemServer对象并执行了run方法。
SystemServer.run():

private void run() {
    ......
    
     // Start services.
        try {
            startBootstrapServices();
            startCoreServices();
            startOtherServices();
            ......
       } catch (Throwable ex) {
           ...
            throw ex;
        }
        ...
        // Loop forever.
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
}

先看一眼startBootstrapServices();

 private void startBootstrapServices() {
        ......
        Installer installer = mSystemServiceManager.startService(Installer.class);

        // Activity manager runs the show.
        mActivityManagerService = mSystemServiceManager.startService(
                ActivityManagerService.Lifecycle.class).getService();
        mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
        ......
 }

在startBootstrapServices()中启动了mActivityManagerService。
随后,我们再回头去看startOtherServices():

private void startOtherServices() {
        final Context context = mSystemContext;
        AccountManagerService accountManager = null;
        ContentService contentService = null;
        .......
        
         mActivityManagerService.systemReady(new Runnable() {
            @Override
            public void run() {
              ......

                try {
                    startSystemUi(context);
                } catch (Throwable e) {
                    reportWtf("starting System UI", e);
                }
         .......

mActivityManagerService.systemReady创建线程去执行startSystemUi(context),从方法名称可以看出,这里将启动systemUI。

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

通过intent.setComponent(new ComponentName("com.android.systemui",
"com.android.systemui.SystemUIService"));
设置启动systemui程序的SystemUIService
进入SystemUIService:

public class SystemUIService extends Service {

    @Override
    public void onCreate() {
        super.onCreate();
        ((SystemUIApplication) getApplication()).startServicesIfNeeded();
    }
......

onCreate方法中获得SystemUIApplication对象并调用其startServicesIfNeeded方法:

 public void startServicesIfNeeded() {
        final int N = SERVICES.length;
        for (int i=0; i cl = SERVICES[i];
            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;
            mServices[i].start();//start服务
            if (mBootCompleted) {
                mServices[i].onBootCompleted();
            }
        }
        mServicesStarted = true;
    }

可以看到startServicesIfNeeded()循环start了很多Services。
数组SERVICES的定义如下:

private final Class[] SERVICES = new Class[] {
            com.android.systemui.tuner.TunerService.class, //定制状态栏服务
            com.android.systemui.keyguard.KeyguardViewMediator.class,//锁屏模块
            com.android.systemui.recents.Recents.class,//最近应用
            com.android.systemui.volume.VolumeUI.class,//全局音量控制
            com.android.systemui.statusbar.SystemBars.class,//系统状态栏
            com.android.systemui.usb.StorageNotification.class,//Storage存储通知
            com.android.systemui.power.PowerUI.class,//电量管理相关
            com.android.systemui.media.RingtonePlayer.class,//铃声播放
            com.android.systemui.keyboard.KeyboardUI.class,//键盘相关
};

可以看到子服务包括:TunerService,KeyguardViewMediator,Recents,VolumeUI,SystemBars,StorageNotification,PowerUI
RingtonePlayer,KeyboardUI。
不过这里的service与我们平时所讲的四大组件的service并不一样。这里的service只是继承了SystemUI类的普通对象而已。
例如SystemBars:

public class SystemBars extends SystemUI implements ServiceMonitor.Callbacks {
           ......
}

小结:

查看到这里,可以总结一下systemUI主体框架的启动流程:
SystemServer启动Android核心服务包括了ActivityManagerService
--->ActivityManagerService一旦启动完成就会在systemReady的回调里启动SystemUIService
--->SystemUIService.onCreate—--->SystemUIApplication.startServicesIfNeeded
--->循环中调用mServices[i].start()启动SystemUI的各种核心service。

二. SystemUI关键视图呈现

手机中的下拉状态栏,锁屏,通知以及最近打开任务列表等功能都是SystemUI实现的。
主要功能点对应的界面如下图所示:



在上文中我们看到了SystemUI各项服务的启动流程,那么服务有了,界面视图又是如何呈现的呢?
接下来将以SystemBars为例,它是SystemUI的主要视图。
上文中mServices[i].start()将调用SystemBars.start():

    @Override
    public void start() {
        if (DEBUG) Log.d(TAG, "start");
        mServiceMonitor = new ServiceMonitor(TAG, DEBUG,
                mContext, Settings.Secure.BAR_SERVICE_COMPONENT, this);
        mServiceMonitor.start();  // will call onNoService if no remote service is found
    }

start中创建ServiceMonitor实例并start();
注释中说明,/服务没启动时,ServiceMonitor会回调SystemBars的onNoService/
所以去看SystemBars的onNoService:

    @Override
    public void onNoService() {
        if (DEBUG) Log.d(TAG, "onNoService");
        createStatusBarFromConfig();  // fallback to using an in-process implementation
    }
    
    private void createStatusBarFromConfig() {
        final String clsName = mContext.getString(R.string.config_statusBarComponent);
        if (clsName == null || clsName.length() == 0) {
            throw andLog("No status bar component configured", null);
        }
        Class cls = null;
        try {
            cls = mContext.getClassLoader().loadClass(clsName);
        } catch (Throwable t) {
            throw andLog("Error loading status bar component: " + clsName, t);
        }
        try {
            mStatusBar = (BaseStatusBar) cls.newInstance();
        } catch (Throwable t) {
            throw andLog("Error creating status bar component: " + clsName, t);
        }
        mStatusBar.mContext = mContext;
        mStatusBar.mComponents = mComponents;
        mStatusBar.start();
    }

需要注意的是,clsName得到的string为com.android.systemui.statusbar.phone.PhoneStatusBar
执行SystemBars.start()后,通过反射机制,最终得到BaseStatusBar对象。
这里需要说明的是BaseStatusBar是PhoneStatusBar的父类。
上文mStatusBar.start()即为PhoneStatusBar.start():

    public void start() {
            ......
            super.start(); // calls createAndAddWindows()
            ......
    }

再去BaseStatusBar.start():

public void start() {
        mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
        mDisplay = mWindowManager.getDefaultDisplay();
        mDevicePolicyManager = (DevicePolicyManager)mContext.getSystemService(
                Context.DEVICE_POLICY_SERVICE);

        mNotificationColorUtil = NotificationColorUtil.getInstance(mContext);

        mNotificationData = new NotificationData(this);

        mAccessibilityManager = (AccessibilityManager)
                mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);

        mDreamManager = IDreamManager.Stub.asInterface(
                ServiceManager.checkService(DreamService.DREAM_SERVICE));
        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);

        .......
        //在这里实例化了许多systemui常用的对象,服务,Manager,Observer等等
        .......
        
        createAndAddWindows(); //创建并添加视图

查看createAndAddWindows():

 protected abstract void createAndAddWindows();

是个抽象方法,很显然调用去了BaseStatusBar的子类,
即PhoneStatusBar的createAndAddWindows():

 @Override
 public void createAndAddWindows() {
        addStatusBarWindow();
 }
 
 private void addStatusBarWindow() {
        makeStatusBarView();//关键方法,创建StatusBarView
        mStatusBarWindowManager = new StatusBarWindowManager(mContext);
        mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
 }

重点来了,makeStatusBarView,创建StatusBarView,
随后,mStatusBarWindowManager将其添加,呈现给用户
makeStatusBarView()的代码很长,但主要代码是这一句:

protected PhoneStatusBarView makeStatusBarView()
{
    ......
    mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
                R.layout.super_status_bar, null);
    ......
}

通过认识super_status_bar.xml就能认识SystemBars的大体构成。
下面是部分省略的super_status_bar文件



    
    
    
    
    

    

    
        
            
        
    

    
    

    


通过上述view布局及makeStatusBarView相关代码,可以发现mStatusBarWindow(StatusBarWindowView)中包含以下4个部分:

  • ScrimView
  • PhoneStatusBarView layout-> status_bar
  • PanelHolder id->PanelHolder
  • ScrimView

其实这里还漏掉了一个重要的view—-keyguard_bouncer,它不是直接在layout布局里加入的,只有用户设置锁屏保护后才可见。

SystemUI启动流程及主体布局介绍_第1张图片
StatusBarWindowView

这里主要查看一下PhoneStatusBarView,PanelHolder及KeyguardBouncer。

PhoneStatusBarView
PhoneStatusBarView即为手机最上方的状态栏,主要用于显示系统状态,通知等,主要包括 notification icons 和 status bar icons

SystemUI启动流程及主体布局介绍_第2张图片
PhoneStatusBarView

PanelHolder
PanelHolder是用户下拉 status bar 后得到的 view。它主要包含 QuickSettings 和 Notification panel 两个部分。
PanelHolder是一个继承自FrameLayout的自定义view,它的内容是通过include status_bar_expanded.xml进行填充的。
PanelHolder的布局比较复杂,为了提高view的重用性大量的使用了include标签。

SystemUI启动流程及主体布局介绍_第3张图片
PanelHolder

在平时修改QuickSettings以及Notification panel界面布局及功能相关的文件分别QSPanel及NotificationPanelView。

KeyguardBouncer
KeyguardBouncer是锁屏解锁界面,根据用户设置的解锁方式不同,展示不同的解锁模式。
先看看KeyguardBouncer长什么样子:

锁屏界面:

SystemUI启动流程及主体布局介绍_第4张图片
Notification Keyguard

上滑锁屏后:

SystemUI启动流程及主体布局介绍_第5张图片
KeyguardBouncer

需要注意的是KeyguardBouncer有多种形式,上图中展示的是图案解锁,若为密码解锁KeyguardBouncer将会以数字键盘的形式展示。但无论哪种形式,都是在KeyguardBouncer中加载进来的。

public class KeyguardBouncer { 
private ViewGroup mRoot; 
private ViewGroup mContainer; 
private KeyguardHostView mKeyguardView;
private void inflateView() {        
       mRoot = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.keyguard_bouncer, null);
       mKeyguardView =(KeyguardHostView)mRoot.findViewById(R.id.keyguard_host_view);
       mKeyguardView.setLockPatternUtils(mLockPatternUtils);
       mKeyguardView.setViewMediatorCallback(mCallback); 
       mContainer.addView(mRoot,mContainer.getChildCount());
}

KeyguardBouncer的View树如下:

SystemUI启动流程及主体布局介绍_第6张图片
KeyguardBouncer

小结:

通过分析SystemBars的呈现流程介绍了PhoneStatusBarView,PanelHolder,keyguardbouncer三个常见SystemUI的界面布局及相关功能。当然,SystemUI的布局还是很复杂的,上述只对主要的视图从大的方向上做了分析。SystemUI也不只以上几个布局,包括最近应用视图,底部导航栏(Navigation Bar),全局音量管理Dialog等,本文暂时未介绍到。

总结:

本文分为两部分,分别介绍了SystemUI主体框架启动流程及SystemUI关键视图的界面布局呈现过程。通过以上介绍,在以后遇到SystemUI相关问题时,可以先定位出问题View属于哪个大的分类,然后结合图例给出的id缩小定位范围。

你可能感兴趣的:(SystemUI启动流程及主体布局介绍)