How does ADB root/unroot work?

Every couple of months the question is asked to the OWNERS: “How does adb root/unroot work?”. Every time, we have to dig out the code to remember. Here is a doc to hopefully solve this problem.

shell uid vs root uid

adbd always starts running as user root. One of the first things the daemon does is to check if it should drop its privileges to run as shell user. There are a few read-only properties involved in the decision.

ro.secure
ro.debuggable

On a user debug, these properties will never allow adbd to remain root. However, on eng and userdebug builds they will.

From CLI to restart

If adbd can remain root, it doesn't mean that it should. There is a second level decision dictated by the property service.adb.root. If set to 1, adbd remains root. Otherwise, it drops to shell.

The command adb root and adb unroot triggers adbd to write service.adb.root and restart.

The one catch is that adbd cannot call exit(3) right away since it must make sure the “success” message makes it back to the caller on the host.

The trick is done by tagging any asocket associated with a root/unroot command to call exit(3) when the asocket they run upon is closed (see exit_on_close).

How adb restarts upon root/unroot

If adbd calls exit(3), how does it restart itself? Since it is a critical process, initd notices that it is gone and restarts it.