[android] Android: How to programmatically access the device serial number shown in the AVD manager (API Version 8)

How do I programmatically access the value shown in the image below ?

enter image description here

This question is related to android serial-number

The answer is


Build.SERIAL can be empty or sometimes return a different value (proof 1, proof 2) than what you can see in your device's settings.

If you want a more complete and robust solution, I've compiled every possible solution I could found in a single gist. Here's a simplified version of it :

public static String getSerialNumber() {
    String serialNumber;

    try {
        Class<?> c = Class.forName("android.os.SystemProperties");
        Method get = c.getMethod("get", String.class);

        serialNumber = (String) get.invoke(c, "gsm.sn1");
        if (serialNumber.equals(""))
            serialNumber = (String) get.invoke(c, "ril.serialnumber");
        if (serialNumber.equals(""))
            serialNumber = (String) get.invoke(c, "ro.serialno");
        if (serialNumber.equals(""))
            serialNumber = (String) get.invoke(c, "sys.serialnumber");
        if (serialNumber.equals(""))
            serialNumber = Build.SERIAL;

        // If none of the methods above worked
        if (serialNumber.equals(""))
            serialNumber = null;
    } catch (Exception e) {
        e.printStackTrace();
        serialNumber = null;
    }

    return serialNumber;
}

I try to update the gist regularly whenever I can test on a new device or Android version. Contributions are welcome too.


Up to Android 7.1 (SDK 25)

Until Android 7.1 you will get it with:

Build.SERIAL

From Android 8 (SDK 26)

On Android 8 (SDK 26) and above, this field will return UNKNOWN and must be accessed with:

Build.getSerial()

which requires the dangerous permission android.permission.READ_PHONE_STATE.

From Android Q (SDK 29)

Since Android Q using Build.getSerial() gets a bit more complicated by requiring:

android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE (which can only be acquired by system apps), or for the calling package to be the device or profile owner and have the READ_PHONE_STATE permission. This means most apps won't be able to uses this feature. See the Android Q announcement from Google.

See Android SDK reference


Best Practice for Unique Device Identifier

If you just require a unique identifier, it's best to avoid using hardware identifiers as Google continuously tries to make it harder to access them for privacy reasons. You could just generate a UUID.randomUUID().toString(); and save it the first time it needs to be accessed in e.g. shared preferences. Alternatively you could use ANDROID_ID which is a 8 byte long hex string unique to the device, user and (only Android 8+) app installation. For more info on that topic, see Best practices for unique identifiers.


From Android P, defining the READ_PHONE_STATE permission in AndroidManifest only, will not work. We have to actually request for the permission. Below code works for me:

@RequiresApi(api = Build.VERSION_CODES.P)
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_PHONE_STATE}, 101);
    }
}

@RequiresApi(api = Build.VERSION_CODES.O)
@Override
protected void onResume() {
    super.onResume();
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
        return;
    }
    Log.d(TAG,Build.getSerial());
}
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    switch (requestCode) {
        case 101:
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
                return;
            }
        } else {
            //not granted
        }
        break;
        default:
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}

Add this permissions in AndroidManifest.xml

<uses-permission android:name = "android.permission.INTERNET"/>
<uses-permission android:name = "android.permission.READ_PHONE_STATE" />

Hope this helps.

Thank You, MJ