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
原创粉丝点击