摄像头和麦克风的使用日志管控方案

一、 实现原理

1.1 前言

  首先,我们来看一下需求:

  1. 显示最近的摄像头和麦克风使用日志信息;
  2. 当使用摄像头和麦克风时,提示用户什么应用正在使用什么设备。

  然后,根据我们的需求使用场景,我们知道要实现对摄像头和麦克风的使用日志管控,就意味着我们至少要做到以下2点:

  1. 获取第三方应用是否允许使用设备的信息;
  2. 获取第三方应用使用设备的时间点

  于是,我们通过使用和借鉴外国开发者的Access Dots应用,发现可以通过系统提供的设备使用回调以及辅助服务一起实现以上需求,那下面就让我们一起来看看具体的实现方案吧。

1.2 辅助服务AccessibilityService

  下面我们可以先来了解一下Android提供的辅助服务AccessibilityService,官方文档描述如下:
在这里插入图片描述
  大意如下:

辅助服务仅应用于协助残障用户使用Android设备和应用。它们在后台运行,并在AccessibilityEvent被触发时接收系统的回调。这样的事件表示用户界面中的一些状态转换,例如,焦点已更改,按钮被单击等。此类服务可以可选地请求查询活动窗口内容的功能。辅助服务的开发需要扩展此类并实现其抽象方法。

辅助服务的生命周期仅由系统管理,并遵循已建立的服务生命周期。用户仅在设备设置中显式打开该服务才能触发启动无障碍服务。系统绑定到服务后,它将调用AccessibilityService#onServiceConnected()。想要执行绑定后设置的客户端可以覆盖此方法。

当用户在设备设置中将其关闭或调用时,可访问性服务将停止AccessibilityService#disableSelf()。

  我们发现可以通过继承AccessibilityService,实现onServiceConnected方法,以达到开机启动后台运行,监控应用界面,可以做到协助实现实时监控摄像头和麦克风的使用情况

1.3 摄像头和麦克风设备使用回调

1.3.1 摄像头设备使用回调

  CameraManager可以注册一个回调registerAvailabilityCallback,有2个方法:void onCameraAvailable(@NonNull String cameraId) 和 void onCameraUnavailable(@NonNull String cameraId),在摄像头调用和结束使用时回调。不过这里的回调参数只有cameraId,没有关于当前是哪个应用在调用和结束使用摄像头的信息,所以这里需要借助辅助服务去实现,这个问题我们先放在这,在下一章节中再继续探索。

1.3.2 麦克风设备使用回调

  AudioManager可以注册一个回调registerAudioRecordingCallback,有1个方法:void onRecordingConfigChanged(List configs),在麦克风设备状态改变时回调。这里不同于摄像头设备使用回调的是,回调参数configs是可以获取到,当前是哪个应用在调用和结束使用麦克风的信息,在“麦克风的使用日志管控方案”章节中会讲到如何获取应用信息。

二、摄像头的使用日志管控方案

  上面我们提到了,摄像头的使用日志管控方案需要辅助服务和注册回调共同实现,那么我们是怎么做的呢,下面来看一看。

2.1 继承AccessibilityService

  首先,我们需要继承辅助服务AccessibilityService,TCLDevicesUsedManagerService并实现下面三个方法:

  • void onAccessibilityEvent(AccessibilityEvent event):接收到系统发送AccessibilityEvent时的回调
  • void onInterrupt():服务中断时的回调
  • void onServiceConnected():系统成功绑定该服务时被触发,也就是当你在设置中开启相应的服务,系统成功的绑定了该服务时会触发,通常我们可以在这里做一些初始化操作

2.2 开启后台服务AudioCameraListenerService

  然后,我们需要注册摄像头的回调,这里需要思考一个问题,在哪里注册回调。通过分析需求我们知道,我们的应用应该是要常驻内存,所以开启一个后台Service去做这件事是一个可选的方案。于是在onServiceConnected回调时我们开启了一个后台服务AudioCameraListenerService,在这里面我们去注册摄像头的回调监听。

2.3 自定义广播通信CameraListenerReceiver

  接下来,回到之前遗留的问题,在接收到摄像头调用和结束使用时回调时,我们如何判断是哪个应用的。这里我们采取了一个适中的方式,不太精准但能满足大部分需求,下面来看看:

1、首先我们在摄像头onCameraAvailable 和 onCameraUnavailable回调时,分别发送摄像头可用和不可用的广播;

2、在“onServiceConnected回调时我们开启了一个后台服务AudioCameraListenerService”的同时再注册了一个自定义广播CameraListenerReceiver,广播的构造方法中传入实现辅助服务的对象TCLDevicesUsedManagerService,在广播中处理摄像头回调时触发的广播;

3、辅助服务有一个方法getRootInActiveWindow,它可以获取当前活动窗口中的根节点,得到对象AccessibilityNodeInfo,该对象可以获取到包名getPackageName()。

  到这里获取到包名,就能获取到该包名所对应应用的其他信息了。实现原理即是:使用摄像头时,通过摄像头使用的回调监听触发时机,获取当前活动窗口的根节点,进而获取到包名。

  :这里会有一个隐藏的风险,当应用在后台偷偷开启摄像头时,那么获取到的包名就不对了,这是个风险点,后文也会去记录的。

三、麦克风的使用日志管控方案

  麦克风的使用日志管控方案就简单多了,因为系统提供的回调已经能满足我们的需求,不需要再像摄像头一样依赖辅助服务了,下面来看一看。

3.1 注册回调registerAudioRecordingCallback

1、我们知道了此回调只有一个方法,一个参数“List configs”,当“configs.size() == 0”时,表示没有正在录音的应用,就可以作为应用停止录音的标志;反之,当“configs.size() != 0”时,可以作为应用开始录音的条件之一;

2、通过AudioRecordingConfiguration.toLogFriendlyString(config),我们可以打印关于录音的一些信息,包括包名;

3、通过判断“config.getClientAudioSource() == MediaRecorder.AudioSource.MIC”为true时,作为录音开始的时机点;进而可以通过getClientPackageName()方法获取到包名。

  :toLogFriendlyString是隐藏api、getClientPackageName是系统api,所以为了编译成功,需要在本地重写类android.media.AudioRecordingConfiguration以及用到的三个方法:toLogFriendlyString、getClientAudioSource、getClientPackageName。

四、风险性

4.1 风险考虑

4.1.1 开机自启以后就能实时监听摄像头和麦克风吗?

  已自测,是的。

4.1.2 应用被杀掉时,摄像头和麦克风会有设备使用结束的回调吗?

  已自测,麦克风有结束回调,摄像头没有结束回调(eg:比如录音宝和美图秀秀可以回调麦克风结束,美图秀秀和美颜相机等不能回调摄像头结束,美图秀秀是即使用了摄像头又使用了麦克风)
  摄像头没有结束回调的原因:应用被杀时,摄像头像麦克风一样也是有回调触发的,但是此时辅助服务getRootInActiveWindow()获取到的AccessibilityNodeInfo为空,就无法知晓包名,于是不能判断是哪个应用结束的摄像头使用。

4.1.3 后台调用摄像头时,会有摄像头使用记录回调吗?

  已自测,有摄像头使用和结束的回调,但是有一个bug(现在的实现方式是:在接收到摄像头使用和回收时,是获取当前Window应用的包名,所以会导致获取到当前使用和回收摄像头的应用不准确),使用“Access Dots应用”验证后台Camera打开时获取到的应用名也不对。

4.1.4 麦克风使用时,其他应用也申请使用会出现异常吗?

  已自测,其他应用不能使用麦克风,也不会有麦克风设备使用结束和开始的回调(eg:正在使用录音宝app录音时,打开美图秀秀的拍照功能adb shell am start com.mt.mtxx.mtxx/com.mt.mtxx.mtxx.TopViewActivity,美图秀秀不能使用到麦克风的功能)。

4.1.5 后台调用麦克风时,会有麦克风使用记录回调吗?

  已自测,有麦克风使用和结束的回调。

4.2 风险点

  • 麦克风方案:可以不依赖辅助服务,目前暂未发现风险点;
  • 摄像头方案:目前实现方案依赖辅助服务,而且后台调用摄像头设备时获取到的应用信息会存在误差,这是个风险点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值