android 系统通知应用程序,android系统设置=》应用程序=》应用=》显示通知选项
"显示通知"的判断:获取当前应用apk的签名证书信息、和系统应用framework-res.apk的签名证书信息比对,如果一样,则不允许操作“显示通知”;如果不一样,则允许操作“显示通知”系统设置apk(5.0):InstalledAppDetails.java中,onResume方法中会调用如下方法,刷新“显示通知”的状态private void initNotificationButton()
"显示通知"的判断:获取当前应用apk的签名证书信息、和系统应用
framework-res.apk的签名证书信息比对,如果一样,则不允许操作“显示通知”;
如果不一样,则允许操作“显示通知”
系统设置apk(5.0):
InstalledAppDetails.java中,onResume方法中会调用如下方法,刷新“显示通知”的状态
private void initNotificationButton() {
INotificationManager nm = INotificationManager.Stub.asInterface( ServiceManager.getService(Context.NOTIFICATION_SERVICE));
boolean enabled = true; // default on
try {
enabled = nm.areNotificationsEnabledForPackage(mAppEntry.info.packageName, mAppEntry.info.uid);
} catch (android.os.RemoteException ex) {
// this does not bode well
}
mNotificationSwitch.setChecked(enabled);
if (Utils.
isSystemPackage(mPm, mPackageInfo)) {
mNotificationSwitch.setEnabled(false);
} else {
mNotificationSwitch.setEnabled(true);
mNotificationSwitch.setOnCheckedChangeListener(this);
}
}
系统设置apk(5.0):
Utils.java中,
/**
* Determine whether a package is a "system package", in which case certain things (like
* disabling notifications or disabling the package altogether) should be disallowed.
*/
public static boolean
isSystemPackage(PackageManager pm, PackageInfo pkg) {
if (sSystemSignature == null) {
sSystemSignature = new Signature[]{ getSystemSignature(pm) };
}
return sSystemSignature[0] != null && sSystemSignature[0].equals(getFirstSignature(pkg));
}
private static Signature[] sSystemSignature;
private static Signature
getFirstSignature(PackageInfo pkg) {
if (pkg != null && pkg.signatures != null && pkg.signatures.length > 0) {
return pkg.signatures[0];
}
return null;
}
private static Signature
getSystemSignature(PackageManager pm) {
try {
final PackageInfo sys = pm.getPackageInfo(
"android", PackageManager.GET_SIGNATURES);
=》包名“android”,对应/system/framework/framework-res.apk
return
getFirstSignature(sys);
} catch (NameNotFoundException e) {
}
return null;
}
PKMS服务中,还提供了另外一种方法,检查两个应用的签名证书是否一致。
(PackageParser会把Package信息转换成PackageInfo信息)
/frameworks/base/services/java/com/android/server/pm/
PackageManagerService.java
public int
checkSignatures(String pkg1, String pkg2) {
synchronized (mPackages) {
final PackageParser.Package p1 = mPackages.get(pkg1);
final PackageParser.Package p2 = mPackages.get(pkg2);
if (p1 == null || p1.mExtras == null || p2 == null || p2.mExtras == null) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
return
compareSignatures(p1.mSignatures, p2.mSignatures);
}
}
/frameworks/base/services/core/java/com/android/server/notification/
NotificationManagerService.java
@Override
public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
checkCallerIsSystem();
return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg) == AppOpsManager.MODE_ALLOWED);
}
/frameworks/base/core/java/android/app/
AppOpsManager.java =》android 5.0 源码中新的权限管理机制
/**
* Like {@link #checkOp} but instead of throwing a {@link SecurityException} it
* returns {@link #MODE_ERRORED}.
* @hide
*/
public int checkOpNoThrow(int op, int uid, String packageName) {
try {
return mService.checkOperation(op, uid, packageName);
} catch (RemoteException e) {
}
return MODE_IGNORED;
}
public static final int OP_POST_NOTIFICATION = 11;
/**
* Retrieve the default mode for the operation.
* @hide
*/
public static int opToDefaultMode(int op) {
return sOpDefaultMode[op];
}
/**
* This specifies the default mode for each operation.
*/
private static int[] sOpDefaultMode = new int[] {
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED, =》通知权限默认是打开的
AppOpsManager.MODE_ALLOWED,
......
};
/frameworks/base/services/core/java/com/android/server/
AppOpsService.java
@Override
public int
checkOperation(int code, int uid, String packageName) {
verifyIncomingUid(uid);
verifyIncomingOp(code);
synchronized (this) {
if (isOpRestricted(uid, code, packageName)) {
return AppOpsManager.MODE_IGNORED;
}
Op op = getOpLocked(AppOpsManager.opToSwitch(code), uid, packageName, false);
if (op == null) {
return AppOpsManager.opToDefaultMode(code);
}
return op.mode;
}
}
private Op
getOpLocked(int code, int uid, String packageName, boolean edit) {
Ops ops = getOpsLocked(uid, packageName, edit);
if (ops == null) {
return null;
}
return getOpLocked(ops, code, edit);
}
private Op
getOpLocked(Ops ops, int code, boolean edit) {
Op op = ops.get(code);
if (op == null) {
if (!edit) {
return null;
}
op = new Op(ops.uid, ops.packageName, code);
ops.put(code, op);
}
if (edit) {
scheduleWriteLocked();
}
return op;
}
public final static class
Op{
public final int uid;
public final String packageName;
public final int op;
public int mode;
public int duration;
public long time;
public long rejectTime;
public int nesting;
public Op(int _uid, String _packageName, int _op) {
uid = _uid;
packageName = _packageName;
op = _op;
mode = AppOpsManager.opToDefaultMode(op);
}
}
private Ops
getOpsLocked(int uid, String packageName, boolean edit) {
if (uid == 0) {
packageName = "root";
} else if (uid == Process.SHELL_UID) {
packageName = "com.android.shell";
}
return
getOpsRawLocked(uid, packageName, edit);
}
参考:
http://androidxref.com
http://blog.mssun.me/security/android-4-3-app-ops-analysis/
更多推荐
所有评论(0)