Policy-key compatibility: stock Android vs GrapheneOS
The HardenedOS DPC uses standard Android
DevicePolicyManager / UserManager
APIs, so the policy capability set works on any Android
Enterprise Device Owner — Pixel, Samsung, and other OEMs — not just on
the Custom OS tier. This page is the per-key
reference for what behaves identically everywhere and the handful of
keys that don't.
Bottom line: of the full key catalogue, exactly
one key is GrapheneOS-only
(block_os_updates) and one is its inverse
(ota_install_window, which works on stock Android but not
GrapheneOS). A few radio controls are an effective block on the
managed tier rather than a hardware radio-off. Everything else is
identical across OEMs.
See policy-tiers.md for
the authoritative key catalogue (types, defaults, value shapes); this
page only classifies portability.
Summary — the keys that differ
| Key | Stock Android (e.g. Samsung) | GrapheneOS | Note |
|---|---|---|---|
block_os_updates |
❌ no-op | ✅ works | Hides app.grapheneos.updater, which doesn't exist off
GrapheneOS. |
ota_install_window |
✅ works (AOSP SystemUpdatePolicy) |
❌ no effect | GrapheneOS's Updater ignores SystemUpdatePolicy. |
disable_wifi |
⚠️ effective block | ⚠️ effective block | Software block (config restriction + match-nothing SSID allowlist). True radio-off needs the Custom OS tier on either OEM. |
disable_nfc |
⚠️ beam/share off | ⚠️ beam/share off | DISALLOW_OUTGOING_BEAM; no Device-Owner API for a full
NFC radio-off on any OEM. |
To control OS updates portably: use
ota_install_window on stock Android and
block_os_updates on GrapheneOS. Setting
both is safe — each no-ops on the OS where it doesn't apply.
Everything below is cross-platform — identical behavior on any Android Enterprise Device Owner.
Full matrix
Lock screen + biometric — all cross-platform
| Key | Mechanism |
|---|---|
screen_lock_required |
setRequiredPasswordComplexity() |
screen_lock_max_attempts |
setMaximumFailedPasswordsForWipe() |
require_biometric_after_seconds |
setMaximumTimeToLock() |
biometric_only |
setKeyguardDisabledFeatures() (face/iris bits) |
disable_biometric_unlock |
setKeyguardDisabledFeatures()
(KEYGUARD_DISABLE_BIOMETRICS) |
screen_timeout_seconds |
setSystemSetting(SCREEN_OFF_TIMEOUT) |
lockscreen_message |
setDeviceOwnerLockScreenInfo() |
lockscreen_notification_redaction |
setKeyguardDisabledFeatures() (notification bits) |
Apps + sideloading — all cross-platform
| Key | Mechanism |
|---|---|
allow_sideloading |
DISALLOW_INSTALL_UNKNOWN_SOURCES |
allow_developer_mode |
DISALLOW_DEBUGGING_FEATURES |
allow_safe_mode |
DISALLOW_SAFE_BOOT |
allow_personal_accounts |
DISALLOW_MODIFY_ACCOUNTS |
force_installed_apps |
setUninstallBlocked() + install |
blocked_apps |
setApplicationHidden() |
disabled_system_apps |
setApplicationHidden() — the package names are
OEM-specific (e.g. Samsung ships different built-ins than
GrapheneOS/AOSP); the mechanism is identical. |
permitted_input_methods |
setPermittedInputMethods() |
Privacy + capture — all cross-platform
| Key | Mechanism |
|---|---|
allow_screenshots |
setScreenCaptureDisabled() |
disable_camera |
setCameraDisabled() |
disable_microphone |
DISALLOW_UNMUTE_MICROPHONE |
disable_usb_transfer |
DISALLOW_USB_FILE_TRANSFER |
Network + radios — cross-platform (radio caveats below)
| Key | Mechanism |
|---|---|
always_on_vpn |
setAlwaysOnVpnPackage(lockdown) |
allowed_wifi_networks |
setWifiSsidPolicy() (API 33+) |
block_other_wifi |
DISALLOW_ADD_WIFI_CONFIG |
disable_wifi |
DISALLOW_CONFIG_WIFI + match-nothing
WifiSsidPolicy — effective block, see
below |
disable_bluetooth |
DISALLOW_BLUETOOTH |
allow_bluetooth_config |
DISALLOW_CONFIG_BLUETOOTH |
disable_nfc |
DISALLOW_OUTGOING_BEAM — beam/share only, see
below |
disable_tethering |
DISALLOW_CONFIG_TETHERING |
disable_data_roaming |
DISALLOW_DATA_ROAMING |
Branding + time + misc — cross-platform
| Key | Mechanism |
|---|---|
wallpaper_url / wallpaper_sha256 |
WallpaperManager |
auto_time |
setAutoTimeEnabled() |
auto_timezone |
setAutoTimeZoneEnabled() |
disable_backup_service |
setBackupServiceEnabled() |
disable_status_bar |
setStatusBarDisabled() |
ota_channel |
persisted config (honored only by the Custom OS Updater) |
High-restriction — cross-platform
| Key | Mechanism |
|---|---|
kiosk_mode_enabled / kiosk_apps |
lock-task / single-app DPM calls |
geofence |
persisted (server/heartbeat-enforced) |
remote_attestation_required |
persisted flag; attestation works on any device with StrongBox |
audit_log_enabled |
setSecurityLoggingEnabled() |
tamper_response |
persisted; mechanism OEM-agnostic |
hardware_locked_settings |
addUserRestriction() over a validated list |
The OS-update keys
block_os_updateshides the GrapheneOS Updater app (app.grapheneos.updater). On stock Android that package doesn't exist, so the call silently no-ops — it cannot freeze a Samsung/Pixel-stock OTA.ota_install_windowuses AOSPsetSystemUpdatePolicy(), which stock Android honours but GrapheneOS ignores (its Updater is independent of the system OTA mechanism).
So they're complementary, not redundant. For a fleet spanning OEMs, set both: the platform applies whichever one the device's OS respects.
The radio caveat (both tiers)
disable_wifi and disable_nfc are an
effective block at the managed tier, not a hardware
radio-off:
disable_wifi=DISALLOW_CONFIG_WIFI+ a match-nothing SSID allowlist, so the device can't associate with any network or change Wi-Fi settings. A non-system Device Owner has no API to power the Wi-Fi radio off (setWifiEnabledis a no-op for non-system apps since Android 10).disable_nfc=DISALLOW_OUTGOING_BEAM(blocks NFC beam/share); there is no Device-Owner API for a full NFC radio-off.
A true hardware radio-off requires system-app privileges — i.e. the Custom OS tier — and even there it is Pixel-only. This caveat is not GrapheneOS-specific; it's a managed-Device-Owner limitation that applies equally on Samsung and Pixel-stock.