Root is an identity or capability in a particular layer, not a universal key. This lab uses only a disposable virtual Android target and read-only observations, except for the reversible adb root / adb unroot request on an eligible debug image. Do not run root, unlock, flash, erase, or relock steps on a personal phone.
Before you start#
Required earlier lessons: ADB & your first safe lab, Android’s security model, and Verified Boot & encryption. If the words UID, SELinux, userdebug, or bootloader state are unfamiliar, review those first. You need a disposable Android Emulator or Cuttlefish instance and Android Platform-Tools for the live option; the supplied source-only alternative below needs no device.
Choose one target deliberately. If you have more than one ADB target, copy its serial from adb devices -l; every command below uses -s SERIAL so an accidental phone selection is less likely. Never treat a serial as proof that the target is disposable.
Learning goals#
By the end, you can distinguish host root from target UID 0, explain why UID 0 does not erase SELinux or framework checks, record an observation with its limits, and name a safe rollback for a virtual-device experiment.
Practice#
Virtual-device path
- Confirm disposable target
Record serial, build type/fingerprint, initial id and SELinux observations.
- Eligible debug-image root request
adb root may restart target adbd; inspect the actual result instead of assuming success.
- Recheck identity and policy observations
A changed target UID does not establish unchanged or production-equivalent policy.
- Restore and verify
adb unroot after a successful request; recheck id. If state is unclear, recreate the disposable target via its documented UI.
Start a fresh emulator or snapshot you can discard. First inspect target identity and build type:
adb devices -l
adb -s SERIAL shell id
adb -s SERIAL shell getenforce
adb -s SERIAL shell getprop ro.build.type
Record the serial, build type, UID, SELinux mode, and whether you selected the intended virtual target. A common starting observation is uid=2000(shell) with SELinux Enforcing; exact output varies. The shell domain’s SELinux rules are kept in Android 14 shell.te, separate from the Unix UID; AID_SHELL is 2000 in android_filesystem_config.h. The observation still must come from the selected target. If the target is not unmistakably your disposable instance, stop.
On an eligible userdebug or eng virtual image only, request root and check what changed:
adb -s SERIAL root
adb -s SERIAL shell id
adb -s SERIAL shell getenforce
The expected successful observation is target uid=0(root) while SELinux may remain Enforcing. AOSP Android 14’s adbd implementation gates root on the debuggable build property (should_drop_privileges()); production user images commonly keep adbd unprivileged, so the root request is refused (the exact message varies). That is a valid result; do not try to bypass it. Restore ordinary adbd mode after the successful debug-image observation:
adb -s SERIAL unroot
adb -s SERIAL shell id
If the target is still running but a command fails, stop issuing commands and inspect the target selection. Restore the named emulator snapshot or close and recreate that virtual device using its documented UI. A factory-data reset normally resets user data only; it does not necessarily restore a modified system image. If you cannot verify which state was changed, do not improvise recovery—recreate the disposable virtual target. Do not substitute a physical device.
Source-only alternative
No emulator? Inspect the Android 14 system/sepolicy/private/shell.te file and the AOSP packages/modules/adb/daemon/main.cpp implementation linked in Sources. Write down what the source establishes about the shell domain and debug-build root request, and what it cannot establish about an arbitrary vendor device’s runtime policy. This is a legitimate source-reading artifact, not a claimed runtime test.
Evidence artifact
Complete a short record:
| Field | Your observation |
|---|---|
| Target type / source revision | |
| Command or source symbol | |
| Observed result | |
| What it establishes | |
| What it does not establish | |
| Safe restoration performed / not applicable |
Do not include personal data, account names, or device identifiers in a shared report.
Knowledge check#
adb rootsucceeds,idreports UID 0, andgetenforcereportsEnforcing. What changed and what did not?- A
userimage refusesadb root. Is that evidence that the lab failed? - Why does
sudo adb shell idnot prove that Android runs the shell as root? - A factory-data reset is offered after a system-image change. Why might that not restore the experiment?
Answers#
- The target-side adbd/shell identity changed to UID 0; SELinux enforcement remains a separate policy control. UID 0 still does not prove all operations are permitted.
- No. Production images commonly disallow root adbd; record the refusal and stop. Do not weaken or modify a production target.
sudochanges host-side privileges. The target process identity must be checked on the target; host elevation alone does not change it.- A factory reset normally wipes user data, not a modified system image or boot state. Restore a known virtual-device snapshot or recreate the disposable instance instead.
Checkpoint#
Pass when your artifact correctly distinguishes host and target identity, records the SELinux result separately, states one evidence limitation, and either records the successful virtual rollback or marks source-only work as not applicable. Revise if you infer that root means SELinux is disabled or that a reset restores every partition. Not yet evidenced is appropriate when you have only read the source and have no runtime observation; do not relabel it as a device test.
For a root/SELinux misunderstanding, revisit Android’s security model. For boot trust or data-wipe questions, revisit Verified Boot & encryption. For target selection, repeat ADB & your first safe lab before any virtual-device command.
Sources#
- AOSP
shell.te, Android 14.0.0_r1 — shell domain policy. - AOSP
android_filesystem_config.h, Android 14.0.0_r1 —AID_SHELL2000 (checked by grep in this review). - AOSP adbd
main.cpp, Android 14.0.0_r1 — debug root decision and privilege handling; source does not guarantee an OEM build behaves identically. - Cuttlefish getting started — disposable virtual-device guidance.
- Verified Boot and A/B updates — boot trust and update state.