<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #49655 Documentation-only change. No server behavior changes. ## What's happening On a personally-owned work profile (BYOD), Android applies the biometric values of `keyguardDisabledFeatures` to the work profile lock. By default the end user has one lock for both the work profile and the host ("Use one lock"), so there is no separate work profile lock to restrict, and Android restricts the host's lock instead. Fingerprint and face unlock turn off for the whole host, including the end user's personal apps. This is documented Android behavior, per [`setKeyguardDisabledFeatures`](https://developer.android.com/reference/android/app/admin/DevicePolicyManager#setKeyguardDisabledFeatures(android.content.ComponentName,%20int)): > `KEYGUARD_DISABLE_FINGERPRINT`, `KEYGUARD_DISABLE_FACE` or `KEYGUARD_DISABLE_IRIS` which affects the managed profile challenge if there is one, **or the parent user otherwise**. Fleet never sets `keyguardDisabledFeatures` itself. Fleet's default Android policy sets only `StatusReportingSettings`, and admin-authored AMAPI policy is passed through as-is. The reason this still lands on Fleet is that the profile in the bug report is byte-for-byte the example Fleet publishes at `docs/solutions/android/configuration-profiles/disable-face-and-biometrics-unlock.json`, with no note about the BYOD side effect. ## What changed - `articles/custom-os-settings.md`: new "Biometric unlock on personally-owned (BYOD) hosts" subsection under "Special Android behavior", covering the behavior and the configuration that scopes the restriction to work. - `docs/solutions/android/configuration-profiles/README.md`: entries for the biometrics profile (carrying the caveat) and for the new example. - `docs/solutions/android/configuration-profiles/require-separate-work-profile-lock.json`: new example using `passwordScope: SCOPE_PROFILE` and `unifiedLockSettings: REQUIRE_SEPARATE_WORK_LOCK`. The remedy needs no Fleet change: `passwordPolicies` is already in the Android policy field mask (`server/mdm/android/service/androidmgmt/policy_field_mask_test.go`), so Fleet already delivers it. ## Testing - [ ] QA'd all new/changed functionality manually Docs-only, so no automated tests were added. Verification done: - Both the new example profile and the combined snippet in the guide decode into the real `androidmanagement.Policy` struct with `DisallowUnknownFields`, confirming every key and nesting level matches the AMAPI schema Fleet ships. - The documented status flow (`USER_ACTION` non-compliance on `passwordPolicies` marks the profile "Failed", then "Verified" once the end user sets the work lock) is confirmed against `server/mdm/android/service/pubsub_test.go`. **Not yet verified on hardware.** I have not run the repro on a physical BYOD Android host. Before merge, this is worth confirming: 1. On a BYOD Android host with fingerprint unlock configured and a work profile enrolled, apply `disable-face-and-biometrics-unlock.json`. Confirm fingerprint disappears as an unlock method device-wide. 2. Add the `passwordPolicies` block from `require-separate-work-profile-lock.json` to that profile and re-upload. Confirm Android prompts for a separate work profile lock, and that Fleet shows the profile "Failed" with `USER_ACTION` on **Host > OS settings** until the end user sets it. 3. After the end user sets the work lock, confirm the profile moves to "Verified", fingerprint unlock works again on the personal side, and the work profile still requires PIN/password. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added an Android configuration profile option that requires a separate lock for the work profile. * Applies password policy settings specifically to the work profile scope. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Solutions
Best Practices
General
- Name the file what the profile does.
- For example, instead of
googlePlayProtectVerifyApps.json(the name of the Android policy for this control), describe what it does:enforce-google-play-protect.json.
- For example, instead of
- Use kebab case in file names, with all letters in lowercase.
- Instead of
passwordPolicy.json, usepassword-policy.json.
- Instead of
- Be sure to end files with an empty newline.
symlinks
If a solution is applicable to multiple platforms, keep the original in the main platform directory and symlink it to the other platforms. For example, if an Apple configuration profile can be used on both macOS and iOS, use macOS as the source, and create a symlink in the iOS directory.
cd docs/solutions/ios-ipados/configuration-profiles/- Note that this is the destination that we want the symlink to be in.
ln -s ../../macos/configuration-profiles/my-profile.mobileconfig .- The
.here at the end means the current directory, and will use the same file name as the original (which is what we want).
- The
git add profile.mobileconfiggit commit