You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android 7下JNI调用open()打开USB摄像头设备FD失败的解决咨询

解决Android 7+下直接访问/dev/video设备节点失败的问题

首先,你遇到的核心问题是Android 7.0及以上版本的安全机制升级,导致普通应用无法直接访问/dev/video*设备节点——即便修改了文件权限也不行,具体原因有两个:

  1. SELinux强制访问控制(MAC):Android 7+默认开启SELinux Enforcing模式,文件权限(DAC)的优先级低于SELinux规则。普通应用的进程域(untrusted_app)被禁止访问video_device类型的字符设备,这是chmod 666无效、canRead()返回false的根本原因。
  2. 应用沙箱隔离:Android 7+进一步强化了应用沙箱,限制普通应用直接操作系统级设备节点,强制使用官方API交互。

既然你明确Camera2 API无法满足参数控制需求,下面给出几种可行的解决途径:

途径一:临时/永久调整SELinux策略(需Root权限)

临时调试方案

在Root权限下执行以下命令关闭SELinux,重启后失效,适合快速验证:

su -c setenforce 0

执行后再运行你的应用,应该能正常打开/dev/video节点。

永久解决方案(定制ROM/设备)

如果是你自己定制的ROM,可以添加自定义SELinux规则,允许普通应用访问视频设备节点:

  1. 创建一个SELinux策略文件(比如my_app_video.te),内容如下:
    allow untrusted_app video_device:chr_file rw_file_perms;
    allow untrusted_app video_device:chr_file ioctl;
    
  2. 将该文件编译成SELinux policy模块,刷入设备的SELinux策略目录(通常是/system/etc/selinux/),然后重启设备。

途径二:将应用升级为系统应用(需系统签名/定制ROM)

如果你的应用是为特定设备开发的,可以将其设置为系统应用:

  1. AndroidManifest.xml中添加系统用户ID:
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.your.package"
        android:sharedUserId="android.uid.system">
    
  2. 使用设备厂商的系统密钥对应用进行签名。
  3. 将APK安装到/system/app//system/priv-app/目录下。

系统应用的进程域是system_app,默认拥有访问/dev/video节点的权限,无需修改SELinux规则或文件权限。

途径三:通过系统级代理服务间接控制(推荐,无需应用Root)

如果无法将应用设为系统应用,也不想修改SELinux规则,可以实现一个系统级代理服务

  1. 编写一个运行在系统进程(比如system_server)或拥有系统权限的独立进程的服务,该服务负责直接与/dev/video节点交互,处理对比度、增益等参数的ioctl调用。
  2. 应用通过Binder IPC与这个代理服务通信,发送参数控制指令,由代理服务代为执行底层操作。

这种方式既避免了应用直接访问设备节点,又能满足你对摄像头参数的精细控制需求,是合规的Android 7+开发方式。

补充验证:检查设备节点的SELinux上下文

你可以在Root终端执行以下命令查看/dev/video0的SELinux上下文:

ls -Z /dev/video0

输出类似:

crw-rw---- root       video          u:object_r:video_device:s0 /dev/video0

其中u:object_r:video_device:s0是该节点的类型,普通应用的untrusted_app域默认没有访问这个类型的权限,这也验证了之前的原因分析。

内容的提问来源于stack exchange,提问作者mikero

火山引擎 最新活动