Android VNC Server

         利用shell开启VNC服务的测试版本==
 

一、直接开启VNC Server

1 )下载地址
         android-vnc-server: http://code.google.com/p/android-vnc-server/downloads/list
         android-vnc: http://code.google.com/p/android-vnc/downloads/list
 
2 )参考网址
         1、电脑控制手机的另一选择——android vnc server
          http://bbs.gfan.com/android-116468-1-1.html
         2、Android vnc server 安装
          http://www.51testing.com/?uid-49689-action-viewspace-itemid-211955
 
3 )操作简述
         前提:机子需要是破解的,否则su不可执行。
 
adb push "F:/androidvncserver" /data/(放进去)
adb shell chmod 755 /data/androidvncserver(加可执行权限)
adb shell /data/androidvncserver(执行androidvncserver)
adb forward tcp:5900 tcp:5901(端口重定向,我没弄==)
 
3.1)Q1:adb push
         有些机子破解后adb shell仍是$符,需要su后才是#。不能直接push进入/data/目录。

         因而可以先adb push "F:/androidvncserver" /sdcard/,之后adb shell->su->mv /sdcard/androidvncserver /data/

         /data/目录可以再建一层,为/data/local。因为如果你要用程序把androidvncserver写入的话,需要给该目录加写权限,这样涉及到的东西少些。
 
3.2)Q2:chmod

         755指rwxr-xr-x,是为了增加其可执行权限。和之前一样,默认是$符需要su才#的破解机子,也只能一步步来:adb shell->su->cd data->chmod a+x androidvncserver->./fbvncserver &

         (su:变更用户身份,不指定时为root;a+x:所有用户执行权限;&:后台运行)
 
3.3)Q3:关闭服务

         ps命令查看pid:ps|grep androidvnc*(这个程序里执行不过==)、ps -l androidvncserver

         kill ,杀死进程,即可关闭服务。
 
3.4)Q4:VNC Viewer连接不到==
         1、确认android端开了VNC Server的进程
         2、PC端看下能不能ping通android的ip
 
二、程序执行
1 )程序截图

 
2 )活动类(VNCServerActivity.java
 
    
  1. /** 
  2.  * @brief 利用shell开启VNC服务的测试版本 
  3.  * @detail 
  4.  * Question 
  5.  *  
  6.  * Q1:操作设计不合理,见谅-_-!(应该一直su,不要su后执行个命令就exit) 
  7.  *     另外,有些破解手机,默认是$而非#。现在这种操作方式就不适用了== 
  8.  * Q2:androidvncserver这个,Google HTC开不起来== 
  9.  *     纯shell操作,看到提示“cannot get ABS_X info, Invalid argument” 
  10.  * Q3:fbvncserver这个,我的那个Viewer接收到的画面怎么花绿的且有挤压== 
  11.  *  
  12.  * Solution 
  13.  *  
  14.  * S1:先还是利用shell来开VNC服务,找下有其他的没且重新改下流程。 
  15.  * S2:难道要下VNCServer源码么?要改东西?要加JNI接口?头疼T^T。 
  16.  *  
  17.  * @author Join 
  18.  * @date 2012-3-20 
  19.  */ 
  20. public class VNCServerActivity extends Activity { 
  21.  
  22.     private static final String TAG = "VNCServerActivity"
  23.     private static final boolean LOGD = true
  24.  
  25.     // assets目录下的VNCServer文件名 
  26.     private static final String VNC_SERVER_FILENAME = "fbvncserver"
  27.  
  28.     private GlobalUtil globalUtil; // 工具类 
  29.  
  30.     private Button startBtn, stopBtn; // 按钮 
  31.     private TextView statusView, connectView; // 标签 
  32.  
  33.     /* dialog identifiers */ 
  34.     private static final int DLG_BASE = 0
  35.     private static final int DLG_ROOT_FAILED = DLG_BASE + 1
  36.  
  37.     @Override 
  38.     public void onCreate(Bundle savedInstanceState) { 
  39.         super.onCreate(savedInstanceState); 
  40.         setContentView(R.layout.main); 
  41.  
  42.         startBtn = (Button) findViewById(R.id.startBtn); 
  43.         stopBtn = (Button) findViewById(R.id.stopBtn); 
  44.         statusView = (TextView) findViewById(R.id.statusView); 
  45.         connectView = (TextView) findViewById(R.id.connectView); 
  46.  
  47.         // 直接获IP地址了拼接个端口了,本应该从stdout获的== 
  48.         connectView.setText(getLocalIpAddress() + ":5901"); 
  49.  
  50.         globalUtil = GlobalUtil.getInstance(); // 获取工具类 
  51.  
  52.         if (initApp()) { // 初始化应用权限 
  53.             /* 判断服务是否开启了,以改变界面 */ 
  54.             changeViews(globalUtil.getPids(VNC_SERVER_FILENAME).size() >= 1); 
  55.         } 
  56.     } 
  57.  
  58.     /** 改变界面状态 */ 
  59.     private void changeViews(boolean isServerOn) { 
  60.         startBtn.setEnabled(!isServerOn); 
  61.         stopBtn.setEnabled(isServerOn); 
  62.         statusView.setText(isServerOn ? R.string.status_run 
  63.                 : R.string.status_stop); 
  64.     } 
  65.  
  66.     /** startBtn点击事件 */ 
  67.     public void startBtn(View v) { 
  68.         // 运行VNCServer文件(&:后台) 
  69.         boolean result = globalUtil.rootCommand("/data/" + VNC_SERVER_FILENAME 
  70.                 + " &"); 
  71.         if (LOGD) 
  72.             Log.d(TAG, "/data/" + VNC_SERVER_FILENAME + " &:\n" + result); 
  73.         changeViews(result); // 改变界面状态 
  74.         connectView.setText(getLocalIpAddress() + ":5901"); // 重设下IP显示 
  75.     } 
  76.  
  77.     /** stopBtn点击事件 */ 
  78.     public void stopBtn(View v) { 
  79.         ArrayList pidArray = globalUtil.getPids(VNC_SERVER_FILENAME); 
  80.         boolean result; 
  81.         for (String pid : pidArray) { 
  82.             result = globalUtil.rootCommand("kill " + pid); 
  83.             if (LOGD) 
  84.                 Log.d(TAG, "kill " + pid + ":" + result); 
  85.         } 
  86.         changeViews(false); 
  87.     } 
  88.  
  89.     /** 初始化应用权限 */ 
  90.     private boolean initApp() { 
  91.         boolean result = globalUtil.rootCommand("chmod 777 " 
  92.                 + getPackageCodePath()); 
  93.         if (result) { 
  94.             copyVNCServer(); // 检查vncserver文件 
  95.         } else { 
  96.             showDialog(DLG_ROOT_FAILED); // 提示退出应用 
  97.         } 
  98.         return result; 
  99.     } 
  100.  
  101.     /** 检查VNCServer文件,不存在时复制进去 */ 
  102.     private void copyVNCServer() { 
  103.         String filePath = "/data/" + VNC_SERVER_FILENAME; 
  104.         File file = new File(filePath); 
  105.  
  106.         /* 文件不存在时,从assets复制进去 */ 
  107.         if (!file.exists()) { 
  108.             try { 
  109.                 /* /data/目录增加所有用户的写权限 */ 
  110.                 boolean result = globalUtil.rootCommand("chmod a+w /data"); 
  111.                 if (LOGD) 
  112.                     Log.d(TAG, "==/data/目录增加写权限:" + result + "=="); 
  113.  
  114.                 if (result) { 
  115.                     /* 将VNCServer文件复制入/data/ */ 
  116.                     InputStream is = getAssets().open(VNC_SERVER_FILENAME); 
  117.                     FileOutputStream fos = new FileOutputStream(file); 
  118.                     byte[] buffer = new byte[2048]; 
  119.                     int count = 0
  120.                     while ((count = is.read(buffer)) > 0) { 
  121.                         fos.write(buffer, 0, count); 
  122.                     } 
  123.                     fos.close(); 
  124.                     is.close(); 
  125.                     if (LOGD) 
  126.                         Log.d(TAG, "==" + VNC_SERVER_FILENAME + "文件写入/data/!=="); 
  127.  
  128.                     /* 给VNCServer文件增加所有用户的执行权限 */ 
  129.                     result = globalUtil.rootCommand("chmod a+x " + filePath); 
  130.                     if (LOGD) 
  131.                         Log.d(TAG, "==" + filePath + "增加执行权限:" + result + "=="); 
  132.                 } 
  133.             } catch (IOException e) { 
  134.                 e.printStackTrace(); 
  135.             } 
  136.         } else { 
  137.             if (LOGD) 
  138.                 Log.d(TAG, "==" + VNC_SERVER_FILENAME + "文件已存在/data/目录下!=="); 
  139.         } 
  140.     } 
  141.  
  142.     @Override 
  143.     protected Dialog onCreateDialog(int id) { 
  144.         switch (id) { 
  145.         case DLG_ROOT_FAILED: 
  146.             return new AlertDialog.Builder(this
  147.                     .setTitle(R.string.root_title) 
  148.                     .setMessage(R.string.root_failed) 
  149.                     .setCancelable(false
  150.                     .setPositiveButton(R.string.dlg_ok, 
  151.                             new DialogInterface.OnClickListener() { 
  152.                                 @Override 
  153.                                 public void onClick(DialogInterface dialog, 
  154.                                         int which) { 
  155.                                     finish(); 
  156.                                 } 
  157.                             }).create(); 
  158.         } 
  159.         return super.onCreateDialog(id); 
  160.     } 
  161.  
  162.     /** 获取IP地址 */ 
  163.     public String getLocalIpAddress() { 
  164.         try { 
  165.             for (Enumeration en = NetworkInterface 
  166.                     .getNetworkInterfaces(); en.hasMoreElements();) { 
  167.                 NetworkInterface intf = en.nextElement(); 
  168.                 for (Enumeration enumIpAddr = intf 
  169.                         .getInetAddresses(); enumIpAddr.hasMoreElements();) { 
  170.                     InetAddress inetAddress = enumIpAddr.nextElement(); 
  171.                     if (!inetAddress.isLoopbackAddress()) { 
  172.                         return inetAddress.getHostAddress().toString(); 
  173.                     } 
  174.                 } 
  175.             } 
  176.         } catch (SocketException e) { 
  177.             e.printStackTrace(); 
  178.         } 
  179.         return null
  180.     } 
  181.  
 
3 )工具类(GlobalUtil.java
 
    
  1. public final class GlobalUtil { 
  2.  
  3.     /** 内部类GlobalUtilHolder */ 
  4.     static class GlobalUtilHolder { 
  5.         static GlobalUtil instance = new GlobalUtil(); 
  6.     } 
  7.  
  8.     /** 返回GlobalUtil的单例 */ 
  9.     public static GlobalUtil getInstance() { 
  10.         return GlobalUtilHolder.instance; 
  11.     } 
  12.  
  13.     /** 
  14.      * @brief ROOT权限执行一个shell命令 
  15.      * @detail 设备必须已破解,否则su不可用 
  16.      *  
  17.      * @param cmd 命令 
  18.      * @return 返回是否执行成功 
  19.      *  
  20.      * @code 
  21.      * 修改应用权限: 
  22.      *   String apkRoot="chmod 777 " + getPackageCodePath(); 
  23.      *   GlobalUtil.getInstance().chmodCommand(apkRoot); 
  24.      * @endcode 
  25.      */ 
  26.     public boolean rootCommand(String cmd) { 
  27.         Process process = null
  28.         DataOutputStream os = null
  29.         try { 
  30.             // su变更用户身份(不指定用户时,预设root) 
  31.             process = Runtime.getRuntime().exec("su"); 
  32.             // 连接到子进程正常输入的输出流 
  33.             os = new DataOutputStream(process.getOutputStream()); 
  34.             os.writeBytes(cmd + "\n"); 
  35.             os.writeBytes("exit\n"); 
  36.             os.flush(); 
  37.             process.waitFor(); // 等待执行完成 
  38.         } catch (Exception e) { 
  39.             return false
  40.         } finally { 
  41.             try { 
  42.                 if (null != process) { 
  43.                     process.destroy(); 
  44.                 } 
  45.                 if (null != os) { 
  46.                     os.close(); 
  47.                 } 
  48.             } catch (Exception e) { 
  49.             } 
  50.         } 
  51.         return true
  52.     } 
  53.  
  54.     /** 
  55.      * @brief 执行一个shell命令 
  56.      * 
  57.      * @param cmd 命令名称&参数组成的数组 
  58.      * @param workDir 命令工作目录 
  59.      * @return 命令输出结果 
  60.      */ 
  61.     public String execCommand(String[] cmd, String workDir) { 
  62.         StringBuffer result = new StringBuffer(); 
  63.         try { 
  64.             // 创建操作系统进程(也可以由Runtime.exec()启动) 
  65.             ProcessBuilder builder = new ProcessBuilder(cmd); 
  66.             // 设置命令工作目录 
  67.             if (workDir != null) { 
  68.                 builder.directory(new File(workDir)); 
  69.             } 
  70.             // 合并标准错误和标准输出 
  71.             builder.redirectErrorStream(true); 
  72.             // 启动一个新进程 
  73.             Process process = builder.start(); 
  74.             /* 获得运行输出结果 */ 
  75.             InputStream is = process.getInputStream(); 
  76.             BufferedReader br = new BufferedReader(new InputStreamReader(is)); 
  77.             String line; 
  78.             while (null != (line = br.readLine())) { 
  79.                 result.append(line); 
  80.                 result.append("\n"); 
  81.             } 
  82.             if (is != null) { 
  83.                 is.close(); 
  84.                 br.close(); 
  85.             } 
  86.         } catch (Exception e) { 
  87.             e.printStackTrace(); 
  88.         } 
  89.         return result.toString(); 
  90.     } 
  91.  
  92.     /** 
  93.      * @brief ps某一执行程序,获取其pid 
  94.      * 
  95.      * @param execFilename 
  96.      * @return pid的list 
  97.      */ 
  98.     public ArrayList getPids(String execFilename) { 
  99.         ArrayList pidArray = new ArrayList(); 
  100.         String result = execCommand(new String[] { "ps""-l", execFilename }, 
  101.                 null); 
  102.         if (null != result && !"".endsWith(result)) { 
  103.             String[] resultArray = result.split("\n"); 
  104.             int len = resultArray.length; 
  105.             try { 
  106.                 /* 从第二行开始遍历 */ 
  107.                 for (int i = 1; i < len; i++) { 
  108.                     // 空格区分的第二个字符串 
  109.                     pidArray.add(resultArray[i].trim().split("\\s+")[1]); 
  110.                 } 
  111.             } catch (ArrayIndexOutOfBoundsException e) { 
  112.             } 
  113.         } 
  114.         return pidArray; 
  115.     } 
 
三、其他参考
         1、linux权限详解
          http://blog.csdn.net/fan_zhen_hua/article/details/2050009
         2、Linux命令大全(修改版).zip
          http://vaero.blog.51cto.com/4350852/796090,附件资料。
         3、Android执行shell命令
          http://vaero.blog.51cto.com/4350852/778139,附件资料。
         4、Google Code的wiki&issues
          http://code.google.com/p/android-vnc-server/wiki/README
 
四、后记

         实现的不好,好多问题啊T^T。(还待完善,请多担待!)

 

         psfastdroid-vnc这个项目好像也不错^^

         http://code.google.com/p/fastdroid-vnc/wiki/fastdroidvnc

 

1)开启fastdroid-vnc

 

2)关闭fastdroid-vnc