zoukankan      html  css  js  c++  java
  • NotificationMangerService处理显示通知

    设置——>应用——>点击“已下载”列表中的任一APP,如图:

     代码位置:SettingssrccomandroidsettingsapplicationsInstalledAppDetails.java

     1 //CheckBox显示通知处理
     2 private void setNotificationsEnabled(boolean enabled) {
     3         String packageName = mAppEntry.info.packageName;
     4         INotificationManager nm = INotificationManager.Stub.asInterface(
     5                 ServiceManager.getService(Context.NOTIFICATION_SERVICE));
     6         try {
     7             final boolean enable = mNotificationSwitch.isChecked();
     8             
     9             nm.setNotificationsEnabledForPackage(packageName, mAppEntry.info.uid, enabled);
    10         } catch (android.os.RemoteException ex) {
    11             mNotificationSwitch.setChecked(!enabled); // revert
    12         }
    13     }
    INotificationManager 是通过AIDL处理,在java层就是NotificationMangerService处理。
    androidframeworksaseservicesjavacomandroidserverNotificationManagerService.java
     1 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
     2         checkCallerIsSystem();//这里校验Uid检查调用程序有没有权限
     3 
     4         Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
     5 
     6         mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
     7                 enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
     8 
     9         // Now, cancel any outstanding notifications that are part of a just-disabled app
    10         if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
    11             cancelAllNotificationsInt(pkg, 0, 0, true, UserHandle.getUserId(uid));
    12         }
    13     }
    校验Uid检查调用程序有没有权限,了解sharedUserId可以参考http://www.cnblogs.com/Ashia/articles/2474321.html
     1 void checkCallerIsSystem() {
     2         if (isCallerSystem()) {
     3             return;
     4         }
     5         throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
     6     }
     7 
     8 boolean isCallerSystem() {
     9         return isUidSystem(Binder.getCallingUid());
    10     }
    11 
    12 // Return true if the UID is a system or phone UID and therefore should not have
    13     // any notifications or toasts blocked.
    14     boolean isUidSystem(int uid) {
    15         Slog.v(TAG, "isUidSystem , uid = " + uid);
    16         final int appid = UserHandle.getAppId(uid);
    17         return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
    18     }
    View Code

    以上处理中mAppOps将需要处理的pkg做了标记,表示是否显示pkg发出的Notification

    Notification的显示过程也是NotificationMangerService处理,在enqueueNotificationInternal(......)中处理,这里会判断pkg是否可以显示通知。

      1 // Not exposed via Binder; for system use only (otherwise malicious apps could spoof the
      2     // uid/pid of another application)
      3 
      4     public void enqueueNotificationInternal(final String pkg, String basePkg, final int callingUid,
      5             final int callingPid, final String tag, final int id, final Notification notification,
      6             int[] idOut, int incomingUserId)
      7     {
      8         if (DBG) {
      9             Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id + " notification=" + notification);
     10         }
     11         checkCallerIsSystemOrSameApp(pkg);
     12         final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg));//再次校验Uid
     13 
     14         final int userId = ActivityManager.handleIncomingUser(callingPid,
     15                 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
     16         final UserHandle user = new UserHandle(userId);
     17 
     18         // Limit the number of notifications that any given package except the android
     19         // package can enqueue.  Prevents DOS attacks and deals with leaks.
     20         if (!isSystemNotification) {
     21             synchronized (mNotificationList) {
     22                 int count = 0;
     23                 final int N = mNotificationList.size();
     24                 for (int i=0; i<N; i++) {
     25                     final NotificationRecord r = mNotificationList.get(i);
     26                     if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) {
     27                         count++;
     28                         if (count >= MAX_PACKAGE_NOTIFICATIONS) {//判断允许的最大通知数
     29                             Slog.e(TAG, "Package has already posted " + count
     30                                     + " notifications.  Not showing more.  package=" + pkg);
     31                             return;
     32                         }
     33                     }
     34                 }
     35             }
     36         }
     37 
     38         // This conditional is a dirty hack to limit the logging done on
     39         //     behalf of the download manager without affecting other apps.
     40         if (!pkg.equals("com.android.providers.downloads")
     41                 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
     42             EventLog.writeEvent(EventLogTags.NOTIFICATION_ENQUEUE, pkg, id, tag, userId,
     43                     notification.toString());
     44         }
     45 
     46         if (pkg == null || notification == null) {
     47             throw new IllegalArgumentException("null not allowed: pkg=" + pkg
     48                     + " id=" + id + " notification=" + notification);
     49         }
     50         if (notification.icon != 0) {
     51             if (notification.contentView == null) {
     52                 throw new IllegalArgumentException("contentView required: pkg=" + pkg
     53                         + " id=" + id + " notification=" + notification);
     54             }
     55         }
     56 
     57         mHandler.post(new Runnable() {
     58             @Override
     59             public void run() {
     60 
     61                 // === Scoring ===
     62 
     63                 // 0. Sanitize inputs
     64                 notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN,
     65                         Notification.PRIORITY_MAX);
     66                 // Migrate notification flags to scores
     67                 if (0 != (notification.flags & Notification.FLAG_HIGH_PRIORITY)) {
     68                     if (notification.priority < Notification.PRIORITY_MAX) {
     69                         notification.priority = Notification.PRIORITY_MAX;
     70                     }
     71                 } else if (SCORE_ONGOING_HIGHER &&
     72                         0 != (notification.flags & Notification.FLAG_ONGOING_EVENT)) {
     73                     if (notification.priority < Notification.PRIORITY_HIGH) {
     74                         notification.priority = Notification.PRIORITY_HIGH;
     75                     }
     76                 }
     77 
     78                 // 1. initial score: buckets of 10, around the app
     79                 int score = notification.priority * NOTIFICATION_PRIORITY_MULTIPLIER; //[-20..20]
     80 
     81                 // 2. Consult external heuristics (TBD)
     82 
     83                 // 3. Apply local rules
     84 
     85                 int initialScore = score;
     86                 if (!mScorers.isEmpty()) {
     87                     if (DBG) Slog.v(TAG, "Initial score is " + score + ".");
     88                     for (NotificationScorer scorer : mScorers) {
     89                         try {
     90                             score = scorer.getScore(notification, score);
     91                         } catch (Throwable t) {
     92                             Slog.w(TAG, "Scorer threw on .getScore.", t);
     93                         }
     94                     }
     95                     if (DBG) Slog.v(TAG, "Final score is " + score + ".");
     96                 }
     97 
     98                 // add extra to indicate score modified by NotificationScorer
     99                 notification.extras.putBoolean(Notification.EXTRA_SCORE_MODIFIED,
    100                         score != initialScore);
    101 
    102                 // blocked apps
    103                 if (ENABLE_BLOCKED_NOTIFICATIONS && !noteNotificationOp(pkg, callingUid)) {//判断pkg是否可以显示通知
    104                     if (!isSystemNotification) {//不拦截系统通知
    105                         score = JUNK_SCORE; //在设置中禁止显示通知的pkg,会进到这里,JUNK_SCORE=-1000
    106                         Slog.e(TAG, "Suppressing notification from package " + pkg
    107                                 + " by user request.");
    108                     }
    109                 }
    110 
    111                 if (DBG) {
    112                     Slog.v(TAG, "Assigned score=" + score + " to " + notification);
    113                 }
    114 
    115                 if (score < SCORE_DISPLAY_THRESHOLD) {//进行"显示通知"拦截判断,SCORE_DIAPLAY_THRESHOLD=-20
    116                     // Notification will be blocked because the score is too low.
    117                     return; //完成拦截
    118                 }
    119 
    120                 
    // Should this notification make noise, vibe, or use the LED?
    121                 final boolean canInterrupt = (score >= SCORE_INTERRUPTION_THRESHOLD);
    122 
    123                 synchronized (mNotificationList) {
    124                     final StatusBarNotification n = new StatusBarNotification(
    125                             pkg, id, tag, callingUid, callingPid, score, notification, user);
    126                     NotificationRecord r = new NotificationRecord(n);
    127                     NotificationRecord old = null;
    128 
    129                     int index = indexOfNotificationLocked(pkg, tag, id, userId);
    130                     if (index < 0) {
    131                         mNotificationList.add(r);
    132                     } else {
    133                         old = mNotificationList.remove(index);
    134                         mNotificationList.add(index, r);
    135                         // Make sure we don't lose the foreground service state.
    136                         if (old != null) {
    137                             notification.flags |=
    138                                 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
    139                         }
    140                     }
    141 
    142                     // Ensure if this is a foreground service that the proper additional
    143                     // flags are set.
    144                     if ((notification.flags&Notification.FLAG_FOREGROUND_SERVICE) != 0) {
    145                         notification.flags |= Notification.FLAG_ONGOING_EVENT
    146                                 | Notification.FLAG_NO_CLEAR;
    147                     }
    148 
    149                     final int currentUser;
    150                     final long token = Binder.clearCallingIdentity();
    151                     try {
    152                         currentUser = ActivityManager.getCurrentUser();
    153                     } finally {
    154                         Binder.restoreCallingIdentity(token);
    155                     }
    156 
    157                     if (notification.icon != 0) {
    158                         if (old != null && old.statusBarKey != null) {
    159                             r.statusBarKey = old.statusBarKey;
    160                             long identity = Binder.clearCallingIdentity();
    161                             try {
    162                                 mStatusBar.updateNotification(r.statusBarKey, n);
    163                             }
    164                             finally {
    165                                 Binder.restoreCallingIdentity(identity);
    166                             }
    167                         } else {
    168                             long identity = Binder.clearCallingIdentity();
    169                             try {
    170                                 r.statusBarKey = mStatusBar.addNotification(n);
    171                                 if ((n.getNotification().flags & Notification.FLAG_SHOW_LIGHTS) != 0
    172                                         && canInterrupt) {
    173                                     mAttentionLight.pulse();
    174                                 }
    175                             }
    176                             finally {
    177                                 Binder.restoreCallingIdentity(identity);
    178                             }
    179                         }
    180                         // Send accessibility events only for the current user.
    181                         if (currentUser == userId) {
    182                             sendAccessibilityEvent(notification, pkg);
    183                         }
    184 
    185                         notifyPostedLocked(r);
    186                     } else {
    187                         Slog.e(TAG, "Not posting notification with icon==0: " + notification);
    188                         if (old != null && old.statusBarKey != null) {
    189                             long identity = Binder.clearCallingIdentity();
    190                             try {
    191                                 mStatusBar.removeNotification(old.statusBarKey);
    192                             }
    193                             finally {
    194                                 Binder.restoreCallingIdentity(identity);
    195                             }
    196 
    197                             notifyRemovedLocked(r);
    198                         }
    199                         // ATTENTION: in a future release we will bail out here
    200                         // so that we do not play sounds, show lights, etc. for invalid notifications
    201                         Slog.e(TAG, "WARNING: In a future release this will crash the app: "
    202                                 + n.getPackageName());
    203                     }
    204 
    205                     // Have ring tone when received SMS when the device is CT mode
    206                     boolean smsRingtone = mContext.getResources().getBoolean(
    207                             com.android.internal.R.bool.config_sms_ringtone_incall);
    208 
    209                     // If we're not supposed to beep, vibrate, etc. then don't.
    210                     if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS)
    211                             == 0 || (smsRingtone && mInCall))
    212                             && (!(old != null
    213                                 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
    214                             && (r.getUserId() == UserHandle.USER_ALL ||
    215                                 (r.getUserId() == userId && r.getUserId() == currentUser))
    216                             && canInterrupt
    217                             && mSystemReady) {
    218 
    219                         final AudioManager audioManager = (AudioManager) mContext
    220                         .getSystemService(Context.AUDIO_SERVICE);
    221 
    222                         // sound
    223 
    224                         // should we use the default notification sound? (indicated either by
    225                         // DEFAULT_SOUND or because notification.sound is pointing at
    226                         // Settings.System.NOTIFICATION_SOUND)
    227                         final boolean useDefaultSound =
    228                                (notification.defaults & Notification.DEFAULT_SOUND) != 0 ||
    229                                        Settings.System.DEFAULT_NOTIFICATION_URI
    230                                                .equals(notification.sound);
    231 
    232                         Uri soundUri = null;
    233                         boolean hasValidSound = false;
    234 
    235                         if (useDefaultSound) {
    236                             soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
    237 
    238                             // check to see if the default notification sound is silent
    239                             ContentResolver resolver = mContext.getContentResolver();
    240                             hasValidSound = Settings.System.getString(resolver,
    241                                    Settings.System.NOTIFICATION_SOUND) != null;
    242                         } else if (notification.sound != null) {
    243                             soundUri = notification.sound;
    244                             hasValidSound = (soundUri != null);
    245                         }
    246 
    247                         if (hasValidSound) {
    248                             boolean looping = (notification.flags & Notification.FLAG_INSISTENT) != 0;
    249                             int audioStreamType;
    250                             if (notification.audioStreamType >= 0) {
    251                                 audioStreamType = notification.audioStreamType;
    252                             } else {
    253                                 audioStreamType = DEFAULT_STREAM_TYPE;
    254                             }
    255                             mSoundNotification = r;
    256                             // do not play notifications if stream volume is 0 (typically because
    257                             // ringer mode is silent) or if there is a user of exclusive audio focus
    258                             if ((audioManager.getStreamVolume(audioStreamType) != 0)
    259                                     && !audioManager.isAudioFocusExclusive()) {
    260                                 final long identity = Binder.clearCallingIdentity();
    261                                 try {
    262                                     final IRingtonePlayer player = mAudioService.getRingtonePlayer();
    263                                     if (player != null) {
    264                                         player.playAsync(soundUri, user, looping, audioStreamType);
    265                                     }
    266                                 } catch (RemoteException e) {
    267                                 } finally {
    268                                     Binder.restoreCallingIdentity(identity);
    269                                 }
    270                             }
    271                         }
    272 
    273                         // vibrate
    274                         // Does the notification want to specify its own vibration?
    275                         final boolean hasCustomVibrate = notification.vibrate != null;
    276 
    277                         // new in 4.2: if there was supposed to be a sound and we're in vibrate
    278                         // mode, and no other vibration is specified, we fall back to vibration
    279                         final boolean convertSoundToVibration =
    280                                    !hasCustomVibrate
    281                                 && hasValidSound
    282                                 && (audioManager.getRingerMode()
    283                                            == AudioManager.RINGER_MODE_VIBRATE);
    284 
    285                         // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
    286                         final boolean useDefaultVibrate =
    287                                 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
    288 
    289                         if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate)
    290                                 && !(audioManager.getRingerMode()
    291                                         == AudioManager.RINGER_MODE_SILENT)) {
    292                             mVibrateNotification = r;
    293 
    294                             if (useDefaultVibrate || convertSoundToVibration) {
    295                                 // Escalate privileges so we can use the vibrator even if the
    296                                 // notifying app does not have the VIBRATE permission.
    297                                 long identity = Binder.clearCallingIdentity();
    298                                 try {
    299                                     mVibrator.vibrate(r.sbn.getUid(), r.sbn.getBasePkg(),
    300                                         useDefaultVibrate ? mDefaultVibrationPattern
    301                                             : mFallbackVibrationPattern,
    302                                         ((notification.flags & Notification.FLAG_INSISTENT) != 0)
    303                                                 ? 0: -1);
    304                                 } finally {
    305                                     Binder.restoreCallingIdentity(identity);
    306                                 }
    307                             } else if (notification.vibrate.length > 1) {
    308                                 // If you want your own vibration pattern, you need the VIBRATE
    309                                 // permission
    310                                 mVibrator.vibrate(r.sbn.getUid(), r.sbn.getBasePkg(),
    311                                         notification.vibrate,
    312                                     ((notification.flags & Notification.FLAG_INSISTENT) != 0)
    313                                             ? 0: -1);
    314                             }
    315                         }
    316                     }
    317 
    318                     // light
    319                     // the most recent thing gets the light
    320                     mLights.remove(old);
    321                     if (mLedNotification == old) {
    322                         mLedNotification = null;
    323                     }
    324                     //Slog.i(TAG, "notification.lights="
    325                     //        + ((old.notification.lights.flags & Notification.FLAG_SHOW_LIGHTS)
    326                     //                  != 0));
    327                     if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0
    328                             && canInterrupt) {
    329                         mLights.add(r);
    330                         updateLightsLocked();
    331                     } else {
    332                         if (old != null
    333                                 && ((old.getFlags() & Notification.FLAG_SHOW_LIGHTS) != 0)) {
    334                             updateLightsLocked();
    335                         }
    336                     }
    337                 }
    338             }
    339         });
    340 
    341         idOut[0] = id;
    342     }
    View Code
  • 相关阅读:
    unity编辑器扩展
    unity给localRotation赋值
    ASp.net常用服务
    二叉树
    Photon Server类函数介绍
    线程间操作无效: 从不是创建控件的线程访问它的三种方法
    使用vs的输出窗口进行调试输出数据
    Bmob后端云之云数据库的使用
    软件设计的七大原则
    Unite Beijing 2018 参会简要分享
  • 原文地址:https://www.cnblogs.com/antoon/p/4276852.html
Copyright © 2011-2022 走看看