最近接到一個需求,要在framework中添加一些上層接口給客戶調用,然後在framework中調用C中的代碼實現和硬件一些數據交互。framework和C交互肯定想到的使用jni,但是和硬件交互的時候需要執行一些shell命令,必須要root權限才能執行成功,如果在framework中使用jni,顯然無法達到我們想要的效果,後來就換了種方式實現,使用localscoket來實現,在系統添加一個服務,然後在init.rc中配置root權限,最終在這個服務中實現C代碼。代碼如下:
framework爲服務端:
private class ServerSocket implements Runnable {
private boolean keepRunning = true;
private LocalServerSocket serverSocket;
private String socketName;
InputStream inputStream = null;
public ServerSocket(String socketName) {
this.socketName = socketName;//這個名字必須和底層socket的名字一樣
Log.e("HarryCan", "socketName : " + socketName );
}
public void stopScoket() {
keepRunning = false;
if (serverSocket != null) {
try {
serverSocket.close();
serverSocket = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void run() {
try {
serverSocket = new LocalServerSocket(socketName);
} catch (IOException e) {
e.printStackTrace();
keepRunning = false;
}
Log.e(TAG, socketName + " wait for new client coming !");
try {
LocalSocket interactClientSocket = serverSocket.accept();
if (keepRunning) {
Log.e(TAG, socketName + " new client coming !");
try {
inputStream = interactClientSocket.getInputStream();
byte[] buf = new byte[1024];
int readBytes = -1;
while ((readBytes = inputStream.read(buf)) != -1 && keepRunning) {
// buff is the result
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
keepRunning = false;
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Log.e(TAG, socketName + " finish running !");
}
}
開啓線程既可以開啓服務端。
系統服務客戶端代碼:
導入頭文件:#include <sys/socket.h>//socket相關
#include <pthread.h>//線程相關
//socketName必須和服務端相同,獲取到socket句柄fd
int fd = socket_local_client(socketName, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
因爲要不斷的把從硬件採集到的數據返回的上層api,所以這裏開了一個線程來把數據寫入到socket,然後在framework中接收:
Param *param = new Param();//結構體傳參
param->s = s;
param->frame = frame;
pthread_t thread_id;
pthread_create( &thread_id, NULL, &threadFunc, param);
void *threadFunc(void *data) {
ALOGE(" threadFunc enter in");
int nbytes;
Param *param = (Param *)data;
int s = param->s;
struct can_frame frame = param->frame;
char dest[20];
while(openCanFlag) {
nbytes = read(s, &frame, sizeof(frame));//循環獲取數據,這裏通過一個socekt從硬件獲取,不關注
//對數據做轉化
if (nbytes > 0) {
char a,b,c,d;
a=(char)(frame.can_id&0xff);
b=(char)((frame.can_id&0xff00)>>8);
c=(char)((frame.can_id&0xff0000)>>16);
d=(char)((frame.can_id&0xff000000)>>24);
frame.can_id=(a<<24)|(b<<16)|(c<<8)|d;
memcpy(&dest[0], (char*)&frame.can_id, sizeof(__u32));
for(int i = 0; i < frame.can_dlc; i++){
dest[i+4] = frame.data[i];
}
//將轉化後的數據寫入到socekt,並在framework接收
write(fd, dest, sizeof(dest));
}
}
ALOGE("threadFunc startCanSocket loop end");
close(s);
pthread_exit(0);
return NULL;
}
然後還有一種,framework做客戶端,C代碼做服務端也一併實現:
framework做客戶端:
private OutputStream mOutputStream;
private LocalSocket socket;
private void listenToSocket(String socketName) throws IOException {
try {
socket = new LocalSocket();
socket.connect(new LocalSocketAddress(socketName));
mOutputStream = socket1.getOutputStream();
Log.e(TAG, socketName + " connect to server ");
} catch (IOException ex) {
Log.e(TAG, socketName + " listenToSocket error : " + ex.toString());
}
}
private void closeSocket() throws IOException {
if (mOutputStream1!= null) {
try {
mOutputStream.close();
} catch (IOException e) {
Log.e(TAG, " Failed closing output stream write_uart1_rt_socket");
}
mOutputStream = null;
}
try {
if (socket != null) {
socket.close();
}
} catch (IOException ex) {
Log.e(TAG, " Failed closing socket : write_uart1_rt_socket");
}
}
private void initSocketClient(final String socketName) {
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
try {
listenToSocket(socketName);
} catch (Exception e) {
Log.e(TAG, socketName + " Error listenToSocket : " + e.toString());
}
}
}).start ();
}
//發送數據到服務端
public void writeGPSUart1Data(byte[] data) throws Exception {
mOutputStream.write(data);
mOutputStream.flush();
Log.e(TAG, "write flush data end ");
}
系統服務中C代碼實現服務端:
//獲取socket句柄,socketName必須和客戶端保持一致
int uart2_fd = socket_local_server(socketName, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
pthread_t thread_id_2;
pthread_create( &thread_id_2, NULL, &threadUart2Func, NULL);//開啓線程接受數據
void *thread2Func(void *data) {
ALOGE("threadUart2Func enter in");
char buf2[512] = {0};
int socketID = accept(uart2_fd,NULL,NULL);//等待客戶端連接
int ret;
while((ret = read(socketID,buf2,sizeof(buf2))) >=0){//循環讀取數據
int result = uart2_write(buf2,ret);
if(isInitGPSModule == 0){
ALOGE("thread2Func exit thread\n");
close(uart2_fd);
pthread_exit(0);
}
}
ALOGE("thread2Func loop end\n");
close(uart2_fd);
pthread_exit(0);
return ((void *)data);
}
服務端必須在客戶端連接之前先初始化,否則客戶端無法連接。
在工作中遇到的問題做下簡單記錄,如果有錯誤,歡迎大家指正,謝謝!
---------------------
作者:abs625
來源:CSDN
原文:https://blog.csdn.net/abs625/article/details/79492934
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!