Android 11 (API 级别 30)AppOpsManager.OnOpNotedCallback监听隐私运行时权限调用

一、简介

监听隐私运行时权限调用: 此流程在搭载 Android 11(API 级别 30)及更高版本的设备上可用,可让您更好地识别可能出现的意外数据访问。您的应用可以注册 AppOpsManager.OnOpNotedCallback 实例,该实例可在每次发生以下任一事件时执行相应操作:

  1. 应用的代码访问私密数据。为了帮助您确定应用的哪个逻辑部分调用了事件,您可以按归因标记审核数据访问。
  2. 依赖库或 SDK 中的代码访问私密数据。

数据访问审核是在发生数据请求的线程上调用的。这意味着,如果应用中的第三方 SDK 或库调用访问私密数据的 API,您的 OnOpNotedCallback 可以调用数据访问审核检查有关该调用的信息。通常,此回调对象可以通过查看应用的当前状态(例如当前线程的堆栈轨迹)以判断调用是来自您的应用还是来自 SDK。

二、使用

1. 监听单个activity

如需使用 AppOpsManager.OnOpNotedCallback 实例执行数据访问审核,请在您打算审核数据访问的组件中实现回调逻辑,例如在某个 Activity 的 onCreate() 方法中。

2. 全局监听

创建自定义子类 Application,并在子类的 onCreate() 方法中定义 AppOpsManager.OnOpNotedCallback。

执行注册监听

override fun onCreate(savedInstanceState: Bundle?) {
    val onOpNotedCallback = object : AppOpsManager.OnOpNotedCallback() {

        // 保存和记录信息。可能从不同线程调用,因此同步。可以进一步优化到只处理可变列表MutableList 的部分。
        /**
         *  @param operation 操作
         *  @param stackTrace 堆栈跟踪
         */
        @Synchronized
        private fun saveAndLog(operation: String, stackTrace: String) {
            // 将 操作和堆栈信息,存到opsNotedForThisApp
            opsNotedForThisApp.add(Pair(operation, stackTrace))

            // Log
            Log.d(TAG, "saveAndLog" + operation)
            Log.d(TAG, "saveAndLog stackTrace:" + stackTrace)


            // 输出到屏幕outputTextView
            val operationsOnly = opsNotedForThisApp.map { "- ${it.first}" }
            runOnUiThread {
                binding.outputTextView.text =
                    operationsOnly.joinToString("\n", "Check Log for stacktrace.\n", "\n")
            }
        }

        /**
         * onNoted—通过同步调用访问受保护数据时调用。例如,如果应用程序请求用户的最后一个已知位置,并且该函数立即返回值synchronous,则会触发onNoted。
         */
        override fun onNoted(operation: SyncNotedAppOp) {
            // 获取 操作operation.op    和 归因
            val operationDescription =
                prettyOperationDescription("onNoted()", operation.op, operation.attributionTag)
            // 获取当前线程的堆栈信息
            val prettyStackTrace = prettyStackTrack(Thread.currentThread().stackTrace)

            saveAndLog(operationDescription, prettyStackTrace)
        }

        /**
         * onAsyncNoted—通过异步回调访问受保护数据时调用。例如,如果某个应用程序订阅的位置发生了更改,
         * 则在调用具有新位置的回调时将触发onAsyncNoted。地理围栏是另一个例子。
         *
         * 重要提示:由于您正在等待GPS信号更新,因此单击按钮后可能需要一两分钟才能显示。
         */
        override fun onAsyncNoted(asyncOp: AsyncNotedAppOp) {
            val operationDescription =
                prettyOperationDescription("onAsyncNoted()", asyncOp.op, asyncOp.attributionTag)

            // 对于AsyncNotedAppOp,使用“message”字段而不是检索当前线程的堆栈跟踪来标识调用更有效。
            val message = asyncOp.message

            saveAndLog(operationDescription, message)
        }

        /**
         *  onSelfNoted—当开发人员调用{@link android.app.apppsmanager#noteOp}
         *  手动触发受保护的数据访问时调用。这是系统未触发的唯一回调。
         *     当应用程序感觉自己正在访问受保护的数据并想要对其进行审核时,这是一种自责的方式
         *
         *  这是一个相当罕见的用例,所以在大多数情况下,您不需要这样做。
         */
        override fun onSelfNoted(operation: SyncNotedAppOp) {
            val operationDescription =
                prettyOperationDescription("onSelfNoted()", operation.op, operation.attributionTag)

            val prettyStackTrace = prettyStackTrack(Thread.currentThread().stackTrace)

            saveAndLog(operationDescription, prettyStackTrace)
        }
    }

    val appOpsManager =
            getSystemService(AppOpsManager::class.java) as AppOpsManager
    appOpsManager.setOnOpNotedCallback(mainExecutor, appOpsCallback)
}

三、按归因【Attribution】标记审核数据访问

如果您在某个 Activity 中访问数据(例如请求位置信息或访问用户的联系人列表),请在该 Activity 的 onCreate() 方法中调用 createAttributionContext(),并传入您希望与应用的一部分相关联的归因标记。

以下代码段展示了如何为应用的“照片位置信息分享”部分创建归因标记:

class SharePhotoLocationActivity : AppCompatActivity() {
    lateinit var attributionContext: Context

    override fun onCreate(savedInstanceState: Bundle?) {
        attributionContext = createAttributionContext("sharePhotos")
    }

    fun getLocation() {
        val locationManager = attributionContext.getSystemService(
                LocationManager::class.java) as LocationManager
        // Use "locationManager" to access device location information.
    }
}

在 回调中拿到归因tag,知道调用原因

val appOpsCallback = object : AppOpsManager.OnOpNotedCallback() {
    // attributionTag  归因tag
    private fun logPrivateDataAccess(
            opCode: String, attributionTag: String, trace: String) {
        Log.i(MY_APP_TAG, "Private data accessed. " +
                    "Operation: $opCode\n " +
                    "Attribution Tag:$attributionTag\nStack Trace:\n$trace")
    }

    override fun onNoted(syncNotedAppOp: SyncNotedAppOp) {
        logPrivateDataAccess(syncNotedAppOp.op,
                syncNotedAppOp.attributionTag,
                Throwable().stackTrace.toString())
    }

    override fun onSelfNoted(syncNotedAppOp: SyncNotedAppOp) {
        logPrivateDataAccess(syncNotedAppOp.op,
                syncNotedAppOp.attributionTag,
                Throwable().stackTrace.toString())
    }

    override fun onAsyncNoted(asyncNotedAppOp: AsyncNotedAppOp) {
        logPrivateDataAccess(asyncNotedAppOp.op,
                asyncNotedAppOp.attributionTag,
                asyncNotedAppOp.message)
    }
}

四、权限列表

运行时权限:

group:android.permission-group.CONTACTS
permission:android.permission.WRITE_CONTACTS
permission:android.permission.GET_ACCOUNTS
permission:android.permission.READ_CONTACTS
 
group:android.permission-group.PHONE
permission:android.permission.READ_CALL_LOG
permission:android.permission.READ_PHONE_STATE
permission:android.permission.CALL_PHONE
permission:android.permission.WRITE_CALL_LOG
permission:android.permission.USE_SIP
permission:android.permission.PROCESS_OUTGOING_CALLS
permission:com.android.voicemail.permission.ADD_VOICEMAIL
 
group:android.permission-group.CALENDAR
permission:android.permission.READ_CALENDAR
permission:android.permission.WRITE_CALENDAR
 
group:android.permission-group.CAMERA
permission:android.permission.CAMERA
 
group:android.permission-group.SENSORS
permission:android.permission.BODY_SENSORS
 
group:android.permission-group.LOCATION
permission:android.permission.ACCESS_FINE_LOCATION
permission:android.permission.ACCESS_COARSE_LOCATION
 
group:android.permission-group.STORAGE
permission:android.permission.READ_EXTERNAL_STORAGE
permission:android.permission.WRITE_EXTERNAL_STORAGE
 
group:android.permission-group.MICROPHONE
permission:android.permission.RECORD_AUDIO
 
group:android.permission-group.SMS
permission:android.permission.READ_SMS
permission:android.permission.RECEIVE_WAP_PUSH
permission:android.permission.RECEIVE_MMS
permission:android.permission.RECEIVE_SMS
permission:android.permission.SEND_SMS
permission:android.permission.READ_CELL_BROADCASTS

普通权限

 
ACCESS_LOCATION_EXTRA_COMMANDS 定位权限
 
ACCESS_NETWORK_STATE 网络状态权限
 
ACCESS_NOTIFICATION_POLICY 通知 APP通知显示在状态栏
 
ACCESS_WIFI_STATE WiFi状态权限
 
BLUETOOTH 使用蓝牙权限
 
BLUETOOTH_ADMIN 控制蓝牙开关
 
BROADCAST_STICKY 粘性广播
 
CHANGE_NETWORK_STATE 改变网络状态
 
CHANGE_WIFI_MULTICAST_STATE 改变WiFi多播状态,应该是控制手机热点(猜测)
 
CHANGE_WIFI_STATE 控制WiFi开关,改变WiFi状态
 
DISABLE_KEYGUARD 改变键盘为不可用
 
EXPAND_STATUS_BAR 扩展bar的状态
 
GET_PACKAGE_SIZE 获取应用安装包大小
 
INTERNET 网络权限
 
KILL_BACKGROUND_PROCESSES 杀死后台进程
 
MODIFY_AUDIO_SETTINGS 改变音频输出设置
 
NFC 支付
 
READ_SYNC_SETTINGS 获取手机设置信息
 
READ_SYNC_STATS 数据统计
 
RECEIVE_BOOT_COMPLETED 监听启动广播
 
REORDER_TASKS 创建新栈
 
REQUEST_INSTALL_PACKAGES 安装应用程序
 
SET_TIME_ZONE 允许应用程序设置系统时间区域
 
SET_WALLPAPER 设置壁纸
 
SET_WALLPAPER_HINTS 设置壁纸上的提示信息,个性化语言
 
TRANSMIT_IR 红外发射
 
USE_FINGERPRINT 指纹识别
 
VIBRATE 震动
 
WAKE_LOCK 锁屏
 
WRITE_SYNC_SETTINGS 改变设置
 
SET_ALARM 设置警告提示
 
INSTALL_SHORTCUT 创建快捷方式
 
UNINSTALL_SHORTCUT 删除快捷方式



官方demo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值