背景

  • Platform: IMX6Q
  • OS: Android5.1
  • Kernel: 3.14.52

需求

项目需求,有些功能需要root权限,但是以前做的系统没有添加su权限进去,所以就另辟蹊径用了这个办法。

实现

底层init启动一个service,主要是实现一个socket服务端,监听客户端发过来的命令,然后执行它。虽然apk与该service在不同的空间,有不同的权限,但底层init启动的service具有root权限

Service服务端实现

源代码大致如下

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <cutils/sockets.h>
#include <sys/un.h> 
#include <netinet/in.h>

#define LOG_TAG "root_proxy"
#define LOG_NDEBUG 0

#include <utils/Log.h>


int main(int argc, char **argv)
{
    	int client_fd = -1;
    	int server_fd;

again: 
	server_fd = android_get_control_socket("root_proxy");

    	listen(server_fd, 5);
    	fcntl(server_fd, F_SETFD, FD_CLOEXEC);
    	ALOGV("listen");
    	
    	while (1) {
    		int ret;
    		char buf[128];

    		if (client_fd == -1) {
    			struct sockaddr addr;
    			socklen_t alen = sizeof(addr);

    			client_fd = accept(server_fd, &addr, &alen); 
    			ALOGV("client connect:%s", strerror(errno));
			if (client_fd == -1) {
				close(server_fd);
				goto again;
			}
    			fcntl(client_fd, F_SETFD, FD_CLOEXEC);
    		}
    		
    		memset(buf, 0, 128);
    		ret = read(client_fd, buf, 128);
    		if (ret == 0) {
    			ALOGV("client exit");
                	close(client_fd);
    			client_fd = -1;
    		} else if (ret > 0) {
    			ALOGV("buf=%s", buf);
			
    			system(buf);
		    }
    	}

	return 0;
}

如果需要返回结果,可使用管道,重定向,大致代码如下:

strlcat(recv_buf, " 2>&1", sizeof(recv_buf));
FILE	*fp = popen(recv_buf, "r");
if (!fp) {
    ALOGE("exec command failed. (%d)\n", -errno);
    close(sock_client);
    continue;
}
while (fgets(send_buf, sizeof(send_buf), fp)) {
    ALOGI("Send %d bytes: %s\n", strlen(send_buf), send_buf);
    len = send(sock_client, send_buf, strlen(send_buf), 0);
    if (len < (int)strlen(send_buf)) {
        ALOGE("send failed. (%d)\n", len);
        break;
    }
}

添加到编译环境

可参考:https://notes.z-dd.online/2019/12/02/Android源码添加自己的可执行程序/
将该Service添加到external

添加init自启动

在系统对应的init.rc里面添加:

service root_proxy /system/bin/root_proxy
	class main
	socket root_proxy stream 777 root radio

APK客户端实现

大致代码如下:

LocalSocket mSocket = new LocalSocket();
LocalSocketAddress address = new LocalSocketAddress("root_proxy", 
LocalSocketAddress.Namespace.RESERVED);
if (mSocket != null){
    try
    {
        mSocket.connect(address);  	
    
        OutputStream mOutputStream = mSocket.getOutputStream();
        mOutputStream.write((cmd).getBytes());
        mOutputStream.flush();
        mOutputStream.close();
        
        mSocket.close();
        Log.i(ConstVar.PORDUCT_NAME, "WriteToRild: " + cmd);
    } catch (IOException e) {
        e.printStackTrace();
    }
}
mSocket = null;	

try {
    Thread.sleep(150);
} catch (InterruptedException e) {
    e.printStackTrace();
}      

参考

  1. https://blog.csdn.net/sgmenghuo/article/details/48996369