AOSP Framework & Internals
3 min read

Death Recipients

Learn about Death Recipients.

In a distributed system, components crash. In Android, processes die frequently—either due to a crash (NullPointerException, native segfault) or because the Low Memory Killer (LMK) terminated them to free up RAM.

When Process A holds a Binder proxy to an object in Process B, and Process B dies, the proxy becomes a stale pointer. If Process A tries to use it, it will encounter a DeadObjectException. To allow systems to gracefully handle these failures, Binder provides the "Death Recipient" mechanism.

linkToDeath() and unlinkToDeath()

A client process can ask the Binder driver to notify it if the process hosting a specific Binder object dies. This is done by registering a Death Recipient.

In Java, this is exposed on the IBinder interface:

IBinder.DeathRecipient recipient = new IBinder.DeathRecipient() {
    @Override
    public void binderDied() {
        Log.w(TAG, "The remote service died!");
        // Clean up state, maybe attempt to reconnect
    }
};

try {
    mRemoteBinder.linkToDeath(recipient, 0);
} catch (RemoteException e) {
    // The binder might ALREADY be dead!
}

If the client no longer cares about the remote object, it should unregister to prevent memory leaks using mRemoteBinder.unlinkToDeath(recipient, 0).

binderDied() Callback

The magic happens in the kernel. The Binder driver tracks which processes own which binder_node structs. It also hooks into the Linux kernel's process teardown mechanisms (like the release file operation on the /dev/binder file descriptor when a process exits).

When Process B dies, the kernel driver:

  1. Cleans up Process B's Binder state.
  2. Finds all other processes that have registered a Death Recipient for objects hosted by Process B.
  3. Sends a BR_DEAD_BINDER command to those processes.
  4. The libbinder framework in the client process receives this, looks up the registered recipient, and invokes the binderDied() callback on a Binder thread.

Use Cases: Service Crashes and Watchdogs

Death Recipients are fundamentally how Android maintains system stability.

  • System Server Watchdog: If system_server crashes, the init process detects it and immediately kills Zygote, forcing a soft reboot. But what about the HAL daemons? Many system services register death recipients on their respective HALs (like AudioFlinger or CameraService). If a HAL daemon crashes, the system service catches the binderDied() callback and immediately triggers a restart of the HAL connection, hiding the crash from the user.
  • ActivityManagerService (AMS): AMS uses death recipients extensively to track application lifecycles. When an app binds to a Service in another process, AMS links to the death of the remote process. If the remote process dies, AMS knows to update its internal state, notify the client app, and potentially schedule a restart of the Service.

Implementation in Native and Java

While the Java implementation is straightforward, it relies entirely on the native C++ BpBinder::linkToDeath method. In C++, a developer creates a class extending IBinder::DeathRecipient and overrides the pure virtual binderDied(const wp<IBinder>& who) method. The semantics and kernel interactions are identical across both languages.