普通Socket通信
客户端代码:
unix_client.c

#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <signal.h> 
#define MAXLINE 80
 
char *client_path = "client-socket";
char *server_path = "server-socket";
 
int main() {
	struct  sockaddr_un cliun, serun;
	int len;
	char buf[100];
	int sockfd, n;
 
	if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
		perror("client socket error");
		exit(1);
	}
//    signal(SIGPIPE, SIG_IGN);	
    memset(&serun, 0, sizeof(serun));
    serun.sun_family = AF_UNIX;
    strncpy(serun.sun_path,server_path ,
                   sizeof(serun.sun_path) - 1);
    if (connect(sockfd, (struct sockaddr *)&serun, sizeof(struct sockaddr_un)) < 0){
    	perror("connect error");
    	exit(1);
    }
    printf("please input send char:");
    while(fgets(buf, MAXLINE, stdin) != NULL) {  
         write(sockfd, buf, strlen(buf));
         n = read(sockfd, buf, MAXLINE);  
         if ( n <= 0 ) {  
            printf("the other side has been closed.\n");
            break;
         }else {  
            printf("received from server: %s \n",buf);
         }
         printf("please input send char:");
    }
    printf("end server  date"); 
    close(sockfd);
    return 0;
}

服务端代码:
unix_server.c

#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h> 
 
#define MAXLINE 80
 
char *socket_path = "server-socket";
 
int main()
{
    struct sockaddr_un serun, cliun;
    socklen_t cliun_len;
    int listenfd, connfd, size;
    char buf[MAXLINE];
    int i, n;
 
    if ((listenfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
        perror("socket error");
        exit(1);
    }
 
    memset(&serun, 0, sizeof(serun));
    serun.sun_family = AF_UNIX;
    strncpy(serun.sun_path,socket_path ,
                   sizeof(serun.sun_path) - 1);
    unlink(socket_path);
    if (bind(listenfd, (struct sockaddr *)&serun, sizeof(struct sockaddr_un)) < 0) {
        perror("bind error");
        exit(1);
    }
    printf("UNIX domain socket bound\n");
    
    if (listen(listenfd, 20) < 0) {
        perror("listen error");
        exit(1);        
    }
    printf("Accepting connections ...\n");
 
    while(1) {
        cliun_len = sizeof(cliun);       
        if ((connfd = accept(listenfd, (struct sockaddr *)&cliun, &cliun_len)) < 0){
            perror("accept error");
            continue;
        }
	printf("new client connect to server,client sockaddr === %s \n",((struct sockaddr *)&cliun)->sa_data);        
        while(1) {
	    memset(buf,0,sizeof(buf));
            n = read(connfd, buf, sizeof(buf));
            if (n < 0) {
                perror("read error");
                break;
            } else if(n == 0) {
                printf("EOF\n");
                break;
            }
            
            printf("received: %s %d %d\n ", buf, sizeof(buf),sizeof("quit"));
	    if (strncmp(buf,"quit",4) == 0) {
		break;
            } 
            for(i = 0; i < n; i++) {
                buf[i] = toupper(buf[i]);
            }
            write(connfd, buf, n);
        }
        close(connfd);
    }
    close(listenfd);
    return 0;
}

epoll代码:
真实的场景很可能有很多个客户端连接服务端,那这个时候服务端 是怎么做到和客户端同时通信的呢? I/O 多路复用技术(I/O multiplexing)。复用是指在同一个进程(线程)中,处理多路 I/O,多路指多个文件描述符。它核心思想收集进程感兴趣的全部描述符,然后调用一个函数,当这些描述符中的一个或多个准备好 I/O 时,函数返回并告知进程是哪些描述符准备好了。此时进程只需要去这些准备好的描述符上操作即可。

服务端代码:

#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/epoll.h>
#define MAXLINE 80

char *socket_path = "server-socket";

int main()
{
    struct sockaddr_un serun, cliun;
    socklen_t cliun_len;
    int listenfd, connfd, size;
    char buf[MAXLINE];
    int i, n;

    if ((listenfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
        perror("socket error");
        exit(1);
    }

    memset(&serun, 0, sizeof(serun));
    serun.sun_family = AF_UNIX;
    strncpy(serun.sun_path,socket_path ,
                   sizeof(serun.sun_path) - 1);
    unlink(socket_path);
    if (bind(listenfd, (struct sockaddr *)&serun, sizeof(struct sockaddr_un)) < 0) {
        perror("bind error");
        exit(1);
    }
    printf("UNIX domain socket bound\n");

    if (listen(listenfd, 20) < 0) {
        perror("listen error");
        exit(1);
    }
    printf("Accepting connections ...\n");
     // 4. 创建epoll树
    int epfd = epoll_create(1000);
    if(epfd == -1)
    {
        perror("epoll_create");
        exit(-1);
    }
    //5、将用于监听的lfd挂的epoll树上(红黑树)
    struct epoll_event ev;//这个结构体记录了检测什么文件描述符的什么事件
    ev.events = EPOLLIN;
    ev.data.fd = listenfd;
    epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev);//ev里面记录了检测lfd的什么事件
    // 循环检测 委托内核去处理
    struct epoll_event events[1024];//当内核检测到事件到来时会将事件写到这个结构体数组里


    while(1) {
        int num = epoll_wait(epfd, events, sizeof(events)/sizeof(events[0]), -1);//最后一个参数                                                                                                                                              表示阻塞
        for (int i = 0;i<num;i++) {
            if(events[i].data.fd == listenfd)//有连接请求到来
            {

                int len = sizeof(cliun);
                int connfd = accept(listenfd, (struct sockaddr *)&cliun, &len);
                if(connfd == -1)
                {
                    perror("accept");
                    exit(-1);
                }
                printf("a new client connected! \n");
                //将用于通信的文件描述符挂到epoll树上
                ev.data.fd = connfd;
                ev.events = EPOLLIN;
                epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev);
            } else {
                 //通信也有可能是写事件
                if(events[i].events & EPOLLOUT)
                {
                    //这里先忽略写事件
                    continue;
                }
                char buf[1024]={0};
                int count = read(events[i].data.fd, buf, sizeof(buf));
                if(count == 0)//客户端关闭了连接
                {
                    printf("客户端关闭了连接。。。。\n");
                    //将对应的文件描述符从epoll树上取下
                    close(events->data.fd);
                    epoll_ctl(epfd, EPOLL_CTL_DEL, events->data.fd, NULL);
                }
                else
                {
                    if(count == -1)
                    {
                        perror("read");
                        exit(-1);
                    }
                    else
                    {
                        //正常通信
                        printf("client say: %s\n" ,buf);
                        write(events[i].data.fd, buf, strlen(buf)+1);
                    }
                }

            }

        }
    }
    close(listenfd);
    return 0;
}

客户端代码:

#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#define MAXLINE 80

char *client_path = "client-socket";
char *server_path = "server-socket";

int main() {
        struct  sockaddr_un cliun, serun;
        int len;
        char buf[100];
        int sockfd, n;

        if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
                perror("client socket error");
                exit(1);
        }
//    signal(SIGPIPE, SIG_IGN);
    memset(&serun, 0, sizeof(serun));
    serun.sun_family = AF_UNIX;
    strncpy(serun.sun_path,server_path ,
                   sizeof(serun.sun_path) - 1);
    if (connect(sockfd, (struct sockaddr *)&serun, sizeof(struct sockaddr_un)) < 0){
        perror("connect error");
        exit(1);
    }
    printf("please input send char:");
    while(fgets(buf, MAXLINE, stdin) != NULL) {
         write(sockfd, buf, strlen(buf));
         n = read(sockfd, buf, MAXLINE);
         if ( n <= 0 ) {
            printf("the other side has been closed.\n");
            break;
         }else {
            printf("received from server: %s \n",buf);
         }
         printf("please input send char:");
    }
    printf("end server  date");
    close(sockfd);
    return 0;
}


Socket让app实现shell命令行执行
在这里插入图片描述
找到一个有执行shell权限的程序,然后和这个程序进行一个跨进程通信,app把要执行的命令发送给这个高权限的程序,程序就会执行app发送过来的命令,这个时候再跨进程返回结果给app既可以;
在这里插入图片描述
MyApplicationB就是我们普通第三方程序

rootServer就是我们写的native执行,负责和MyApplicationB进行通信和执行shell命令

adbd就是负责来拉起rootServer

具体实现步骤:
主要把main.cpp覆盖到项目的:system/core/adb/daemon/main.cpp 然后在重新编译系统:make
其实这里核心就修改了一句代码而已:
StartSubprocess("./system/bin/rootServer", nullptr, SubprocessType::kRaw,
SubprocessProtocol::kNone);

/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define TRACE_TAG ADB

#include "sysdeps.h"

#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <sys/prctl.h>

#include <memory>

#include <android-base/logging.h>
#include <android-base/macros.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <libminijail.h>
#include <log/log_properties.h>
#include <scoped_minijail.h>

#include <private/android_filesystem_config.h>
#include "debuggerd/handler.h"
#include "selinux/android.h"

#include "adb.h"
#include "adb_auth.h"
#include "adb_listeners.h"
#include "adb_utils.h"
#include "transport.h"
#include "shell_service.h"
#include "mdns.h"

static const char* root_seclabel = nullptr;

static void drop_capabilities_bounding_set_if_needed(struct minijail *j) {
#if defined(ALLOW_ADBD_ROOT)
    if (__android_log_is_debuggable()) {
        return;
    }
#endif
    minijail_capbset_drop(j, CAP_TO_MASK(CAP_SETUID) | CAP_TO_MASK(CAP_SETGID));
}

static bool should_drop_privileges() {
#if defined(ALLOW_ADBD_ROOT)
    // The properties that affect `adb root` and `adb unroot` are ro.secure and
    // ro.debuggable. In this context the names don't make the expected behavior
    // particularly obvious.
    //
    // ro.debuggable:
    //   Allowed to become root, but not necessarily the default. Set to 1 on
    //   eng and userdebug builds.
    //
    // ro.secure:
    //   Drop privileges by default. Set to 1 on userdebug and user builds.
    bool ro_secure = android::base::GetBoolProperty("ro.secure", true);
    bool ro_debuggable = __android_log_is_debuggable();

    // Drop privileges if ro.secure is set...
    bool drop = ro_secure;

    // ... except "adb root" lets you keep privileges in a debuggable build.
    std::string prop = android::base::GetProperty("service.adb.root", "");
    bool adb_root = (prop == "1");
    bool adb_unroot = (prop == "0");
    if (ro_debuggable && adb_root) {
        drop = false;
    }
    // ... and "adb unroot" lets you explicitly drop privileges.
    if (adb_unroot) {
        drop = true;
    }

    return drop;
#else
    return true; // "adb root" not allowed, always drop privileges.
#endif // ALLOW_ADBD_ROOT
}

static void drop_privileges(int server_port) {
    ScopedMinijail jail(minijail_new());

    // Add extra groups:
    // AID_ADB to access the USB driver
    // AID_LOG to read system logs (adb logcat)
    // AID_INPUT to diagnose input issues (getevent)
    // AID_INET to diagnose network issues (ping)
    // AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
    // AID_SDCARD_R to allow reading from the SD card
    // AID_SDCARD_RW to allow writing to the SD card
    // AID_NET_BW_STATS to read out qtaguid statistics
    // AID_READPROC for reading /proc entries across UID boundaries
    // AID_UHID for using 'hid' command to read/write to /dev/uhid
    gid_t groups[] = {AID_ADB,          AID_LOG,          AID_INPUT,    AID_INET,
                      AID_NET_BT,       AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW,
                      AID_NET_BW_STATS, AID_READPROC,     AID_UHID};
    minijail_set_supplementary_gids(jail.get(), arraysize(groups), groups);

    // Don't listen on a port (default 5037) if running in secure mode.
    // Don't run as root if running in secure mode.
    if (should_drop_privileges()) {
        drop_capabilities_bounding_set_if_needed(jail.get());

        minijail_change_gid(jail.get(), AID_SHELL);
        minijail_change_uid(jail.get(), AID_SHELL);
        // minijail_enter() will abort if any priv-dropping step fails.
        minijail_enter(jail.get());

        D("Local port disabled");
    } else {
        // minijail_enter() will abort if any priv-dropping step fails.
        minijail_enter(jail.get());

        if (root_seclabel != nullptr) {
            if (selinux_android_setcon(root_seclabel) < 0) {
                LOG(FATAL) << "Could not set SELinux context";
            }
        }
        std::string error;
        std::string local_name =
            android::base::StringPrintf("tcp:%d", server_port);
        if (install_listener(local_name, "*smartsocket*", nullptr, 0, nullptr, &error)) {
            LOG(FATAL) << "Could not install *smartsocket* listener: " << error;
        }
    }
}

static void setup_port(int port) {
    local_init(port);
    setup_mdns(port);
}

int adbd_main(int server_port) {
    umask(0);

    signal(SIGPIPE, SIG_IGN);

    init_transport_registration();

    // We need to call this even if auth isn't enabled because the file
    // descriptor will always be open.
    adbd_cloexec_auth_socket();

    if (ALLOW_ADBD_NO_AUTH && !android::base::GetBoolProperty("ro.adb.secure", false)) {
        auth_required = false;
    }

    adbd_auth_init();

    // Our external storage path may be different than apps, since
    // we aren't able to bind mount after dropping root.
    const char* adb_external_storage = getenv("ADB_EXTERNAL_STORAGE");
    if (adb_external_storage != nullptr) {
        setenv("EXTERNAL_STORAGE", adb_external_storage, 1);
    } else {
        D("Warning: ADB_EXTERNAL_STORAGE is not set.  Leaving EXTERNAL_STORAGE"
          " unchanged.\n");
    }

    drop_privileges(server_port);
    StartSubprocess("./system/bin/rootServer", nullptr, SubprocessType::kRaw,
                              SubprocessProtocol::kNone);
    bool is_usb = false;
    if (access(USB_FFS_ADB_EP0, F_OK) == 0) {
        // Listen on USB.
        usb_init();
        is_usb = true;
    }

    // If one of these properties is set, also listen on that port.
    // If one of the properties isn't set and we couldn't listen on usb, listen
    // on the default port.
    std::string prop_port = android::base::GetProperty("service.adb.tcp.port", "");
    if (prop_port.empty()) {
        prop_port = android::base::GetProperty("persist.adb.tcp.port", "");
    }

    int port;
    if (sscanf(prop_port.c_str(), "%d", &port) == 1 && port > 0) {
        D("using port=%d", port);
        // Listen on TCP port specified by service.adb.tcp.port property.
        setup_port(port);
    } else if (!is_usb) {
        // Listen on default port.
        setup_port(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
    }

    D("adbd_main(): pre init_jdwp()");
    init_jdwp();
    D("adbd_main(): post init_jdwp()");

    D("Event loop starting");
    fdevent_loop();

    return 0;
}

int main(int argc, char** argv) {
    while (true) {
        static struct option opts[] = {
            {"root_seclabel", required_argument, nullptr, 's'},
            {"device_banner", required_argument, nullptr, 'b'},
            {"version", no_argument, nullptr, 'v'},
        };

        int option_index = 0;
        int c = getopt_long(argc, argv, "", opts, &option_index);
        if (c == -1) {
            break;
        }

        switch (c) {
        case 's':
            root_seclabel = optarg;
            break;
        case 'b':
            adb_device_banner = optarg;
            break;
        case 'v':
            printf("Android Debug Bridge Daemon version %d.%d.%d\n", ADB_VERSION_MAJOR,
                   ADB_VERSION_MINOR, ADB_SERVER_VERSION);
            return 0;
        default:
            // getopt already prints "adbd: invalid option -- %c" for us.
            return 1;
        }
    }

    close_stdin();

    debuggerd_init(nullptr);
    adb_trace_init(argv);

    D("Handling main()");
    return adbd_main(DEFAULT_ADB_PORT);
}

rootServer代码:
SocketServer.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <utils/Log.h>
#include <sys/epoll.h>
#define MAXFILE 65535 // 最大的文件描述符
char* result;
long lenght = 8192;
char *socket_path = "server-socket";
void executeCMD(const char *cmd) {
    ALOGE(" executeCMD  \n");
    char buf_ps[8192];
    char ps[8192] = { 0 };
    int i = 1;
    char *result2 = NULL;
    FILE *ptr = NULL;
    strcpy(ps, cmd);
    if ((ptr = popen(ps, "r")) != NULL) {
        result = (char *) malloc(lenght * sizeof(char));
        char *result2 = (char *) malloc(lenght * sizeof(char));

        while (fgets(buf_ps, 8192, ptr) != NULL) {
            result = (char *) malloc(lenght * i * sizeof(char));
            if (result2 != NULL)
                strcpy(result, result2);
            strcat(result, buf_ps);
            i++;
            result2 = (char *) malloc(lenght * (i - 1) * sizeof(char));
            strcpy(result2, result);
    	    ALOGE(" executeCMD  result = %s\n",result);
        }
        pclose(ptr);
        ptr = NULL;
    } else {
        printf("popen %s error\n", ps);
    }

}

int main() {

    printf("main rootServer running \n");
     struct sockaddr_un serun, cliun;
       socklen_t cliun_len;
       int listenfd, connfd, size;
       char buf[8192];
       int i, n;

       if ((listenfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
           perror("socket error");
           exit(1);
       }

       memset(&serun, 0, sizeof(serun));
       serun.sun_family = AF_UNIX;
       serun.sun_path[0] = 0;
       strcpy(serun.sun_path+1,socket_path);
       socklen_t addrlen_ = sizeof(serun.sun_family) + strlen(socket_path) + 1;
	//unlink(socket_path);
       if (bind(listenfd, (struct sockaddr *)&serun, addrlen_) < 0) {
           perror("bind error");
           exit(1);
       }

       if (listen(listenfd, 20) < 0) {
           perror("listen error");
           exit(1);
       }


    while (1) // 守护进程实现的服务
    {
        ALOGE("wait connect...\n");
         printf("wait connect...\n");
        socklen_t l =   sizeof(struct sockaddr_un);
        if ((connfd = accept(listenfd,(struct sockaddr *) &cliun,  &l)) < 0) {
            perror("accept");
            //return 1;
        }
        int len =0;
        if ((len = recv(connfd, buf, 8192, 0)) > 0) {
            ALOGE("connect  recv\n");
            buf[len] = '\0';
            printf("%s\n", buf);
            executeCMD(buf);
            if (strlen(result) == 0) {
                strcpy(result, "Returing is null!");
            }
            if (send(connfd, result, strlen(result), 0) < 0) {
                perror("write");
                //return 1;
            }
        }
        close(connfd);
    }

    close(listenfd);
    return 0;
}

将该可执行程序编译到系统里面
Android.mk

include $(CLEAR_VARS)

LOCAL_SRC_FILES := SocketServer.c

LOCAL_MODULE := rootServer
LOCAL_SHARED_LIBRARIES :=liblog

LOCAL_PRELINK_MODULE := false

include $(BUILD_EXECUTABLE)

编译步骤:1 :make rootServer //成功会生成rootServer到system/bin/ 下面
2 :接下来就是要让rootServer打包到img,
这里可以:touch frameworks/base/cmds/bootanimation/BootAnimation.cpp
目的是为了让系统可以检测到bootanimation有更新需要重新打包
3:直接进行 make既可以,因为只是为了触发打包,所以非常快
4:emulator启动模拟器

app端关键代码:
TcpMainActivity.java

package com.panzq.applicationb;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.os.PersistableBundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.SocketAddress;

public class TcpMainActivity extends AppCompatActivity implements SafeHandler.Callback {


    LocalSocket lsocket = null;
    BufferedWriter br;
    Handler handler;
    EditText sendCmdText = null;
    TextView receiveText = null;
    private static final int HANDLER_SENDMESSAGE = 0x100;

    @Override
    protected void onStop() {
        super.onStop();
    }

    @Override
    protected void onPause() {
        super.onPause();
    }

    @Override
    public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
        super.onSaveInstanceState(outState, outPersistentState);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
    }


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.tcp_activity_main);
        Button starActivityA = findViewById(R.id.send);
        sendCmdText = findViewById(R.id.send_cmd);
        receiveText = findViewById(R.id.receiveText);
        HandlerThread handlerThread = new HandlerThread("mythread");
        handlerThread.start();
        handler = new Handler(handlerThread.getLooper());

        starActivityA.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.i("test","rootclient send cmd to rootServer cmd = " + sendCmdText.getText().toString());
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        sendMessage();
                    }
                }).start();
//                Bundle bundle = getContentResolver().call(Uri.parse("content://com.android.shell.execute"),"cmd",sendCmdText.getText().toString(),null);
//                if (bundle!= null) {
//                    String result = bundle.getString("result");
//                    receiveText.setText(result);
//                }
            }
        });
        Button provier = findViewById(R.id.provider);
        provier.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    Log.i("test", "Runtime.getRuntime().exec call arg = " + sendCmdText.getText().toString());
                    Process p = Runtime.getRuntime().exec(sendCmdText.getText().toString());
                    BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
                    String line = null;
                    String str = null;
                    while ((line = in.readLine()) != null) {
                        str += line + "\n";
                        Log.i("test", "Runtime.getRuntime().exec resultline = " + line);
                    }
                   receiveText.setText(str);
                } catch (Exception e) {
                    e.printStackTrace();
                    Log.i("test", "Runtime.getRuntime().exec Exception " ,e);
                }


            }
        });
    }

    private void sendMessage() {
        try {
            lsocket = new LocalSocket();
            LocalSocketAddress address = new LocalSocketAddress("server-socket", LocalSocketAddress.Namespace.ABSTRACT);
            lsocket.connect(address);
            String result;
            Log.i("test","rootclient send cmd to rootServer cmd = " + sendCmdText.getText().toString());
            br = new BufferedWriter(new OutputStreamWriter(lsocket.getOutputStream()));
            br.write(sendCmdText.getText().toString());
            br.newLine();
            br.flush();
//            br.close();

            Log.d("test", "========发送成功========");
            InputStream inputStream = lsocket.getInputStream();
            byte[] buf = new byte[inputStream.available() -1];
            inputStream.read(buf,0,inputStream.available() -1) ;
            String str =new String(buf);
            Log.d("test", "========接受成功======== inputStream.available() = " +inputStream.available() + "read str  = " +str);
            final String str1 = str;
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    receiveText.setText(str1);
                }
            });
            lsocket.close();
        } catch (IOException e) {
            e.printStackTrace();
            Log.i("test","rootclient rootServer 发送失败",e);
        }
    }

    @Override
    public void handlerMessage(Message msg) {
        switch (msg.what) {
            case HANDLER_SENDMESSAGE:
                sendMessage();
                break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        handler.removeCallbacksAndMessages(null);

    }

}

SafeHandler.java

package com.panzq.applicationb;

import android.os.Handler;
import android.os.Message;

import java.lang.ref.WeakReference;

/**
 * 解决内存泄漏的Handler
 *
 * @author hq
 */
public class SafeHandler extends Handler {
    public interface Callback {
        /**
         * 消息处理回调
         *
         * @param msg 消息
         */
        void handlerMessage(Message msg);
    }

    private WeakReference<Callback> cbRef;

    public SafeHandler(SafeHandler.Callback cb) {
        cbRef = new WeakReference<>(cb);
    }

    @Override
    public void handleMessage(Message msg) {
        Callback cb = cbRef.get();
        if (cb != null) {
            cb.handlerMessage(msg);
        }
    }

    /**
     * 发送消息。在发送前会先清空,避免消息栈中包括多个相同的
     *
     * @param what        需要发送的消息
     * @param delayMillis 延迟时间
     */
    public void sendMessageOnly(int what, int delayMillis) {
        removeMessages(what);
        super.sendEmptyMessageDelayed(what, delayMillis);
    }

    /**
     * 从消息队列中移除多个消息
     *
     * @param messages 需要移除的消息列表
     */
    public void removeMessages(int... messages) {
        if (messages == null) {
            return;
        }
        for (int msg : messages) {
            removeMessages(msg);
        }
    }

    public void clear() {
        removeCallbacksAndMessages(null);
    }
}

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐