Skip to content

Instantly share code, notes, and snippets.

@flawyte
Last active March 8, 2024 06:05
  • Star 46 You must be signed in to star a gist
  • Fork 18 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save flawyte/efd23dd520fc2320f94ba003b9aabfce to your computer and use it in GitHub Desktop.
How to get an Android device's serial number, visible to the user in "Settings > About phone/tablet/device > Status > Serial number".

NOTE 2021/01/08: As of Android 10 (API level 29), there's no way for non-system and non-carrier apps to get the device's serial number, not even by calling the new Build.getSerial() method with the READ_PHONE_STATE permission, since per the docs it'll always either return Build.UNKNOWN (API < 29) or throw a SecurityException (API >= 29). This means that the code below might not work on some devices running Android 10+, due to changes in the Android OS itself and AFAIK there's no work around. See this official guide to migrate from using the device's serial number ; the Settings.Secure.ANDROID_ID might also be a good replacement. Also read the comments to see how other people are dealing with this problem, maybe someone has found a solution that will help you.

Devices tested

This code snippet has been successfully tested on the following devices and Android versions :

  • Archos 133 Oxygen : 6.0.1
  • Google Nexus 5 : 6.0.1
  • Hannspree HANNSPAD 13.3" TITAN 2 (HSG1351) : 5.1.1
  • Honor 5C (NEM-L51) : 7.0
  • Honor 5X (KIW-L21) : 6.0.1
  • Honor 9 Lite (LLD-L31) : 8.0
  • Huawei M2 (M2-801w) : 5.1.1
  • Samsung Galaxy S5 (SM-G900F) : 6.0.1
  • Samsung Galaxy S6 (SM-G920F) : 7.0
  • Samsung Galaxy Tab 4 (SM-T530) : 5.0.2
  • Xiaomi Mi 8 (M1803E1A) : 8.1.0
import android.os.Build;
import java.lang.reflect.Method;
public class Device {
/**
* @return The device's serial number, visible to the user in {@code Settings > About phone/tablet/device > Status
* > Serial number}, or {@code null} if the serial number couldn't be found
*/
public static String getSerialNumber() {
String serialNumber;
try {
Class<?> c = Class.forName("android.os.SystemProperties");
Method get = c.getMethod("get", String.class);
// (?) Lenovo Tab (https://stackoverflow.com/a/34819027/1276306)
serialNumber = (String) get.invoke(c, "gsm.sn1");
if (serialNumber.equals(""))
// Samsung Galaxy S5 (SM-G900F) : 6.0.1
// Samsung Galaxy S6 (SM-G920F) : 7.0
// Samsung Galaxy Tab 4 (SM-T530) : 5.0.2
// (?) Samsung Galaxy Tab 2 (https://gist.github.com/jgold6/f46b1c049a1ee94fdb52)
serialNumber = (String) get.invoke(c, "ril.serialnumber");
if (serialNumber.equals(""))
// Archos 133 Oxygen : 6.0.1
// Google Nexus 5 : 6.0.1
// Hannspree HANNSPAD 13.3" TITAN 2 (HSG1351) : 5.1.1
// Honor 5C (NEM-L51) : 7.0
// Honor 5X (KIW-L21) : 6.0.1
// Huawei M2 (M2-801w) : 5.1.1
// (?) HTC Nexus One : 2.3.4 (https://gist.github.com/tetsu-koba/992373)
serialNumber = (String) get.invoke(c, "ro.serialno");
if (serialNumber.equals(""))
// (?) Samsung Galaxy Tab 3 (https://stackoverflow.com/a/27274950/1276306)
serialNumber = (String) get.invoke(c, "sys.serialnumber");
if (serialNumber.equals(""))
// Archos 133 Oxygen : 6.0.1
// Hannspree HANNSPAD 13.3" TITAN 2 (HSG1351) : 5.1.1
// Honor 9 Lite (LLD-L31) : 8.0
// Xiaomi Mi 8 (M1803E1A) : 8.1.0
serialNumber = Build.SERIAL;
// If none of the methods above worked
if (serialNumber.equals(Build.UNKNOWN))
serialNumber = null;
} catch (Exception e) {
e.printStackTrace();
serialNumber = null;
}
return serialNumber;
}
}
@fraca7
Copy link

fraca7 commented Dec 7, 2020

Works on Galaxy Tab A (Android 9.0) and Galaxy Tab S2 (Android 7.0)

@vmsJenni
Copy link

vmsJenni commented Dec 7, 2020

What we have been experiencing, is that once the OS is updated to SDK Q, that the getSerialNumber code is no longer is useful.
We have resorted to using another method when the above no longer works (however, it will change during a factory reset)

Using MediaDrm to retrieve the WIDEVINE ID - which will return a unique id - there are several threads mentioning this approach - basically:

    String getWidevineSN(){
    String sRet = "";

    UUID WIDEVINE_UUID = new UUID(-0x121074568629b532L, -0x5c37d8232ae2de13L);
    MediaDrm mediaDrm = null;

     try {
        mediaDrm = new MediaDrm(WIDEVINE_UUID);
        byte[] widevineId = mediaDrm.getPropertyByteArray(MediaDrm.PROPERTY_DEVICE_UNIQUE_ID);

        MessageDigest md = MessageDigest.getInstance("SHA-256");
        md.update(widevineId);

        sRet = cvtByteArrayToHex(md.digest()); //we convert byte[] to hex for our purposes
    } catch (Exception e) {
        //WIDEVINE is not available
        Log.e(TAG, "getWidevineSN.WIDEVINE is not available");
        return null;
    } finally {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            if(null!=mediaDrm) {
                mediaDrm.close();
            }
        } else {
             if(null!=mediaDrm) {
                mediaDrm.release();
            }
        }
    }

    return sRet;
}//getWidevineSN

@MikeDimmickMnetics
Copy link

Regarding Android 10:

In the interests of user privacy, Google has restricted APIs that retrieve non-resettable device identifiers such as the serial number and IMEI. This is documented in Google's Privacy changes in Android 10 guide. The only apps that can use Build.getSerial (which replaced Build.SERIAL in Android 9) are:

  1. Preloaded apps with the READ_PRIVILEGED_PHONE_STATE permission - limited to apps that the manufacturer ships with the device, Google Play Store will not accept apps that request this permission.
  2. Device or profile owner apps with the READ_PHONE_STATE permission. These are mobile device management tools such as Microsoft InTune, Google Workspace, Soti MobileControl, Wavelink Avalanche etc.
  3. Apps supplied by the mobile network. The package ID of the app has to be listed in the SIM card.
  4. The app which is the current SMS role holder - the app which handles SMS messages.

If your target SDK is 28 or lower (Android 9/P), and you have the READ_PHONE_STATE permission, calling Build.getSerial will return Build.UNKNOWN. Otherwise (you don't have the permission, or your target SDK is 29 or higher) it throws a SecurityException.

Google state that you should use a different identifier, one that is resettable by the user. For example, use Settings.Secure.ANDROID_ID, which is persistent until the user factory resets the device. If you have more than one app, they will all see the same ID as long as you're using the same signing key to sign all the apps (from Android 8.0 onwards; before Android 8.0 all apps would see the same value).

Some of the other methods to get the serial number may still work, where the manufacturer provided a different method which hasn't been blocked by Google's change. But really, you should stop trying to do this. Google may restrict non-SDK interfaces in future: Restrictions on non-SDK interfaces. That said, android.os.SystemProperties.get is whitelisted in Android 10 and 11.

@flawyte
Copy link
Author

flawyte commented Dec 16, 2020

As @MikeDimmickMnetics explained, using the above method for retrieving the phone's serial number isn't reliable anymore.
I actually had added a paragraph explaining that too a few months ago but since people reported this code to be still working on Android 10 I eventually removed it. I'll add it back.

@SaketSharma11
Copy link

As @MikeDimmickMnetics explained, using the above method for retrieving the phone's serial number isn't reliable anymore.
I actually had added a paragraph explaining that too a few months ago but since people reported this code to be still working on Android 10 I eventually removed it. I'll add it back.

Please add the code which works on Android 10. I need it because the above code is not working on my device.

@vmsJenni
Copy link

vmsJenni commented Jan 8, 2021

We still have a lot of different devices running OS 10 that continue to retrieve a valid id using this code - however, most are defaulting to:
deviceID= Build.SERIAL;

It seems that this starts to return 'UNKNOWN' once the Build.ID value is updated - our Galaxy Tab S5e continued to retrieve a valid ID while on OS 10, until recently the Build.ID was updated to: QP1A.190711.020

To handle the situations where the ID will change, or return 'UNKNOWN', we tiered our getID method to 1st try:
deviceID = Build.SERIAL;

If it returned empty or 'unknown', then we try:
deviceID= Settings.Secure.getString(getApplicationContext().getContentResolver(), Settings.Secure.ANDROID_ID);

If that returns empty or 'unknown', then we default to using MediaDrm to get an ID.

In our case, we are able to handle if the deviceID changes by always sending the current ID, and the 'last_used' ID to our validation check - if the new ID is not found, we then look for a record containing the old ID. If neither is found, no record exists...

In the end, we probably could have just resorted to creating a GUID initially, and use the same validation checking, since it handles changes, but I'm always concerned if ever these generated GUID's might duplicate somewhere... keeps it fun, right?

@SaketSharma11
Copy link

@vmsJenni ok .Thank you so much, I will try and see.

@NaagAlgates
Copy link

As @MikeDimmickMnetics explained, using the above method for retrieving the phone's serial number isn't reliable anymore.
I actually had added a paragraph explaining that too a few months ago but since people reported this code to be still working on Android 10 I eventually removed it. I'll add it back.

Please add the code which works on Android 10. I need it because the above code is not working on my device.

I don't think it is possible anymore.

NOTE 2021/01/08: As of Android 10 (API level 29), there's no way for non-system and non-carrier apps to get the device's serial number, not even by calling the new Build.getSerial() method with the READ_PHONE_STATE permission, since per the docs it'll always either return Build.UNKNOWN (API < 29) or throw a SecurityException (API >= 29). This means that the code below might not work on some devices running Android 10+, due to changes in the Android OS itself and AFAIK there's no workaround. See this official guide to migrate from using the device's serial number; the Settings.Secure.ANDROID_ID might also be a good replacement.

Also read the comments to see how other people are dealing with this problem, maybe someone has found a solution that will help you.

@mdinopol
Copy link

Testing on Xiaomi Redmi 9C (Android 10). always returns unknown.
Does this have resolution for android 10?

@flawyte
Copy link
Author

flawyte commented Sep 14, 2021

@ammdsoftdev
Testing on Xiaomi Redmi 9C (Android 10). always returns unknown.
Does this have resolution for android 10?

As written in the readme it's not possible anymore to get the device's serial number on devices running Android 10 or newer. AFAIK there's no workaround since it's a limitation enforced by the Android OS itself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment