Android Framework之 SystemUI的秘密

SystemUI的秘密

路径:frameworks/base/packages/SystemUI

其实SystemUI就是个APP,主要功能如下

  • 状态栏信息显示,比如电池,wifi/信号
  • 通知面板,比如系统消息,第三方应用消息
  • 近期任务栏显示面板,比如长按近期任务快捷键,显示近期使用的应用
  • 截图服务
  • 壁纸服务....

不死的秘密

ini 复制代码
<application  
android:name=".SystemUIApplication"  
android:persistent="true"  
android:allowClearUserData="false"  
android:backupAgent=".backup.BackupHelper"  
android:killAfterRestore="false"  
android:hardwareAccelerated="true"  
android:label="@string/app_label"  
android:icon="@drawable/icon"  
android:process="com.android.systemui"  
android:supportsRtl="true"  
android:theme="@style/Theme.SystemUI"  
android:defaultToDeviceProtectedStorage="true"  
android:directBootAware="true"  
tools:replace="android:appComponentFactory"  
android:appComponentFactory=".SystemUIAppComponentFactory">

android:persistent="true" 保证在挂掉以后,会被系统强行拉起来。

这里注意一下 android:appComponentFactory=".SystemUIAppComponentFactory" 后面会提到。

SystemUI的启动

  • SystemServer.java ->startOtherServices->startSystemUi(context, windowManagerF);

其实这里我们就看SystemUI其实是一个服务,因为启动的时候是startService

java 复制代码
private static void startSystemUi(Context context, WindowManagerService windowManager) {
    PackageManagerInternal pm = LocalServices.*getService*(PackageManagerInternal.class);
    Intent intent = new Intent();
       //pm.getSystemUiServiceComponent() 这里其实就是获得了组件路径
    intent.setComponent(pm.getSystemUiServiceComponent());
    intent.addFlags(Intent.*FLAG_DEBUG_TRIAGED_MISSING*);
    //Slog.d(TAG, "Starting service: " + intent);
    context.startServiceAsUser(intent, UserHandle.*SYSTEM*);
    windowManager.onSystemUiStarted();
}
java 复制代码
@Override
public ComponentName getSystemUiServiceComponent() {
    return ComponentName.*unflattenFromString*(mContext.getResources().getString(
            com.android.internal.R.string.config_systemUIServiceComponent));
}

路径 :frameworks/base/core/res/res/values/config.xml

xml 复制代码
  

<!-- SystemUi service component -->
    <string name="config_systemUIServiceComponent" translatable="false"
            >com.android.systemui/com.android.systemui.SystemUIService</string>

SystemUIService.java

java 复制代码
onCreate(){
   //SystemUISerice启动之前会检查 是否已经有了实例,避免多次启动。
   ((SystemUIApplication) getApplication()).startServicesIfNeeded();
...
  
   
  startServiceAsUser(
                new Intent(getApplicationContext(), SystemUIAuxiliaryDumpService.class),
                UserHandle.SYSTEM);
}

SystemUIApplication.java

  • implements SystemUIAppComponentFactory.ContextInitializer(注意这个接口)
java 复制代码
 

public class SystemUIApplication extends Application implements
        SystemUIAppComponentFactory.ContextInitializer {
public void startServicesIfNeeded() {
  //回去要启动的服务名称  如果玩的是car 那返回值是不一样的
  //路径 frameworks/base/packages/SystemUI/res/values/config.xml
        String[] names = SystemUIFactory.getInstance().getSystemUIServiceComponents(getResources());
        startServicesIfNeeded(/* metricsPrefix= */ "StartServices", names);
    }


private void startServicesIfNeeded(String metricsPrefix, String[] services) {
   //已经启动就返回  这里有个点要注意  String[] services 是个数组
        if (mServicesStarted) {
            return;
        }
        mServices = new SystemUI[services.length];

        if (!mBootCompleteCache.isBootComplete()) {
            // check to see if maybe it was already completed long before we began
            // see ActivityManagerService.finishBooting()
            if ("1".equals(SystemProperties.get("sys.boot_completed"))) {
                mBootCompleteCache.setBootComplete();
                if (DEBUG) {
                    Log.v(TAG, "BOOT_COMPLETED was already sent");
                }
            }
        }

        final DumpManager dumpManager = mSysUIComponent.createDumpManager();

   
     
        final int N = services.length;
        for (int i = 0; i < N; i++) {
            String clsName = services[i];
          
            log.traceBegin(metricsPrefix + clsName);
            long ti = System.currentTimeMillis();
            try {
              //反射构建
                SystemUI obj = mComponentHelper.resolveSystemUI(clsName);
                if (obj == null) {
                  //无则构建 有则无需在构建 缓存进去
                    Constructor constructor = Class.forName(clsName).getConstructor(Context.class);
                    obj = (SystemUI) constructor.newInstance(this);
                }
                mServices[i] = obj;
            } catch (ClassNotFoundException
                    | NoSuchMethodException
                    | IllegalAccessException
                    | InstantiationException
                    | InvocationTargetException ex) {
                throw new RuntimeException(ex);
            }

            if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
            mServices[i].start();//调用启动
           

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

            dumpManager.registerDumpable(mServices[i].getClass().getName(), mServices[i]);
        }
        mSysUIComponent.getInitController().executePostInitTasks();
        log.traceEnd();
         //最后赋值避免多次启动
        mServicesStarted = true;
    }}

路径 : frameworks/base/packages/SystemUI/res/values/config.xml

xml 复制代码
 <!-- SystemUI Services: The classes of the stuff to start. -->
    <string-array name="config_systemUIServiceComponents" translatable="false">
        <item>com.android.systemui.util.NotificationChannels</item>
        <item>com.android.systemui.keyguard.KeyguardViewMediator</item>
        <item>com.android.systemui.recents.Recents</item>
        <item>com.android.systemui.volume.VolumeUI</item>
        <item>com.android.systemui.statusbar.phone.StatusBar</item>
        <item>com.android.systemui.usb.StorageNotification</item>
        <item>com.android.systemui.power.PowerUI</item>
        <item>com.android.systemui.media.RingtonePlayer</item>
        <item>com.android.systemui.keyboard.KeyboardUI</item>
        <item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
        <item>@string/config_systemUIVendorServiceComponent</item>
        <item>com.android.systemui.util.leak.GarbageMonitor$Service</item>
        <item>com.android.systemui.LatencyTester</item>
        <item>com.android.systemui.globalactions.GlobalActionsComponent</item>
        <item>com.android.systemui.ScreenDecorations</item>
        <item>com.android.systemui.biometrics.AuthController</item>
        <item>com.android.systemui.SliceBroadcastRelayHandler</item>
        <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
        <item>com.android.systemui.theme.ThemeOverlayController</item>
        <item>com.android.systemui.accessibility.WindowMagnification</item>
        <item>com.android.systemui.accessibility.SystemActions</item>
        <item>com.android.systemui.toast.ToastUI</item>
        <item>com.android.systemui.wmshell.WMShell</item>
    </string-array>

第一步总结

SystemUI怎么启动的。

SystemServer启动的时候,执行run, 调用 startOtherServices(t); 调用 startSystemUi(context, windowManagerF);

启动了 SystemUIService 服务,在该服务的onCreate(),检查了是否已经启动,避免了多次启动,然后加载了需要的系统UI服务。

Factory的小秘密 (SystemUIFactory的构建)

  • APP启动的基础流程。

Android应用程序的启动始于Zygote进程 fork 出一个新的子进程。对于每一个Android应用程序,其生命周期的起点可以认为是从ActivityThread类的main()方法开始的。以下是简化后的ActivityThread启动流程:

  1. 系统启动应用进程
    • 当用户点击图标或者通过其他方式触发一个应用组件(如Activity)启动时,系统首先找到对应的Package以及进程信息。
    • 如果需要,系统会通过Zygote机制fork出一个新的进程。
  2. 初始化ApplicationThread
    • 在新进程中,ActivityThreadmain()方法被调用,这是进程的实际入口点。
    • main()方法中会创建一个内部类ApplicationThread实例,这个类继承自IApplicationThread接口,并实现了Binder通信所需的AIDL接口,它是ActivityThread与系统服务(主要是ActivityManagerService,简称AMS)之间进行跨进程通信的桥梁。
  3. 绑定至AMS
    • ActivityThread将创建的ApplicationThread对象注册给AMS,这样AMS就可以通过Binder机制向该进程发送指令,包括启动、停止或重启Activity等操作。
  4. 创建Application实例
    • ActivityThread接着会加载并创建应用程序定义的Application类实例,并调用其生命周期方法。
  5. 启动第一个Activity
    • 当AMS决定启动某个Activity时,会通过Binder机制调用ApplicationThread的相应方法,这些方法最终会在ActivityThread的主线程中回调。
    • ActivityThread接收到启动Activity的消息后,会通过一系列步骤,如准备Context、Instrumentation、Intent等,进而调用performLaunchActivity()方法创建并启动目标Activity。

总结来说,ActivityThread并不是由开发者直接启动的,而是由Android系统在创建新的应用程序进程时自动启动,并作为该进程的主线程运行,负责管理整个应用组件的生命周期和系统服务之间的交互。

java 复制代码
 Process.java -->start()
                -->startViaZygote(processClass, niceName, uid, gid, gids,
                    runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false,
                    packageName, zygotePolicyFlags, isTopApp, disabledCompatChanges,
                    pkgDataInfoMap, allowlistedDataInfoList, bindMountAppsData,
                    bindMountAppStorageDirs, zygoteArgs);
                    最终启动ActivityThread的main()。
   
  • 应用的创建 和AppComponentFactory
java 复制代码
 
 performLaunchActivity()-->
 Application app = r.packageInfo.makeApplication(false, mInstrumentation);
   -->  app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);



// 看这块代码
 public Application newApplication(ClassLoader cl, String className, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        Application app = getFactory(context.getPackageName())
                .instantiateApplication(cl, className);
        app.attach(context);
        return app;
    }

 private AppComponentFactory getFactory(String pkg) {
        if (pkg == null) {
            Log.e(TAG, "No pkg specified, disabling AppComponentFactory");
            return AppComponentFactory.DEFAULT;
        }
   //没配置则走默认 有则走对应的factory
        if (mThread == null) {
            Log.e(TAG, "Uninitialized ActivityThread, likely app-created Instrumentation,"
                    + " disabling AppComponentFactory", new Throwable());
            return AppComponentFactory.DEFAULT;
        }
        LoadedApk apk = mThread.peekPackageInfo(pkg, true);
        // This is in the case of starting up "android".
        if (apk == null) apk = mThread.getSystemContext().mPackageInfo;
        return apk.getAppFactory();
    }

SystemUIAppComponentFactory.java

  • 这里有个点 app instanceof ContextInitializer 如果你是这个接口 那么就回调了如下方法。

    createFromConfig() 根据当前启动的不同 ,可能是如下之一

    • com.android.systemui.SystemUIFactory

    • com.android.systemui.tv.TvSystemUIFactory

    • com.android.systemui.CarSystemUIFactory

java 复制代码
   @NonNull
    @Override
    public Application instantiateApplicationCompat(
            @NonNull ClassLoader cl, @NonNull String className)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        Application app = super.instantiateApplicationCompat(cl, className);
        if (app instanceof ContextInitializer) {
            ((ContextInitializer) app).setContextAvailableCallback(
                    context -> {
                      //回调该方法 使用dagger2完成一个注入
                        SystemUIFactory.createFromConfig(context);
                         //这里根据启动的时候的配置 可能 是 com.android.systemui.SystemUIFactory / com.android.systemui.tv.TvSystemUIFactory/ com.android.systemui.CarSystemUIFactory
                        
                        SystemUIFactory.getInstance().getSysUIComponent().inject(
                                SystemUIAppComponentFactory.this);
                    }
            );
        }

        return app;
    }

再次回到SystemUIApplication

ini 复制代码
public void onCreate() {
        super.onCreate();
        
        //构建注入完成 可以使用
        mRootComponent = SystemUIFactory.getInstance().getRootComponent();
        mSysUIComponent = SystemUIFactory.getInstance().getSysUIComponent();
        mComponentHelper = mSysUIComponent.getContextComponentHelper();
        mBootCompleteCache = mSysUIComponent.provideBootCacheImpl();
        
        }

最后的总结

SystemServer启动的时候,执行run方法, 调用 startOtherServices(t); 调用 startSystemUi(context, windowManagerF);

在SystemUIApplication 创建的时候,使用了SystemUIAppComponentFactory 使用dagger2构建了SystemUIFactory。

在启动动 SystemUIService 服务,在该服务的onCreate(),检查了是否已经启动,避免了多次启动,然后加载了需要的系统UI样式。

相关推荐
安冬的码畜日常1 小时前
【D3.js in Action 3 精译_029】3.5 给 D3 条形图加注图表标签(上)
开发语言·前端·javascript·信息可视化·数据可视化·d3.js
小白学习日记2 小时前
【复习】HTML常用标签<table>
前端·html
丁总学Java2 小时前
微信小程序-npm支持-如何使用npm包
前端·微信小程序·npm·node.js
yanlele2 小时前
前瞻 - 盘点 ES2025 已经定稿的语法规范
前端·javascript·代码规范
懒羊羊大王呀3 小时前
CSS——属性值计算
前端·css
DOKE3 小时前
VSCode终端:提升命令行使用体验
前端
xgq3 小时前
使用File System Access API 直接读写本地文件
前端·javascript·面试
用户3157476081353 小时前
前端之路-了解原型和原型链
前端
永远不打烊3 小时前
librtmp 原生API做直播推流
前端