The Journey Of Launching An Android Activity

Muhammad Youssef
5 min readJan 6, 2019

What happens inside Android, stays inside Android.

You are an Android developer; You know very well how to launch an Android activity and by the time you are reading this you probably did it zillion times. But have you ever wondered why do we do it this way? Why do we use intents to create an activity object? What makes an Activity object so unique and different from any other java object? After all, it’s a java object right? Then where, when and how the “new Activity()” statement actually gets executed?! What happens before an activity gets created? In this article we take a glance at the behind-the-scenes of launching Android activities. I assume that you’re already familiar with Java programming language, OOP principles and Android development fundamentals.

Let’s start by creating a project with an activity and override the default constructor. The simplest way to check the path to a constructor is by placing a breakpoint to it. It will enable us to walk through all the calls and explore the implemented code to find exactly what we want. Executing the project will result into the following:

Android studio debugger

In any Unix-based operating system, the first thing the kernel does is to execute init process. Init is the root/parent of all processes executing on Linux.

As we can see at the very bottom of the debugger frames, Android internally calls something called ZygoteInit.
Wait what?!
Yes, as the name implies, it’s the very beginning for the rest of the Android application. It gets its name from dictionary definition: “It is the initial cell formed when a new organism is produced”.

Android at its core has this process called Zygote, which starts up at init. It’s a special Android OS process that enables shared code across Dalvik/Art VM. This process is a “Warmed-up” process, which means it starts by preloading all classes and resources which an app may potentially need at runtime into the system’s memory. It then forks itself to start a well managed process called SystemServer which starts initializing all core platform services it houses. One of the core services that gets started by SystemServer that we are particularly interested in is ActivityManagerService.

ActivityManagerService

This service is where all the magic happens. It is responsible for a new Activity thread process creation, maintenance of the Activity lifecycle and managing the Activity stack. At it’s startup, it performs three main steps:

1- Collect Target Activity Information

Full implementation: ActivityManagerService: resolveActivityInfo()

The first step is to collect information about the target activity. This is done by calling resolveIntent() method on some hidden implementation for IPackageManager interface. After that the target information is saved back into the intent object to avoid re-doing this step.

2- Check User Privileges

Full implementation: ActivityManagerService: grantUriPermissionLocked()

Next important step is to check if user has enough privileges to invoke the target activity. This is typically done by calling grantUriPermissionLocked() and it does the following:

  1. Make sure the target package has a valid UID associated with it
  2. Use the UID to check if the target package can grant permission to access uri by calling checkGrantUriPermissionLocked()
  3. After making sure that the caller has all the permissions grantUriPermissionUncheckedLocked() grants them to the target package as well

3- Activity object Instantiation

Now to the juicy stuff, it’s time to check if the ProcessRecord already exists for the process. If the ProcessRecord is null, the ActivityManagerService has to create a new process to instantiate the activity (duh). The instantiation is done by the help of ActivityThread class

At this point, all required permissions have been granted, all the information about the target activity have been stored in the intent object, and the system has made sure that the user has all the privileges to invoke the target activity. Now it’s time to instantiate and launch the target Activity. This phase can be divided into three sub-phases

3.1- Get The Environment Ready

Full implementation: ActivityThread: handleLaunchActivity()

First things first, let’s get the environment ready. It does so by calling handleLaunchActivity(). This makes sure the configurations are up to date, the graphics environment is initialized and then initializes the WindowManager.

3.2- Retrieve The Previously Collected Information

Full implementation: ActivityThread: performLaunchActivity()

Now let’s retrieve the previously collected information such as ComponentName and create the baseContext to get prepared for the instantiation.

3.3- The Instantiation

Full implementation: AppComponentFactory: instantiateActivity()

This is where it gets interesting. Android uses the help of java reflection library to execute the new Activity() statement. It does so by calling newActivity() method on the Instrumentation object which then delegates the action to theAppComponentFactory object by calling instantiateActivity() method.

After instantiation,ActivityThread proceeds by callingcallActivityOnCreate(). And this is the start of what we all know as “ActivityLifeCycle” 😄

Thanks for reading through 🙌🏼. If you found this post useful, please share it through your circles.

📝 Read this story later in Journal.

🗞 Wake up every Sunday morning to the week’s most noteworthy Tech stories, opinions, and news waiting in your inbox: Get the noteworthy newsletter >

--

--

Muhammad Youssef

I studied computer science for four years just to google stuff and I persuade Android into doing things for a living