SystemUI模块总结

SystemUI模块总结

1,SystemUI路径

SystemUI被放在

framework/base/packages/apps/SystemUI

在该目录的二级目录src/com/android下可看到SystemUI和Keyguard两个目录

SystemUI
Keyguard

由此可见如今将锁屏界面也整合在SystemUI中

2,SystemUI所需权限

从清单文件中可以发现 SystemUI需要建立以下开通权限用以监听开机广播,读写内存和访问所有用户存储状态,监听物理硬件,控制AM,WM,屏保,
锁屏,recent事件,wifi的展示,截屏,快捷设置入口等

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Used to read storage for all users -->
<uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

<uses-permission android:name="android.permission.INJECT_EVENTS" />
<uses-permission android:name="android.permission.DUMP" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />

<uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
<uses-permission android:name="android.permission.STATUS_BAR" />
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
<uses-permission android:name="android.permission.REMOTE_AUDIO_PLAYBACK" />

<uses-permission android:name="android.permission.MANAGE_USERS" />
<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />


。。。。。。


<uses-permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS" />

3,SystemUI启动流程

SystemUI启动分为两部分
1)Service部分

代码路径:

framework/base/services/java/com/android/server/SystemServer.java

开机后系统会首先启动SystemServer,SystemServer启动后才会带动其他一系列系统服务的启动,也包括SystemUI的启动

    public static void main(String[] args) {
    new SystemServer().run();
}

在SystemUI的main方法中启用了 SystemServer().run();run方法中主要做了以下操作

traceBeginAndSlog("StartServices");
        startBootstrapServices();
        startCoreServices();
        startOtherServices();

而在run()方法中做了startBootstrapServices(),startCoreServices(),startOtherServices()三个操作
而在startOtherServices()中做了startSystemUi(context, windowManagerF)的方法

	traceBeginAndSlog("StartSystemUI");
    	try {
            startSystemUi(context, windowManagerF);
        } catch (Throwable e) {
            reportWtf("starting System UI", e);
        }
        traceEnd();

startSystemUi具体实现如下,用Intent启动了SystemUIService

    static final void startSystemUi(Context context, WindowManagerService windowManager) {
    Intent intent = new Intent();
    intent.setComponent(new ComponentName("com.android.systemui",
                "com.android.systemui.SystemUIService"));
    intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
    //Slog.d(TAG, "Starting service: " + intent);
    context.startServiceAsUser(intent, UserHandle.SYSTEM);
    windowManager.onSystemUiStarted();
	}
2)SystemUI部分

接下来就走到了SystemUIService中,我们看一下SystemUIService中的onCreat方法

扫描二维码关注公众号,回复: 9154559 查看本文章
 @Override
public void onCreate() {
    super.onCreate();
    ((SystemUIApplication) getApplication()).startServicesIfNeeded();
		......	
  
}

可知在SystemUIService中启动了SystemUIApplication中的startServicesIfNeeded()方法

public void startServicesIfNeeded() {
    startServicesIfNeeded(SERVICES);
}

其中SERVICES是一组所有用户共用的SystemUI服务,如下

    private final Class<?>[] SERVICES = new Class[] {

        Dependency.class,         //SystemUI的依赖项

        NotificationChannels.class,  //展示系统或应用通知内容

        CommandQueue.CommandQueueStart.class,   //StatusBar的扩展类

        KeyguardViewMediator.class,  //协调与keyguard相关的请求

        Recents.class, //近期应用管理

        VolumeUI.class,  //来用展示或控制音量的变化:媒体音量、铃声音量与闹钟音量

        Divider.class,  //控制堆栈的服务

        SystemBars.class,  //通知栏

        StorageNotification.class,  //存储设备管理

        PowerUI.class,   //主要处理和Power相关的事件,比如省电模式切换、电池电量变化和开关屏事件等

        RingtonePlayer.class,   //铃声播放

        KeyboardUI.class,   //键盘界面

        PipUI.class,   //画中画

        ShortcutKeyDispatcher.class,  //系统组件快捷方式

        VendorServices.class,  //厂商定制的服务

        GarbageMonitor.Service.class, //垃圾监视服务

        LatencyTester.class,  //debug测试

        GlobalActionsComponent.class,  //全局控制

        RoundedCorners.class,  //圆角切割
};

下面看看在SystemUIApplication是如何启动这一系列服务的

   private void startServicesIfNeeded(Class<?>[] services) {
    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 for user " +
            Process.myUserHandle().getIdentifier() + ".");
    TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
            Trace.TRACE_TAG_APP);



    log.traceBegin("StartServices");

    final int N = services.length;       //获取启动服务列表的长度

    for (int i = 0; i < N; i++) {
        Class<?> cl = services[i];
        if (DEBUG) Log.d(TAG, "loading: " + cl);
        log.traceBegin("StartServices" + cl.getSimpleName());
        long ti = System.currentTimeMillis();
        try {
				/*通过SystemUI创建相应的单例*/
            Object newService = SystemUIFactory.getInstance().createInstance(cl);
            mServices[i] = (SystemUI) ((newService == null) ? cl.newInstance() : newService);
        } 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();  //依次启动相应的服务
        log.traceEnd();

        // Warn if initialization of component takes too long
        ti = System.currentTimeMillis() - ti;
        if (ti > 1000) {
            Log.w(TAG, "Initialization of " + cl.getName() + " took " + ti + " ms");
        }
        if (mBootCompleted) {
            mServices[i].onBootCompleted();
        }
    }

上面的代码的逻辑首先获取SERVICE数组中的class名,然后分别实例化他们,最后调用start接口统一启动,因此,每一个UI元素都必须继承自SystemUI这个抽象类,并且重载其中的start方法。

3,SystemUI主要模块

StatusBar:通知消息提示和状态展现

NavigationBar:返回,HOME,Recent

KeyGuard:锁屏模块可以看做单独的应用,提供基本的手机个人隐私保护

Recents:近期应用管理,以堆叠栈的形式展现。

Notification Panel:展示系统或应用通知内容。提供快速系统设置开关。

VolumeUI:来用展示或控制音量的变化:媒体音量、铃声音量与闹钟音量

截屏界面:长按电源键+音量下键后截屏,用以展示截取的屏幕照片/内容

PowerUI:主要处理和Power相关的事件,比如省电模式切换、电池电量变化和开关屏事件等。

RingtonePlayer:铃声播放

StackDivider:控制管理分屏

PipUI:提供对于画中画模式的管理

SystemBar的启动过程

由上文可知SystemBar存在于SystemUIApplication的services集合中,因此在mServices[i].start()时,SystemBars也同时被启动了
下面看一下SystemBar服务,SystemBar继承SystemUI抽象类

public class SystemBars extends SystemUI {
private static final String TAG = "SystemBars";
private static final boolean DEBUG = false;
private static final int WAIT_FOR_BARS_TO_DIE = 500;

// in-process fallback implementation, per the product config
private SystemUI mStatusBar;

@Override
public void start() {
    if (DEBUG) Log.d(TAG, "start");
    createStatusBarFromConfig();
}

由此可见在SystemUI的start方法中只执行了一个createStatusBarFromConfig()创建了staturbar,SystemBar只是作了一个中间过程
再来看一下createStatusBarFromConfig()方法

private void createStatusBarFromConfig() {
    if (DEBUG) Log.d(TAG, "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 = (SystemUI) cls.newInstance();
    } catch (Throwable t) {
        throw andLog("Error creating status bar component: " + clsName, t);
    }
    mStatusBar.mContext = mContext;
    mStatusBar.mComponents = mComponents;
    mStatusBar.start();
    if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName());
}

同样也是调用了statusbar中的start方法,再来看一下statusbar中的start方法

@Override
public void start() {   
...
//这里面进行了StatusBar中各个组件的初始化
mBarService = IStatusBarService.Stub.asInterface(
        ServiceManager.getService(Context.STATUS_BAR_SERVICE));
...
try {
    /* 经过一系列对象的创建与初始化后,开始向StatusBarService进行注册。这里涉及跨进程操作,
              因而传递的参数都是继承自Parcelable的 */
    mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders,
            fullscreenStackBounds, dockedStackBounds);
} ...

createAndAddWindows();  //这里才是真正将Status Bar显示出来的地方

StarusBarService通过Context.STATUS_BAR_SERVICE启动,这个服务在SystemServer中注册,先看一下SystemServer中的代码

if (!disableSystemUI) {
   traceBeginAndSlog("StartStatusBarManagerService");
   try {
       statusBar = new StatusBarManagerService(context, wm);
       ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
   } catch (Throwable e) {
       reportWtf("starting StatusBarManagerService", e);  //原来StatusBarManagerService这个家伙注册的
   }
   traceEnd();
}

接下来进一步分析StatusBarManagerService的实现,首先看下其中的registerStatusBar中的代码:

StatusBarManagerService代码路径:

framework/base/services/core/java/com/android/server/statusbar/StatusBarManagerService.java

不在之前的SystemUI的路径中

 @Override
public void registerStatusBar(IStatusBar bar, List<String> iconSlots,
        List<StatusBarIcon> iconList, int switches[], List<IBinder> binders,
        Rect fullscreenStackBounds, Rect dockedStackBounds) {
    enforceStatusBarService();

    Slog.i(TAG, "registerStatusBar bar=" + bar);
    mBar = bar;
    try {
        mBar.asBinder().linkToDeath(new DeathRecipient() {
            @Override
            public void binderDied() {
                mBar = null;
                notifyBarAttachChanged();
            }
        }, 0);
    } catch (RemoteException e) {
    }
    notifyBarAttachChanged();
    synchronized (mIcons) {        //复制icon列表
        for (String slot : mIcons.keySet()) {
            iconSlots.add(slot);
            iconList.add(mIcons.get(slot));
        }
    }
    synchronized (mLock) {
        switches[0] = gatherDisableActionsLocked(mCurrentUserId, 1);
        switches[1] = mSystemUiVisibility;
        switches[2] = mMenuVisible ? 1 : 0;
        switches[3] = mImeWindowVis;
        switches[4] = mImeBackDisposition;
        switches[5] = mShowImeSwitcher ? 1 : 0;
        switches[6] = gatherDisableActionsLocked(mCurrentUserId, 2);
        switches[7] = mFullscreenStackSysUiVisibility;
        switches[8] = mDockedStackSysUiVisibility;
        binders.add(mImeToken);
        fullscreenStackBounds.set(mFullscreenStackBounds);
        dockedStackBounds.set(mDockedStackBounds);
    }
}

从上面的代码看,registerStatusBar的作用主要是:一,为新启动的SystemUI应用赋予当前系统的真实值(比如有多少需要显示的图标);二,通过mBar记录istatusBar对象,它在SystemUI中对应的是CommandQueue。
下面是整理的流程图,大家可以参考一下

发布了45 篇原创文章 · 获赞 23 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/Easyhood/article/details/88180527