设为首页 收藏本站
查看: 637|回复: 0

[经验分享] Android VNC Server New

[复制链接]

尚未签到

发表于 2018-10-13 11:00:58 | 显示全部楼层 |阅读模式
  Android VNC Server New

         关于VNC请参见维基百科:http://zh.wikipedia.org/wiki/VNC  关于执行Android VNC Server,请参见前一篇文章:点击链接

一、VNC下载
1)fastdroid-vnc  Android VNC Server开源项目

         http://code.google.com/p/fastdroid-vnc/
2)TightVNC
         免费的VNC软件(这个都不需要填邮箱^^)
         http://www.tightvnc.com/download.php
二、程序执行
         这种方式看手机了==。Google HTC上倒是可以,详细的说明看注释了。
1)简易UI
         布局一点没变动…
VNCServerNewActivity.java  

  


  • public class VNCServerNewActivity extends Activity {

  •     private static final String TAG = "VNCServer";
  •     private static final boolean LOGD = true;

  •     /** assets目录下的VNCServer文件名 */
  •     private static final String VNC_SERV_NAME = "fastdroid-vnc";

  •     /** Shell工具类 */
  •     private ShellUtil mShellUtil;

  •     /** dialog基础标识值 */
  •     private static final int DLG_BASE = 0;
  •     /** 获root权限失败的dialog id */
  •     private static final int DLG_ROOT_FAILED = DLG_BASE + 1;
  •     /** 开启VNC服务失败的dialog id */
  •     private static final int DLG_EXEC_FAILED = DLG_BASE + 2;

  •     /** VNC服务端口:5901 */
  •     private static final String VNC_SERV_PORT = "5901";

  •     /** 按钮 */
  •     private Button startBtn, stopBtn;
  •     /** 标签 */
  •     private TextView statusView, connectView;

  •     /** 'ps -l VNC_SERV_NAME'命令 */
  •     private static final String[] PS_VNC_SERVER = new String[] { "ps", "-l",
  •             VNC_SERV_NAME };
  •     /** 执行上述命令获取的pid结果集 */
  •     private ArrayList pidList;

  •     @Override
  •     public void onCreate(Bundle savedInstanceState) {
  •         super.onCreate(savedInstanceState);
  •         setContentView(R.layout.main);

  •         mShellUtil = ShellUtil.getInstance(); // 获取实例

  •         initApp(); // 初始化应用
  •         initViews(); // 初始化组件
  •     }

  •     /** 初始化组件 */
  •     private void initViews() {
  •         startBtn = (Button) findViewById(R.id.startBtn);
  •         stopBtn = (Button) findViewById(R.id.stopBtn);
  •         statusView = (TextView) findViewById(R.id.statusView);
  •         connectView = (TextView) findViewById(R.id.connectView);
  •         updateViews(isServerOn()); // 由服务状态更新界面
  •     }

  •     /** 初始化应用 */
  •     private void initApp() {
  •         boolean result = mShellUtil.root(); // 获取ROOT权限
  •         if (LOGD)
  •             Log.d(TAG, "获取Root权限:" + result);
  •         if (result) {
  •             copyVNCServer(); // 检查VNCServer文件
  •         } else {
  •             showDialog(DLG_ROOT_FAILED); // 提示DLG_ROOT_FAILED对话框
  •         }
  •     }

  •     /** 检查VNCServer文件,不存在时复制进去 */
  •     private void copyVNCServer() {
  •         String filePath = "/data/local/" + VNC_SERV_NAME;
  •         File file = new File(filePath);

  •         /* 文件不存在时,从assets复制进去 */
  •         if (!file.exists()) {
  •             /* /data/local/目录增加所有用户的写权限 */
  •             boolean result = mShellUtil.rootCommand("chmod a+x /data/local/");
  •             if (LOGD)
  •                 Log.d(TAG, "/data/local/增加写权限:" + result);

  •             // 避免某些机子new FileOutputStream(file)时报System.err==
  •             result = mShellUtil.rootCommand("touch " + filePath);
  •             if (LOGD)
  •                 Log.d(TAG, "创建一个空文件:" + result);

  •             /* VNCServer文件设为777权限 */
  •             result = mShellUtil.rootCommand("chmod 777 " + filePath);
  •             if (LOGD)
  •                 Log.d(TAG, "/data/local/设为777权限:" + result);

  •             if (result) {
  •                 try {
  •                     /* 将VNCServer文件复制入/data/local/ */
  •                     InputStream is = getAssets().open(VNC_SERV_NAME);
  •                     FileOutputStream fos = new FileOutputStream(file);
  •                     byte[] buffer = new byte[4096];
  •                     int count = 0;
  •                     while ((count = is.read(buffer)) > 0) {
  •                         fos.write(buffer, 0, count);
  •                     }
  •                     fos.close();
  •                     is.close();
  •                     if (LOGD)
  •                         Log.d(TAG, VNC_SERV_NAME + "文件写入/data/local/!");
  •                 } catch (IOException e) {
  •                     e.printStackTrace();
  •                 }
  •             }
  •         } else {
  •             if (LOGD)
  •                 Log.d(TAG, VNC_SERV_NAME + "文件已存在/data/目录下!");
  •         }
  •     }

  •     /** startBtn点击事件 */
  •     public void startBtn(View v) {
  •         /* 执行VNCServer文件 */
  •         String cmd = "/data/local/" + VNC_SERV_NAME + " &";
  •         boolean result = mShellUtil.rootCommand(cmd);
  •         if (LOGD)
  •             Log.d(TAG, cmd + ":" + result);
  •         if (isServerOn()) { // 否开启了服务
  •             updateViews(true);
  •         } else {
  •             /**
  •              * 1)有些ROM执行开启不了T^T(ps进程显示Done,再一会就没了)
  •              * 2)用其他VNC文件发现未开启也好提示用户
  •              */
  •             showDialog(DLG_EXEC_FAILED); // 提示DLG_EXEC_FAILED对话框
  •         }
  •     }

  •     /** stopBtn点击事件 */
  •     public void stopBtn(View v) {
  •         boolean result;
  •         /** 直到关闭为止。避免kill进程仅改变了状态(遇到S->Z的情况) */
  •         while (isServerOn()) {
  •             for (String pid : pidList) {
  •                 result = mShellUtil.rootCommand("kill " + pid);
  •                 if (LOGD)
  •                     Log.d(TAG, "kill " + pid + ":" + result);
  •             }
  •         }
  •         updateViews(false); // 更新服务关闭时的界面状态
  •     }

  •     @Override
  •     protected void onDestroy() {
  •         super.onDestroy();
  •         boolean result = mShellUtil.rootRelease(); // 释放占用资源
  •         if (LOGD)
  •             Log.d(TAG, "释放占用资源:" + result);
  •     }

  •     /** 由服务状态更新界面 */
  •     private void updateViews(boolean isServerOn) {
  •         /* 更新按钮状态 */
  •         startBtn.setEnabled(!isServerOn);
  •         stopBtn.setEnabled(isServerOn);
  •         /* 更新标签显示 */
  •         if (isServerOn) {
  •             statusView.setText(R.string.status_run);
  •             connectView.setText(getLocalIpAddress() + ":" + VNC_SERV_PORT);
  •         } else {
  •             statusView.setText(R.string.status_stop);
  •             connectView.setText(R.string.address);
  •         }
  •     }

  •     /** 是否开启了服务,并处理得到pid列表 */
  •     private boolean isServerOn() {
  •         mShellUtil.setFilter(new PsLineFilter()); // 设置过滤器
  •         // 获取ps命令的pid列表
  •         pidList = mShellUtil.execCommand(PS_VNC_SERVER, null, true);
  •         mShellUtil.resetFilter(); // 重置过滤器
  •         boolean result = (null != pidList) && (pidList.size() >= 1);
  •         if (LOGD)
  •             Log.d(TAG, "VNC服务开启状态:" + result);
  •         return result;
  •     }

  •     /** 获取IP地址 */
  •     private String getLocalIpAddress() {
  •         try {
  •             // 遍历网络接口
  •             for (Enumeration en = NetworkInterface
  •                     .getNetworkInterfaces(); en.hasMoreElements();) {
  •                 NetworkInterface intf = en.nextElement();
  •                 // 遍历IP地址
  •                 for (Enumeration enumIpAddr = intf
  •                         .getInetAddresses(); enumIpAddr.hasMoreElements();) {
  •                     InetAddress inetAddress = enumIpAddr.nextElement();
  •                     // 非回传地址时返回
  •                     if (!inetAddress.isLoopbackAddress()) {
  •                         return inetAddress.getHostAddress().toString();
  •                     }
  •                 }
  •             }
  •         } catch (SocketException e) {
  •             e.printStackTrace();
  •         }
  •         return null;
  •     }

  •     @Override
  •     protected Dialog onCreateDialog(int id) {
  •         省略……
  •     }

  • }
  


2)Shell工具类
ShellUtil.java  


  • /** Shell工具类 */
  • public final class ShellUtil {

  •     /** 内部类ShellUtilHolder */
  •     static class ShellUtilHolder {
  •         static ShellUtil instance = new ShellUtil();
  •     }

  •     /** 返回ShellUtil的单例 */
  •     public static ShellUtil getInstance() {
  •         return ShellUtilHolder.instance;
  •     }

  •     /** \link #root()\endlink后的进程 */
  •     private Process process;

  •     /** \link #root()\endlink后的父进程的标准输入 */
  •     private DataOutputStream dos;

  •     /** 标准输出的过滤 */
  •     private IStdoutFilter mIStdoutFilter;

  •     /** 设置标准输出的过滤器 */
  •     public void setFilter(IStdoutFilter filter) {
  •         this.mIStdoutFilter = filter;
  •     }

  •     /** 重置过滤器为空 */
  •     public void resetFilter() {
  •         this.mIStdoutFilter = null;
  •     }

  •     /**
  •      * @brief 切换至ROOT用户
  •      * @details 执行su命令,变更为root用户
  •      * @pre 设备已经破解,否则su不可用
  •      *
  •      * @return 是否成功
  •      */
  •     public boolean root() {
  •         try {
  •             // 执行su变更用户身份为root
  •             process = Runtime.getRuntime().exec("su");
  •             // 转成DataOutputStream方便写入字符串
  •             dos = new DataOutputStream(process.getOutputStream());
  •         } catch (Exception e) {
  •             e.printStackTrace();
  •             return false;
  •         }
  •         return true;
  •     }

  •     /**
  •      * @brief ROOT权限下执行命令
  •      * @pre 执行\link #root()\endlink
  •      *
  •      * @param cmd 命令
  •      */
  •     public boolean rootCommand(String cmd) {
  •         if (null != dos) {
  •             try {
  •                 dos.writeBytes(cmd + "\n");
  •                 dos.flush();
  •             } catch (IOException e) {
  •                 e.printStackTrace();
  •                 return false;
  •             }
  •             return true;
  •         }
  •         return false;
  •     }

  •     // /**
  •     // * @brief \link #rootCommand()\endlink后的结果
  •     // * @pre 执行\link #rootCommand()\endlink
  •     // *
  •     // * @warning 不能在stdin流输入命令后再从stdout获输出结果
  •     // * (之前测试版也放在不同位置试过,都不成,死锁?没找到更多资料)
  •     // *
  •     // * @return 输出结果的集合
  •     // */
  •     // public ArrayList getStdout() {
  •     // ArrayList lineArray = new ArrayList();
  •     // try {
  •     // handleStdout(lineArray, process);
  •     // } catch (IOException e) {
  •     // e.printStackTrace();
  •     // }
  •     // return lineArray;
  •     // }

  •     /** 释放占用资源 */
  •     public boolean rootRelease() {
  •         try {
  •             dos.writeBytes("exit\n");
  •             dos.flush();
  •             process.waitFor(); // 等待执行完成
  •         } catch (Exception e) {
  •             e.printStackTrace();
  •             return false;
  •         } finally {
  •             try {
  •                 if (null != process) {
  •                     process.destroy();
  •                 }
  •                 if (null != dos) {
  •                     dos.close();
  •                 }
  •             } catch (Exception e) {
  •                 e.printStackTrace();
  •             }
  •         }
  •         return true;
  •     }

  •     /**
  •      * @brief 执行一个shell命令
  •      *
  •      * @param cmd 命令&参数组成的数组
  •      * @param workDir 命令工作目录
  •      * @param isStdout 是否输出结果
  •      * @return 输出结果的集合
  •      */
  •     public ArrayList execCommand(String[] cmd, String workDir,
  •             boolean isStdout) {
  •         ArrayList lineArray = null;
  •         try {
  •             // 创建操作系统进程(也可以由Runtime.exec()启动)
  •             ProcessBuilder builder = new ProcessBuilder(cmd);
  •             // 设置命令工作目录
  •             if (workDir != null) {
  •                 builder.directory(new File(workDir));
  •             }
  •             // 合并标准错误和标准输出
  •             builder.redirectErrorStream(true);
  •             // 启动一个新进程
  •             Process process = builder.start();

  •             // 如果输出结果的话
  •             if (isStdout) {
  •                 lineArray = new ArrayList(); // 创建对象
  •                 handleStdout(lineArray, process);
  •             }
  •         } catch (Exception e) {
  •             e.printStackTrace();
  •         }
  •         return lineArray;
  •     }

  •     /**
  •      * 处理标准输出内容
  •      *
  •      * @throws IOException
  •      */
  •     private void handleStdout(ArrayList lineArray, Process process)
  •             throws IOException {
  •         InputStream is = process.getInputStream(); // 获得标准输出流
  •         if (null != mIStdoutFilter) { // 如果设置了过滤
  •             // 判断是否是行过滤器
  •             if (mIStdoutFilter instanceof AbstractLineFilter) {
  •                 // 转成BufferedReader
  •                 BufferedReader br = new BufferedReader(
  •                         new InputStreamReader(is));
  •                 String line;
  •                 while (null != (line = br.readLine())) {
  •                     /* 如果未被过滤,则将处理后内容加入List */
  •                     if (!mIStdoutFilter.filter(line)) {
  •                         lineArray.add(mIStdoutFilter.handle());
  •                     }
  •                 }
  •                 if (br != null) {
  •                     br.close();
  •                 }
  •             } else {
  •                 // 默认把流直接转成字符串返回
  •                 lineArray.add(inputStream2Str(is));
  •             }
  •         } else {
  •             // 默认把流直接转成字符串返回
  •             lineArray.add(inputStream2Str(is));
  •         }
  •         if (is != null) {
  •             is.close();
  •         }
  •     }

  •     /**
  •      * 输入流转成字符串
  •      *
  •      * @throws IOException
  •      */
  •     public String inputStream2Str(InputStream is) throws IOException {
  •         StringBuffer out = new StringBuffer();
  •         byte[] b = new byte[4096];
  •         for (int n; (n = is.read(b)) != -1;) {
  •             out.append(new String(b, 0, n));
  •         }
  •         return out.toString();
  •     }

  • }
  


3)过滤器
IStdoutFilter.java  


  • /** 标准输出过滤接口 */
  • public interface IStdoutFilter {

  •     /**
  •      * @brief 过滤操作
  •      * @param stdout
  •      *            标准输出的内容
  •      * @return true:过滤;false:保留
  •      */
  •     boolean filter(T stdout);

  •     /**
  •      * @brief 处理操作
  •      * @return 处理后的内容
  •      */
  •     T handle();

  • }
  


AbstractLineFilter.java  


  • /**
  • * @brief 抽象的行过滤器
  • * @details 以行的方式遍历标准输出,都进行一次过滤判断
  • */
  • public abstract class AbstractLineFilter implements IStdoutFilter {

  •     /** 行内容 */
  •     protected String line;

  •     /**
  •      * @brief 行过滤操作
  •      * @param line
  •      *            标准输出的某行内容
  •      * @return true:过滤;false:保留
  •      */
  •     protected abstract boolean lineFilter(String line);

  •     @Override
  •     public boolean filter(String stdout) {
  •         this.line = stdout;
  •         return lineFilter(stdout);
  •     }

  •     @Override
  •     public String handle() {
  •         return line; // 默认返回原行
  •     }

  • }
  


PsLineFilter.java(应该加个单例==)  


  • /**
  • * ps命令的行过滤及处理成pid的实现
  • */
  • public final class PsLineFilter extends AbstractLineFilter {

  •     @Override
  •     protected boolean lineFilter(String line) {
  •         // 过滤空行及标题行
  •         if (null == line || "".endsWith(line) || line.startsWith("USER")) {
  •             return true;
  •         }
  •         return false;
  •     }

  •     @Override
  •     public String handle() {
  •         try {
  •             return line.trim().split("\\s+")[1]; // 获取PID列
  •         } catch (Exception e) { // null和越界异常
  •             return line;
  •         }
  •     }

  • }
  


三、后记
         这个东西貌似还得动手改源码么T^T。小弟告罄了,不想碰那个东西==。
         附件工程,随便看看了……
         ps:Doxygen简单生成了个chm帮助文件,在docs目录下。
DSC0000.png


         我是不是很无聊了-_-!


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-621071-1-1.html 上篇帖子: The requested URL /server-status was not found on this server-Holy 下篇帖子: 解密SQL SERVER 2005加密存储过程,函数
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表