[Java][Android][Process] 暴力的服务能够解决一切,暴力的方式运行命令行语句

简介:
不管是在Java或者Android中运行命令行语句殊途同归都是创建一个子进程运行调用可运行文件运行命令。类似于Windows中的CMD一样。

此时你有两种方式运行:ProcessBuilder与Runtime;两种创建方式各有千秋,至于差别详见:[Java][Android][Process] ProcessBuilder与Runtime差别

在Android中创建子进程运行命令的时候有着一定的限制:

1.JVM提供的内存有限。

2.底层缓冲区间大小有限。

3.在高并发情况下easy造成堵塞。

基于上几点在运行命令行时我们不得不慎重操作。不能随便创建。

在上一篇文章中我提到:[Java][Android][Process] Process 创建+控制+分析 经验浅谈 了一些我的管理方式已经对实现的分析;其归根结底为:创建一个子进程的时候同一时候创建一个线程用于读取输出的流信息。在返回后及时退出。图示:



通过以上的控制方式能有效的解决掉底层ProcessManager线程死掉情况(出现等待IO缓冲区情况),当此线程死掉后子进程也将进入等待且永不退出。通过这种情况能达到运行上万条命令不出现故障。可是经过我半个月的观察发现其并非最稳定的方式,当程序中还有非常多其它IO操作如(文件读写。网络请求等)出现的时候;我运行到接近2万条命令行后出现了相同的问题。

查询后得出。尽管我们启动了线程来读取多余的流数据。可是当线程非常多或者请求非常多的时候线程可能来不及马上启动,而此时IO却已经满了,那么将会进入IO临界区等待,也就是说线程事实上不是万能的。庆幸的是在Android中有这样一种机制:服务

Android服务是什么?我不多说百度一下就知道!

如今来说说我的新思路:

首先咱们创建一个服务,并设置服务为独立进程:android:process=".command.CommandService"

然后把实现部分放在我们开启的服务中。使用一个类来控制服务启动以及调用服务做任务,其任务就是把上面的部分放在服务中控制实现,如图:


这样看来是不是没有差别?事实上不然,差别已经来了,第一因为是独立进程的服务。所以会有独立的JVM空间,同一时候该进程的IO与主线程IO不是同一个(逻辑上);所以假设在主进程中操作其它的流并不影响独立进程的流。

而且有一个特别重要的情况:当独立服务进程出现死掉(IO)等待情况,这时服务中的守护进程将会自己主动杀掉自己。然后等待又一次启动后继续运行任务。


实现代码:

public CommandServiceImpl() {
            //线程初始化
            thread = new Thread(CommandServiceImpl.class.getName()) {
                @Override
                public void run() {
                    while (thread == this && !this.isInterrupted()) {
                        if (commandExecutors != null && commandExecutors.size() > 0) {
                            lock.lock();
                            LogUtil.i(TAG, "Executors Size:" + commandExecutors.size());
                            for (CommandExecutor executor : commandExecutors) {
                                if (executor.isTimeOut())
                                    try {
                                        killSelf();
                                    } catch (RemoteException e) {
                                        e.printStackTrace();
                                    }
                                if (thread != this && this.isInterrupted())
                                    break;
                            }
                            lock.unlock();
                        }
                        try {
                            Thread.sleep(10000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            };
            thread.setDaemon(true);
            thread.start();
        }

<span style="white-space:pre">	</span>/**
         * 杀掉自己
         *
         * @throws RemoteException
         */
        @Override
        public void killSelf() throws RemoteException {
            android.os.Process.killProcess(android.os.Process.myPid());
        }
        /**
         * 运行命令
         *
         * @param params 命令
         * @return 结果
         * @throws RemoteException
         */
        @Override
        public String command(String params) throws RemoteException {
            CommandExecutor executor = CommandExecutor.create(params);
            lock.lock();
            commandExecutors.add(executor);
            lock.unlock();
            String result = executor.getResult();
            lock.lock();
            commandExecutors.remove(executor);
            lock.unlock();
            return result;
        }

此时因为服务杀掉自己没法在内存中保存当前队列任务,那任务是否就丢弃掉呢?这肯定是不同意的,我们没法在服务中控制可是能够在控制任务的:


代码例如以下:

package net.qiujuer.libraries.genius.command;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;

import net.qiujuer.libraries.genius.journal.LogUtil;
import net.qiujuer.libraries.genius.utils.GlobalValue;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by Genius on 2014/8/13.
 * 命令运行Model
 */
public class CommandModel {
    private static final String TAG = CommandModel.class.getName();
    //调用服务接口
    private static ICommandInterface iService = null;
    //服务链接类,用于实例化服务接口
    private static ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            iLock.lock();
            iService = ICommandInterface.Stub.asInterface(service);
            if (iService != null) {
                try {
                    iCondition.signalAll();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else
                bindService();
            iLock.unlock();
            LogUtil.i(TAG, "onServiceConnected");
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            iService = null;
            LogUtil.i(TAG, "onServiceDisconnected");
        }
    };
    //锁
    private static Lock iLock = new ReentrantLock();
    //等待与唤醒
    private static Condition iCondition = iLock.newCondition();

    //运行參数
    private String parameter;
    //是否取消測试
    private boolean isCancel;

    /**
     * 实例化
     *
     * @param params @param params 命令參数 eg: "/system/bin/ping", "-c", "4", "-s", "100","www.qiujuer.net"
     */
    public CommandModel(String... params) {
        //check params
        if (params == null)
            throw new NullPointerException();
        //run
        StringBuilder sb = new StringBuilder();
        for (String str : params) {
            sb.append(str);
            sb.append(" ");
        }
        this.parameter = sb.toString();
    }

    /**
     * 运行測试
     *
     * @param model ProcessModel
     * @return 结果
     */
    public static String command(CommandModel model) {
        //检測是否取消測试
        if (model.isCancel)
            return null;
        //check Service
        if (iService == null) {
            iLock.lock();
            try {
                iCondition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            iLock.unlock();
        }

        String result;
        try {
            result = iService.command(model.parameter);
        } catch (Exception e) {
            e.printStackTrace();
            bindService();
            result = command(model);
        }
        return result;
    }

    /**
     * 启动并绑定服务
     */
    private static void bindService() {
        Context context = GlobalValue.getContext();
        Intent intent = new Intent(context, CommandService.class);
        context.startService(intent);
        context.bindService(intent, conn, Context.BIND_AUTO_CREATE);
    }

    /**
     * 取消測试
     */
    public void cancel() {
        isCancel = true;
    }

    /**
     * 静态初始化
     */
    static {
        bindService();
    }

}
当中:

    public static String command(CommandModel model) {
        //检測是否取消測试
        if (model.isCancel)
            return null;
        //check Service
        if (iService == null) {
            iLock.lock();
            try {
                iCondition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            iLock.unlock();
        }

        String result;
        try {
            result = iService.command(model.parameter);
        } catch (Exception e) {
            e.printStackTrace();
            bindService();
            result = command(model);
        }
        return result;
    }
採用回调,就是为了完毕任务运行的方法!



独立进程服务接口:ICommandInterface.aidl

interface ICommandInterface {
     void killSelf();
     String command(String params);
}
命令运行者(服务中的实际功能实现):CommandExecutor.java

package net.qiujuer.libraries.genius.command;

import net.qiujuer.libraries.genius.journal.LogUtil;
import net.qiujuer.libraries.genius.utils.ToolUtil;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by Genius on 2014/8/13.
 * 命令行运行命令
 */
class CommandExecutor {
    private static final String TAG = CommandExecutor.class.getName();
    //换行符
    private static final String BREAK_LINE;
    //错误缓冲
    private static final byte[] BUFFER;
    //缓冲区大小
    private static final int BUFFER_LENGTH;
    //创建进程时须要相互排斥进行
    private static final Lock LOCK = new ReentrantLock();
    //不能超过1分钟
    private static final long TIMEOUT = 60000;
    //ProcessBuilder
    private static ProcessBuilder PRC;

    final private Process process;
    final private InputStream in;
    final private InputStream err;
    final private OutputStream out;
    final private StringBuilder sbReader;

    private BufferedReader bInReader = null;
    private InputStreamReader isInReader = null;
    private boolean isDone;
    private long startTime;

    /**
     * 静态变量初始化
     */
    static {
        BREAK_LINE = "\n";
        BUFFER_LENGTH = 128;
        BUFFER = new byte[BUFFER_LENGTH];

        LOCK.lock();
        PRC = new ProcessBuilder();
        LOCK.unlock();
    }


    /**
     * 实例化一个CommandExecutor
     *
     * @param process Process
     */
    private CommandExecutor(Process process) {
        //init
        this.startTime = System.currentTimeMillis();
        this.process = process;
        //get
        out = process.getOutputStream();
        in = process.getInputStream();
        err = process.getErrorStream();

        //in
        if (in != null) {
            isInReader = new InputStreamReader(in);
            bInReader = new BufferedReader(isInReader, BUFFER_LENGTH);
        }

        sbReader = new StringBuilder();

        //start read thread
        Thread processThread = new Thread(TAG) {
            @Override
            public void run() {
                startRead();
            }
        };
        processThread.setDaemon(true);
        processThread.start();
    }

    /**
     * 运行命令
     *
     * @param param 命令參数 eg: "/system/bin/ping -c 4 -s 100 www.qiujuer.net"
     */
    protected static CommandExecutor create(String param) {
        String[] params = param.split(" ");
        CommandExecutor processModel = null;
        try {
            LOCK.lock();
            Process process = PRC.command(params)
                    .redirectErrorStream(true)
                    .start();
            processModel = new CommandExecutor(process);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //sleep 100
            ToolUtil.sleepIgnoreInterrupt(100);
            LOCK.unlock();
        }
        return processModel;
    }


    /**
     * 获取是否超时
     *
     * @return 是否超时
     */
    protected boolean isTimeOut() {
        return ((System.currentTimeMillis() - startTime) >= TIMEOUT);
    }

    //读取结果
    private void read() {
        String str;
        //read In
        try {
            while ((str = bInReader.readLine()) != null) {
                sbReader.append(str);
                sbReader.append(BREAK_LINE);
            }
        } catch (Exception e) {
            String err = e.getMessage();
            if (err != null && err.length() > 0) {
                LogUtil.e(TAG, "Read Exception:" + err);
            }
        }
    }

    /**
     * 启动线程进行异步读取结果
     */
    private void startRead() {
        //while to end
        while (true) {
            try {
                process.exitValue();
                //read last
                read();
                break;
            } catch (IllegalThreadStateException e) {
                read();
            }
            ToolUtil.sleepIgnoreInterrupt(50);
        }

        //read end
        int len;
        if (in != null) {
            try {
                while ((len = in.read(BUFFER)) > 0) {
                    LogUtil.d(TAG, "Read End:" + len);
                }
            } catch (IOException e) {
                String err = e.getMessage();
                if (err != null && err.length() > 0)
                    LogUtil.e(TAG, "Read Thread IOException:" + err);
            }
        }

        //close
        close();
        //destroy
        destroy();
        //done
        isDone = true;

    }

    /**
     * 获取运行结果
     *
     * @return 结果
     */
    protected String getResult() {
        //until startRead en
        while (!isDone) {
            ToolUtil.sleepIgnoreInterrupt(200);
        }

        //return
        if (sbReader.length() == 0)
            return null;
        else
            return sbReader.toString();
    }

    /**
     * 关闭全部流
     */
    private void close() {
        //close out
        if (out != null) {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //err
        if (err != null) {
            try {
                err.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //in
        if (in != null) {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (isInReader != null) {
            try {
                isInReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (bInReader != null) {
            try {
                bInReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 销毁
     */
    private void destroy() {
        String str = process.toString();
        try {
            int i = str.indexOf("=") + 1;
            int j = str.indexOf("]");
            str = str.substring(i, j);
            int pid = Integer.parseInt(str);
            try {
                android.os.Process.killProcess(pid);
            } catch (Exception e) {
                try {
                    process.destroy();
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

好了本次採用暴力方式快要结束了,对于运行命令參数能够说是比較完美的运行方式了,採用这种方式我运行Ping測试达到10万次,并发达到500个任务同一时候运行没有问题。測试的设备为:魅族M9.

本次的代码我已经打包到自己的类库中。并开源到GitHub。地址:Genius-Android
希望大家多多迁移我的项目。该类库中还带有一个自己开发的完整的日志系统,以后还会增加其它东西,比方图片处理相关(模糊等)








本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5347621.html,如需转载请自行联系原作者 


相关文章
|
1月前
|
算法 数据处理 Android开发
掌握安卓性能优化的秘诀:电池寿命与运行效率的提升
【10月更文挑战第6天】 本文深入探讨了安卓应用开发中的性能优化技巧,重点分析了影响电池寿命和运行效率的关键因素,并提供了针对性的优化策略。通过代码优化、资源管理、后台任务处理等方法,开发者可以显著提升应用的续航能力和流畅度。同时,结合具体案例,展示了如何在实际开发中应用这些技巧,确保应用在各种场景下都能保持高效运行。本文旨在为安卓开发者提供实用的性能优化指导,助力其打造更优质的应用体验。
47 2
|
1月前
|
分布式计算 大数据 Java
大数据-86 Spark 集群 WordCount 用 Scala & Java 调用Spark 编译并打包上传运行 梦开始的地方
大数据-86 Spark 集群 WordCount 用 Scala & Java 调用Spark 编译并打包上传运行 梦开始的地方
24 1
大数据-86 Spark 集群 WordCount 用 Scala & Java 调用Spark 编译并打包上传运行 梦开始的地方
|
1月前
|
IDE Java 编译器
Java:如何确定编译和运行时类路径是否一致
类路径(Classpath)是JVM用于查找类文件的路径列表,对编译和运行Java程序至关重要。编译时通过`javac -classpath`指定,运行时通过`java -classpath`指定。IDE如Eclipse和IntelliJ IDEA也提供界面管理类路径。确保编译和运行时类路径一致,特别是外部库和项目内部类的路径设置。
|
28天前
|
安全 Java 网络安全
Android远程连接和登录FTPS服务代码(commons.net库)
Android远程连接和登录FTPS服务代码(commons.net库)
23 1
|
1月前
|
Java Unix Linux
Android Studio中Terminal运行./gradlew clean build提示错误信息
遇到 `./gradlew clean build`命令执行出错时,首先应检查错误信息的具体内容,这通常会指向问题的根源。从权限、环境配置、依赖下载、版本兼容性到项目配置本身,逐一排查并应用相应的解决措施。记住,保持耐心,逐步解决问题,往往复杂问题都是由简单原因引起的。
239 2
|
1月前
|
Java
Java关键字 —— super 与 this 详细解释!一看就懂 有代码实例运行!
本文介绍了Java中this和super关键字的用法,包括在构造方法中使用this来区分参数和成员变量、使用super调用父类构造方法和方法,以及它们在同一个方法中同时使用的场景。
118 0
Java关键字 —— super 与 this 详细解释!一看就懂 有代码实例运行!
|
1月前
|
Java
Java关键字 —— static 与 final 详细解释!一看就懂 有代码实例运行!
这篇文章详细解释了Java中static和final关键字的用法,包括它们修饰类、方法、变量和代码块时的行为,并通过代码示例展示了它们的具体应用。
182 0
Java关键字 —— static 与 final 详细解释!一看就懂 有代码实例运行!
|
1月前
|
Java Maven Spring
用Spring导致的无法运行Java文件的问题的解决方案
本文提供了解决在IntelliJ IDEA社区版中使用Spring Initializr插件创建Spring项目后,Java文件无法运行的问题的方法,主要是通过加载Maven项目来解决。
69 0
|
6天前
|
搜索推荐 Android开发 开发者
探索安卓开发中的自定义视图:打造个性化UI组件
【10月更文挑战第39天】在安卓开发的世界中,自定义视图是实现独特界面设计的关键。本文将引导你理解自定义视图的概念、创建流程,以及如何通过它们增强应用的用户体验。我们将从基础出发,逐步深入,最终让你能够自信地设计和实现专属的UI组件。