分析下Notification的更新机制。java
涉及Service:android
StatusBarManagerService
NotificationManagerServiceapp
这个两个service都会在 frameworks/base/services/java/com/android/server/SystemServer.java文件里面进行启动的ide
class ServerThread extends Thread { public void run() { ...... StatusBarManagerService statusBar = null; NotificationManagerService notification = null; ...... statusBar = new StatusBarManagerService(context, wm); ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar); ...... notification = new NotificationManagerService(context, statusBar, lights); ServiceManager.addService(Context.NOTIFICATION_SERVICE, notification); ...... } }
下面开始跟踪Notification的Notify流程。函数
1.post
当在Activity里面建立一个Notification,并Notifyui
NotificationManager nm = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE); Notification n = new Notification(R.drawable.chat, "Hello,there!", System.currentTimeMillis()); n.flags = Notification.FLAG_AUTO_CANCEL; Intent i = new Intent(arg0.getContext(), NotificationShow.class); i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_NEW_TASK); //PendingIntent PendingIntent contentIntent = PendingIntent.getActivity( arg0.getContext(), R.string.app_name, i, PendingIntent.FLAG_UPDATE_CURRENT); n.setLatestEventInfo( arg0.getContext(), "Hello,there!", "Hello,there,I'm john.", contentIntent); nm.notify(R.string.app_name, n);
2.调用NotificationManager.notify,进入notify 方法server
public void notify(int id, Notification notification) { notify(null, id, notification); } public void notify(String tag, int id, Notification notification) { ...... INotificationManager service = getService(); ...... service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id, notification, idOut, UserHandle.myUserId()); ...... }
3.在调用notify(String tag, int id, Notification notification)时,会调用getService()对象
static public INotificationManager getService() 78 { 79 if (sService != null) { 80 return sService; 81 } 82 IBinder b = ServiceManager.getService("notification"); 83 sService = INotificationManager.Stub.asInterface(b); 84 return sService; 85 }
这里发现,会调用ServiceManager.getService("notification"), 这样就会获取到文章刚开始讲的NotificationManagerService 的一个binder对象。获取回到第二步调用service.enqueueNotificationWithTAG.继承
4.进入NotificationManagerService的enqueueNotificationWithTAG
public void enqueueNotificationWithTag(String pkg, String basePkg, String tag, int id, 1621 Notification notification, int[] idOut, int userId) 1622 { 1623 enqueueNotificationInternal(pkg, basePkg, Binder.getCallingUid(), Binder.getCallingPid(), 1624 tag, id, notification, idOut, userId); 1625 } 1634 public void enqueueNotificationInternal(final String pkg, String basePkg, final int callingUid, 1635 final int callingPid, final String tag, final int id, final Notification notification, 1636 int[] idOut, int incomingUserId) 1637 { ...... final StatusBarNotification n = new StatusBarNotification( 1755 pkg, id, tag, callingUid, callingPid, score, notification, user); 1792 mStatusBar.updateNotification(r.statusBarKey, n); 1793 ...... }
在这个方法里,会将前面传递进来的Notification封装成一个StatusBarNotification对象,而后调用mStatusBar.updateNotification去更新,这个mStatusBar是什么?
5. 文章最开始提到会在ServerThread里面添加NotificationManagerService,在建立的NotificationManagerService的时候,会调用它的构造函数
NotificationManagerService(Context context, StatusBarManagerService statusBar, 1291 LightsService lights) 1292 { ....... }
这里面就会传递进来,在ServerThread里刚刚建立的StatusBarManagerService. 因此在第4步的时候咱们可以调用mStatusBar.updateNotification()。
6. StatusBarManagerService 中mStatusBar .updateNotification()方法
public void updateNotification(IBinder key, StatusBarNotification notification) { 512 synchronized (mNotifications) { 516 mNotifications.put(key, notification); ...... 519 mBar.updateNotification(key, notification); ...... 524 }
这里会调用mBar.updateNotification(),mBar是什么?
7. StatusBarManagerService 中 mBar对象
volatile IStatusBar mBar; // Callbacks from the status bar service. 428 // ================================================================================ 429 public void registerStatusBar(IStatusBar bar, StatusBarIconList iconList, 430 List<IBinder> notificationKeys, List<StatusBarNotification> notifications, 431 int switches[], List<IBinder> binders) { ......
上面发现有个registerStatusBar方法,会传递进来一个IStatusBar 对象,那这个方法会在哪里调用呢?
8. 在StatusBarManagerService中,咱们发现调用mBar对象都是去处理StatusBar的UI,那这个StatusBar是哪里的?SystemUI里面的。检索下SystemUI的代码,果真发如今
BaseStatusBar里面:
public void start() { mBarService.registerStatusBar(mCommandQueue, iconList, notificationKeys, notifications, 250 switches, binders); }
在这里registerStatusBar, 而这个mCommandQueue参数就是前面IStatusBar对象。
9. mCommanQueue变量
protected CommandQueue mCommandQueue;
28/** 29 * This class takes the functions from IStatusBar that come in on 30 * binder pool threads and posts messages to get them onto the main 31 * thread, and calls onto Callbacks. It also takes care of 32 * coalescing these calls so they don't stack up. For the calls 33 * are coalesced, note that they are all idempotent. 34 */ 35public class CommandQueue extends IStatusBar.Stub{ /** 78 * These methods are called back on the main thread. 79 */ 80 public interface Callbacks { 81 public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon); 82 public void updateIcon(String slot, int index, int viewIndex, 83 StatusBarIcon old, StatusBarIcon icon); 84 public void removeIcon(String slot, int index, int viewIndex); 85 public void addNotification(IBinder key, StatusBarNotification notification); 86 public void updateNotification(IBinder key, StatusBarNotification notification); 87 public void removeNotification(IBinder key); 88 public void disable(int state); 89 public void animateExpandNotificationsPanel(); 90 public void animateCollapsePanels(int flags); 91 public void animateExpandSettingsPanel(); 92 public void setSystemUiVisibility(int vis, int mask); 93 public void topAppWindowChanged(boolean visible); 94 public void setImeWindowStatus(IBinder token, int vis, int backDisposition); 95 public void setHardKeyboardStatus(boolean available, boolean enabled); 96 public void toggleRecentApps(); 97 public void preloadRecentApps(); 98 public void showSearchPanel(); 99 public void hideSearchPanel(); 100 public void cancelPreloadRecentApps(); 101 public void setNavigationIconHints(int hints); 102 public void setWindowState(int window, int state); 103 } }
发现这个方法继承IStatusBar.stub,里面有一连串的回调函数。这些回调函数在BaseStatusBar里面实现的
public abstract class BaseStatusBar extends SystemUI implements 79 CommandQueue.Callbacks {
10. 回到第6步,当在StatusBarManagerService中调用mBar.updateNotification时,根据7,8,9的分析,最终会调用在BaseStatusBar里面实现的UpdateNotification方法
updateNotification(IBinder key, StatusBarNotification notification) { ...... }
在这里会将Notification显 示在StatusBar上面。
这里面主要涉及到两个NotificationManagerService和StatusBarManager的交互。
第一步。
系统启动时在ServerThread里生成StatusBarManagerService和NotificationManagerService,并将StatusBarManagerService对象做为一个参数传递到NotificationManagerService的构造方法中。
系统加载应用,SystemUI中, BaseStatusBar实现回调函数CommandQueue.Callbacks, 并调用StatusBarManagerService的registerStatusBar方法,将CommandQueue对象传递进去
第二步
Activity里调用notify方法,在NotificationManagerService将Notification封装成StatusBarNotification。
NotificationManagerService调用statusBarManagerService的updateNotification()。
第三步
StatusBarManagerService调用CommandQueue实现的回调函数,最终将Notification显示在SystemUI上面。