关联文章:
android grantRuntimePermission 详解
android GrantPermissionsActivity 详解
AppOps 对于Normal permission 的控制
前言:
在 Android Runtime Permission 详解 中详细的说明了permission 在Android 6.0 前后的区别,对于M 以后应用可以通过checkPermission 、requestPermission 等一系列的接口控制,但是在M之前的应用是看不到这样的接口,功能的开启会直接调用接口,例如Camera,会直接调用open 的接口。
那我们如何来控制这些权限的呢?在M 之后的系统中,native 的接口里会通过checkPermission 的接口,来确认是否拥有改功能对应的权限,例如Camera,会check android.permission.CAMERA 这个权限。
这一篇博文就是分析M 之后系统对于权限native接口的控制流程。
源码分析:
首先来看IServiceManager.h:
namespace android {
// ----------------------------------------------------------------------
class IServiceManager : public IInterface
{
...
...
};
sp<IServiceManager> defaultServiceManager();
template<typename INTERFACE>
status_t getService(const String16& name, sp<INTERFACE>* outService)
{
const sp<IServiceManager> sm = defaultServiceManager();
if (sm != NULL) {
*outService = interface_cast<INTERFACE>(sm->getService(name));
if ((*outService) != NULL) return NO_ERROR;
}
return NAME_NOT_FOUND;
}
bool checkCallingPermission(const String16& permission);
bool checkCallingPermission(const String16& permission,
int32_t* outPid, int32_t* outUid);
bool checkPermission(const String16& permission, pid_t pid, uid_t uid);
}; // namespace android
1、首先命名空间是android,所以有的地方通过接口android::checkPermission 来调用此处的接口
例如,PermissionCache.cpp 中:
bool PermissionCache::checkPermission(
const String16& permission, pid_t pid, uid_t uid) {
if ((uid == 0) || (pid == getpid())) {
// root and ourselves is always okay
return true;
}
PermissionCache& pc(PermissionCache::getInstance());
bool granted = false;
if (pc.check(&granted, permission, uid) != NO_ERROR) {
nsecs_t t = -systemTime();
granted = android::checkPermission(permission, pid, uid);
t += systemTime();
ALOGD("checking %s for uid=%d => %s (%d us)",
String8(permission).string(), uid,
granted?"granted":"denied", (int)ns2us(t));
pc.cache(permission, uid, granted);
}
return granted;
2、之所以首先来看IServiceManager.h,是因为其中提供了很多android 空间中的公共接口,例如defaultServiceManager()、getService()、checkPermission()
最终checkPermission() 实现的地方是在IServiceManger.cpp 中:
bool checkPermission(const String16& permission, pid_t pid, uid_t uid)
{
sp<IPermissionController> pc;
gDefaultServiceManagerLock.lock();
pc = gPermissionController;
gDefaultServiceManagerLock.unlock();
int64_t startTime = 0;
while (true) {
if (pc != NULL) {
bool res = pc->checkPermission(permission, pid, uid);
...
}
...
}
...
}
通过IPermissionController 来调用checkPermission()
来看下IPermissionController.h:
class IPermissionController : public IInterface
{
public:
DECLARE_META_INTERFACE(PermissionController)
virtual bool checkPermission(const String16& permission, int32_t pid, int32_t uid) = 0;
virtual void getPackagesForUid(const uid_t uid, Vector<String16> &packages) = 0;
virtual bool isRuntimePermission(const String16& permission) = 0;
enum {
CHECK_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
GET_PACKAGES_FOR_UID_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 1,
IS_RUNTIME_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 2
};
};
class BnPermissionController : public BnInterface<IPermissionController>
{
public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
};
实现的地方就看BnPermissionController 的地方了,从整个项目来看,native 会启动一个permission 的native service,详细看framework/native/services/nativeperms/nativeperms.cpp:
class PermissionService : public android::os::BnPermissionController {
public:
::android::binder::Status checkPermission(
const ::android::String16& permission, int32_t pid, int32_t uid,
bool* _aidl_return) {
(void)permission;
(void)pid;
(void)uid;
*_aidl_return = true;
return binder::Status::ok();
}
再来看下Java 中android.os.IPermissionController,首先来看aidl,
package android.os;
/** @hide */
interface IPermissionController {
boolean checkPermission(String permission, int pid, int uid);
String[] getPackagesForUid(int uid);
boolean isRuntimePermission(String permission);
}
跟着这个aidl 来知道它的service 端,在ActivityManagerService.java中,
public void setSystemProcess() {
try {
ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
ServiceManager.addService("meminfo", new MemBinder(this));
ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
ServiceManager.addService("dbinfo", new DbBinder(this));
if (MONITOR_CPU_USAGE) {
ServiceManager.addService("cpuinfo", new CpuBinder(this));
}
ServiceManager.addService("permission", new PermissionController(this));//这里添加permission 的service
ServiceManager.addService("processinfo", new ProcessInfoService(this));
接着就是service 端:
static class PermissionController extends IPermissionController.Stub {
ActivityManagerService mActivityManagerService;
PermissionController(ActivityManagerService activityManagerService) {
mActivityManagerService = activityManagerService;
}
@Override
public boolean checkPermission(String permission, int pid, int uid) {
return mActivityManagerService.checkPermission(permission, pid,
uid) == PackageManager.PERMISSION_GRANTED;
}
接着:
@Override
public int checkPermission(String permission, int pid, int uid) {
if (permission == null) {
return PackageManager.PERMISSION_DENIED;
}
return checkComponentPermission(permission, pid, uid, -1, true);
}
接着:
int checkComponentPermission(String permission, int pid, int uid,
int owningUid, boolean exported) {
if (pid == MY_PID) {
return PackageManager.PERMISSION_GRANTED;
}
return ActivityManager.checkComponentPermission(permission, uid,
owningUid, exported);
}
接着:
public static int checkComponentPermission(String permission, int uid,
int owningUid, boolean exported) {
...
...
try {
return AppGlobals.getPackageManager()
.checkUidPermission(permission, uid);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
最终会调到PMS 中的checkUidPermission,完成最后的确认工作。
这里source code 基本都是逻辑问题,不需要详细讲解,有什么问题可以随时交流。
checkUidPermission 的source code 这里暂不贴出来,详细可以看下 android grantRuntimePermission 详解
其实,最主要的是PermissionsState 中的mPermissions,如果grant 了,那么里面会有这样的permission,如果是revoke 的,那么就不会有这样的permission。当然,对于M 之前的app,这里默认肯定都是granted的。
这一篇博文主要是分析native 的check 流程,至于CTA 要求M 之前app 同样需要弹出对话框提示用户,看另一篇博文