最新碰到了一个问题,由于发送了一个复位的广播:权限为:
<uses-permission android:name="android.permission.MASTER_CLEAR" />
然后并未接收到复位的这条广播,根据logcat打印发现:
W/BroadcastQueue( 2346): Permission Denial:
broadcasting Intent { act=android.intent.action.MASTER_CLEAR flg=0x10 }
from com.bestv.ott (pid=2593, uid=10006)
requires android.permission.MASTER_CLEAR due to receiver android/com.android.server.MasterClearReceiver
从日志分析上看是因为没有在AndroidManifest.xml中添加权限导致的,但代码中已添加以上权限。
解决方法:
由于FunTVLauncher.apk是在system/app目录下导致的。然后使用mv命令移动到system/priv-app/目录下可以了。那么为什么会导致这种情况。
问题开始分析(以下源码是Android4.4):
从日志可以看出,是在BroadcastQueue.java这个类中找到输出异常日志,从以下代码看出首先会进行权限检测,那么问题就出现在权限检测未通过,那么继续往里面找,链进去找到mService.checkComponentPermission方法
private final void deliverToRegisteredReceiverLocked(BroadcastRecord r,
BroadcastFilter filter, boolean ordered) {
boolean skip = false;
if (filter.requiredPermission != null) {
int perm = mService.checkComponentPermission(filter.requiredPermission,
r.callingPid, r.callingUid, -1, true);
if (perm != PackageManager.PERMISSION_GRANTED) {
Slog.w(TAG, "Permission Denial: broadcasting "
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid="
+ r.callingPid + ", uid=" + r.callingUid + ")"
+ " requires " + filter.requiredPermission
+ " due to registered receiver " + filter);
skip = true;
}
}
}
mService就是ActivityManagerService,找到ActivityManagerService.java -> checkComponentPermission方法继续进行权限的检测
int checkComponentPermission(String permission, int pid, int uid,
int owningUid, boolean exported) {
Identity tlsIdentity = sCallerIdentity.get();
if (tlsIdentity != null) {
Slog.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
+ tlsIdentity.pid + "," + tlsIdentity.uid + "}");
uid = tlsIdentity.uid;
pid = tlsIdentity.pid;
}
if (pid == MY_PID) {
return PackageManager.PERMISSION_GRANTED;
}
return ActivityManager.checkComponentPermission(permission, uid,
owningUid, exported);
}
接着进入到 ActivityManager.checkComponentPermission;
public static int checkComponentPermission(String permission, int uid,
int owningUid, boolean exported) {
if (uid == 0 || uid == Process.SYSTEM_UID) {
return PackageManager.PERMISSION_GRANTED;
}
if (UserHandle.isIsolated(uid)) {
return PackageManager.PERMISSION_DENIED;
}
if (owningUid >= 0 && UserHandle.isSameApp(uid, owningUid)) {
return PackageManager.PERMISSION_GRANTED;
}
if (!exported) {
return PackageManager.PERMISSION_DENIED;
}
if (permission == null) {
return PackageManager.PERMISSION_GRANTED;
}
try {
return AppGlobals.getPackageManager()
.checkUidPermission(permission, uid);
} catch (RemoteException e) {
Slog.e(TAG, "PackageManager is dead?!?", e);
}
return PackageManager.PERMISSION_DENIED;
}
通过AppGlobals进入到PackageManagerService中继续进行权限检查。AppGlobals.getPackageManager()是通过 ActivityThread.getPackageManager()来获取到IPackageManager实例,AIDL来进行跨进程通信。就回调用到PackageManagerService.java -> checkUidPermission
由一下代码可以发现我们传入进去的是权限的名字,那么grantedPermissions是一个HashSet,可以看出来传入的android.permission.MASTER_CLEAR"这个权限没有在HashSet集合中,由此要找到grantedPermissions.add数据的方法.
public int checkUidPermission(String permName, int uid) {
synchronized (mPackages) {
Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
if (obj != null) {
GrantedPermissions gp = (GrantedPermissions)obj;
if (gp.grantedPermissions.contains(permName)) {
return PackageManager.PERMISSION_GRANTED;
}
} else {
HashSet<String> perms = mSystemPermissions.get(uid);
if (perms != null && perms.contains(permName)) {
return PackageManager.PERMISSION_GRANTED;
}
}
}
return PackageManager.PERMISSION_DENIED;
}
由一下代码看出grantedPermissions.add数据的地方是grantPermissionsLPw中,allowed这个参数就是是否允add权限,那么就要找到为什么allowed为false, 找到grantSignaturePermission(perm, pkg, bp, origPermissions)方法
private void grantPermissionsLPw(PackageParser.Package pkg, boolean replace) {
final PackageSetting ps = (PackageSetting) pkg.mExtras;
if (ps == null) {
return;
}
boolean allowed;
boolean allowedSig = false;
final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
if (level == PermissionInfo.PROTECTION_NORMAL
|| level == PermissionInfo.PROTECTION_DANGEROUS) {
allowed = (required || origPermissions.contains(perm)
|| (isSystemApp(ps) && !isUpdatedSystemApp(ps)));
} else if (bp.packageSetting == null) {
allowed = false;
} else if (level == PermissionInfo.PROTECTION_SIGNATURE) {
allowed = grantSignaturePermission(perm, pkg, bp, origPermissions);
if (allowed) {
allowedSig = true;
}
} else {
allowed = false;
}
if (DEBUG_INSTALL) {
if (gp != ps) {
}
}
if (allowed) {
if (!isSystemApp(ps) && ps.permissionsFixed) {
if (!allowedSig && !gp.grantedPermissions.contains(perm)) {
allowed = isNewPlatformPermissionForPackage(perm, pkg);
}
}
if (allowed) {
if (!gp.grantedPermissions.contains(perm)) {
changedPermission = true;
gp.grantedPermissions.add(perm);
gp.gids = appendInts(gp.gids, bp.gids);
} else if (!ps.haveGids) {
gp.gids = appendInts(gp.gids, bp.gids);
}
} else {
Slog.w(TAG, "Not granting permission " + perm
+ " to package " + pkg.packageName
+ " because it was previously installed without");
}
}
}
主要是isPrivilegedApp(pkg);这个函数,把apk放入system/priv-app目录下后,系统会自动的给上PARSE_IS_PRIVILEGED权限。
private boolean grantSignaturePermission(String perm, PackageParser.Package pkg,
BasePermission bp, HashSet<String> origPermissions) {
boolean allowed;
allowed = (compareSignatures(
bp.packageSetting.signatures.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH)
|| (compareSignatures(mPlatformPackage.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH);
Log.d("PM_DEBUG","allowed1 is " + allowed + " for pkg " + pkg.packageName + " permission is " + perm);
if (!allowed && (bp.protectionLevel
& PermissionInfo.PROTECTION_FLAG_SYSTEM) != 0) {
if (isSystemApp(pkg)) {
Log.d("PM_DEBUG","isUpdatedSystemApp(akg) ->" + isUpdatedSystemApp(pkg) + "perm ->" + perm);
if (isUpdatedSystemApp(pkg)) {
final PackageSetting sysPs = mSettings
.getDisabledSystemPkgLPr(pkg.packageName);
final GrantedPermissions origGp = sysPs.sharedUser != null
? sysPs.sharedUser : sysPs;
if (origGp.grantedPermissions.contains(perm)) {
allowed = true;
Log.d("PM_DEBUG","allowed2 is " + allowed + " for pkg " + pkg.packageName + " permission is " + perm);
} else {
if (sysPs.pkg != null && sysPs.isPrivileged()) {
for (int j=0;
j<sysPs.pkg.requestedPermissions.size(); j++) {
if (perm.equals(
sysPs.pkg.requestedPermissions.get(j))) {
allowed = true;
Log.d("PM_DEBUG","allowed3 is " + allowed + " for pkg " + pkg.packageName + " permission is " + perm);
break;
}
}
}
}
} else {
allowed = isPrivilegedApp(pkg);
Log.d("PM_DEBUG","allowed4 is " + allowed + " for pkg " + pkg.packageName + " permission is " + perm);
}
}
}
if (!allowed && (bp.protectionLevel
& PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0) {
allowed = origPermissions.contains(perm);
Log.d("PM_DEBUG","allowed5 is " + allowed + " for pkg " + pkg.packageName + " permission is " + perm);
}
return allowed;
}
PackageManagerService初始化的地方给定了priv-app特殊的权限PARSE_IS_PRIVILEGED
File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
mPrivilegedInstallObserver = new AppDirObserver(
privilegedAppDir.getPath(), OBSERVER_EVENTS, true, true);
mPrivilegedInstallObserver.startWatching();
scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED, scanMode, 0);
总结:系统在开机的时候会在SystemServer中启动PackageManagerService服务,然后在初始化的时候会去将priv-app目录,app目录设定权限,并且解析所有apk中的清单文件并根据节点来进行存储,例如permission节点等权限存入Hashset中.
|