Android Internals: The Android OS Bootup Process
Learn more about what happens when you boot up your Android device.
Join the DZone community and get the full member experience.Join For Free
This post is targeted for software engineers wanting to dive deep into the inner workings of Android's Internals. We'll take a look at what happens when your Android device boots up, but specifically Zygote in Android and what is its role in firing up an application.
We'll see how an activity is fired up in Android using
ActivityManager and who's responsible for initializing that Activity Manager, as well as what happens in the init.rc file, which starts various daemons in Android. And more such interesting questions.
Knowledge of Android Internals is necessary if you want to build a career as an Android Engineer. Internals will make you aware of all the optimizations that can be used in your regular development tasks. You'll be more cautious while allocating objects and creating new activities. Apart from that, it'll also help you in interviews!
Let's get started.
There are some prerequisites for this article. You must be familiar with concepts such as:
How Does Android Boot Up?
Here's the cycle of the bootup process in Android:
This is how it goes: Boot ROM -> Bootloader -> Kernel -> Init -> Dalvik VM -> Zygote -> System Server -> Managers.
Boot ROM contains the initial code that's run as soon as the device wakes up. It is a mask ROM or write-protected flash drive. Embedded in the CPU chip, Boot ROM loads the Bootloader into RAM for execution.
Here are some examples of Bootrom that I found on StackOverflow:
- iPhone boot ROM. Embedded in the mask ROM and can't be modified. Loads the next stage boot loader from flash or USB (in DFU mode) and verifies its signature using built-in RSA implementation. It would also provide accelerated decryption functions for the next stage bootloader.
- TI's OMAP4 boot ROM. Can load user code from flash (NOR, NAND, OneNAND), external memory, SD/MMC, USB or UART. Boot order and options are set by strap (SYSBOOT) pins. Provides some functionality for later stages (cache/TLB management etc.)
- NXP's LPCxxxx series Boot ROM. Placed in a hidden portion of the internal flash which is mapped at 0 on power-on. Implements CRP (code read protection), ISP (In-System Programming) which allows to upload and flash new code over UART. If a valid user code is in flash (needs to have proper checksum), maps it to 0 and jumps to it. A part of bootrom remains mapped to provide IAP (In-Application Programming) and some other services.
Bootloader is a piece of code that runs before any operating system. It is responsible for loading an operating system from the device, setting up a minimal environment in which OS can run, and beginning the startup process. Hence, the bootloader is not specific to Android.
In the context of Android (pun intended!), you might've heard of OEM manufacturers placing certain limitations on the operating system (e.g. limited background processes). This is where those rules are stored.
One of the major tasks of bootloader involves setting up memory management, security options. This is essential for the Kernel. Bootloader contains two important files: init.s and main.c
Init.s is responsible for initializing stacks and BSS segments. It eventually calls main.c, which is responsible for initializing hardware such as a keyboard, system clock, console, etc.
Most importantly, the bootloader verifies the integrity of the boot and recovery partitions before moving execution to the Kernel and displays the warnings specified in the section Boot state.
Once Kernel boots up, it starts to set up the cache, load drivers, mount the file system, start Kernel daemons, etc. Once it finishes the system setup, it looks for the init process in the system files and launches the root/first process.
Without Kernel, your software won't have a chance to communicate with the hardware.
This is a very crucial process. It is where the directories such as /dev, /sys, /proc are mounted. This is also the place where init.rc script is executed.
Init process also starts the daemons, such as bluetooth daemon, adb daemon, etc. These handle low-level hardware interfaces including radio interface.
If you take a look at init.rc script, you'll find that it includes commands such as "start vold" for the file system and "trigger zygote" for starting the Zygote process in Android.
One of the most important things that happens during this init process is a call to start the Zygote. The
app_process command starts the ART or Dalvik VM and also gives a call to Zygote's
Zygote and VM
When the command
app_process launches the Zygote, first, a VM instance is created, and then, a call to Zygote's
main() function happens.
According to the dictionary definition: Zygote is the first cell that's formed during fertilization. Similarly, Zygote is the first Android-specific process when Android OS boots up!
Zygote preloads all the system resources and classes used by the Android framework, thus achieving fast app launches.
The Zygote forks itself to start a "system-server." The system-server starts services such as
ActivityManagerService, hardware services, etc.
It starts listening on a socket interface for future requests to spawn off new virtual machines (VM) for managing new application processes. On receiving a new request, it forks itself to create a new process that gets a pre-initialized VM instance.
This forking is available due to the copy-on-write resource management technique. It doesn't copy anything actually, just points to the pages of the parent process. The actual copying happens when there is a new write to the process' pages.
Forking happens very efficiently. A new Dalvik VM is created, and then, the process gets its own thread and resources to work with. This enables code sharing among VMs, resulting in minimal startup time.
System Server is the first service started by the Zygote. The first thing that the system server does is start the native library called android_servers that provides interfaces to native functionalities.
It starts initializing each system service and registering them with the previously started Service Manager. Each service runs in a separate Dalvik thread in system server.
ActivityManager is responsible for starting the Launcher App and registering click listeners to it. It also manages the activity lifecycle, maintains activity stack, etc.
System Server also starts other services beginning with com.android, such as com.android.phone and com.android.email. It also starts other managers such as Location Manager, Bluetooth Manager, etc.
It is responsible for activity thread process creation, activity stack management, and activity lifecycle management. In the end, it launches an intent to start Home Launcher and registers on click listeners to it. Whenever a click is detected, it launches new apps from icons on the home screen.
The click events are transferred to
AcitivityManagerService via Binder IPC. AMS performs multiple steps:
- Collects info about the target intent of the intent object. It does so using
- Information about the target is saved back into the intent object.
- Now, it's checked if the user can actually access the target using
- Then, AMS checks if the intent needs to be opened as a new task. It checks for flags such as FLAG_ACTIVITY_NEW_TASK, etc.
- If the process doesn't already exist for the target, the AMS has to create a new process for this.
This article will help you host CloudAnchors using Google Cloud Anchors API. Let me know if you'll face any problems and I'll be happy to help :)
*Important*: Join the AndroidVilleSLACK workspace for mobile developers where people share their learnings about everything latest in Tech, especially in Android Development, RxJava, Kotlin, Flutter, and mobile development in general.
Published at DZone with permission of Ayusch Jain. See the original article here.
Opinions expressed by DZone contributors are their own.