Android6.0 init.rc更改

本文介绍如何在Android设备上设置开机启动C程序的方法。通过修改init.rc文件,并将可执行程序放置在特定路径下,实现开机自动运行指定的C程序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题:刚接触android驱动,需要开机启动一个C程序。

答:修改init.rc文件,开机时候执行守护进程方式运行。

问题:init.rc文件在哪?

答:在开发过程中用的是天嵌提供的源码包,init.rc源文件在out/target/product/sabresd_6dq/root/目录下。


在android源码目录下进行boot.img编译就ok,他会从新生成ramdisk.img,并打包成boot.img,有朋友好奇为什么要这么麻烦,直接在原有基础上更改ramdisk.img,再手动打包boot.img就好了。

为什么不那么做的原因有两个:1、如果不修改init.rc源码,下次编译就会被覆盖,每次自己手动打包boot.img很麻烦。

      2、手动打包的boot.img启动不起来啊,查找ramdisk.img失败。



1) 把可执行程序放在/system/bin/目录下。

2) 在init.rc中增加如下代码:

service 自己取的服务名 /system/bin/可执行文件名
	class main
	user root
	oneshot


<think>我们正在解决Android应用中串口通信打开失败的问题,错误信息为“java.io.IOException: Cannot open port”或“打开串口失败”。根据引用[2]和引用[4],我们知道在Android上进行串口通信通常需要JNI层的支持,并且涉及到设备节点的访问权限问题。同时,引用[1]和引用[5]提到了蓝牙通信中的类似错误,但串口通信的问题更偏向于设备节点和权限。 结合之前回答中的原因分析,我们可以总结如下: 1. 权限问题:串口设备节点(如/dev/ttyS1)的访问权限不足,或者应用没有获得访问硬件的权限。 2. 设备节点不存在或路径错误:尝试打开的串口设备节点路径错误。 3. 端口被占用:该串口已经被其他进程打开。 4. 硬件或驱动问题:串口硬件故障或驱动未加载。 下面我们针对这些原因逐一提供解决方法: ### 1. 检查并设置串口设备节点的权限 在Android中,串口设备节点通常位于`/dev`目录下,如`/dev/ttyS0`、`/dev/ttyS1`等。默认情况下,这些节点的权限可能只允许root用户或某些系统用户组访问。因此,我们需要确保应用有权限访问这些节点。 **方法一:修改设备节点权限(需要root权限)** 在应用打开串口之前,尝试修改设备节点的权限为666(即所有用户可读写)。可以通过以下代码尝试(需要root权限): ```java try { // 修改设备节点权限 Process su = Runtime.getRuntime().exec("su"); DataOutputStream outputStream = new DataOutputStream(su.getOutputStream()); outputStream.writeBytes("chmod 666 " + device.getAbsolutePath() + "\n"); outputStream.flush(); outputStream.writeBytes("exit\n"); outputStream.flush(); su.waitFor(); } catch (Exception e) { e.printStackTrace(); } ``` **方法二:在JNI层打开串口时设置权限** 在JNI层,我们可以使用`open`函数打开设备节点,并在打开之前尝试设置权限。但是,如果没有root权限,这种方法可能不可行。因此,通常的做法是确保设备在启动时就有正确的权限(通过init.rc配置)。 **方法三:使用具有权限的应用程序** 对于系统应用,可以在AndroidManifest.xml中声明共享用户ID并签名,或者将应用放入系统分区(需要系统签名)。 ### 2. 确认设备节点路径 不同的设备,串口设备节点可能不同。常见的节点有: - `/dev/ttyS0`、`/dev/ttyS1` ...(通常用于嵌入式系统) - `/dev/ttyMT0`、`/dev/ttyMT1` ...(MTK平台) - `/dev/ttyHSL0`、`/dev/ttyHSL1` ...(高通平台) 可以通过以下方式获取设备上的串口节点: ```java File devDir = new File("/dev"); File[] files = devDir.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.startsWith("ttyS") || name.startsWith("ttyMT") || name.startsWith("ttyHSL"); } }); // 遍历files,得到所有可能的串口设备节点 ``` 或者使用ADB命令查看: ```bash adb shell ls /dev/ttyS* adb shell ls /dev/ttyMT* adb shell ls /dev/ttyHSL* ``` ### 3. 检查端口是否被占用 如果串口已经被其他进程打开,那么再次打开就会失败。确保在打开串口之前,没有其他应用或服务在使用同一个串口。如果之前打开过,请确保在不需要时关闭串口。 ### 4. 检查硬件连接和驱动 确保串口硬件连接正常。如果是USB转串口,需要确认USB转串口的驱动已经加载。可以通过ADB执行`dmesg`命令查看内核日志,确认串口设备是否被正确识别。 ### 5. 使用成熟的串口库 考虑使用已经成熟的串口库,如[mik3y/usb-serial-for-android](https://github.com/mik3y/usb-serial-for-android),该库支持多种USB转串口芯片,并且处理了权限和节点问题。 ### 6. JNI层代码问题 如果使用了自己的JNI代码(如SerialPort类),那么需要检查JNI层的实现。通常,打开串口的代码类似于: ```c JNIEXPORT jobject JNICALL Java_com_example_SerialPort_open (JNIEnv *env, jobject thiz, jstring path, jint baudrate) { int fd; const char *path_utf = (*env)->GetStringUTFChars(env, path, NULL); fd = open(path_utf, O_RDWR | O_NOCTTY | O_NDELAY); (*env)->ReleaseStringUTFChars(env, path, path_utf); if (fd == -1) { // 抛出异常 jclass exception = (*env)->FindClass(env, "java/io/IOException"); (*env)->ThrowNew(env, exception, "Cannot open port"); return NULL; } // 配置串口(波特率、数据位、停止位、校验位等) // ... return fd; } ``` 确保JNI代码正确,并且编译后的so库被正确打包到APK中。 ### 7. 动态权限申请(针对Android 6.0以上) 虽然串口通信通常不需要Android运行时权限(因为不是危险权限),但如果是通过USB转串口,可能需要USB设备权限。因此,在打开USB设备时,需要请求用户授权。可以参考[usb-serial-for-android](https://github.com/mik3y/usb-serial-for-android)中的权限处理。 ### 具体步骤 1. **确认设备节点存在且权限正确**:通过ADB检查。 2. **在代码中动态修改权限(如果可能)**:使用root命令修改。 3. **使用正确的节点路径**:根据设备平台选择。 4. **确保串口未被占用**:在打开前关闭其他可能占用串口的程序。 5. **检查JNI代码**:确保打开串口的JNI函数正确。 6. **使用日志调试**:在JNI层添加日志,确认open函数的返回值及错误码(errno)。 通过以上步骤,应该能够解决大部分串口打开失败的问题。 如果问题仍然存在,可能需要设备厂商提供支持,因为有些设备可能对串口访问有特殊限制。 最后,根据引用[3]和引用[4],如果无法解决,可能需要考虑自己编写或使用其他JNI库。 下面是一个简单的串口打开工具类,包含了修改权限的尝试: ```java public class SerialPortHelper { private static final String TAG = "SerialPortHelper"; public SerialPort open(String path, int baudrate) { // 先尝试修改权限 chmod(path, 666); try { return new SerialPort(new File(path), baudrate, 0); } catch (IOException e) { Log.e(TAG, "Failed to open serial port: " + path, e); return null; } } private void chmod(String path, int mode) { try { File device = new File(path); if (!device.exists()) { Log.e(TAG, "Device node not exists: " + path); return; } // 执行chmod命令 Process su = Runtime.getRuntime().exec("su"); DataOutputStream outputStream = new DataOutputStream(su.getOutputStream()); outputStream.writeBytes("chmod " + Integer.toString(mode, 8) + " " + path + "\n"); outputStream.flush(); outputStream.writeBytes("exit\n"); outputStream.flush(); su.waitFor(); } catch (Exception e) { Log.e(TAG, "chmod failed", e); } } } ``` 注意:执行`su`命令需要设备已经root,并且应用有root权限。 如果设备没有root,那么需要寻找其他方法,比如让系统在启动时设置好串口节点的权限(修改init.rc),或者使用系统签名来提升应用权限。 希望这些方法能够帮助你解决问题。 §§相关问题§§ 1. 如何在Android设备上获取root权限? 2. 如何为Android应用进行系统签名? 3. Android串口通信中如何配置波特率等参数? 4. 如何通过ADB调试Android串口?</think>### Android 串口通信打开失败解决方案(java.io.IOException) 以下是针对串口打开失败问题的系统性解决方案,结合设备权限、硬件配置和代码调试三个维度: #### 1. **权限配置方案** ```java // 动态申请USB权限(Android 6.0+) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (checkSelfPermission(Manifest.permission.USB_PERMISSION) != PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.USB_PERMISSION}, REQUEST_CODE); } } // 在JNI层修改设备权限(需root) public native void chmodDevice(String path); ``` ```c // SerialPort.c (JNI实现) JNIEXPORT void JNICALL Java_com_example_SerialPort_chmodDevice(JNIEnv *env, jobject obj, jstring path) { const char *dev_path = (*env)->GetStringUTFChars(env, path, 0); chmod(dev_path, 0666); // 设置读写权限 (*env)->ReleaseStringUTFChars(env, path, dev_path); } ``` **关键步骤**: 1. 在`AndroidManifest.xml`添加: ```xml <uses-permission android:name="android.permission.USB_PERMISSION"/> <uses-feature android:name="android.hardware.usb.host"/> ``` 2. 通过ADB验证节点权限: ```bash adb shell ls -l /dev/ttyS* # 查看设备权限 adb shell su -c "chmod 666 /dev/ttyS1" # 临时修改权限 ``` #### 2. **设备节点确认** ```java // 扫描可用串口设备 public List<String> findSerialPorts() { List<String> devices = new ArrayList<>(); File devDir = new File("/dev"); File[] files = devDir.listFiles(); for (File file : files) { if (file.getName().matches("ttyS[0-9]+") || file.getName().matches("ttyUSB[0-9]+")) { devices.add(file.getAbsolutePath()); } } return devices; } ``` **常见设备路径**: - 主板原生串口:`/dev/ttyS0`~`/dev/ttyS4` - USB转串口:`/dev/ttyUSB0` - 蓝牙串口:`/dev/rfcomm0` #### 3. **端口占用处理** ```java // 确保单例打开和及时关闭 private SerialPort mSerialPort; public void openPort(String path) throws IOException { if (mSerialPort != null) { mSerialPort.close(); // 先关闭已占用端口 } mSerialPort = new SerialPort(new File(path), 9600, 0); } ``` #### 4. **硬件驱动检查** 通过ADB验证驱动状态: ```bash adb shell dmesg | grep -i "usb\|serial" # 正常输出示例: # [ 5.132] usb 1-1: FTDI USB Serial Device converter detected # [ 5.150] ftdi_sio 1-1:1.0: ttyUSB0 detected ``` #### 5. **JNI层调试(关键步骤)** 根据引用[4]的指引: 1. 生成JNI头文件: ```bash cd app/build/intermediates/javac/debug/classes javah -jni com.silan.robotpeisongcontrl.utils.SerialPort ``` 2. 检查`SerialPort.c`中的`open`实现: ```c fd = open(path_utf, O_RDWR | O_NOCTTY | O_NDELAY); // 关键参数 if (fd == -1) { throwIOException(env, "Cannot open port"); // 此处抛出异常 } ``` 3. 添加错误码记录: ```c if (fd == -1) { char buf[256]; snprintf(buf, sizeof(buf), "Open failed: %s (errno=%d)", strerror(errno), errno); throwIOException(env, buf); } ``` #### 6. **替代方案:使用成熟开源库** 在`build.gradle`添加: ```gradle implementation 'com.github.mik3y:usb-serial-for-android:3.4.3' ``` 使用示例: ```java UsbSerialPort port = UsbSerialProber.getDefaultProber().openDevice(usbManager, device); port.open(connection); port.setParameters(9600, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE); ``` ### 常见错误码解析 | 错误码 | 含义 | 解决方案 | |--------|---------------------|------------------------------| | EACCES (13) | 权限不足 | 执行chmod 666或动态授权 | | ENOENT (2) | 设备节点不存在 | 检查路径或加载驱动 | | EBUSY (16) | 端口被占用 | 关闭其他进程或重启设备 | | EIO (5) | I/O硬件错误 | 检查线缆/接口连接状态 | > **硬件调试提示**:使用示波器检查串口信号电平,确认波特率匹配(常见值:9600/115200),并检查RTS/CTS硬件流控信号[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值