This post is targeted for Software Engineers wanting to dive deep into Android’s Internals and its workings. We’ll take a look at what happens when your Android Phone boots up but specifically what is Zygote in Android and 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. What happens in the init.rc file which starts various daemons in Android. And more such interesting questions.
A knowledge of Android Internals is necessary if you want to build a career as an Android Engineer. Knowledge of Android 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 to this article. You must be familiar with concepts such as:
Android Internals: How Android Boots 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 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. Also provides 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, 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 (eg: 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 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 setup cache, loads drivers, mounts file system, starts kernel daemons etc. Once it finishes system setup, it looks for init process in the system files and launch the root/first process.
Without Kernel, your software won’t have a chance to communicate with the hardware.
This is a very crucial process to understand Android Internals. 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 interface including radio interface.
If you take a look at init.rc script you’ll find that it includes commands such as “start vold” for file system, “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 give a call to Zygote’s main() method.
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 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! Click To Tweet
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 which gets a pre-initialized VM instance.
This forking is available due to 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.
The forking happens very efficiently. A new Dalvik VM is created, process gets its own thread and resources to work with. This enables code sharing among VMs thus resulting in minimal startup time.
System Server is the first service started by the Zygote. The first thing system server does is starts the native library called android_servers that provides interfaces to native functionalities.
It starts initializing each system service and 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, 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. At 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 home screen.
The click events are transferred to AcitivityManagerService via Binder IPC. AMS performs multiple steps:
- Collect info about the target intent of intent object. It does so using resolveIntent() method.
- Information about target is saved back into the intent object.
- Now, it’s checked if the user can actually access the target using grantUriPermissionLocked() method.
- Then AMS checks if the intent needs to be opened as a new task. It check 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 understand Android Internals in depth, this’ll help you in your Android Interviews. Let me know if you’ll face any problems and I’ll be happy to help 🙂
*Important*: Join the AndroidVille SLACK 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.
Like what you read? Don’t forget to share this post on Facebook, Whatsapp, and LinkedIn.
If you want to stay updated with all the latest articles, subscribe to the weekly newsletter by entering your email address in the form on the top right section of this page.