To protect sensitive app logic or user data, verifying the host Android device’s security configuration is a critical layer of defense. Below are actionable implementations for monitoring three high-risk device states.
Checking for Enabled Developer Options
Modern Android stores developer options toggle state in Settings.Global (deprecated usage in Settings.Secure for newer API levels). The following implementation graceful handles API differences, returning a boolean flagging enabled status:
import android.content.Context
import android.provider.Settings
fun checkDevOptionsActive(ctx: Context): Boolean {
val resolver = ctx.contentResolver
val key = Settings.Global.DEVELOPMENT_SETTINGS_ENABLED
return try {
Settings.Global.getInt(resolver, key) == 1
} catch (e: Settings.SettingNotFoundException) {
// If key is missing, default to false as disabled state
false
}
}
Verifying ADB Debugging Activation
ADB debugging grants full device access when connected to a trusted computer, so its status must be checked. This implementation also uses Settings.Global with error handling:
import android.content.Context
import android.provider.Settings
fun checkAdbDebuggingOn(ctx: Context): Boolean {
val resolver = ctx.contentResolver
val debugKey = Settings.Global.ADB_ENABLED
return try {
Settings.Global.getInt(resolver, debugKey) != 0
} catch (ex: Settings.SettingNotFoundException) {
// Fallback: assume disabled if setting is unavailable
false
}
}
Detecting Root Privileges
Root detection combines multiple checks to reduce false negatives, including su binary location scanning, system property validation, and test command execution. Here’s a multi-layered Kotlin implementation:
import java.io.File
fun checkDeviceRooted(): Boolean {
// Step 1: Scan common su binary directories
val suPaths = listOf(
"/system/bin/su", "/system/xbin/su", "/sbin/su", "/system/sd/xbin/su",
"/system/bin/failsafe/su", "/data/local/xbin/su", "/data/local/bin/su",
"/data/local/su", "/system/sbin/su", "/usr/bin/su", "/vendor/bin/su"
)
val hasSuBinary = suPaths.any { File(it).exists() }
if (hasSuBinary) return true
// Step 2: Test execution of su command
return try {
Runtime.getRuntime().exec(arrayOf("su", "-c", "id")).waitFor() == 0
} catch (t: Throwable) {
false
}
}