Understanding Android Application Lifecycle and Process
Tags: android, androiddev, mobile, kotlin
Published: 2024-06-26 07:54:33

Let’s dive into the details of how Android manages processes, components, and the overall lifecycle of an app.

## Introduction
Understanding how Android manages processes, components, and the overall lifecycle of an application is fundamental for any developer creating  apps. This article delves into the core concepts behind process creation, control, and sandboxing within the Android system. It also explores the lifecycles of key components like Activities, Services, and BroadcastReceivers, providing a roadmap for effective component management. 

## Processes in Android

1. **Process Creation**:
   - Every Android application runs in its own Linux process.
   - When an app's code needs to run (e.g., launching an activity), the system creates a process for that app.
   - The process remains running until the system reclaims its memory for other applications.

2. **Process Lifetime Control**:
   - Unlike traditional systems, an app's process lifetime isn't directly controlled by the app itself.
   - The system determines when to start, pause, or terminate a process based on various factors:
     - Active components (e.g., Activity, Service, BroadcastReceiver)
     - Importance to the user
     - Overall system memory availability

3. **Common Pitfall**:
   - Incorrectly managing components (e.g., starting threads from a BroadcastReceiver) can lead to process termination.
   - Solution: Use JobService to ensure active work is recognized by the system.

## Sandboxing in Android Processes

- Android enforces strong process isolation through sandboxing.
- Each app runs in its own sandboxed process, isolated from other apps.
- Linux user-based security ensures file permissions and access control.
- Inter-process communication (IPC) mechanisms allow controlled data exchange.

## Viewing Android Processes with `adb shell ps`

ADB (Android Debug Bridge) is a versatile command-line tool that allows you to interact with an Android device or emulator. One of its essential features is the ability to view running processes.

### Prerequisites
Before we begin, ensure that you have the following:

1. A computer with ADB installed.
2. An Android device connected to your computer via USB.
3. USB debugging enabled on your Android device (you can enable it in the Developer Options).

### Steps to View Processes
Follow these steps to view the processes:

1. Open a terminal or command prompt on your computer.
2. Connect your Android device to your computer via USB.
3. Execute the following command:
```
adb shell ps
```
This will display a list of all processes, including their PIDs, UIDs, and other relevant details.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ycact6vlv5cwaknz3zhn.png)

### Understanding the Output
The output will include information such as:

- **PID (Process ID):** A unique identifier for each running process.
- **UID (User ID):** The user associated with the process.
- **Name:** The name of the process (e.g., app package name).
- **Status:** Whether the process is running, sleeping, or stopped.
- **Memory usage:** Details about memory consumption.

### Additional Tips
- To filter the output for a specific package name (e.g., `com.example.app`), you can use:

```
adb shell ps | grep com.example.app
```
- Some processes may run as system or root users, so their UIDs may differ.

if it's showing grep not found, you can use below command:

```
adb shell pgrep com.dilip.workmangagerexample
```

1. **Application Object**:
   - The `Application` class (or application object) is a specific class within the Android framework.
   - A single instance of this class is created when the application is launched.
   - It remains alive for as long as the application is running.
   - Developers can override the `onCreate()` method in the application class to initialize global resources.

2. **Global Objects**:
   - Global objects are referenced from the application object itself.
   - They remain in memory for the entire lifetime of the application.
   - Use global objects to share state between different components within your app.
   - Avoid using singletons; prefer global objects for better resource management.

# Understanding Component Lifecycles

A well-structured app relies on a clear understanding of component lifecycles. Let's break down the key components and their lifecycle methods:

1. **Activities**:
   - These are the single screens that make up your app's UI.
   - Lifecycle methods (onCreate(), onStart(), onResume(), onPause(), onStop(), onDestroy()) manage how an activity behaves at different stages:
     - Creation
     - Visibility changes
     - Pausing due to another activity coming to the foreground
     - Destruction

2. **Services**:
   - Designed for long-running operations or tasks that run in the background.
   - Lifecycle methods (onCreate(), onStartCommand(), onDestroy()) govern their behavior.
   - Different service types (bound, background, and foreground) address particular use cases.

3. **BroadcastReceivers**:
   - These components respond to system-wide events or broadcasts.
   - Simple lifecycle (onReceive()) executes only when a relevant broadcast is received.

## Strategies for Process Optimization and Efficient App Management

Now that we understand the core concepts, let's explore strategies to optimize processes and create efficient apps:

1. **Choose the Right Component for the Job**:
   - Utilize lightweight components like BroadcastReceivers for short tasks.
   - Use Services with appropriate start modes (foreground for critical tasks with user notification) for long-running operations.

2. **Asynchronous Operations**:
   - Long-running tasks that block the UI thread can lead to a sluggish app.
   - Techniques like AsyncTask or WorkManager help execute these tasks asynchronously, keeping your UI responsive.

3. **Handling Configuration Changes**:
   - Android can handles configuration changes like (e.g., screen orientation, language settings).
   - onSaveInstanceState() and onRestoreInstanceState() methods allow activities to save and restore their state during such changes.
   - ViewModel simplifies UI data management across configuration changes.

4. **Background Execution with Control**:
   - Carefully manage background tasks.
   - Explore alternatives like JobScheduler or WorkManager for background operations.
   - These offer more control and flexibility over execution timing compared to traditional Services.

5. **Leverage Profiling Tools**:
   - Android Studio's Profiler helps monitor app performance and identify potential memory leaks.
   - Pinpoint resource bottlenecks to optimize your app's process usage and ensure a smooth user experience.

## The Out-of-Memory Killer (OOM Killer)

- To manage limited system resources, the Android system can terminate running applications.
- Each application is started in a new process with a unique ID under a unique user.
- The system follows a priority system to determine which processes to terminate:

If the Android system needs to terminate processes, it follows the following priority system:

| Process Status | Description | Priority |
| --- | --- | --- |
| Foreground | An application in which the user is interacting with an activity, or which has a service bound to such an activity. Also, if a service is executing one of its lifecycle methods or a broadcast receiver runs its `onReceive()` method. | 1 |
| Visible | User is not interacting with the activity, but the activity is still (partially) visible, or the application has a service used by an inactive but visible activity. | 2 |
| Service | Application with a running service that does not qualify for 1 or 2. | 3 |
| Background | Application with only stopped activities and without a service or executing receiver. Android keeps them in a least recently used (LRU) list and terminates the one that was least used when necessary. | 4 |
| Empty | Application without any active components. | 5 |

- The system maintains a least recently used (LRU) list of processes.
- The out-of-memory killer (OOM killer) terminates processes from the beginning of the LRU list.
- If an app is restarted by the user, it moves to the end of the queue.

## Conclusion
Android applications run in their own Linux processes, with the system controlling their lifetime based on factors like active components, user importance, and memory availability. Sandboxing ensures app isolation and security. Activities, services, and broadcast receivers are the key components with their own lifecycles that need to be managed effectively. To optimize processes and create efficient apps, developers should choose the right component for the job, leverage asynchronous operations, handle configuration changes gracefully, manage background execution with control, and utilize profiling tools to identify potential issues. Finally, we discussed the Out-of-Memory (OOM) Killer, the system's mechanism for terminating processes when resources are limited, and the priority hierarchy it follows when making these decisions. By effectively managing processes and components, developers can create Android applications that are both user-friendly and resource-conscious. This article provides a solid foundation for understanding the intricacies of the Android system, allowing developers to optimize their apps for performance and efficiency.