Skip to content

Releases: azoila/openmdm-android

v0.4.0 — Enrollment hardening, QR alignment, kiosk & command-delivery fixes

Choose a tag to compare

@andersonkxiass andersonkxiass released this 16 Jul 18:42

Hardening pass on device enrollment, QR provisioning alignment, kiosk, and command delivery — driven by an end-to-end test of the enrollment flow against openmdm-demo on an emulator.

Enrollment protocol & security

  • Enum-valid enrollment method. The agent reported method as device_code:<CODE>, which is not one of the server's EnrollmentMethod values — any server configured with enrollment.allowedMethods would reject every enrollment. Manual enrollment now sends manual, managed provisioning sends qr; the device code stays the on-device pairing reference. (6381683)
  • HMAC fallback signs with the provisioned secret. The QR admin-extras openmdm.device_secret was persisted but ignored — the HMAC path always signed with the compiled-in BuildConfig.DEVICE_SECRET, so a stock/provisioned APK failed enrollment against any server on the HMAC path. The secret now follows the same precedence as the server URL: provisioned wins, compiled-in is the fallback. (0a5c692)
  • Protocol-v2 envelope decoding. The agent stamps X-Openmdm-Protocol: 2 on every request but never decoded the {ok, action, data} envelope — Gson parsed the envelope against the flat payload models, every field landed null, and enrollment crashed with an NPE on deviceId. New AgentEnvelopeInterceptor unwraps success to data and maps failure actions to legacy statuses (reauth→401, unenroll→404, retry→503) with the action in an X-Openmdm-Action header; non-envelope bodies pass through untouched. (ebb11f0)
  • App versionName length. A real-world Android versionName longer than the server's varchar(50) (Google's TTS app ships 53 chars) made Postgres reject the insert and the server 500 the entire heartbeat, on every heartbeat. The agent now truncates defensively; the column was also widened server-side in @openmdm/drizzle-adapter@0.6.3. (688b870)

QR provisioning & enrollment UX

  • QR aligned to managed provisioning only. An in-app QR scanner was prototyped and then deliberately removed: the QR is the Android managed-provisioning QR, scanned by the setup wizard on a factory-reset device — the only path that grants Device Owner. An in-app scan enrolls without DO (no silent installs, no true kiosk), which reads as broken, so the enrollment screen offers device-code entry only. (f185670, reverted in 9d0fc5d)
  • QR parser reads flat payloads. openmdm.enrollment_token and openmdm.config_url were only read from the admin-extras bundle, unlike every other key — flat JSON payloads silently dropped the pairing token. (170ecc9)
  • Provisioning progress state. During managed-provisioning enrollment the screen now shows "Applying provisioned configuration — enrolling…" instead of a device-code prompt that would race the background worker.

Kiosk / Device Owner

  • Lock-task dedup. DeviceManager.startLockTaskMode passed [packageName, ownPackage] to setLockTaskPackages, which rejects a duplicate with "duplicate element" — so a single-app kiosk whose target is the agent failed. Both lock-task entry points now dedup. (c9b85db)

Command delivery & reliability

  • Fast in-process command poll loop. With no push channel (polling provider), commands were only fetched on the WorkManager heartbeat, whose periodic floor is 15 minutes — so a sub-minute policy interval was silently clamped and commands sat undelivered for up to ~15 min. MDMService now runs an in-process poll loop while the foreground service is alive, gated to the polling provider (persisted from the enrollment response's pushConfig) and a no-op for fcm/mqtt/websocket. Measured drain dropped from ~7 minutes to ~16 seconds. (9952511, gate extracted + unit-tested in 2e9ca49)

Verification

Verified end-to-end on an emulator: device enrolled as Device Owner (dpm set-device-owner), commands drain autonomously in ~16s, kiosk enterKiosk completes success=true, and pushConfig persistence + the poll-loop provider gate are covered by unit tests. Coordinated server-side fixes shipped in @openmdm/core@0.11.1 (identity errors map to real HTTP statuses instead of 500) and @openmdm/drizzle-adapter@0.6.3 (app-version columns widened).

Full commit range: f9796f6..2e9ca49

v0.3.0 — Provisioning that works, AMAPI features, hardened enrollment

Choose a tag to compare

@andersonkxiass andersonkxiass released this 15 Jul 13:50
144347d

Highlights

A prebuilt demo agent APK is attached to this releaseopenmdm-agent-v0.3.0.apk, signed, generic (server URL and enrollment config arrive via the provisioning QR), built without a TLS pin for evaluation. provisioning-checksum.txt carries the ready-to-paste PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM. See the README Quick Start and the openmdm-demo Android quick start.

Provisioning & enrollment

  • Managed provisioning actually works end-to-end: QR, afw#, and zero-touch provisioning intents are consumed, the mandatory GET_PROVISIONING_MODE / ADMIN_POLICY_COMPLIANCE activities exist (required on API 31+), and provisioning extras flow into automatic enrollment via a network-constrained worker (#16)
  • Work profile (BYOD) and COPE provisioning support (#21)
  • Device-pinned-key enrollment: single-use server challenge + hardware-Keystore ECDSA signature, with automatic HMAC fallback (#3); corrected HMAC canonical form (#2)
  • Enrollment security moved into :library for embedders; APK hash verification on installApp (#15)

Security

  • TLS certificate pinning is enforced on release builds — it was previously silently disabled because the buildConfig fields the pinner read were never defined (#14)

AMAPI feature set

  • ComplianceEvaluator enforcing OS-version/encryption/screen-lock rules, managed configurations, OS update policy + freeze periods, certificate install, full password policy (#18); AMAPI policy fields deserialized in PolicyMapper (#20)
  • DeviceOwnerManager collapsed onto the library's DeviceManager (965→185 lines), fixing a setAdbEnabled no-op and a wipeDevice preserveData inversion (#17)
  • VPN/proxy policy stubs removed rather than left advertising unimplemented behavior (#19)

Project

  • First CI (build/lint/test, caught 4 latent bugs), dependabot, hygiene docs (#4); test flake fixes (#22, #23)
  • Release workflow publishing the signed demo APK + provisioning checksum with every release (#24)
  • README rewritten to match the implementation: both enrollment paths, QR admin-extras keys, apksigner checksum recipe, correct minimum server version (#25)

Compatibility

Requires OpenMDM server ≥ 0.3.0 (protocol v2); device-pinned-key enrollment needs ≥ 0.9 with challenge storage. Tested against server 0.10.0.

Known limitations

The managed-provisioning flow and the new AMAPI DPM calls have unit/Robolectric coverage but have not yet had a full real-hardware Device Owner verification pass. Treat this as an evaluation release; production hardening is ongoing.

v0.2.0 - Reliability Improvements

Choose a tag to compare

@andersonkxiass andersonkxiass released this 24 Jan 22:02

What's New

🗄️ Command Persistence (Room Database)

  • Commands survive app crashes and device restarts
  • Track command status (PENDING, IN_PROGRESS, COMPLETED, FAILED)
  • Automatic retry with attempt tracking

⚡ WorkManager Integration

  • Heartbeats survive process death (minimum 15-min interval)
  • Reliable background execution with exponential backoff
  • Workers: HeartbeatWorker, CommandWorker, PushTokenWorker, SyncPendingCommandsWorker

🔄 Network Resilience

  • RetryInterceptor with exponential backoff (1s, 2s, 4s)
  • Automatic retry on IOException and 5xx server errors
  • No retry on 4xx client errors

📱 Kiosk Mode Improvements

  • Auto-restore kiosk mode on device boot
  • Auto-launch kiosk app after installation (PackageInstalledReceiver)
  • Smart app variant fallback (staging/dev builds)

🔒 Secure Updates

  • SHA-256 hash verification for APK updates
  • Downgrade protection
  • State backup for agent self-updates
  • Version constraint checking

📚 Library Updates

  • PolicyMapper.fromJson() for JSON parsing

✅ Test Coverage

  • 121 unit tests passing
  • WorkScheduler, CommandWorker, HeartbeatWorker tests
  • MDMRepository and integration tests

Usage (JitPack)

Add to your build.gradle:

```gradle
dependencies {
implementation 'com.github.azoila:openmdm-android:v0.2.0'
}
```

Full Changelog: v0.1.0...v0.2.0