The four components
An Android app has no main(). It has four kinds of entry point that the system can start on its own — and that fact explains most of the platform's design.
Most programs begin at a known place. A C program starts at main, a web server at a listen call, a
script at its first line. An Android app never begins at all — it is entered, from the outside, at
a point the operating system chooses.
TL;DR#
- An Android app has no user-written entry point. The framework's
ActivityThreadcallsmain()in a forked process, and from then on the system invokes your code through components. - There are four component types: (a screen), (work with no UI), (a short reaction to a message), and (data behind a URI).
- Every component is declared in the manifest, and the system — not your code — decides when to create it, which process it runs in, and whether another app may reach it.
- A component's lifetime is not the process's lifetime. The system can create a component in a running process, or kill the whole process once no component matters.
- Components are the boundary between apps. An
Intentnames an action; the system finds a component that can perform it, possibly in an app you have never met.
Mental model#
Think of a large office building with four kinds of room.
A meeting room has a door, a table and a schedule. Someone books it, people come in, and when the meeting ends the room is empty again but the building stays. That is an Activity.
A back office has no visitor entrance. Work arrives through an internal hatch, gets done, and the room stays open as long as there is work. That is a Service.
A mail slot in the lobby accepts one envelope at a time, drops it on a desk, and is done. Nobody waits at the slot. That is a BroadcastReceiver.
A records counter has a clerk behind glass who will fetch a document by its reference number, check your badge, and hand it over. That is a ContentProvider.
Where the analogy breaks#
The building has a landlord who can demolish any room at any moment — and the room's occupant is not consulted. Android's system can destroy your Activity while it is in the background, kill your process to reclaim memory, and later rebuild the screen from a saved bundle. The office analogy suggests stable rooms; Android offers restartable ones. That single difference is why so much of this module is about lifecycle and saved state rather than about drawing screens.
The big picture#
Text description of this diagram
A sequence diagram of starting an activity. Your app calls startActivity, which crosses Binder into ActivityTaskManagerService inside system_server. ActivityTaskManager asks PackageManagerService to resolve the intent against installed intent filters, and gets back a ResolveInfo. It checks that the target component is exported, that the caller holds any declared permission, and it pauses the current activity. If the target app has no live process, ActivityManager asks Zygote to fork one; the child inherits preloaded classes copy-on-write and drops to the app's UID. The new process calls bindApplication, creating the Application object, and only then does ActivityThread instantiate the Activity and run onCreate, onStart and onResume.
Read that diagram once and note how much happens before your onCreate. The activity is the last
thing created, not the first. Everything above it — resolution, permission checks, process creation,
application setup — happens because the system, not your code, is driving.
Deep dive#
An app is a set of entry points, not a program#
The manifest is the app's real interface description. It declares the package, the components, the permissions the app wants and the permissions it offers, and the minimum and target SDK levels.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.notes">
<application android:label="Notes" android:theme="@style/Theme.Notes">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".SyncService"
android:exported="false" />
<receiver
android:name=".BootReceiver"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<provider
android:name=".NotesProvider"
android:authorities="com.example.notes.provider"
android:exported="false" />
</application>
</manifest>That file is not configuration in the usual sense. It is a published contract: the launcher reads
it to know what icon to show, the package manager reads it to answer "who can open this?", and the
system reads it to decide which process to start. Since Android 12 (API 31) every component with an
intent filter must state android:exported explicitly, because the old default silently changed
between releases.1 API 31Android 12
Activity: a screen with a lifecycle#
An Activity owns a window and a state machine. It is the only component users see, and the only one whose destruction is routine rather than exceptional: rotate the phone and the activity is destroyed and recreated.2
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
NotesTheme {
NotesApp()
}
}
}
}Modern apps increasingly use a single activity and put screens inside it, because Compose destinations do not need a window each. The activity is still there; it is just no longer the unit of navigation.
Service: work without a window#
A Service is a component the system can start, bind to, or stop, and which keeps running when no UI
is visible. It is emphatically not a thread. onStartCommand and onBind run on the main
thread unless you move them. Confusing a service with concurrency is one of the classic Android
mistakes: a service that blocks its main thread produces an ANR just like any other
component.3
Since Android 8.0 the platform has tightened when a background service may keep running, which is
why most real work now happens in WorkManager or in a foreground service with a visible
notification.4
BroadcastReceiver: one callback, then gone#
A receiver exists for the duration of a single onReceive call. The system may create the process
for it, deliver the intent, and let the process die again. The callback has a deadline — roughly ten
seconds for a foreground broadcast, sixty for a background one — and exceeding it is an
ANR.5
class BootReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action != Intent.ACTION_BOOT_COMPLETED) return
// Enqueue work; do not do it here.
WorkManager.getInstance(context).enqueue(SyncWorker.request())
}
}The pattern in that snippet is the whole lesson of broadcast receivers: hand off, do not work. Since Android 8.0 most implicit broadcasts cannot be declared in the manifest at all, precisely because waking every app for every system event did not scale.5
ContentProvider: data behind a URI#
A ContentProvider exposes structured data — rows, files, streams — through a URI interface, with
permissions enforced by the framework rather than by your code. ContentResolver is the client
side; you almost never talk to a provider object directly.6
val resolver = context.contentResolver
resolver.query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
arrayOf(MediaStore.Images.Media._ID, MediaStore.Images.Media.DISPLAY_NAME),
null, null, null,
)?.use { cursor ->
val nameCol = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME)
while (cursor.moveToNext()) {
println(cursor.getString(nameCol))
}
}Providers have one more property that surprises people: the provider object is created before the
Application object, because other components in the process may need data during application startup.
That ordering is deliberate and is why provider onCreate must be fast.6
What "component" buys you#
The four types are not an arbitrary list. Each one answers a different question the system needs to ask:
| Component | The system's question | Lifetime |
|---|---|---|
| Activity | "What is the user looking at?" | Until it is finished or the system reclaims it |
| Service | "What should keep running without a screen?" | Until stopped, or the process is killed |
| BroadcastReceiver | "Who should hear about this event?" | One onReceive call |
| ContentProvider | "Who can read or write this data?" | As long as the process lives |
Because the system asks these questions, it can make decisions no app could make alone: start your app in the background to deliver a message, keep a music player alive while the screen is off, or refuse to let a stranger read your database.
Export, permission, and the trust boundary#
A component is a door. By default, whether that door is open to other apps depends on the component
type: activities and services with intent filters are reachable, providers are not. android:exported
makes the choice explicit, and an android:permission on the component turns the door into one with
a lock.
<activity
android:name=".ShareTargetActivity"
android:exported="true"
android:permission="com.example.notes.permission.SHARE" />The check happens in system_server, not in your process. Your code never gets to decide whether the
caller was allowed, which is the point: a compromised app cannot talk its way past a check it does
not run.
How it evolved#
The four component types have existed since Android 1.0. What changed is how tightly the platform controls when they may run.
| API | Version | What changed |
|---|---|---|
| 1 | 1.0 |
|
| 17 | 4.2 Jelly Bean |
|
| 19 | 4.4 KitKat |
|
| 21 | 5.0 Lollipop |
|
| 26 | 8.0 Oreo |
|
| 28 | 9 Pie |
|
| 29 | 10 |
|
| 30 | 11 |
|
| 31 | 12 |
|
| 34 | 14 Upside Down Cake |
|
| 35 | 15 Vanilla Ice Cream |
|
| 36 | 16 Baklava |
|
Three eras are visible in that table. In the first, any component could start anything and background
work was unlimited. In the second, starting with Android 8.0, background services and implicit
broadcasts were restricted. In the third, starting with Android 12, even starting an activity from
the background requires an exemption. Each restriction pushed work toward WorkManager, foreground
services and notification-driven flows — components that the user can see.
Under the hood#
The four declarations map onto four framework base classes, and each has a server-side counterpart that decides when to instantiate it.
- Activity.javathe client-side base class; lifecycle callbacks are invoked by ActivityThread
- ActivityThread.javathe real main() of an app process, and the dispatcher for every component callback
- Intent.javathe message type that names a component or an action
- ActivityTaskManagerService.javathe system_server side that starts activities and owns tasks
- ContentProvider.javathe provider base class, with its URI and permission contract
Curiosity corner#
- The launcher is just an app with a category.
CATEGORY_LAUNCHERon aMAINactivity is what puts an icon on the home screen. Replace the launcher and the icons change with it. - A component can live in another process.
android:process=":sync"in the manifest puts a component in its own process, with its own memory and its own main thread. - ContentProvider is older than the concept of an app store. It shipped in Android 1.0 as the way system apps shared contacts and call logs.
Try it#
adb shell dumpsys package com.example.notes | grep -A 40 "Resolver Table"
Example output
Activity Resolver Table:
Non-Data Actions:
android.intent.action.MAIN:
.../.MainActivity filter ...
Service Resolver Table:
...
Receiver Resolver Table:
...
Provider Resolver Table:
...adb shell am start -n com.example.notes/.MainActivity
Check yourself#
Check yourself
You call `startActivity()` for an activity in another app. Which check does the system perform before delivering the intent?
Sources#
Sources
Every version number, API level, class name and date on this page is traced to one of these. Pages are re-verified against them; last_verified above says when.
- docsApp manifest overviewdeveloper.android.comaccessed 2026-10-27↩
- docs活動簡介 | App architecturedeveloper.android.comaccessed 2026-10-27↩
- docsServices overview | Background workdeveloper.android.comaccessed 2026-10-27↩
- docsProcesses and threads overview | App qualitydeveloper.android.comaccessed 2026-10-27↩
- docsBroadcasts overview | Background workdeveloper.android.comaccessed 2026-10-27↩
- docsContent provider | App data and filesdeveloper.android.comaccessed 2026-10-27↩
- docsComponentsdeveloper.android.comaccessed 2026-10-27↩
- docsIntents and intent filters | App architecturedeveloper.android.comaccessed 2026-10-27↩