Just An Application

June 1, 2012

Adventures In Distributed Garbage Collection: Part Seventeen – Binders And Garbage Collection

Filed under: Android, Android Internals, Java, Mobile Java, Services — Tags: , , , , — Simon Lewis @ 9:33 am

1.0 An Alternative Service implementation

Unlike the previous example the following Android Service implementation creates the Java Binder object returned from the onBind() method on demand and it does not retain a reference to it.

    package xper.service.malin;

    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import android.util.Log;

    public final class MalinService 
                       extends 
                           Service 
    {
        public MalinService()
        {
        }
	

        @Override
        public IBinder onBind(Intent intent) 
        {
            Log.d(TAG, "onBind(" + intent + ")");
            return new MalinServiceBinder(this);
        }
	
        //
	
        @Override
        public boolean onUnbind(Intent intent) 
        {
            Log.d(TAG, "onUnbind(" + intent + ")");
            return super.onUnbind(intent);
        }

        void doSomethingInParticular()
        {
        }

        //
	
        private static final String TAG = "MalinService";
    }

The MarlinServiceBinder object retains a reference to the MalinService object but that is all.

    package xper.service.malin;

    import android.os.RemoteException;
    import xper.service.malin.Malin.Stub;

    final class MalinServiceBinder 
                extends 
                    Stub 
    {
        public void doSomethingInParticular() 
                    throws 
                        RemoteException 
        {
            service.doSomethingInParticular();
        }

        //
	
        MalinServiceBinder(MalinService theService)
        {
            service = theService;
        }
	
        //
	
        private MalinService	service;
    }

Once it has been created there are no references to the MarlinServiceBinder object from any other Java objects.

We can show this using MAT and by examining the heap dump directly.

As in the ServiceRecord case MAT erroneously reports that the MalinServiceBinder object is referenced by a Native Stack GC Root but examination of the heap dump shows that, as expected, it is actually a JNI Global reference.

In this example, if the JNI Global reference did not exist then the MarlinServiceBinder object would be eligible for garbage collection. This is of course precisely why the Binder C++ code creates the JNI Global reference. It is to ensure that a Java Binder object that is otherwise unreferenced in the process in which it was created is not garbage collected whilest there are references to it from other processes.

2.0 Binder References

Explaining exactly how the Binder reference mechanism works more or less requires explaining exactly how Binders work full-stop, which would take a lot more space than is available in the margin of this post, so what follows is a somewhat simplified explanation.

2.2 Reference Counting

Binders are reference counted. Each BinderProxy which references a Binder constitutes a reference to that Binder.

The Binder reference counting mechanism is, necessarily, cross-process and entirely orthogonal to the per-process Java garbage collection mechanism.

2.2.1 Incrementing The Reference Count

Effectively each time a Binder is sent to another process and a BinderProxy is created for that Binder the reference count is incremented.

2.2.2 Decrementing The Reference Count

The finalize() method of a Java BinderProxy object, that is an instance of the class android.os.BinderProxy, calls the native method destroy() which decrements the reference count of the associated Binder object.

In other words, once a Java BinderProxy object has been created in a process then the reference from it to the associated Binder will exist until that Java BinderProxy object has both been garbage collected and finalized.

2.2 Interaction With Java GC

As we have seen the Binder reference mechanism creates a JNI Global reference to a Java Binder object to prevent it from being garbage collected whilest there remain BinderProxy objects in other processes that reference it.

The JNI Global reference is created the first time the Binder is referenced by a BinderProxy.

The JNI Global reference is destroyed when there are no longer any BinderProxies referencing the Binder as determined by the reference count.

That is the only interaction between the Binder reference mechanism and the Java garbage collection mechanism of the process in which the Binder object was created and it is completely opaque. That is the Binder reference mechanism creates a vanilla JNI Global reference that is indistinguishable from a JNI Global reference created by any other piece of native code.

2.4 Inspecting Per-Process Binder Related State At Runtime

It is possible to inspect the Binders and BinderProxies in use in a given process by looking at the contents of the file

    /proc/binder/proc/<PID>

where <PID> is the id of the process.

For example, entering

 cat /proc/binder/proc/368

in a shell running on the device after the client has bound to the Malin Service results in the following output

    binder proc state:
    proc 368
      thread 368: l 00
      thread 374: l 12
      thread 375: l 11
      node 3879: u0007ccf0 c00094f88 hs 1 hw 1 ls 0 lw 0 is 1 iw 1 proc 60
      node 3904: u001a5bb8 c001a5b98 hs 1 hw 1 ls 0 lw 0 is 2 iw 2 proc 357 60
      ref 3874: desc 0 node 1 s 1 w 1 d (null)
      ref 3877: desc 1 node 135 s 1 w 1 d (null)
      ref 3882: desc 2 node 196 s 1 w 1 d (null)
      ref 3883: desc 3 node 131 s 1 w 1 d (null)
      ref 3884: desc 4 node 183 s 1 w 1 d (null)
      ref 3887: desc 5 node 3886 s 1 w 1 d (null)
      ref 3896: desc 6 node 23 s 1 w 1 d (null)
      ref 3899: desc 7 node 44 s 1 w 1 d (null)

In this case 368 is the id of the process running the Malin Service, 357 is the id of the process running the client, and 60 is the id of the System process.

The corresponding output for the process running the client looks like this

    binder proc state:
    proc 357
      thread 357: l 00
      thread 366: l 12
      thread 367: l 11
      node 3830: u000a5168 c001ad3c0 hs 1 hw 1 ls 0 lw 0 is 1 iw 1 proc 60
      node 3754: u0014c9a0 c00094f88 hs 1 hw 1 ls 0 lw 0 is 1 iw 1 proc 60
      node 3785: u001ad4f0 c001ae468 hs 1 hw 1 ls 0 lw 0 is 2 iw 2 proc 113 60
      node 3783: u001ae450 c001ae430 hs 1 hw 1 ls 0 lw 0 is 1 iw 1 proc 60
      node 3791: u001ae6d0 c001ae6b0 hs 1 hw 1 ls 0 lw 0 is 1 iw 1 proc 60
      node 3870: u001b3ba8 c001b3b88 hs 1 hw 1 ls 0 lw 0 is 1 iw 1 proc 60
      ref 3749: desc 0 node 1 s 1 w 1 d (null)
      ref 3752: desc 1 node 135 s 1 w 1 d (null)
      ref 3757: desc 2 node 196 s 1 w 1 d (null)
      ref 3758: desc 3 node 131 s 1 w 1 d (null)
      ref 3759: desc 4 node 183 s 1 w 1 d (null)
      ref 3762: desc 5 node 3761 s 1 w 1 d (null)
      ref 3772: desc 6 node 23 s 1 w 1 d (null)
      ref 3775: desc 7 node 44 s 1 w 1 d (null)
      ref 3781: desc 8 node 219 s 1 w 1 d (null)
      ref 3789: desc 9 node 3788 s 1 w 1 d (null)
      ref 3799: desc 10 node 3798 s 1 w 1 d (null)
      ref 3803: desc 11 node 3802 s 1 w 1 d (null)
      ref 3807: desc 12 node 3806 s 1 w 1 d (null)
      ref 3828: desc 13 node 272 s 1 w 1 d (null)
      ref 3843: desc 14 node 3821 s 1 w 1 d (null)
      ref 3866: desc 15 node 765 s 1 w 1 d c5ff8940
      ref 3907: desc 16 node 3904 s 1 w 1 d c469be40

2.4.1 Binder Entries

The lines with the prefix node describe Binder objects that have been created in the process.

The numbers after the proc keyword are the ids of the processes which hold references to that Binder, that is, there
are BinderProxy objects in those processes which reference the Binder.

For example, the entry

      node 3904: u001a5bb8 c001a5b98 hs 1 hw 1 ls 0 lw 0 is 2 iw 2 proc 357 60

from the first example above from the Service process, 368, specifies that the System process (60) and the client process (357) both have BinderProxy objects which reference this Binder in the service process.

By inference this entry must be for the MalinServiceBinder Java Binder object.

2.4.2 BinderProxy Entries

The lines with the prefix ref describe the BinderProxy objects that have been created in the process

The number after the node keyword is the id of the Binder the BinderProxy references.

For example, the entry

      ref 3907: desc 16 node 3904 s 1 w 1 d c469be40

from the second example above from the client process, 357, specfies the BinderProxy which references the Binder with id 3904 which as we have seen is a Binder in the service process, 368.

3.0 A Binder Cycle Made For Two

The way the Binder reference mechanism works means that it possible to create cross-process reference cycles such that none of the objects in the cycle can be garbage collected if they are Java objects or freed if they are C++ objects despite the fact that none of them are in use. In short a memory leak.

The simplest cycle requires just two Java Binder objects in two separate processes each of which holds a Java BinderProxy object referencing the other, like so


Copyright (c) 2012 By Simon Lewis. All Rights Reserved.

Advertisements

1 Comment »

  1. […] we have seen it is possible for a Java Binder object to be part of a Binder reference cycle which will prevent […]

    Pingback by Adventures In Distributed Garbage Collection: Part Eighteen – The Great Service Record Mystery Revisited « Just An Application — June 6, 2012 @ 9:32 am


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: