android13#NotificationManagerService

746 阅读21分钟

1.简介

整理一下发送一个新的通知,源码层的逻辑

1.1.测试代码

就是通知管理器发送一个通知,学习下流程

notificationManager.notify(id, notification)

>1.notify

public void notify(int id, Notification notification)
{
    notify(null, id, notification);
}
public void notify(String tag, int id, Notification notification)
{
    notifyAsUser(tag, id, notification, mContext.getUser());
}
public void notifyAsUser(String tag, int id, Notification notification, UserHandle user)
{
    INotificationManager service = getService();
    String pkg = mContext.getPackageName();
    try {//这里就走到2.1
        service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
                fixNotification(notification), user.getIdentifier());
    } 
}

2.INotificationManager

小节4NMS里的变量

    final IBinder mService = new INotificationManager.Stub() {

2.1.enqueueNotificationWithTag

        public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
                Notification notification, int userId) throws RemoteException {
                //见4.1
            enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
                    Binder.getCallingPid(), tag, id, notification, userId);
        }

2.2.requestBindListener

绑定通知监听服务

        public void requestBindListener(ComponentName component) {
            checkCallerIsSystemOrSameApp(component.getPackageName());
            try {
                ManagedServices manager =
                        mAssistants.isComponentEnabledForCurrentProfiles(component)
                        ? mAssistants
                        : mListeners;
                manager.setComponentState(component, UserHandle.getUserId(uid), true);
            }
        }

2.3.setNotificationListenerAccessGrantedForUser

        public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
                boolean granted, boolean userSet) {
    //..
            try {//权限检查,这里是空,所以为true
                if (mAllowedManagedServicePackages.test(
                        listener.getPackageName(), userId, mListeners.getRequiredPermission())) {
                    mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
                            userId, false, granted, userSet);
                    //见11.8,加入approved集合
                    mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
                            userId, true, granted, userSet);
            //发送广播
                    getContext().sendBroadcastAsUser(new Intent(
                            ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
                                    .setPackage(listener.getPackageName())
                                    .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
                            UserHandle.of(userId), null);
                //保存数据
                    handleSavePolicyFile();
                }
            } 
        }

3.NotificationManagerInternal

    private final NotificationManagerInternal mInternalService = new NotificationManagerInternal()

3.1.getNotificationChannel

        public NotificationChannel getNotificationChannel(String pkg, int uid, String
                channelId) {
            return mPreferencesHelper.getNotificationChannel(pkg, uid, channelId, false);
        }

3.2.enqueueNotification

  • 服务里边调用startForeground发送一个前台通知,一路走下去到ServiceRecord.java,里边postNotification里会调用
        public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
                String tag, int id, Notification notification, int userId) {
            enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
                    userId);
        }

3.3.cancelNotification

        public void cancelNotification(String pkg, String opPkg, int callingUid, int callingPid,
                String tag, int id, int userId) {
            cancelNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, userId);
        }

4.NotificationManagerService

4.1.enqueueNotificationInternal

    void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
            final int callingPid, final String tag, final int id, final Notification notification,
            int incomingUserId) {
        enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
                incomingUserId, false);
    }
    void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
            final int callingPid, final String tag, final int id, final Notification notification,
            int incomingUserId, boolean postSilently) {
        //..
        final int userId = ActivityManager.handleIncomingUser(callingPid,
                callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
        final UserHandle user = UserHandle.of(userId);

        // 
        final int notificationUid = resolveNotificationUid(opPkg, pkg, callingUid, userId);

        if (notificationUid == INVALID_UID) {
            throw new SecurityException("Caller " + opPkg + ":" + callingUid
                    + " trying to post for invalid pkg " + pkg + " in user " + incomingUserId);
        }

        checkRestrictedCategories(notification);

        // 补充1,调整通知
        try {
            fixNotification(notification, pkg, tag, id, userId);
        } catch (Exception e) {
            if (notification.isForegroundService()) {
                throw new SecurityException("Invalid FGS notification", e);
            }
            return;
        }

        final ServiceNotificationPolicy policy = mAmi.applyForegroundServiceNotification(
                notification, tag, id, pkg, userId);
        if (policy == ServiceNotificationPolicy.UPDATE_ONLY) {
            if (!isNotificationShownInternal(pkg, tag, id, userId)) {
                reportForegroundServiceUpdate(false, notification, id, pkg, userId);
                return;
            }
        }

        mUsageStats.registerEnqueuedByApp(pkg);
        //创建状态栏通知对象
        final StatusBarNotification n = new StatusBarNotification(
                pkg, opPkg, id, tag, notificationUid, callingPid, notification,
                user, null, System.currentTimeMillis());

        String channelId = notification.getChannelId();

        String shortcutId = n.getShortcutId();
        final NotificationChannel channel = mPreferencesHelper.getConversationNotificationChannel(
                pkg, notificationUid, channelId, shortcutId,
                true /* parent ok */, false /* includeDeleted */);
        //通知所属的channel为空
        if (channel == null) {
            boolean appNotificationsOff = !mPermissionHelper.hasPermission(notificationUid);

            if (!appNotificationsOff) {
            //提示
                doChannelWarningToast(notificationUid,
                        "Developer warning for package \"" + pkg + "\"\n" +
                        "Failed to post notification on channel \"" + channelId + "\"\n" +
                        "See log for more details");
            }
            return;
        }
        //创建通知记录对象
        final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
        r.setIsAppImportanceLocked(mPermissionHelper.isPermissionUserSet(pkg, userId));
        r.setPostSilently(postSilently);
        r.setFlagBubbleRemoved(false);
        r.setPkgAllowedAsConvo(mMsgPkgsAllowedAsConvos.contains(pkg));
        boolean isImportanceFixed = mPermissionHelper.isPermissionFixed(pkg, userId);
        r.setImportanceFixed(isImportanceFixed);
        //前台通知
        if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
            final boolean fgServiceShown = channel.isFgServiceShown();
            if (((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
                        || !fgServiceShown)
                    && (r.getImportance() == IMPORTANCE_MIN
                            || r.getImportance() == IMPORTANCE_NONE)) {
                if (TextUtils.isEmpty(channelId)
                        || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
                    r.setSystemImportance(IMPORTANCE_LOW);
                } else {
                    channel.setImportance(IMPORTANCE_LOW);
                    r.setSystemImportance(IMPORTANCE_LOW);
                    if (!fgServiceShown) {
                        channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
                        channel.setFgServiceShown(true);
                    }
                    mPreferencesHelper.updateNotificationChannel(
                            pkg, notificationUid, channel, false);
                    r.updateNotificationChannel(channel);
                }
            } else if (!fgServiceShown && !TextUtils.isEmpty(channelId)
                    && !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
                channel.setFgServiceShown(true);
                r.updateNotificationChannel(channel);
            }
        }

        ShortcutInfo info = mShortcutHelper != null
                ? mShortcutHelper.getValidShortcutInfo(notification.getShortcutId(), pkg, user)
                : null;

        r.setShortcutInfo(info);
        r.setHasSentValidMsg(mPreferencesHelper.hasSentValidMsg(pkg, notificationUid));
        r.userDemotedAppFromConvoSpace(
                mPreferencesHelper.hasUserDemotedInvalidMsgApp(pkg, notificationUid));
        //检查通知是否可以post
        if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
                r.getSbn().getOverrideGroupKey() != null)) {
            return;
        }

        if (info != null) {
            mShortcutHelper.cacheShortcut(info, user);
        }


        if (notification.allPendingIntents != null) {
            final int intentCount = notification.allPendingIntents.size();
            if (intentCount > 0) {
                final long duration = LocalServices.getService(
                        DeviceIdleInternal.class).getNotificationAllowlistDuration();
                for (int i = 0; i < intentCount; i++) {
                    PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
                    if (pendingIntent != null) {
                        mAmi.setPendingIntentAllowlistDuration(pendingIntent.getTarget(),
                                ALLOWLIST_TOKEN, duration,
                                TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
                                REASON_NOTIFICATION_SERVICE,
                                "NotificationManagerService");
                        mAmi.setPendingIntentAllowBgActivityStarts(pendingIntent.getTarget(),
                                ALLOWLIST_TOKEN, (FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER
                                        | FLAG_SERVICE_SENDER));
                    }
                }
            }
        }

        //需要升级特权来获得包的重要性
        final long token = Binder.clearCallingIdentity();
        boolean isAppForeground;
        try {
            isAppForeground = mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND;
        } finally {
            Binder.restoreCallingIdentity(token);
        }
        //见4.2
        mHandler.post(new EnqueueNotificationRunnable(userId, r, isAppForeground,
                SystemClock.elapsedRealtime()));
    }
            

>1.fixNotification

通知进行适配调整

    protected void fixNotification(Notification notification, String pkg, String tag, int id,
            int userId) throws NameNotFoundException, RemoteException {
        final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
                pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                (userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId);
        Notification.addFieldsFromContext(ai, notification);
          //彩色通知权限  
        int canColorize = mPackageManagerClient.checkPermission(
                android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg);
        if (canColorize == PERMISSION_GRANTED) {
            notification.flags |= Notification.FLAG_CAN_COLORIZE;
        } else {
            notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
        }

        if (notification.fullScreenIntent != null && ai.targetSdkVersion >= Build.VERSION_CODES.Q) {
        //全屏通知需要权限
            int fullscreenIntentPermission = mPackageManagerClient.checkPermission(
                    android.Manifest.permission.USE_FULL_SCREEN_INTENT, pkg);
            if (fullscreenIntentPermission != PERMISSION_GRANTED) {
                notification.fullScreenIntent = null;//没有权限,数据置为空
            }
        }

        // Ensure CallStyle has all the correct actions
        if (notification.isStyle(Notification.CallStyle.class)) {
            Notification.Builder builder =
                    Notification.Builder.recoverBuilder(getContext(), notification);
            Notification.CallStyle style = (Notification.CallStyle) builder.getStyle();
            List<Notification.Action> actions = style.getActionsListWithSystemActions();
            notification.actions = new Notification.Action[actions.size()];
            actions.toArray(notification.actions);
        }

        //确保MediaStyle对远程设备附加功能具有正确的权限
        if (notification.isStyle(Notification.MediaStyle.class)) {
            //多媒体类型的通知,需要权限
            int hasMediaContentControlPermission = mPackageManager.checkPermission(
                    android.Manifest.permission.MEDIA_CONTENT_CONTROL, pkg, userId);
            if (hasMediaContentControlPermission != PERMISSION_GRANTED) {
                notification.extras.remove(Notification.EXTRA_MEDIA_REMOTE_DEVICE);
                notification.extras.remove(Notification.EXTRA_MEDIA_REMOTE_ICON);
                notification.extras.remove(Notification.EXTRA_MEDIA_REMOTE_INTENT);

            }
        }

        //确保只有允许的包有一个替代的应用程序名称
        if (notification.extras.containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME)) {
        //权限检查
            int hasSubstituteAppNamePermission = mPackageManager.checkPermission(
                    permission.SUBSTITUTE_NOTIFICATION_APP_NAME, pkg, userId);
            if (hasSubstituteAppNamePermission != PERMISSION_GRANTED) {
                notification.extras.remove(Notification.EXTRA_SUBSTITUTE_APP_NAME);

            }
        }

        //尺寸检查,太大的话设置为空
        checkRemoteViews(pkg, tag, id, notification);
    }

4.2.EnqueueNotificationRunnable

一个把通知数据插入队列的Runnable

        public void run() {
            synchronized (mNotificationLock) {
                final Long snoozeAt =
                        mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
                                r.getUser().getIdentifier(),
                                r.getSbn().getPackageName(), r.getSbn().getKey());
                final long currentTime = System.currentTimeMillis();
                if (snoozeAt.longValue() > currentTime) {
                    (new SnoozeNotificationRunnable(r.getSbn().getKey(),
                            snoozeAt.longValue() - currentTime, null)).snoozeLocked(r);
                    return;
                }

                final String contextId =
                        mSnoozeHelper.getSnoozeContextForUnpostedNotification(
                                r.getUser().getIdentifier(),
                                r.getSbn().getPackageName(), r.getSbn().getKey());
                if (contextId != null) {
                    (new SnoozeNotificationRunnable(r.getSbn().getKey(),
                            0, contextId)).snoozeLocked(r);
                    return;
                }
                //加入队列
                mEnqueuedNotifications.add(r);
                //见补充1,如果有设置自动取消通知时间的
                scheduleTimeoutLocked(r);

                final StatusBarNotification n = r.getSbn();

                NotificationRecord old = mNotificationsByKey.get(n.getKey());
                if (old != null) {
                    //保留以前记录中的排名信息
                    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();


                updateNotificationBubbleFlags(r, isAppForeground);


                handleGroupedNotificationLocked(r, old, callingUid, callingPid);

                //群组通知里的一种,更新summary
                if (n.isGroup() && notification.isGroupChild()) {
                    mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
                }

                //
                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;
                    }
                }

                // tell the assistant service about the notification
                if (mAssistants.isEnabled()) {
                    mAssistants.onNotificationEnqueuedLocked(r);
                    mHandler.postDelayed(
                            new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
                                    r.getUid(), enqueueElapsedTimeMs),
                            DELAY_FOR_ASSISTANT_TIME);
                } else {
                //见4.3
                    mHandler.post(new PostNotificationRunnable(r.getKey(),
                            r.getSbn().getPackageName(), r.getUid(), enqueueElapsedTimeMs));
                }
            }
        }

>1.scheduleTimeoutLocked

处理超时自动取消的广播,这里添加了一个闹铃,到时候取消通知

    void scheduleTimeoutLocked(NotificationRecord record) {
        //有设置超时时间的
        if (record.getNotification().getTimeoutAfter() > 0) {
        //封装一个意图广播,到时间发送广播
            final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
                    REQUEST_CODE_TIMEOUT,
                    new Intent(ACTION_NOTIFICATION_TIMEOUT)//见补充2处理
                            .setPackage(PackageManagerService.PLATFORM_PACKAGE_NAME)
                            .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
                                    .appendPath(record.getKey()).build())
                            .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
                            .putExtra(EXTRA_KEY, record.getKey()),
                    PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
            //通过闹铃管理器处理        
            mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                    SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
        }
    }

>2.mNotificationTimeoutReceiver

    private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (action == null) {
                return;
            }
            if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
                final NotificationRecord record;
                synchronized (mNotificationLock) {
                    record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
                }
                if (record != null) {
                //取消通知
                    cancelNotification(record.getSbn().getUid(), record.getSbn().getInitialPid(),
                            record.getSbn().getPackageName(), record.getSbn().getTag(),
                            record.getSbn().getId(), 0,
                            FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
                            REASON_TIMEOUT, null);
                }
            }
        }
    };

4.3.PostNotificationRunnable

处理通知发送的Runnable

        public void run() {
            //没有发送通知的权限,则为true
            boolean appBanned = !areNotificationsEnabledForPackageInt(pkg, uid);
            //通话中
            boolean isCallNotification = isCallNotification(pkg, uid);
            synchronized (mNotificationLock) {
                try {
                    NotificationRecord r = null;
                    int N = mEnqueuedNotifications.size();
                    for (int i = 0; i < N; i++) {
                        final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
                        if (Objects.equals(key, enqueued.getKey())) {
                            r = enqueued;
                            break;
                        }
                    }
                    if (r == null) {
                        return;
                    }

                    final StatusBarNotification n = r.getSbn();
                    final Notification notification = n.getNotification();
                    boolean isCallNotificationAndCorrectStyle = isCallNotification
                            && notification.isStyle(Notification.CallStyle.class);

                    if (!(notification.isMediaNotification() || isCallNotificationAndCorrectStyle)
                            && (appBanned || isRecordBlockedLocked(r))) {
                        mUsageStats.registerBlocked(r);
                    //通知被禁止的
                        return;
                    }
                    //包是挂起状态
                    final boolean isPackageSuspended =
                            isPackagePausedOrSuspended(r.getSbn().getPackageName(), r.getUid());
                    r.setHidden(isPackageSuspended);
                    if (isPackageSuspended) {
                        mUsageStats.registerSuspendedByAdmin(r);
                    }
                    //获取旧的通知记录
                    NotificationRecord old = mNotificationsByKey.get(key);

                    if (old == null || old.getSbn().getInstanceId() == null) {
                        n.setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
                    } else {
                        n.setInstanceId(old.getSbn().getInstanceId());
                    }
                    //获取在通知列表里的索引
                    int index = indexOfNotificationLocked(n.getKey());
                    if (index < 0) {//没找到,新加通知
                        mNotificationList.add(r);
                        mUsageStats.registerPostedByApp(r);
                        mUsageStatsManagerInternal.reportNotificationPosted(r.getSbn().getOpPkg(),
                                r.getSbn().getUser(), postElapsedTimeMs);
                        final boolean isInterruptive = isVisuallyInterruptive(null, r);
                        r.setInterruptive(isInterruptive);
                        r.setTextChanged(isInterruptive);
                    } else {//有旧的,更新通知
                        old = mNotificationList.get(index);  // Potentially *changes* old
                        mNotificationList.set(index, r);
                        mUsageStats.registerUpdatedByApp(r, old);
                        mUsageStatsManagerInternal.reportNotificationUpdated(r.getSbn().getOpPkg(),
                                r.getSbn().getUser(), postElapsedTimeMs);
                        // Make sure we don't lose the foreground service state.
                        notification.flags |=
                                old.getNotification().flags & FLAG_FOREGROUND_SERVICE;
                        r.isUpdate = true;
                        final boolean isInterruptive = isVisuallyInterruptive(old, r);
                        r.setTextChanged(isInterruptive);
                    }
                
                    mNotificationsByKey.put(n.getKey(), r);

                    //前台服务通知,添加必要的flag
                    if ((notification.flags & FLAG_FOREGROUND_SERVICE) != 0) {
                        notification.flags |= FLAG_NO_CLEAR;
                        if (!mAllowFgsDismissal) {
                            notification.flags |= FLAG_ONGOING_EVENT;
                        }
                    }
                    //排序
                    mRankingHelper.extractSignals(r);
                    mRankingHelper.sort(mNotificationList);
                    final int position = mRankingHelper.indexOf(mNotificationList, r);

                    int buzzBeepBlinkLoggingCode = 0;
                    if (!r.isHidden()) {
                        //见补充1,获取声音震动闪灯的状态,封装成一个值返回
                        buzzBeepBlinkLoggingCode = buzzBeepBlinkLocked(r);
                    }

                    if (notification.getSmallIcon() != null) {
                        StatusBarNotification oldSbn = (old != null) ? old.getSbn() : null;
                        //更新状态栏通知
                        mListeners.notifyPostedLocked(r, old);
                        //旧的通知为空或者新旧通知的group不一样。并且新的非紧急通知
                        if ((oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup()))
                                && !isCritical(r)) {//补充2
                            mHandler.post(() -> {
                                synchronized (mNotificationLock) {
                                //发布新的状态栏通知
                                    mGroupHelper.onNotificationPosted(
                                            n, hasAutoGroupSummaryLocked(n));
                                }
                            });
                        } else if (oldSbn != null) {
                            final NotificationRecord finalRecord = r;
                            //更新状态栏通知
                            mHandler.post(() ->
                                    mGroupHelper.onNotificationUpdated(finalRecord.getSbn()));
                        }
                    } else {
                        //通知没有设置smallIcon,这是有问题的
                        if (old != null && !old.isCanceled) {
                            //移除旧的通知
                            mListeners.notifyRemovedLocked(r,
                                    NotificationListenerService.REASON_ERROR, r.getStats());
                            mHandler.post(new Runnable() {
                                @Override
                                public void run() {
                                    mGroupHelper.onNotificationRemoved(n);
                                }
                            });
                        }
                    }

                    if (mShortcutHelper != null) {
                        mShortcutHelper.maybeListenForShortcutChangesForBubbles(r,
                                false /* isRemoved */,
                                mHandler);
                    }
                    
                    maybeRecordInterruptionLocked(r);
                    maybeRegisterMessageSent(r);
                    maybeReportForegroundServiceUpdate(r, true);


                } finally {
                    //末尾从队列集合里移除当前已处理的通知
                    int N = mEnqueuedNotifications.size();
                    for (int i = 0; i < N; i++) {
                        final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
                        if (Objects.equals(key, enqueued.getKey())) {
                            mEnqueuedNotifications.remove(i);
                            break;
                        }
                    }
                }
            }
        }

>1.buzzBeepBlinkLocked

确定通知是否应该发出声音,震动,闪烁

    int buzzBeepBlinkLocked(NotificationRecord record) {
        if (mIsAutomotive && !mNotificationEffectsEnabledForAutomotive) {
        //汽车并且通知效果不可用
            return 0;
        }
        boolean buzz = false;
        boolean beep = false;
        boolean blink = false;

        final String key = record.getKey();

        //重要性大于等于默认值3的才有效果的
        final boolean aboveThreshold =
                mIsAutomotive
                        ? record.getImportance() > NotificationManager.IMPORTANCE_DEFAULT
                        : record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
        //请记住此通知是否已经拥有通知通道
        boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
        boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
        //如果允许通知发出噪声,则在条件中设置这些参数
        boolean hasValidVibrate = false;
        boolean hasValidSound = false;
        boolean sentAccessibilityEvent = false;

        // 如果通知将出现在状态栏中,它应该发送一个可访问性事件
        final boolean suppressedByDnd = record.isIntercepted()
                && (record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_STATUS_BAR) != 0;
        if (!record.isUpdate
                && record.getImportance() > IMPORTANCE_MIN
                && !suppressedByDnd
                && isNotificationForCurrentUser(record)) {
            sendAccessibilityEvent(record);
            sentAccessibilityEvent = true;
        }

        if (aboveThreshold && isNotificationForCurrentUser(record)) {
            if (mSystemReady && mAudioManager != null) {
                Uri soundUri = record.getSound();
                hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
                VibrationEffect vibration = record.getVibration();
                //如果缺少振动且手机处于振动模式,则将声音调为振动
                if (vibration == null
                        && hasValidSound
                        && (mAudioManager.getRingerModeInternal()
                        == AudioManager.RINGER_MODE_VIBRATE)
                        && mAudioManager.getStreamVolume(
                        AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) {
                    boolean insistent = (record.getFlags() & Notification.FLAG_INSISTENT) != 0;
                    vibration = mVibratorHelper.createFallbackVibration(insistent);
                }
                hasValidVibrate = vibration != null;
                boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
                //见补充3
                if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
                    if (!sentAccessibilityEvent) {
                        sendAccessibilityEvent(record);
                        sentAccessibilityEvent = true;
                    }
                    //持续更新,就是连续的通知。。
                    boolean isInsistentUpdate = isInsistentUpdate(record);
                    if (hasValidSound) {
                        if (isInsistentUpdate) {
                            // 声音为true
                            beep = true;
                        } else {
                            if (isInCall()) {
                                playInCallNotification();
                                beep = true;
                            } else {
                            //播放声音返回结果
                                beep = playSound(record, soundUri);
                            }
                            if (beep) {
                                mSoundNotificationKey = key;
                            }
                        }
                    }

                    final boolean ringerModeSilent =
                            mAudioManager.getRingerModeInternal()
                                    == AudioManager.RINGER_MODE_SILENT;
                        //非通话中,有设置震动,非静音模式
                    if (!isInCall() && hasValidVibrate && !ringerModeSilent) {
                        if (isInsistentUpdate) {
                            buzz = true;
                        } else {
                        //震动
                            buzz = playVibration(record, vibration, hasValidSound);
                            if (buzz) {
                                mVibrateNotificationKey = key;
                            }
                        }
                    }
                } else if ((record.getFlags() & Notification.FLAG_INSISTENT) != 0) {
                    hasValidSound = false;
                }
            }
        }
        //旧通知有声音,新的没有
        if (wasBeep && !hasValidSound) {
            //停止声音播放
            clearSoundLocked();
        }
        //同上
        if (wasBuzz && !hasValidVibrate) {
        //停止震动
            clearVibrateLocked();
        }

        //旧的light状态
        boolean wasShowLights = mLights.remove(key);
        //见4.4,是否可以闪灯
        if (canShowLightsLocked(record, aboveThreshold)) {
            //加入集合
            mLights.add(key);
            //见4.6,闪灯或者灭灯
            updateLightsLocked();
//mUseAttentionLight:只有当设备具有单独的注意灯和通知灯时,才将此设置为true,默认false
            if (mUseAttentionLight && mAttentionLight != null) {
                //如果支持提示灯并且不为空的话,见7.1.4
                mAttentionLight.pulse();
            }
            blink = true;
        } else if (wasShowLights) {
            updateLightsLocked();
        }
        //3种状态封装成一个int
        final int buzzBeepBlink = (buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0);
        if (buzzBeepBlink > 0) {
            // 忽略摘要更新,因为我们不会显示大部分信息
            if (record.getSbn().isGroup() && record.getSbn().getNotification().isGroupSummary()) {

            } else if (record.canBubble()) {

            } else {
                record.setInterruptive(true);
            }
        //为true记录下震动或声音的开始时间,为false,时间为-1
        record.setAudiblyAlerted(buzz || beep);
        return buzzBeepBlink;
    }

>2.isCritical

是否是紧急通知,默认的critical是normal=2,还有个0和1就是紧急的

    private boolean isCritical(NotificationRecord record) {
        // 0 is the most critical
        return record.getCriticality() < CriticalNotificationExtractor.NORMAL;
    }

>3.shouldMuteNotificationLocked

通知是否应该静默的

    boolean shouldMuteNotificationLocked(final NotificationRecord record) {

        final Notification notification = record.getNotification();
        if (record.isUpdate && (notification.flags & FLAG_ONLY_ALERT_ONCE) != 0) {
        //通知更新,并且限制只提示一次
            return true;
        }

        // Suppressed because a user manually unsnoozed something (or similar)
        if (record.shouldPostSilently()) {
            return true;
        }

        // muted by listener,见补充4
        final String disableEffects = disableNotificationEffects(record);
        if (disableEffects != null) {
            ZenLog.traceDisableEffects(record, disableEffects);
            return true;
        }

        // suppressed due to DND
        if (record.isIntercepted()) {
            return true;
        }

        // Suppressed because another notification in its group handles alerting
        if (record.getSbn().isGroup()) {
            if (notification.suppressAlertingDueToGrouping()) {
                return true;
            }
        }

        // Suppressed for being too recently noisy
        final String pkg = record.getSbn().getPackageName();
        if (mUsageStats.isAlertRateLimited(pkg)) {
            Slog.e(TAG, "Muting recently noisy " + record.getKey());
            return true;
        }

        // A different looping ringtone, such as an incoming call is playing
        if (isCurrentlyInsistent() && !isInsistentUpdate(record)) {
            return true;
        }

        // Suppressed since it's a non-interruptive update to a bubble-suppressed notification
        final boolean isBubbleOrOverflowed = record.canBubble() && (record.isFlagBubbleRemoved()
                || record.getNotification().isBubbleNotification());
        if (record.isUpdate && !record.isInterruptive() && isBubbleOrOverflowed
                && record.getNotification().getBubbleMetadata() != null) {
            if (record.getNotification().getBubbleMetadata().isNotificationSuppressed()) {
                return true;
            }
        }

        return false;
    }

>4.disableNotificationEffects

  • mListenerHints是NotificationListenerService.java里设置的,暂时没找到哪里用到
    private String disableNotificationEffects(NotificationRecord record) {
        if (mDisableNotificationEffects) {
            //一种是setupwizard还没完成,一种是状态栏disable了通知
            return "booleanState";
        }
        if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
            return "listenerHints";
        }
        if (record != null && record.getAudioAttributes() != null) {
            if ((mListenerHints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
                if (record.getAudioAttributes().getUsage()
                        != AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
                    return "listenerNoti";
                }
            }
            if ((mListenerHints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
                if (record.getAudioAttributes().getUsage()
                        == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
                    return "listenerCall";
                }
            }
        }
        if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
            return "callState";
        }
        return null;
    }

4.4.canShowLightsLocked

返回通知是否支持led灯

    boolean canShowLightsLocked(final NotificationRecord record, boolean aboveThreshold) {
        if (!mHasLight) {
        //配置不支持light,补充1
            return false;
        }
        //Settings.System.NOTIFICATION_LIGHT_PULSE的值,默认是true的
        if (!mNotificationPulseEnabled) {
            return false;
        }
        //见5.1.5,用户enableShowLight才不为空
        if (record.getLight() == null) {
            return false;
        }
        // 不重要的通知
        if (!aboveThreshold) {
            return false;
        }
        // 勿扰模式限制
        if ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) != 0) {
            return false;
        }
        // Suppressed because it's a silent update
        final Notification notification = record.getNotification();
        if (record.isUpdate && (notification.flags & FLAG_ONLY_ALERT_ONCE) != 0) {
            return false;
        }
        // Suppressed because another notification in its group handles alerting
        if (record.getSbn().isGroup() && record.getNotification().suppressAlertingDueToGrouping()) {
            return false;
        }
        // not if in call
        if (isInCall()) {
            return false;
        }
        // check current user
        if (!isNotificationForCurrentUser(record)) {
            return false;
        }
        // Light, but only when the screen is off
        return true;
    }

>1.mHasLight

        mHasLight =
                resources.getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed);

>2.mNotificationPulseEnabled

    boolean mNotificationPulseEnabled;

监听Settings.System.NOTIFICATION_LIGHT_PULSE的值,打印了下是1

            if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
                boolean pulseEnabled = Settings.System.getIntForUser(resolver,
                            Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT)
                        != 0;
                if (mNotificationPulseEnabled != pulseEnabled) {
                    mNotificationPulseEnabled = pulseEnabled;
                    updateNotificationPulse();
                }
            }

4.5.mIntentReceiver

  • 跟踪屏幕的开/关状态,但不要关闭通知灯直到用户通过锁屏或下拉查看通知
  • 如下3种,屏幕点亮,熄灭以及通话状态的改变,会更新通知灯的状态
    private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();

            if (action.equals(Intent.ACTION_SCREEN_ON)) {
                mScreenOn = true;
                updateNotificationPulse();//见补充1
            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
                mScreenOn = false;
                updateNotificationPulse();
            } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
                mInCallStateOffHook = TelephonyManager.EXTRA_STATE_OFFHOOK
                        .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
                updateNotificationPulse();
            }

>1.updateNotificationPulse

    private void updateNotificationPulse() {
        synchronized (mNotificationLock) {
        //见4.6
            updateLightsLocked();
        }
    }

4.6.updateLightsLocked

更新通知灯的状态

    void updateLightsLocked()
    {
        if (mNotificationLight == null) {
            return;
        }

        //通过lights查找对应的通知,没找到的话从集合里删除
        NotificationRecord ledNotification = null;
        while (ledNotification == null && !mLights.isEmpty()) {
        //找到最新的一个通知
            final String owner = mLights.get(mLights.size() - 1);
            ledNotification = mNotificationsByKey.get(owner);
            if (ledNotification == null) {
                mLights.remove(owner);
            }
        }

        //没有需要led的通知,或者通话中,或者屏幕点亮
        if (ledNotification == null || isInCall() || mScreenOn) {
            //关闭led,见7.1.2
            mNotificationLight.turnOff();
        } else {
            NotificationRecord.Light light = ledNotification.getLight();
            if (light != null && mNotificationPulseEnabled) {
                //led开始脉冲,见7.1.1
                mNotificationLight.setFlashing(light.color, LogicalLight.LIGHT_FLASH_TIMED,
                        light.onMs, light.offMs);
            }
        }
    }

4.7.canUseManagedServices

  • 包的权限检查,如果没有要检查的权限,则返回true
  • mAllowedManagedServicePackages会调用test方法,就是这个方法
        // Needs to be set before loadPolicyFile
        mAllowedManagedServicePackages = this::canUseManagedServices;
   boolean canUseManagedServices(String pkg, Integer userId, String requiredPermission) {
       boolean canUseManagedServices = true;
       if (requiredPermission != null) {
           try {
               if (mPackageManager.checkPermission(requiredPermission, pkg, userId)
                       != PackageManager.PERMISSION_GRANTED) {
                   canUseManagedServices = false;
               }
           } 
       }

       return canUseManagedServices;
   }

4.8.handleSavePolicyFile

这个就是保存policy数据到文件的方法,几十个地方调用,就不看了。

    protected void handleSavePolicyFile() {
        if (!IoThread.getHandler().hasCallbacks(mSavePolicyFile)) {
            IoThread.getHandler().postDelayed(mSavePolicyFile, 250);
        }
    }

4.9.loadPolicyFile

  • init方法里调用
  • 首次加载会走catch方法里,第一次文件肯定不存在,catch里会加载默认数据
    protected void loadPolicyFile() {
        synchronized (mPolicyFile) {
            InputStream infile = null;
            try {
                infile = mPolicyFile.openRead();
                //见4.10,解析数据
                readPolicyXml(infile, false /*forRestore*/, UserHandle.USER_ALL);
            } catch (FileNotFoundException e) {
                //第一次的话文件没找到,加载默认的允许的管理服务,见补充1
                loadDefaultApprovedServices(USER_SYSTEM);
                //补充2,末尾会保存文件,之后就不会走到这个异常里了
                allowDefaultApprovedServices(USER_SYSTEM);
            }
        }
    }

>1.loadDefaultApprovedServices

    void loadDefaultApprovedServices(int userId) {
        //见9.5
        mListeners.loadDefaultsFromConfig();

        mConditionProviders.loadDefaultsFromConfig();
        //见10.5
        mAssistants.loadDefaultsFromConfig();
    }

>2.allowDefaultApprovedServices

    protected void allowDefaultApprovedServices(int userId) {
    //数据就是补充1里加载的,见9.5.1里的配置
        ArraySet<ComponentName> defaultListeners = mListeners.getDefaultComponents();
        for (int i = 0; i < defaultListeners.size(); i++) {
            ComponentName cn = defaultListeners.valueAt(i);
            //最终会走2.3,再到11.8,加入approved集合
            allowNotificationListener(userId, cn);
        }
        //这个配置的是DND勿扰模式下允许的包,
        ArraySet<String> defaultDnds = mConditionProviders.getDefaultPackages();
        for (int i = 0; i < defaultDnds.size(); i++) {
            allowDndPackage(userId, defaultDnds.valueAt(i));
        }

        setDefaultAssistantForUser(userId);
    }

4.10.readPolicyXml

    void readPolicyXml(InputStream stream, boolean forRestore, int userId)
            throws XmlPullParserException, NumberFormatException, IOException {
        //..
        while (XmlUtils.nextElementWithin(parser, outerDepth)) {
            if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) {
                mZenModeHelper.readXml(parser, forRestore, userId);
            } else if (PreferencesHelper.TAG_RANKING.equals(parser.getName())){
                mPreferencesHelper.readXml(parser, forRestore, userId);
            }
            if (mListeners.getConfig().xmlTag.equals(parser.getName())) {
                if (ineligibleForManagedServices) {
                    continue;
                }

                mListeners.readXml(parser, mAllowedManagedServicePackages, forRestore, userId);
                migratedManagedServices = true;
            } else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) {
                if (ineligibleForManagedServices) {
                    continue;
                }
                //解析数据
                mAssistants.readXml(parser, mAllowedManagedServicePackages, forRestore, userId);
                migratedManagedServices = true;
            } else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) {
                if (ineligibleForManagedServices) {
                    continue;
                }//解析数据
                mConditionProviders.readXml(
                        parser, mAllowedManagedServicePackages, forRestore, userId);
                migratedManagedServices = true;
            } else if (mSnoozeHelper.XML_TAG_NAME.equals(parser.getName())) {
                mSnoozeHelper.readXml(parser, System.currentTimeMillis());
            }
            if (LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG.equals(parser.getName())) {
                if (forRestore && userId != UserHandle.USER_SYSTEM) {
                    continue;
                }
                mLockScreenAllowSecureNotifications = parser.getAttributeBoolean(null,
                        LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE, true);
            }
        }

        if (!migratedManagedServices) {
            mListeners.migrateToXml();
            mAssistants.migrateToXml();
            mConditionProviders.migrateToXml();
            handleSavePolicyFile();
        }

        mAssistants.resetDefaultAssistantsIfNecessary();
    }

5.NotificationRecord.java

  • 学习下通知相关的声音,震动,灯光等默认值,以及key

5.1.构造方法

    public NotificationRecord(Context context, StatusBarNotification sbn,
            NotificationChannel channel) {
        this.sbn = sbn;
        mTargetSdkVersion = LocalServices.getService(PackageManagerInternal.class)
                .getPackageTargetSdkVersion(sbn.getPackageName());
        mAm = ActivityManager.getService();
        mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
        mOriginalFlags = sbn.getNotification().flags;
        mRankingTimeMs = calculateRankingTimeMs(0L);
        mCreationTimeMs = sbn.getPostTime();
        mUpdateTimeMs = mCreationTimeMs;
        mInterruptionTimeMs = mCreationTimeMs;
        mContext = context;
        stats = new NotificationUsageStats.SingleNotificationStats();
        mChannel = channel;
        //api26才添加的channel,这里判断是否是26以前的版本,肯定是false
        mPreChannelsNotification = isPreChannelsNotification();
        mSound = calculateSound();//补充1
        mVibration = calculateVibration();//补充2
        mAttributes = calculateAttributes();//补充3
        mImportance = calculateInitialImportance();//补充4
        mLight = calculateLights();//补充5
        mAdjustments = new ArrayList<>();
        mStats = new NotificationStats();
        calculateUserSentiment();
        calculateGrantableUris();
    }

>1.calculateSound

通知声音获取

    private Uri calculateSound() {
        final Notification n = getSbn().getNotification();

        // tv不支持通知
        if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
            return null;
        }
        //获取channel里的声音uri,这个是有默认值的
        Uri sound = mChannel.getSound();

        //..
        return sound;
    }

2.calculateVibration

通知震动

    private VibrationEffect calculateVibration() {
        VibratorHelper helper = new VibratorHelper(mContext);
        final Notification notification = getSbn().getNotification();
        final boolean insistent = (notification.flags & Notification.FLAG_INSISTENT) != 0;
        //获取默认的震动效果
        VibrationEffect defaultVibration = helper.createDefaultVibration(insistent);
        VibrationEffect vibration;
        //获取channel里设置的是否需要震动
        if (getChannel().shouldVibrate()) {
        //没有设置震动模式的话,用默认的
        //有设置的话就生成一个新的
            vibration = getChannel().getVibrationPattern() == null
                    ? defaultVibration
                    : helper.createWaveformVibration(getChannel().getVibrationPattern(), insistent);
        } else {//不需要震动
            vibration = null;
        }
        //..
        return vibration;
    }

>3.calculateAttributes

    private AudioAttributes calculateAttributes() {
        final Notification n = getSbn().getNotification();
        AudioAttributes attributes = getChannel().getAudioAttributes();
        if (attributes == null) {
            attributes = Notification.AUDIO_ATTRIBUTES_DEFAULT;
        }

    //..
        return attributes;
    }

>4.calculateInitialImportance

    private int calculateInitialImportance() {
        final Notification n = getSbn().getNotification();
        //获取channel设置的重要性
        int importance = getChannel().getImportance(); 
        
        mInitialImportanceExplanationCode = getChannel().hasUserSetImportance()
                ? MetricsEvent.IMPORTANCE_EXPLANATION_USER
                : MetricsEvent.IMPORTANCE_EXPLANATION_APP;

        //flag转化成优先级
        if (0 != (n.flags & Notification.FLAG_HIGH_PRIORITY)) {
            n.priority = Notification.PRIORITY_MAX;
        }

        int requestedImportance = IMPORTANCE_DEFAULT;
        n.priority = NotificationManagerService.clamp(n.priority, Notification.PRIORITY_MIN,
                Notification.PRIORITY_MAX);
        //转化通知里的priority为和channel里一样的重要性
        switch (n.priority) {
            case Notification.PRIORITY_MIN:
                requestedImportance = IMPORTANCE_MIN;
                break;
            case Notification.PRIORITY_LOW:
                requestedImportance = IMPORTANCE_LOW;
                break;
            case Notification.PRIORITY_DEFAULT:
                requestedImportance = IMPORTANCE_DEFAULT;
                break;
            case Notification.PRIORITY_HIGH:
            case Notification.PRIORITY_MAX:
                requestedImportance = IMPORTANCE_HIGH;
                break;
        }
        stats.requestedImportance = requestedImportance;
        stats.isNoisy = mSound != null || mVibration != null;

        //..

        stats.naturalImportance = importance;
        return importance;
    }

>5.calculateLights

    private Light calculateLights() {
        //获取默认的灯光颜色以及开关时间
        int defaultLightColor = mContext.getResources().getColor(
                com.android.internal.R.color.config_defaultNotificationColor);
        int defaultLightOn = mContext.getResources().getInteger(
                com.android.internal.R.integer.config_defaultNotificationLedOn);
        int defaultLightOff = mContext.getResources().getInteger(
                com.android.internal.R.integer.config_defaultNotificationLedOff);

        int channelLightColor = getChannel().getLightColor() != 0 ? getChannel().getLightColor()
                : defaultLightColor;
        //enableShowLights的话才创建light对象
        Light light = getChannel().shouldShowLights() ? new Light(channelLightColor,
                defaultLightOn, defaultLightOff) : null;
    //.
        return light;
    }

5.2.getKey

    public String getKey() { return getSbn().getKey(); }//6.1.1

6.StatusBarNotification

  • 主要学习下key和groupKey的获取,这个是区分通知的标志

6.1.构造方法

    public StatusBarNotification(String pkg, String opPkg, int id,
            String tag, int uid, int initialPid, Notification notification, UserHandle user,
            String overrideGroupKey, long postTime) {
        if (pkg == null) throw new NullPointerException();
        if (notification == null) throw new NullPointerException();

        this.pkg = pkg;
        this.opPkg = opPkg;
        this.id = id;
        this.tag = tag;
        this.uid = uid;
        this.initialPid = initialPid;
        this.notification = notification;
        this.user = user;
        this.postTime = postTime;
        this.overrideGroupKey = overrideGroupKey;
        this.key = key();//补充1
        this.groupKey = groupKey();//补充2
    }

>1.key

  • 可以看到key是一堆唯一的表示组合到一起的字符串
    private String key() {
        String sbnKey = user.getIdentifier() + "|" + pkg + "|" + id + "|" + tag + "|" + uid;
        if (overrideGroupKey != null && getNotification().isGroupSummary()) {
            sbnKey = sbnKey + "|" + overrideGroupKey;
        }
        return sbnKey;
    }

>2.groupKey

    private String groupKey() {
        if (overrideGroupKey != null) {
            return user.getIdentifier() + "|" + pkg + "|" + "g:" + overrideGroupKey;
        }
        final String group = getNotification().getGroup();
        final String sortKey = getNotification().getSortKey();
        //这两个默认是空的,除非你手动设置
        if (group == null && sortKey == null) {
            // 所以默认情况下用的这个
            return key;
        }
        //默认情况下,groupKey 和user,pkg以及channelId有关。
        return user.getIdentifier() + "|" + pkg + "|" +
                (group == null
                        ? "c:" + notification.getChannelId()
                        : "g:" + group);
    }

7.LightsService.java

7.1.LightImpl

    private final class LightImpl extends LogicalLight {

>1.setFlashing

        public void setFlashing(int color, int mode, int onMS, int offMS) {
            synchronized (this) {
            //见补充3
                setLightLocked(color, mode, onMS, offMS, BRIGHTNESS_MODE_USER);
            }
        }

>2.turnOff

        public void turnOff() {
            synchronized (this) {
                setLightLocked(0, LIGHT_FLASH_NONE, 0, 0, 0);
            }
        }

>3.setLightLocked

        private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) {
            if (shouldBeInLowPersistenceMode()) {//vr有关的,为false
                brightnessMode = BRIGHTNESS_MODE_LOW_PERSISTENCE;
            } else if (brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) {
                brightnessMode = mLastBrightnessMode;
            }
            //以下任何一种发生变化,都重新设置light
            if (!mInitialized || color != mColor || mode != mMode || onMS != mOnMS ||
                    offMS != mOffMS || mBrightnessMode != brightnessMode) {
                mInitialized = true;
                mLastColor = mColor;
                mColor = color;
                mMode = mode;
                mOnMS = onMS;
                mOffMS = offMS;
                mBrightnessMode = brightnessMode;
                setLightUnchecked(color, mode, onMS, offMS, brightnessMode);
            }
        }

>4.pulse

脉冲闪灯,这里用的是硬件,默认的闪白光,才7毫秒就被stop了。。

        public void pulse() {
            pulse(0x00ffffff, 7);
        }

        @Override
        public void pulse(int color, int onMS) {
            synchronized (this) {
                if (mColor == 0 && !mFlashing) {
                    setLightLocked(color, LIGHT_FLASH_HARDWARE, onMS, 1000,
                            BRIGHTNESS_MODE_USER);
                    mColor = 0;
                    mH.postDelayed(this::stopFlashing, onMS);
                }
            }
        }
        private void stopFlashing() {
            synchronized (this) {
                setLightLocked(mColor, LIGHT_FLASH_NONE, 0, 0, BRIGHTNESS_MODE_USER);
            }
        }

8.NotificationChannel.java

8.1.创建

  • 下边是自己写的demo
  • 构造方法3个参数,唯一个id,名字,以及重要性
  • 以前没有channel的时候,通知的灯光震动灯都是自己设置的,现在方法都过期了,需要在channel里设置
private fun createChannel(groupID: String?,
                          groupName: String?,
                          channelID: String,
                          channelName: String,
                          channelDes: String) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        //channelId要唯一
        val adChannel = NotificationChannel(channelID, channelName, NotificationManager.IMPORTANCE_DEFAULT).apply {

            //补充channel的含义(可选)
            description = channelDes
            //默认是true,在app的logo右上角有个圆点,而且长按logo还能看到最新一条通知
            setShowBadge(true)
            //灯光
            enableLights(true)
            //led灯的颜色设置
            lightColor = Color.RED
            //震动
            enableVibration(false)
        }

        //将渠道添加进组(先创建组才能添加)
        groupID?.apply {
            //分组(可选)
            notificationManager.createNotificationChannelGroup(NotificationChannelGroup(this, groupName))
            adChannel.group = groupID
        }
        //创建channel
        notificationManager.createNotificationChannel(adChannel)

}

8.2.Notification.java

>1.创建

  • 正常都是通过Builder创建的
    private fun createNotificationWithChannel(channelID: String, title: String, content: String, id: Int) {
        var builder: Notification.Builder = Notification.Builder(this)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            //创建通知时,标记你的渠道id
            builder = Notification.Builder(this, channelID)
//            builder.setTimeoutAfter(1 * 60 * 1000)//1分钟后自动消失
        }
        val notification = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            builder.setSmallIcon(R.drawable.ic_lock).setLargeIcon(Icon.createWithResource(this, R.drawable.my_alram))
                .setContentTitle("This is $title")
                .setContentText("content:$content")

                .setAutoCancel(false).build()
        } 
        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.notify(id, notification)

    }

>2.setGroup

        .setGroup(group)
        .setGroupSummary(true)
  • 没有设置group的时候,一个应用里发出的通知会会在一个群组里,如下图 image.png
  • 设置了group以后,不同group显示在不同的群组里,同样的group一次只能看到一个,新的删除才能看到旧的。如下图

image.png

9.NotificationListeners

  • 小节4 NMS的内部类
   public class NotificationListeners extends ManagedServices {

9.1.getConfig

          protected Config getConfig() {
            Config c = new Config();
            c.caption = "notification listener";
            c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
            c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS;
            c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
            c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
            c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
            c.clientLabel = R.string.notification_listener_binding_label;
            return c;
        }

9.2.onServiceAdded

        public void onServiceAdded(ManagedServiceInfo info) {
            final INotificationListener listener = (INotificationListener) info.service;
            final NotificationRankingUpdate update;
            synchronized (mNotificationLock) {
                update = makeRankingUpdateLocked(info);
                updateUriPermissionsForActiveNotificationsLocked(info, true);
            }
            try {
                listener.onListenerConnected(update);
            } 
        }

9.3.getBindFlags

        protected int getBindFlags() {
            return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE
                    | BIND_NOT_PERCEPTIBLE | BIND_ALLOW_WHITELIST_MANAGEMENT;
        }

9.4.getRequiredPermission

        protected String getRequiredPermission() {
            return null;
        }

9.5.loadDefaultsFromConfig

        protected void loadDefaultsFromConfig() {
            String defaultListenerAccess = mContext.getResources().getString(
                    R.string.config_defaultListenerAccessPackages);
            if (defaultListenerAccess != null) {
                String[] listeners =
                        defaultListenerAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR);
                for (int i = 0; i < listeners.length; i++) {
                    if (TextUtils.isEmpty(listeners[i])) {
                        continue;
                    }
                    int packageQueryFlags = MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;

                    if (mIsHeadlessSystemUserMode) {
                        packageQueryFlags += MATCH_ANY_USER;
                    }
                    ArraySet<ComponentName> approvedListeners =
                            this.queryPackageForServices(listeners[i], packageQueryFlags,
                                    USER_SYSTEM);
                    for (int k = 0; k < approvedListeners.size(); k++) {
                        ComponentName cn = approvedListeners.valueAt(k);
                        //见11.9加入默认包或者组件集合里
                        addDefaultComponentOrPackage(cn.flattenToString());
                    }
                }
            }
        }

>1.config_defaultListenerAccessPackages

AOSP里是空的,GMS里有配置

<string name="config_defaultListenerAccessPackages" translatable="false">com.android.launcher3:com.google.android.projection.gearhead</string>

10.NotificationAssistants

  • 小节4 NMS的内部类
    public class NotificationAssistants extends ManagedServices {

10.1.onUserUnlocked

        @Override
        public void onUserUnlocked(int user) {
            rebindServices(true, user);
        }

10.2.getConfig()

        protected Config getConfig() {
            Config c = new Config();
            c.caption = "notification assistant";
            c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
            c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
            c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
            c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
            c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
            c.clientLabel = R.string.notification_ranker_binding_label;
            return c;
        }

10.3.onServiceAdded

  • mListeners就是小节9的实例
        protected void onServiceAdded(ManagedServiceInfo info) {
        //父类小节11里实现的,
            mListeners.registerGuestService(info);
        }

10.4.getRequiredPermission

        protected String getRequiredPermission() {
            // only signature/privileged apps can be bound.
            return android.Manifest.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE;
        }

10.5.loadDefaultsFromConfig

        protected void loadDefaultsFromConfig() {
            loadDefaultsFromConfig(true);
        }

        protected void loadDefaultsFromConfig(boolean addToDefault) {
            ArraySet<String> assistants = new ArraySet<>();
            assistants.addAll(Arrays.asList(mContext.getResources().getString(
                    com.android.internal.R.string.config_defaultAssistantAccessComponent)
                    .split(ManagedServices.ENABLED_SERVICES_SEPARATOR)));
            for (int i = 0; i < assistants.size(); i++) {
                ComponentName assistantCn = ComponentName
                        .unflattenFromString(assistants.valueAt(i));
                String packageName = assistants.valueAt(i);
                if (assistantCn != null) {
                    packageName = assistantCn.getPackageName();
                }
                if (TextUtils.isEmpty(packageName)) {
                    continue;
                }
                ArraySet<ComponentName> approved = queryPackageForServices(packageName,
                        MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, USER_SYSTEM);
                if (approved.contains(assistantCn)) {
                    if (addToDefault) {
                        //见11.9
                        addDefaultComponentOrPackage(assistantCn.flattenToString());
                    } else {
                        // otherwise, store in the mDefaultFromConfig for NAS settings migration
                        mDefaultFromConfig = assistantCn;
                    }
                }
            }
        }

>1.config_defaultAssistantAccessComponent

GMS覆写的

<string name="config_defaultAssistantAccessComponent" translatable="false">com.google.android.ext.services/android.ext.services.notification.Assistant</string>

默认的

<string name="config_defaultAssistantAccessComponent" translatable="false">android.ext.services/android.ext.services.notification.Assistant</string>

11.ManagedServices.java

11.1.rebindServices

  • 当用户改变(切换,添加,删除等),或者包改变(新加,删除,状态变化等),或者安全设置改变等都会调用这个
    protected void rebindServices(boolean forceRebind, int userToRebind) {
        //先获取所有用户id
        IntArray userIds = mUserProfiles.getCurrentProfileIds();
        //如果指定要rebind的用户id不是ALL
        if (userToRebind != USER_ALL) {
            //那么就使用这个指定的用户id
            userIds = new IntArray(1);
            userIds.add(userToRebind);
        }
        //要绑定的组件集合
        final SparseArray<Set<ComponentName>> componentsToBind = new SparseArray<>();
        //要解除绑定的组件集合
        final SparseArray<Set<ComponentName>> componentsToUnbind = new SparseArray<>();

        synchronized (mMutex) {
            //见补充1,获取可用的组件
            final SparseArray<ArraySet<ComponentName>> approvedComponentsByUser =
                    getAllowedComponents(userIds);
            //获取可移除的服务信息
            final Set<ManagedServiceInfo> removableBoundServices = getRemovableConnectedServices();

            //见补充2过滤下冻结的数据
            populateComponentsToBind(componentsToBind, userIds, approvedComponentsByUser);

            //见补充3
            populateComponentsToUnbind(
                    forceRebind, removableBoundServices, componentsToBind, componentsToUnbind);
        }

        unbindFromServices(componentsToUnbind);
        bindToServices(componentsToBind);
    }

>1.getAllowedComponents

    protected SparseArray<ArraySet<ComponentName>> getAllowedComponents(IntArray userIds) {
        final int nUserIds = userIds.size();
        final SparseArray<ArraySet<ComponentName>> componentsByUser = new SparseArray<>();

        for (int i = 0; i < nUserIds; ++i) {
            final int userId = userIds.get(i);
            synchronized (mApproved) {
            //可以看到数据是从map里读取的,后边查看mApproved数据来源
                final ArrayMap<Boolean, ArraySet<String>> approvedLists = mApproved.get(userId);
                if (approvedLists != null) {
                    final int N = approvedLists.size();
                    for (int j = 0; j < N; j++) {
                        ArraySet<ComponentName> approvedByUser = componentsByUser.get(userId);
                        if (approvedByUser == null) {
                            approvedByUser = new ArraySet<>();
                            componentsByUser.put(userId, approvedByUser);
                        }
                        approvedByUser.addAll(
                                loadComponentNamesFromValues(approvedLists.valueAt(j), userId));
                    }
                }
            }
        }
        return componentsByUser;
    }

>2.populateComponentsToBind

数据过滤下

    protected void populateComponentsToBind(SparseArray<Set<ComponentName>> componentsToBind,
            final IntArray activeUsers,
            SparseArray<ArraySet<ComponentName>> approvedComponentsByUser) {
        mEnabledServicesForCurrentProfiles.clear();
        mEnabledServicesPackageNames.clear();
        final int nUserIds = activeUsers.size();

        for (int i = 0; i < nUserIds; ++i) {
            // decode the list of components
            final int userId = activeUsers.get(i);
            final ArraySet<ComponentName> userComponents = approvedComponentsByUser.get(userId);
            if (null == userComponents) {
                componentsToBind.put(userId, new ArraySet<>());
                continue;
            }

            final Set<ComponentName> add = new HashSet<>(userComponents);
            //移除了冻结的数据
            add.removeAll(mSnoozingForCurrentProfiles);
            //最终的数据就是移除后的
            componentsToBind.put(userId, add);
            //这里记录的是可用的组件
            mEnabledServicesForCurrentProfiles.addAll(userComponents);

            for (int j = 0; j < userComponents.size(); j++) {
                final ComponentName component = userComponents.valueAt(j);
                //可用的包名
                mEnabledServicesPackageNames.add(component.getPackageName());
            }
        }
    }

>3.populateComponentsToUnbind

    protected void populateComponentsToUnbind(
            boolean forceRebind,
            Set<ManagedServiceInfo> removableBoundServices,
            SparseArray<Set<ComponentName>> allowedComponentsToBind,
            SparseArray<Set<ComponentName>> componentsToUnbind) {
        //循环所有可移除的info
        for (ManagedServiceInfo info : removableBoundServices) {
            //获取允许绑定的组件
            final Set<ComponentName> allowedComponents = allowedComponentsToBind.get(info.userid);
            if (allowedComponents != null) {
                //强制重新绑定,或者 不在允许绑定的集合里
                if (forceRebind || !allowedComponents.contains(info.component)) {
                    //那就放入要unbind的集合里
                    Set<ComponentName> toUnbind =
                            componentsToUnbind.get(info.userid, new ArraySet<>());
                    toUnbind.add(info.component);
                    componentsToUnbind.put(info.userid, toUnbind);
                }
            }
        }
    }

11.2.bindToServices

    private void bindToServices(SparseArray<Set<ComponentName>> componentsToBind) {
        for (int i = 0; i < componentsToBind.size(); i++) {
            final int userId = componentsToBind.keyAt(i);
            final Set<ComponentName> add = componentsToBind.get(userId);
            for (ComponentName component : add) {
                try {
                //根据组件信息获取服务信息
                    ServiceInfo info = mPm.getServiceInfo(component,
                            PackageManager.GET_META_DATA
                                    | PackageManager.MATCH_DIRECT_BOOT_AWARE
                                    | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
                            userId);
                    if (info == null) {
                        continue;
                    }
                    if (!mConfig.bindPermission.equals(info.permission)) {
                        //权限不满足
                        continue;
                    }

                    registerService(info, userId);
                }
            }
        }

>1.registerService

    void registerService(final ServiceInfo si, final int userId) {
        ensureFilters(si, userId);
        registerService(si.getComponentName(), userId);
    }

    void registerService(final ComponentName cn, final int userId) {
        synchronized (mMutex) {
            registerServiceLocked(cn, userId);
        }
    }

    void reregisterService(final ComponentName cn, final int userId) {
        //先判断下组件或者包是否可用,万一被disable了
        if (isPackageOrComponentAllowed(cn.getPackageName(), userId)
                || isPackageOrComponentAllowed(cn.flattenToString(), userId)) {
            registerService(cn, userId);
        }
    }

    void registerService(final ComponentName cn, final int userId) {
        synchronized (mMutex) {
            registerServiceLocked(cn, userId);
        }
    }

    private void registerServiceLocked(final ComponentName name, final int userid) {
    //补充2
        registerServiceLocked(name, userid, false /* isSystem */);
    }

>2.registerServiceLocked

    private void registerServiceLocked(final ComponentName name, final int userid,
            final boolean isSystem) {
   
        final Pair<ComponentName, Integer> servicesBindingTag = Pair.create(name, userid);
        if (mServicesBound.contains(servicesBindingTag)) {
            //已经注册了
            return;
        }
        //新注册的,加入集合
        mServicesBound.add(servicesBindingTag);

        final int N = mServices.size();
        for (int i = N - 1; i >= 0; i--) {
            final ManagedServiceInfo info = mServices.get(i);
            if (name.equals(info.component)
                && info.userid == userid) {
                //有旧的,先断开
                removeServiceLocked(i);
                if (info.connection != null) {
                    unbindService(info.connection, info.component, info.userid);
                }
            }
        }
        //具体的action见9.1和10.2
        Intent intent = new Intent(mConfig.serviceInterface);
        intent.setComponent(name);

        intent.putExtra(Intent.EXTRA_CLIENT_LABEL, mConfig.clientLabel);

        final PendingIntent pendingIntent = PendingIntent.getActivity(
            mContext, 0, new Intent(mConfig.settingsAction), PendingIntent.FLAG_IMMUTABLE);
        intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);

        ApplicationInfo appInfo = null;
        try {
            appInfo = mContext.getPackageManager().getApplicationInfo(
                name.getPackageName(), 0);
        } catch (NameNotFoundException e) {
            // Ignore if the package doesn't exist we won't be able to bind to the service.
        }
        final int targetSdkVersion =
            appInfo != null ? appInfo.targetSdkVersion : Build.VERSION_CODES.BASE;
        final int uid = appInfo != null ? appInfo.uid : -1;

        try {
           //下边就是绑定服务的回调了
            ServiceConnection serviceConnection = new ServiceConnection() {
                IInterface mService;

                @Override
                public void onServiceConnected(ComponentName name, IBinder binder) {
                    boolean added = false;
                    ManagedServiceInfo info = null;
                    synchronized (mMutex) {
                        mServicesRebinding.remove(servicesBindingTag);
                        try {
                            mService = asInterface(binder);
                            //绑定成功以后封装一个info
                            info = newServiceInfo(mService, name,
                                userid, isSystem, this, targetSdkVersion, uid);
                            binder.linkToDeath(info, 0);
                            //加入集合
                            added = mServices.add(info);
                        }
                    }
                    if (added) {
                    //新加的服务
                        onServiceAdded(info);
                    }
                }

                @Override
                public void onServiceDisconnected(ComponentName name) {
                }

                @Override
                public void onBindingDied(ComponentName name) {
                    synchronized (mMutex) {
                        unbindService(this, name, userid);
                        if (!mServicesRebinding.contains(servicesBindingTag)) {
                            mServicesRebinding.add(servicesBindingTag);
                            mHandler.postDelayed(() ->
                                    reregisterService(name, userid),
                                    ON_BINDING_DIED_REBIND_DELAY_MS);
                        } 
                    }
                }

                @Override
                public void onNullBinding(ComponentName name) {
                    mContext.unbindService(this);
                }
            };
            //开始绑定服务
            if (!mContext.bindServiceAsUser(intent,
                    serviceConnection,
                    getBindFlags(),
                    new UserHandle(userid))) {
                mServicesBound.remove(servicesBindingTag);
                return;
            }
        } catch (SecurityException ex) {
            mServicesBound.remove(servicesBindingTag);
        }
    }

子类可以重写,见9.3

    protected int getBindFlags() {
        return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE | BIND_ALLOW_WHITELIST_MANAGEMENT;
    }

11.3.记录下开机后rebindService

看下都哪里调用了11.1的方法

>1.onStart

//见11.7.1末尾
at com.android.server.notification.ManagedServices.rebindServices(ManagedServices.java:1361)
//见4.10
at com.android.server.notification.ManagedServices.readXml(ManagedServices.java:700)
at com.android.server.notification.NotificationManagerService.readPolicyXml(NotificationManagerService.java:971)
at com.android.server.notification.NotificationManagerService.loadPolicyFile(NotificationManagerService.java:1015)
at com.android.server.notification.NotificationManagerService.init(NotificationManagerService.java:2343)
at com.android.server.notification.NotificationManagerService.onStart(NotificationManagerService.java:2512)
at com.android.server.SystemServiceManager.startService(SystemServiceManager.java:258)
at com.android.server.SystemServiceManager.startService(SystemServiceManager.java:236)
at com.android.server.SystemServer.startOtherServices(SystemServer.java:2062)
at com.android.server.SystemServer.run(SystemServer.java:941)

>2.resetDefaultAssistantsIfNecessary

at com.android.server.notification.ManagedServices.rebindServices(ManagedServices.java:1361)
at com.android.server.notification.ManagedServices.setPackageOrComponentEnabled(ManagedServices.java:831)
at com.android.server.notification.ManagedServices.setPackageOrComponentEnabled(ManagedServices.java:791)
at com.android.server.notification.NotificationManagerService.setNotificationAssistantAccessGrantedForUserInternal(NotificationManagerService.java:5809)
at com.android.server.notification.NotificationManagerService.allowAssistant(NotificationManagerService.java:940)
at com.android.server.notification.NotificationManagerService.setDefaultAssistantForUser(NotificationManagerService.java:875)
at com.android.server.notification.NotificationManagerService$NotificationAssistants.resetDefaultAssistantsIfNecessary(NotificationManagerService.java:10671)
at com.android.server.notification.NotificationManagerService.readPolicyXml(NotificationManagerService.java:1005)
at com.android.server.notification.NotificationManagerService.loadPolicyFile(NotificationManagerService.java:1015)
at com.android.server.notification.NotificationManagerService.init(NotificationManagerService.java:2343)
at com.android.server.notification.NotificationManagerService.onStart(NotificationManagerService.java:2512)

>3.onUserSwitched

at com.android.server.notification.ManagedServices.rebindServices(ManagedServices.java:1361)
at com.android.server.notification.ManagedServices.onUserSwitched(ManagedServices.java:984)
at com.android.server.notification.NotificationManagerService$6.onReceive(NotificationManagerService.java:1838)

>4.onUserUnlocked

at com.android.server.notification.ManagedServices.rebindServices(ManagedServices.java:1361)
at com.android.server.notification.NotificationManagerService$NotificationAssistants.onUserUnlocked(NotificationManagerService.java:10276)
at com.android.server.notification.NotificationManagerService$6.onReceive(NotificationManagerService.java:1864)

11.4日志相关的代码

NotificationManagerService.java

>1.readPolicyXml

参考11.3.1日志

    void readPolicyXml(InputStream stream, boolean forRestore, int userId)
    //...
            if (mListeners.getConfig().xmlTag.equals(parser.getName())) {
                if (ineligibleForManagedServices) {
                    continue;
                }
                //这个是小节9实例
                mListeners.readXml(parser, mAllowedManagedServicePackages, forRestore, userId);
                migratedManagedServices = true;
            } else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) {
                if (ineligibleForManagedServices) {
                    continue;
                }
                //这个是小节10实例
                mAssistants.readXml(parser, mAllowedManagedServicePackages, forRestore, userId);
                migratedManagedServices = true;
                migratedManagedServices = true;
            } else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) {
                if (ineligibleForManagedServices) {
                    continue;
                }
                //这个的log也是11.3.1
                mConditionProviders.readXml(
                        parser, mAllowedManagedServicePackages, forRestore, userId);
                migratedManagedServices = true;
            }
//...
        //log见11.3.2
        mAssistants.resetDefaultAssistantsIfNecessary();
    }

文件路径 /data/system/notification_policy.xml

                new AtomicFile(new File(
                        systemDir, "notification_policy.xml"), "notification-policy"),

>2.ACTION_USER_SWITCHED

具体实现见11.5

            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
                final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
                mUserProfiles.updateCache(context);
                //非配置用户,默认启动会走这里的
                if (!mUserProfiles.isProfileUser(userId)) {
                    // reload per-user settings
                    mSettingsObserver.update(null);
                    //这里两处调用,log见11.3.3
                    mConditionProviders.onUserSwitched(userId);
                    mListeners.onUserSwitched(userId);
                    mZenModeHelper.onUserSwitched(userId);
                }
                //这里也调用,log见11.3.3
                mAssistants.onUserSwitched(userId);
            }

>3.ACTION_USER_UNLOCKED

            } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
                final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
                mUserProfiles.updateCache(context);
                //log见11.3.4,方法见11.6
                mAssistants.onUserUnlocked(userId);
                if (!mUserProfiles.isProfileUser(userId)) {
                    mConditionProviders.onUserUnlocked(userId);
                    mListeners.onUserUnlocked(userId);
                    mZenModeHelper.onUserUnlocked(userId);
                }
            }

11.5.onUserSwitched

    public void onUserSwitched(int user) {
        unbindOtherUserServices(user);
        rebindServices(true, user);
    }

11.6.onUserUnlocked

    public void onUserUnlocked(int user) {
        rebindServices(false, user);
    }

11.7.addApprovedList

  • mApproved数据就是这里添加的,允许绑定为managed services的集合,第一层key是user,第二层key是true或者false也就是是否是isPrimary
  • mUserSetServices用户显示的配置为可用或不可用的包或者组件集合
    protected ArrayMap<Integer, ArrayMap<Boolean, ArraySet<String>>> mApproved = new ArrayMap<>();

    protected ArrayMap<Integer, ArraySet<String>> mUserSetServices = new ArrayMap<>();
    protected void addApprovedList(String approved, int userId, boolean isPrimary) {
        addApprovedList(approved, userId, isPrimary, approved);
    }

    protected void addApprovedList(String approved, int userId, boolean isPrimary, String userSet) {
        if (TextUtils.isEmpty(approved)) {
            approved = "";
        }
        if (userSet == null) {
            userSet = approved;
        }
        synchronized (mApproved) {
            ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
            if (approvedByType == null) {
                approvedByType = new ArrayMap<>();
                mApproved.put(userId, approvedByType);
            }

            ArraySet<String> approvedList = approvedByType.get(isPrimary);
            if (approvedList == null) {
                approvedList = new ArraySet<>();
                approvedByType.put(isPrimary, approvedList);
            }
            //数据用冒号分组
            String[] approvedArray = approved.split(ENABLED_SERVICES_SEPARATOR);
            for (String pkgOrComponent : approvedArray) {
                String approvedItem = getApprovedValue(pkgOrComponent);
                if (approvedItem != null) {
                //是个有效的组件名,加入集合
                    approvedList.add(approvedItem);
                }
            }

            ArraySet<String> userSetList = mUserSetServices.get(userId);
            if (userSetList == null) {
                userSetList = new ArraySet<>();
                mUserSetServices.put(userId, userSetList);
            }
            //冒号分组
            String[] userSetArray = userSet.split(ENABLED_SERVICES_SEPARATOR);
            for (String pkgOrComponent : userSetArray) {
                String approvedItem = getApprovedValue(pkgOrComponent);
                if (approvedItem != null) {
                    userSetList.add(approvedItem);
                }
            }
        }
    }

下边贴下数据的来源

>1.readXml

读取配置里的数据

  • 配置里的数据也是写入的,存的就是approved里的数据,那首次开机这数据哪里来的啊?
  • 参考4.9,首次加载数据,文件不存在,就会读取默认的配置,完事保存文件。
    public void readXml(
    //..
            if (type == XmlPullParser.START_TAG) {
                if (TAG_MANAGED_SERVICES.equals(tag)) {//"service_listing"
                //先读取配置里的数据
                    final String approved = XmlUtils.readStringAttribute(parser, ATT_APPROVED_LIST);//"approved"
    //...

    //test方法见4.7,权限见9.4以及10.4
                    if (allowedManagedServicePackages == null || allowedManagedServicePackages.test(
                            getPackageName(approved), resolvedUserId, getRequiredPermission())
                            || approved.isEmpty()) {
                        if (mUm.getUserInfo(resolvedUserId) != null) {
                        //添加数据
                            addApprovedList(approved, resolvedUserId, isPrimary, userSetComponent);
                        }
                        mUseXml = true;
                    }

    //... 见11.1 重新绑定服务,不强制
        rebindServices(false, USER_ALL);
    }

11.8.setPackageOrComponentEnabled

添加或者删除mApproved里的数据

    protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId,
            boolean isPrimary, boolean enabled, boolean userSet) {
        synchronized (mApproved) {
            ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.get(userId);
            if (allowedByType == null) {
                allowedByType = new ArrayMap<>();
                mApproved.put(userId, allowedByType);
            }
            ArraySet<String> approved = allowedByType.get(isPrimary);
            if (approved == null) {
                approved = new ArraySet<>();
                allowedByType.put(isPrimary, approved);
            }
            String approvedItem = getApprovedValue(pkgOrComponent);

            if (approvedItem != null) {
                if (enabled) {
                    approved.add(approvedItem);
                } else {
                    approved.remove(approvedItem);
                }
            }
            ArraySet<String> userSetServices = mUserSetServices.get(userId);
            if (userSetServices == null) {
                userSetServices = new ArraySet<>();
                mUserSetServices.put(userId, userSetServices);
            }
            if (userSet) {
                userSetServices.add(pkgOrComponent);
            } else {
                userSetServices.remove(pkgOrComponent);
            }
        }

        rebindServices(false, userId);
    }            

11.9.addDefaultComponentOrPackage

    protected void addDefaultComponentOrPackage(String packageOrComponent) {
        if (!TextUtils.isEmpty(packageOrComponent)) {
            synchronized (mDefaultsLock) {
                if (mApprovalLevel == APPROVAL_BY_PACKAGE) {
                    mDefaultPackages.add(packageOrComponent);
                    return;
                }
                ComponentName cn = ComponentName.unflattenFromString(packageOrComponent);
                if (cn != null  && mApprovalLevel == APPROVAL_BY_COMPONENT) {
                    mDefaultPackages.add(cn.getPackageName());
                    mDefaultComponents.add(cn);
                    return;
                }
            }
        }
    }

12.总结

  • 普通通知发送的流程比较简单,见2.1再到4.1,之后就是4.2和4.3
  • 小节5到7,主要学习了通知相关的震动声音灯设置以及判定
  • 另外学习下通知改变的监听服务NotificationListenerService如何默认启动,这是个抽象类,其他地方会继承这个类,主要是launcher里有用到这个,没看到服务咋启动的,这里学下。
  • 4.9里首次读取配置的时候,会加载默认值,见4.9.1以及4.9.2,里边有分析走到2.3再走到11.8,数据加入了approved集合里。后续都是从配置文件里读取的。
  • 11.3以及11.4里分析了rebind方法的调用,这个方法就是读取approved里的组件,进行bindService启动对应的服务。