android应用层程序直接与framework…

时间:2021-04-23 08:59:37

原文地址:http://blog.csdn.net/goleftgoright/article/details/7406292?reload

关于Android应用与Framework的socket通信,相信关心这个问题的朋友们已经看过《android使用socket使底层和framework通信》这篇文章,美中不足的是作者只贴出一些关键的代码片段而并没有放出源码。我这里还是以一个能实际运行的例子为基础来讲,这样也方便大家学习。

首先看一下效果,如下图。我填写姓名"Potter",选择性别"Mr"然后点击发送,底层socket收到消息后将消息直接返回给我,我将返回的结果(Mr.Potter)直接显示在Result。

android应用层程序直接与framework…



ok,有了初步了解后我们现在来看一下如何一步步实现这个例子。

1、配置system/core/rootdir/init.rc。我在init.rc加入如下配置

service htfskservice /system/bin/htfsk 
    class main
    socket htfsk stream 666 system system
    oneshot 

这里配置了一个名为 “htfskservice” 的服务,手机开机后该服务会自启动并运行/system/bin目录下的脚本htfsk(步骤二将提到如何生成这个脚本)。

同时这里还配置了一个名为 "htfsk" 的socket,并且只有拥有system权限的应用才允许连接这个socket,如何使应用获取system权限可以参考http://my.unix-center.net/~Simon_fu/?p=531这篇文章。

666表示socket的权限

2、编写socket服务端代码,生成可执行脚本htfsk。

首先来看下socket服务端代码 htfsk.c ,内容如下:

#define SOCKET_NAME "htfsk"

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <cutils/sockets.h>
#include <utils/Log.h>
#include <android/log.h>


int main(){
    char log[200];

    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];
    //这一步很关键,就是获取init.rc中配置的名为 "htfsk" 的socket
    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);
    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);
    }
    //等待Socket客户端发启连接请求
    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){
    //循环等待Socket客户端发来消息
    __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;
    }
    //发送消息回执给Socket客户端
    if(send(new_fd,buff,strlen(buff),0)==-1)
    {
        perror("send");
        close(new_fd);
        exit(0);
    }       
    }
   
    close(new_fd);
    close(fdListen);
    return 0;
}

写好服务端代码后我们要将他编译成可执行脚本htfsk,编译的Android.mk内容如下:

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE_TAGS :=optional
LOCAL_C_INCLUDES := $(KERNEL_HEADERS)
LOCAL_SHARED_LIBRARIES := libcutils liblog
LOCAL_MODULE:= htfsk
LOCAL_SRC_FILES:=htfsk.c
LOCAL_PRELINK_MODULE := false
include $(BUILD_EXECUTABLE)

编译成功后就会在/system/bin/目录下找到生成的可执行脚本htfsk

3、编写客户端java代码。核心代码如下: 

SocketClient.java
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();
    }
 
    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";
    }
 
    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");
                }
            }
        }
    }
     public void closeSocket() {
        try {
            client.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

MySocketActivity.java


public class MySocketActivity extends Activity {
    private SocketClient socketClient = null;
    private static String INFO;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Log.i("MySocketActivity", "Sleep waiting for service socket start");
        socketClient = new SocketClient();
    }
    public void sendName(View view) {
        String name = ((TextView) this.findViewById(R.id.editText1)).getText().toString();
        if (name == "") {
            Toast.makeText(this, getResources().getString(R.string.nameNull), Toast.LENGTH_SHORT).show();
            return;
        }
        String sex = ((Spinner) this.findViewById(R.id.spinner1)).getSelectedItem().toString();
        INFO = sex+ "." + name ;
        new SocketThread(handler).start();
    }

    private class SocketThread extends Thread {
        private Handler handler;

        public SocketThread(Handler handler) {
            super();
            this.handler = handler;
        }

        @Override
        public void run() {
            Log.i("MySocketActivity", "SocketThead wait for result.");
            String result = getSocketClient().sendMsg(INFO);
            Log.i("MySocketActivity", "Socket reslut:" + result);
            Message msg = handler.obtainMessage();
            Bundle bundle = new Bundle();
            bundle.putString("result", result);
            msg.setData(bundle);
            handler.sendMessage(msg);
        }
    }

    private Handler handler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            String result = msg.getData().getString("result");
            Log.i("MySocketActivity", "Handler result:" + result);
            ((TextView) MySocketActivity.this.findViewById(R.id.tvResult)).setText(result);
        };
    };

    @Override
    protected void onDestroy() {
        if (socketClient != null) {
            getSocketClient().closeSocket();
        }
        super.onDestroy();
    }

    public SocketClient getSocketClient() {
        if (socketClient == null) {
            socketClient = new SocketClient();
        }
        return socketClient;
    }

}