原創不易,轉載請標明出處。若閱讀過程當中發現問題,請不吝指教,比心~java
這是一個基於 Android 10 源碼,全面分析 Android通知系統實現原理 的系列,這是第二篇,全系列將覆蓋:android
爲了讓讀者更全面地瞭解 系統通知服務總體流程,這一篇咱們會先簡單介紹 手機是如何在啓動的過程當中拉起NMS服務的,涉及到 Zygote進程的啓動 和 System進程啓動;而後介紹 NMS服務的功能實現 以及 如何獲取到NMS服務。數組
簡單說明:下文出現的簡寫bash
NM -> NotificationManager
NMS -> NotificationManagerService
Sysui -> SystemUI
複製代碼
相關類: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
/*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;
}
複製代碼
有三個主要的步驟:函數
com.android.server.SystemServer 的 main函數
爲 System
進程的程序入口Zygote 去 fork System
進程,並返回一個進程id,咱們知道,當fork返回的id爲0時表示子進程fork成功,也就是步驟3要執行的handleSystemServerProcess
函數,該函數會進一步完成System
進程的啓動工做,往下走的主要工做就是去到native層了,這裏就再也不跟蹤了(不行了)上面分析了,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服務的大致功能與實現,先簡單說明下:
INotificationManager.aidl
定義了系統通知服務指望暴露給其餘客戶端的各類接口;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()
函數,這是系統通知服務的入口,該函數主要完成了:
NotificationManagerService
中一系列成員變量的賦值(經過init(...)
方法),如AMS、PMS
類的代理對象的獲取,各類輔助類實例的建立等等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 爲 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
中的對應代理類,從而咱們就能夠利用這些代理類來間接與各類系統服務交互了。