375

I would like to have my code run slightly differently when running on the emulator than when running on a device. (For example, using 10.0.2.2 instead of a public URL to run against a development server automatically.) What is the best way to detect when an Android application is running in the emulator?

Nikhil
  • 16,194
  • 20
  • 64
  • 81
Joe Ludwig
  • 6,756
  • 7
  • 30
  • 29

41 Answers41

194

How about this solution (class implementation of SystemProperties is available here):

val isProbablyRunningOnEmulator: Boolean by lazy {
    // Android SDK emulator
    return@lazy ((Build.MANUFACTURER == "Google" && Build.BRAND == "google" &&
            ((Build.FINGERPRINT.startsWith("google/sdk_gphone_")
                    && Build.FINGERPRINT.endsWith(":user/release-keys")
                    && Build.PRODUCT.startsWith("sdk_gphone_")
                    && Build.MODEL.startsWith("sdk_gphone_"))
                    //alternative
                    || (Build.FINGERPRINT.startsWith("google/sdk_gphone64_")
                    && (Build.FINGERPRINT.endsWith(":userdebug/dev-keys") || Build.FINGERPRINT.endsWith(":user/release-keys"))
                    && Build.PRODUCT.startsWith("sdk_gphone64_")
                    && Build.MODEL.startsWith("sdk_gphone64_"))))
            //
            || 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")
            //bluestacks
            || "QC_Reference_Phone" == Build.BOARD && !"Xiaomi".equals(Build.MANUFACTURER, ignoreCase = true)
            //bluestacks
            || Build.MANUFACTURER.contains("Genymotion")
            || Build.HOST.startsWith("Build")
            //MSI App Player
            || Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")
            || Build.PRODUCT == "google_sdk"
            // another Android SDK emulator check
            || SystemProperties.getProp("ro.kernel.qemu") == "1")
}

Note that some emulators fake exact specs of real devices, so it might be impossible to detect it. I've added what I could, but I don't think there is a 100% way to detect if it's really an emulator or not.

Here a tiny snippet you can make in the APK to show various things about it, so you could add your own rules:

        textView.text = "FINGERPRINT:${Build.FINGERPRINT}\n" +
                "MODEL:${Build.MODEL}\n" +
                "MANUFACTURER:${Build.MANUFACTURER}\n" +
                "BRAND:${Build.BRAND}\n" +
                "DEVICE:${Build.DEVICE}\n" +
                "BOARD:${Build.BOARD}\n" +
                "HOST:${Build.HOST}\n" +
                "PRODUCT:${Build.PRODUCT}\n"
android developer
  • 114,585
  • 152
  • 739
  • 1,270
  • 14
    That's the way Facebook detects emulators in React-Native – Vaiden Jan 27 '16 at 09:12
  • This is what I had to update to after using the answer from @Aleadam for quite awhile (it stopped working for me). – ckbhodge Jul 08 '16 at 10:20
  • @Sid What should be added for it? – android developer Aug 13 '17 at 06:54
  • I am not very sure, have looked around a lot but haven't been able to find anything which is correct for sure. The following code returns BlueStacks when run on a blustack emulator: android.opengl.GLES20.glGetString(android.opengl.GLES20.GL_RENDERER). The only thing is that I need to test this across real devices to make sure that there are no false positives. So in short still not sure, looking around for more help. – Sid Aug 13 '17 at 11:01
  • 2
    @Sid Have you printed out various Build class variables there? Nothing seems special? Have you tried this: https://github.com/framgia/android-emulator-detector ? – android developer Aug 13 '17 at 11:14
  • What is to stop me as an attacker, Backsmaling your app and return 0x0 :) – Dr Deo Dec 26 '17 at 09:16
  • 1
    @DrDeo You can add a check of the current build using BuildConfig.DEBUG, or create your own build with your own custom variable. You might also be able to use Proguard to make this function always return false, or something (you can remove logs, for example, as shown here: https://medium.com/tixdo-labs/obfuscating-and-optimizing-android-app-proguard-can-do-it-all-3d19c8ae9ec , so maybe that's possible too) – android developer Dec 26 '17 at 10:19
  • Unable to detect blustacks 4 – san88 May 06 '19 at 06:22
  • @san88 It's not an official way anyway. It's just a guess if it's an emulator or not. Technically , even a real device can fool this function, by editing those variables (using root or a custom rom). If you want to support (and again, it's only a guessing function) something new that this function doesn't support, check the various things in `Build` , and decide what's the best one that suits your case. I can't just test all the current emulator apps on PCs, and the future ones, and gather them all. It's not practical. I just got some of them. – android developer May 07 '19 at 07:12
  • @KishitaVariya See my previous comment about it. Also, if the emulator fakes everything, how could you check if it's an emulator or not? Anyway, I've updated the answer. Even if it works for you today, it might not work in the future. – android developer Nov 20 '19 at 12:18
  • For a Sony Xperia X (model F5321) the Host property returns "BuildHost" so this condition doesn't work well here. – digitalbreed Mar 27 '21 at 14:32
  • 1
    @digitalbreed OK I've updated it so that it will be more fitting for MSI app player. But always remember: this is not a reliable thing... – android developer Mar 28 '21 at 11:01
  • Doesn't it need more parenthesis around && operands? – Zahra Jamshidi Apr 09 '21 at 02:47
  • @ZahraJamshidi You mean there is an error here with them? – android developer Apr 09 '21 at 06:01
  • I'm asking. In the line you are checking for "QC_Reference_Phone" there is && operator. Does it need parenthesis? – Zahra Jamshidi Apr 09 '21 at 06:08
  • To be more specific a || b && c || d is ambiguous. did you mean a || (b && c) || d ? – Zahra Jamshidi Apr 09 '21 at 06:47
  • @ZahraJamshidi It is not ambiguous. There is an order of operations, just like in math. If you use Android Studio, it will even give you the option to remove redundant ones. Of course, in complicated cases, it might be better to split them. In my case, I chose to split using new lines when possible, and with parentheses when not. – android developer Apr 09 '21 at 08:25
  • Right. I was thinking about && operator short circuit but noticed && has higher precedence than || Thanks! – Zahra Jamshidi Apr 09 '21 at 12:14
  • 1
    @ZahraJamshidi I think in some course I had in school/university, it was possible to treat "&&" as multiplication and "||" as addition. It helped with understanding some rules of making them look different, very similar to how it works in math (but a bit different rules). – android developer Apr 09 '21 at 19:35
  • These methods are no longer working on most emulator like Memu – Aman May 09 '21 at 09:02
  • @Aman I'm open to suggestions of what to change here. As I said, this can change all the time, should never be 100% trusted. It's a guess based on what I noticed. Maybe I should create a Github repository for this? – android developer May 09 '21 at 10:10
  • How do I get `SystemProperties`? Through reflection? – Aykhan Hagverdili Jul 28 '21 at 05:48
  • 1
    @AyxanHaqverdili Using the link I've provided right in the beginning. – android developer Jul 28 '21 at 10:48
  • @android thank you. I don't know how I missed it! – Aykhan Hagverdili Jul 28 '21 at 19:49
  • 2
    @AyxanHaqverdili Sometimes I'm very tired too, making weird mistakes. – android developer Jul 28 '21 at 23:16
122

One common one sems to be Build.FINGERPRINT.contains("generic")

Vishal Yadav
  • 3,642
  • 3
  • 25
  • 42
Aleadam
  • 40,203
  • 9
  • 86
  • 108
98

The Flutter community uses this code in the device-info plugin to determine if the device is an emulator:

private val isEmulator: Boolean
    get() = (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))
        || Build.FINGERPRINT.startsWith("generic")
        || Build.FINGERPRINT.startsWith("unknown")
        || Build.HARDWARE.contains("goldfish")
        || Build.HARDWARE.contains("ranchu")
        || Build.MODEL.contains("google_sdk")
        || Build.MODEL.contains("Emulator")
        || Build.MODEL.contains("Android SDK built for x86")
        || Build.MANUFACTURER.contains("Genymotion")
        || Build.PRODUCT.contains("sdk_google")
        || Build.PRODUCT.contains("google_sdk")
        || Build.PRODUCT.contains("sdk")
        || Build.PRODUCT.contains("sdk_x86")
        || Build.PRODUCT.contains("sdk_gphone64_arm64")
        || Build.PRODUCT.contains("vbox86p")
        || Build.PRODUCT.contains("emulator")
        || Build.PRODUCT.contains("simulator");
}
Moshe Katz
  • 15,992
  • 7
  • 69
  • 116
Rockney
  • 10,380
  • 2
  • 20
  • 26
  • Here is a link directly to the code in question: https://github.com/flutter/plugins/blob/master/packages/device_info/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/MethodCallHandlerImpl.java#L115-L131 – Raman Nov 14 '20 at 00:28
  • This is how the firebase crashlytics library does it: `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; }` – Pepijn Feb 24 '21 at 16:13
  • These methods are no longer working on most emulator like Memu – Aman May 09 '21 at 09:02
  • Add one more check, `Build.PRODUCT == "sdk_gphone64_arm64"` – Shahab Rauf Aug 12 '21 at 22:18
  • You may want to add: `Build.FINGERPRINT == "robolectric"` if your using robolectric – Werner Altewischer Oct 13 '21 at 07:44
67

Well Android id does not work for me, I'm currently using:

"google_sdk".equals( Build.PRODUCT );
Marcus
  • 8,601
  • 4
  • 24
  • 24
  • 37
    Anyone reading this may be interested to know that this string appears to have changed to 'sdk', rather than 'google_sdk'. – Daniel Sloof Jun 06 '10 at 19:48
  • 15
    @Daniel: I use 2.3.3 with Google API and it says 'google_sdk'. Seems that it's 'google_sdk' for AVD with Google API and 'sdk' for the normal ones. – Randy Sugianto 'Yuku' Apr 25 '11 at 06:39
  • 1
    Is this a reliable way to handle this issue. Our servers use the device id and we want to be able to prevent usage of the app on emulators at all costs as the device ID can easily be faked, but I want to make sure that we are not excluding any devices in case there are devices that use "google_sdk" or "sdk" – Tolga E Jan 14 '12 at 23:33
  • 4
    The Intel emulator returns "full_x86" so I wouldn't count on this method. – user462982 Jul 28 '12 at 11:33
  • ITYM Build.PRODUCT.equals("google_sdk"). Writing it backwards is just being different for the sake of it. @TolgaE: Of course there's no way, since anything you can query to see if you're in an emulator, the emulator can lie about. – Glenn Maynard Jul 02 '13 at 16:32
  • 4
    @GlennMaynard The reverse form is ugly, but practical: Build.PRODUCT could be null whereas "google_sdk" cannot, thus this form avoids a potential null reference error. – Rupert Rawnsley Jul 27 '13 at 16:07
  • My [intel] emulator uses `sdk_x86`. – gdw2 Oct 01 '13 at 23:28
  • sdk_x86 for my emulator as well. Not valid anymore. – holmes Oct 02 '13 at 00:16
  • 1
    Genymotion uses vbox86p. FINGERPRINT solution below seems more reliable. – gdw2 Oct 03 '13 at 19:16
  • 4
    Including more cases: "google_sdk".equals(Build.PRODUCT) || "sdk".equals(Build.PRODUCT) || "sdk_x86".equals(Build.PRODUCT) || "vbox86p".equals(Build.PRODUCT) – Alberto Alonso Ruibal Mar 07 '14 at 17:51
  • 1
    My Build.MODEL is Android SDK built for x86 , and Build.PRODUCT is google_sdk_x86 . I think, this variables not trustable. – MERT DOĞAN Feb 07 '18 at 10:15
  • I suggest for any `Build` variable to get its string like `String product = "" + Build.PRODUCT;` because it may be null but `contains` can still be used rather than `equals`. Additionally use `toLowercase` to compare case in-sensitive. – Manuel May 19 '19 at 21:34
31

Based on hints from other answers, this is probably the most robust way:

isEmulator = Build.HARDWARE.equals("ranchu")

w0mbat
  • 2,430
  • 1
  • 15
  • 16
Vitali
  • 3,411
  • 2
  • 24
  • 25
  • Yes. Unlike Build.PRODUCT, Build.HARDWARE (goldfish) is the same for the official SDK and AOSP. Prior to API 8, you have to use reflection to get at the HARDWARE field, however. – David Chandler Apr 26 '13 at 15:15
  • 5
    I'd go with `isEmulator = Build.HARDWARE.contains("golfdish")` – holmes Oct 02 '13 at 00:24
  • 9
    @holmes: typo, s/b "goldfish" – Noah Nov 14 '13 at 13:11
  • 9
    For the Android 5.1 x86_64 image (and probably other more recent 64bit images) that would be "ranchu" instead of "goldfish". – warbi Sep 01 '16 at 22:23
20

How about something like the code below to tell if your app was signed with the debug key? it's not detecting the emulator but it might work for your purpose?

public void onCreate Bundle b ) {
   super.onCreate(savedInstanceState);
   if ( signedWithDebugKey(this,this.getClass()) ) {
     blah blah blah
   }

  blah 
    blah 
      blah

}

static final String DEBUGKEY = 
      "get the debug key from logcat after calling the function below once from the emulator";    


public static boolean signedWithDebugKey(Context context, Class<?> cls) 
{
    boolean result = false;
    try {
        ComponentName comp = new ComponentName(context, cls);
        PackageInfo pinfo = context.getPackageManager().getPackageInfo(comp.getPackageName(),PackageManager.GET_SIGNATURES);
        Signature sigs[] = pinfo.signatures;
        for ( int i = 0; i < sigs.length;i++)
        Log.d(TAG,sigs[i].toCharsString());
        if (DEBUGKEY.equals(sigs[0].toCharsString())) {
            result = true;
            Log.d(TAG,"package has been signed with the debug key");
        } else {
            Log.d(TAG,"package signed with a key other than the debug key");
        }

    } catch (android.content.pm.PackageManager.NameNotFoundException e) {
        return false;
    }

    return result;

} 
Amanda S
  • 3,266
  • 4
  • 33
  • 45
Jeff S
  • 3,256
  • 1
  • 18
  • 7
  • 1
    Thank you for this code. I have checked and it is working, aldo coping the long debug key can be painful but it is done only once. This is the only **reliable** solution, as all other answers compare some part of the OS build info string with a static string, and this can and was changed over Android SDK versions, and also can be forged by custom Android builds. – ZoltanF Aug 19 '11 at 05:32
  • I think it is the only reliable solution. However, the debug key can change more quickly than we want. – rds Aug 26 '12 at 13:19
  • 2
    A better way to do this is `BuildConfig.DEBUG`. – Mygod May 15 '17 at 09:34
14

This code works for me

TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
String networkOperator = tm.getNetworkOperatorName();
if("Android".equals(networkOperator)) {
    // Emulator
}
else {
    // Device
}

In case that device does not have sim card, It retuns empty string:""

Since Android emulator always retuns "Android" as network operator, I use above code.

J.J. Kim
  • 1,845
  • 1
  • 16
  • 21
  • 4
    What does a device without a SIM card (such as a tablet) return? – rds Aug 26 '12 at 13:17
  • Running emulator for Android 2.1. This code was working for me, but since upgrading Cordova to 2.7.0, the Context variable appears to be undefined or something. Here's the error I'm getting in ADT: "Context cannot be resolved to a variable." Also, according to comment above, this is NOT a reliable method (though I haven't actually had it fail myself). – Rustavore May 17 '13 at 16:48
  • 2
    @rds Devices which does not have a SIM card returns empty string ("") – J.J. Kim Jun 12 '13 at 07:43
  • Is there no way to have this value with emulator? because I'd like to block all the users if they don't have any sim cards. – c-an Nov 12 '19 at 06:54
  • fyi, nox does not return "Android" as network operator – ramen87x May 14 '21 at 03:58
13

I never found a good way to tell if you're in the emulator.

but if you just need to detecet if you're in a development environment you can do this :

     if(Debug.isDebuggerConnected() ) {
        // Things to do in debug environment...
    }

Hope this help....

Etherpulse
  • 166
  • 1
  • 4
12

I tried several techniques, but settled on a slightly revised version of checking the Build.PRODUCT as below. This seems to vary quite a bit from emulator to emulator, that's why I have the 3 checks I currently have. I guess I could have just checked if product.contains("sdk") but thought the check below was a bit safer.

public static boolean isAndroidEmulator() {
    String model = Build.MODEL;
    Log.d(TAG, "model=" + model);
    String product = Build.PRODUCT;
    Log.d(TAG, "product=" + product);
    boolean isEmulator = false;
    if (product != null) {
        isEmulator = product.equals("sdk") || product.contains("_sdk") || product.contains("sdk_");
    }
    Log.d(TAG, "isEmulator=" + isEmulator);
    return isEmulator;
}

FYI - I found that my Kindle Fire had Build.BRAND = "generic", and some of the emulators didn't have "Android" for the network operator.

Patrick Montelo
  • 2,211
  • 1
  • 20
  • 14
11

I just look for _sdk, _sdk_ or sdk_, or even just sdk part in Build.PRODUCT:

if(Build.PRODUCT.matches(".*_?sdk_?.*")){
  //-- emulator --
}else{
  //-- other device --
}
S.D.
  • 29,290
  • 3
  • 79
  • 130
  • 5
    Why not just `contains("sdk")`? The only difference (other than being faster) is that `matches(".*_?sdk_?.*")` requires that if there is a character before or after sdk, it must be an underscore '_', which is not all that important to check. – Nulano Jan 28 '15 at 17:00
11

Both the following are set to "google_sdk":

Build.PRODUCT
Build.MODEL

So it should be enough to use either one of the following lines.

"google_sdk".equals(Build.MODEL)

or

"google_sdk".equals(Build.PRODUCT)
Sileria
  • 15,223
  • 4
  • 49
  • 28
8

use this function :

 public static final boolean isEmulator() {

    int rating = 0;

    if ((Build.PRODUCT.equals("sdk")) || (Build.PRODUCT.equals("google_sdk"))
            || (Build.PRODUCT.equals("sdk_x86")) || (Build.PRODUCT.equals("vbox86p"))) {
        rating++;
    }
    if ((Build.MANUFACTURER.equals("unknown")) || (Build.MANUFACTURER.equals("Genymotion"))) {
        rating++;
    }
    if ((Build.BRAND.equals("generic")) || (Build.BRAND.equals("generic_x86"))) {
        rating++;
    }
    if ((Build.DEVICE.equals("generic")) || (Build.DEVICE.equals("generic_x86")) || (Build.DEVICE.equals("vbox86p"))) {
        rating++;
    }
    if ((Build.MODEL.equals("sdk")) || (Build.MODEL.equals("google_sdk"))
            || (Build.MODEL.equals("Android SDK built for x86"))) {
        rating++;
    }
    if ((Build.HARDWARE.equals("goldfish")) || (Build.HARDWARE.equals("vbox86"))) {
        rating++;
    }
    if ((Build.FINGERPRINT.contains("generic/sdk/generic"))
            || (Build.FINGERPRINT.contains("generic_x86/sdk_x86/generic_x86"))
            || (Build.FINGERPRINT.contains("generic/google_sdk/generic"))
            || (Build.FINGERPRINT.contains("generic/vbox86p/vbox86p"))) {
        rating++;
    }

    return rating > 4;

    }
AndroidCrop
  • 109
  • 1
  • 6
8

This is how Firebase Crashlytics approaches it:

private static final String GOLDFISH = "goldfish";
private static final String RANCHU = "ranchu";
private static final String SDK = "sdk";
    
public static boolean isEmulator() {
    return Build.PRODUCT.contains(SDK)
        || Build.HARDWARE.contains(GOLDFISH)
        || Build.HARDWARE.contains(RANCHU);
}
G00fY
  • 4,545
  • 1
  • 22
  • 26
7

Don't know if there are better ways to detect the emu, but the emulator will have the file init.goldfish.rc in the root-directory.

It's the emulator specific startup-script, and it shouldn't be there on a non-emulator build.

Nils Pipenbrinck
  • 83,631
  • 31
  • 151
  • 221
  • During startup of the Android system the Linux kernel first calls the process "init". init reads the files "/init.rc" and "init.device.rc". "init.device.rc" is device specific, on the virtual device this file is called "init.goldfish.rc". – NET3 Feb 09 '18 at 02:05
  • I read in a different stackoverflow comment here: https://stackoverflow.com/questions/2799097/how-can-i-detect-when-an-android-application-is-running-in-the-emulator/4320752#comment83201605_37227101 that this file is present on many actual devices, many Samsungs. I'm seeing it in our logs as well from some Samsung devices. – gjgjgj Sep 01 '20 at 04:07
7

From Battery, the emulator: Power source is always AC Charger. Temperature is always 0.

And you can use Build.HOST to record host value, different emulator has different host value.

Louie Liu
  • 99
  • 1
  • 7
7

Here is my solution (it works only if you run a web server on your debug machine): I have created a background task that starts when the application starts. It looks for http://10.0.2.2 and if it exists it changes a global parameter (IsDebug) to true. It is a silent way to find out where you are running.

public class CheckDebugModeTask extends AsyncTask<String, Void, String> {
public static boolean IsDebug = false;

public CheckDebugModeTask()
{

}

@Override
protected String doInBackground(String... params) {     
  try {
    HttpParams httpParameters = new BasicHttpParams();
    int timeoutConnection = 1000;
    HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
    int timeoutSocket = 2000;
    HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);

    String url2 = "http://10.0.2.2";        
          HttpGet httpGet = new HttpGet(url2);
    DefaultHttpClient client = new DefaultHttpClient(httpParameters);

    HttpResponse response2 = client.execute(httpGet);
    if (response2 == null || response2.getEntity() == null || response2.getEntity().getContent() == null)
    return "";

    return "Debug";

} catch (Exception e) {
    return "";
}
}

@Override
protected void onPostExecute (String result)
{       
if (result == "Debug")
{
    CheckDebugModeTask.IsDebug = true;
}
}

from the main activity onCreate:

CheckDebugModeTask checkDebugMode = new CheckDebugModeTask();
checkDebugMode.execute("");
Eyal
  • 516
  • 6
  • 9
6

Another option would be to look at the ro.hardware property and see if its set to goldfish. Unfortunately there doesn't seem to be an easy way to do this from Java but its trivial from C using property_get().

Tim Kryger
  • 11,166
  • 4
  • 52
  • 41
  • 4
    This appears to work from the NDK. Include and use __system_property_get("ro.hardware", buf) then check that buf is "goldfish". – NuSkooler Jan 25 '11 at 21:19
6

I found the new emulator Build.HARDWARE = "ranchu".

Reference:https://groups.google.com/forum/#!topic/android-emulator-dev/dltBnUW_HzU

And also I found the Android official way to check whether emulator or not.I think it's good reference for us.

Since Android API Level 23 [Android 6.0]

package com.android.internal.util;

/**
 * @hide
 */
public class ScreenShapeHelper {
    private static final boolean IS_EMULATOR = Build.HARDWARE.contains("goldfish");
}

We have ScreenShapeHelper.IS_EMULATOR to check whether emulator.

Since Android API Level 24 [Android 7.0]

package android.os;

/**
 * Information about the current build, extracted from system properties.
 */
public class Build {


    /**
     * Whether this build was for an emulator device.
     * @hide
     */
    public static final boolean IS_EMULATOR = getString("ro.kernel.qemu").equals("1");

}

We have Build.IS_EMULATOR to check whether emulator.

The way the official to check whether emulator is not new,and also maybe not enough,the answers above also mentioned.

But this maybe show us that the official will provide the way of official to check whether emulator or not.

As using the above all ways mentioned,right now we can also use the two ways about to check whether emulator.

How to access the com.android.internal package and @hide

and wait for the official open SDK.

ifeegoo
  • 7,054
  • 3
  • 33
  • 38
5

The above suggested solution to check for the ANDROID_ID worked for me until I updated today to the latest SDK tools released with Android 2.2.

Therefore I currently switched to the following solution which works so far with the disadvantage however that you need to put the PHONE_STATE read permission (<uses-permission android:name="android.permission.READ_PHONE_STATE"/>)

private void checkForDebugMode() {
    ISDEBUGMODE = false; //(Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID) == null);

    TelephonyManager man = (TelephonyManager) getApplicationContext().getSystemService(Context.TELEPHONY_SERVICE);
    if(man != null){
        String devId = man.getDeviceSoftwareVersion();
        ISDEBUGMODE = (devId == null);
    }
} 
Juri
  • 32,424
  • 20
  • 102
  • 136
4
Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")

This should return true if the app is running on an emulator.

What we should be careful about is not detecting all the emulators because there are only several different emulators. It is easy to check. We have to make sure that actual devices are not detected as an emulator.

I used the app called "Android Device Info Share" to check this.

On this app, you can see various kinds of information of many devices (probably most devices in the world; if the device you are using is missing from the list, it will be added automatically).

j0k
  • 22,600
  • 28
  • 79
  • 90
kanji
  • 729
  • 9
  • 14
4

All answers in one method

static boolean checkEmulator()
{
    try
    {
        String buildDetails = (Build.FINGERPRINT + Build.DEVICE + Build.MODEL + Build.BRAND + Build.PRODUCT + Build.MANUFACTURER + Build.HARDWARE).toLowerCase();

        if (buildDetails.contains("generic") 
        ||  buildDetails.contains("unknown") 
        ||  buildDetails.contains("emulator") 
        ||  buildDetails.contains("sdk") 
        ||  buildDetails.contains("genymotion") 
        ||  buildDetails.contains("x86") // this includes vbox86
        ||  buildDetails.contains("goldfish")
        ||  buildDetails.contains("test-keys"))
            return true;
    }   
    catch (Throwable t) {Logger.catchedError(t);}

    try
    {
        TelephonyManager    tm  = (TelephonyManager) App.context.getSystemService(Context.TELEPHONY_SERVICE);
        String              non = tm.getNetworkOperatorName().toLowerCase();
        if (non.equals("android"))
            return true;
    }
    catch (Throwable t) {Logger.catchedError(t);}

    try
    {
        if (new File ("/init.goldfish.rc").exists())
            return true;
    }
    catch (Throwable t) {Logger.catchedError(t);}

    return false;
}
XXX
  • 8,996
  • 7
  • 44
  • 53
  • Nice one. `init.goldfish.rc` only exists in emulators; it's additionally a good check going forward in addition to the Build details. – sud007 May 25 '16 at 06:07
  • 3
    @sud007 There are many devices out there with `/init.goldfish.rc and this will lead to false positives. For example, many Samsung Galaxy series devices. – laalto Jan 05 '18 at 11:49
  • @laalto you were actually correct. I found that out later and apologies that I forget to update it here. – sud007 Jan 31 '18 at 07:10
  • test-keys has been generating false positives for me. – A P Nov 15 '18 at 17:11
  • On which devices they are generating false positives ? – Aman Verma Dec 21 '18 at 21:20
4

Checking the answers, none of them worked when using LeapDroid, Droid4x or Andy emulators,

What does work for all cases is the following:

 private static String getSystemProperty(String name) throws Exception {
    Class systemPropertyClazz = Class.forName("android.os.SystemProperties");
    return (String) systemPropertyClazz.getMethod("get", new Class[]{String.class}).invoke(systemPropertyClazz, new Object[]{name});
}

public boolean isEmulator() {
    boolean goldfish = getSystemProperty("ro.hardware").contains("goldfish");
    boolean emu = getSystemProperty("ro.kernel.qemu").length() > 0;
    boolean sdk = getSystemProperty("ro.product.model").equals("sdk");
    return goldfish || emu || sdk;
}
4

My recommendation:

try this from github.

Easy to detect android emulator

How to use with an Example:

EmulatorDetector.with(this)
                .setCheckTelephony(true)
                .addPackageName("com.bluestacks")
                .setDebug(true)
                .detect(new EmulatorDetector.OnEmulatorDetectorListener() {
                    @Override
                    public void onResult(boolean isEmulator) {
                        if(isEmulator){
                         // Do your work
                        }
                        else{
                        // Not emulator and do your work
                        }
                    }
                });
Saeed
  • 3,294
  • 5
  • 35
  • 52
3

Put a file in the file system of the emulator; since the file won't exist on the real device, this should be stable, reliable and easy to fix when it breaks.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
3

you can check the IMEI #, http://developer.android.com/reference/android/telephony/TelephonyManager.html#getDeviceId%28%29

if i recall on the emulator this return 0. however, there's no documentation i can find that guarantees that. although the emulator might not always return 0, it seems pretty safe that a registered phone would not return 0. what would happen on a non-phone android device, or one without a SIM card installed or one that isn't currently registered on the network?

seems like that'd be a bad idea, to depend on that.

it also means you'd need to ask for permission to read the phone state, which is bad if you don't already require it for something else.

if not that, then there's always flipping some bit somewhere before you finally generate your signed app.

Jeff
  • 145
  • 1
3

I've collected all the answers on this question and came up with function to detect if Android is running on a vm/emulator:

public boolean isvm(){


        StringBuilder deviceInfo = new StringBuilder();
        deviceInfo.append("Build.PRODUCT " +Build.PRODUCT +"\n");
        deviceInfo.append("Build.FINGERPRINT " +Build.FINGERPRINT+"\n");
        deviceInfo.append("Build.MANUFACTURER " +Build.MANUFACTURER+"\n");
        deviceInfo.append("Build.MODEL " +Build.MODEL+"\n");
        deviceInfo.append("Build.BRAND " +Build.BRAND+"\n");
        deviceInfo.append("Build.DEVICE " +Build.DEVICE+"\n");
        String info = deviceInfo.toString();


        Log.i("LOB", info);


        Boolean isvm = false;
        if(
                "google_sdk".equals(Build.PRODUCT) ||
                "sdk_google_phone_x86".equals(Build.PRODUCT) ||
                "sdk".equals(Build.PRODUCT) ||
                "sdk_x86".equals(Build.PRODUCT) ||
                "vbox86p".equals(Build.PRODUCT) ||
                Build.FINGERPRINT.contains("generic") ||
                Build.MANUFACTURER.contains("Genymotion") ||
                Build.MODEL.contains("Emulator") ||
                Build.MODEL.contains("Android SDK built for x86")
                ){
            isvm =  true;
        }


        if(Build.BRAND.contains("generic")&&Build.DEVICE.contains("generic")){
            isvm =  true;
        }

        return isvm;
    }

Tested on Emulator, Genymotion and Bluestacks (1 October 2015).

Pedro Lobito
  • 94,083
  • 31
  • 258
  • 268
3

Whichever code you use to do emulator detection, I'd highly recommend writing unit tests to cover all the Build.FINGERPRINT, Build.HARDWARE and Build.MANUFACTURER values that you are depending on. Here are some example tests:

@Test
public void testIsEmulatorGenymotion() throws Exception {
    assertThat(
            DeviceUtils.isRunningOnEmulator(
                    "generic/vbox86p/vbox86p:4.1.1/JRO03S/eng.buildbot.20150217.102902:userdebug/test-keys",
                    "vbox86", "Genymotion")).isTrue();

    assertThat(
            DeviceUtils.isRunningOnEmulator(
                    "generic/vbox86p/vbox86p:5.1/LMY47D/buildbot06092001:userdebug/test-keys", "vbox86",
                    "Genymotion")).isTrue();
}

@Test
public void testIsEmulatorDefaultAndroidEmulator() throws Exception {
    assertThat(
            DeviceUtils.isRunningOnEmulator(
                    "generic_x86/sdk_google_phone_x86/generic_x86:5.0.2/LSY66H/1960483:eng/test-keys", "goldfish",
                    "unknown")).isTrue();

    assertThat(
            DeviceUtils.isRunningOnEmulator(
                    "Android/sdk_google_phone_x86_64/generic_x86_64:6.0/MASTER/2469028:userdebug/test-keys",
                    "ranchu", "unknown")).isTrue();
}

@Test
public void testIsEmulatorRealNexus5() throws Exception {
    assertThat(
            DeviceUtils.isRunningOnEmulator("google/hammerhead/hammerhead:6.0.1/MMB29K/2419427:user/release-keys",
                    "hammerhead", "LGE")).isFalse();
}

...and here's our code (debug logs and comments removed for conciseness):

public static boolean isRunningOnEmulator() {
    if (sIsRunningEmulator == null) {
        sIsRunningEmulator = isRunningOnEmulator(Build.FINGERPRINT, Build.HARDWARE, Build.MANUFACTURER);
    }

    return sIsRunningEmulator;
}

static boolean isRunningOnEmulator(String fingerprint, String hardware, String manufacturer) {
    boolean isEmulatorFingerprint = fingerprint.endsWith("test-keys");
    boolean isEmulatorManufacturer = manufacturer.equals("Genymotion")
            || manufacturer.equals("unknown");

    if (isEmulatorFingerprint && isEmulatorManufacturer) {
        return true;
    } else {
        return false;
    }
}
Dan J
  • 25,433
  • 17
  • 100
  • 173
3

Another option is to check if you are in debug mode or production mode:

if (BuildConfig.DEBUG) { Log.i(TAG, "I am in debug mode"); }

simple and reliable.

Not totally the answer of the question but in most cases you may want to distinguish between debugging/test sessions and life sessions of your user base.

In my case I set google analytics to dryRun() when in debug mode so this approach works totally fine for me.


For more advanced users there is another option. gradle build variants:

in your app's gradle file add a new variant:

buildTypes {
    release {
        // some already existing commands
    }
    debug {
        // some already existing commands
    }
    // the following is new
    test {
    }
}

In your code check the build type:

if ("test".equals(BuildConfig.BUILD_TYPE)) { Log.i(TAG, "I am in Test build type"); }
 else if ("debug".equals(BuildConfig.BUILD_TYPE)) { Log.i(TAG, "I am in Debug build type"); }

Now you have the opportunity to build 3 different types of your app.

mikes
  • 2,323
  • 1
  • 16
  • 11
3

Actually, ANDROID_ID on 2.2 always equals 9774D56D682E549C (according to this thread + my own experiments).

So, you could check something like this:

String androidID = ...;
if(androidID == null || androidID.equals("9774D56D682E549C"))
    do stuff;

Not the prettiest, but it does the job.

Eric Eijkelenboom
  • 6,943
  • 2
  • 25
  • 29
3

This works for me

public boolean isEmulator() {
    return Build.MANUFACTURER.equals("unknown");
}
Ribomation
  • 121
  • 4
  • 3
    the firmware engineer we have in-house didn't update this; getting Build.Manufacturer on our hardware returned "unknown". The Fingerprint seems like a better way. – Someone Somewhere Nov 14 '11 at 20:47
3

Try using this method.

Tested on Google and Genymotion emulators.

public Boolean IsVM() {
    String radioVersion = android.os.Build.getRadioVersion();
    return radioVersion == null || radioVersion.isEmpty() || radioVersion.equals("1.0.0.0");
}
Yusuph wickama
  • 450
  • 4
  • 15
2
if ("sdk".equals( Build.PRODUCT )) {
 // Then you are running the app on the emulator.
        Log.w("MyAPP", "\n\n  Emulator \n\n"); 
}

Edit:

Tested on 2023-04 Android Studio IDE emulator and on real device.

 public static boolean isRunningOnEmulator() {
        return Build.PRODUCT.startsWith("sdk");
 }
noam cohen
  • 87
  • 1
  • 6
Abhishek Bedi
  • 5,205
  • 2
  • 36
  • 62
2

Since the underlying emulation engine for Genymotion is VirtualBox and that's not going to change any time soon I found the following code the most reliable:

   public static boolean isGenymotion() {
        return Build.PRODUCT != null && Build.PRODUCT.contains("vbox");
}
Nati Dykstein
  • 1,240
  • 11
  • 19
2

It is a good idea to verify if the device has these packages installed:

    mListPackageName.add("com.google.android.launcher.layouts.genymotion");
    mListPackageName.add("com.bluestacks");
    mListPackageName.add("com.vphone.launcher");
    mListPackageName.add("com.bignox.app");

I just put it inside an ArrayList...

And then simply check against the package manager till it finds one.

private static boolean isEmulByPackage(Context context) {
        final PackageManager pm = context.getPackageManager();
        for (final String pkgName : mListPackageName) {
            return isPackageInstalled(pkgName, pm);
        }
        return false;
    }

private static boolean isPackageInstalled(final String packageName, final PackageManager packageManager) {
    try {
        packageManager.getPackageInfo(packageName, 0);
        return true;
    } catch (PackageManager.NameNotFoundException e) {
        return false;
    }
}

Just note that there are most likely some ways for a VM to fool the application, in that case it might be worthwhile looking at some physical sensors which wouldn't be present in a virtual device.

A P
  • 2,131
  • 2
  • 24
  • 36
1
if (Build.BRAND.equalsIgnoreCase("generic")) {
    // Is the emulator
}

All BUILD references are build.prop values, so you have to consider that if you are going to put this into release code, you may have some users with root that have modified theirs for whatever reason. There are virtually no modifications that require using generic as the brand unless specifically trying to emulate the emulator.

Fingerprint is the build compile and kernel compile signature. There are builds that use generic, usually directly sourced from Google.

On a device that has been modified, the IMEI has a possibility of being zeroed out as well, so that is unreliable unless you are blocking modified devices altogether.

Goldfish is the base android build that all other devices are extended from. EVERY Android device has an init.goldfish.rc unless hacked and removed for unknown reasons.

Abandoned Cart
  • 4,512
  • 1
  • 34
  • 41
1

This worked for me instead of startsWith : Build.FINGERPRINT.contains("generic")

For more check this link: https://gist.github.com/espinchi/168abf054425893d86d1

1

try this link from github.

https://github.com/mofneko/EmulatorDetector

This module help you to emulator detection to your Android project suported Unity.

Basic checker

  • BlueStacks
  • Genymotion
  • Android Emulator
  • Nox App Player
  • Koplayer
  • .....
Saeid Parvizi
  • 21
  • 1
  • 5
0

Most commonly used technique is to match values from brand,name ... etc. But this method is static and for a limited versions of emulators. What if there are 1000+ VM manufacturers ? then you would have to write a code to match 1000+ VMs ?

But its time waste. Even after sometime, there would be new other VMs launched and your script would be wasted.

So based upon my tests, I got know getRadioVersion() returns empty on VM, and returns version number on real android device.

public Boolean IsVM() 
{
    return android.os.Build.getRadioVersion().length() == 0;
} 
//return true if VM
//return false if real

Although it works, But I don't have official explanation for this.

Code: http://github.com/Back-X/anti-vm/blob/main/android/anti-vm.b4a

Release: http://github.com/Back-X/anti-vm/releases/download/1/anti-vm.apk

Gray Programmerz
  • 479
  • 1
  • 5
  • 22
0

this method work for me

    public static boolean isRunningOnEmulator(String fingerprint, String hardware, String manufacturer) {
    boolean isEmulatorFingerprint = fingerprint.endsWith("test-keys");
    boolean isHardware = hardware.toLowerCase().contains("intel") || hardware.toLowerCase().contains("vbox");
    boolean isEmulatorManufacturer = manufacturer.equals("Genymotion")
            || manufacturer.equals("unknown");

    if (isHardware || isEmulatorFingerprint && isEmulatorManufacturer) {
        return true;
    } else {
        return false;
    }
}
Javid Sattar
  • 749
  • 8
  • 14
-1

You may check if deviceId (IMEI) is "000000000000000" (15 zeroes)

SparK
  • 5,181
  • 2
  • 23
  • 32
-1

In Android Studio under [Run > Edit Configurations... > Launch Flags]

In Launch Flags add the following...

--ei running_emulator 1

Then in your Activity onCreate

Bundle extras = getIntent().getExtras();
if (extras.getInt("running_emulator", 0) == 1) {
   //Running in the emulator!... Make USE DEV ENV!!
}

Easy!

Cal
  • 359
  • 3
  • 5