android 6.0 Java层和native守护进程socket通信

在android 系统中,有大量的地方使用socket进行通信,例如phone进程的RIL.java和rild守护进程之间的通信。

因此,本文实现一个简单的系统apk和native守护进程,实现socket通信。本篇文章基于android 6.0。

目标:

1,写一个简单的系统apk,native守护进程;

2,实现socket通信

1, 概念

Java主要代码

client = new LocalSocket();  
address = new LocalSocketAddress(SOCKET_NAME, LocalSocketAddress.Namespace.RESERVED);
client.connect(address);//连接socket
mIn = mSocket.getInputStream();//输入流 发送数据到socket
mOut = mSocket.getOutputStream();//输出流 从socket中读取数据

native层主要代码

s_fdListen = android_get_control_socket(SOCKET_NAME);//获取socket
ret = listen(s_fdListen, n); //监听客户端
s_fdCommand = accept(s_fdListen, (sockaddr *)&peeraddr, &socklen);//等待Socket客户端发启连接请求
recv(new_fd,buff,sizeof(buff),0)); //接收客户端从socket发过来的数据
send(new_fd,buff,strlen(buff),0);// 发送消息给客户端

具体实现的过程请看下面。

2,守护进程

1, 配置init.rc,在该文件中添加以下代码,

service myguardservice /system/bin/myguardservice
   class main
   socket myguard stream 0660 root system

2,在frameworks/native/cmds/路径下添加 myguardservice文件夹,当然这条路径可以不一样。

首先添加myguard_service.c文件,内容如下,

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define SOCKET_NAME "myguard"
#define  LOG_TAG    "myguardservice "
#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

int main(){
    char log[200]; 
    LOGI("main");
    int connect_number = 6;
    int fdListen = -1, new_fd = -1;
    int ret;
    struct sockaddr_un peeraddr;
    socklen_t socklen = sizeof (peeraddr);
    int numbytes ;
    char buff[256];
    fdListen = android_get_control_socket(SOCKET_NAME);
    if (fdListen < 0) {
    sprintf(log,"Failed to get socket '" SOCKET_NAME "' errno:%d", errno);
    __android_log_write(ANDROID_LOG_DEBUG,"FTM_JNI",log); 
    LOGI("main listen exit ");
    exit(-1);
    }
    ret = listen(fdListen, connect_number);    

    sprintf(log,"Listen result %d",ret);
    __android_log_write(ANDROID_LOG_DEBUG,"FTM_JNI",log); 

    if (ret < 0) {
        perror("listen");
        exit(-1);
    }


    new_fd = accept(fdListen, (struct sockaddr *) &peeraddr, &socklen);
    sprintf(log,"Accept_fd %d",new_fd);
    __android_log_write(ANDROID_LOG_DEBUG,"FTM_JNI",log); 
    if (new_fd < 0 ) {
        sprintf(log,"%d",errno);
        __android_log_write(ANDROID_LOG_DEBUG,"FTM_JNI",log); 
        perror("accept error");
        exit(-1);
    }

    while(1){
    __android_log_write(ANDROID_LOG_DEBUG,"FTM_JNI","Waiting for receive");
    if((numbytes = recv(new_fd,buff,sizeof(buff),0))==-1){
        sprintf(log,"%d",errno);
        __android_log_write(ANDROID_LOG_DEBUG,"FTM_JNI",log); 
        perror("recv");
        continue;
    }

    if(send(new_fd,buff,strlen(buff),0)==-1)
    {
        perror("send");
        close(new_fd);
        exit(0);
    }       
    }
    LOGI("main close ");
    close(new_fd);
    close(fdListen);
    return 0;
}

然后添加Android.mk文件,内容如下,

LOCAL_PATH:= $(call my-dir)
svc_c_flags =	\
	-Wall -Wextra \
ifneq ($(TARGET_USES_64_BIT_BINDER),true)
ifneq ($(TARGET_IS_64_BIT),true)
svc_c_flags += -DBINDER_IPC_32BIT=1
endif
endif

include $(CLEAR_VARS)
LOCAL_SHARED_LIBRARIES := liblog libselinux
LOCAL_SRC_FILES := myguard_service.c
LOCAL_CFLAGS += $(svc_c_flags)
LOCAL_MODULE := myguardservice
include $(BUILD_EXECUTABLE)

这样,编译刷入版本开机启动之后, myguardservice守护进程就会启动。

3 socket权限

以下操作每个手机厂商可能都不一样,路径也不同。

Socket通信的实质也是对文件的读写,

首先在device/qcom/sepolicy/common/ 路径下添加myguard.te文件,内容如下,

#myguard
allow myguard_socket myguard_socket:sock_file create_file_perms; 
type_transition myguard_socket socket_device:sock_file myguard_socket;

然后在device/qcom/sepolicy/common/的file_contexts文件中添加

/dev/socket/myguard                             u:object_r:myguard_socket:s0

在device/qcom/sepolicy/common/file.te中添加

type myguard_socket, file_type;

最后设置权限:

在device/qcom/sepolicy/common/system_app.te 中添加

allow system_app myguard_socket:sock_file rw_file_perms;

在device/qcom/sepolicy/common/system_server.te中添加

allow system_server myguard_socket:sock_file rw_file_perms;

编译刷入版本开机启动之后,在dev/ socket路径下出现myguard

4 Java层

Java客户端核心代码如下,

import java.io.BufferedReader;  
import java.io.IOException;  
import java.io.InputStreamReader;  
import java.io.PrintWriter;  
  
import android.net.LocalSocket;  
import android.net.LocalSocketAddress;  
import android.util.Log;  
  
public class SocketClient {  
    private final String SOCKET_NAME = "htfsk";  
    private LocalSocket client;  
    private LocalSocketAddress address;  
    private boolean isConnected = false;  
    private int connetTime = 1;  
  
    public SocketClient() {  
        client = new LocalSocket();  
        address = new LocalSocketAddress(SOCKET_NAME, LocalSocketAddress.Namespace.RESERVED);  
        new ConnectSocketThread().start();  
    }  
  
    /** 
     * 发送消息 
     * @param msg 
     * @return 返回Socket服务端的消息回执 
     */  
    public String sendMsg(String msg) {  
        if (!isConnected) {  
            return "Connect fail";  
        }  
        try {  
            BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));  
            PrintWriter out = new PrintWriter(client.getOutputStream());  
            out.println(msg);  
            out.flush();  
            return in.readLine();  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
        return "Nothing return";  
    }  
  
    /** 
     * 异步连接Socket,如果连接不上会尝试重复连接十次 
     *  
     */  
    private class ConnectSocketThread extends Thread {  
        @Override  
        public void run() {  
            while (!isConnected && connetTime <= 10) {  
                try {  
                    sleep(1000);  
                    Log.i("SocketClient","Try to connect socket;ConnectTime:"+connetTime);  
                    client.connect(address);  
                    isConnected = true;  
                } catch (Exception e) {  
                    connetTime++;  
                    isConnected = false;  
                    Log.i("SocketClient","Connect fail");  
                }  
            }  
        }  
    }  
  
    /** 
     * 关闭Socket 
     */  
    public void closeSocket() {  
        try {  
            client.close();  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  
  
}

将包含该代码的apk放到/packages/apps目录下,在AndroidManifest.xml文件中添加

android:sharedUserId="android.uid.system"

最后将该apk内置为系统的apk就可以和myguardservice守护进程进行通信了。

你可能感兴趣的:(---【实践】)