Deep Dive Into Android OS Fundamentals
When we look at the basics of Android Apps, we see four basic components. Activities, Services, Broadcast receivers and Content providers. Before moving on to components and Android OS, let’s look at what an android user does.
On our Android phone we are greeted by a list of Apps. Clicking on an application icon opens the application. By clicking on the icons in the Navigation Bar, you can navigate between Back, Home, Recent apps. Now let’s see how these operations work on the technical side.
Android OS is actually a customized version of Linux. Just as different users are created in Linux, each application is actually a user. Each application has its own private areas. These private areas can be accessed with permissions. Each installed application has a UID (User ID) and GID (Group ID)
- UID : Controls the application’s access to files-folders-resources, etc.
- GID : Allows to group a specific set of users together. Users within the group can access shared files within permissions.
Applications need a starting point for the user to open them. Here we need one of our four basic components.
- Activity : They are the basic building blocks of Android applications. They take up all the space they occupy. They are stacked on top of each other
- Services : Background processes. Basically a service is activated when another service is required. Services can be offered to components outside of an application. Thus, some of the basic functions of that application can be made available to other applications.
- Broadcast Receivers : Similar to Interrupt Handlers, triggered when an important event occurs to process it in the application. Inactive when not handling a specific event.
- Content Providers : We use it when we want to access the data of one application from another application. It can retrieve files or other storage components. Mostly relies on SQLite
The basic components that will be used statically in the application should be defined in AndroidManifest.xml Android OS checks the Manifest when launching applications and accordingly opens the necessary applications and understands the needs of the application.
When we turn on our Android phone, we are greeted by an Activity by the System, which contains a list of application icons. We can access any of the apps with our basic components. This can be by clicking on the app icon, notification or other basic components. There are as many entry points to our application as there are components.
When the user clicks on the application icon, the system calls onClick() in the launcher to respond. Activity Manager calls startActivity(). Activity Manager calls startViaZygote() under Android OS. Zygote forks the application to stand up and forwards it to the system.
Activity Manager
It takes care of the basic components. If you get an ANR error while developing an application, it is Activity Manager. It also deals with Activity LifeCycle, OOM and Low Memory.
When the user clicks on an application, it may be in the backstack or it may be launched for the first time. When apps are launched for the first time, they start to manage more system resources.
The hardware has a certain capacity and this process cannot go on forever. At some point the system needs to kill/release old apps or low priority ones for newly launched components/apps. In order to prevent the processes from being detected by the user, android provides components with a LifeCycle. LifeCycle CallBacks are offered by the system.
Android has two structures for memory management, Out Of Memory (OOM) and Low Memory. OOM is actually the same as in Linux. It creates a scoring system between -17 and +15 to clear memory. The higher the score, the more likely it is to be killed by OOM. The score is calculated based on parameters such as CPU time, runtime, memory size, etc. OOM kicks in when memory starts to fill up. Android developers wanted to have more control over memory, so they created the Low Memory structure.
In Low Memory, the system is triggered at certain threshold values. Background processes running in the system are taken and saved. As the thresholds increase, OOM kills non-critical background processes and foreground applications that are saved at the thresholds.
Zygote
It is a specialized structure that launches applications. It centralizes components shared by all applications to unify them and shorten their launch process. It is only active when a new application is to be launched. Prepares resources that the application will potentially need at runtime.
It creates a socket in the system, listens and forks when it receives an application launch request. The advantage of forking is that all the resources the application will need are available, pre-loaded. Fork operations actually use their own copy. Therefore, a single copy of the resources is kept in RAM regardless of the number of applications.
The first application that Zygote launches is System Server, which runs as a separate process.
Jetpack Compose is a different case. Since Jetpack Compose is a separate library, it cannot benefit from Zygote. Instead it uses Profile Installers for builds from 1.0 onwards.
Intent
It allows components/applications to interact. Intent is a passive object. The effects of sending it may vary depending on its content, the mechanism used and the applications installed. If the application itself does not provide the user request, it can provide it by interacting with other applications. For example, in Camera-Gallery operations, operations can be performed by interacting with applications provided by the system.
In the Navigation Bar provided by the system, actually back, home screen, recent apps also call an Intent. For example, the Home button uses Intent.CATEGORY_HOME.
Part II — Deep Dive Into Android Memory
For comments, suggestions or criticisms, you can reach us on LinkedIn or Twitter.