In modern Android versions, privacy restrictions strictly govern access to non-resettable device identifiers, including the International Mobile Equipment Identity (IMEI), Mobile Equipment Identifier (MEID), hardware serial numbers, and International Mobile Subscriber Identity (IMSI). Prior to Android 10, applications frequently gathered hardware serial numbers for permanent device fingerprinting and cross-app tracking without explicit user consent. Google introduced the Device Identifier Policy subsystem and restricted direct hardware identifier queries exclusively to privileged system applications or apps possessing carrier privileges.
For system engineers, enterprise mobility administrators, and Android security auditors, the Android Debug Bridge (ADB) provides direct visibility into this privacy architecture via dumpsys device_identifiers. This command reveals runtime policy states, active restriction enforcement levels, and identifier access audits across the device.
The Privacy Architecture of Device Identifiers
Android categorises hardware identifiers into distinct security rings:
- Non-Resettable Hardware Identifiers: Persistent identifiers embedded into hardware modems and mainboards (IMEI, MEID, build serial number). Third-party applications cannot reset or alter these values. Under current Android policy, standard runtime permissions such as
READ_PHONE_STATEare insufficient to read them; apps must possess the privilegedREAD_PRIVILEGED_PHONE_STATEsignature permission or active carrier privilege certificates. - Resettable Software Identifiers: Dynamic tokens such as the Google Advertising ID (GAID) or developer-scoped app set IDs, which users can reset at any time via system settings.
- Scoped Android IDs: The
Settings.Secure.ANDROID_IDstring, which Android now generates uniquely per signing key and per user profile, preventing apps from correlating activity across different developer ecosystems.
The DeviceIdentifiersPolicyService intercepts requests targeting telephony and hardware identity services, verifying that the calling package UID satisfies strict cryptographic and permission constraints before returning telemetry.
Connecting via ADB and Verifying Telephony Privileges
Ensure that USB debugging or Wireless debugging is enabled on the target Android handset and connect via ADB from a terminal workstation:
# Verify connected device status
adb devices -l
# Ensure device is authorized and online
adb get-state
Confirm that the device is running Android 10 or later, where device identifier enforcement is globally mandated:
# Query Android OS API level and platform version
adb shell getprop ro.build.version.release
adb shell getprop ro.build.version.sdk
Executing dumpsys device_identifiers
To inspect the status of the device identifier policy engine, query the service directly via the ADB shell:
# Query the DeviceIdentifiersPolicyService diagnostic dump
adb shell dumpsys device_identifiers
Depending on the OEM build and active Android release, the command outputs the active policy configuration, including:
- Device Identifier Access Enforcement: Indicates whether hardware identifier restrictions are active globally or if relaxed compatibility modes exist for legacy pre-installed system packages.
- Carrier Privilege Mappings: Details cryptographic certificate hashes recognised by the SIM UICC card that grant carrier applications exemption from identifier blocks.
- Profile and Secondary User Restrictions: Confirms whether work profile boundaries or guest user containers inherit separate privacy ceilings.
Auditing Telephony Service Identifier Interceptions
Because device_identifiers interacts directly with Android telephony registries, combine the dump with telephony service queries to identify applications attempting to read restricted modem fields:
# Audit telephony registry for phone state listeners
adb shell dumpsys telephony.registry | grep -iE "mCallState|mServiceState|events"
# Inspect carrier privilege rules configured on the active SIM profile
adb shell dumpsys carrier_config | grep -iE "carrier_privilege|device_id"
If an unprivileged application attempts to call TelephonyManager.getImei() or Build.getSerial(), the policy service returns a SecurityException or substitutes the call with an empty null response or placeholder string (such as UNKNOWN), preventing fingerprinting without crashing the application.
Verifying App Capabilities with ADB Command-Line Queries
To audit whether a specific application holds the necessary privileges to query non-resettable identifiers, evaluate its granted permissions and AppOps state via ADB:
# Check whether an app holds the privileged phone state permission
adb shell dumpsys package com.example.diagnosticapp | grep -i "READ_PRIVILEGED_PHONE_STATE"
# Check AppOps state for read device identifiers
adb shell cmd appops get com.example.diagnosticapp READ_DEVICE_IDENTIFIERS
Standard user-installed applications will display READ_DEVICE_IDENTIFIERS: ignore or deny, confirming that Android’s device identifier privacy framework successfully neutralises unauthorised hardware tracking.
Testing Identifier Protection on Test and Staging Builds
Enterprise administrators and mobile application developers testing device enrollment workflows can verify fallback behaviours when hardware serial numbers are blocked:
# Simulate unprivileged state and query build serial via ADB
adb shell getprop ro.serialno
# Observe system logcat filter for device identifier access denials
adb shell logcat -d -s DeviceIdentifiersPolicyService TelephonyManager | grep -i "denied"
Auditing these diagnostic layers ensures that enterprise enterprise mobility management (EMM) agents and internal business applications properly adopt resettable tokens or modern Enrollment IDs rather than failing due to hardware identifier privacy locks.