Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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;
}
}
@semoLi
Copy link

semoLi commented Sep 15, 2018

i'm tested on Samsung Galaxy A5 (SM-A500FQ) and Turkcell T-Tablet (Based ZTE).
works perfectly

@atatlisu
Copy link

atatlisu commented Dec 20, 2018

Also works on Samsung Galaxy Tab A SM-P550.

@basmasrour
Copy link

basmasrour commented Jan 21, 2019

what about this:
https://developer.android.com/reference/android/os/Build#SERIAL

"This field was deprecated in API level 26.
Use getSerial() instead.
this field is set to UNKNOWN"

@gmavenis
Copy link

gmavenis commented Apr 24, 2019

Thanks for your code!
But anyone knows the key for LG devices?
I get properties by: adb shell getprop
but it doesn't return S/N inside.

@maj3091
Copy link

maj3091 commented Oct 16, 2019

Thanks for this, tested and working on a Zebra MC9300 running 8.1.0

@iformas
Copy link

iformas commented Jan 22, 2020

what about this:
https://developer.android.com/reference/android/os/Build#SERIAL

"This field was deprecated in API level 26.
Use getSerial() instead.
this field is set to UNKNOWN"

Build.getSerial() calls to IDeviceIdentifiersPolicyService.getSerialForPackage(...) and returns SystemProperties.get("ro.serialno", Build.UNKNOWN);

So, it miss all the other vendor keys

@mattwynyard
Copy link

mattwynyard commented Jun 8, 2020

works on galaxy 10

@leiyugithub
Copy link

leiyugithub commented Jun 11, 2020

works on xiaomi4

@adriatikgashi
Copy link

adriatikgashi commented Jul 29, 2020

Works on Lenovo TB-7104F (Lenovo TB-7104F) and Samsung Galaxy S10+

@vmsJenni
Copy link

vmsJenni commented Aug 22, 2020

vinodkumargangal commented on this gist.


Does not work on Android 10

Please be specific on what device you are stating it not working on (to better inform us)

It does work on the following devices we have (all Android 10):
Galaxy Tab S5e (SM-T720)
Galaxy Tab A (SM-T290)
Galaxy S9 (SM-G960U)
Galaxy S10 (SM-G973U)
Galaxy S10+ (SM-G975U)

@satti8893
Copy link

satti8893 commented Sep 11, 2020

Guys not working on Mi A2 & Poco F1. Both running Android 10

@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

MikeDimmickMnetics commented Dec 16, 2020

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

SaketSharma11 commented Jan 8, 2021

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

SaketSharma11 commented Jan 8, 2021

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

@NaagAlgates
Copy link

NaagAlgates commented Jan 18, 2021

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

mdinopol commented Sep 14, 2021

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