原创不易,转载请标明出处。若阅读过程中发现问题,请不吝指教,比心~
前言
这是一个基于 Android 10 源码,全面分析 Android通知系统实现原理 的系列,这是第二篇,全系列将覆盖:
- 1.Notification 的简单使用 和 常用接口介绍
- 2.系统通知服务的启动流程
- 3.通知发送的服务端实现
- 4.通知发送的客户端实现(ing)
- 2.Android 通知系统定制(ing)
写在前面
为了让读者更全面地了解 系统通知服务整体流程,这一篇我们会先简单介绍 手机是如何在启动的过程中拉起NMS服务的,涉及到 Zygote进程的启动 和 System进程启动;然后介绍 NMS服务的功能实现 以及 如何获取到NMS服务。
简单说明:下文出现的简写
NM -> NotificationManager
NMS -> NotificationManagerService
Sysui -> SystemUI
NMS系统通知服务的启动流程
相关类:
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服务的吧:
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方法:
/*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(),我们接下来看看这个入口函数做了什么事:
- 直接调用
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)`
- ......
1、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 为 notification 的 INotificationManager 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面向用户的代理类为NotificationManager,ActivityManagerService面向用户的代理类为ActivityManager,这些代理类均被注册在一个叫SystemServiceRegistry的管理类中(代码路径frameworks/base/core/java/android/app/SystemServiceRegistry.java),当我们调用Activity的getSystemService(String name)方法去获取系统服务时,最终会获取到SystemServiceRegistry中的对应代理类,从而我们就可以利用这些代理类来间接与各种系统服务交互了。