文章目录
1. 涉及到的文件
framework下的:
./base/tests/SerialChat/src/com/android/serialchat/SerialChat.java 测试类
主要以下几个文件:
1. ./base/core/java/android/hardware/SerialManager.java
2. ./base/services/java/com/android/server/SerialService.java
3. ./base/core/java/android/hardware/SerialPort.java
4. ./base/core/jni/android_hardware_SerialPort.cpp
5. ./base/services/jni/com_android_server_SerialService.cpp
还有一个aidl文件
2. 从测试类开始
主要是以下调用:
private SerialManager mSerialManager = (SerialManager)getSystemService(Context.SERIAL_SERVICE);
String[] ports = mSerialManager.getSerialPorts();
private SerialPort mSerialPort = mSerialManager.openSerialPort(ports[0], 115200);
2.1.获取服务类
2.2调用方法:getSerialPorts,
即从xml文件中得到设置的字符串.
2.3.打开串口:
public class SerialManager {
public String[] getSerialPorts() {
return mService.getSerialPorts();
}
public SerialPort openSerialPort(String name, int speed) {
ParcelFileDescriptor pfd = mService.openSerialPort(name);
if (pfd != null) {
SerialPort port = new SerialPort(name);
port.open(pfd, speed);
return port;
}
}
}
其中:
2.3.1 openSerialPort打开串口,得到描述符
private final ISerialManager mService;
ParcelFileDescriptor pfd = mService.openSerialPort(name);
会调用到服务程序SerialService:
./base/services/java/com/android/server/SerialService.java
public class SerialService extends ISerialManager.Stub {
public ParcelFileDescriptor openSerialPort(String path) {
for (int i = 0; i < mSerialPorts.length; i++) {
if (mSerialPorts[i].equals(path)) {
return native_open(path);
}
}
}
private native ParcelFileDescriptor native_open(String path);
}
进而调用native方法,返回一个串口的文件描述符:
- ./base/services/jni/com_android_server_SerialService.cpp:
- com/android/server/SerialService :
static jobject android_server_SerialService_open(JNIEnv *env, jobject thiz, jstring path)
{
const char *pathStr = env->GetStringUTFChars(path, NULL);
int fd = open(pathStr, O_RDWR | O_NOCTTY);
if (fd < 0) {
ALOGE("could not open %s", pathStr);
env->ReleaseStringUTFChars(path, pathStr);
return NULL;
}
env->ReleaseStringUTFChars(path, pathStr);
jobject fileDescriptor = jniCreateFileDescriptor(env, fd);
if (fileDescriptor == NULL) {
return NULL;
}
return env->NewObject(gParcelFileDescriptorOffsets.mClass,
gParcelFileDescriptorOffsets.mConstructor, fileDescriptor);
}
static JNINativeMethod method_table[] = {
{ "native_open", "(Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;",
(void*)android_server_SerialService_open },
};
2.3.2. 构造SerialPort对象
SerialPort port = new SerialPort(name);
port.open(pfd, speed);
public class SerialPort {
public void open(ParcelFileDescriptor pfd, int speed) throws IOException {
native_open(pfd.getFileDescriptor(), speed);
mFileDescriptor = pfd;
}
private native void native_open(FileDescriptor pfd, int speed) throws IOException;
}
调用JNI:
- android/hardware/SerialPort
- {“native_open”, “(Ljava/io/FileDescriptor;I)V”, (void *)android_hardware_SerialPort_open},
android_hardware_SerialPort_open(JNIEnv *env, jobject thiz, jobject fileDescriptor, jint speed)
{
int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
// 将fd设置到context field,后面读写要用
env->SetIntField(thiz, field_context, fd);
//设置波特率等参数,串口的常规操作
tcsetattr(fd, TCSANOW, &tio);
tcflush(fd, TCIFLUSH);
}
3.总结调用流程:
private SerialManager mSerialManager;
./base/core/java/android/hardware/SerialManager.java
public SerialPort openSerialPort(String name, int speed)
mService.openSerialPort(name);//通过名字得到fd
/*服务进程:*/
./base/services/java/com/android/server/SerialService.java
ParcelFileDescriptor openSerialPort(String path)
native_open(path);
./base/services/jni/com_android_server_SerialService.cpp
com/android/server/SerialService
native_open : android_server_SerialService_open(JNIEnv *env, jobject thiz, jstring path)
SerialPort port = new SerialPort(name);
port.open(pfd, speed);
native_open(pfd.getFileDescriptor(), speed);
./base/core/jni/android_hardware_SerialPort.cpp
android/hardware/SerialPort
native_open: android_hardware_SerialPort_open(JNIEnv *env, jobject thiz, jobject fileDescriptor, jint speed)
后续的读写就是用拿到的服务进程的fd去操作了.