zoukankan      html  css  js  c++  java
  • 【Android】不弹root请求框检测手机是否root

    由于项目需要root安装软件,并且希望在合适的时候引导用户去开启root安装,故需要检测手机是否root。

    最基本的判断如下,直接运行一个底层命令。(参考https://github.com/Trinea/android-common/blob/master/src/cn/trinea/android/common/util/ShellUtils.java)

    也可参考csdn http://blog.csdn.net/fm9333/article/details/12752415

    1     /**
      2      * check whether has root permission
      3      * 
      4      * @return
      5      */
      6     public static boolean checkRootPermission() {
      7         return execCommand("echo root", true, false).result == 0;
      8     }
      9     
     10 
     11     /**
     12      * execute shell commands
     13      * 
     14      * @param commands
     15      *            command array
     16      * @param isRoot
     17      *            whether need to run with root
     18      * @param isNeedResultMsg
     19      *            whether need result msg
     20      * @return <ul>
     21      *         <li>if isNeedResultMsg is false, {@link CommandResult#successMsg}
     22      *         is null and {@link CommandResult#errorMsg} is null.</li>
     23      *         <li>if {@link CommandResult#result} is -1, there maybe some
     24      *         excepiton.</li>
     25      *         </ul>
     26      */
     27     public static CommandResult execCommand(String[] commands, boolean isRoot,
     28             boolean isNeedResultMsg) {
     29         int result = -1;
     30         if (commands == null || commands.length == 0) {
     31             return new CommandResult(result, null, null);
     32         }
     33 
     34         Process process = null;
     35         BufferedReader successResult = null;
     36         BufferedReader errorResult = null;
     37         StringBuilder successMsg = null;
     38         StringBuilder errorMsg = null;
     39 
     40         DataOutputStream os = null;
     41         try {
     42             process = Runtime.getRuntime().exec(
     43                     isRoot ? COMMAND_SU : COMMAND_SH);
     44             os = new DataOutputStream(process.getOutputStream());
     45             for (String command : commands) {
     46                 if (command == null) {
     47                     continue;
     48                 }
     49 
     50                 // donnot use os.writeBytes(commmand), avoid chinese charset
     51                 // error
     52                 os.write(command.getBytes());
     53                 os.writeBytes(COMMAND_LINE_END);
     54                 os.flush();
     55             }
     56             os.writeBytes(COMMAND_EXIT);
     57             os.flush();
     58 
     59             result = process.waitFor();
     60             // get command result
     61             if (isNeedResultMsg) {
     62                 successMsg = new StringBuilder();
     63                 errorMsg = new StringBuilder();
     64                 successResult = new BufferedReader(new InputStreamReader(
     65                         process.getInputStream()));
     66                 errorResult = new BufferedReader(new InputStreamReader(
     67                         process.getErrorStream()));
     68                 String s;
     69                 while ((s = successResult.readLine()) != null) {
     70                     successMsg.append(s);
     71                 }
     72                 while ((s = errorResult.readLine()) != null) {
     73                     errorMsg.append(s);
     74                 }
     75             }
     76         } catch (IOException e) {
     77             e.printStackTrace();
     78         } catch (Exception e) {
     79             e.printStackTrace();
     80         } finally {
     81             try {
     82                 if (os != null) {
     83                     os.close();
     84                 }
     85                 if (successResult != null) {
     86                     successResult.close();
     87                 }
     88                 if (errorResult != null) {
     89                     errorResult.close();
     90                 }
     91             } catch (IOException e) {
     92                 e.printStackTrace();
     93             }
     94 
     95             if (process != null) {
     96                 process.destroy();
     97             }
     98         }
     99         return new CommandResult(result, successMsg == null ? null
    100                 : successMsg.toString(), errorMsg == null ? null
    101                 : errorMsg.toString());
    102     }
    103 
    104     /**
    105      * result of command,
    106      * <ul>
    107      * <li>{@link CommandResult#result} means result of command, 0 means normal,
    108      * else means error, same to excute in linux shell</li>
    109      * <li>{@link CommandResult#successMsg} means success message of command
    110      * result</li>
    111      * <li>{@link CommandResult#errorMsg} means error message of command result</li>
    112      * </ul>
    113      * 
    114      * @author Trinea 2013-5-16
    115      */
    116     public static class CommandResult {
    117 
    118         /** result of command **/
    119         public int result;
    120         /** success message of command result **/
    121         public String successMsg;
    122         /** error message of command result **/
    123         public String errorMsg;
    124 
    125         public CommandResult(int result) {
    126             this.result = result;
    127         }
    128 
    129         public CommandResult(int result, String successMsg, String errorMsg) {
    130             this.result = result;
    131             this.successMsg = successMsg;
    132             this.errorMsg = errorMsg;
    133         }
    134     }    /**
    135      * execute shell command, default return result msg
    136      * 
    137      * @param command
    138      *            command
    139      * @param isRoot
    140      *            whether need to run with root
    141      * @return
    142      * @see ShellUtils#execCommand(String[], boolean, boolean)
    143      */
    144     public static CommandResult execCommand(String command, boolean isRoot) {
    145         return execCommand(new String[] { command }, isRoot, true);
    146     }

    但是这会带来一个问题,每次判断是否root都会弹出一个root请求框。这是十分不友好的一种交互方式,而且,用户如果选择取消,有部分手机是判断为非root的。

    这是方法一。交互不友好,而且有误判。

    在这个情况下,为了不弹出确认框,考虑到一般root手机都会有一些的特殊文件夹,比如/system/bin/su,/system/xbin/su,里面存放有相关的权限控制文件。

    因此只要手机中有一个文件夹存在就判断这个手机root了。

    然后经过测试,这种方法在大部分手机都可行。

    代码如下:

    /** 判断是否具有ROOT权限 ,此方法对有些手机无效,比如小米系列 */
     2     public static boolean isRoot() {
     3 
     4         boolean res = false;
     5 
     6         try {
     7             if ((!new File("/system/bin/su").exists())
     8                     && (!new File("/system/xbin/su").exists())) {
     9                 res = false;
    10             } else {
    11                 res = true;
    12             }
    13             ;
    14         } catch (Exception e) {
    15             res = false;
    16         }
    17         return res;
    18     }

    这是方法二。交互友好,但是有误判。

    后来测试的过程中发现部分国产,比如小米系列,有这个文件夹,但是系统是未root的,判断成了已root。经过分析,这是由于小米有自身的权限控制系统而导致。

    考虑到小米手机有大量的用户群,这个问题必须解决,所以不得不寻找第三种方案。

    从原理着手,小米手机无论是否root,应该都是具有相关文件的。但是无效的原因应该是,文件设置了相关的权限。导致用户组无法执行相关文件。

    从这个角度看,就可以从判断文件的权限入手。

    先看下linux的文件权限吧。

    linux文件权限详细可参考《鸟叔的linux私房菜》http://vbird.dic.ksu.edu.tw/linux_basic/0210filepermission.php#filepermission_perm

    只需要在第二种方法的基础上,再另外判断文件拥有者对这个文件是否具有可执行权限(第4个字符的状态),就基本可以确定手机是否root了。

    在已root手机上(三星i9100 android 4.4),文件权限(x或者s,s权限,可参考http://blog.chinaunix.net/uid-20809581-id-3141879.html)如下

    未root手机,大部分手机没有这两个文件夹,小米手机有这个文件夹。未root小米手机权限如下(由于手头暂时没有小米手机,过几天补上,或者有同学帮忙补上,那真是感激不尽)。

    【等待补充图片】

    代码如下:
    /** 判断手机是否root,不弹出root请求框<br/> */
     2     public static boolean isRoot() {
     3         String binPath = "/system/bin/su";
     4         String xBinPath = "/system/xbin/su";
     5         if (new File(binPath).exists() && isExecutable(binPath))
     6             return true;
     7         if (new File(xBinPath).exists() && isExecutable(xBinPath))
     8             return true;
     9         return false;
    10     }
    11 
    12     private static boolean isExecutable(String filePath) {
    13         Process p = null;
    14         try {
    15             p = Runtime.getRuntime().exec("ls -l " + filePath);
    16             // 获取返回内容
    17             BufferedReader in = new BufferedReader(new InputStreamReader(
    18                     p.getInputStream()));
    19             String str = in.readLine();
    20             Log.i(TAG, str);
    21             if (str != null && str.length() >= 4) {
    22                 char flag = str.charAt(3);
    23                 if (flag == 's' || flag == 'x')
    24                     return true;
    25             }
    26         } catch (IOException e) {
    27             e.printStackTrace();
    28         }finally{
    29             if(p!=null){
    30                 p.destroy();
    31             }
    32         }
    33         return false;
    34     }

    这种方法基本可以判断所有的手机,而且不弹出root请求框。这才是我们需要的,perfect。

    方法三,交互友好,基本没有误判。

    参考链接:http://www.cnblogs.com/waylife/p/3846440.html

  • 相关阅读:
    图论算法之查找强分支
    图论算法之拓扑排序的简单代码
    图论算法之最短路径
    由函数符号找不到联想到的动态链接过程
    linux下cp覆盖原so文件时引起的段错误原因确定
    java 中能否使用 动态加载的类(Class.forName) 来做类型转换?
    为什么java不支持多重继承?
    static inner class 什么时候被加载
    thinking in java 读书笔记 --- overriding private method
    java List排序方法 Comparator和Comparable
  • 原文地址:https://www.cnblogs.com/klcf0220/p/3856375.html
Copyright © 2011-2022 走看看