Android的权限部分详解

一、 背景

       应用权限有助于保护对数据和操作的访问/执行权限,从而为保护用户隐私提供支持。如果应用必须访问受限数据或执行受限操作才能实现某个用例,请声明相应的权限。
       Android 将权限分为不同的类型,包括安装时权限、运行时权限和特殊权限。每种权限类型都指明了当系统授予应用该权限后,应用可以访问的受限数据范围以及应用可以执行的受限操作范围。每项权限的保护级别取决于其类型以及对车机的影响。
当然你也可以访问Android官方网站查看权限相关的定义,不过很可惜,他只写了一些关于APP的

  • https://juejin.cn/post/7028196921143459870
  • https://blog.csdn.net/k663514387/article/details/141535594

权限分类:

 · 安装时权限:有些权限是用户安装应用时自动授予的权限;
 · 运行时权限:其他权限则需要应用在运行时进一步请求权限,比如麦克风、摄像头、地理位置等,系统会为运行时权限分配 dangerous 保护级别。
 · 特殊权限:只有平台和原始设备制造商 (OEM) 可以定义特殊权限,为特定应用限制操作范围和限制数据访问范围,系统会为特殊权限分配 appop 保护级别。
1. XML文件解析流程
(1) packages.xml

        存在 /data/system/文件夹下,记录了系统中所有安装的应用信息,包括基本信息、签名和权限等信息。当系统中的APK安装、删除、升级时,文件就会被更新。

packages.xml文件中主要的信息分为下面几个部分:

  • permission块: 里面包含了系统中所有定义的权限的信息
  • package块:里面包含了系统中所有安装的app的详细信息
  • shared-user块:里面包含了所有系统定义的shareuser的信息
  • keyset-settings块:里面包含了已安装app签名的public key信息
(2) default-permission.xml

       default-permissions.xml存在/system/etc/default-permissions/文件夹下。Android开机后,除了根据上次开机的记录(runtime-permissions.xml)授予运行时权限外,一些系统重要的组件也需要提前授予运行时权限,最常见的时为系统重要功能的默认组件提前授予运行时权限,例如系统会为默认的浏览器提前授予位置相关的运行时权限。

    提前授权的步骤分三步:

  • 系统特权组件授权;
  • 系统默认组件授权;
  • 特定文件指定授权。

default-permission.xml 中的fixed表示授权后是否可以被非系统组件修改权限

(3) runtime-permission.xml

       runtime-permission.xml存在/data/misc_de/0/apexdata/com.android.permission/文件夹下,会记录APP运行时所有的权限配置,运行时权限含有危险权限,此类权限授予应用对受限数据的额外访问权限,或允许应用执行对系统和其他应用具有更严重影响的受限操作。因此,需要先在应用中请求运行时权限,然后才能访问受限数据或执行受限操作。请勿假定这些权限之前已经授予过,务必仔细检查,并根据需要在每次访问之前请求这些权限。系统会为某些运行时权限分配 dangerous 保护级别。

2. 系统权限部分
(1) 系统启动

在AOSP中的路径是:frameworks/base/services/java/com/android/server/SystemServer.java,从Zygote创建system_process进程时,最先调用的就是声明了main()方法的类,main()方法创建了SystemServer的构造方法,构造方法里面只做了从属性系统中读取了工厂测试模式;

 public static void main(String[] args) {
    new SystemServer().run();
}

public SystemServer() {
    // Check for factory test mode.
    mFactoryTestMode = FactoryTest.getMode();
    …………
}

private void run() {
    try {
        // AndroidRuntime using the same set of system properties, but only the system_server
        // Initialize the system context.
        createSystemContext();

        // Create the system service manager.
        mSystemServiceManager = new SystemServiceManager(mSystemContext);
        LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
    }
    
    // Start services.
    try {
        t.traceBegin("StartServices");
        startBootstrapServices();
        startCoreServices();
        startOtherServices();
    } catch (Throwable ex) {
        Slog.e("System", "************ Failure starting system services", ex);
        throw ex;
    } finally {
        t.traceEnd(); // StartServices
    }
    …………
}
(2) startBootstrapServices()

这里启动了Installer、ActivityManagerService.Lifecycle //Activity管理服务
PowerManagerService //程序包管理服务
……

private void startBootstrapServices() {
    Installer installer = mSystemServiceManager.startService(Installer.class);

    // Activity manager runs the show.
    mActivityManagerService = mSystemServiceManager.startService(
            ActivityManagerService.Lifecycle.class).getService();
    mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
    mActivityManagerService.setInstaller(installer);

    ......

    // Start the package manager.
    mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
                mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
 
    //PKMS是否是第一次启动
    mFirstBoot = mPackageManagerService.isFirstBoot();
    ......
}
(3) startCoreServices()

SystemConfigService是用来读取并解析platform.xml

 /**
     * Starts some essential services that are not tangled up in the bootstrap process.
     */
    private void startCoreServices() {

        // Service for system config
        mSystemServiceManager.startService(SystemConfigService.class);
        ......
    }   
(4) startOtherServices()

这一块知识属于拓展,就是想记录WindowManagerService启动位置

/**
     * Starts a miscellaneous grab bag of stuff that has yet to be refactored and organized.
     */
    private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
    ......
        // WMS needs sensor service ready
        ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE);
        mSensorServiceStart = null;
        wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
                new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
        ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
                DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
        ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
                /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
    ......
    }
3. APP申请权限
(1) 背景

       `在不同行动设备上,权限的使用和管理有所不同。 为了提高用户对隐私的保护,Android 允许用户在应用运行时授权或拒绝某些敏感权限。 常见的敏感权限包括读取联系人、访问相机、获取位置等。 因此,开发者需要遵循系统规定,进行权限申请。

(2) 动态申请权限源码流程
  • AndroidMainfest.xml中声明应用权限
<manifest ...>
    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <application ...>
        ...
    </application>
</manifest>

  • 在需要申请权限的Activity中做动态权限检查
    // 请求单个权限
    private fun checkPermission() {
        if (ContextCompat.checkSelfPermission(
                this,
                android.Manifest.permission.CAMERA
            )
            != PackageManager.PERMISSION_GRANTED
        ) {
            Log.d(TAG, "onResume(): requestPermission()没有权限")
            // 没有权限,需要请求权限
            ActivityCompat.requestPermissions(
                this,
                arrayOf(android.Manifest.permission.CAMERA), 1001
            )
        } else {
            // 已经有权限,可以执行相关操作
            Log.d(TAG, "onResume(): requestPermission()已有权限")
        }
    }

    // 请求多个个权限
    private val PERMISSIONS_STORAGE: Array<String> = arrayOf<String>(
        android.Manifest.permission.RECORD_AUDIO,
        android.Manifest.permission.CAMERA
    )
    private fun ckeckPermissions() {
        
        for ( permission in PERMISSIONS_STORAGE){
            if (ActivityCompat.checkSelfPermission(this,
                    permission)!= PackageManager.PERMISSION_GRANTED) {
                Log.d(TAG, "onResume(): requestPermission()没有权限")
                ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, 200);
            }else {
            Log.d(TAG, "onResume(): requestPermission()已有权限")
            }
        }
    }
  • 在onRequestPermissionsResult() 方法中查看回调结果
// 请求权限回调方法
    @Deprecated("Deprecated in Java")
    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<String?>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        when (requestCode) {
            1001 -> {
                // 1001的请求码对应的是申请的权限
                //单个授权
                if (grantResults.isNotEmpty()) {
                    if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                        Log.d(TAG, "onRequestPermissionsResult(): 同意授权")
                    } else {
                        Log.d(TAG, "onRequestPermissionsResult(): 未同意授权")
                    }
                }else{
                    Log.d(TAG, "onRequestPermissionsResult(): 授权结果为空")
                }
                // 判断是否同意授权,PERMISSION_GRANTED 这个值代表的是已经获取了权限
                //多个授权
//                var allGranted = true
//                for (result in grantResults) {
//                    if (result != PackageManager.PERMISSION_GRANTED) {
//                        allGranted = false
//                        break
//                    }
//                }
//                if (allGranted) {
//                    // 所有权限都已授予,可以执行相关操作
//                    Log.d(TAG, "onRequestPermissionsResult(): 同意授权")
//                } else {
//                    // 有部分权限未授予,可能需要提示用户或调整应用功能
//                    Log.d(TAG, "onRequestPermissionsResult(): 未同意授权")
//                }
            }

        }
    }
  • 小知识点
    有个点需要注意一下就是同一个APP同时或者间隔一分钟去申请同一个权限两次结果是怎么样的?
    结果是第一次正常走检查申请流程,第二次申请的时候,在Activity.java中会提示“Can request only one set of permissions at a time”只能申请完一组,等用户同意或者拒绝才能申请下一组,所以不会重复弹窗,并且在onRequestPermissionsResult()中会立马收到一个空结果;
    override fun requestPermissions(permissions: Array<String?>, requestCode: Int) {
        require(requestCode >= 0) { "requestCode should be >= 0" }
        if (mHasCurrentPermissionsRequest) {
            Log.w(TAG, "Can request only one set of permissions at a time")
            // Dispatch the callback with empty arrays which means a cancellation.
            onRequestPermissionsResult(requestCode, arrayOfNulls(0), IntArray(0))
            return
        }
        val intent: Intent = packageManager.buildRequestPermissionsIntent(permissions)
        startActivityForResult(REQUEST_PERMISSIONS_WHO_PREFIX, intent, requestCode, null)
        mHasCurrentPermissionsRequest = true
    }

另外,不同的应用申请同一个权限不会有问题,因为申请权限的包名不同,弹窗是根据包名以及权限名去显示的

(3) 流程图
  • 请求运行权限流程图
    Android的权限部分详解_第1张图片

  • 请求特殊权限流程图
    Android的权限部分详解_第2张图片

你可能感兴趣的:(权限,android,笔记)