Original not easy, reproduced please indicate the source. If you find any problems in the reading process, please do not hesitate to give advice

preface

This is a based on Android 10 source code, a comprehensive analysis of the Android notification system implementation principle of the series, this is the second, the full series will cover:

  • 1. This section describes how to use the Notification and common interfaces
  • 2. Process for starting the system notification service
  • 3. Server implementation of notification sending
  • 4. Client implementation of notification sending (ING)
  • 2.Android Notification System customization (ING)

Writing in the front

In order to give readers a more comprehensive understanding of the overall process of System notification service, this article will first briefly introduce how the mobile phone starts the NMS service during the startup process, which involves the startup of the Zygote process and the System process. Then it introduces the function implementation of the NMS service and how to obtain the NMS service.

Brief description: the abbreviation that appears below

NM -> NotificationManager
NMS -> NotificationManagerService
Sysui -> SystemUI
Copy the code

NMS Process for starting the system notification service

Related categories:

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
frameworks/base/services/java/com/android/server/SystemServer.java
Copy the code

As we know (or pretend to know), the init process is the first process to start when the phone starts. This process will start a process called Zygote, which will create a virtual machine object as it starts. Other processes are then started directly from the Zygote fork, so that each process has its own virtual machine, but that’s another story. The System process is a fork of the Zygote process during startup. It is a System process that is responsible for starting various core System services, such as AMS, PMS, and NMS, during startup.

Here’s how Zygote starts the NMS service step by step:

The Zygote process fork out the System process during startup. Procedure

/*frameworks/base/core/java/com/android/internal/os/ZygoteInit.java*/
    public static void main(String argv[]) {
        ......
        try {
            ......
            boolean startSystemServer = false;
            for (int i = 1; i < argv.length; i++) {
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = true; }... }if(startSystemServer) { Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer); . }... }Copy the code

The argv array in zygoteinit. main will contain the start-system-server field, indicating that Zygote needs to start the system process, where startSystemServer=true, The forkSystemServer method is executed next:

/*frameworks/base/core/java/com/android/internal/os/ZygoteInit.java*/
    // Prepare the arguments and forks for the system server process.
    private static Runnable forkSystemServer(String abiList, String socketName,ZygoteServer zygoteServer) {
        ......
        String args[] = {
                "--setuid=1000"."--setgid=1000"."- setgroups = 1001100 2100 3100 4100 5100 6100 7100 8100 9101 0101 8102 1102 3,"
                        + "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010"."--capabilities=" + capabilities + "," + capabilities,
                "--nice-name=system_server"."--runtime-args"."--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
                "com.android.server.SystemServer", / / step 1: specify the System processes the entrance to the class for the com. Android. Server. The main method of SystemServer}; ZygoteArguments parsedArgs = null; int pid; try { ...... // Step 2: Pid = forkSystemServer(parsedargs. mUid, parsedargs. mGid, parsedargs. mGids, parsedArgs.mRuntimeFlags, null, parsedArgs.mPermittedCapabilities, parsedArgs.mEffectiveCapabilities); } catch (IllegalArgumentException ex) { throw new RuntimeException(ex); } // Step 3: Pid = 0 indicates that the child process fork is successfulif (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }
            zygoteServer.closeServerSocket();
            return handleSystemServerProcess(parsedArgs);
        }
        return null;
    }
Copy the code

There are three main steps:

  • 1. SpecifyCom. Android. Server. The main function of SystemServerforSystemThe program entry of a process
  • 2. ByThe Zygote to fork SystemProcess, and return a process ID. We know that when fork returns an ID of 0, the child process fork succeeds, which is what step 3 executes
  • 3. When PID =0, the command output in Step 3 is executedhandleSystemServerProcessFunction, which is further completedSystemThe main work to go down is to go to the native layer, where tracing is no longer possible.

System process startup: SystemServer’s main function

As shown above, the Zygote process creates the System process and specifies the program entry as systemServer.main (). Let’s see what this entry function does:

  • Direct callSystemServer().run()
/*frameworks/base/services/java/com/android/server/SystemServer.java*/
    // The main entry point from zygote.
    public static void main(String[] args) {
        new SystemServer().run();
    }
Copy the code
  • runMethod After various preparations are made, various system services are started. The NMS is started instartOtherServices()Execute in a function
/*frameworks/base/services/java/com/android/server/SystemServer.java*/
    private void run() {
        try {
            ......
        // Start services.
        try {
            traceBeginAndSlog("StartServices"); startBootstrapServices(); startCoreServices(); startOtherServices(); SystemServerInitThreadPool.shutdown(); }... }Copy the code

Through SystemServiceManager. StartService () start NMS service, SystemServiceManager is a dedicated to create, start, and manage the system service life cycle events management class

/*frameworks/base/services/java/com/android/server/SystemServer.java*/
    private void startOtherServices() {... mSystemServiceManager.startService(NotificationManagerService.class); . }Copy the code

The content of the startService function is simple and ends up executing directly to the onStart function of the NMS service.

/*frameworks/base/services/core/java/com/android/server/SystemServiceManager.java*/ public void startService(@NonNull final SystemService service) { mServices.add(service); try { service.onStart(); }... }Copy the code

The NMS service is a System service that lives in the System process and is pulled up during the startup process of the mobile phone System.


How to obtain the NMS service

In this section, we will look at the general functions and implementation of AN NMS service from the perspective of the framework.

  • 1.INotificationManager.aidlDefines the various interfaces that the system notification service expects to expose to other clients;
  • 2.NotificationManagerServiceTo achieve theINotificationManager.aidlThis interface and willBinderThe proxy object is registeredServiceManagerTo enable other services to be invoked with applications such asNotificationManager

Related classes are as follows:

1. frameworks/base/core/java/android/app/NotificationManager.java
2. frameworks/base/core/java/android/app/INotificationManager.aidl
3. frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java
Copy the code

The following analysis, we mentioned above, the system at the time of start NMS service, calls the NotificationManagerService. OnStart () function, this is a system notification service entrance, the function is mainly completed:

  • 1.NotificationManagerServiceAssignment to a series of member variables (byinit(...)Method), such asAMS, PMS,Class, the creation of various secondary class instances, and so on
  • 2. Register all kinds of broadcasts and listen to the required status, such as on and off screen broadcasts, user switch broadcasts, application add and delete broadcasts, etc
  • 3. Implement oneINotificationManager.aidlBinder proxy object for the interfacemServiceRegistered toServiceManager

Above mentioned many times INotificationManager. The aidl interface file, we look at the interface: the file is mainly, so several types of interfaces are defined:

/ * frameworks/base/core/Java/android/app/INotificationManager aidl * / - notification to add (including updates), delete, namely we previously ` notify, cancel `, such as the implementation of the interface, Such as ` enqueueNotificationWithTag (...). '- Setting and judging notification properties, such as whether to allow notification of an application to be displayed or whether to allow notification dots (the corner mark on the upper right corner of the desktop icon) to be displayed, such as'setShowBadge (String PKG, int uid, Boolean ShowBadge) notify ` ` - channel ` add and delete, such as ` createNotificationChannels (...). - Notification list such as' StatusBarNotification[] getActivenotifcommunications (String callingPkg) '- Notification status listening on the relevant interface, such as' registerListener(in INotificationListener listener, in ComponentName component, int userid)`
- ......
Copy the code

The content of 1, 2 point does not speak, children’s shoes directly interested in watching the onStart method of the NMS, here we point 3, let’s take a look at INotificationManager. The implementation of an aidl and registration process:

NMS realization INotificationManager aidl

/*frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java*/
    final IBinder mService = new INotificationManager.Stub() { @Override public void enqueueToast(String pkg, ITransientNotification callback, int duration, int displayId) {...... } @Override ...... }Copy the code

Register the Binder proxy object with the ServiceManager:

/*frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java*/
    @Override
    public void onStart() {// Initialize the member variables and register the various broadcast listeners...... // Register the ServiceManager publishBinderService(context.notification_Service, mService, /* allowIsolated= */false,
                DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
    }

    protected final void publishBinderService(String name, IBinder service,
            boolean allowIsolated, int dumpPriority) {
        ServiceManager.addService(name, service, allowIsolated, dumpPriority);
    }
Copy the code

Where the value of NOTIFICATION_SERVICE is “notification”, The INotificationManager Binder proxy object named Notification can then be acquired by the ServiceManager for other services or applications to interact with. For example, The entry class NotificationManager for developers to operate on notifications, look look:

/*frameworks/base/core/java/android/app/NotificationManager.java*/
    private static INotificationManager sService;
    static public INotificationManager getService()
    {
        if(sService ! = null) {return sService;
        }
        IBinder b = ServiceManager.getService("notification");
        sService = INotificationManager.Stub.asInterface(b);
        return sService;
    }

Copy the code

You can see that NotificationManager directly obtains the Binder object whose name is Notification in The ServiceManager by querying. The Binder object on the server is converted to an object of the AIDL interface type required by the client through the asInterface method, which is then stored in the member variable sService for subsequent invocation.

It should be noted that the service registered in ServiceManager does not support the common application to obtain, as we know, when we need to send notification, send the following entry:

        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(notiTag, notiId, notification);
Copy the code

Here getSystemService(String name) is an Activity method, not provided by ServiceManager, Android in order to avoid these system services directly with the user to deal with, unified provides a proxy class for users to obtain services.

Like a proxy class for the NotificationManager NotificationManagerService user-oriented, ActivityManagerService user-oriented proxy class for ActivityManager, The proxy class has been registered in a class called SystemServiceRegistry management (code path frameworks/base/core/Java/android/app/SystemServiceRegistry. Java), When we call the getSystemService(String name) method on the Activity to get the system service, we will eventually get the corresponding proxy class in the SystemServiceRegistry. We can then use these proxy classes to indirectly interact with various system services.