# Security posture signals

> [!IMPORTANT]
> **Important:** Device Trust from Android Enterprise is a unique API solution that makes available these and more signals to evaluate the security posture of an Android-powered device. For additional information see: [**Device Trust from Android Enterprise**](https://developers.google.com/android/management/device-trust-register).

Android provides a variety of device signals that administrators can use to
determine the security posture of a device. In a Zero Trust security model,
these signals are used to assess whether a device should be allowed to access
corporate information.

| Feature | Description | devices | Work profile on company-owned devices | Work profile on personally-owned devices (BYOD) | Unmanaged devices |
|---|---|---|---|---|---|
| [Play Integrity API](https://developer.android.com/google/play/integrity) | A can retrieve the following signals: - Device integrity - App integrity - Play license details - Environment details including the new Play Protect verdict | Yes | Yes | Yes | Yes |
| [Secure Hardware Present / Key Attestation](https://developer.android.com/training/articles/security-key-attestation) | A Trust broker can verify that their PKI credentials were generated and stored in secure hardware | Yes | Yes | Yes | Yes |
| [Device Properties Attestation](https://developer.android.com/about/versions/12/features#device-properties-verification) | As part of key attestation, device properties can be included as part of the attestation record | Yes | Yes | Yes | Yes |
| [Device Security Patch Level](https://developer.android.com/reference/android/os/Build.VERSION#SECURITY_PATCH) | A Trust broker can validate the OS Security Patch Level | Yes | Yes | Yes | Yes |
| [Does the device have pending OTA](https://developer.android.com/reference/android/app/admin/DevicePolicyManager#getPendingSystemUpdate(android.content.ComponentName)) | A Trust broker can check if there is a pending device OS update available | Yes | Yes | Yes | N/A |
| [Mainline Security Patch Level](https://developers.google.com/android/work/security-posture-signals#retrieve_mainline_version) | A Trust broker can read the security patch level for the installed mainline train | Yes | Yes | Yes | Yes |
| [Enrollment Specific ID](https://developer.android.com/reference/android/app/admin/DevicePolicyManager#getEnrollmentSpecificId()) | A Trust broker can access a unique device ID specific to that enterprise. This ID survives work profile re-creation and device factory reset | Yes | Yes | Yes | N/A |
| [Management State (and managing app)](https://developers.google.com/android/work/security-posture-signals#retrieve_management_state) | A Trust broker can use this to determine if a device is managed | Yes | Yes | Yes | N/A |
| [Disk encryption](https://developer.android.com/reference/android/app/admin/DevicePolicyManager#getStorageEncryptionStatus()) | A Trust broker can check if the device is encrypted (if Android 8 support is needed) | Yes | Yes | Yes | Yes |
| [OS Version](https://developer.android.com/reference/android/os/Build.VERSION#SDK_INT) | A Trust broker can check the device OS version and confirm it exceeds a certain version | Yes | Yes | Yes | Yes |
| [Access Network State (Network state and WiFi state)](https://developer.android.com/reference/android/net/ConnectivityManager#getActiveNetwork()) | A Trust broker can get information about the active network state (cellular and WiFi) | Yes | Yes | Yes | Yes |
| Access the WiFi State ([Android 11 and lower](https://developer.android.com/reference/android/net/wifi/WifiManager#getConnectionInfo()), Android 12 and higher support both a [callback](https://developer.android.com/reference/android/net/ConnectivityManager.NetworkCallback#onCapabilitiesChanged(android.net.Network,%20android.net.NetworkCapabilities)) or an [on-demand](https://developer.android.com/reference/android/net/ConnectivityManager#getNetworkCapabilities(android.net.Network)) approach) | A Trust broker can get information about the active WiFi network | Yes | Yes | Yes | Yes |
| [Proxy Settings](https://developer.android.com/reference/android/net/ConnectivityManager#getDefaultProxy()) | A Trust broker can get information about the current default HTTP proxy settings. | Yes | Yes | Yes | Yes |
| [Screen lock quality check](https://developer.android.com/work/versions/android-10#screen_lock_quality_check) | A Trust broker can ensure a device has a certain quality screen lock configured before granting access | Yes | Yes | Yes | Yes |
| [Developer options enabled](https://developer.android.com/reference/android/provider/Settings.Global#ADB_ENABLED) | A Trust broker can identify a device as having a broader attack surface when developer options are enabled | Yes | Yes | Yes | Yes |
| [Is DNS over TLS enabled](https://developer.android.com/reference/android/app/admin/DevicePolicyManager#getGlobalPrivateDnsMode(android.content.ComponentName)) | A Trust broker can leverage this to ensure that that the Private DNS mode is enabled | Yes | Yes | Yes | Yes |
| [SafetyNet Safe Browsing](https://developer.android.com/training/safetynet/safebrowsing) | A Trust broker can determine whether a particular URL has been classified by Google as a known threat. | Yes | Yes | Yes | Yes |
| [External Media Mounted](https://developer.android.com/reference/android/content/Intent#ACTION_MEDIA_MOUNTED) | A Trust broker can be notified when an external storage is mounted | Yes | Yes | Yes | Yes |
| [UsageStatsManager](https://developer.android.com/reference/android/app/usage/UsageStats) | A Trust broker can study usage patterns of individual apps | Yes | Yes | Yes | Yes[^1^](https://developers.google.com/android/work/security-posture-signals#fn1) |
| [Security logging](https://developer.android.com/reference/android/app/admin/SecurityLog) | A Trust broker can leverage this data as part of their contextual engine to ensure compliance and create a behavior based fingerprint | Yes | Yes[^2^](https://developers.google.com/android/work/security-posture-signals#fn2) | Yes[^2^](https://developers.google.com/android/work/security-posture-signals#fn2) | N/A |
| [Network logging](https://developer.android.com/reference/android/app/admin/NetworkEvent) | A Trust broker can leverage this data as part of their contextual engine to ensure compliance and create a behavior based fingerprint | Yes | Yes[^2^](https://developers.google.com/android/work/security-posture-signals#fn2) | Yes[^2^](https://developers.google.com/android/work/security-posture-signals#fn2) | N/A |
| [NetworkStatsManager](https://developer.android.com/reference/android/app/usage/NetworkStatsManager) | A Trust broker can query app's network usage within a given time interval | Yes | Yes | Yes[^2^](https://developers.google.com/android/work/security-posture-signals#fn2) | Yes[^1^](https://developers.google.com/android/work/security-posture-signals#fn1) |
| [Package Visibility (List all apps on device)](https://developer.android.com/training/package-visibility/declaring) | A Trust broker can query what apps are installed on the device | Yes | Yes[^3^](https://developers.google.com/android/work/security-posture-signals#fn3) | Yes[^3^](https://developers.google.com/android/work/security-posture-signals#fn3) | Yes |
| [Read Phone State](https://developer.android.com/reference/android/Manifest.permission#READ_PHONE_STATE) | A Trust broker can get mobile network info, the status of any ongoing calls, and a list of [PhoneAccount](https://developer.android.com/reference/android/telecom/PhoneAccount) registered on the device | Yes | Yes | Yes | Yes |
| [When the device last rebooted](https://developer.android.com/reference/android/os/SystemClock#elapsedRealtime()) | A Trust broker can get the system uptime | Yes | Yes | Yes | Yes |
| [Get Accounts](https://developer.android.com/reference/android/accounts/AccountManager#getAccounts()) | A Trust broker can leverage this to access the list of accounts in the Accounts Service | Yes | Yes[^3^](https://developers.google.com/android/work/security-posture-signals#fn3) | Yes[^3^](https://developers.google.com/android/work/security-posture-signals#fn3) | Yes[^1^](https://developers.google.com/android/work/security-posture-signals#fn1) |
| [Monitor significant changes in battery level](https://developer.android.com/training/monitoring-device-state/battery-monitoring#MonitorLevel) | A Trust broker can monitor significant changes in battery level | Yes | Yes | Yes | Yes |
| [Location (Fine, Coarse, etc...)](https://developer.android.com/training/location) | A Trust broker can access the device physical location | Yes | Yes | Yes[^1^](https://developers.google.com/android/work/security-posture-signals#fn1) | Yes[^1^](https://developers.google.com/android/work/security-posture-signals#fn1) |

<br />

^1^ With user consent

^2^ Work profile only

^3^ Access limited to work profile information

## Retrieve Mainline version

A Trust broker can access the [PackageInfo](https://developer.android.com/reference/android/content/pm/PackageInfo) for the
`com.google.android.modulemetadata` module and retrieve from there the
`versionName`:

    private fun mainlineVersion(context: Context): String? {
        val moduleProvider = "com.google.android.modulemetadata"

        return try {
                val pm = context.packageManager
                val packageInfo = pm.getPackageInfo(moduleProvider, 0)
                packageInfo.versionName
            } catch (e: PackageManager.NameNotFoundException) {
                null
            }
    }

You can parse the returned string into a `Date` object using the
[`SimpleDateFormat`](https://developer.android.com/reference/java/text/SimpleDateFormat) class:

    private val VERSION_NAME_DATE_PATTERNS = Arrays.asList(
          "yyyy-MM-dd",
          "yyyy-MM"
    )

    private fun parseDateFromVersionName(text: String): Date? {
        for (pattern in VERSION_NAME_DATE_PATTERNS) {
            try {
                val simpleDateFormat = SimpleDateFormat(
                    pattern,
                    Locale.getDefault()
                )
                simpleDateFormat.timeZone = TimeZone.getDefault()
                return simpleDateFormat.parse(text)
            } catch (e: ParseException) {
                // ignore and try next pattern
            }
        }
        return null
    }

Remember that for Android 11 and newer you have to add a query declaration in
you `AndroidManifest.xml` file to satisfy Android's [package visibility](https://developer.android.com/training/package-visibility):

```xml
<manifest package="com.example.game">
    <queries>
        <package android:name="com.google.android.modulemetadata" />
    </queries>
    ...
</manifest>
```

## Retrieve management state

A Trust broker can use these methods to verify if a device is under management
mode and which management mode is active.

### Check for device management

Use [getActiveAdmins()](https://developer.android.com/reference/android/app/admin/DevicePolicyManager#getActiveAdmins()) to check if a device is under management. If this
method returns `null` the device is unmanaged.

### Check for fully managed device

Use [`isDeviceOwnerApp()`](https://developer.android.com/reference/android/app/admin/DevicePolicyManager#isDeviceOwnerApp(java.lang.String)) to check if the device is fully managed.

### Check for work profile on a company-owned device

Use [`isOrganizationOwnedDeviceWithManagedProfile()`](https://developer.android.com/reference/android/app/admin/DevicePolicyManager#isOrganizationOwnedDeviceWithManagedProfile()) to check if a device
is using a work profile management mode for corporate-owned devices

### Check for work profile on a personally-owned device

Use [`isProfileOwnerApp()`](https://developer.android.com/reference/android/app/admin/DevicePolicyManager#isProfileOwnerApp(java.lang.String)) to check if an app is running inside a work
profile and verify that `isOrganizationOwnedDeviceWithManagedProfile()` returns
`false`.

> [!NOTE]
> **Note:** If the `isProfileOwnerApp()` check is done from an app running outside the work profile it will always return `false`.