基于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来看通知是如何发送的
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里
/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 }
......
}
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));
}
以上代码主要就是创建了StatusBarNotification和NotificationRecord,
很典型的一个数据封装类,继承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 }
......
}
数据封装类,将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传递参数
/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
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是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);
此方法由子类调用
可以看到此处是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 }
......
}
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继承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是由NotificationListenerService的registerAsSystemService方法调用注册得到的INotificationListener,即NotificationListenerWrapper,再通过ManagedServices的registerServiceImpl中调用newServiceInfo将NotificationListenerWrapper封装成ManagedServiceInfo
/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 }
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,即NotificationListenerWrapper的onNotificationPosted
/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 }
}
通过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的通知发送过程分析完了,最终到了NotificationListenerService的onNotificationPosted方法
总结一下:
应用创建通知之后发送流程从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
在SystemUI中NotificationListenerWithPlugins类继承了NotificationListenerService,其子类NotificationListener对onNotificationPosted方法做了具体实现
这样我们发送的通知就到了SystemUI,之后便由SystemUI将此通知显示在锁屏上,关于SystemUI部分下一篇分析