You often want to restrict user on a rooted device for doing any specific operation, like making an online payment in a Banking app or e-commerce App.
If you google around, there are tons of code which might help you determine whether a device is rooted or not. Hence, in order to make your life a little simpler, you can use the following code to determine the same.
public boolean isRooted() { boolean isRootManagementApplicationInstalled = detectRootManagementApps(); boolean isPotentiallyDangerousAppsInstalled = detectPotentiallyDangerousApps(); boolean isRootCloakingApplicationInstalled = detectRootCloakingApps(); boolean isSuBinaryFileExists = isSuBinaryFileExists(); boolean isDangerousPropsExists = checkForDangerousProps(); boolean isRWPaths = checkForRWPaths(); boolean isTestKeysAvailable = detectTestKeys(); boolean isSuCommandExecutes = isSuCommandExecutes(); boolean isMagiskBinaryFileExists = isMagiskBinaryFileExists(); boolean isThirdPartyApp = isRootManagementApplicationInstalled || isPotentiallyDangerousAppsInstalled || isRootCloakingApplicationInstalled; boolean isSuOrDangerousPath = isSuBinaryFileExists || isSuCommandExecutes || isDangerousPropsExists; boolean isTestOrMagiskOrRW = isRWPaths || isTestKeysAvailable || isMagiskBinaryFileExists; return isThirdPartyApp || isSuOrDangerousPath || isTestOrMagiskOrRW; } /** * this function checks whether the kernel is signed with custom key generated by a third-party developer. * * @return true if signed with test-keys */ private boolean detectTestKeys() { String buildTags = android.os.Build.TAGS; return buildTags != null && buildTags.contains(TEST_KEYS); } /** * This methods check for root apps using PackageManager. * * @return true if one of the rooting app is installed else false */ private boolean detectRootManagementApps() { ArrayList<String> packages = new ArrayList<>(); packages.addAll(Arrays.asList(ROOT_APPS_PACKAGES)); return isAnyPackageFromListInstalled(packages); } /** * check for the apps which require roo * * @return true if root requiring app installed else false */ private boolean detectPotentiallyDangerousApps() { ArrayList<String> packages = new ArrayList<>(); packages.addAll(Arrays.asList(DANGEROUS_APPS_PACKAGES)); return isAnyPackageFromListInstalled(packages); } /** * This function check for the root cloaking apps using PackageManager. * * @return true if one of the apps it's installed */ private boolean detectRootCloakingApps() { ArrayList<String> packages = new ArrayList<>(); packages.addAll(Arrays.asList(ROOT_CLOAKING_PACKAGES)); return isAnyPackageFromListInstalled(packages); } /** * This method check for common locations of SU binary * * @return true if found su binary else false */ private boolean isSuBinaryFileExists() { return checkForBinary(SU); } /** * * @return true if @link {MAGISK} binary found else false */ private boolean isMagiskBinaryFileExists() { return checkForBinary(MAGISK); } /** * checks for binary in common su_Paths * * filename - check for this existence of this file * @return true if found else false */ private boolean checkForBinary(String filename) { boolean result = false; for (String path : SU_PATHS) { File f = new File(path, filename); boolean fileExists = f.exists(); if (fileExists) { result = true; } } return result; } /** * @return array of getProp splitted using "\\A" */ private String[] propsReader() { try { InputStream inputstream = Runtime.getRuntime().exec(GETPROP).getInputStream(); if (inputstream == null) { return new String[0]; } String propVal = new Scanner(inputstream).useDelimiter(DELIMETER_A).next(); return propVal.split("\n"); } catch (IOException | NoSuchElementException exception) { Log.e(TAG, "RootHelper.propsReader : exception - " + exception); return new String[0]; } } /** * @return array of mount command splitted using "\\A" and "\n" */ private String[] mountReader() { try { InputStream inputstream = Runtime.getRuntime().exec(MOUNT).getInputStream(); if (inputstream == null) { return new String[0]; } String propVal = new Scanner(inputstream).useDelimiter(DELIMETER_A).next(); return propVal.split("\n"); } catch (IOException | NoSuchElementException exception) { Log.e(TAG, "RootHelper.mountReader : exception - " + exception); return new String[0]; } } /** * Check if any package in the list is installed * * packages - list of packages to search for * @return true if any of the packages are installed */ private boolean isAnyPackageFromListInstalled(List<String> packages) { boolean result = false; PackageManager pm = BaseApplication.getInstance().getPackageManager(); for (String packageName : packages) { try { pm.getPackageInfo(packageName, 0); result = true; } catch (PackageManager.NameNotFoundException exception) { Log.e(TAG, "RootHelper.isAnyPackageFromListInstalled : exception - " + exception); } } return result; } /** * This method check for system's dangerous properties * * @return - true if dangerous props found else false */ private boolean checkForDangerousProps() { final Map<String, String> dangerousProps = new ArrayMap<>(); dangerousProps.put(RO_DEBUGGABLE, "1"); dangerousProps.put(RO_SECURE, "0"); boolean result = false; String[] lines = propsReader(); if (lines.length == 0) { return false; } for (String line : lines) { for (Map.Entry<String, String> entry : dangerousProps.entrySet()) { result = isDangerousProps(line, entry); } } return result; } /** * line line * entry map entry set * @return rue if dangerous props found else false */ private boolean isDangerousProps(String line, Map.Entry<String, String> entry) { if (line.contains(entry.getKey())) { StringBuilder badValue = new StringBuilder(entry.getValue()); badValue.append(OPEN_BRACKET).append(badValue).append(CLOSING_BRACKET); if (line.contains(badValue)) { return true; } } return false; } /** * this method checks * if any of the paths are writable. * * @return true any of the non writable directory is writable, else false */ public boolean checkForRWPaths() { boolean result = false; String[] lines = mountReader(); if (lines.length == 0) { return false; } for (String line : lines) { String[] args = line.split(" "); if (args.length < 4) { continue; } String mountPoint = args[1]; String mountOptions = args[3]; for (String pathToCheck : PATHS_THAT_SHOULD_NOT_BE_WRITABLE) { result = checkForRWPathsExtended(mountPoint, mountOptions, pathToCheck); } } return result; } /** * checks if directory is writable * * mountPoint mount point * mountOptions mount options * pathToCheck path to check * @return true if directory is writable else false */ private boolean checkForRWPathsExtended(String mountPoint, String mountOptions, String pathToCheck) { if (mountPoint.equalsIgnoreCase(pathToCheck)) { for (String option : mountOptions.split(",")) { if (option.equalsIgnoreCase(RW)) { return true; } } } return false; } /** * * @return true if 'which su' command executes else false */ private boolean isSuCommandExecutes() { Process process = null; try { process = Runtime.getRuntime().exec(new String[]{WHICH, SU}); BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream())); return in.readLine() != null; } catch (IOException exception) { Log.e(TAG, "RootHelper.isSuCommandExecutes : exception - " + exception); } finally { if (process != null) { process.destroy(); } } return false; } }
Note: If you have any method which can be part of this Util class, feel free to leave a comment. You can download the sample app from here.
With increase vulnerabilities in security, it makes sense to check if the device is rooted or not.