Analyse du code source Android 12 - Couche applicative 2 (Organisation générale et processus de démarrage de SystemUI)

Analyse du code source Android 12 - Couche applicative 2 (Organisation générale et processus de démarrage de SystemUI)

Dans l'article précédent, nous avons présenté comment SystemUI utilise l'IDE pour l'édition et le débogage. Il s'agit de l'analyse la plus élémentaire de SystemUI, et j'espère que les lecteurs pourront la maîtriser autant que possible.

Cet article présentera la structure organisationnelle approximative de SystemUI et son processus de démarrage. Après avoir lu cet article, vous saurez :

  1. Pourquoi SystemUI choisit d'utiliser Dagger2
  2. Comment créer un nouveau module dans SystemUI
  3. Processus de démarrage de SystemUI

Avant de lire, suivez-moi pour réfléchir aux questions suivantes :

  1. Quelles fonctions SystemUI doit-il remplir ?
  2. Les différentes fonctions doivent-elles communiquer entre elles ?
  3. Si une communication entre fonctions est nécessaire, comment organiser la relation de référence entre elles
  4. Chaque fonction doit-elle communiquer avec les services système ?
  5. Si chaque fonction a besoin de communiquer avec les services système, comment organiser efficacement les références entre elles ?
  6. Existe-t-il des dépendances entre différentes fonctions ?
  7. Existe-t-il des exigences de commande pour démarrer diverses fonctions ?

Pour les problèmes 1, 2 et 3 ci-dessus, nous pouvons voir sur l'interface que SystemUI comprend : un écran de verrouillage, une barre d'état, une barre de navigation, un affichage Toast, un réglage du volume et d'autres fonctions. Ces fonctions peuvent faire référence les unes aux autres, par exemple, le module de barre d'état a besoin de connaître la situation du module d'écran de verrouillage, afin de décider s'il doit masquer certaines icônes de la barre d'état.

Ces fonctions vont plus ou moins interagir avec le système. Par exemple, le module d'écran de verrouillage a besoin de connaître l'état du bouton d'alimentation pour décider d'afficher ou de masquer l'écran de verrouillage ; un autre exemple est de savoir si chaque module fonctionnel doit afficher le mode nuit, etc.

De là, nous savons déjà que chaque module doit se référer les uns aux autres et communiquer avec le système. Pour cela, il est nécessaire de concevoir une bonne architecture pour que chaque module puisse facilement obtenir les objets souhaités, et la création de ces objets puisse nécessite également Dépend de la création d'autres objets. En fait, les dépendances entre les différents objets de SystemUI sont relativement complexes : si vous créez chaque objet manuellement, vous devez écrire beaucoup de code. Pour ce faire, nous utilisons une nouvelle méthode de gestion des composants : DI (injection de dépendances)

L'idée centrale de l'injection de dépendances est la suivante : lors de l'écriture du code, ce n'est plus au développeur de modifier explicitement la façon dont chaque objet doit être créé, mais la bibliothèque d'injection de dépendances décide comment créer l'objet. SystemUI a choisi Dagger2 comme bibliothèque d'injection de dépendances.

Remarque : Que faut-il expliquer ici ? La dépendance signifie que le composant A doit utiliser un autre composant B pour remplir sa fonction, qui est appelé A en fonction de B. A et B peuvent être des classes, des objets, des modules, etc. Alors, qu’est-ce que l’injection ? L'injection est le processus de fourniture de dépendances aux composants.

Nous avons maintenant conçu comment obtenir les objets souhaités entre chaque module - Injection de dépendances Dagger.

Réfléchissez maintenant à la manière de communiquer entre SystemUI et le système ? Cela implique comment diviser SystemUI. En tant que composant de base de l'interface utilisateur de l'ensemble du système, SystemUI occupe une position très importante dans l'ensemble du système Android. Afin de s'adapter à des scénarios plus divers tels qu'Android TV et Android Car, ils peuvent avoir des SystemUI différents, tout en respectant la conception modulaire. Par conséquent, SystemUI est conçu comme un apk résidant en mémoire.

Maintenant que SystemUI a été conçu comme un apk, il s'exécute séparément dans un autre processus. Pour communiquer avec le système, il ne peut interagir que via les quatre composants principaux d'Android et utiliser le Binder d'Android pour interagir. SystemUI devient alors une collection de divers services, activités, BroadcastReceivers et ContentProviders. Activez ensuite ces composants le cas échéant.

Sur la base de la réflexion précédente, chaque module fonctionnel, tel que l'écran de verrouillage, la barre d'état et la barre de navigation, peut être affiché au bon endroit à condition qu'il soit placé dans le composant approprié. Parallèlement, afin de faciliter l'accès aux autres modules, nous utilisons également Dagger pour nous assister.

Tout a l’air bien, mais est-ce vraiment bien ? Vous avez manqué une question importante ? Y a-t-il un ordre entre ces modules ? Afin d'entrer rapidement dans le système, actuellement SystemUI n'impose pas cette exigence. Si un certain module doit attendre qu'un autre module soit prêt avant de pouvoir fonctionner normalement, alors la logique de conception doit être ajustée.

Découvrez les composants de SystemUI

D'après ce qui précède, nous savons que SystemUI est divisé en quatre composants principaux dans leur ensemble, vérifions donc AndroidManifest.xml pour voir quels composants sont définis.

Sur la branche android-12.0.0_r34, AndroidManifest.xml contient 38 activités, 11 services, 4 fournisseurs et 11 récepteurs.

Ensuite, je donnerai une brève description de chaque composant, et dans les chapitres suivants, nous présenterons en détail comment ces composants sont démarrés et quelles fonctions ils remplissent.

Activités

  1. LongScreenShotActivity : La vue utilisée pour les captures d'écran longues. Cette activité est appelée lorsque l'utilisateur décide de prendre une longue capture d'écran.
  2. ScreenRecordDialog : la vue de la boîte d'options qui apparaît lors de l'enregistrement de l'écran.
  3. TunerActivity : Il s'agit d'une interface de réglage fin pour les développeurs. Vous pouvez utiliser la commande suivante pour ouvrir l'entrée de l'interface
adb shell pm enable com.android.systemui/com.android.systemui.tuner.TunerActivity

Entrez ensuite dans l'interface dans Paramètres->Système->System UI Tuner

  1. DemoMode : Le mode Démo de SystemUI est également utilisé par les développeurs. Il s'agit d'un complément fonctionnel à TunerActivity et peut être activé dans les options du développeur.
  2. ForceReSizingInfoActivity : les applications contextuelles ne peuvent pas s'exécuter en mode écran partagé ou sur des écrans secondaires
  3. UsbPermissionActivity : boîte contextuelle de confirmation de l'autorisation USB
  4. UsbResolverActivity : sélectionnez une boîte de dialogue d'application pour le périphérique USB
  5. UsbConfirmActivity : affiche une vue pour déterminer s'il faut utiliser une application, qui est la vue suivante de UsbResolverActivity
  6. SensorUseStartedActivity : lorsque le capteur est en mode confidentialité, la boîte de dialogue contextuelle lorsque vous souhaitez utiliser le capteur
  7. TvUnblockSensorActivity : identique à SensorUseStartedActivity, sauf qu'il s'agit de la vue utilisée sur le téléviseur.
  8. UsbAccessoryUriActivity : Une boîte apparaît pour vous permettre de télécharger l'application correspondant à ce périphérique USB
  9. UsbContaminantActivity : une boîte de dialogue apparaît indiquant que la clé USB a été désactivée. La raison de la désactivation peut être qu'il y a des biens volés sur le port USB.
  10. UsbDebuggingActivity : apparaît si le débogage USB doit être autorisé
  11. UsbDebuggingActivityAlias : c'est l'alias de UsbDebuggingActivity
  12. WifiDebuggingActivity : affiche si le débogage sans fil doit être autorisé sur le réseau.
  13. WifiDebuggingActivityAlias : est l'alias de WifiDebuggingActivity
  14. WifiDebuggingSecondaryUserActivity : apparaît. L'utilisateur actuellement connecté ne peut pas activer le débogage sans fil et doit être basculé vers l'utilisateur principal.
  15. NetworkOverLimitActivity : le trafic de données contextuelles a atteint la limite supérieure
  16. MediaProjectionPermissionActivity : Confirmation de l'autorisation de projection multimédia
  17. TvNotificationPanelActivity : dédié à la télévision, affiche une boîte de message
  18. SlicePermissionActivity : boîte contextuelle d'autorisation de tranche
  19. DessertCase:Un des œufs de Pâques
  20. MLandActivity : mini-jeu d'œufs de Pâques
  21. PeopleSpaceActivity : inviter l'emplacement de l'interface utilisateur Pepole Space, nouvelles fonctionnalités d'Android 11
  22. LaunchConversationActivity : lorsque vous cliquez sur la session, développez la vue, nouvelles fonctionnalités d'Android 11
  23. WorkLockActivity : déverrouillez l'interface du profil professionnel
  24. CreateUserActivity : créer une vue utilisateur
  25. Somnambulateur : économiseur d'écran
  26. BrightnessDialog : boîte contextuelle de luminosité
  27. ForegroundServicesDialog : une boîte contextuelle qui affiche les services de premier plan
  28. ChooserActivity : affiche une boîte de dialogue permettant à l'utilisateur de choisir quelle application ouvrir pour gérer l'intention actuelle.
  29. ControlsProviderSelectorActivity apparaît "Sélectionnez l'application pour ajouter un contrôleur"
  30. ControlsEditingActivity : modifiez le contrôleur, faites glisser et déposez pour modifier
  31. ControlsFavoritingActivity : Contrôleur, préférences
  32. ControlsActivity : répertorier les contrôleurs de périphériques
  33. WalletActivity : portefeuille électronique
  34. ControlsRequestDialog : demande de contrôle pour ajouter une boîte contextuelle de contrôleur de périphérique

Remarque : Les commandes ici sont des contrôleurs de périphériques externes, tels que les contrôleurs de l'intelligence globale de la maison.

Ce qui précède n’est qu’un aperçu très simple, et certains détails courants de la logique des composants et de l’interface utilisateur apparaîtront dans les articles suivants.

Voyant cela, certains lecteurs peuvent se demander : Les activités ci-dessus ne semblent pas avoir de barre d'état ni d'écran de verrouillage. Leurs points de vue ne sont-ils pas dans ces activités ?

Pour explorer cette question, nous devons d’abord examiner les composants restants.

Prestations de service

  1. SystemUIService : Wow, quel nom rafraîchissant. Ce service contient la plupart des fonctions de SystemUI. C'est également la priorité absolue de notre analyse du code source SystemUI.
  2. SystemUISecondaryUserService : dans le cas de plusieurs utilisateurs, ce service garantit que les fonctions SystemUI de plusieurs utilisateurs sont normales.
  3. SystemUIAuxiliaryDumpService : pour le développement et l'utilisation, videz les informations de chaque composant nécessaire et affichez-les
  4. TakeScreenshotService : services liés à la capture d'écran
  5. RecordingService : services liés à l'enregistrement d'écran
  6. ImageWallpaper : services liés au papier peint
  7. PeopleBackupFollowUpJob : Services liés à l'interface utilisateur du service People
  8. DessertCaseDream:Petit œuf de Pâques
  9. KeyguardService : services liés à l'écran de verrouillage
  10. AuxiliaryPersistenceWrapper$DeletionJobService : services liés aux contrôleurs de périphériques externes
  11. DozeService : Services liés à Doze

Fournisseur de contenu篇

  1. FileProvider : fournir des fichiers
  2. KeyguardSliceProvider : fournit un écran de verrouillage Slice
  3. ClockOptionsProvider : fournit un aperçu de l'horloge pour le programme de sélection
  4. PeopleProvider : renvoie un aperçu de la vignette de personnes pour un raccourci donné

BroadcastReceiver篇

  1. ScreenshotServiceErrorReceiver : capture d'écran du récepteur de diffusion défaillant
  2. SysuiRestartReceiver : redémarrer le récepteur de diffusion SystemUI
  3. ActionProxyReceiver : intercepter l'intention de partage et de modification, récepteur de diffusion pour traiter certaines choses à l'avance
  4. SupprimerScreenshotReceiver : Supprimer le récepteur de diffusion de capture d'écran
  5. SmartActionsReceiver : une fois que l'utilisateur a cliqué sur l'action intelligente dans la notification, il est utilisé pour recevoir la diffusion correspondante et exécuter l'action intelligente.
  6. ControlsRequestReciver : un récepteur de diffusion qui reçoit les demandes d'ajout de contrôleurs
  7. TunerService$ClearReciver : récepteur de diffusion clair utilisé pour appeler TunerService
  8. KeyboardShortcutsReceiver : récepteur de diffusion qui affiche ou masque les raccourcis clavier
  9. MediaOutputDialogReceiver : récepteur de diffusion qui reçoit la sortie multimédia
  10. PeopleSpaceWidgetPinnedReceiver : ce récepteur est appelé lorsqu'un widget Tile de contact est ajouté
  11. PeopleSpaceWidgetProvider : implémentation du widget People Space

Après avoir lu jusqu'ici, les lecteurs ont encore des questions : où sont affichés l'écran de verrouillage et la barre d'état de SystemUI ? L’interface utilisateur peut-elle être affichée dans le service ? C'est évidemment déraisonnable. Alors, comment l'écran de verrouillage et la barre d'état d'Android s'affichent-ils ?

Astuce : En plus des composants répertoriés ci-dessus pour afficher les vues, SystemUI affiche également les vues en interagissant directement avec WindowManager. Quoi~~ Soupirez-vous, l'architecture de conception d'Android est vraiment un peu déroutante.

Non représenté ici, sera expliqué en détail plus tard. Ensuite, nous devons traiter du Dagger2 susmentionné, comment il gère la relation de référence de chaque composant dans SystemUI.

Conception des composants internes de SystemUI

Nous voulons que Dagger2 gère les dépendances de chaque composant, nous devons donc indiquer à Dagger2 quelles sont les dépendances et quelle méthode doit être utilisée ? Est-il décrit par un fichier XML ? Ou utiliser une autre méthode ?

Dagger2 utilise des annotations Java pour décrire les dépendances entre elles. Dans le même temps, afin d'améliorer les performances, Dagger2 générera différents objets Java basés sur les annotations lors de la compilation, puis organisera toutes les dépendances et cycles de vie dans les objets Java générés.

Les annotations utilisées pour représenter diverses dépendances sont appelées dessiner un graphique pour Dagger2. Ensuite, nous combinons les exemples dans SystemUI pour voir comment SystemUI dessine un graphique pour Dagger2.

Application de Dagger2 dans SystemUI

Dans notre idée, nous avons besoin d'un objet le plus haut tel que RootManager. Ensuite, nous pouvons obtenir chaque objet dont nous avons besoin en fonction de ce RootManager.

Dans SystemUI, il existe toujours un tel RootManager. Il s'agit de : GlobalRootComponent. Pour chaque module de SystemUI, si vous souhaitez obtenir l'objet souhaité, vous pouvez l'obtenir via GlobalRootComponent.

Remarque : les lecteurs, en lisant ceci, seront certainement très confus quant à la raison pour laquelle il est appelé Composant au lieu de Manager. Après tout, Manager est si courant sur Android. En effet, SystemUI utilise l'abstraction de Dagger2. Dans Dagger2, Component représente un composant. En fait, c'est un conteneur qui contient toutes les dépendances qu'il peut fournir. Par conséquent, GlobalRootComponent est un composant qui peut être fourni à toutes les dépendances.

Voyons donc comment dessiner une image pour GlobalRootComponent.

//@Singeton:告诉Dagger2所有带有@singtone注解的对象,生命周期一致。此处表示全局唯一
//@Component(xxx):告诉Dagger2,定义了一个Component组件
//modules={xxx}:告诉Dagger2,这个组件依赖这些模块。关于模块的概念,见后文
@Singleton
@Component(modules = {
    
    
        GlobalModule.class,
        SysUISubcomponentModule.class,
        WMModule.class})
//此处是interface接口定义,Dagger2会生成对应的实现类,并按照我们给Dagger2的注解图,管理好
//各个对象的依赖和创建
public interface GlobalRootComponent {
    
    

    //@Component.Builder:
    //告诉Dagger2,这个是创建GlobalRootComponent的Builder类
    //请务必要思考:为什么此处的对象创建要用Builder模式,而不是工厂模式?
    @Component.Builder
    interface Builder {
    
    
        @BindsInstance
        Builder context(Context context);

        GlobalRootComponent build();
    }

    //提供一个方法,这个方法的返回类型,就是这个组件可以提供的依赖,此处表示可以提供
    //WMComponent.Builder对象
    WMComponent.Builder getWMComponentBuilder();

    //表示此组件可以提供,SysUIComponent.Builder对象
    SysUIComponent.Builder getSysUIComponent();

    //注:上面两个方法提供的返回类型可以看到,他们依然是一个Component

    //表示可以提供ThreadFactory对象
    ThreadFactory createThreadFactory();
}

Dans l'exemple ci-dessus, nous avons évoqué le concept de module. Avant d'introduire ce concept, réfléchissons à une question : Et s'il y avait de nombreuses dépendances dans GlobalRootComponent ? Si chacune est dessinée sur le diagramme, cela aura l'air compliqué, donc dagger2 fournit une fonction pour diviser logiquement ces différentes dépendances à l'aide de modules. Ensuite, il vous suffit de spécifier les éléments suivants lors du dessin du composant :

@Component(modules={
    
    xxx.class})

Nous sélectionnons SysUISubComponentModule à afficher, le code source est le suivant :

//@Module:告诉Dagger2,这个module内的所有依赖,逻辑划分为:SysUISubcomponentModule
//subcomponents = {SysUIComponent.class}:告诉Dagger2,这个模块含有SysUIComponent子组件
//关于子组件的概念,我们下文介绍
@Module(subcomponents = {
    
    SysUIComponent.class})
public abstract class SysUISubcomponentModule {
    
    
}

Dans l'exemple ci-dessus, nous avons mentionné le sous-composant. Avant d'introduire ce concept, réfléchissons à une autre question : si un composant fournit un objet à d'autres utilisateurs, l'objet fourni doit-il être créé à chaque fois ou une seule fois ? Il s'agit du cycle de vie de l'objet. Afin de mieux gérer le cycle de vie, nous recommandons de placer les objets appartenant au même cycle de vie dans un sous-composant. Par conséquent, tous les objets du sous-composant SysUIComponent ci-dessus appartiendront au même cycle de vie. Bien entendu, les sous-composants peuvent non seulement isoler le cycle de vie, mais également isoler le module pour rendre le code plus clair.

Voyons donc comment ce sous-composant est informé à Dagger2.

//@SysUISingleton:告诉Dagger2所有SysUISingleton注解的对象生命周期相同
//@Subcomponent:告诉Dagger2,这是一个子组件
//modules={xxx}:告诉dagger2,这个子组件有这么些module的需要依赖
@SysUISingleton
@Subcomponent(modules = {
    
    
        DefaultComponentBinder.class,
        DependencyProvider.class,
        SystemUIBinder.class,
        SystemUIModule.class,
        SystemUIDefaultModule.class})
public interface SysUIComponent {
    
    

    //告诉Dagger2生命周期
    @SysUISingleton
    //告诉Dagger2这个子组件的Builder接口定义
    @Subcomponent.Builder
    interface Builder {
    
    
        //省略若干相同部分

        //@BindsInstance:告诉Dagger2,将t绑定到这个Builder对象中
        //在Dagger2根据我们画的图,会根据这个Builder接口,生成一个SysUIComponentBuilder对象
        //在这个对象中,会有一个成员,类型为Optional<TaskSurfaceHelper>名字为setTaskSurfaceHelper.
        //然后这个setTaskSurfaceHelper()接口函数的实现,就会将参数传入的t保存在setTaskSurfaceHelper成员中。
        //这个过程就叫做:绑定实例,也即@BindsInstance的语义
        @BindsInstance
        Builder setTaskSurfaceHelper(Optional<TaskSurfaceHelper> t);

        //任何一个Builder接口,都必须有一个build()函数,且返回类型为需要构建的对象类型,此处即为SysUIComponent
        SysUIComponent build();
    }

    //定义了一个默认方法,这个方法什么也没有做
    default void init() {
    
    
        // Do nothing
    }

    //告诉Dagger2它的生命周期
    @SysUISingleton
    //subcomponent和component一样,如果想要对外提供依赖,就可以定义任何一个函数,函数的返回类型就是
    //被提供对象的类型。
    BootCompleteCacheImpl provideBootCacheImpl();


    //省略若干相同部分

    //当返回类型为空,而传入类型不为空的时候,表示需要向传入类型对象(SystemUIAppComponentFactory)
    //中被@inject标记的成员赋值,叫做注入
    //理论上,函数名为任意值,但是此种函数,几乎只会完成注入的功能,因此此函数最后都叫做inject
    void inject(SystemUIAppComponentFactory factory);

    //省略若干相同部分
}

Dans la fonction d'injection ci-dessus, nous pouvons voir à quoi ressemble SystemUIAppComponentFactory. Le code source est le suivant :

public class SystemUIAppComponentFactory extends AppComponentFactory {
    
    

    //@Inject:告诉Dagger2,这个成员,需要Dagger2的注入。
    //可是Dagger2又是如何知道,该怎么创建ContextComponentHelper的呢?
    //这就是我们给Dagger2画图的作用,我们已经提前画好图给Dagger2,告诉它应该
    //怎么创建这个ContextComponentHelper
    @Inject
    public ContextComponentHelper mComponentHelper;

}

Voyons ensuite comment nous dessinons des images pour ContextComponentHelper. Le code source est le suivant :

public interface ContextComponentHelper {
    
    
    //省略若干无用部分
}

À partir du code source ci-dessus, nous pouvons savoir qu'il n'a aucune annotation, c'est-à-dire qu'il n'est pas dessiné dans le diagramme Dagger2. Il existe d'autres classes dessinées dans le diagramme Dagger2. La classe d'implémentation de ContextComponentHelper est : ContextComponentResolver. La source le code est le suivant :

//@SysUISingleton:告诉Dagger2它的生命周期
@SysUISingleton
public class ContextComponentResolver implements ContextComponentHelper {
    
    
    private final Map<Class<?>, Provider<Activity>> mActivityCreators;
    private final Map<Class<?>, Provider<Service>> mServiceCreators;
    private final Map<Class<?>, Provider<SystemUI>> mSystemUICreators;
    private final Map<Class<?>, Provider<RecentsImplementation>> mRecentsCreators;
    private final Map<Class<?>, Provider<BroadcastReceiver>> mBroadcastReceiverCreators;

    //@Inject:此处就是告诉Dagger图,注入Dagger2的各种辅助功能,帮助创建这个对象
    //在创建对象的时候,需要它的各种参数,而这些参数又应该怎么被Dagger2提供呢?
    //只要我们把需要的参数,画好图给Dagger2即可,过程就和这个ContextComponentResolver一样啦,
    //在构造器上面标注一下@Inject就可以了
    @Inject
    ContextComponentResolver(Map<Class<?>, Provider<Activity>> activityCreators,
            Map<Class<?>, Provider<Service>> serviceCreators,
            Map<Class<?>, Provider<SystemUI>> systemUICreators,
            Map<Class<?>, Provider<RecentsImplementation>> recentsCreators,
            Map<Class<?>, Provider<BroadcastReceiver>> broadcastReceiverCreators) {
    
    
        mActivityCreators = activityCreators;
        mServiceCreators = serviceCreators;
        mSystemUICreators = systemUICreators;
        mRecentsCreators = recentsCreators;
        mBroadcastReceiverCreators = broadcastReceiverCreators;
    }

    //省略若干无用部分
}

En voyant cela, nous avons déjà une idée générale de la façon d'utiliser Dagger2 (comment lui fournir une image). Mais si vous y réfléchissez bien, il y a toujours un problème - si certaines classes ne sont pas créées par nous, alors nous ne pouvons pas ajouter @Inject au constructeur, alors comment pouvons-nous faire savoir à Dagger2 : quand il a besoin de cet objet, comment devrait-il Être créé? À l'heure actuelle, Dagger2 fournit une autre annotation @Provides.

Nous prenons GlobalModule comme exemple pour illustrer. Le code source est le suivant :

//@Module:告诉Dagger2,定义一个逻辑模块,这个模块包含FrameworkServicesModule,GlobalConcurrencyModule
@Module(includes = {
    
    
        FrameworkServicesModule.class,
        GlobalConcurrencyModule.class})
public class GlobalModule {
    
    

    //@Provides:告诉Dagger2,如果需要DisplayMetrics对象,就调用provideDisplayMetrics()函数即可
    //至于这个函数需要的参数Context,该怎么创建,Dagger2已经能够从我们给它的图中自动找到了
    @Provides
    public DisplayMetrics provideDisplayMetrics(Context context) {
    
    
        DisplayMetrics displayMetrics = new DisplayMetrics();
        context.getDisplay().getMetrics(displayMetrics);
        return displayMetrics;
    }

}

Jusqu'à présent, nous avons présenté grossièrement comment dessiner des images dans Dagger2 (c'est-à-dire comment utiliser les annotations), par exemple comment utiliser @Component, @SubComponent, @Inject, @Provides, @Module, etc. Il existe d'autres annotations qui n’ont pas été introduits dans Dagger2, mais cela suffit pour la suite de cet article. Pour d'autres annotations, vous pouvez directement vous référer à la documentation de Dagger2. Cet article se concentre uniquement sur l'analyse de SystemUI.

Cependant, ce qui précède n'est qu'un dessin et ne mentionne pas comment l'utiliser. Ensuite, nous combinerons le processus de démarrage de SystemUI pour voir comment utiliser l'image Dagger2 dessinée ci-dessus.

Processus de démarrage de SystemUI

Le démarrage de n'importe quel Apk commence à partir de ses quatre composants principaux. Avant de démarrer les quatre composants principaux, il vérifiera s'il existe une application personnalisée. Si c'est le cas, l'application sera créée en premier.

À partir d'Android 9, une AppComponentFactory a été ajoutée pour effectuer les opérations correspondantes avant de créer les quatre composants principaux. Comme Application, il est configuré dans AndroidManifest.xml, comme suit :

<application
        android:name=".SystemUIApplication"
        .
        .
        .
        android:appComponentFactory=".SystemUIAppComponentFactory">
        <!--省略若干不相干话题-->
</application>

À partir de cette configuration, nous pouvons voir le processus de démarrage suivant :

SystemUIAppComponentFactory->SystemUIApplication->un composant à démarrer (les quatre composants majeurs d'Android).

Avant d'analyser plus en détail ce processus, voyons qui a lancé SystemUI.

Le point de départ de system_server

Mais certains lecteurs se demanderont : qui a lancé SystemUI ? Vous voyez que d'autres applications sont démarrées en cliquant sur l'icône, qui a démarré SystemUI ?

Bonne réponse : SystemUI est démarré par un processus appelé system_server dans le système Android. system_server est démarré lorsque l'ordinateur est allumé, puis system_server démarre divers services clés, y compris le démarrage de SystemUI. Cela sera expliqué en détail plus tard lors de l'analyse de system_server.

Seule une brève description du démarrage de SystemUI par system_server est donnée ici :

  1. Une fois que le système aura démarré le processus system_server, il exécutera
new SystemServer().run();
  1. Dans la méthode run(), divers services seront démarrés, notamment :
  • Démarrer le service de démarrage
  • les services de base
  • autre service
  1. Lors du démarrage d'autres services, SystemUI sera démarré (via Intent). Pour obtenir les composants spécifiques qui démarrent SystemUI,
    vous pouvez les obtenir via PackageManager d'Android.

  2. Le PacakgeManager obtient le nom du composant spécifique en lisant la configuration config_systemUIServiceComponent. Dans le système Android, cette configuration
    est

<string name="config_systemUIServiceComponent" translatable="false"
            >com.android.systemui/com.android.systemui.SystemUIService</string>

On peut voir que c'est exactement le composant que nous avons défini dans SystemUI.

Ensuite, nous pouvons résumer le processus de démarrage de SystemUI

  1. Le démarrage du système Android est terminé, démarrez system_server
  2. system_server, selon la configuration, démarre les composants SystemUI via Intent
  3. Avant que SystemUI ne démarre le composant, il créera d'abord l'objet SystemUIAppComponentFactory, puis appellera sa méthode correspondante.
  4. Ensuite, SystemUI créera SystemUIApplication, puis appellera sa méthode correspondante
  5. Enfin, SystemUI créera SystemUIService et appellera la méthode correspondante. Avant de créer SystemUIService, il appellera la méthode correspondante de l'objet SystemUIAppComponentFactory créé à l'étape 3.

Pourquoi utiliser SystemUIAppComponentFactory

Le code source de SystemUIAppComponentFactory est le suivant :

public class SystemUIAppComponentFactory extends AppComponentFactory {
    
    

    private static final String TAG = "AppComponentFactory";
    @Inject
    public ContextComponentHelper mComponentHelper;

    public SystemUIAppComponentFactory() {
    
    
        super();
    }

    @NonNull
    @Override
    //在创建Application之前,这个函数被调用
    public Application instantiateApplicationCompat(
            @NonNull ClassLoader cl, @NonNull String className)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
    
    
        //调用父类方法,创建Application,此处会创建AndroidManifest.xml中配置的类
        //也即SystemUIApplication
        Application app = super.instantiateApplicationCompat(cl, className);
        //倘若创建的组件是ContextInitializer,则注册一个回调
        //请一定注意:虽然此处创建了Application,但是它还不能当做Context来使用
        if (app instanceof ContextInitializer) {
    
    
            ((ContextInitializer) app).setContextAvailableCallback(
                    context -> {
    
    
                        //1.在回调中,首先创建SystemUIFactory对象
                        SystemUIFactory.createFromConfig(context);
                        //2.通过这个SystemUIFactory得到SysUIComponent
                        //3.注入SystemUIAppComponentFactory中的成员,见上一小节
                        SystemUIFactory.getInstance().getSysUIComponent().inject(
                                SystemUIAppComponentFactory.this);
                    }
            );
        }

        return app;
    }

    @NonNull
    @Override
    //ContentProvider被创建之前,该函数被回调
    public ContentProvider instantiateProviderCompat(
            @NonNull ClassLoader cl, @NonNull String className)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
    
    
        //省略若干
        //此处没有列出内容,原因是:它的逻辑和上一个函数一样
    }

    @NonNull
    @Override
    public Activity instantiateActivityCompat(@NonNull ClassLoader cl, @NonNull String className,
            @Nullable Intent intent)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
    
    
        //省略若干
        //此处没有列出内容,原因是:它的逻辑和上一个函数一样
    }

    @NonNull
    @Override
    public Service instantiateServiceCompat(
            @NonNull ClassLoader cl, @NonNull String className, Intent intent)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
    
    
        //判断是否为空,如果是,则再次注入
        //第一次注入,在instantiateApplicationCompat()函数设置的回调中,
        //这个回调由SystemUIApplication的onCreate()触发
        if (mComponentHelper == null) {
    
    
            // This shouldn't happen, but does when a device is freshly formatted.
            // Bug filed against framework to take a look: http://b/141008541
            SystemUIFactory.getInstance().getSysUIComponent().inject(
                    SystemUIAppComponentFactory.this);
        }
        //注意:这里的Service的创建
        //1. 先查询mComponentHelper中是否有对应的Service
        //2. 如果有则直接用,如果没有则调用父类方法创建
        //对于SystemUIService而言,它的构造函数有@Inject注解,因此当调用mComponentHelper.resolveService时,能够正确返回SystemUIService
        //请思考:为什么这个不要系统自己创建?
        //答案:因为SystemUIService,需要有其他依赖对象,若是由系统创建,那么必然会有
        //像SystemUIService.setXXX()之类的函数,会增加代码和逻辑。如果由Dagger2来创建则不会有
        //这些烦恼
        Service service = mComponentHelper.resolveService(className);
        if (service != null) {
    
    
            return service;
        }
        return super.instantiateServiceCompat(cl, className, intent);
        
    }

    @NonNull
    @Override
    public BroadcastReceiver instantiateReceiverCompat(@NonNull ClassLoader cl,
            @NonNull String className, @Nullable Intent intent)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
    
    
        //省略若干
        //此处没有列出内容,原因是:它的逻辑和上一个函数一样
    }

}

Dans cette classe, les fonctions les plus importantes sont trois points :

  1. Création des composants correspondants, tels que SystemUIApplication, SystemUIService, etc.
  2. Initialisation de mComponentHelper, c'est-à-dire par injection
  3. Avant que le composant Service ne soit créé, il peut d'abord demander s'il existe déjà un composant dans mComponentHelper, et si c'est le cas, l'utiliser directement

Avant d’aborder la création de SystemUIApplication et SystemUIService, il faut encore réfléchir à nouveau à une question :
Pourquoi utiliser la classe SystemUIAppComponentFactory ? Ce cours est-il vraiment raisonnable ? Existe-t-il une meilleure alternative ?

Je pense que la réponse réside dans la création de SystemUIService. C'est l'utilisation de la classe SystemUIAppComponentFactory qui permet de mieux injecter les dépendances

Avant d'entrer dans SystemUIService, la première chose créée est SystemUIApplication. Voyons ce que ça fait.

SystèmeUIApplication

Le code source est le suivant :

public class SystemUIApplication extends Application implements
        SystemUIAppComponentFactory.ContextInitializer {
    
    

    public SystemUIApplication() {
    
    
        super();
        Log.v(TAG, "SystemUIApplication constructed.");
        // SysUI may be building without protolog preprocessing in some cases
        ProtoLog.REQUIRE_PROTOLOGTOOL = false;
    }

    @Override
    public void onCreate() {
    
    
        super.onCreate();
        Log.v(TAG, "SystemUIApplication created.");
        //用于跟踪启动和关闭的时序数据
        TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
                Trace.TRACE_TAG_APP);
        log.traceBegin("DependencyInjection");
        //这就是初始化各种Dagger2依赖的地方,这个回调在SystemUIAppComponentFactory中被设置
        mContextAvailableCallback.onContextAvailable(this);
        //有了Dagger2,就是直接使用对应的组件
        mRootComponent = SystemUIFactory.getInstance().getRootComponent();
        mSysUIComponent = SystemUIFactory.getInstance().getSysUIComponent();
        mComponentHelper = mSysUIComponent.getContextComponentHelper();
        mBootCompleteCache = mSysUIComponent.provideBootCacheImpl();
        log.traceEnd();

        //设置主题
        setTheme(R.style.Theme_SystemUI);

        //判断是否为主进程
        if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {
    
    
            //监听系统的启动广播
            IntentFilter bootCompletedFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
            bootCompletedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);

            //设置线程渲染优先级
            int sfPriority = SurfaceControl.getGPUContextPriority();
            Log.i(TAG, "Found SurfaceFlinger's GPU Priority: " + sfPriority);
            if (sfPriority == ThreadedRendererCompat.EGL_CONTEXT_PRIORITY_REALTIME_NV) {
    
    
                Log.i(TAG, "Setting SysUI's GPU Context priority to: "
                        + ThreadedRendererCompat.EGL_CONTEXT_PRIORITY_HIGH_IMG);
                ThreadedRendererCompat.setContextPriority(
                        ThreadedRendererCompat.EGL_CONTEXT_PRIORITY_HIGH_IMG);
            }

            //注册广播接收器
            registerReceiver(new BroadcastReceiver() {
    
    
                @Override
                public void onReceive(Context context, Intent intent) {
    
    
                    //mBootCompleteCache表示的是:是否SytemUI的各种服务启动完成
                    //这些服务的启动,可能早于系统启动完成广播,也可能晚于系统启动完成广播

                    //1. 如果SystemUI的各种服务已经启动完成则直接返回
                    if (mBootCompleteCache.isBootComplete()) return;

                    if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received");
                    //2. 如果没有启动完成,则挨个启动
                    unregisterReceiver(this);
                    mBootCompleteCache.setBootComplete();
                    if (mServicesStarted) {
    
    
                        final int N = mServices.length;
                        for (int i = 0; i < N; i++) {
    
    
                            mServices[i].onBootCompleted();
                        }
                    }
                }
            }, bootCompletedFilter);

            //监听是否Local改变
            //如果Local改变,则通知中的显示就需要改变,如中英文切换等
            IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
            registerReceiver(new BroadcastReceiver() {
    
    
                @Override
                public void onReceive(Context context, Intent intent) {
    
    
                    if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
    
    
                        if (!mBootCompleteCache.isBootComplete()) return;
                        // Update names of SystemUi notification channels
                        NotificationChannels.createAll(context);
                    }
                }
            }, localeChangedFilter);
        } else {
    
    
            //如果是子进程则会进入此部分逻辑

            //如果是主用户下的子进程,则什么也不做,直接返回
            String processName = ActivityThread.currentProcessName();
            ApplicationInfo info = getApplicationInfo();
            if (processName != null && processName.startsWith(info.processName + ":")) {
    
    
                return;
            }
            //如果不是主用户,则需要去启动必要的SystemUI组件
            startSecondaryUserServicesIfNeeded();
        }
    }

    //省略若干,简单代码

}

Le code de SystemUIApplication est relativement simple et il a été marqué dans les commentaires. Regard suivant sur SystemUIService

ServiceUISystème

Le code source est le suivant :

public class SystemUIService extends Service {
    
    

    //省略若干,简单代码

    //@Inject:嘿嘿,这就是给Dagger画的图,好让Dagger2知道怎么创建SystemUIService
    @Inject
    public SystemUIService(
            @Main Handler mainHandler,
            DumpHandler dumpHandler,
            BroadcastDispatcher broadcastDispatcher,
            LogBufferFreezer logBufferFreezer,
            BatteryStateNotifier batteryStateNotifier) {
    
    
        //省略赋值代码
    }

    @Override
    public void onCreate() {
    
    
        super.onCreate();

        //对没错,startServicesIfNeeded作为整个SystemUI关键服务的启动源头,就在这里了。
        //在进入分析之前,先思考:为什么要放在这里执行呢?就不能直接放在SystemUIApplication中吗?
        ((SystemUIApplication) getApplication()).startServicesIfNeeded();

        //LogBufferFreezer接收bugreport开始的广播,然后停止对应的LogBuffer的记录
        mLogBufferFreezer.attach(mBroadcastDispatcher);

        //是否监听电池的状态,并且会提示在通知栏上
        if (getResources().getBoolean(R.bool.config_showNotificationForUnknownBatteryState)) {
    
    
            mBatteryStateNotifier.startListening();
        }

        //调试代码,用debug.crash_sysui触发RescueParty
        if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.crash_sysui", false)) {
    
    
            throw new RuntimeException();
        }

        //Binder调试相关
        //如果太多binder调用就触发onLimitReached回调
        if (Build.IS_DEBUGGABLE) {
    
    
            //设置Binder代理计数开
            BinderInternal.nSetBinderProxyCountEnabled(true);
            //配置Binder代理触发BinderProxyLimitListener回调的最高和最低阈值,最低表示:只有降到最低以下,才能再次触发
            BinderInternal.nSetBinderProxyCountWatermarks(1000,900);
            //设置BinderProxyLimitListener监听
            BinderInternal.setBinderProxyCountCallback(
                    new BinderInternal.BinderProxyLimitListener() {
    
    
                        @Override
                        public void onLimitReached(int uid) {
    
    
                            Slog.w(SystemUIApplication.TAG,
                                    "uid " + uid + " sent too many Binder proxies to uid "
                                    + Process.myUid());
                        }
                    }, mMainHandler);
        }

        //启动DumpService,如果系统运行bugreport,SystemUIAuxiliaryDumpService会将SystemUI中的一些关键数据dump出来
        startServiceAsUser(
                new Intent(getApplicationContext(), SystemUIAuxiliaryDumpService.class),
                UserHandle.SYSTEM);
    }

    //省略若干,简单代码
}

Examinons ensuite le contenu spécifique de la fonction startServicesIfNeeded()

Fonction startServicesIfNeeded()

Cette fonction se trouve dans la classe SystemUIApplication et le code source est le suivant :

public void startServicesIfNeeded() {
    
    
    //1. 获取需要start的服务列表
    //2. 然后调用startServicesIfNeed()继续启动
    //注意:看到这里,其实大家应该大胆假设,getSystemUIServiceComponents函数
    //是不是通过Dagger2的依赖得到的。如果不是为什么?
    String[] names = SystemUIFactory.getInstance().getSystemUIServiceComponents(getResources());
    startServicesIfNeeded(/* metricsPrefix= */ "StartServices", names);
}

private void startServicesIfNeeded(String metricsPrefix, String[] services) {
    
    
    //省略判断

    mServices = new SystemUI[services.length];

    //启动完成缓存对象的修改,简单,略
    
    //首先获取DumpManager
    final DumpManager dumpManager = mSysUIComponent.createDumpManager();

    //trace跟踪点,略

    //挨个启动服务
    // 1. 首先查看mComponentHelper是否有缓存,如果有则直接使用
    // 2. 如果没有则反射创建
    // 3. 创建完成调用start()
    // 4. 判断是否系统启动完成,如果完成则调用onBootCompleted()
    // 5. 将启动的服务,加入DumpManager中,以便bugreport触发其dump
    final int N = services.length;
    for (int i = 0; i < N; i++) {
    
    
        String clsName = services[i];
        if (DEBUG) Log.d(TAG, "loading: " + clsName);
        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();
        log.traceEnd();

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

Comme vous pouvez le voir ci-dessus, la fonction principale de SystemUIService est d'appeler les fonctions start() et onBootCompleted() de chaque service. Démarrage terminé.

Maintenant, réfléchissez à la raison pour laquelle cette partie du contenu doit être placée dans SystemUIApplication, pourquoi ne peut-elle pas être placée directement dans SystemUIService ?

Avant de répondre à cette question, voyons d'abord comment la fonction getSystemUIServiceComponents() obtient les services qui doivent être démarrés.

La fonction getSystemUIServiceComponents obtient le service à démarrer

Le code source est le suivant :

public String[] getSystemUIServiceComponents(Resources resources) {
    
    
    return resources.getStringArray(R.array.config_systemUIServiceComponents);
}

La fonction ci-dessus est obtenue via le tableau de chaînes configuré. Vous pourriez être curieux : pourquoi est-il différent de Dagger2 ? Pourquoi configurer un tableau de chaînes pour une chose aussi pratique ?

Pourquoi est-il configuré de cette façon ? Je pense qu’il y a plusieurs raisons principales :

  1. Lors de la compilation du code AOSP, vous pouvez utiliser la fonction de remplacement pour placer ces fichiers de ressources dans un répertoire personnalisé à des fins de modification.
  2. Pour des raisons historiques, c'était configuré comme ça avant, haha

Voyons maintenant pourquoi la logique fonctionnelle de démarrage du service ne peut pas être placée dans SystemUIservice mais dans SystemUIApplication.
Si vous souhaitez le mettre dans SystemUIApplication, pourquoi ne pas le démarrer via SystemUIApplication, mais utiliser SystemUIService pour le démarrer.

  1. En plus du service de démarrage SystemUIService, dans le cas de plusieurs utilisateurs, il est également nécessaire de démarrer certains services, et à ce moment, l'application SystemUI

    Appelez d'abord SystemUIApplication au lieu de SystemUIService. Parce que le déclenchement de SystemUIService est démarré par system_server.

    De plus, la logique de démarrage du système de surveillance doit être traitée de manière unifiée. Il devient naturel de mettre la logique de démarrage dans SystemUIApplication.

Remarque : Cela conduit évidemment à un bug. Si SystemUI signale une erreur à mi-chemin et s'arrête de fonctionner, lors de son exécution à nouveau, les différents
services démarrés par SystemUIService peuvent-ils toujours s'initialiser correctement ? Évidemment non, cela arrive souvent au moment où j’écris cet article.

  1. Puisque la logique de démarrage a été placée dans SystemUIApplication, n'est-il pas possible pour SystemUIApplication de démarrer cette partie du service ?

    Pourquoi un SystemUIService distinct devrait-il être utilisé comme point d'entrée pour démarrer ? Pour répondre à cette question, il faut savoir que les applications Android se démarrent en démarrant un composant à exécuter. Autrement dit, si system_server souhaite exécuter SystemUI, il doit démarrer un certain composant, pas seulement une application.

    Par conséquent, nous avons besoin d'un composant pour démarrer, et ce composant est SystemUI. Il est responsable du démarrage de chaque service spécifique. En plus du suivi du boot broadcast et de la collaboration sous multi-utilisateur, cette partie du contenu est placée dans SystemUIApplication pour être complétée.

    Et comme SystemUIService nécessite une injection de dépendances, SystemUIAppComponentFactory a été créé pour implémenter l'injection de dépendances correspondante.

À ce stade, nous avons complètement compris le processus de démarrage de SystemUIService, SystemUIApplication, SystemUIAppComponentFactory
et pourquoi les fonctions sont allouées de cette manière. Le résumé est le suivant.

  1. Après le démarrage de system_server, il commence à démarrer divers services
  2. Lors du démarrage d'autres services, il obtiendra d'abord le nom du composant pour démarrer systemui via PackageManager, puis démarrera le composant systemui selon le nom
  3. Le nom obtenu à l’étape ci-dessus est SystemUIService.
  4. Lorsque SystemUIService est démarré, SystemUIApplication sera créé en premier et SystemUIAppComponentFactory sera appelé pour ajouter l'injection de dépendance correspondante avant la création.
  5. Une fois SystemUIApplication créé, il écoutera la diffusion de démarrage du système.
  6. Créez ensuite SystemUIService.Avant de le créer, la méthode correspondante de SystemUIAppComponentFactory sera appelée pour ajouter l'injection de dépendances.
  7. Après avoir créé SystemUIService, démarrez divers services via SystemUIApplication

À ce stade, l’intégralité du démarrage de SystemUI est terminée.

Ajouter un service personnalisé à SystemUI

Avec l'analyse précédente, nous devons maintenant la tester : écrire un module de service personnalisé. Dans ce module, nous imprimons uniquement son processus de démarrage.

  1. Créez une nouvelle classe appelée PrintLogService, qui peut hériter de SystemUI. comme suit
public class PrintLogService extends SystemUI{
    
    

    private String TAG = "PrintLogService";

    //使用@Inject标记,让Dagger2自动管理依赖
    @Inject
    public PrintLogService(Context context) {
    
    
        super(context);
    }

    //简单打印log
    @Override
    public void start() {
    
    
        Slog.d(TAG, "Start PrintLogService");
    }
    //简单打印log
    @Override
    protected void onBootCompleted() {
    
    
        Slog.d(TAG,"PrintLogService boot completed");
    }

}
  1. Mettez le nom de cette classe dans le tableau de configuration config_systemUIServiceComponents comme suit :
<!-- 最后一行加入我们自定义的服务 -->
    <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>
        <item>com.android.systemui.PrintLogService</item>
    </string-array>

  1. Utilisez la commande suivante pour compiler et envoyer au téléphone
mmm frameworks/base/packages/SystemUI
adb root
adb remount
adb shell rm -rf system_ext/priv-app/SystemUI
adb push out/**/system_ext/priv-app/SystemUI /system_ext/priv-app/

Utilisez ensuite kill pour tuer le processus SystemUI existant.

  1. À partir du journal, nous pouvons voir le résultat suivant

Insérer la description de l'image ici

Cela signifie que notre service personnalisé a démarré avec succès ! ! !

Cet article est terminé ! !

Dans l'article, nous mentionnons seulement brièvement mContextAvailableCallback.onContextAvailable(this); qui
concerne l'initialisation de divers composants dans Dagger2. Le prochain article partira de cette fonction pour explorer l'initialisation de divers composants dans SystemUI et comprendre SystemUI. Comment chaque composant Devrait être utilisé.

Acho que você gosta

Origin blog.csdn.net/xiaowanbiao123/article/details/132409010
Recomendado
Clasificación