串口api供app层调用"/>
Android11.0封装串口api供app层调用
Android11.0封装串口api供app层调用
- RK3568 Android11.0串口服务
- 自定义服务中封装串口服务
- 添加权限
- SDK中添加上层应用调用API
RK3568 Android11.0串口服务
Android11.0已自带串口服务,官方demo在frameworks/base/tests/SerialChat
自定义服务中封装串口服务
如上目录,对SerialManager、SerialPort进行封装:
- hardware/SerialHelper.java
import android.content.Context;
import android.hardware.SerialPort;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.hardware.SerialManager;
import android.hardware.SerialPort;
import android.os.ServiceManager;
import android.util.ArrayMap;
import android.hardware.ISerialManager;
import android.util.Log;import java.io.IOException;import com.yjz.demo.hardware.serial.SerialImpl;
import com.yjz.demo.hardware.serial.ISerial;public final class SerialHelper {private static final String TAG = SerialHelper.class.getSimpleName();private Context mContext;private SerialManager mSerialManager;public SerialHelper(Context context) {this.mContext = context;mSerialManager = (SerialManager) context.getSystemService(Context.SERIAL_SERVICE);}public ISerial createSerial() {return new SerialImpl(mSerialManager);}
}
- /hardware/serial/ISerial.java;
import java.io.IOException;public interface ISerial {void open(String name, int speed, SerialCallback callback) throws IOException;void write(byte[] buffer);void close();void release();
}
- /hardware/serial/SerialCallback.java
public interface SerialCallback {void onRead(byte[] buffer);
}
- /hardware/serial/SerialImpl.java
import android.hardware.SerialManager;
import android.hardware.SerialPort;
import android.util.Log;import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;public final class SerialImpl implements ISerial {private static final String TAG = SerialImpl.class.getSimpleName();private String mName;private int mSpeed;private SerialCallback mCallback;private SerialPort mSerialPort;private SerialManager mSerialManager;private volatile boolean mIsClose;public SerialImpl(SerialManager serialManager) {mSerialManager = serialManager;}@Overridepublic void open(String name, int speed, SerialCallback callback) throws IOException {mCallback = callback;mSerialPort = mSerialManager.openSerialPort(name, speed);if (null == mSerialPort) {throw new IOException("Could not open serial port " + name);}Log.d(TAG, "serial open success");mIsClose = false;new Thread() {@Overridepublic void run() {Log.d(TAG, "serial read thread run " + Thread.currentThread().getName());int ret = 0;ByteBuffer inputBuffer = ByteBuffer.allocate(1024);byte[] buffer = new byte[1024];while (ret >= 0) {if (mIsClose) {Log.d(TAG, "serial had close " + Thread.currentThread().getName());break;}try {
// Log.d(TAG, "calling read");inputBuffer.clear();ret = mSerialPort.read(inputBuffer);
// Log.d(TAG, "serial read returned " + ret + " " + Thread.currentThread().getName());inputBuffer.get(buffer, 0, ret);byte[] rtArray = Arrays.copyOf(buffer, ret);if (null != mCallback && ret > 0) {mCallback.onRead(rtArray);}} catch (Exception e) {Log.w(TAG, "serial read failed " + Thread.currentThread().getName(), e);break;} }Log.d(TAG, "serial read thread out" + Thread.currentThread().getName());}}.start();}@Overridepublic void write(byte[] buffer) {if (null != buffer && buffer.length > 0) {ByteBuffer outputBuffer = ByteBuffer.allocate(buffer.length);outputBuffer.put(buffer);if (null != mSerialPort) {try {mSerialPort.write(outputBuffer, buffer.length);} catch (Exception e) {Log.e(TAG, "serial write fail ", e);}} else {Log.d(TAG, "serial had close");}} else {Log.d(TAG, "serial no write data");}}@Overridepublic void close() {Log.d(TAG, "serial close");mIsClose = true;if (mSerialPort != null) {try {mSerialPort.close();} catch (IOException e) {e.printStackTrace();}mSerialPort = null;}if (null != mCallback) {mCallback = null;}}@Overridepublic void release() {Log.d(TAG, "serial release");close();mSerialManager = null;}
}
- 修改SerialService /frameworks/base/services/core/java/com/android/server/SerialService.java;
SerialService服务默认只允许系统app调用,第三方应用调用,需要删除权限检查语句;
默认串口设置号是从/frameworks/base/core/res/values/config.xml文件中定义的config_serialPorts数组中获取,这里修改成上层调用者传入;
public String[] getSerialPorts() {
// 注释掉权限检查语句
// mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SERIAL_PORT, null);ArrayList<String> ports = new ArrayList<String>();for (int i = 0; i < mSerialPorts.length; i++) {String path = mSerialPorts[i];if (new File(path).exists()) {ports.add(path);}}String[] result = new String[ports.size()];ports.toArray(result);return result;}public ParcelFileDescriptor openSerialPort(String path) {
// 注释掉权限检查,设备号使用传入参数
// mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SERIAL_PORT, null);
// for (int i = 0; i < mSerialPorts.length; i++) {
// if (mSerialPorts[i].equals(path)) {
// return native_open(path);
// }
// }
// throw new IllegalArgumentException("Invalid serial port " + path);return native_open(path);}
- 修改android_hardware_SerialPort /frameworks/base/core/jni/android_hardware_SerialPort.cpp;
默认串口的read方法等待读取最少字符模式,此模式下当关闭串口时,读线程无法立即退出,在次获取串口后,读方法会报一次错,需要修改为读取超时模式;
static void
android_hardware_SerialPort_open(JNIEnv *env, jobject thiz, jobject fileDescriptor, jint speed)//*****省略代码******/* no timeout but request at least one character per read *///默认为://tio.c_cc[VTIME] = 0;//tio.c_cc[VMIN] = 1;//修改为:tio.c_cc[VTIME] = 1;//1 * 100毫秒tio.c_cc[VMIN] = 0;//*****省略代码******
}
- 自定义服务中添加获取串口接口对象的方法:
public ISerial createSerial() {return mSerialHelper.createSerial();}
- 修改hiddenapi-greylist-packages.txt,
/frameworks/base/config/hiddenapi-greylist-packages.txt,
默认添加的类及方法都是隐藏api,上层应用无法直接调用,需要在文件中添加相应包名:
com.yjz.demo//只包括包下的类文件,子包不包含,需要单独声明,如下
com.yjz.demo.hardware.serial
添加权限
- 添加SEAndroid权限,文件路径:
/device/rockchip/rk356x/sepolicy_vendor/serial.te
allow untrusted_app serial_device:chr_file { open read write ioctl};
- 为串口设备添加权限,文件路径:
/device/rockchip/rk356x/init.rk356x.rc
on boot//****省略代码chmod 0777 /dev/ttyS3chmod 0777 /dev/ttyS4chmod 0777 /dev/ttyS5chmod 0777 /dev/ttyS7chmod 0777 /dev/ttyS8chmod 0777 /dev/ttyS9
SDK中添加上层应用调用API
SDK最终编译成jar包,供应用导入调用相关api。
SDK中目录如上:
- /sdk/api/serial/ImplSerial.java
import com.yjz.demo.DemoManager;
import java.io.IOException;public final class ImplSerial implements ISerial {private static final String TAG = ImplSerial.class.getSimpleName();private String mName;private int mSpeed;private com.yjz.demo.hardware.serial.ISerial mISerial;public ImplSerial(DemoManager manager) {mISerial = manager.createSerial();}@Overridepublic void open(String name, int speed, SerialListener listener) throws IOException {mISerial.open(name, speed, new com.yjz.demo.hardware.serial.SerialCallback() {@Overridepublic void onRead(byte[] buffer) {if (null != listener) {listener.onRead(buffer);}}});}@Overridepublic void write(byte[] buffer) {mISerial.write(buffer);}@Overridepublic void close() {mISerial.close();}@Overridepublic void release() {mISerial.release();mISerial = null;}
}
- /sdk/api/serial/Iserial.java
import java.io.IOException;public interface ISerial {void open(String name, int speed, SerialListener listener) throws IOException;void write(byte[] buffer);void close();void release();
}
- /sdk/api/serial/SerialListener.java
public interface SerialListener {void onRead(byte[] buffer);
}
- /sdk/api/ImplIApi.java
import android.content.Context;
import com.yjz.demo.DemoManager;
import com.yjz.sdk.api.gpio.Gpio;
import com.yjz.sdk.api.serial.ISerial;
import com.yjz.sdk.api.serial.ImplSerial;final class ImplIApi implements IApi {private DemoManager mDemoManager;public ImplIApi(Context context) {mDemoManager = (DemoManager) context.getSystemService(Context.DEMO_SERVICE);}@Overridepublic Gpio createGpio(int gpioNum) {return new Gpio(mDemoManager, gpioNum);}@Overridepublic boolean setRelay(int type, String value) {return mDemoManager.writeRelayValue(type, value);}@Overridepublic ISerial createSerial() {return new ImplSerial(mDemoManager);}
}
更多推荐
Android11.0封装串口api供app层调用
发布评论