Android Q notification创建发送流程-framework篇

基于Android10源码分析notification创建到添加到systemui的流程
本篇主要分析framework部分

以下是发送一个简单notification的示例代码:

    public static final int NOTIFY_ID = 110;
    NotificationManager notificationManager;
    private void sendNotification() {
        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        intent.setClass(this, MainActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
        PendingIntent pendingIntent = PendingIntent.getActivity(this
                , (int) SystemClock.uptimeMillis()
                , intent
                , PendingIntent.FLAG_UPDATE_CURRENT);
        notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        //创建notificationChannel
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            NotificationChannel mChannel = new NotificationChannel(getString(R.string.app_name), getString(R.string.app_name), NotificationManager.IMPORTANCE_LOW);
            mChannel.setDescription("notication channel");
            mChannel.setShowBadge(false);
            notificationManager.createNotificationChannel(mChannel);
        }
        Notification.Builder builder = new Notification.Builder(this, getString(R.string.app_name));
        //设置通知栏大图标,上图中右边的大图
        builder.setLargeIcon(BitmapFactory.decodeResource(
                getResources(), R.mipmap.ic_launcher))
                // 设置状态栏和通知栏小图标
                .setSmallIcon(R.drawable.ic_launcher_background)
                // 设置通知栏应用名称
                .setTicker("ticker")
                // 设置通知栏显示时间
                .setWhen(System.currentTimeMillis())
                // 设置通知栏标题
                .setContentTitle("title")
                // 设置通知栏内容
                .setContentText("contentText")
                // 设置通知栏点击后是否清除,设置为true,当点击此通知栏后,它会自动消失
                .setAutoCancel(false)
                // 设置通知栏点击意图
                .setContentIntent(pendingIntent)
                // 铃声、闪光、震动均系统默认
                .setDefaults(Notification.DEFAULT_ALL)
                // 设置为public后,通知栏将在锁屏界面显示
                .setVisibility(Notification.VISIBILITY_PRIVATE)
                // 从Android4.1开始,可以通过以下方法,设置通知栏的优先级,优先级越高的通知排的越靠前,
                // 优先级低的,不会在手机最顶部的状态栏显示图标
                // 设置优先级为PRIORITY_MAX,将会在手机顶部显示通知栏
                .setPriority(Notification.PRIORITY_MIN);

        notificationManager.notify(NOTIFY_ID, builder.build());
    }

上面代码执行后会在下拉通知栏出现如下图通知:
在这里插入图片描述

在Android O之后发送通知必须手动添加notificationChannel,我们就从notificationManager.notify来看通知是如何发送的

notify

frameworks/base/core/java/android/app/NotificationManager.java

/**
409       * Post a notification to be shown in the status bar. If a notification with
410       * the same id has already been posted by your application and has not yet been canceled, it
411       * will be replaced by the updated information.
412       *
413       * @param id An identifier for this notification unique within your
414       *        application.
415       * @param notification A {@link Notification} object describing what to show the user. Must not
416       *        be null.
417       */
418      public void notify(int id, Notification notification)
419      {
420          notify(null, id, notification);
421      }
          public void notify(String tag, int id, Notification notification)
443      {
444          notifyAsUser(tag, id, notification, mContext.getUser());
445      }
487      public void notifyAsUser(String tag, int id, Notification notification, UserHandle user)
488      {   //
489          INotificationManager service = getService();
490          String pkg = mContext.getPackageName();
492          try {
493              if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
494              service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
495                      fixNotification(notification), user.getIdentifier());
496          } catch (RemoteException e) {
497              throw e.rethrowFromSystemServer();
498          }
499      }
386      static public INotificationManager getService()
387      {
388          if (sService != null) {
389              return sService;
390          }
391          IBinder b = ServiceManager.getService("notification");
392          sService = INotificationManager.Stub.asInterface(b);
393          return sService;
394      }

通过Binder调到了NotificationManagerService里

enqueueNotificationWithTag

/frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java

2254      final IBinder mService = new INotificationManager.Stub() {
              ......
2389          @Override
2390          public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
2391                  Notification notification, int userId) throws RemoteException {
2392              enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
2393                      Binder.getCallingPid(), tag, id, notification, userId);
2394          }
             ......
}

enqueueNotificationInternal

4676      void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
4677              final int callingPid, final String tag, final int id, final Notification notification,
4678              int incomingUserId) {
4680             ......
4699             final NotificationChannel channel = mPreferencesHelper.getNotificationChannel(pkg,
4716                  notificationUid, channelId, false /* includeDeleted */);
              //检查是否创建notificationChannel
4717          if (channel == null) {
4718              final String noChannelStr = "No Channel found for "
4719                      + "pkg=" + pkg
4720                      + ", channelId=" + channelId
4721                      + ", id=" + id
4722                      + ", tag=" + tag
4723                      + ", opPkg=" + opPkg
4724                      + ", callingUid=" + callingUid
4725                      + ", userId=" + userId
4726                      + ", incomingUserId=" + incomingUserId
4727                      + ", notificationUid=" + notificationUid
4728                      + ", notification=" + notification;
4729              Slog.e(TAG, noChannelStr);
4733                ......
4735                 return;}
             //将创建的notification相关数据进一步封装为StatusBarNotification
4741         final StatusBarNotification n = new StatusBarNotification(
4742                  pkg, opPkg, id, tag, notificationUid, callingPid, notification,
4743                  user, null, System.currentTimeMillis());
              //将StatusBarNotification进一步再封装为NotificationRecord
4744          final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
              //对通知flag的一些判断,是否是前台,根据一些条件设置优先级等
4747          if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
4748              final boolean fgServiceShown = channel.isFgServiceShown();
4749              if (((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
4750                          || !fgServiceShown)
4751                      && (r.getImportance() == IMPORTANCE_MIN
4752                              || r.getImportance() == IMPORTANCE_NONE)) {
4753                  // Increase the importance of foreground service notifications unless the user had
4754                  // an opinion otherwise (and the channel hasn't yet shown a fg service).
4755                  if (TextUtils.isEmpty(channelId)
4756                          || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
4757                      r.setSystemImportance(IMPORTANCE_LOW);
4758                  } else {
4759                      channel.setImportance(IMPORTANCE_LOW);
4760                      r.setSystemImportance(IMPORTANCE_LOW);
4761                      if (!fgServiceShown) {
4762                          channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
4763                          channel.setFgServiceShown(true);
4764                      }
4765                      mPreferencesHelper.updateNotificationChannel(
4766                              pkg, notificationUid, channel, false);
4767                      r.updateNotificationChannel(channel);
4768                  }
4769              } else if (!fgServiceShown && !TextUtils.isEmpty(channelId)
4770                      && !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
4771                  channel.setFgServiceShown(true);
4772                  r.updateNotificationChannel(channel);
4773              }
4774          }
4775          ......
4802          mHandler.post(new EnqueueNotificationRunnable(userId, r));
}

以上代码主要就是创建了StatusBarNotificationNotificationRecord

StatusBarNotification

很典型的一个数据封装类,继承Parcelable,进行跨进程传输,主要关注一下Key()方法,此方法用来唯一标识某个应用的某条notification,避免重复显示
/frameworks/base/core/java/android/service/notification/StatusBarNotification.java

42  public class StatusBarNotification implements Parcelable {
43      static final int MAX_LOG_TAG_LENGTH = 36;
44  
45      @UnsupportedAppUsage
46      private final String pkg;
47      @UnsupportedAppUsage
48      private final int id;
49      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
50      private final String tag;
51      private final String key;
52      private String groupKey;
53      private String overrideGroupKey;
54  
55      @UnsupportedAppUsage
56      private final int uid;
57      private final String opPkg;
58      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
59      private final int initialPid;
60      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
61      private final Notification notification;
62      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
63      private final UserHandle user;
64      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
65      private final long postTime;
66  
67      private Context mContext; // used for inflation & icon expansion
68  
69      /** @hide */
70      public StatusBarNotification(String pkg, String opPkg, int id,
71              String tag, int uid, int initialPid, Notification notification, UserHandle user,
72              String overrideGroupKey, long postTime) {
73          if (pkg == null) throw new NullPointerException();
74          if (notification == null) throw new NullPointerException();
75  
76          this.pkg = pkg;
77          this.opPkg = opPkg;
78          this.id = id;
79          this.tag = tag;
80          this.uid = uid;
81          this.initialPid = initialPid;
82          this.notification = notification;
83          this.user = user;
84          this.postTime = postTime;
85          this.overrideGroupKey = overrideGroupKey;
86          this.key = key();
87          this.groupKey = groupKey();
88      }
267       * Returns a userid for whom this notification is intended.
268       *
269       * @deprecated Use {@link #getUser()} instead.
270       */
271      @Deprecated
272      public int getUserId() {
273          return this.user.getIdentifier();
274      }
275     ......
136      private String key() {
137          String sbnKey = user.getIdentifier() + "|" + pkg + "|" + id + "|" + tag + "|" + uid;
138          if (overrideGroupKey != null && getNotification().isGroupSummary()) {
139              sbnKey = sbnKey + "|" + overrideGroupKey;
140          }
141          return sbnKey;
142      }
        ......
}

NotificationRecord

数据封装类,将StatusBarNotification的数据进一步封装到NotificationRecord
/frameworks/base/services/core/java/com/android/server/notification/NotificationRecord.java

91  public final class NotificationRecord {
92      static final String TAG = "NotificationRecord";
93      static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
94      // the period after which a notification is updated where it can make sound
95      private static final int MAX_SOUND_DELAY_MS = 2000;
96      final StatusBarNotification sbn;
97      IActivityManager mAm;
98      UriGrantsManagerInternal mUgmInternal;
99      final int mTargetSdkVersion;
100      final int mOriginalFlags;
101      private final Context mContext;
102  
103      NotificationUsageStats.SingleNotificationStats stats;
104      boolean isCanceled;
105      IBinder permissionOwner;
106  
107      // These members are used by NotificationSignalExtractors
108      // to communicate with the ranking module.
109      private float mContactAffinity;
110      private boolean mRecentlyIntrusive;
111      private long mLastIntrusive;
112  
113      // is this notification currently being intercepted by Zen Mode?
114      private boolean mIntercept;
115  
116      // is this notification hidden since the app pkg is suspended?
117      private boolean mHidden;
118  
119      // The timestamp used for ranking.
120      private long mRankingTimeMs;
121  
122      // The first post time, stable across updates.
123      private long mCreationTimeMs;
124  
125      // The most recent visibility event.
126      private long mVisibleSinceMs;
127  
128      // The most recent update time, or the creation time if no updates.
129      @VisibleForTesting
130      final long mUpdateTimeMs;
131  
132      // The most recent interruption time, or the creation time if no updates. Differs from the
133      // above value because updates are filtered based on whether they actually interrupted the
134      // user
135      private long mInterruptionTimeMs;
136  
137      // The most recent time the notification made noise or buzzed the device, or -1 if it did not.
138      private long mLastAudiblyAlertedMs;
139  
140      // Is this record an update of an old record?
141      public boolean isUpdate;
142      private int mPackagePriority;
         195      public NotificationRecord(Context context, StatusBarNotification sbn,
196              NotificationChannel channel) {
197          this.sbn = sbn;
198          mTargetSdkVersion = LocalServices.getService(PackageManagerInternal.class)
199                  .getPackageTargetSdkVersion(sbn.getPackageName());
200          mAm = ActivityManager.getService();
201          mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
202          mOriginalFlags = sbn.getNotification().flags;
203          mRankingTimeMs = calculateRankingTimeMs(0L);
204          mCreationTimeMs = sbn.getPostTime();
205          mUpdateTimeMs = mCreationTimeMs;
206          mInterruptionTimeMs = mCreationTimeMs;
207          mContext = context;
208          stats = new NotificationUsageStats.SingleNotificationStats();
209          mChannel = channel;
210          mPreChannelsNotification = isPreChannelsNotification();
211          mSound = calculateSound();
212          mVibration = calculateVibration();
213          mAttributes = calculateAttributes();
214          mImportance = calculateInitialImportance();
215          mLight = calculateLights();
216          mAdjustments = new ArrayList<>();
217          mStats = new NotificationStats();
218          calculateUserSentiment();
219          calculateGrantableUris();
220      }
         .......
}

通过dump命令可以看到NotificationRecord的数据
adb shell dumpsys notification |grep -i --color “NotificationRecord”
以我们这个例子就可以看到如下信息:

NotificationRecord(0x002ba9de: pkg=com.example.app3 
user=UserHandle{0} id=110 tag=null importance=2 
key=0|com.example.app3|110|null|10161appImportanceLocked=false: 
Notification(channel= pri=-2 contentView=null vibrate=null sound=null 
defaults=0x0 flags=0x0 color=0x00000000 vis=PRIVATE))

回到之前的代码,接着通过mHandler执行EnqueueNotificationRunnable,将NotificationRecord传递参数

EnqueueNotificationRunnable

/frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java

5292      protected class EnqueueNotificationRunnable implements Runnable {
5293          private final NotificationRecord r;
5294          private final int userId;
5295  
5296          EnqueueNotificationRunnable(int userId, NotificationRecord r) {
5297              this.userId = userId;
5298              this.r = r;
5299          };
5300  
5301          @Override
5302          public void run() {
5303              synchronized (mNotificationLock) {
                      //将NotificationRecord添加到mEnqueuedNotifications
5304                  mEnqueuedNotifications.add(r);
5305                  ......
5307                  final StatusBarNotification n = r.sbn;
                      /*mNotificationsByKey是一个map结构,
                      通过StatusBarNotification的key()方法来唯一表示notification,
                      应用首次发送通知时应该获取到是空*/
5314                  NotificationRecord old = mNotificationsByKey.get(n.getKey());
5315                  final int callingUid = n.getUid();
5316                  final int callingPid = n.getInitialPid();
5317                  final Notification notification = n.getNotification();
5318                  final String pkg = n.getPackageName();
5319                  final int id = n.getId();
5320                  final String tag = n.getTag();
5342                  //写入events log notification_enqueue
                      EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
5343                              pkg, id, tag, userId, notification.toString(),
5344                              enqueueStatus);
5345                  }
5347                  ......
                      /*传入PostNotificationRunnable的NotificationRecord的getKey()
                      方法调用的就是StatusBarNotification的key()方法*/
5348                  if (mAssistants.isEnabled()) {
5349                      mAssistants.onNotificationEnqueuedLocked(r);
5350                      mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
5351                              DELAY_FOR_ASSISTANT_TIME);
5352                  } else {
5353                      mHandler.post(new PostNotificationRunnable(r.getKey()));
5354                  }
5355              }
5356          }
5357      }

接着mHandler又post了一个runnable

PostNotificationRunnable

5367      protected class PostNotificationRunnable implements Runnable {
5368          private final String key;
5370          PostNotificationRunnable(String key) {
5371              this.key = key;
5372          }
5373  
5374          @Override
5375          public void run() {
5376              synchronized (mNotificationLock) {
5377                  try {
5378                      NotificationRecord r = null;
5379                      int N = mEnqueuedNotifications.size();
                           /*
                           遍历mEnqueuedNotifications中的所有NotificationRecord,
                           通过对比key判断是否是同一条通知
                           */
5380                      for (int i = 0; i < N; i++) {
5381                          final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
                              //对比key
5382                          if (Objects.equals(key, enqueued.getKey())) {
5383                              r = enqueued;
5384                              break;
5385                          }
5386                      }
5387                      if (r == null) {
5388                          Slog.i(TAG, "Cannot find enqueued record for key: " + key);
5389                          return;
5390                      }
5391  
5392                      if (isBlocked(r)) {
5393                          Slog.i(TAG, "notification blocked by assistant request");
5394                          return;
5395                      }
5396  
5397                      final boolean isPackageSuspended = isPackageSuspendedLocked(r);
5398                      r.setHidden(isPackageSuspended);
5399                      if (isPackageSuspended) {
5400                          mUsageStats.registerSuspendedByAdmin(r);
5401                      }
5402                      NotificationRecord old = mNotificationsByKey.get(key);
5403                      final StatusBarNotification n = r.sbn;
5404                      final Notification notification = n.getNotification();
                          //首次创建通知时还没有添加到mNotificationList里,所以返回-1
5405                      int index = indexOfNotificationLocked(n.getKey());
5406                      if (index < 0) {
                          //将NotificationRecord添加到mNotificationList
5407                          mNotificationList.add(r);
5408                          mUsageStats.registerPostedByApp(r);
5409                          r.setInterruptive(isVisuallyInterruptive(null, r));
5410                      } else {
5411                          old = mNotificationList.get(index);
5412                          mNotificationList.set(index, r);
5413                          mUsageStats.registerUpdatedByApp(r, old);
5414                          // Make sure we don't lose the foreground service state.
5415                          notification.flags |=
5416                                  old.getNotification().flags & FLAG_FOREGROUND_SERVICE;
5417                          r.isUpdate = true;
5418                          r.setTextChanged(isVisuallyInterruptive(old, r));
5419                      }
5420                      //将NotificationRecord添加到
                          //mNotificationsByKey,以key为键
5421                      mNotificationsByKey.put(n.getKey(), r);
5422                      //判断是否是前台通知
5425                      if ((notification.flags & FLAG_FOREGROUND_SERVICE) != 0) {
5426                          notification.flags |= FLAG_ONGOING_EVENT
5427                                  | FLAG_NO_CLEAR;
5428                      }
5429  
5430                      mRankingHelper.extractSignals(r);
5431                      mRankingHelper.sort(mNotificationList);
5432  
5433                      if (!r.isHidden()) {
5434                          buzzBeepBlinkLocked(r);
5435                      }
5436                      /*这里在sdk22之后必须设置小图标,
                           不然会报错,具体报错在NotificationManager
                           fixNotification方法中*/
5437                      if (notification.getSmallIcon() != null) {
5438                          StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
                              //继续传递StatusBarNotification和NotificationRecord
5439                          mListeners.notifyPostedLocked(r, old);
5440                          if ((oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup()))
5441                                  && !isCritical(r)) {
5442                              mHandler.post(new Runnable() {
5443                                  @Override
5444                                  public void run() {
5445                                      mGroupHelper.onNotificationPosted(
5446                                              n, hasAutoGroupSummaryLocked(n));
5447                                  }
5448                              });
5449                          }
5450                      } else {
5451                          Slog.e(TAG, "Not posting notification without small icon: " + notification);
5452                          if (old != null && !old.isCanceled) {
5453                              mListeners.notifyRemovedLocked(r,
5454                                      NotificationListenerService.REASON_ERROR, r.getStats());
5455                              mHandler.post(new Runnable() {
5456                                  @Override
5457                                  public void run() {
5458                                      mGroupHelper.onNotificationRemoved(n);
5459                                  }
5460                              });
5461                          }
5462                       
5465                          Slog.e(TAG, "WARNING: In a future release this will crash the app: "
5466                                  + n.getPackageName());
5467                      }
5468  
5469                      maybeRecordInterruptionLocked(r);
5470                  } finally {
5471                      int N = mEnqueuedNotifications.size();
5472                      for (int i = 0; i < N; i++) {
5473                          final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
5474                          if (Objects.equals(key, enqueued.getKey())) {
5475                              mEnqueuedNotifications.remove(i);
5476                              break;
5477                          }
5478                      }
5479                  }
5480              }
5481          }
5482      }

上面提到的sdk大于22如果不设置小图标将会报错,报错代码:
/frameworks/base/core/java/android/app/NotificationManager.java

private Notification fixNotification(Notification notification) {
        ......
        if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
            if (notification.getSmallIcon() == null) {
                throw new IllegalArgumentException("Invalid notification (no valid small icon): "
                        + notification);
            }
        }
        ......
        return Builder.maybeCloneStrippedForDelivery(notification, isLowRam, mContext);
    }

通过dump命令得到的NotificationRecord,key格式:

 NotificationRecord(0x07a15017: pkg=com.example.app3 user=UserHandle{0} id=110 tag=null importance=2
 key=0|com.example.app3|110|null|10161
 appImportanceLocked=false: Notification(channel= pri=-2 
 contentView=null vibrate=null sound=null defaults=0x0
 flags=0x0 color=0x00000000 vis=PRIVATE))

回看一下key方法

     private String key() {
137    String sbnKey = user.getIdentifier() + "|" + pkg + "|" + id + "|" + tag + "|" + uid;
138    if (overrideGroupKey != null && getNotification().isGroupSummary()) {
139      sbnKey = sbnKey + "|" + overrideGroupKey;
140    }
141    return sbnKey;
142  }

继续mListeners.notifyPostedLocked

mListeners是NotificationListeners,这是NotificationManagerService的内部类

/frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java

7820      public class NotificationListeners extends ManagedServices {
              ......
7926          @GuardedBy("mNotificationLock")
7927          public void notifyPostedLocked(NotificationRecord r, NotificationRecord old) {
7928              notifyPostedLocked(r, old, true);
7929          }
7930  
7931          /**
7932           * @param notifyAllListeners notifies all listeners if true, else only notifies listeners
7933           *                           targetting <= O_MR1
7934           */
7935          @GuardedBy("mNotificationLock")
7936          private void notifyPostedLocked(NotificationRecord r, NotificationRecord old,
7937                  boolean notifyAllListeners) {
7938              
7939              StatusBarNotification sbn = r.sbn;
7940              StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
7941              TrimCache trimCache = new TrimCache(sbn);
7942              //遍历所有的ManagedServiceInfo,getServices()调用父类方法
7943              for (final ManagedServiceInfo info : getServices()) {
7944                  boolean sbnVisible = isVisibleToListener(sbn, info);
7945                  boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
7946                  
7947                  if (!oldSbnVisible && !sbnVisible) {
7948                      continue;
7949                  }
7950                  ......
7964                  final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
7965  
7966                  // This notification became invisible -> remove the old one.
7967                  if (oldSbnVisible && !sbnVisible) {
7968                      final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
7969                      mHandler.post(new Runnable() {
7970                          @Override
7971                          public void run() {
7972                              notifyRemoved(
7973                                      info, oldSbnLightClone, update, null, REASON_USER_STOPPED);
7974                          }
7975                      });
7976                      continue;
7977                  }
7978                  ......
7984                  final StatusBarNotification sbnToPost = trimCache.ForListener(info);
7985                  mHandler.post(new Runnable() {
7986                      @Override
7987                      public void run() {
7988                          notifyPosted(info, sbnToPost, update);
7989                      }
7990                  });
7991              }
7992          }
          ......
}

getServices()调的父类方法
/frameworks/base/services/core/java/com/android/server/notification/ManagedServices.java

124 private final ArrayList<ManagedServiceInfo> mServices = new ArrayList<>();
         //通过mServices构造一个List
175      protected List<ManagedServiceInfo> getServices() {
176          synchronized (mMutex) {
177              List<ManagedServiceInfo> services = new ArrayList<>(mServices);
178              return services;
179          }
180      }

mServices添加info

1250      private ManagedServiceInfo registerServiceImpl(ManagedServiceInfo info) {
1251          synchronized (mMutex) {
1252              try {
1253                  ......
1254                  mServices.add(info);
1255                  return info;
1256              } catch (RemoteException e) {
1258              }
1259          }
1260          return null;
1261      }

1243      private ManagedServiceInfo registerServiceImpl(final IInterface service,
1244              final ComponentName component, final int userid) {
1245          ManagedServiceInfo info = newServiceInfo(service, component, userid,
1246                  true /*isSystem*/, null /*connection*/, Build.VERSION_CODES.LOLLIPOP);
1247          return registerServiceImpl(info);
1248      }

685      public void registerService(IInterface service, ComponentName component, int userid) {
686          ......
687          ManagedServiceInfo info = registerServiceImpl(service, component, userid);
688          if (info != null) {
689              onServiceAdded(info);
690          }
691      }

ManagedServiceInfo.registerService->ManagedServiceInfo.registerServiceImpl(三个参数)->ManagedServiceInfo.registerServiceImpl(一个参数)->mServices.add(info);

registerListener

此方法由子类调用
可以看到此处是INotificationManager server端具体实现
/frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java

2254      final IBinder mService = new INotificationManager.Stub() {
              ......
3067          @Override
3068          public void registerListener(final INotificationListener listener,
3069                  final ComponentName component, final int userid) {
3070              enforceSystemOrSystemUI("INotificationManager.registerListener");
3071              mListeners.registerService(listener, component, userid);
3072          }
             ......
         }

registerAsSystemService

server端的registerListener则是由NotificationListenerService调过来的
/frameworks/base/core/java/android/service/notification/NotificationListenerService.java

1134      @SystemApi
1135      public void registerAsSystemService(Context context, ComponentName componentName,
1136              int currentUser) throws RemoteException {
1137          if (mWrapper == null) {
1138              mWrapper = new NotificationListenerWrapper();
1139          }
1140          mSystemContext = context;
1141          INotificationManager noMan = getNotificationInterface();
1142          mHandler = new MyHandler(context.getMainLooper());
1143          mCurrentUser = currentUser;
1144          noMan.registerListener(mWrapper, componentName, currentUser);
1145      }

NotificationListenerWrapper

NotificationListenerWrapper继承INotificationListener.Stub,作为binder server端具体方法的实现
/frameworks/base/core/java/android/service/notification/NotificationListenerService.java

1263      /** @hide */
1264      protected class NotificationListenerWrapper extends INotificationListener.Stub {
          @Override
1266          public void onNotificationPosted(IStatusBarNotificationHolder sbnHolder,
1267                  NotificationRankingUpdate update) {
1268              StatusBarNotification sbn;
1269              try {
1270                  sbn = sbnHolder.get();
1271              } catch (RemoteException e) {
1272                  Log.w(TAG, "onNotificationPosted: Error receiving StatusBarNotification", e);
1273                  return;
1274              }
1275  
1276              try {
1277                  // convert icon metadata to legacy format for older clients
1278                  createLegacyIconExtras(sbn.getNotification());
1279                  maybePopulateRemoteViews(sbn.getNotification());
1280                  maybePopulatePeople(sbn.getNotification());
1281              } catch (IllegalArgumentException e) {
1282                  // warn and drop corrupt notification
1283                  Log.w(TAG, "onNotificationPosted: can't rebuild notification from " +
1284                          sbn.getPackageName());
1285                  sbn = null;
1286              }
1287  
1288              // protect subclass from concurrent modifications of (@link mNotificationKeys}.
1289              synchronized (mLock) {
1290                  applyUpdateLocked(update);
1291                  if (sbn != null) {
1292                      SomeArgs args = SomeArgs.obtain();
1293                      args.arg1 = sbn;
1294                      args.arg2 = mRankingMap;
1295                      mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_POSTED,
1296                              args).sendToTarget();
1297                  } else {
1298                      // still pass along the ranking map, it may contain other information
1299                      mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_RANKING_UPDATE,
1300                              mRankingMap).sendToTarget();
1301                  }
1302              }
1303  
1304          }
1305  
1306          @Override
1307          public void onNotificationRemoved(IStatusBarNotificationHolder sbnHolder,
1308                  NotificationRankingUpdate update, NotificationStats stats, int reason) {
1309              StatusBarNotification sbn;
1310              try {
1311                  sbn = sbnHolder.get();
1312              } catch (RemoteException e) {
1313                  Log.w(TAG, "onNotificationRemoved: Error receiving StatusBarNotification", e);
1314                  return;
1315              }
1316              // protect subclass from concurrent modifications of (@link mNotificationKeys}.
1317              synchronized (mLock) {
1318                  applyUpdateLocked(update);
1319                  SomeArgs args = SomeArgs.obtain();
1320                  args.arg1 = sbn;
1321                  args.arg2 = mRankingMap;
1322                  args.arg3 = reason;
1323                  args.arg4 = stats;
1324                  mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_REMOVED,
1325                          args).sendToTarget();
1326              }
1327  
1328          }
1329  
1330          @Override
1331          public void onListenerConnected(NotificationRankingUpdate update) {
1332              // protect subclass from concurrent modifications of (@link mNotificationKeys}.
1333              synchronized (mLock) {
1334                  applyUpdateLocked(update);
1335              }
1336              isConnected = true;
1337              mHandler.obtainMessage(MyHandler.MSG_ON_LISTENER_CONNECTED).sendToTarget();
1338          }
}

那么registerAsSystemService是哪里调的呢,registerAsSystemService其实由SystemUI调用过来的,SystemUI部分后面再分析

通过之前分析我们知道了getServices()中的service是由NotificationListenerServiceregisterAsSystemService方法调用注册得到的INotificationListener,即NotificationListenerWrapper,再通过ManagedServicesregisterServiceImpl中调用newServiceInfoNotificationListenerWrapper封装成ManagedServiceInfo

newServiceInfo

/frameworks/base/services/core/java/com/android/server/notification/ManagedServices.java

188      private ManagedServiceInfo newServiceInfo(IInterface service,
189              ComponentName component, int userId, boolean isSystem, ServiceConnection connection,
190              int targetSdkVersion) {
191          return new ManagedServiceInfo(service, component, userId, isSystem, connection,
192                  targetSdkVersion);
193      }

回到之前的notifyPostedLocked方法,mHandler又post了一个runnable,里面调用了notifyPosted方法
/frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java

7935          @GuardedBy("mNotificationLock")
7936          private void notifyPostedLocked(NotificationRecord r, NotificationRecord old,
7937                  boolean notifyAllListeners) {
7939              StatusBarNotification sbn = r.sbn;
7940              StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
7941              TrimCache trimCache = new TrimCache(sbn);
7942  
7943              for (final ManagedServiceInfo info : getServices()) {
7944                  ......
7984                  final StatusBarNotification sbnToPost = trimCache.ForListener(info);
7985                  mHandler.post(new Runnable() {
7986                      @Override
7987                      public void run() {
7988                          notifyPosted(info, sbnToPost, update);
7989                      }
7990                  });
7991              }
7992          }

notifyPosted

8199          private void notifyPosted(final ManagedServiceInfo info,
8200                  final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
                  //info.service即NotificationListenerWrapper
8201              final INotificationListener listener = (INotificationListener) info.service;
                  //将StatusBarNotification封装为StatusBarNotificationHolder
8202              StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
8203              try {
8204                  listener.onNotificationPosted(sbnHolder, rankingUpdate);
8205              } catch (RemoteException ex) {
8206                  Slog.e(TAG, "unable to notify listener (posted): " + listener, ex);
8207              }
8208          }

继续调用listener.onNotificationPosted,即NotificationListenerWrapperonNotificationPosted
/frameworks/base/core/java/android/service/notification/NotificationListenerService.java

1263      /** @hide */
1264      protected class NotificationListenerWrapper extends INotificationListener.Stub {
1265          @Override
1266          public void onNotificationPosted(IStatusBarNotificationHolder sbnHolder,
1267                  NotificationRankingUpdate update) {
1268              StatusBarNotification sbn;
1269              try {
1270                  sbn = sbnHolder.get();
1271              } catch (RemoteException e) {
1272                  Log.w(TAG, "onNotificationPosted: Error receiving StatusBarNotification", e);
1273                  return;
1274              }
1275
1289              synchronized (mLock) {
1290                  applyUpdateLocked(update);
1291                  if (sbn != null) {
1292                      SomeArgs args = SomeArgs.obtain();
1293                      args.arg1 = sbn;
1294                      args.arg2 = mRankingMap;
1295                      mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_POSTED,
1296                              args).sendToTarget();
1297                  } else {
1298                      // still pass along the ranking map, it may contain other information
1299                      mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_RANKING_UPDATE,
1300                              mRankingMap).sendToTarget();
1301                  }
1302              }
1303  
1304          }
           }

MSG_ON_NOTIFICATION_POSTED

通过handler消息机制
/frameworks/base/core/java/android/service/notification/NotificationListenerService.java

2012          @Override
2013          public void handleMessage(Message msg) {
2014              if (!isConnected) {
2015                  return;
2016              }
2017              switch (msg.what) {
2018                  case MSG_ON_NOTIFICATION_POSTED: {
2019                      SomeArgs args = (SomeArgs) msg.obj;
2020                      StatusBarNotification sbn = (StatusBarNotification) args.arg1;
2021                      RankingMap rankingMap = (RankingMap) args.arg2;
2022                      args.recycle();
2023                      onNotificationPosted(sbn, rankingMap);
2024                  } 

调到了外部类NotificationListenerService的onNotificationPosted方法

336      /**
337       * Implement this method to learn about new notifications as they are posted by apps.
338       *
339       * @param sbn A data structure encapsulating the original {@link android.app.Notification}
340       *            object as well as its identifying information (tag and id) and source
341       *            (package name).
342       * @param rankingMap The current ranking map that can be used to retrieve ranking information
343       *                   for active notifications, including the newly posted one.
344       */
345      public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
346          onNotificationPosted(sbn);
347      }
325      /**
326       * Implement this method to learn about new notifications as they are posted by apps.
327       *
328       * @param sbn A data structure encapsulating the original {@link android.app.Notification}
329       *            object as well as its identifying information (tag and id) and source
330       *            (package name).
331       */
332      public void onNotificationPosted(StatusBarNotification sbn) {
333          // optional
334      }

我们看到这两个方法都没有具体实现,都需要子类自己去实现逻辑
到此framework的通知发送过程分析完了,最终到了NotificationListenerServiceonNotificationPosted方法
总结一下:
应用创建通知之后发送流程从NotificationManager开始,

NotificationManager.notify->NotificationManager.notifyAsUser->

NotificationListenerService.mService.enqueueNotificationWithTag->

NotificationListenerService.mService.enqueueNotificationInternal->

NotificationListenerService.EnqueueNotificationRunnable.run->

NotificationListenerService.PostNotificationRunnable.run->

NotificationManagerService.mListeners.notifyPostedLocked->

NotificationManagerService.mHandler.post(notifyPosted)->

NotificationListenerService.NotificationListenerWrapper.onNotificationPosted->

NotificationListenerService.mHandler(MSG_ON_NOTIFICATION_POSTED)->

NotificationListenerService.onNotificationPosted

SystemUINotificationListenerWithPlugins类继承了NotificationListenerService,其子类NotificationListeneronNotificationPosted方法做了具体实现
这样我们发送的通知就到了SystemUI,之后便由SystemUI将此通知显示在锁屏上,关于SystemUI部分下一篇分析

发布了28 篇原创文章 · 获赞 40 · 访问量 4819

猜你喜欢

转载自blog.csdn.net/qq_34211365/article/details/103385247