android 實現framework和底層C/C++通訊

最近接到一個需求,要在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 
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章