Android系统通知服务的启动流程 和 功能实现(基于Android 10)

原创不易,转载请标明出处。若阅读过程当中发现问题,请不吝指教,比心~java

前言

这是一个基于 Android 10 源码,全面分析 Android通知系统实现原理 的系列,这是第二篇,全系列将覆盖:android

写在前面

为了让读者更全面地了解 系统通知服务总体流程,这一篇咱们会先简单介绍 手机是如何在启动的过程当中拉起NMS服务的,涉及到 Zygote进程的启动 和 System进程启动;而后介绍 NMS服务的功能实现 以及 如何获取到NMS服务数组

简单说明:下文出现的简写bash

NM -> NotificationManager
NMS -> NotificationManagerService
Sysui -> SystemUI
复制代码

NMS系统通知服务的启动流程

相关类:app

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
frameworks/base/services/java/com/android/server/SystemServer.java
复制代码

咱们知道(不知道就伪装知道吧),手机启动的过程当中,init进程 是第一个启动的进程,该进程在启动的过程当中会去启动一个叫 Zygote的进程,Zygote进程在启动的过程当中会去建立一个虚拟机对象,后续其余进程的启动则是直接从Zygote进程fork,从而达到每一个进程都拥有一个独立虚拟机的目的,这是题外话了。其中 System进程 就是 Zygote进程在启动的过程当中fork出来的一个进程,这是一个系统进程,负责在开机的时候启动各类核心系统服务,例如AMS、PMS、NMS等常见的服务。框架

下面来看看Zygote是如何一步步启动 NMS服务的吧:socket

Zygote进程在启动过程当中fork出了System进程

/*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);
                ......
            }
            ......
    }
复制代码

ZygoteInit.main函数中的argv数组会带有start-system-server字段,代表Zygote进程须要启动System进程,上面startSystemServer=true,也就是接下来执行的是forkSystemServer方法:ide

/*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=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
                        + "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", // 步骤1:指定 System进程 的入口类为 com.android.server.SystemServer 的 main 方法
        };
        ZygoteArguments parsedArgs = null;
        int pid;
        try {
            ......
            // 步骤2:经过 Zygote 去 fork System 进程
            pid = Zygote.forkSystemServer(
                    parsedArgs.mUid, parsedArgs.mGid,
                    parsedArgs.mGids,
                    parsedArgs.mRuntimeFlags,
                    null,
                    parsedArgs.mPermittedCapabilities,
                    parsedArgs.mEffectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

        // 步骤3:pid = 0 表示子进程fork成功
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }
            zygoteServer.closeServerSocket();
            return handleSystemServerProcess(parsedArgs);
        }
        return null;
    }
复制代码

有三个主要的步骤:函数

  • 1.指定com.android.server.SystemServer 的 main函数System进程的程序入口
  • 2.经过 Zygote 去 fork System 进程,并返回一个进程id,咱们知道,当fork返回的id为0时表示子进程fork成功,也就是步骤3要执行的
  • 3.当pid=0时,会执行步骤3中的handleSystemServerProcess函数,该函数会进一步完成System进程的启动工做,往下走的主要工做就是去到native层了,这里就再也不跟踪了(不行了)

System进程的启动:SystemServer的main函数

上面分析了,Zygote进程启建立了System进程并指定了程序入口为SystemServer.main(),咱们接下来看看这个入口函数作了什么事:post

  • 直接调用SystemServer().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();
    }
复制代码
  • run方法在作好各类准备工做以后,就开始开启各类系统服务,NMS的启动在startOtherServices()函数中执行
/*frameworks/base/services/java/com/android/server/SystemServer.java*/
    private void run() {
        try {
            ......
        // Start services.
        try {
            traceBeginAndSlog("StartServices");
            startBootstrapServices();
            startCoreServices();
            startOtherServices();
            SystemServerInitThreadPool.shutdown();
        }
        ......
    }
复制代码

经过SystemServiceManager.startService()启动NMS服务,SystemServiceManager是一个专门用于建立、启动以及管理各系统服务生命周期事件的管理类

/*frameworks/base/services/java/com/android/server/SystemServer.java*/
    private void startOtherServices() {
        ......
        mSystemServiceManager.startService(NotificationManagerService.class);
        ......
    }
复制代码

startService函数的内容很简单,最终直接执行到NMS服务的onStart函数。

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

到这里,NMS服务的启动流程和启动时机就分析完了,稍微总结下:NMS服务是一个常驻在System进程中的系统服务,在手机系统启动的过程当中被拉起。


NMS服务的功能实现 以及 如何获取到NMS服务

这一节咱们会从框架上来看看NMS服务的大致功能与实现,先简单说明下:

  • 1.INotificationManager.aidl定义了系统通知服务指望暴露给其余客户端的各类接口;
  • 2.NotificationManagerService实现了INotificationManager.aidl这个接口,并将Binder代理对象注册到了ServiceManager中去,以便其余服务与应用调用,如NotificationManager

相关类以下:

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
复制代码

下面开始分析,咱们上面讲过,系统在启动NMS服务的时候,调用了 NotificationManagerService.onStart() 函数,这是系统通知服务的入口,该函数主要完成了:

  • 1.NotificationManagerService 中一系列成员变量的赋值(经过init(...)方法),如AMS、PMS类的代理对象的获取,各类辅助类实例的建立等等
  • 2.注册各类广播,监听所需状态,如亮灭屏广播、用户切换广播、应用添加删除广播等等
  • 3.将一个实现了INotificationManager.aidl接口的Binder代理对象mService注册到ServiceManager

上面屡次提到INotificationManager.aidl这个接口文件,咱们看下这个接口:该文件主要定义了这么几种类型的接口:

/*frameworks/base/core/java/android/app/INotificationManager.aidl*/
- 通知的添加(包括更新)、删除操做,即咱们前面讲到的 `notify、cancel` 等接口的实现,如`enqueueNotificationWithTag(...)`
- 通知属性的设置和判断,如是否容许显示某应用的通知、是否容许显示通知圆点(桌面图标右上角上的角标)等,如`setShowBadge(String pkg, int uid, boolean showBadge)`
- 通知`channel`的增删改查,如`createNotificationChannels(...)`
- 通知列表的获取如`StatusBarNotification[] getActiveNotifications(String callingPkg)`
- 通知状态监听相关接口,如`registerListener(in INotificationListener listener, in ComponentName component, int userid)`
- ......
复制代码

一、2点的内容不展开讲,感兴趣的童鞋直接看下NMS的onStart方法便可,这里咱们直接看第3点,咱们来看看INotificationManager.aidl的实现和注册过程:

NMS 实现 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
        ......
    }
复制代码

Binder代理对象注册到ServiceManager

/*frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java*/
    @Override
    public void onStart() {
        // 各成员变量的初始化 与 注册各类广播监听器
        ......
        // 注册到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);
    }
复制代码

其中 NOTIFICATION_SERVICE 的值为"notification", 这样其余服务或应用就能够经过ServiceManager来获取到 name 为 notificationINotificationManager Binder代理对象了, 从而达到与其交互的目的了,例如咱们上面讲到的,开发者操做通知的入口类NotificationManager,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;
    }

复制代码

能够看到NotificationManager直接经过查询得到ServiceManager中 name 为 notification 的 Binder对象,并经过asInterface方法将这个服务端的Binder对象转换成客户端所需的 AIDL 接口类型的对象,而后保存到成员变量sService中,以供后续调用。

须要注意的是,ServiceManager中注册的服务是不支持普通应用获取的,咱们知道,当咱们须要发送通知的时候,发送的入口以下:

NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(notiTag, notiId, notification);
复制代码

这里getSystemService(String name)Activity的方法,并非ServiceManager提供的,Android为了不这些系统服务直接与用户打交道,统一提供了代理类供用户获取服务。

NotificationManagerService面向用户的代理类为NotificationManagerActivityManagerService面向用户的代理类为ActivityManager,这些代理类均被注册在一个叫SystemServiceRegistry的管理类中(代码路径frameworks/base/core/java/android/app/SystemServiceRegistry.java),当咱们调用ActivitygetSystemService(String name)方法去获取系统服务时,最终会获取到SystemServiceRegistry中的对应代理类,从而咱们就能够利用这些代理类来间接与各类系统服务交互了。

相关文章
相关标签/搜索