jQuery鼠标指针特效

Anroid 11 关于NotificationManager && NotificationManagerService -- 衍生到权限管理

NotificationManager && NotificationManagerService

frameworks/base/core/java/android/app/NotificationManager.java
几个比较重要的函数:

//移除mContext.getUser发送的通知
public void cancel(@Nullable String tag, int id)
    {
        cancelAsUser(tag, id, mContext.getUser());
    }
//移除所有通知 
public void cancelAll()
    {
        INotificationManager service = getService();
        String pkg = mContext.getPackageName();
        if (localLOGV) Log.v(TAG, pkg + ": cancelAll()");
        try {
            service.cancelAllNotifications(pkg, mContext.getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

//发送通知,这里可以做判断屏蔽不发送通知
public void notify(int id, Notification notification)
public void notify(String tag, int id, Notification notification)
public void notifyAsUser(String tag, int id, Notification notification, UserHandle user)
    {
        INotificationManager service = getService();
        String pkg = mContext.getPackageName();

        try {
            if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
            service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
                    fixNotification(notification), user.getIdentifier());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

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

enqueueNotificationInternal(...)
{
      ...
     if (notificationUid == INVALID_UID) {
            throw new SecurityException("Caller " + opPkg + ":" + callingUid
                    + " trying to post for invalid pkg " + pkg + " in user " + incomingUserId);
        }
    
     //检查通知是否属于仅限于系统使用的类别类型
     checkRestrictedCategories(pkg, notification);
    ...
    //Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
    //检查是否可以发送通知。检查速率限制器、贪睡助手和阻塞。
    if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
                r.getSbn().getOverrideGroupKey() != null)) {
            return;
      }
    ...
    mHandler.post(new EnqueueNotificationRunnable(userId, r, isAppForeground));
}
-> postPostNotificationRunnableMaybeDelayedLocked(r, new PostNotificationRunnable(r.getKey()));
->class PostNotificationRunnable implements Runnable 
{   
        @Override
        public void run() {
            //通知放在通知队列中,按照顺序处理
            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) {
                        Slog.i(TAG, "Cannot find enqueued record for key: " + key);
                        return;
                    }

                    if (isBlocked(r)) {
                        Slog.i(TAG, "notification blocked by assistant request");
                        return;
                    }
}


//负责处理通知声音的函数.
//判断通知是否应尝试发出噪音、振动或闪烁LED,
//@return buzzBeepBlink - bitfield (buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)

int buzzBeepBlinkLocked(NotificationRecord record) {
    if (mIsAutomotive && !mNotificationEffectsEnabledForAutomotive) {
            return 0;
        }
        boolean buzz = false;
        boolean beep = false;
        boolean blink = false;
    ...
        if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
                    if (!sentAccessibilityEvent) {
                        sendAccessibilityEvent(record);
                        sentAccessibilityEvent = true;
                    }
                    if (DBG) Slog.v(TAG, "Interrupting!");
                    if (hasValidSound) {
                        if (isInCall()) {
                            playInCallNotification();//电话铃声?
                            beep = true;
                        } else {
                            beep = playSound(record, soundUri);//播放通知的声音函数,soundUri.getPath()通知声音文件路径
                        }
                        if(beep) {
                            mSoundNotificationKey = key;
                        }
                    }

                    final boolean ringerModeSilent =
                            mAudioManager.getRingerModeInternal()
                                    == AudioManager.RINGER_MODE_SILENT;
                    if (!isInCall() && hasValidVibrate && !ringerModeSilent) {
                        buzz = playVibration(record, vibration, hasValidSound);
                        if(buzz) {
                            mVibrateNotificationKey = key;
                        }
                    }
                } else if ((record.getFlags() & Notification.FLAG_INSISTENT) != 0) {
                    hasValidSound = false;
                }
            }
            ...
}

Notification的setNotificationsEnabledForPackage接口的使用:屏蔽特定应用的通知提示

Notification的setNotificationsEnabledForPackage接口详解

./packages/apps/Settings/src/com/android/settings/notification/app/..
Settings界面负责通知权限开关的...
/**
 * Parent class for preferences appearing on notification setting pages at the app,
 * notification channel group, or notification channel level.
 */
public abstract class NotificationPreferenceController extends AbstractPreferenceController {
    protected final NotificationManager mNm;
    protected final NotificationBackend mBackend;
    ...
    
    public NotificationPreferenceController(Context context, NotificationBackend backend) {
        super(context);
        mContext = context;
        mNm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
        mBackend = backend;
        mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
        mPm = mContext.getPackageManager();
    }
}

public class BlockPreferenceController extends NotificationPreferenceController
        implements PreferenceControllerMixin, SwitchBar.OnSwitchChangeListener {
    ...
    @Override
    public void onSwitchChanged(Switch switchView, boolean isChecked) {
        ...
        } else if (mChannelGroup != null) {
            mChannelGroup.setBlocked(blocked);
            mBackend.updateChannelGroup(mAppRow.pkg, mAppRow.uid, mChannelGroup);
        } else if (mAppRow != null) {
            mAppRow.banned = blocked;
            mBackend.setNotificationsEnabledForPackage(mAppRow.pkg, mAppRow.uid, !blocked);
        }
    }
}

./packages/apps/Settings/src/com/android/settings/notification/NotificationBackend.java

    //查询某个应用通知是否启用
    public boolean getNotificationsBanned(String pkg, int uid) {
        try {
            final boolean enabled = sINM.areNotificationsEnabledForPackage(pkg, uid);
            return !enabled;
        } catch (Exception e) {
            Log.w(TAG, "Error calling NoMan", e);
            return false;
        }
    }
    
    //打开或关闭某个应用通知
    public boolean setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
        try {
            if (onlyHasDefaultChannel(pkg, uid)) {
                NotificationChannel defaultChannel =
                        getChannel(pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID, null);
                defaultChannel.setImportance(enabled ? IMPORTANCE_UNSPECIFIED : IMPORTANCE_NONE);
                updateChannel(pkg, uid, defaultChannel);
            }
            sINM.setNotificationsEnabledForPackage(pkg, uid, enabled);
            return true;
        } catch (Exception e) {
            Log.w(TAG, "Error calling NoMan", e);
            return false;
        }
    }


frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java
    @Override
    public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
        ...
        // Now, cancel any outstanding notifications that are part of a just-disabled app
            if (!enabled) {
                //取消某个应用中发送的所有通知
                cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
                        UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
            }
            //重新授予通知权限,true->MODE_ALLOWED 0(授予)  false->MODE_IGNORED 1
            mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
                    enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
        ...
    
    }

./frameworks/base/services/core/java/com/android/server/appop/AppOpsService.java
    private void setMode(int code, int uid, @NonNull String packageName, int mode,
            @Nullable IAppOpsCallback permissionPolicyCallback) {
            
            ...
            if (repCbs != null) {
            mHandler.sendMessage(PooledLambda.obtainMessage(
                    AppOpsService::notifyOpChanged,
                    this, repCbs, code, uid, packageName));
            }

            notifyOpChangedSync(code, uid, packageName, mode, previousMode);
            
    }

AppOpsServicey详解
Android10原生设置中INotificationManager

关于Android的权限管理:一套是Android Runtime运行时权限机制,对应Framework中的PermissionManager和PermissionService服务;
一套是AppOpsManager和AppOpsService服务:App-ops提供两个用途:一个是访问控制,这个具体是和runtime运行时权限配合;
负责app权限管理的是AppOpsManager和AppOpsService,每次开机它都会走一遍流程,对相应的app进行权限的授予

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

    public int checkOp(int op, int uid, String packageName) {
        try {
            int mode = mService.checkOperation(op, uid, packageName);
            if (mode == MODE_ERRORED) {
                throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
            }
            return mode;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
    
./frameworks/base/services/core/java/com/android/server/appop/AppOpsService.java

checkOperation->checkOperationInternal->checkOperationImpl

private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName,boolean raw) {
        ...
        synchronized (this) {
            if(packageName.equals("com.sclick.aura2")){
                android.util.Log.d("tww","set synchronized!");
            }
            if (isOpRestrictedLocked(uid, code, packageName, bypass)) {
                return AppOpsManager.MODE_IGNORED;
            }
            //add text
            if(code == AppOpsManager.OP_POST_NOTIFICATION && packageName.equals("com.xxxx.xx")){
                return AppOpsManager.MODE_IGNORED;
            }
            //add text
            code = AppOpsManager.opToSwitch(code);
            UidState uidState = getUidStateLocked(uid, false);
            if (uidState != null && uidState.opModes != null
                    && uidState.opModes.indexOfKey(code) >= 0) {
                final int rawMode = uidState.opModes.get(code);
                return raw ? rawMode : uidState.evalMode(code, rawMode);
            }
            Op op = getOpLocked(code, uid, packageName, null, bypass, false);
            if (op == null) {
                return AppOpsManager.opToDefaultMode(code);
            }
            return raw ? op.mode : op.evalMode();
        
    }
    
//adb命令可以看应用当前的权限状态
adb shell dumpsys package com.android.systemui(包名)

declared permissions -- 自定义权限
requested permissions ——应用在AndroidManifest.xml中请求的权限
install permissions —— normal权限授权情况,包括signature权限
runtime permissions —— 危险权限授权情况


Framework中的Permission.java和PermissionManagerService.java;
updatePermissions->restorePermissionState{
//首先判断这个权限的属性是运行时权限还是安装权限,
 isNormal()来进行判断,返回true,代表是安装权限;在isRuntime()中返回false就代表不是运行时权限
}

AppOpsService架构
权限管理

Settings负责管理应用通知动作的相关类

//控制
./packages/apps/Settings/src/com/android/settings/notification/app/BlockPreferenceController.java
./packages/apps/Settings/src/com/android/settings/notification/app/NotificationPreferenceController.java
./packages/apps/Settings/src/com/android/settings/notification/NotificationBackend.java

//通知--Suggested actions and replies 开关
./packages/apps/Settings/src/com/android/settings/notification/AssistantCapabilityPreferenceController.java

//应用图标上的通知原点--dot 开关
./packages/apps/Settings/src/com/android/settings/notification/BadgingNotificationPreferenceController.java
//有这个Secure属性控制
Settings.Secure.putInt(mContext.getContentResolver(),NOTIFICATION_BADGING,0);
adb shell settings get secure notification_badging

思路:接受开机广播,然后调用对应函数关闭它们

//shell 命令获取Uid ps -A | grep com.android.systemui
u0_a123        2140    269 14460252 246692 0     0 S com.android.systemui

a=10 十六进制  Uid = 10123

//获取系统内置应用的Uid
private void getAppUid(){
        PackageManager mPm = getPackageManager();
        try {
            ApplicationInfo applicationInfo = mPm.getApplicationInfo("com.android.providers.downloads", 0);
            int uid = applicationInfo.uid;
            Log.d("tag","--->uid:"+uid);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

import android.service.notification.Adjustment;
import com.android.settings.notification.NotificationBackend;

private boolean flag = false;
private void closeNotificationsEnabledApps() {
        if (!flag) {
            NotificationBackend mBackend = new NotificationBackend();
            mBackend.setNotificationsEnabledForPackage("com.xx.xx", 10132, false);//10132 app的Uid 唯一固定不变的
            //Suggested actions and replies
            mBackend.allowAssistantAdjustment(Adjustment.KEY_CONTEXTUAL_ACTIONS, false);
            mBackend.allowAssistantAdjustment(Adjustment.KEY_TEXT_REPLIES, false);
            flag = true;
        }
    }
posted @ 2024-07-20 14:40  僵小七  阅读(15)  评论(0编辑  收藏  举报