Binder is a communication framework similar to C/S architecture. Sometimes the client may want to know the status of the server, for example, if the server is down, the client wants to be notified in time, instead of waiting for the server to know again. This scenario is most commonly used when the SERVER is C/S, such as AMS and APP. AMS wants to know when an APP process exits unexpectedly. Not only does AMS need to clean up some information on the APP side, such as ActivityRecord, ServiceRecord, etc., but it may also need to restore some self-started services in time. Binder implements a set of “obituary” features. When a server dies or exits properly, the Binder driver sends an obituary to the client informing it that the service has died.
How did this “obituary” come about? What does it do? For Android, Binder obituaries are somewhat Observer like, so you need to register the Observer with the target object first. In fact, you need to register the Client with the Binder driver, so that when the Binder service fails, it can be sent via the driver. Binder obituaries have only one entry: When releasing a Binder device, all resources required by the process are reclaimed, including opened device files such as Binder character devices, regardless of normal or abnormal exit. At release time, the corresponding release function is called, and the obituary is sent at this point. Binder obituaries therefore consist of only two parts: registration and notice.
Binder” Obituary “registration entry
BindService will first request AMS to start the Service. Server process will call the function open to open the device file /dev/binder. At the same time, the Binder service entity is returned to AMS, and AMS passes the reference handle of the Binder entity to Client through Binder communication, that is, when AMS is returned to Client, it is registered with the Binder driver. In fact, this is easier to understand, the server side of the proxy, you should care about the server side. When AMS returns a Binder service entity to the Client using the IServiceConnection communication line, InnerConnection indirectly registers the death callback with the kernel:
private static class InnerConnection extends IServiceConnection.Stub {
final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
public void connected(ComponentName name, IBinder service) throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if(sd ! =null) { sd.connected(name, service); }}}Copy the code
The ServiceDispatcher function further calls doConnected
public void doConnected(ComponentName name, IBinder service) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;
synchronized (this) {
if(service ! =null) {
mDied = false;
info = new ConnectionInfo();
info.binder = service;
info.deathMonitor = new DeathMonitor(name, service);
try{<! -- Key points1-->
service.linkToDeath(info.deathMonitor, 0); }}Copy the code
LinkToDeath is a Native function that will further call BpBinde’s linkToDeath:
status_t BpBinder::linkToDeath(
const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags){ <! Key points -1-->
IPCThreadState* self = IPCThreadState::self();
self->requestDeathNotification(mHandle, this);
self->flushCommands();
}Copy the code
Finally call IPCThreadState’s requestDeathNotification(mHandle, this) to send the BC_REQUEST_DEATH_NOTIFICATION request to the kernel:
status_t IPCThreadState::requestDeathNotification(int32_t handle, BpBinder* proxy)
{
mOut.writeInt32(BC_REQUEST_DEATH_NOTIFICATION);
mOut.writeInt32((int32_t)handle);
mOut.writeInt32((int32_t)proxy);
return NO_ERROR;
}Copy the code
Finally, let’s take a look at how registration works in the kernel:
int
binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
void __user *buffer, int size, signed long *consumed)
{
...
case BC_REQUEST_DEATH_NOTIFICATION:
case BC_CLEAR_DEATH_NOTIFICATION: {
...
ref = binder_get_ref(proc, target);
if(cmd == BC_REQUEST_DEATH_NOTIFICATION) { ... The key point1
death = kzalloc(sizeof(*death), GFP_KERNEL);
binder_stats.obj_created[BINDER_STAT_DEATH]++;
INIT_LIST_HEAD(&death->work.entry);
death->cookie = cookie;
ref->death = death;
if (ref->node->proc == NULL) {
ref->death->work.type = BINDER_WORK_DEAD_BINDER;
if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) {
list_add_tail(&ref->death->work.entry, &thread->todo);
} else{ list_add_tail(&ref->death->work.entry, &proc->todo); wake_up_interruptible(&proc->wait); }}}}Copy the code
Look at key point 1, which is essentially creating a binder_ref_death object for the Client and assigning it to binder_ref. Binder drivers use binder_node to log all binder_refs. When the binder_node process crashes, the binder_node driver can find binder_refs of all clients based on the global binder_ref list. And send an “obituary” to the Client with the death callback set, because when binder_get_ref_for_node inserts a binder_ref into the Client, the binder_node’s binder_ref list is also inserted.
static struct binder_ref *
binder_get_ref_for_node(struct binder_proc *proc, struct binder_node *node)
{
struct rb_node *n;
struct rb_node **p = &proc->refs_by_node.rb_node;
struct rb_node *parent = NULL;
struct binder_ref *ref, *new_ref;
if (node) {
hlist_add_head(&new_ref->node_entry, &node->refs);
}
return new_ref;
}Copy the code
This way, the death callback entry is registered with the Binder kernel driver, which then triggers the death callback when the process terminates to release binder.
Death notification sent
When the binder_realEASE function is called to release the corresponding resource, the binder_deferred_release function is eventually called. This function iterates through all binder_nodes in the binder_proc and sends an obituary to the Client that registered the death callback.
static void binder_deferred_release(struct binder_proc *proc)
{ ....
if (ref->death) {
death++;
if (list_empty(&ref->death->work.entry)) {
ref->death->work.type = BINDER_WORK_DEAD_BINDER;
list_add_tail(&ref->death->work.entry, &ref->proc->todo);
// Insert the binder thread wait queue into the binder_ref request process ????? Natural support for Binder communication?
// When do YOU need a death callback as a binder service?wake_up_interruptible(&ref->proc->wait); }... }Copy the code
The death notice is sent directly to the Client’s binder process TODO queue, which seems to be useful only for C/S communication scenarios. When the Client’s binder thread is woken up, it does some cleanup for the “death notice” :
static int
binder_thread_read(struct binder_proc *proc, struct binder_thread *thread,
void __user *buffer, int size, signed long *consumed, int non_block)
{
case BINDER_WORK_DEAD_BINDER:
case BINDER_WORK_DEAD_BINDER_AND_CLEAR:
case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: {
struct binder_ref_death *death = container_of(w, struct binder_ref_death, work);
uint32_t cmd;
if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION)
cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE;
elsecmd = BR_DEAD_BINDER; . }Copy the code
A BR_DEAD_BINDER command is written to user space and the talkWithDriver function is returned, on which IPCThreadState continues to execute executeCommand,
status_t IPCThreadState::executeCommand(int32_t cmd)
{
// Obituary of death
case BR_DEAD_BINDER:
{
BpBinder *proxy = (BpBinder*)mIn.readInt32();
<! -- Key point 1 -->
proxy->sendObituary();
mOut.writeInt32(BC_DEAD_BINDER_DONE);
mOut.writeInt32((int32_t)proxy);
} break;Copy the code
}
In fact, Obituary is actually sent using BpBinder, and when the uary is processed, confirmation notifications are sent to the Binder driver.
void BpBinder::sendObituary()
{
ALOGV("Sending obituary for proxy %p handle %d, mObitsSent=%s\n".this, mHandle, mObitsSent ? "true" : "false");
mAlive = 0;
if (mObitsSent) return;
mLock.lock();
Vector<Obituary>* obits = mObituaries;
if(obits ! = NULL) { <! Key points -1-->
IPCThreadState* self = IPCThreadState::self();
self->clearDeathNotification(mHandle, this);
self->flushCommands();
mObituaries = NULL;
}
mObitsSent = 1;
mLock.unlock();
if(obits ! = NULL) {const size_t N = obits->size();
for (size_t i=0; i<N; i++) {
reportOneDeath(obits->itemAt(i));
}
deleteobits; }}Copy the code
Look at key point 1, which corresponds to registering, removing yourself from the observer list, and then reporting
void BpBinder::reportOneDeath(const Obituary& obit)
{
sp<DeathRecipient> recipient = obit.recipient.promote();
ALOGV("Reporting death to recipient: %p\n", recipient.get());
if (recipient == NULL) return;
recipient->binderDied(this);
}Copy the code
Then invoke the upper-layer DeathRecipient callback to do some cleanup and the like. In the case of AMS, the binderDied function is quite complex, including some data cleaning and even process reconstruction.
Android background Kill (FragmentActivity, PhoneWindow) LowMemoryKiller (4.3-6.0) LowMemoryKiller (4.3-6.0) Binder Obituary Principle Android Background Kill series 5: Android process alive – “cut” or rogue