SystemUI之USB2(Framework UEvent -> SystemUI)
来源:互联网 发布:mac最好用的输入法 编辑:程序博客网 时间:2024/05/21 01:56
第二节 Framework UEvent -> SystemUI
逻辑主要在Framework里面的NotificationManagerService.java
UsbDeviceManager.java 到framework的NotificationManagerService.java,这里面涉及到通知的分类和排序,通知的显示风格等等,然后通过NotificationListenerService来通知SystemUI.
在SystemUI注册服务,然后在framework层回调,贯通SystemUI以及Framework。
UsbDeviceManager.java中——》
mNotificationManager.notifyAsUser(null, id, notification, UserHandle.ALL);
调用NotificationManager的notifyAsUser()往上上传notification,跟到方法里面看下,
路径:framework/base/core/java/android/app/NotificationManager.java
INotificationManager service = getService();//获取IBinder对象
我们看下Notification的addFieldsFromContext方法做了哪些事情:
路径:frameworks/base/core/java/android/app/Notification.java
public static void addFieldsFromContext(Context context, Notification notification) { addFieldsFromContext(context.getApplicationInfo(), context.getUserId(), notification); } /** * @hide */ public static void addFieldsFromContext(ApplicationInfo ai, int userId, Notification notification) { notification.extras.putParcelable(EXTRA_BUILDER_APPLICATION_INFO, ai);//"android.appinfo" notification.extras.putInt(EXTRA_ORIGINATING_USERID, userId);//"android.originatingUserId" }
addFieldsFromContext方法主要实现将当前应用的ApplicationInfo对象保存到“android.appinfo”字段,将当前的userId保存到“android.originatingUserId”字段中。
fixLegacySmalIcon,notify函数会判断notification是否有small icon,如果没有设icon或small icon,用notify方法时会抛出异常。fixLegacySmallIcon方法如下:
private void fixLegacySmallIcon(Notification n, String pkg) { if (n.getSmallIcon() == null && n.icon != 0) { n.setSmallIcon(Icon.createWithResource(pkg, n.icon)); } }
完成上面的操作后,调用通知管理类NotificationManagerService的enqueueNotificationWithTag方法, @Override public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id, Notification notification, int[] idOut, int userId) throws RemoteException { enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(), Binder.getCallingPid(), tag, id, notification, idOut, userId); }
我们看到在enqueueNotificationWithTag方法中调用了enqueueNotificationInternal方法,这里就是通知处理的核心了。[java] view plain copy在CODE上查看代码片派生到我的代码片 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid, final int callingPid, final String tag, final int id, final Notification notification, int[] idOut, int incomingUserId) { if (DBG) { Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id + " notification=" + notification); } checkCallerIsSystemOrSameApp(pkg); // 校验UID final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg)); final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg); final int userId = ActivityManager.handleIncomingUser(callingPid, callingUid, incomingUserId, true, false, "enqueueNotification", pkg); final UserHandle user = new UserHandle(userId); // Fix the notification as best we can. try { final ApplicationInfo ai = getContext().getPackageManager().getApplicationInfoAsUser( pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING, (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId); Notification.addFieldsFromContext(ai, userId, notification); } catch (NameNotFoundException e) { Slog.e(TAG, "Cannot create a context for sending app", e); return; } mUsageStats.registerEnqueuedByApp(pkg); // Limit the number of notifications that any given package except the android // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks. // 这里会做一个限制,除了系统级别的应用之外,其他应用的notification数量会做限制,用来防止DOS攻击导致的泄露 if (!isSystemNotification && !isNotificationFromListener) { synchronized (mNotificationList) { final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg); if (appEnqueueRate > mMaxPackageEnqueueRate) { mUsageStats.registerOverRateQuota(pkg); final long now = SystemClock.elapsedRealtime(); if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) { Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate + ". Shedding events. package=" + pkg); mLastOverRateLogTime = now; } return; } int count = 0; final int N = mNotificationList.size(); for (int i=0; i<N; i++) { final NotificationRecord r = mNotificationList.get(i); if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) { if (r.sbn.getId() == id && TextUtils.equals(r.sbn.getTag(), tag)) { break; // Allow updating existing notification } count++; if (count >= MAX_PACKAGE_NOTIFICATIONS) {// 同一个应用发送notification数量不能超过50 mUsageStats.registerOverCountQuota(pkg); Slog.e(TAG, "Package has already posted " + count + " notifications. Not showing more. package=" + pkg); return; } } } } } if (pkg == null || notification == null) {//通知不能为空 throw new IllegalArgumentException("null not allowed: pkg=" + pkg + " id=" + id + " notification=" + notification); } // Whitelist pending intents. if (notification.allPendingIntents != null) { final int intentCount = notification.allPendingIntents.size(); if (intentCount > 0) { final ActivityManagerInternal am = LocalServices .getService(ActivityManagerInternal.class); final long duration = LocalServices.getService( DeviceIdleController.LocalService.class).getNotificationWhitelistDuration(); for (int i = 0; i < intentCount; i++) { PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i); if (pendingIntent != null) { am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(), duration); } } } } // Sanitize inputs notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN, Notification.PRIORITY_MAX); // setup local book-keeping // 验证完条件后,将前面传递进来的Notification封装成一个StatusBarNotification对象, final StatusBarNotification n = new StatusBarNotification( pkg, opPkg, id, tag, callingUid, callingPid, 0, notification, user); // 封装NotificationRecord对象 final NotificationRecord r = new NotificationRecord(getContext(), n); mHandler.post(new EnqueueNotificationRunnable(userId, r)); idOut[0] = id; } 开启线程,异步处理。
private class EnqueueNotificationRunnable implements Runnable { private final NotificationRecord r; private final int userId; EnqueueNotificationRunnable(int userId, NotificationRecord r) { this.userId = userId; this.r = r; }; @Override public void run() { synchronized (mNotificationList) { final StatusBarNotification n = r.sbn; if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey()); NotificationRecord old = mNotificationsByKey.get(n.getKey()); if (old != null) { // Retain ranking information from previous record r.copyRankingInformation(old); } final int callingUid = n.getUid(); final int callingPid = n.getInitialPid(); final Notification notification = n.getNotification(); final String pkg = n.getPackageName(); final int id = n.getId(); final String tag = n.getTag(); final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg)); // Handle grouped notifications and bail out early if we // can to avoid extracting signals. handleGroupedNotificationLocked(r, old, callingUid, callingPid); // This conditional is a dirty hack to limit the logging done on // behalf of the download manager without affecting other apps. if (!pkg.equals("com.android.providers.downloads") || Log.isLoggable("DownloadManager", Log.VERBOSE)) { int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW; if (old != null) { enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE; } EventLogTags.writeNotificationEnqueue(callingUid, callingPid, pkg, id, tag, userId, notification.toString(), enqueueStatus); } mRankingHelper.extractSignals(r); final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid); // blocked apps 判断pkg是否可以显示通知 if (r.getImportance() == NotificationListenerService.Ranking.IMPORTANCE_NONE || !noteNotificationOp(pkg, callingUid) || isPackageSuspended) { if (!isSystemNotification) {//不拦截系统通知 if (isPackageSuspended) { Slog.e(TAG, "Suppressing notification from package due to package " + "suspended by administrator."); mUsageStats.registerSuspendedByAdmin(r); } else { Slog.e(TAG, "Suppressing notification from package by user request."); mUsageStats.registerBlocked(r); } return; } } // tell the ranker service about the notification if (mRankerServices.isEnabled()) { mRankerServices.onNotificationEnqueued(r); // TODO delay the code below here for 100ms or until there is an answer } // 获取是否已经发送过此notification int index = indexOfNotificationLocked(n.getKey()); if (index < 0) { // 如果是新发送的notification,就走新增流程. mNotificationList.add(r); mUsageStats.registerPostedByApp(r); } else { //如果有发送过,就获取oldNtificationRecord,后面走更新流程 mStatusBar.updateNotification(r.statusBarKey, n) old = mNotificationList.get(index); mNotificationList.set(index, r); mUsageStats.registerUpdatedByApp(r, old); // Make sure we don't lose the foreground service state. notification.flags |= old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE; r.isUpdate = true; } Slog.d(TAG, "NotificationRecord, r = "+r); mNotificationsByKey.put(n.getKey(), r); // Ensure if this is a foreground service that the proper additional // flags are set. if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) { notification.flags |= Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR; } applyZenModeLocked(r); mRankingHelper.sort(mNotificationList);//将mNotificationList排序 // 如果notification设置了smallIcon,调用所有NotificationListeners的notifyPostedLocked方法, // 通知有新的notification,传入的参数为上面封装成的StatusBarNotification对象. if (notification.getSmallIcon() != null) { StatusBarNotification oldSbn = (old != null) ? old.sbn : null; mListeners.notifyPostedLocked(n, oldSbn); } else { Slog.e(TAG, "Not posting notification without small icon: " + notification); if (old != null && !old.isCanceled) { mListeners.notifyRemovedLocked(n); } // ATTENTION: in a future release we will bail out here // so that we do not play sounds, show lights, etc. for invalid // notifications Slog.e(TAG, "WARNING: In a future release this will crash the app: " + n.getPackageName()); } // buzzBeepBlinkLocked方法负责对消息进行处理。 // 通知status bar显示该notification,确认是否需要声音,震动和闪光,如果需要,那么就发出声音,震动和闪光 buzzBeepBlinkLocked(r); } } }
到这里,就开始进入SystemUI了。
// 如果notification设置了smallIcon,调用所有NotificationListeners的notifyPostedLocked方法, // 通知有新的notification,传入的参数为上面封装成的StatusBarNotification对象. if (notification.getSmallIcon() != null) { StatusBarNotification oldSbn = (old != null) ? old.sbn : null; mListeners.notifyPostedLocked(n, oldSbn); } else { Slog.e(TAG, "Not posting notification without small icon: " + notification); if (old != null && !old.isCanceled) { mListeners.notifyRemovedLocked(n); } // ATTENTION: in a future release we will bail out here // so that we do not play sounds, show lights, etc. for invalid // notifications Slog.e(TAG, "WARNING: In a future release this will crash the app: " + n.getPackageName()); }
其中,mListeners为NotificationListeners,为内部类。查看方法notifyPostedLocked()
/** * asynchronously notify all listeners about a new notification * * <p> * Also takes care of removing a notification that has been visible to a listener before, * but isn't anymore. */ public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) { // Lazily initialized snapshots of the notification. TrimCache trimCache = new TrimCache(sbn);通知所有的监听者关于这个新通知, for (final ManagedServiceInfo info : mServices) { boolean sbnVisible = isVisibleToListener(sbn, info); boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false; // This notification hasn't been and still isn't visible -> ignore. if (!oldSbnVisible && !sbnVisible) { continue; } final NotificationRankingUpdate update = makeRankingUpdateLocked(info); // This notification became invisible -> remove the old one. if (oldSbnVisible && !sbnVisible) { final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight(); mHandler.post(new Runnable() { @Override public void run() { notifyRemoved(info, oldSbnLightClone, update); } }); continue; } final StatusBarNotification sbnToPost = trimCache.ForListener(info); mHandler.post(new Runnable() { @Override public void run() { notifyPosted(info, sbnToPost, update); } }); } }
然后在notifyPosted()方法里面推送通知,我们来看下这个方法:
private void notifyPosted(final ManagedServiceInfo info, final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) { final INotificationListener listener = (INotificationListener)info.service; StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); try { listener.onNotificationPosted(sbnHolder, rankingUpdate); } catch (RemoteException ex) { Log.e(TAG, "unable to notify listener (posted): " + listener, ex); } }
然后监听者调用onNotificationPosted()继续往上推送
路径:frameworks/base/core/java/android/service/notification/INotificationListener.aidl
INotificationManager.aidl BaseStatusBar.java
目录:frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
在BaseStatusBar.java 里面注册NotificationListenerService。
try { mNotificationListener.registerAsSystemService(mContext, new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()), UserHandle.USER_ALL); } catch (RemoteException e) { Log.e(TAG, "Unable to register notification listener", e); }!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!在registerAsSystemService中调用registerListener方法。这个方法在INotificationManager.stub中声明了,而INotificationManager.stub 跟NotificationManagerService进行了绑定。so 跟进了NotificationManagerService.java
frameworks/base/core/java/android/app/INotificationManager.aidl
framework/base/services/core/java/com/android/server/notification/NotificationManagerService.java
在NotificationManagerService.java里面
private final IBinder mService = new INotificationManager.Stub()
----> NotificationManagerService.java在实例化INotificationManager.stub 对象的时候,对registerListener 进行了override。在这个方法中,它首先去调用enforceSystemOrSystemUI,接着才去registerService。很显然,想要的答案就在enforceSystemOrSystemUI 中。so 跟进enforceSystemOrSystemUI。这个方法呢,也是在实例化INotificationManager.stub 对象mService的时候,对其 进行了override。
这样NotificationManagerService和NotificationListenerService连接上,可以吧消息传到systemUI进去。
0 0
- SystemUI之USB2(Framework UEvent -> SystemUI)
- SystemUI之USB1(kernel->Framework UEvent)
- SystemUI
- SystemUI
- android SystemUI浅析之SystemUI启动流程
- systemUI之statusBar
- systemUI之statusbar
- SystemUI之呈现流程
- SystemUI 之 BrightnessDialog、BrightnessController
- Android 7.0之systemUI
- SystemUI之控制中心实现
- SystemUI之notification排序
- SystemUI之任务管理器
- ROM界面美化基础(framework-res、SystemUI)
- SystemUI之:Notification前世今生
- Android SystemUI 之 通知栏
- SystemUI之启动过程整理
- Android核心程序之SystemUI
- 【AJAX】AJAX小结(二)
- 山东驴友和梁定郊小兄弟一起川藏游
- 数据结构实例<三>(匹配链表所有元素删除后并返回新的链表)入门
- Senparc.Weixin.MP 微信公众平台开发教程(2)自定义菜单
- java 可变参数的问题 String... params
- SystemUI之USB2(Framework UEvent -> SystemUI)
- Ext获取各个值
- 千里行创始人梁闪贿的人生
- centos增加环境变量
- asp.net core mvc剖析:KestrelServer
- CentOS 安装MySQL(rpm)提示错误Header V3 DSA/SHA1 Signature
- 关于Java中时区切换
- Html学习笔记
- CodeBlocks下如何给main函数传递参数