如题:java.io.FileNotFoundException: /proc/tty/drivers: read failed: EACCES Permission denied
问题的出现
在使用Google开源的串口库时,其中有一个类是去扫描节点文件的这个文件叫SerialPortFinder,它会去专门扫描一个路径 /proc/tty/drivers,如果是在Android低版本下有读写存储权限且路径 /proc/tty/drivers 权限大于等于666时,基本上都是可以直接扫描到 /dev/tty 这些路径节点的,但是如果在Android高版本时,因为SELinux的加入导致大多数涉及串口开发的应用都会碰壁,本章博客就告诉你为什么在系统权限都赋予的情况下,为什么依旧还是报错
Android高版本权限处理
private void checkExternalPermission() {
Log.e(TAG, "checkExternalPermission Build.VERSION.SDK_INT = " + Build.VERSION.SDK_INT);
//Android 6.0 (23) 之上 Android 11 (30) 以下申请权限
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
if (checkAllPermissionGranted(permissions, this)) {
jumpToMainActivity();
} else {
ActivityCompat.requestPermissions(this, permissions, requestExternalPermission);
}
}
//Android11申请权限
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
//判断是否有管理外部存储的权限
if (!Environment.isExternalStorageManager()) {
Log.e(TAG, "MANAGE_EXTERNAL_STORAGE DENIED...");
goManagerFileAccess();
return;
}
Log.e(TAG, "MANAGE_EXTERNAL_STORAGE GRANTED...");
jumpToMainActivity();
}
}
上述代码区分了Android11和Android11之下的权限申请问题,只是为说明问题而写请不要copy使用!因为还有Android10和9等等一些版本也要区别对待,否则有可能会报错!
意思是在11之下申请所需要的权限就行了,11之后需要手动去设置给与manager权限,当你拿到权限之后以为可以读写串口了,但你错了,这并不会使你成功
你会得到如下log日志信息:
2023-07-06 21:35:14.963 3630-3630/com.licheedev.serialtool W/edev.serialtool: type=1400 audit(0.0:91): avc: denied { read } for name="drivers" dev="proc" ino=4026531853 scontext=u:r:system_app:s0 tcontext=u:object_r:proc_tty_drivers:s0 tclass=file permissive=0
2023-07-06 21:35:14.967 3630-3630/com.licheedev.serialtool W/System.err: java.io.FileNotFoundException: /proc/tty/drivers: open failed: EACCES (Permission denied)
2023-07-06 21:35:14.971 3630-3630/com.licheedev.serialtool W/System.err: at libcore.io.IoBridge.open(IoBridge.java:492)
2023-07-06 21:35:14.971 3630-3630/com.licheedev.serialtool W/System.err: at java.io.FileInputStream.<init>(FileInputStream.java:160)
2023-07-06 21:35:14.971 3630-3630/com.licheedev.serialtool W/System.err: at java.io.FileInputStream.<init>(FileInputStream.java:115)
2023-07-06 21:35:14.971 3630-3630/com.licheedev.serialtool W/System.err: at java.io.FileReader.<init>(FileReader.java:58)
2023-07-06 21:35:14.971 3630-3630/com.licheedev.serialtool W/System.err: at android.serialport.SerialPortFinder.getDrivers(SerialPortFinder.java:71)
2023-07-06 21:35:14.972 3630-3630/com.licheedev.serialtool W/System.err: at android.serialport.SerialPortFinder.getAllDevicesPath(SerialPortFinder.java:114)
2023-07-06 21:35:14.972 3630-3630/com.licheedev.serialtool W/System.err: at com.licheedev.serialtool.activity.MainActivity.initDevice(MainActivity.java:107)
2023-07-06 21:35:14.972 3630-3630/com.licheedev.serialtool W/System.err: at com.licheedev.serialtool.activity.MainActivity.onCreate(MainActivity.java:76)
2023-07-06 21:35:14.972 3630-3630/com.licheedev.serialtool W/System.err: at android.app.Activity.performCreate(Activity.java:8000)
2023-07-06 21:35:14.973 3630-3630/com.licheedev.serialtool W/System.err: at android.app.Activity.performCreate(Activity.java:7984)
2023-07-06 21:35:14.973 3630-3630/com.licheedev.serialtool W/System.err: at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
2023-07-06 21:35:14.974 3630-3630/com.licheedev.serialtool W/System.err: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
2023-07-06 21:35:14.974 3630-3630/com.licheedev.serialtool W/System.err: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
2023-07-06 21:35:14.974 3630-3630/com.licheedev.serialtool W/System.err: at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
2023-07-06 21:35:14.974 3630-3630/com.licheedev.serialtool W/System.err: at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
2023-07-06 21:35:14.974 3630-3630/com.licheedev.serialtool W/System.err: at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
2023-07-06 21:35:14.975 3630-3630/com.licheedev.serialtool W/System.err: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
2023-07-06 21:35:14.975 3630-3630/com.licheedev.serialtool W/System.err: at android.os.Handler.dispatchMessage(Handler.java:106)
2023-07-06 21:35:14.975 3630-3630/com.licheedev.serialtool W/System.err: at android.os.Looper.loop(Looper.java:223)
2023-07-06 21:35:14.976 3630-3630/com.licheedev.serialtool W/System.err: at android.app.ActivityThread.main(ActivityThread.java:7656)
2023-07-06 21:35:14.976 3630-3630/com.licheedev.serialtool W/System.err: at java.lang.reflect.Method.invoke(Native Method)
2023-07-06 21:35:14.976 3630-3630/com.licheedev.serialtool W/System.err: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
2023-07-06 21:35:14.977 3630-3630/com.licheedev.serialtool W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
2023-07-06 21:35:14.978 3630-3630/com.licheedev.serialtool W/System.err: Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied)
2023-07-06 21:35:14.978 3630-3630/com.licheedev.serialtool W/System.err: at libcore.io.Linux.open(Native Method)
2023-07-06 21:35:14.978 3630-3630/com.licheedev.serialtool W/System.err: at libcore.io.ForwardingOs.open(ForwardingOs.java:166)
2023-07-06 21:35:14.978 3630-3630/com.licheedev.serialtool W/System.err: at libcore.io.BlockGuardOs.open(BlockGuardOs.java:254)
2023-07-06 21:35:14.979 3630-3630/com.licheedev.serialtool W/System.err: at libcore.io.ForwardingOs.open(ForwardingOs.java:166)
2023-07-06 21:35:14.979 3630-3630/com.licheedev.serialtool W/System.err: at android.app.ActivityThread$AndroidOs.open(ActivityThread.java:7542)
2023-07-06 21:35:14.979 3630-3630/com.licheedev.serialtool W/System.err: at libcore.io.IoBridge.open(IoBridge.java:478)
此时你肯定很疑惑,为什么权限都有了还报没有权限的错误,现在请看下面这段Log
2023-07-06 21:35:14.963 3630-3630/com.licheedev.serialtool W/edev.serialtool: type=1400 audit(0.0:91): avc: denied { read } for name="drivers" dev="proc" ino=4026531853 scontext=u:r:system_app:s0 tcontext=u:object_r:proc_tty_drivers:s0 tclass=file permissive=0
此段log为系统SELinux报的错误,当然要想解决还得从系统上解决
问题的解决
首先你得要熟悉系统SELinux代码和配置,找到安全规则和权限配置文件后,需要添加如下权限给
/proc/tty/drivers
allow system_app proc_tty_drivers:file { read write open getattr };
如笔者的配置则在/device/&{product}/&{board}/common/sepolicy/system_app.te
allow system_app serial_device:chr_file rw_file_perms;
allow system_app tty_device:chr_file { read write ioctl open };
allow system_app vendor_cusdata_file:dir { search getattr open read };
allow system_app vendor_cusdata_file:file { getattr open read write};
allow system_app tv_certificate_file:dir { search getattr read };
allow system_app tv_certificate_file:file { getattr open read write};
allow system_app apk_data_file:dir { search getattr read };
allow system_app apk_data_file:file { getattr open read write};
allow mediaserver vendor_cusdata_file:file { getattr open read };
allow system_app serial_device:chr_file { read write open ioctl};
# give /proc/tty/drivers read write open getattr permission
allow system_app proc_tty_drivers:file { read write open getattr };
这里笔者介绍一些语法的意义,该段规则为允许系统级app 对 /proc/tty/drivers 进行 read write open getattr 操作,请大家一定要把这些权限加上
缺 read 权限时,报错:
java.io.FileNotFoundException: /proc/tty/drivers: read failed: EACCES (Permission denied)
缺 open 权限时,报错:
java.io.FileNotFoundException: /proc/tty/drivers: open failed: EACCES (Permission denied)
缺 getattr 权限时,报错:
java.io.FileNotFoundException: /proc/tty/drivers: fstat failed: EACCES (Permission denied)
除write权限可选之外,其他3个权限必须要给予!否则都会报错!
题外拓展
上述 te 文件中 allow 后面的 system_app 为系统及 app,何为系统app呢,就是原生framework下的一些系统级app,当然还有后期内置的有系统签名的app,在 selinux 中app主要分为三大类,按照权限高低分别是 system_app 、platform_app、untrusted_app
system_app :拥有系统权限、系统签名、当AndroidManifest.xml中申明persistent时可以生效
platform_app:没有系统权限、系统签名、当AndroidManifest.xml中申明android:sharedUserId=“android.uid.system” 时也可以生效为系统app(需要再配置mk文件),当app为系统级时,此种方式可以不用push直接studio run apk就可以安装到系统并且具有系统权限,做系统开发时非常的方便
untrusted_app:没有系统权限、没有系统签名、来自第三方的app(安装此类型app需要在开发者中关闭USB安装授权,否则安装不了)
三方app如何具备系统签名
1.首先需要下载一个工具,keytool-importkeypair-master
2.下载完后进行解压,然后进入系统根目录下 build/target/product/security
3. 拷贝 platform.x509.pem、platform.pk8 两个文件到2步骤解压的目录下
4.执行命令(需要linux环境,如果没有可以使用Git的Open Git Bash here) keytool-importkeypair -k [jks文件名] -p [jks的密码] -pk8 platform.pk8 -cert platform.x509.pem -alias [jks的别名]
5.将生成的jks拷贝到Android studio中并且配置gradle文件
解压目录图示:
拷贝至Android studio中图示:
配置gradle文件图示:
继续处理权限问题
当配置完 te 的权限问题后,全编系统代码待系统编译完后烧录固件查看效果
可以看到我们的app已经可以正常操作 /proc/tty/drivers 了,也读取到了 /dev/tty 的各个节点文件
原创不易,希望各位老板点赞关注!后续会更加努力创作!