在android 系统中,有大量的地方使用socket进行通信,例如phone进程的RIL.java和rild守护进程之间的通信。
因此,本文实现一个简单的系统apk和native守护进程,实现socket通信。本篇文章基于android 6.0。
目标:
1,写一个简单的系统apk,native守护进程;
2,实现socket通信
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);// 发送消息给客户端
具体实现的过程请看下面。
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守护进程就会启动。
以下操作每个手机厂商可能都不一样,路径也不同。
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
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守护进程进行通信了。