HardenedOS

Enrollment — Device Owner provisioning on any Android

The HardenedOS DPC manages a device by being made the Android Device Owner. That is a standard Android Enterprise operation, so enrollment works on any OEM — Pixel, Samsung, and others — with the same flow and the same code. This guide covers the enrollment paths and the OEM-specific gotchas (notably Samsung/Knox).

The mechanism is OEM-agnostic. Earlier docs and admin routes were named "graphene"; that was naming, not a technical constraint. The provisioning payload, signing-cert pin, and ADB steps are pure AOSP.


The one hard precondition (every OEM)

Android only allows Device Owner assignment on a freshly-set-up device with no accounts added. So a device must be factory-fresh (or factory-reset) and you must enroll before adding any Google/Samsung/other account.

This is Android's rule, not ours, and it is identical on Pixel and Samsung. There is no way around it — if an account exists, set-device-owner / QR provisioning will refuse.


Enrollment paths

All paths install the same DPC, assign Device Owner, and hand the device a one-time activation code (XXXX-XXXX-XXXX-XXXX) minted by the reseller.

On the device's first welcome screen, tap six times to launch the QR provisioning flow, then scan a QR generated by:

Android downloads the DPC from the pinned URL, verifies its signing certificate matches the pinned SHA, installs it, promotes it to Device Owner, and passes the activation code through the provisioning bundle. The payload uses only standard android.app.extra.PROVISIONING_* keys — it works on any Android 7+ device that supports Android Enterprise QR provisioning, including Samsung One UI.

2. WebUSB (browser-driven, no operator tooling)

Open api.hardenedos.com/enroll/usb?code=XXXX-XXXX-XXXX-XXXX in Chrome/Edge on a Mac/PC, connect the device over USB with USB debugging on, and the page drives ADB to: push the DPC, pm install -r, dpm set-device-owner, and launch activation with the code pre-filled. All five steps are pure AOSP ADB — no GrapheneOS- or Pixel-specific commands.

3. Manual / adb (development)

adb install -r dpc.apk
adb shell dpm set-device-owner com.hardenedos.dpc/.HardenedOSDeviceAdminReceiver
adb shell am start -n com.hardenedos.dpc/.activation.ActivationActivity \
  --es com.hardenedos.dpc.ACTIVATION_CODE XXXX-XXXX-XXXX-XXXX

Custom OS tier

On the Custom OS tier the system image provisions the DPC as Device Owner at first boot — no external QR/WebUSB step. Post-activation the lifecycle is identical.


Artifacts the enrollment paths use

URL What it is
https://api.hardenedos.com/dpc.apk the DPC APK (served no-store)
https://api.hardenedos.com/dpc.apk.sha256 SHA-256 of the APK file bytes — verify a download against this
https://api.hardenedos.com/dpc.sha256 SHA-256 of the signing certificate — the QR PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM pin
GET /partner/v1/enrollment-config live {dpc_apk_url, dpc_integrity_url, signing-cert SHA (hex + base64url), device-admin component, activation-code extra key, ready-to-fill QR payload template}

The DPC is currently debug-signed (cert SHA 2ac25242…). The pin mechanism is OEM-agnostic; a production signing cert just changes the pinned value (set via DPC_APK_SIGNING_CERT_SHA256).


Samsung (and other stock-OEM) specifics

The flows above work unchanged on a Samsung Galaxy (One UI on Android 15). The only differences are operational, not code:

Not yet hardware-validated

Everything to date has been validated on Pixel hardware. The DPC has no GrapheneOS gate and uses only standard APIs, so Samsung should behave identically — but a few UserRestrictions are enforced slightly differently by some OEMs, so validate the specific policy set you care about on real Samsung hardware before relying on it. See the policy-key compatibility matrix for keys that are known to differ by OS.


What is OEM-agnostic vs named "graphene"

For maintainers: the enrollment logic is already generic. The admin-panel route, handler names, and some UI copy historically said "graphene"; the generic route is /provision/managed (the legacy /provision/graphene remains as an alias). The partner enrollment-config API never carried any OEM branding.