Android native 权限控制流程

关联文章:

Android Runtime Permission 详解

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 同样需要弹出对话框提示用户,看另一篇博文。





猜你喜欢

转载自blog.csdn.net/jingerppp/article/details/80519212
今日推荐