【app】1.3 传入diag命令

前言

界面都做好了,就剩下下发diag命令了。

抓取qxdm_log命令

diag_mdlog -f /sdcard/default_V2.6_auddsp_btfmwlan_ril1.cfg

    private void startRecordQxdmLog(){
        StringBuffer cmdBuf = new StringBuffer();
        cmdBuf.append("diag_mdlog");
        cmdBuf.append(" -f ");
        cmdBuf.append("/sdcard/default_V2.6_auddsp_btfmwlan_ril1.cfg");
        Toast.makeText(getApplicationContext(), "start record qxdm log\n"+cmdBuf.toString(), Toast.LENGTH_SHORT).show();

        // send start record cmd

    }

注意使用stringbuffer存储命令。

参考:StringBuffer详解

String、StringBuffer与StringBuilder之间区别

CharSequence 详情介绍

效果
在这里插入图片描述

下发命令机制——socket

仿照应用logmaster2,使用socket实现下发命令。

底层实现了/dev/socket/logd2
这里只需要创建client,实现通信。
socket相关内容,参见文章:Android中LocalSocket使用

package com.example.demo_v4_qxdmlog;

import android.net.LocalSocketAddress;
import android.net.LocalSocket;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.PrintStream;
import java.net.UnknownHostException;

/**
 * @hide
 *
 * The socket connects to logd2
 */
public class SocketClient {

    private static final String LOGD2_SOCKET = "/dev/socket/logd2";

    // default socket connection timeout
    public static final int SOCKET_TIMEOUT = 1000;

    private BufferedReader mServerReader = null;
    private PrintStream mServerWriter = null;
    private LocalSocket mSkt = null;

    public SocketClient() {
    }

    public void connect() throws UnknownHostException, IOException {
        connect(SOCKET_TIMEOUT);
    }

    public void connect(int timeout) throws UnknownHostException, IOException {
        mSkt = new LocalSocket();
        LocalSocketAddress address = new LocalSocketAddress(LOGD2_SOCKET, LocalSocketAddress.Namespace.FILESYSTEM);

        mSkt.connect(address);

        if (timeout != 0) {
            mSkt.setSoTimeout(timeout);
        }

        mServerReader = new BufferedReader(new InputStreamReader(mSkt.getInputStream()));
        mServerWriter = new PrintStream(mSkt.getOutputStream());
    }

    public void close() {
        try {
            if (mSkt != null) {
                mSkt.close();
                mSkt = null;
            }
            mServerReader = null;
            mServerWriter = null;
        } catch (IOException ie) {
            ie.printStackTrace();
        }
    }

    public String getServerMessage() throws IOException {
        return mServerReader.readLine();
    }

    public int read() throws IOException {
        return mServerReader.read();
    }

    public void sendMessageToServer(String message) {
        mServerWriter.println(message);
    }

}

再添加Executor,实现cmd的下发及命令监控。

package com.example.demo_v4_qxdmlog;


import android.util.Log;

import java.io.IOException;
import java.net.UnknownHostException;
import java.util.Observable;

/**
 * @hide
 *
 * Logd2 Java interface.
 */
public class Executor extends Observable {

    private static final String TAG = "LogdJ";

    public static final String TERMINATE_BY_REMOTE = "terMiNaTeByReMote";

    private SocketClient mSktClient = null;
    private volatile boolean mStopByLocal = false;

    public Executor() {
    }

    // execute shell command and return with socket connected. (Closed by UI)
    public boolean shellAsync(String shellCmd) {
        boolean ret = true;
        mSktClient = new SocketClient();
        try {
            mSktClient.connect();
            mSktClient.sendMessageToServer(shellCmd);
            new SocketMonitor().start();
        } catch (UnknownHostException uhe) {
            // connect fail.
            Log.w(TAG, "leave shellSync with UnknownHostException");
            stop();
            ret = false;
        } catch (IOException ie) {
            // done.
            Log.w(TAG, "leave shellSync with IOException, " + ie.toString());
            stop(false);
            ret = true;
        } catch (Exception e) {
            // exception.
            Log.w(TAG, "leave shellSync with Exception");
            stop();
            ret = false;
        }

        return ret;
    }

    // execute shell command and return with socket connected. (Closed by UI)
    public boolean oemAsync(String shellCmd) {
        boolean ret = true;
        mSktClient = new SocketClient();
        String serverMessage = "";
        try {
            mSktClient.connect(0);
            mSktClient.sendMessageToServer(shellCmd);
            serverMessage = mSktClient.getServerMessage();
            Log.i(TAG, "[Server] said: " + serverMessage);
            setChanged();
            notifyObservers(serverMessage);
            new SocketMonitor().start();
        } catch (UnknownHostException uhe) {
            // connect fail.
            Log.w(TAG, "leave oemAsync with UnknownHostException");
            stop();
            ret = false;
        } catch (IOException ie) {
            // done.
            Log.w(TAG, "leave oemAsync with IOException, " + ie.toString());
            stop(false);
            ret = true;
        } catch (Exception e) {
            // exception.
            Log.w(TAG, "leave oemAsync with Exception");
            stop();
            ret = false;
        }

        return ret;
    }

    // execute shell command and return when socket closed. (Closed by logd2)
    public boolean shellSync(String shellCmd) {
        return shellSync(shellCmd, SocketClient.SOCKET_TIMEOUT);
    }

    public boolean shellSync(String shellCmd, int timeout) {
        Log.w(TAG, "enter shellSync, timeout:" + timeout);
        boolean ret = true;
        mSktClient = new SocketClient();
        try {
            mSktClient.connect(timeout);
            mSktClient.sendMessageToServer(shellCmd);

            String serverMessage;
            while ((serverMessage = mSktClient.getServerMessage()) != null) {
                Log.i(TAG, "[Server] said: " + serverMessage);
                setChanged();
                notifyObservers(serverMessage);
                // break;
            }
        } catch (UnknownHostException uhe) {
            // connect fail.
            Log.w(TAG, "leave shellSync with UnknownHostException");
            ret = false;
        } catch (IOException ie) {
            // done.
            Log.w(TAG, "leave shellSync with IOException, " + ie.toString());
            ret = true;
        } catch (Exception e) {
            // exception.
            Log.w(TAG, "leave shellSync with Exception");
            e.printStackTrace();
            ret = false;
        }
        stop();
        return ret;
    }

    public void requestStop() {
        Log.d(TAG,"requestStop");
        mSktClient.sendMessageToServer("terminate");
    }

    public void stop() {
        stop(true);
    }

    public void stop(boolean byLocal) {
        mStopByLocal = byLocal;
        if (mSktClient != null) {
            mSktClient.close();
            mSktClient = null;
        }
    }

    public class SocketMonitor extends Thread {
        public SocketMonitor() {
        }

        @Override
        public void run() {
            try {
                if (mSktClient != null) {
                    int serverMessage = 0;
                    do {
                        try {
                            serverMessage = mSktClient.read();
                            Log.d(TAG,"SocketMonitor serverMessage: "+serverMessage);
                            // Log.d(TAG,
                            // "[SocketMonitor] getServerMessage() serverMessage:\""+serverMessage+"\"");
                        } catch (UnknownHostException uhe) {
                            // connect fail.
                            Log.w(TAG, "[SocketMonitor] Connection failed.", uhe);
                            break;
                        } catch (IOException ie) {
                            // done.
                            if (!"Try again".equals(ie.getMessage())) {
                                Log.w(TAG, "[SocketMonitor] Done.", ie);
                                break;
                            }
                        }
                    } while (serverMessage != -1);
                    if (!mStopByLocal) {
                        Log.d(TAG,"notifyObservers TERMINATE_BY_REMOTE");
                        setChanged();
                        notifyObservers(TERMINATE_BY_REMOTE);
                    }
                    // Log.d(TAG, "[SocketMonitor] getServerMessage() END");
                }
            } catch (Exception e) {
                // exception.
                Log.w(TAG, "[SocketMonitor] Exception.", e);
                Executor.this.stop();
            }
        }
    }
}

注意,需要底层以及实现了socket。

启动停止录制

定义启动函数,在点击悬浮球时会触发。
同时新增了一个功能,增加了一个输入框,用于输入启动命令。

以启动录制为例:
1 创建StringBuffer 变量用于存放启动命令
2 判断输入框editText中是否有有内容
若非空,且非默认值,则将输入框的内容传入cmd_start 中。该参数用于存放启动命令
3 执行sendstartcmd函数,开始录制
这里就是创建Executor实例,然后执行shellAsync下发cmd


    private void startRecordQxdmLog(){
//        StringBuffer cmdBuf = new StringBuffer();
//        cmdBuf.append("diag_mdlog");
//        cmdBuf.append(" -f ");
//        cmdBuf.append("/sdcard/default_V2.6_auddsp_btfmwlan_ril1.cfg");

        Toast.makeText(getApplicationContext(), "start record qxdm log", Toast.LENGTH_SHORT).show();

        // send start record cmd
        startQxdmRecording();
    }

    private void startQxdmRecording(){
        // 1. set default start cmd
        StringBuffer default_start_cmd = new StringBuffer();
        default_start_cmd.append("diag_mdlog -f /sdcard/default_V2.6_auddsp_btfmwlan_ril1.cfg");

        // add log save path
        String ExternalStorage = "sdcard";
        String diagLogPath = ExternalStorage + "/diag_logs/" + getDateTimeString();
        default_start_cmd.append(" -o " + diagLogPath);

        // 2. display file path
        text = (TextView) findViewById(R.id.textView);
        text.setText(diagLogPath);

        // 3. get edit text value, use to update start cmd
        String tempcmd = null;
        textview_cmd_send = (EditText) findViewById(R.id.cmd_send);
        tempcmd = textview_cmd_send.getText().toString();

        // 4. judge editcmd is not null or default
        String temp_judge_sendcmd_empty = "input start cmd";
        // ps: judge string value use equals()
        if (tempcmd.isEmpty())
        {
            // default cmd
            cmd_start = "diag_mdlog -f /sdcard/default_V2.6_auddsp_btfmwlan_ril1.cfg";
        }
        else if ( tempcmd.equals(temp_judge_sendcmd_empty)  ){
            // tips: edit text value is not changed, so use default cmd
            Toast.makeText(getApplicationContext(), "please input start cmd. \n now use default cmd", Toast.LENGTH_SHORT).show();

            cmd_start = default_start_cmd.toString();
        }
        else
        {
            // use edit cmd
            cmd_start = tempcmd;
        }
//        Toast.makeText(getApplicationContext(), tempcmd, Toast.LENGTH_SHORT).show();

        // 5. display start cmd
        textview_cmd_current = (TextView) findViewById(R.id.cmd_display);
        textview_cmd_current.setText("current_cmd : \n" + cmd_start);

        // ***send start cmd***
//        sendstartcmd(cmd_start);
    }

    private void sendstartcmd(String start_cmd){

        mExecutor = new Executor();
        boolean ret = false;

        Log.d("sendstartcmd", "startQxdmRecording");
        Log.d("sendstartcmd", "cmd : "+start_cmd);

        Toast.makeText(getApplicationContext(), start_cmd, Toast.LENGTH_SHORT).show();

        ret = mExecutor.shellAsync(start_cmd);
        if (ret) {
            Toast.makeText(getApplicationContext(), "cmd set success", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(getApplicationContext(), "cmd set fail", Toast.LENGTH_SHORT).show();
        }
    }

    private void stopRecordQxdmLog(){

        Toast.makeText(getApplicationContext(), "stop record QXDM log", Toast.LENGTH_SHORT).show();

        // send stop record cmd
        stopQxdmRecording();

        //func2 for send cmd -- error
//        cmd_exec = new CommandExecution();
//        String cmdBuf2 = "exit\n";
//        cmd_exec.execCommand( cmdBuf2 ,false);
    }

    private void stopQxdmRecording(){
        StringBuffer cmd_stop = new StringBuffer();
        cmd_stop.append("diag_mdlog -k");   // kill pid

        textview_cmd_current = (TextView) findViewById(R.id.cmd_display);
        textview_cmd_current.setText("current_cmd : \n"+cmd_stop.toString());

        // ***send cmd***
//        sendstopcmd(cmd_stop);
    }

    private void sendstopcmd(String stop_cmd) {
        mExecutor_stop = new Executor();
        boolean ret = false;

        Log.d("", "stopQxdmRecording");
        Log.d("", "cmd : " + stop_cmd);

        Toast.makeText(getApplicationContext(), stop_cmd, Toast.LENGTH_SHORT).show();

        ret = mExecutor_stop.shellSync(stop_cmd);
        if (ret) {
            Toast.makeText(getApplicationContext(), "cmd set success", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(getApplicationContext(), "cmd set fail", Toast.LENGTH_SHORT).show();
        }
    }

PS:使用string类型判断时需要调用equals()判断是否为指定字符串。

String temp_judge_sendcmd_empty = "input start cmd";

tempcmd.equals(temp_judge_sendcmd_empty)

结果

开始界面
在这里插入图片描述
点击打开layout,关闭layout,然后再点击一次打开layout。(由于第一次弹出悬浮框无法接收到点击事件,该bug后续修复)
此时看到有红色的悬浮框显示,点击红色文字
在这里插入图片描述
点击完毕后,悬浮框变为绿色,同时弹出提示,当前使用默认命令,如果有需要则再输入框中输入启动命令。
同时会显示本次录制存放的路径。

在这里插入图片描述

代码已上传:https://github.com/monsterLang/floatingball/tree/master/demo_v5_addeditsendcmd/demo_v4_qxdmlog

小结

重点在于建立socket下发命令,socket部分不太了解,目前只是使用示例的接口,后续再学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值