POSIX Threads (pthreads)
Android's native layer (C/C++) utilizes POSIX threads (pthreads) as its fundamental threading API. A thread is an independent sequence of execution within a process. While processes have isolated memory spaces, multiple threads within the same process share the same global memory, heap, and file descriptors. This makes thread creation lighter and inter-thread communication faster than Inter-Process Communication (IPC), but introduces significant concurrency challenges.
The Thread Execution Model
When a process starts, it begins with a single thread, often called the "main thread". In Android apps, this is the UI thread. The main thread can spawn additional worker threads to handle background tasks without blocking the UI.
Thread Creation and Join
The core functions for managing threads in the pthread API are pthread_create and pthread_join.
pthread_create
This function spawns a new thread.
#include <pthread.h>
void* thread_function(void* arg) {
int thread_id = *(int*)arg;
// Perform background work...
return NULL;
}
int main() {
pthread_t my_thread;
int id = 1;
// 1. pointer to thread handle, 2. attributes (NULL for default),
// 3. start routine, 4. argument to pass
int result = pthread_create(&my_thread, NULL, thread_function, &id);
if (result != 0) {
// Handle error
}
// ...
}
pthread_join
If the main thread needs to wait for a worker thread to finish its task and retrieve its result, it uses pthread_join. This blocks the calling thread until the specified thread terminates.
void* thread_result;
pthread_join(my_thread, &thread_result);
// my_thread has now finished.
If a thread is "detached" (pthread_detach), its resources are automatically released upon termination, and it cannot be joined.
Thread-Local Storage (TLS)
Because threads share the same global memory, using global variables can lead to race conditions. Thread-Local Storage (TLS) provides a mechanism to allocate variables that are global in scope but have a unique instance for each thread.
In C++, this is elegantly handled using the thread_local keyword.
// Each thread gets its own independent copy of 'request_counter'
thread_local int request_counter = 0;
void process_request() {
request_counter++; // Safe, no mutex required
}
TLS is crucial in Android for storing context specific to a thread, such as JNI environments (JNIEnv*) or thread-specific event loop configurations (like Android's Looper).
Android Thread Naming and Debugging
A process in AOSP can easily have over 50 threads running simultaneously (Binder threads, GC threads, RenderThreads, etc.). When a crash occurs or when profiling performance, identifying these threads by their numeric ID is impossible.
Android strongly encourages naming threads for debuggability.
Setting Thread Names
In native C/C++, thread names are typically set using pthread_setname_np (non-portable extension).
#include <pthread.h>
void* my_worker(void* arg) {
pthread_setname_np(pthread_self(), "AudioDecoderThread");
// ...
return NULL;
}
In Java/Kotlin, you pass the name to the Thread constructor:
Thread t = new Thread(myRunnable, "NetworkDispatcher");
t.start();
Viewing Thread Names
Thread names are truncated to 15 characters. They are visible in crash logs (tombstones), ANR traces (traces.txt), and system tracing tools like Systrace or Perfetto, making it drastically easier to pinpoint which specific subsystem is causing a deadlock or performance bottleneck.