目录
- Notification介绍
- Notification框架原理
- Notification框架服务端启动过程
- SystemUI进程启动和绑定NotificationManagerService服务端过程
- Notification调用过程
- Notification通知提示音响起过程
- 总结
Notification介绍
功能作用
- 显示接收到短息、即时消息等信息 (如QQ、微信、新浪、短信)
- 显示客户端的推送消息(如有新版本发布,广告,推荐新闻等)
- 显示正在进行的事务(例如:后台运行的程序)(如音乐播放器、版本更新时候的下载进度等)
通知的基本组成

1. 标题
2. 大图标
3. 内容文字
4. 内容信息
5. 小图标
6. 通知的时间(Timestamp,默认为系统发出通知的时间,也可通过setWhen()来设置)
Notification框架原理
通知栏框架(Notificaiton),它适用于Android系统中交互事件的通知。它主要由三部分组成:系统服务端NotificationManagerService,通知显示端SystemUI,还有创建和更新通知的App端。
NotificationManagerService作为框架的服务端,在系统启动时就会启动并在后台运行,显示端SystemUI作为系统UI进程,也是Notification框架的客户端,在系统启动时也会启动并一直运行。
其它模块需调用Notification时,只需要调用NotificationManager.notify(int,Notification)就可以发出通知。

根据Notification框架的原理,我们就分别按以下几点来分析:
1. Notification框架服务端启动过程
2. SystemUI进程启动和绑定NotificationManagerService服务端过程
3. Notification调用过程
4. Notification通知提示音响起过程
Notification框架相关的包
android/frameworks/base/services/java/com/android/server/SystemServer.java //系统服务类启动的地方
android/frameworks/base/core/java/com/android/server/LocalServices.java //系统服务类通信的辅助类
android/frameworks/base/core/java/android/service/notification/ //Notification服务的接口类和监听类
android/frameworks/base/services/core/java/com/android/server/notification/ //NotificationManagerService服务相关的类
android/frameworks/base/core/java/android/app/ //NotificationManager、Notification类和INotificationManager.aidl的包
android/frameworks/base/packages/SystemUI/ //Notification显示的UI进程
Notification框架的关系类图

Notification框架服务端启动过程
SystemServer启动的Notification管理服务类是NotificationManagerService,保存到SystemServiceManager的是NotificationManagerService服务对象中的INotificationManager.Stub(),但是绑定到ServiceManager中Context.NOTIFICATION_ SERVICE的服务类是NotificationManager,所有开发者通过Context.getSystemService(Context.NOTIFICATION_SERVICE)获取回来的服务类不是NotificationManagerServiced服务对象,而是NotificationManager对象,需要再通过NotificationManager对象中的getService()方法,获取SystemServiceManager系统服务管理对象中保存的INotificationManager.Stub()对象。这样NotificationManager就能通过INotificationManager.Stub()对象和NotificationManagerService服务对象进行远程通信了
系统启动时,SystemServiceRegistry类中会把NotificationManager注册为系统服务提供给其它服务或者应用获取系统服务使用,
1 | /android/frameworks/base/core/java/android/app/SystemServiceRegistry.java |
在Activity或者Service中,可以直接通过Context.getSystemService(Context.NOTIFICATION_SERVICE)就可以获取系统服务使用。ActivityThread.performLaunchActivity()方法中创建ContextImpl对象并通过activity.attach()传递给Activity对象,再通过attachBaseContext()方法赋值给父类ContextWrapper中Context mBase对象,在Activity或者Service中调用getSystemService()方法,最终是调用ContextImpl中的getSystemService()方法。
1 | //android/frameworks/base/core/java/android/app/ContextImpl.java |
SystemServiceRegistry中注册的NotificationManager对象,其实不是真正的Notification服务,它只是一个调用接口对象,需要通过远程调用来实现和NotificationManagerService服务对象进行通信,真正实现相应的操作。以下是NotificationManagerService服务的启动流程。系统启动时会调用SystemServer来启动相应的系统服务对象。
1 | /android/frameworks/base/services/java/com/android/server/SystemServer.java |
SystemServer中调用NotificationManagerService的onStart()方法来启动NotificationManagerService服务。
1 | /android/frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java |
SystemUI进程启动和绑定NotificationManagerService服务端过程:
至此,Notification框架的服务端就已经启动完毕,NotificationManagerService类只是管理Notification的逻辑,显示端是在SystemUI进程中实现的,那么NotificationManagerService服务对象和SystemUI进程间是怎么通信的呢?两个不同进程间通信,很多同学可能就会想到Android的远程过程调用(Remote Procedure Call,RPC)方式来实现,这种猜测是合理的,而且这里也的确是这么实现的。与很多其他的基于RPC的解决方案一样,Android使用一种接口定义语言(Interface Definition Language,IDL)来公开服务的接口。所以我们先来看下NotificationManagerService服务和SystemUI进程通信的服务接口文件:
1 | /android/frameworks/base/core/java/android/app/INotificationManager.aidl |
这个接口类的服务端就是NotificationManagerService服务对象中的INotificationManager.Stub对象mService
private final IBinder mService = new INotificationManager.Stub(){};
客户端可以通过以下方式来获取和服务端通信的桩对象:
IBinder b = ServiceManager.getService(Context.NOTIFICATION_SERVICE);
INotificationManager service = INotificationManager.Stub.asInterface(b);
SystemUI进程在初始化过程中,会创建一个NotificationListenerService服务类,服务对象中创建一个INotificationListener对象并通过远程过程调用把这个INotificationListener对象注册到NotificationManagerService服务对象的服务管理类子类NotificationListeners对象mListeners中
1 | /android/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java |
Notification调用过程
Notification调用过程可以从应用开始,通过NotificationManager.notify()来发出通知,NotificationManager通过和NotificationManagerService服务对象通信,NotificationManagerService服务对象再利用通过NotificationListeners中监听的服务列表与SystemUI进程启动的系统服务NotificationListenerService中的INotificationListener对象通信,就可以调用SystemUI进程进行显示。
调用过程如下图所示:

对应的代码,如以下所示:
应用程序要发通知或取消通知,只需要获取系统的通知管理服务,调用notify或者cancel来操作通知即可。
1 | NotificationManager nm = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE); //获取通知管理服务 |
NotificationManager是管理通知的服务类,它负责与NotificationManagerService服务对象通信,并通过调用NotificationManagerService服务对象添加、更新、删除通知等等,所支持的功能可以参照远程通信服务接口INotificationManager.aidl中公开的方法。
1 | /android/frameworks/base/core/java/android/app/NotificationManager.java |
NotificationManagerService服务对象只是处理逻辑,显示的逻辑是放在系统UI的进程SystemUI中去的,所以NotificationManagerService服务对象处理完逻辑后,还需要远程调用SystemUI进程去更新显示。所以SystemUI进程需要把INotificationListener服务对象注册到NotificationManagerService服务对象中来,当需要更新UI是,就可以通过INotificationListener服务对象回调SystemUI进程中的方法来更新。
1 | /android/frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java |
INotificationListener服务对象是从BaseStatusBar对象中启动的系统服务BNotificationListenerService注册到NotificationManagerService对象中的,当NotificationManagerService服务对象通过INotificationListener服务对象回调SystemUI进程中的方法时,就可以调用BaseStatusBar对象中的方法来更新UI显示了。
1 | /android/frameworks/base/core/java/android/service/notification/NotificationListenerService.java |
PhoneStatusBar是BaseStatusBar的子类,实现了BaseStatusBar中的相关方法,addNotification()就是其中之一,这个方法是用来添加Notification和状态栏通知图标的。
1 | /android/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java |
StatusBarIconController是状态栏图标控制的类,用来控制状态栏通知图标显示和系统图标显示等等。
1 | /android/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java |
把状态栏通知图标和通知行布局都分别添加到相应的容器类后,显示部分的逻辑也就完成了。
Notification通知提示音响起过程
SystemUI的RingtonePlayer服务通过IAudioService.setRingtonePlayer(IRingtonePlayer)把IRingtonePlayer实现的回调接口对象注册到AudioService服务中,第三方App调用NotificationManager.notify()时,会调用NotificationManagerService中的enqueueNotificationInternal方法中的buzzBeepBlinkLocked()方法,这个方法会通过IAudioService.getRingtonePlayer()获取AudioServoce中的IRingtonePlayer对象,并调用回调方法来调用SystenUI.RingtonePlayer.mCallback的playAsync()来实现播放notification铃声、震动、闪烁灯功能。
调用过程如下图所示:

对应的代码,如以下所示:
启动AudioService服务过程,
1 | /android/frameworks/base/services/java/com/android/server/SystemServer.java |
启动SystemUI的RingtonePlayer服务过程,
1 | /android/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java |
RingtonePlayer是运行在SystemUI进程的服务,RingtonePlayer服务会获取AudioService服务对象,并把IRingtonePlayer对象传给AudioService服务对象中去,其它模块通过AudioService.getRingtonePlayer()来控制RingtonePlayer服务播放提示音的功能。
1 | private IRingtonePlayer mCallback = new IRingtonePlayer.Stub() { |
如果需要调用异步方式来播放提示音,就需要用到NotificationPlayer这个类,它会把播放任务保存到队列中,通过线程一个一个为队列中每个提示音播放任务创建一个播放线程并执行。
1 | /android/frameworks/base/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java |
应用或者服务通过NotificationManager调用notify()发出通过,NotificationManager通过和NotificationManagerService服务通信,调用发出通知,并调用buzzBeepBlinkLocked()方法来触发通知提示音、震动或者led闪烁。
1 | /android/frameworks/base/core/java/android/app/NotificationManager.java |
NotificationManagerService服务中就是通过AudioService服务获取IRingtonePlayer对象来控制SystemUI进程进行播放提示音的,
final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
player.playAsync(soundUri, record.sbn.getUser(), looping, audioAttributes);
SystemUI进程播放提示音的流程如下:
1 | /android/frameworks/base/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java |
总结
要理解Notification框架的原理,需要理清NotificationManager和NotificationManagerService之间是怎么通信的,NotificationManagerService和SystemUI之间是怎么通信的。INotificationManager.Stub不仅作为NotificationManagerService和NotificationManager的远程通信方式,也是NotificationManagerService和SystemUI的远程通信方式,不过SystemUI进程会创建和启动一个系统服务NotificationListenerService,这个系统服务通过INotificationManager.Stub把INotificationListener.Stub对象远程传给NotificationListenerService服务中,让NotificationListenerService服务通过INotificationListener.Stub对象和系统服务NotificationListenerService通信,系统服务NotificationListenerService再调用SystemUI进程来更新UI。
