我的应用程序有一个特定的功能,只能在根可用的设备上工作。与其让这个特性在使用时失败(然后向用户显示适当的错误消息),我更希望能够先静默地检查根目录是否可用,如果不可用,则首先隐藏相应的选项。
有办法做到这一点吗?
我的应用程序有一个特定的功能,只能在根可用的设备上工作。与其让这个特性在使用时失败(然后向用户显示适当的错误消息),我更希望能够先静默地检查根目录是否可用,如果不可用,则首先隐藏相应的选项。
有办法做到这一点吗?
当前回答
http://code.google.com/p/roottools/
如果你不想使用jar文件,请使用下面的代码:
public static boolean findBinary(String binaryName) {
boolean found = false;
if (!found) {
String[] places = { "/sbin/", "/system/bin/", "/system/xbin/",
"/data/local/xbin/", "/data/local/bin/",
"/system/sd/xbin/", "/system/bin/failsafe/", "/data/local/" };
for (String where : places) {
if (new File(where + binaryName).exists()) {
found = true;
break;
}
}
}
return found;
}
程序将尝试查找su文件夹:
private static boolean isRooted() {
return findBinary("su");
}
例子:
if (isRooted()) {
textView.setText("Device Rooted");
} else {
textView.setText("Device Unrooted");
}
其他回答
截至2021年(今天),似乎没有任何可靠的方法或方法来检测根目录,特别是在启用了MagiskHide等强大的隐藏工具的情况下。这里的大多数答案都不再相关,所以不要在生产中使用它。依靠可靠的检查,如SafetyNet,而不是额外的英里检测根,我建议在两个运行时保护你的应用程序,如防止调试器/检测,并确保使用混淆。
根据这里的一些答案,我合并了它们,并添加了一个检查是否安装了一些已知的根管理器应用程序:
fun isProbablyRooted(context: Context, alsoIncludeCheckingRootManagerApp: Boolean = false): Boolean {
return hasRootManagerSystemApp(context) || (alsoIncludeCheckingRootManagerApp && hasRootManagerSystemApp(context))
}
fun hasRootManagerSystemApp(context: Context): Boolean {
val rootAppsPackageNames = arrayOf("com.topjohnwu.magisk", "eu.chainfire.supersu", "com.koushikdutta.superuser", "com.noshufou.android.su", "me.phh.superuser")
rootAppsPackageNames.forEach { rootAppPackageName ->
try {
context.packageManager.getApplicationInfo(rootAppPackageName, 0)
return true
} catch (e: Exception) {
}
}
return false
}
fun hasSuBinary(): Boolean {
return try {
findBinary("su")
} catch (e: Exception) {
e.printStackTrace()
false
}
}
private fun findBinary(binaryName: String): Boolean {
val paths = System.getenv("PATH")
if (!paths.isNullOrBlank()) {
val systemPlaces: List<String> = paths.split(":")
return systemPlaces.firstOrNull { File(it, binaryName).exists() } != null
}
val places = arrayOf("/sbin/", "/system/bin/", "/system/xbin/", "/data/local/xbin/", "/data/local/bin/",
"/system/sd/xbin/", "/system/bin/failsafe/", "/data/local/")
return places.firstOrNull { File(it, binaryName).exists() } != null
}
清单:
<queries>
<package android:name="com.topjohnwu.magisk" />
<package android:name="eu.chainfire.supersu" />
<package android:name="com.koushikdutta.superuser" />
<package android:name="com.noshufou.android.su" />
<package android:name="me.phh.superuser" />
</queries>
当然,这仍然是一个猜测,就像所有其他解一样。 例如,用户可以安装Magisk,而无需对设备进行root操作。
另外两个方法,如果你想检查一个设备在你的应用程序中是否具有根功能:
检查是否存在“su”二进制文件:从Runtime.getRuntime().exec()运行"which su" 在/system/app/ SuperUser.apk目录下查找SuperUser.apk
下面是一个类,它将以三种方式之一检查Root。
/** @author Kevin Kowalewski */
public class RootUtil {
public static boolean isDeviceRooted() {
return checkRootMethod1() || checkRootMethod2() || checkRootMethod3();
}
private static boolean checkRootMethod1() {
String buildTags = android.os.Build.TAGS;
return buildTags != null && buildTags.contains("test-keys");
}
private static boolean checkRootMethod2() {
String[] paths = { "/system/app/Superuser.apk", "/sbin/su", "/system/bin/su", "/system/xbin/su", "/data/local/xbin/su", "/data/local/bin/su", "/system/sd/xbin/su",
"/system/bin/failsafe/su", "/data/local/su", "/su/bin/su"};
for (String path : paths) {
if (new File(path).exists()) return true;
}
return false;
}
private static boolean checkRootMethod3() {
Process process = null;
try {
process = Runtime.getRuntime().exec(new String[] { "/system/xbin/which", "su" });
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
if (in.readLine() != null) return true;
return false;
} catch (Throwable t) {
return false;
} finally {
if (process != null) process.destroy();
}
}
}
在我的应用程序中,我通过执行“su”命令检查设备是否根。但是今天我删除了这部分代码。为什么?
因为我的应用程序成了内存杀手。怎么做?让我告诉你我的故事。
There were some complaints that my application was slowing down devices(Of course I thought that can not be true). I tried to figure out why. So I used MAT to get heap dumps and analyze, and everything seemed perfect. But after relaunching my app many times I realized that device is really getting slower and stopping my application didn't make it faster (unless I restart device). I analyzed dump files again while device is very slow. But everything was still perfect for dump file. Then I did what must be done at first. I listed processes.
$ adb shell ps
使震惊;我的应用程序有许多进程(应用程序的进程标签在manifest上)。有些是僵尸,有些不是。
对于一个只有一个Activity并只执行“su”命令的示例应用程序,我意识到在每次启动应用程序时都会创建一个僵尸进程。起初,这些僵尸进程分配0KB,但后来发生了一些事情,僵尸进程与我的应用程序的主进程占用了几乎相同的kb,它们成为了标准进程。
在bugs.sun.com: http://bugs.sun.com/view_bug.do?bug_id=6474073上有一个关于相同问题的错误报告,这解释了如果命令没有找到,将使用exec()方法创建僵尸。但我仍然不明白它们为什么以及如何成为标准流程并保持重要的kb。(这并不是一直都在发生)
你可以尝试如果你想下面的代码示例;
String commandToExecute = "su";
executeShellCommand(commandToExecute);
简单的命令执行方法;
private boolean executeShellCommand(String command){
Process process = null;
try{
process = Runtime.getRuntime().exec(command);
return true;
} catch (Exception e) {
return false;
} finally{
if(process != null){
try{
process.destroy();
}catch (Exception e) {
}
}
}
}
总结:总结;我没有建议你确定设备是否扎根。但如果我是你,我不会使用Runtime.getRuntime().exec()。
顺便说一下;RootTools.isRootAvailable()也会引起同样的问题。