Anroid 11 关于NotificationManager && NotificationManagerService -- 衍生到权限管理
1.Android 11 -- 强制清理app后台,关于权限引发的问题2.Android 11 (MTK)状态栏图标反色-->跟随当前应用变化代码流程3.Android 11 --关于Toast的异常4.Android 11 -- 关于dialog和悬浮窗导致SystemUI状态栏下拉频繁闪烁(窗口焦点问题)5.Android 11 下拉菜单长按WiFi图标SystemUI ANR6.Android 11 sim卡来电不弹出悬浮通知,默认来电默认全屏7.Android Bluetooth 蓝牙开发/蓝牙协议 小结8.Android11 —— 自定义添加一个System Services9.Android系统——AOSP相关-->随记10.Android11 , Launcher3 切换阿拉伯语,最近应用(后台)不能滑动11.Android 底层问题日志记录12.Android 11 -- app 服务保活13.Android11 - 添加自定义服务注意事项14.Android 11 导航栏添加一个虚拟按钮--问题合集15.Android 11--设置第三方Launcher并默认 与 如何预置apk16.Android11 系统修改 AOSP输入法的默认输入键盘布局17.Settings里面切换不同Launcher的代码流程18.关于Android`系统默认屏保`19.关于Android 11 Settings添加新的选项界面的细节20.Android 11 自由窗口模式 || 全屏模式启动app21.强制app横屏显示或者竖屏显示(动态)22.Android 11 禁止从SD卡上安装第三方应用23.实体物理音量键替换为home键24.AMS- kill Launcher进程的代码流程25.Android 11 recovery恢复出厂设置保留某些文件26.Android 11 禁用 adb root (userdebug版本)27.Android11 应用默认获取通知使用权限(可以获取系统所有通知信息)28.Android 11 UsbDebug 关于adb RSA 认证29.Android 11 NavigationBar && Status Bar 如果改变背景颜色
30.Anroid 11 关于NotificationManager && NotificationManagerService -- 衍生到权限管理
31.Android13 控制设置界面 双栏显示或单栏显示32.Android 13 大屏显示时关于SystemUI和Launcher3问题33.Android 系统适配无源码app34.Android 11 关于app的权限重置35.Android 11.0 关于app进程保活36.Android 11 关于按键拦截/按键事件处理分享37.Android R Settings关于屏保/PowerManagerService欺骗系统不让其进入休眠状态38.Android13 关于SystemUI更新/Nav Bar add volume button&&other button39.Android 13 移植EthernetSettings/Ethernet更新40.Anrdoir 13 关于设置静态IP后,突然断电,在上电开机卡动画41.Android T(13) The app is granted permissions by default42.Android T 关于屏幕旋转 (一)43.Android T about screen rotation(二)44.Android 13 about launcher3 (1)45.Android T don't abort background activity starts46.Android T adout replace bootanimation47.Launcher start App WINDOWING_MODE_FREEFORM48.Android 11 About SleepToken / (Settings)Screen timeout49.Settings.System数据监听/prop&SystemProperties数据监听NotificationManager && NotificationManagerService
Android 12.0 应用中监听系统收到的通知
Android 12.0 通知发送流程分析
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就代表不是运行时权限
}
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;
}
}
分类:
Android
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· 【.NET】调用本地 Deepseek 模型
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
2023-07-20 关于Android 控件没有动态设置界面效果时,如何处理