363 Stimmen

Feststellen, ob ein gerootetes Gerät verwendet wird

Meine App hat eine bestimmte Funktionalität, die nur auf einem Gerät funktioniert, auf dem Root verfügbar ist. Anstatt diese Funktion bei der Verwendung fehlschlagen zu lassen (und dem Benutzer dann eine entsprechende Fehlermeldung anzuzeigen), würde ich eine Möglichkeit bevorzugen, zuerst stillschweigend zu prüfen, ob Root verfügbar ist, und wenn nicht, die entsprechenden Optionen von vornherein auszublenden.

Gibt es eine Möglichkeit, dies zu tun?

295voto

Kevin Parker Punkte 16483

Hier ist eine Klasse, die auf eine von drei Arten nach Root sucht.

/** @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();
        }
    }
}

108voto

kingston Punkte 10251

Wenn Sie bereits Fabric/Firebase Crashlytics verwenden, können Sie

CommonUtils.isRooted(context)

Dies ist die derzeitige Umsetzung dieser Methode:

public static boolean isRooted(Context context) {
    boolean isEmulator = isEmulator(context);
    String buildTags = Build.TAGS;
    if (!isEmulator && buildTags != null && buildTags.contains("test-keys")) {
        return true;
    } else {
        File file = new File("/system/app/Superuser.apk");
        if (file.exists()) {
            return true;
        } else {
            file = new File("/system/xbin/su");
            return !isEmulator && file.exists();
        }
    }
}

public static boolean isEmulator(Context context) {
    String androidId = Secure.getString(context.getContentResolver(), "android_id");
    return "sdk".equals(Build.PRODUCT) || "google_sdk".equals(Build.PRODUCT) || androidId == null;
}

60voto

Intrications Punkte 16452

Die RootTools-Bibliothek bietet einfache Methoden zur Prüfung auf Root:

RootTools.isRootAvailable()

Referenz

60voto

Devrim Punkte 14995

In meiner Anwendung habe ich überprüft, ob das Gerät verwurzelt ist oder nicht, indem ich den Befehl "su" ausgeführt habe. Aber heute habe ich diesen Teil meines Codes entfernt. Warum?

Denn meine Anwendung wurde zu einem Speicherkiller. Wie das? Lassen Sie mich Ihnen meine Geschichte erzählen.

Es gab einige Beschwerden, dass meine Anwendung Geräte verlangsamt (natürlich dachte ich, dass das nicht stimmen kann). Ich habe versucht, herauszufinden, warum. Also verwendete ich MAT, um Heap Dumps zu erhalten und zu analysieren, und alles schien perfekt zu sein. Aber nachdem ich meine Anwendung mehrmals neu gestartet hatte, stellte ich fest, dass das Gerät wirklich langsamer wurde und das Stoppen meiner Anwendung es nicht schneller machte (es sei denn, ich starte das Gerät neu). Ich analysierte die Dump-Dateien erneut, während das Gerät sehr langsam war. Aber alles war immer noch perfekt für die Dump-Datei. Dann habe ich getan, was als erstes getan werden muss. Ich habe die Prozesse aufgelistet.

$ adb shell ps

Zu meiner Überraschung gab es viele Prozesse für meine Bewerbung (mit dem Prozess-Tag meiner Bewerbung bei manifest). Einige von ihnen war Zombie einige von ihnen nicht.

Bei einer Beispielanwendung, die eine einzige Aktivität hat und nur den Befehl "su" ausführt, habe ich festgestellt, dass bei jedem Start der Anwendung ein Zombieprozess erstellt wird. Zuerst weisen diese Zombies 0 KB zu, aber dann passiert etwas und die Zombie-Prozesse halten fast die gleichen KBs wie der Hauptprozess meiner Anwendung und sie wurden zu Standardprozessen.

Es gibt einen Fehlerbericht für dasselbe Problem auf bugs.sun.com: http://bugs.sun.com/view_bug.do?bug_id=6474073 Dies erklärt, dass, wenn der Befehl nicht gefunden wird, Zombies mit der Methode exec() erstellt werden. Aber ich verstehe immer noch nicht, warum und wie sie zu eigenständigen Prozessen werden und wichtige KBs halten können. (Dies geschieht nicht die ganze Zeit)

Sie können es mit dem unten stehenden Beispielcode versuchen;

String commandToExecute = "su";
executeShellCommand(commandToExecute);

Einfache Methode zur Befehlsausführung;

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) {
            }
        }
    }
}

Zusammenfassend kann ich Ihnen keinen Rat geben, wie Sie feststellen können, ob Ihr Gerät verwurzelt ist oder nicht. Aber wenn ich Sie wäre, würde ich nicht Runtime.getRuntime().exec() verwenden.

Übrigens: RootTools.isRootAvailable() verursacht dasselbe Problem.

41voto

rsimp Punkte 700

Viele der hier aufgeführten Antworten sind mit Problemen behaftet:

  • Die Prüfung auf Testschlüssel korreliert mit dem Root-Zugriff, garantiert ihn aber nicht unbedingt.
  • "PATH"-Verzeichnisse sollten von der aktuellen "PATH"-Umgebungsvariablen abgeleitet werden, anstatt hart kodiert zu sein
  • Das Vorhandensein der ausführbaren Datei "su" bedeutet nicht unbedingt, dass das Gerät gerootet wurde
  • Die ausführbare Datei "which" kann installiert sein oder auch nicht, und Sie sollten den Pfad nach Möglichkeit vom System ermitteln lassen
  • Nur weil die SuperUser-App auf dem Gerät installiert ist, bedeutet das noch nicht, dass das Gerät Root-Zugriff hat.

Les RootTools Bibliothek von Stericson scheint die Überprüfung auf Root legitimer zu sein. Sie hat auch viele zusätzliche Tools und Dienstprogramme, so dass ich sie sehr empfehlen kann. Allerdings gibt es keine Erklärung, wie es speziell für Root überprüft, und es kann ein bisschen schwerer sein als die meisten Anwendungen wirklich brauchen.

Ich habe eine Reihe von Dienstprogrammen entwickelt, die lose auf der RootTools-Bibliothek basieren. Wenn Sie einfach nur überprüfen wollen, ob sich die ausführbare Datei "su" auf dem Gerät befindet, können Sie die folgende Methode verwenden:

public static boolean isRootAvailable(){
    for(String pathDir : System.getenv("PATH").split(":")){
        if(new File(pathDir, "su").exists()) {
            return true;
        }
    }
    return false;
}

Diese Methode durchläuft einfach die Verzeichnisse, die in der Umgebungsvariablen "PATH" aufgeführt sind, und prüft, ob eine "su"-Datei in einem dieser Verzeichnisse existiert.

Um wirklich auf Root-Zugriff zu prüfen, muss der Befehl "su" tatsächlich ausgeführt werden. Wenn eine Anwendung wie SuperUser installiert ist, kann sie an dieser Stelle nach Root-Zugriff fragen, oder wenn dieser bereits gewährt/verweigert wurde, kann ein Toast angezeigt werden, der angibt, ob der Zugriff gewährt/verweigert wurde. Ein guter Befehl ist "id", damit Sie überprüfen können, ob die Benutzerkennung tatsächlich 0 (Root) ist.

Hier ein Beispiel für eine Methode, um festzustellen, ob Root-Zugriff gewährt wurde:

public static boolean isRootGiven(){
    if (isRootAvailable()) {
        Process process = null;
        try {
            process = Runtime.getRuntime().exec(new String[]{"su", "-c", "id"});
            BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String output = in.readLine();
            if (output != null && output.toLowerCase().contains("uid=0"))
                return true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (process != null)
                process.destroy();
        }
    }

    return false;
}

Es ist wichtig, die Ausführung des "su"-Befehls tatsächlich zu testen, da einige Emulatoren die ausführbare Datei "su" vorinstalliert haben, aber nur bestimmten Benutzern den Zugriff darauf erlauben, wie z. B. der adb-Shell.

Es ist auch wichtig zu überprüfen, ob die ausführbare Datei "su" vorhanden ist, bevor man versucht, sie auszuführen, da Android dafür bekannt ist, Prozesse, die versuchen, fehlende Befehle auszuführen, nicht ordnungsgemäß zu entsorgen. Diese Geisterprozesse können mit der Zeit den Speicherverbrauch in die Höhe treiben.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X