在公司中做Framework的定制也已经两年多了,陆陆续续的也改了不少的系统服务,替客户制定过不少api接口。之前关于一些需要系统级权限的接口也都是通过将apk进行系统签名的方式来实现的,虽然这种做法也并无不妥,但是仔细考虑了一下应该还是有其他方式可以让apk与系统的耦合度变的更低的。(大不了就是在其他机器上调用不了这个接口了)
网上找了一下也早就已经有人对权限机制和安全机制做过一些分析,但是都不太涉及到具体的调用链,而且一般都是添加新的权限限制而不是绕开原有限制。
浅析Android权限机制(一) —— Android的权限机制
Android安全机制(2) Android Permission权限控制机制
好了,接下来就是一些系统Framework的接口调用追踪了,只想看解决方案的话可以直接拉到最后。
调用流程(MT8735_M平台):
这里我们就挑一个具体的案例来分析吧,以蓝牙作为例子,apk如果需要管理蓝牙连接,就必须声明蓝牙相关的permission,那么这个permission的检查又是在哪里进行的呢。
BluetoothManagerService.java
public boolean enable() {
if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
(!checkIfCallerIsForegroundUser())) {
Log.w(TAG,"enable(): not allowed for non-active and non system user");
return false;
}
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permission");
if (DBG) {
Log.d(TAG,"enable(): mBluetooth =" + mBluetooth +
" mBinding = " + mBinding);
}
从这个enable函数可以看到,在执行enable函数开启蓝牙时,会先检查是否是系统进程,如果不是系统进程的话就需要在前台运行。
然后就通过Context(aondroid.content.Context)类的enforceCallingOrSelfPermission函数来检查相应的权限,这里的权限是一个常量,具体的定义是
private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
现在我们转到Context.java这个类里去看看:
/**
* Determine whether the calling process of an IPC <em>or you</em> have been
* granted a particular permission. This is the same as
* {
@link #checkCallingPermission}, except it grants your own permissions
* if you are not currently processing an IPC. Use with care!
*
* @param permission The name of the permission being checked.
*
* @return {
@link PackageManager#PERMISSION_GRANTED} if the calling
* pid/uid is allowed that permission, or
* {
@link PackageManager#PERMISSION_DENIED} if it is not.
*
* @see PackageManager#checkPermission(String, String)
* @see #checkPermission
* @see #checkCallingPermission
*/
@CheckResult(suggest="#enforceCallingOrSelfPermission(String,String)")
@PackageManager.PermissionResult
public abstract int checkCallingOrSelfPermission(@NonNull String permission)
这里的注释已经写的很详细了(谷歌aosp里的源码注释还是挺多的,很多比较难懂的地方都会有详细的注释),简单解释一下就是检查你的应用有没有声明这个权限,或者应用运行的uid(通过AndroidManifest.xml里的sharedUserId定义)是否有相应的权限。
这是一个抽象方法,那么一定会有一个实现这个方法的类,一般来说aosp里的命名都比较规范,这种实现一般都是xxxImpl.java或者xxxService.java之类的,不过一般我会直接用git grep去确认。这里的具体实现是在ContextImpl.java(framework/base/core/java/android/app/ContextImpl.java)中:
@Override
public int checkCallingOrSelfPermission(String permission) {
if (permission == null) {
throw new IllegalArgumentException("permission is null");
}
return checkPermission(permission, Binder.getCallingPid(),
Binder.getCallingUid());
可以看到这里是调用了checkPermission这个函数,如果把代码稍微浏览一遍的话会发现,context中检查权限的代码,包括checkxxxPermission或者enforcexxxPermission最后都是调到了这个 checkPermission的函数。
这里也贴一下enforce的调用吧,帮大家省点找代码的时间:
private void enforce(
String permission, int resultOfCheck,
boolean selfToo, int uid, String message) {
if