What are the Android emulator detection methods?

What are the Android emulator detection methods?

The general method of detecting the Android emulator is to determine whether the application is running on the emulator by checking some characteristics of the device.

  1. Check Build Information: Determine whether the device is running on the simulator by reading the device's Build information. For example, check whether the device's Build.MODEL and Build.MANUFACTURER contain common simulator keywords, such as "generic", "sdk", etc.
  2. Check hardware features: The simulator usually simulates some hardware features, such as IMEI, MAC address, etc. Check these hardware features to determine whether it is running on the simulator.
  3. Check the virtualized instruction set: The simulator usually uses a virtualized instruction set to simulate the hardware. You can check the CPU's instruction set to determine whether it is running on the simulator.
  4. Check the operating environment: Check the operating environment of the device, such as whether it has phone function, GPS function, etc. to determine whether it is running on the simulator.

These methods are not absolutely reliable, and the continuous development of simulators may bypass these detection methods. In practical applications, detection is performed by combining multiple methods to improve accuracy.

Universal detection method

 public boolean isEmulator() { String url = "tel:" + "123456"; Intent intent = new Intent(); intent.setData(Uri.parse(url)); intent.setAction(Intent.ACTION_DIAL); // 是否可以处理跳转到拨号的Intent boolean canResolveIntent = intent.resolveActivity(mContext.getPackageManager()) != null; return Build.FINGERPRINT.startsWith("generic") || Build.FINGERPRINT.toLowerCase().contains("vbox") || Build.FINGERPRINT.toLowerCase().contains("test-keys") || Build.MODEL.contains("google_sdk") || Build.MODEL.contains("Emulator") || Build.SERIAL.equalsIgnoreCase("unknown") || Build.SERIAL.equalsIgnoreCase("android") || Build.MODEL.contains("Android SDK built for x86") || Build.MANUFACTURER.contains("Genymotion") || (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")) || "google_sdk".equals(Build.PRODUCT) || ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE)) .getNetworkOperatorName().toLowerCase().equals("android") || !canResolverIntent; }

There are two problems with the above method of detecting simulators:

  1. Dial detection, Android10.0 and above are all false, Android10.0 and above will cause misjudgment.
  2. Build.SERIAL, Android 8.0 and above are all unknown, which will cause systems above 8.0 to be misjudged.

Recommended testing methods

Device information detection
 private static final String[] known_numbers = {"15555215554", "15555215556", "15555215558", "15555215560", "15555215562", "15555215564", "15555215566", "15555215568", "15555215570", "15555215572", "15555215574", "15555215576", "15555215578", "15555215580", "15555215582", "15555215584",}; private boolean detectEmulator() { if (Build.FINGERPRINT.startsWith("generic") || Build.FINGERPRINT.startsWith("unknown") || Build.MODEL.contains("google_sdk") || Build.MODEL.contains("Emulator") || Build.MODEL.contains("Android SDK built for x86") || Build.MANUFACTURER.contains("Genymotion") || (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")) || "google_sdk".equals(Build.PRODUCT)) { return true; } if (Build.PRODUCT.equals("sdk") || Build.PRODUCT.equals("sdk_x86") || Build.PRODUCT.equals("vbox86p") || Build.PRODUCT.equals("emulator")) { return true; } if (Build.BOARD == null) { return true; } if (Build.BOARD.equals("unknown") || Build.BOARD.contains("android") || Build.BOARD.contains("droid")) { return true; } if (Build.DEVICE == null) { return true; } if (Build.DEVICE.equals("unknown") || Build.DEVICE.contains("android") || Build.DEVICE.contains("droid")) { return true; } if (Build.HARDWARE == null) { return true; } if (Build.HARDWARE.equals("goldfish") || Build.HARDWARE.equals("ranchu") || Build.HARDWARE.contains("ranchu")) { return true; } if (Build.BRAND == null) { return true; } if (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")) { return true; } if (Build.MANUFACTURER.equals("unknown")) { return true; } if (Build.MANUFACTURER.equals("Genymotion")) { return true; } if ((Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")) || "google_sdk".equals(Build.PRODUCT)) { return true; } if (Build.PRODUCT == null) { return true; } if (Build.PRODUCT.equals("sdk") || Build.PRODUCT.equals("sdk_x86") || Build.PRODUCT.equals("vbox86p") || Build.PRODUCT.equals("emulator")) { return true; } if (Build.HARDWARE.equals("goldfish") || Build.HARDWARE.equals("ranchu")) { return true; } if (Build.FINGERPRINT.startsWith("generic") || Build.FINGERPRINT.startsWith("unknown") || Build.MODEL.contains("google_sdk") || Build.MODEL.contains("Emulator") || Build.MODEL.contains("Android SDK built for x86") || Build.MANUFACTURER.contains("Genymotion") || (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")) || "google_sdk".equals(Build.PRODUCT)) { return true; } if (Build.PRODUCT == null) { return true; } if (Build.PRODUCT.equals("sdk") || Build.PRODUCT.equals("sdk_x86") || Build.PRODUCT.equals("vbox86p") || Build.PRODUCT.equals("emulator")) { return true; } if (Build.HARDWARE.equals("goldfish") || Build.HARDWARE.equals("ranchu")) { return true; } if (new File("/dev/socket/qemud").exists() || new File("/dev/qemu_pipe").exists()) { return true; } try { TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); if (telephonyManager != null) { String deviceId = telephonyManager.getDeviceId(); List<String> knownNumbers = Arrays.asList(known_numbers); if (knownNumbers.contains(deviceId)) { return true; } } } catch (Exception e) { } return false; }

The above method uses a variety of methods to detect whether the device is a simulator, including:

  • Check if Build.FINGERPRINT starts with "generic" or "unknown"
  • Check if Build.MODEL contains "google_sdk", "Emulator" or "Android SDK built for x86"
  • Check if Build.MANUFACTURER is "Genymotion"
  • Check if Build.PRODUCT is "sdk", "sdk_x86", "vbox86p" or "emulator"
  • Check if Build.BOARD is "unknown" or contains "android" or "droid"
  • Check if Build.DEVICE is "unknown" or contains "android" or "droid"
  • Check if Build.HARDWARE is "goldfish", "ranchu" or contains "ranchu"
  • Check if Build.BRAND starts with "generic" and Build.DEVICE starts with "generic"
  • Check if Build.PRODUCT is "google_sdk"
  • Check whether the file "/dev/socket/qemud" or "/dev/qemu_pipe" exists
  • Check if the device's phone number is a known simulator phone number

These are all based on the judgment of the firmware information. Through testing, it is found that many simulators are invalid. Referring to the tutorials on the Internet, as well as Bluetooth, light sensor, and CPU detection, combined with the above firmware information, most simulators can basically be handled.

Bluetooth detection
 public boolean notHasBlueTooth() { BluetoothAdapter ba = BluetoothAdapter.getDefaultAdapter(); if (ba == null) { return true; } else { // 如果有蓝牙不一定是有效的。获取蓝牙名称,若为null 则默认为模拟器String name = ba.getName(); if (TextUtils.isEmpty(name)) { return true; } else { return false; } } }
Light sensor detection
 public static Boolean notHasLightSensorManager(Context context) { SensorManager sensorManager = (SensorManager) context.getSystemService(SENSOR_SERVICE); Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); //光if (null == sensor) { return true; } else { return false; } }
CPU Detection
 public static boolean checkIsNotRealPhone() { String cpuInfo = readCpuInfo(); if ((cpuInfo.contains("intel") || cpuInfo.contains("amd"))) { return true; } return false; } public static String readCpuInfo() { String result = ""; try { String[] args = {"/system/bin/cat", "/proc/cpuinfo"}; ProcessBuilder cmd = new ProcessBuilder(args); Process process = cmd.start(); StringBuffer sb = new StringBuffer(); String readLine = ""; BufferedReader responseReader = new BufferedReader(new InputStreamReader(process.getInputStream(), "utf-8")); while ((readLine = responseReader.readLine()) != null) { sb.append(readLine); } responseReader.close(); result = sb.toString().toLowerCase(); } catch (IOException ex) { } return result; }

The above detection method is not completely feasible. With the update of Android system and the increase of simulators, it is necessary to study the corresponding changes to update the above code. The final judgment result may not be able to detect all simulators, but it must not kill the real machine by mistake and affect the normal use of users.

<<:  Android device WiFi scanning strategy: How to efficiently manage network connections when the screen is on or off

>>:  Master the powerful functions of ClipboardManager in Android development and efficiently manage clipboard data

Recommend

Why do the Winter Olympics use artificial snow?

Recently, some people on the Internet said that a...

Rating 9.3! Probably the best domestic documentary this year

The Chinese white dolphin, a mammal at the top of...

iOS uses Metrickit to collect crash logs

What is Metrickit MetricKit is a tool introduced ...

500 kinds of homepage designs for event operation and promotion!

1. What are operational activities? Starting from...

How many Tik Tok views are considered popular? Tips to become popular on TikTok

This article mainly introduces how many Douyin pl...

No offline business: Can Internet TV escape being a niche?

After experiencing a wave of Internet development...