"显示通知"的判断:获取当前应用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/

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐