SystemUI的启动与定制化

SystemUI的启动与定制化
SystemUI包含基本的StatusBar、VolumeBar、NavigationBar等部分,在手机开机时就已经为我们加载好,但是有时候会出现对StatusBar,DropList等进行定制化的任务,那么就需要了解SystemUI的启动流程,了解StatusBar,DropList等view是如何加载在系统界面上,下文是从SystemUI启动入口、SystemUI的加载机制以及以StatusBar为例来分析整个流程

在这里插入图片描述

一、SystemUI的启动入口
SystemUI的加载是在Android系统启动的时候,那么我们可以知道SystemUI的入口可能是在系统启动的流程中。发现在SyetemServer进程中开始启动系统服务,如AMS,PMS,蓝牙,窗口管理服务等,其中就包括SystemUI

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

在SystemServer中可以发现启动SystemServer的是zygote进程

public final class SystemServer {

/**
 * The main entry point from zygote.
 */
public static void main(String[] args) {
    new SystemServer().run();//函数入口
}
    ...
    
private void run() {
         ...
    // Initialize native services.初始化了native services
    System.loadLibrary("android_servers");

    // Check whether we failed to shut down last time we tried.
    // This call may not return.
    performPendingShutdown();

    // Initialize the system context.初始化了system context
    createSystemContext();

    // Create the system service manager.接着创建一个SystemServiceManager对象用于后续系统服务的启动和管理
    mSystemServiceManager = new SystemServiceManager(mSystemContext);
    mSystemServiceManager.setStartInfo(mRuntimeRestart,
            mRuntimeStartElapsedTime, mRuntimeStartUptime);
    LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
    // Prepare the thread pool for init tasks that can be parallelized
    SystemServerInitThreadPool.get();

    // Start services.
    try {
        traceBeginAndSlog("StartServices");开始系统服务的启动
        startBootstrapServices();启动引导service
        startCoreServices();启动核心service
        startOtherServices();启动其他的services
        SystemServerInitThreadPool.shutdown();
    } catch (Throwable ex) {
        Slog.e("System", "******************************************");
        Slog.e("System", "************ Failure starting system services", ex);
        throw ex;
    } finally {
        traceEnd();
    }
    
    ...
}

~startBootstrapServices()
private void startBootstrapServices() {

    Installer installer = mSystemServiceManager.startService(Installer.class);

    mSystemServiceManager.startService(DeviceIdentifiersPolicyService.class);
  
    mActivityManagerService = mSystemServiceManager.startService(
            ActivityManagerService.Lifecycle.class).getService();
    mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
    mActivityManagerService.setInstaller(installer);

    mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
    
    mSystemServiceManager.startService(LightsService.class);
    
    mSystemServiceManager.startService(new OverlayManagerService(mSystemContext, installer));
    ...

}

在startBootstrapServices()方法中,可以发现mSystemServiceManager.startServic()为核心所在,方法中传入不同的service作为参数,以实现不同services的开启,包括AMS,PMS,LightsService等系统所需的一些小的关键服务

~startCoreServices()
/**
* Starts some essential services that are not tangled up in the bootstrap process.
*/
private void startCoreServices() {
traceBeginAndSlog(“StartBatteryService”);
// Tracks the battery level. Requires LightService.
mSystemServiceManager.startService(BatteryService.class);
traceEnd();

    // Tracks application usage stats.
    traceBeginAndSlog("StartUsageService");
    mSystemServiceManager.startService(UsageStatsService.class);
    mActivityManagerService.setUsageStatsManager(
            LocalServices.getService(UsageStatsManagerInternal.class));
    traceEnd();

    // Tracks whether the updatable WebView is in a ready state and watches for update installs.
    if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
        traceBeginAndSlog("StartWebViewUpdateService");
        mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class);
        traceEnd();
    }

    ...
}

同样的,代码中以mSystemServiceManager.startService()来开启服务,只不过里面的参数不同

~startOtherServices():在这个方法中启动SystemUI
private void startOtherServices() {

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

}

~startSystemUi()
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();
}

在上面代码中可以看见创建了一个Intent,然后通过设置组件名称来开启SystemUIService,至此,SystemUI才只是找到启动的入口,对于系统启动完全完成,需要进入到SystemUIService中查看详细的启动流程。

二、SystemUI开始加载
/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java
public class SystemUIService extends Service {

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

}

/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
public class SystemUIApplication extends Application implements SysUiServiceProvider {
/**
* The classes of the stuff to start.
*/
private final Class<?>[] SERVICES = new Class[] {
Dependency.class,//启动的第一个SystemUI服务应始终为Dependency。Dependency是用来封装SystemUI应用中的一些依赖对象。
//Dependency提供了一种静态方法,用于获取具有跨越sysui的生命周期的依赖项。
//Dependency具有如何创建手动添加的所有依赖项的代码。 SystemUIFactory还能够添加/替换这些依赖项。
NotificationChannels.class,
CommandQueue.CommandQueueStart.class,
KeyguardViewMediator.class, // 锁屏界面
Recents.class,//最近使用的Activity
VolumeUI.class,//音量相关的UI
Divider.class,// 多窗口分屏
SystemBars.class, //系统状态栏,包括 StatusBar 、 NavigationBar、下拉消息、快捷菜单等等
StorageNotification.class, //存储相关的通知
PowerUI.class, //电池电量弹窗
RingtonePlayer.class, // 铃声控制
KeyboardUI.class,
PipUI.class,
ShortcutKeyDispatcher.class,
VendorServices.class,
GarbageMonitor.Service.class,
LatencyTester.class,
GlobalActionsComponent.class,
RoundedCorners.class,
};

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

在startServicesIfNeeded()方法中先将这些小部件集合在一起,然后调用startServicesIfNeeded(String[] services)

private void startServicesIfNeeded(String[] services) {
private SystemUI[] mServices;

mServices = new SystemUI[services.length];

    ...
    final int N = services.length;
    for (int i = 0; i < N; i++) {
        String clsName = services[i];
        
        Class cls;
        try {
            cls = Class.forName(clsName);
            mServices[i] = (SystemUI) cls.newInstance();
        } catch(ClassNotFoundException ex){
            throw new RuntimeException(ex);
        } 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();
        ...
    }

}
首先创建了一个SystemUI数组,这个是用来装载systemUI上各个小部件,接着遍历了在startServicesIfNeeded()方法中获取的services数组,通过反射的方式,获取各个不同的systemUI的对象,最后分别调用他们的start()方法。例如循环第六次获取到的是VolumeUI的对象,最后便调用的是VolumeUI的start()方法。

SystemUI开始加载不同位置的UI,而每个UI内部是如何加载,如何将view放置在不同的位置上的,我们继续往下看。

三、StatusBar的加载与定制化
由于SystemUI所包含的部分很多,这里就以加载状态栏StatusBar为例。上述遍历获取到了SystemBar对象,并开始调用它的start(),那么我们就进入到SystemBar类中查看它的start()。

/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemBars.java
public class SystemBars extends SystemUI {

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

private void createStatusBarFromConfig() {
final String clsName = mContext.getString(R.string.config_statusBarComponent);

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

}

start方法中调用了createStatusBarFromConfig(),接着进入到createStatusBarFromConfig中,在这里,第一眼感觉代码有点熟悉,回想一下和上面SystemUIApplication类中startServicesIfNeeded(String[] services)加载不同systemUI的方法很像,都是使用了反射的手法,同样的首先通过id 查找到config.xml文件里的name

/frameworks/base/packages/SystemUI/res/values/config.xml
com.android.systemui.statusbar.phone.StatusBar
从这个string name可以发现最后启动的是StatusBar,也就是调用StatusBar的start()方法。

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java

public class StatusBar extends SystemUI{

@Override
public void start() {
...
//第一步
createAndAddWindows();
...
}

public void createAndAddWindows() {
//第二步
    addStatusBarWindow();
}
...
private void addStatusBarWindow() {
//第三步
    makeStatusBarView();
    mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class);
    ...
//第五步
    mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
}
...
protected void makeStatusBarView() {
    final Context context = mContext;
    ...
//第四步
    inflateStatusBarWindow(context);
}
    ...
//加载Layout,初始化StatusBarWindow
protected void inflateStatusBarWindow(Context context) {
    mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
            R.layout.super_status_bar, null);
}

}

在StatusBar类中省略了大量代码,只保留了StatusBar加载的主要流程,从Start()方法中调用createAndAddWindows()接着再调用addStatusBarWindow(),紧接着在makeStatusBarView()方法中通过inflate加载layout的方式初始化StatusBarWindow,将super_status_bar.xml里所设计的样式加载到StatusBar界面上。
也就是说,当我们碰到需要定制化SystemUI的情况下,可以自己自定义一个layout.xml,然后在这里替换掉源文件。到了第5步是在初始化StatusBarWindow后,通过StatusBarWindowManager的add()方法,将statusBarView加载到系统界面上,并设置了statusBar的高度。那么我们就进入StatusBarWindowManager类的add()方法,如下所示:
public class StatusBarWindowManager{

/**
* Adds the status bar view to the window manager.
*
* @param statusBarView The view to add.
* @param barHeight The height of the status bar in collapsed state.
*/
public void add(View statusBarView, int barHeight) {

    // Now that the status bar window encompasses the sliding panel and its
    // translucent backdrop, the entire thing is made TRANSLUCENT and is
    // hardware-accelerated.
    mLp = new WindowManager.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT,
            barHeight,
            WindowManager.LayoutParams.TYPE_STATUS_BAR,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                    | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
                    | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
                    | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                    | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
            PixelFormat.TRANSLUCENT);
    mLp.token = new Binder();
    mLp.gravity = Gravity.TOP;
    mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
    mLp.setTitle("StatusBar");
    mLp.packageName = mContext.getPackageName();
    mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
    mStatusBarView = statusBarView;
    mBarHeight = barHeight;
    mWindowManager.addView(mStatusBarView, mLp);
    mLpChanged = new WindowManager.LayoutParams();
    mLpChanged.copyFrom(mLp);
}

}

可以发现StatusBar的加载真正在于WindowManager的处理,先设置好WindowManager.LayoutParams的宽高,层级TYPE,Flag等参数,然后将设置好的LayoutParams和上面传进来的mStatusBarView作为参数,调用addView()方法使View加载到相应的位置上。那么我们反过来思考下,如果将mStatusBarView换成我们自定义的View,那么结果会是什么样?

至此,StatusBar在SystemUI上的加载也就结束了,同样的道理,VolumeBar,NavigationBar等SystemUI其他部分的加载也和StatusBar的加载基本一致,这里就不再做分析。理清了上述代码,再回到文章开头看那张时序图,就可以清楚的知道SystemUI的启动流程,在此基础上,对SystemUI的定制化任务也就变得明朗起来。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值