Understanding the magic of APK installation process in Android πŸͺ„

Understanding the magic of APK installation process in Android πŸͺ„

Learn about the android package installation process, install location, components involved, and how they are managed.

Β·

8 min read

Introduction

Hello folks πŸ‘‹, We install applications daily from various sources. Do you know how android handles the installation process? πŸ€” No? Don't worry, That's what we are gonna discuss in this article. So grab a cup of tea β˜• with you and jump straight into the article.

What will you get out of this article?

This article covers how android handles the application installation process.

  1. What are the different ways we can install applications?
  2. How does android handle the installation process?
  3. How the default application PackageInstaller performs its magic?
  4. How the flow goes from one activity to another?
  5. What are the various components involved in this process?

Diffrent ways to install APK 🌿

There are a few ways to install Android applications:

  • Using an app store client (i.e. Google Play Store). This is how most of the users install applications.

  • Downloading the APK file to the device and then opening it. This can only be installed if the "Unknown sources" option is enabled in the setting. We will consider this method throughout this blog.

  • Using the adb install command of Android SDK, which at the end invokes the pm install command which goes to cmd package install.

  • By directly copying an APK file to one of the system application directories. When an APK file is copied directly to one of the application directories, it automatically gets detected and installed.

The almighty Android OS πŸ’ͺ🏼

Recently, Android has become the world’s most popular mobile platform. Originally it was designed for smartphones but now powers tablets, TVs, and wearable devices and will soon even be found in cars.

Android is built on top of the Linux kernel. In the android system architecture, Applications lies at the highest level. In Android, each app gets its own directory for saving data. Android assigns each application a UID (userID) at the installation time. It is a constant value that does not change until the app is reinstalled. It is different from the PID (processID), which keeps changing.

Android uses the UID to set up a kernel-level Application Sandbox. The kernel enforces security between apps and the system at the process level through standard Linux facilities, such as user and group IDs assigned to apps. By default, apps can’t interact with each other and have limited access to the OS.

There are mainly two categories of Android applications.

1. System Apps

Included in the OS image, it is a read-only application that cannot be uninstalled or changed by a normal user. System applications can be found in /system/app/ directory, while some privileged applications are present in /system/priv-app/ directory. The /system/vendor/app/ directory hosts vendor-specific applications.

system apps.png

2. User Apps

User-installed apps are installed on a dedicated read-write partition (typically mounted as /data) that hosts user data and can be uninstalled or changed. User-installed applications can be found in /data/app/.

user apps.png

Data directory

Both system and the user-installed application create a data directory at the /data/data/ directory. The user data partition also hosts the optimized DEX files for user-installed applications in /data/dalvik-cache/.

package permission.png

Here, the first column indicates permission for the application data folder. The third and fourth column indicate owner and group, respectively. last is the application package name directory, where the data is stored.

Installation process flow πŸ‚

Install Process Flow.drawio.png

PackageInstaller and PackageManager

PackageInstaller is the default application for installing any application on your android device. It provides an interactive interface to install a normal package.

PackageManager is a class for retrieving various information related to the application packages currently installed on the device. It is abstract class and concrete implementation is provided by ApplicationPackageManager which is created in ContextImpl#getPackageManager().

Initial Activity

Any application installed using its APK file is considered an "unknown source". The actual definition of unknown source is a bit broader; when started, PackageInstaller retrieves the UID and the app package that requested APK installation. It checks if requesting app is privileged (present in /system/priv-app/, i.e. GooglePackageInstaller), if not, then it is considered an unknown source.

Initial Activity.png

The package that is to be installed can be in the form of a content URI, or it can be a file URI. The first activity that takes place is the InstallStart activity which decides which activity is the first visible activity of the installation and forwards the intent to it.

If a package gets installed from a content URI (e.g. "content://com.android.externalstorage.docum.."), then the InstallStaging activity is started. It loads the package and turns it into an installation from a file. It creates StagingAsyncTask and gets a package file (e.g. "file:///data/user_de/0/com.google.android.packageinstaller/no_backup/package318526161049147654.apk") from the content URI. The output of this task could result in success or failure.

emulator.png

If any error occurs in this process, the error result is set, and showError() is called. If the file is staged, then it starts DeleteStagedFileOnResult, which at the end calls PackageInstallerActivity and deletes the staged install file.

PackageInstallerActivity

Installing a package from an APK file is also referred to as a side-loading app. PackageInstallerActivity is launched when an application is installed via sideloading.

one.png

In PackageInstallerActivity, the package is first parsed, and the user is notified of parse errors via a dialog. If the package is successfully parsed, the user is notified to turn on the "Unknown sources" option in the setting. If the package already exists on the device, a confirmation dialog (to replace the existing package) is presented to the user. All state transitions are handled in this activity.

Activity parses the package and checks for any error. If the package is parsed properly, then it sets up the installer for this package.

PackageInstaller calls startInstall() which starts subactivity InstallInstalling to actually install the application.

InstallInstalling activity

one.png

InstallInstalling activity sends the package to the package manager and handles the results from the package manager. This has two phases: First, send the data to the package manager, then wait until the package manager processes the result.

This activity checks for the package if there is already an application with the given package name installed on the system for other users, then it calls PackageManager#installExistingPackage() and installs it for the calling user.

Actual installation is here πŸ‘‡πŸ»

one.png

InstallInstalling activity creates PackageInstaller.SessionParams and set some important attributes:

  • MODE_FULL_INSTALL
  • Package Source
  • Package Name
  • Size of the Package
  • Installation location
  • all other important attributes can be found in the Documentation.

This information session is created by createSession(params).

InstallInstalling activity creates InstallingAsyncTask, AsyncTask that sends the package to the installer. It opens PackageInstaller.Session, which is retrieved by openSession() and opens OutputStream using openWrite(String name, long offsetBytes, long lengthBytes) which opens a stream to write an APK file into the session. Progress of installation is set using setStagingProgress(float) and addProgress(float). At the end, commit everything staged in this session.

Result Activity πŸ“²

result.png

In InstallInstalling activity an broadcast receiver InstallEventReceiver is registred with observer launchFinishBasedOnResult method. When the installation process is finished, InstallEventReceiver notifies the observer.

launchFinishBasedOnResult launches the appropriate finish activity based on the result.

  • InstallSuccess by calling launchSuccess() if the process is completed successfully.
  • InstallFailed by calling launchFailure() with the appropriate statusCode, legacyStatus and statusMessage for the failed result.

Install finish.png

Updating information in the system database πŸ—„οΈ

Android OS has two profiles for saving app information in the Android system. packages.list and packages.xml. Both files can be located in the /data/system/ directory.

packages.list

com.google.android.carriersetup 10073 0 /data/user/0/com.google.android.carriersetup default:privapp:targetSdkVersion=28 3003
com.android.wallpaperbackup 1000 0 /data/user/0/com.android.wallpaperbackup platform:privapp:targetSdkVersion=28 1065,3002,1023,3003,3001
com.innersloth.spacemafia 10090 0 /data/user/0/com.innersloth.spacemafia default:targetSdkVersion=30 3003
...
com.kruna1pate1.pictionaryapp 10089 1 /data/user/0/com.kruna1pate1.pictionaryapp default:targetSdkVersion=32 3003

Here, the space is divided into 6 columns, which contain 6 app-related information:

  1. Name of the application package
  2. UID of the application. (by looking at them, one can easily map that u0_a89 => 10089)
  3. Whether the app is in debug mode, specified by android:debuggable in AndroidManifext.xml.
  4. Datastore path of the application. (usually /data/data/<package>)
  5. SEinfo information of the app, includes targetSdkVersion.
  6. User group to which the app belongs.

packages.xml

A huge file has 5500+ lines. Here is an abstract view of its content.

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<packages>
    <version ... />

    <permission-trees>
        <item name="xyz" package="xyz" />
        ...
    </permission-trees>

    <permissions>
        ...
    </permissions>

    <package ...>
        <sigs count="1" schemeVersion="3">
            <cert ... />
        </sigs>

        <perms>
            <item name="xyz" granted="true" flags="0" />
            ...
        </perms>

        <proper-signing-keyset identifier="6" />
    </package>

    <updated-package ... >
        <perms>
            ...
        </perms>
    </updated-package>

    <shared-user ... >
        <sigs count="1" schemeVersion="3">
            <cert index="4" />
        </sigs>

        <perms>
            ...
        </perms>
    </shared-user>

    <keyset-settings version="1">
        <keys>
            <public-key ... />
            ...
        </keys>

        <keysets>
            <keyset identifier="1">
                <key-id identifier="1" />
            </keyset>
        </keysets>

        <lastIssuedKeyId value="17" />
        <lastIssuedKeySetId value="17" />

    </keyset-settings>
</packages>

Key elements of this file:

  • Permission block: List of the permissions defined in the system.
  • Package block: Details of the installed application.
  • Updated-package block: Information associated with updated packages.
  • Shared-user block: Information of system-defined share user.
  • Keyset-settings block: contains the public key information of the installed app signature.

Notify other components πŸ””

Finally, changes to the package database (new package entry and any new permissions) are persisted on the disk. PackageManagerService sends the ACTION_PACKAGE_ADDED or ACTION_PACKAGE_REPLACED in case of an update to notify other components about the newly added application.

Conclusion πŸ€ΉπŸ»β€β™‚οΈ

To conclude this article, Here, we have seen there are various ways one can install an application. The package is first parsed by PackageInstaller and then the session is created. An app is delivered for installation through a PackageInstaller.Session. Once the session is created, the installer can stream APK into place until it decides to either commit or destroy the session. We have also seen various components involved in this process and the flow of the process.

Once the application is installed system packages.list and packages.xml file is updated.

I hope you have got something out of it. Feel free to give your reaction and leave a comment down below πŸ“. Any feedback would be greatly appreciated πŸ™‚.

Refrences πŸ“š

Android Security Internals: An In-Depth Guide to Android's Security Architecture

Application Sandbox

Dzone - depth android package manager

Android development system packages file parsing

PackageManager and PackageInstaller

Β