386

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?

4
  • 2
    Might have a look at android.os.Build. Commented May 9, 2010 at 21:25
  • 16
    Amaze me... Google should have a standard way of doing this? Commented Apr 11, 2014 at 19:41
  • @kreker what is issue, you are facing in existing solutions? Commented Oct 1, 2018 at 6:07
  • @Khemraj fraud issues. Evil guy can mock some sensors and change some strings to pretend real device Commented Oct 2, 2018 at 8:46

41 Answers 41

201

How about this solution (class implementation of SystemProperties is available here), which I also published on my public repository here:

val isProbablyRunningOnEmulator: Boolean by lazy {
    return@lazy (
            // Android SDK emulator
            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_")))
                            //Google Play Games emulator https://play.google.com/googleplaygames https://developer.android.com/games/playgames/emulator#other-downloads
                            || (Build.MODEL == "HPE device" &&
                            Build.FINGERPRINT.startsWith("google/kiwi_") && Build.FINGERPRINT.endsWith(":user/release-keys")
                            && Build.BOARD == "kiwi" && Build.PRODUCT.startsWith("kiwi_"))
                            )
                    //
                    || 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")
                    // From com.google.firebase.crashlytics.internal.common.CommonUtils.isEmulator
                    || Build.HARDWARE.contains("goldfish") || Build.HARDWARE.contains("ranchu")|| Build.PRODUCT.contains("sdk")
}

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"
Sign up to request clarification or add additional context in comments.

24 Comments

That's the way Facebook detects emulators in React-Native
@Sid Have you printed out various Build class variables there? Nothing seems special? Have you tried this: github.com/framgia/android-emulator-detector ?
@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: medium.com/tixdo-labs/… , so maybe that's possible too)
@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...
@AyxanHaqverdili Sometimes I'm very tired too, making weird mistakes.
|
122

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

7 Comments

This works even with Galaxy Tab Emulator. The top liked answer didn't.
Please state whether a fingerprint containing "generic" is either an emulator or the device. That information is key but not provided.
Emulator - judging by the comments before yours :)
This returns true on my devices running CyanogenMod so beware.
The Android documentation says you shouldn't try to interpret the FINGERPRINT value.
|
108

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");
}

6 Comments

Here is a link directly to the code in question: github.com/flutter/plugins/blob/master/packages/device_info/…
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; }
These methods are no longer working on most emulator like Memu
Add one more check, Build.PRODUCT == "sdk_gphone64_arm64"
You may want to add: Build.FINGERPRINT == "robolectric" if your using robolectric
|
67

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

"google_sdk".equals( Build.PRODUCT );

12 Comments

Anyone reading this may be interested to know that this string appears to have changed to 'sdk', rather than 'google_sdk'.
@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.
The Intel emulator returns "full_x86" so I wouldn't count on this method.
@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.
Including more cases: "google_sdk".equals(Build.PRODUCT) || "sdk".equals(Build.PRODUCT) || "sdk_x86".equals(Build.PRODUCT) || "vbox86p".equals(Build.PRODUCT)
|
32

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

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

4 Comments

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.
I'd go with isEmulator = Build.HARDWARE.contains("golfdish")
@holmes: typo, s/b "goldfish"
For the Android 5.1 x86_64 image (and probably other more recent 64bit images) that would be "ranchu" instead of "goldfish".
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;

} 

3 Comments

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.
I think it is the only reliable solution. However, the debug key can change more quickly than we want.
A better way to do this is BuildConfig.DEBUG.
15

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.

5 Comments

What does a device without a SIM card (such as a tablet) return?
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).
@rds Devices which does not have a SIM card returns empty string ("")
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.
fyi, nox does not return "Android" as network operator
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....

1 Comment

This works only if you don't plan to debug your app on a real hardware device.
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.

1 Comment

Wouldn't product.contains("sdk") would cover all three cases?
12

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

1 Comment

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.
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)

3 Comments

When running the x86 emulator on Windows, Build.Product is sdk_x86.
checking with PRODUCT is not a good choice as it returns various values from different emulators
This is out of date and no longer valid.
11

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

2 Comments

FYI, Android Studio complains: Using getString to get device identifiers is not recommended
@thijsonline looks like this condition got removed recently. Updated my answer.
8

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.

2 Comments

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".
I read in a different stackoverflow comment here: stackoverflow.com/questions/2799097/… that this file is present on many actual devices, many Samsungs. I'm seeing it in our logs as well from some Samsung devices.
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;

    }

Comments

8

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.

1 Comment

How do you get the power source and temperature ?
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("");

Comments

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().

1 Comment

This appears to work from the NDK. Include <sys/system_properties.h> and use __system_property_get("ro.hardware", buf) then check that buf is "goldfish".
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.

Comments

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

Comments

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).

1 Comment

On my Genymotion running on a mac Build.DEVICE = vbox86p
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;
}

5 Comments

Nice one. init.goldfish.rc only exists in emulators; it's additionally a good check going forward in addition to the Build details.
@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 you were actually correct. I found that out later and apologies that I forget to update it here.
test-keys has been generating false positives for me.
On which devices they are generating false positives ?
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;
}

3 Comments

Andy_46.16_48 returns "andy" for Build.HARDWARE
Lead false positive for Samsung J series devices. Used following to detect emulator: github.com/gingo/android-emulator-detector
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
                        }
                    }
                });

1 Comment

Does not work with nox player , it is not detecting nox emulator
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.

2 Comments

IMEI is likely also to return 0 on an Android tablet, or on a phone without SIM card.
We can edit IMEI on the emulator. so this may not serve the purpose. Also, starting from API 29 we cannot access IMEI.
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.

1 Comment

I'd be careful with that because of this horrible bug: code.google.com/p/android/issues/detail?id=10603
3

This works for me

public boolean isEmulator() {
    return Build.MANUFACTURER.equals("unknown");
}

1 Comment

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.
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.

Comments

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).

Comments

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;
    }
}

Comments

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.