Just An Application

May 19, 2012

Adventures In Distributed Garbage Collection: Part Eight – Binding To A Service

1.0 Process: Service Client

Actor: Service Client

The following code in the Service Client calls the Activity’s implementation of the method

    public abstract boolean bindService(Intent service, ServiceConnection conn, int flags);

passing it a ServiceConnection object

        ...

        connection = new FastnetServiceConnection();
        bindService(
            new Intent("xper.service.fastnet.ACTION_FASTNET"), 
            connection, 
            Service.BIND_AUTO_CREATE);
		
        ...

where the class FastnetServiceConnection is defined as follows

    final class FastnetServiceConnection 
                implements 
                    ServiceConnection 
    {
        public void onServiceConnected(ComponentName theName, IBinder theService) 
        {
            Log.d("FastnetSeviceConnection", "onServiceConnected(" + theName + ", " + theService + ")");
            service = theService;
        }

	public void onServiceDisconnected(ComponentName theName) 
	{
		Log.d("FastnetSeviceConnection", "onServiceDisonnected(" + theName + ")");
	}

        private IBinder	service;
    }

This eventually results in a call to the ContextImpl implementation of the bindService() method.

1.1 bindService(…)

Object: ContextImpl

Definition: ContextImpl.java [863-885]

    public boolean bindService(Intent service, ServiceConnection conn, int flags)

Argument: Intent service

  • The Intent identifying the Service to bind to.

Argument: ServiceConnection conn

  • ServiceConnection object on which callback methods should be invoked when the status of the connection changes.

Argument: int flags

  • A set of bit-flags used to specify options which control aspects of the behaviour of the method.

Method

The method begins by calling the getServiceDispatcher() method on mPackageInfo to obtain an IServiceConnection object.

It then invokes the bindService() method on the ActivityManagerProxy obtained by a call to the static method ActivityManagerNative.getDefault().

This results in a remote procedure call to the ActivityManagerService implementation of the IActivityManager method bindService().

1.2 getServiceDispatcher(…)

Object: LoadedApk

Definition: LoadedApk.java [824-844]

    public final IServiceConnection getServiceDispatcher(ServiceConnection c, Context context, Handler handler, int flags)

Argument: ServiceConnection c

Argument: Context context

  • The Context in which ServiceConnection is being used.

Argument: Handler handler

Argument: int flags

  • A setof bit-flags specifying aspects of the required behaviour of the ServiceDispatcher

Method

The method begins by attempting to obtain an existing ServiceDispatcher for the given ServiceConnection from the ServiceConnection to ServiceDispatcher map for the given Context held in the mServices map.

If an existing ServiceDispatcher is found then the validate() method is called on it to ensure that in can be used with the given Context and Handler.

Otherwise a new one is created and added to the ServiceConnection to ServiceDispatcher map for the given Context held in the mServices map.

The method then calls getIServiceConnection() on the new or existing ServiceDispatcher object and returns the result.

2.0 Process: System

Entry Point: remote procedure call to the ActivityManagerService implementation of the IActivityManager method bindService().

2.1 bindService(…)

Caller: Service Client via remote procedure call

Actor: ActivityManagerService

Definition: ActivityManagerService.java [9401-9540]

    public int bindService(
                   IApplicationThread caller, 
                   IBinder            token,
                   Intent             service, 
                   String             resolvedType,
                   IServiceConnection connection, 
                   int                flags)

Argument: IApplicationThread caller

Argument: IBinder token

  • The ActivityRecord which represents the Activity which invoked this method, or null.

Argument: Intent service

  • The Intent specifying the Service to bind to.

Argument: String resolvedType

  • The data type, if any, explicitly or implicitly specified by the service argument.

Argument: IServiceConnection connection

  • The proxy for the InnerConnection object which implements the IServiceConnection interface in the Service Client.

Argument: int flags

  • The set of bit-flags that were passed to the original call to bindService() by the Service client.

Method

The method begins by attempting to get the ProcessRecord which represents the process in which the caller is running by calling the method

    final ProcessRecord getRecordForAppLocked(IApplicationThread thread)

passing the caller argument to it.

If getRecordForAppLocked() returns null a SecurityException is thrown.

It the token argument is not null then

  • The method checks to see whether it is valid.

  • If it is not the method returns at this point, otherwise the corresponding ActivityRecord is obtained.

The method then calls retrieveServiceLocked() to obtain a ServiceRecord object.

If this is not successful the method returns at this point.

If it is successful the method calls retriveAppBindingLocked() on the ServiceRecord object to obtain the AppBindRecord for the calling process.

It then creates a new ConnectionRecord object.

The newly created ConnectionRecord object is added to

If the BIND_AUTO_CREATE flag is set in the flags argument then

If the ServiceRecord has an associated ProcessRecord and the binding for the given Intent already exists then

  • The connected() method is invoked on the IServiceConnection object held by the ConnectionRecord (conn).

  • This results in an asynchronous remote procedure call to the object implementing the IServiceConnection interface in the Service client process.

  • If this is the first connection to use the binding and the doRebind flag of the IntentBindRecord is true

Otherwise if a binding has not already been requested (b.intent.requested == false) then

  • The method calls requestServiceBindingLocked() with the rebind argument set to false.

2.2 retrieveAppBindingLocked(…)

Object: ServiceRecord

Definition: ServiceRecord.java [288-303]

    public AppBindRecord retrieveAppBindingLocked(Intent intent, ProcessRecord app)

Argument: Intent intent

  • The Intent used by the client to bind to the Service.

Argument: ProcessRecord app

  • The ProcessRecord which represents the process in which the client binding to the Service is running.

Method

The method starts by wrapping the intent argument in an Intent.FilterComparison object and then uses the result to retrieve the corresponding IntentBindRecord from the bindings map.

If there is no IntentBindRecord for the given Intent one is created and added to the bindings map.

The AppBindRecord for the process represented by the app argument is then retrieved from the apps map of the IntentBindRecord using the ProcessRecord as the key.

If the corresponding AppBindRecord exists it is returned, otherwise a new AppBindRecord is created added to the IntentBindRecord‘s apps map and then returned.

2.3 requestServiceBindingLocked(…)

Definition: ActivityManagerService.java [8770-8791]

    private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i, boolean rebind)

Argument: ServiceRecord r

  • The ServiceRecord which represents the Service to request the binding from.

Argument: IntentBindRecord i

  • The IntentBindRecord which specifies the Intent the binding is being requested for

Argument: boolean rebind

  • true if this is a rebind notification.

Method

If the Service represented by the ServiceRecord is not already running the method returns false immediately.

If a binding has not already been requested (i.requested == false) or rebind is true and there are one or more clients, then

The method then returns true.

3.0 Process: Service

Entry Point: remote procedure call to the ApplicationThread implementation of the IApplicationThread method scheduleBindService().

3.1 scheduleBindService(..)

Caller: The ActivityManagerService via remote procedure call

Actor: ApplicationThread

Definition: ActivityThread.java [502-510]

    public final void scheduleBindService(IBinder token, Intent intent, boolean rebind)

Argument: IBinder token

  • A proxy for the ServiceRecord which represents the Service from which the binding is required.

Argument: Intent intent

  • The Intent the binding is required for.

Argument: boolean rebind

  • true if this is a rebind request.

Method

The method encapsulates its arguments in an instance of the ActivityThread inner class BindServiceData

        ...

        private static final class BindServiceData {
            IBinder token;
            Intent  intent;
            boolean rebind;
            ...
        }
		
        ...

and then sends it to the ActivityThread as the payload of a message.

This message is handled by the method ActivityThread.handleBindService().

3.2 handleBindService(…)

Actor: ActivityThread

Definition: ActivityThread.java [1962-1988]

    private final void handleBindService(BindServiceData data)

Argument: BindServiceData data

  • The encapsulated arguments passed to the ApplicationThread.scheduleBindService() method.

Method

The method starts by getting the Service Component object from the mServices map using the IBinder object held in data.token as the key.

If no Service Component object is found then the method does nothing more.

If there is a corresponding Service Component object then

  • if data.rebind is false then

    The method onBind() is called on the Service Component object with the argument data.intent.

    The static method ActivityManagerNative.getDefault() is called and the method publishService() is called on the ActivityManagerProxy object returned, with arguments

    • data.token

    • data.intent

    • the IBinder object returned from the call to Service.onBind()

    This results in a remote procedure call to the implementation of publishService() in the ActivityManagerService.

  • If data.rebind is true then

    The method onRebind() is called on the Service object with the argument data.intent.

    The static method ActivityManagerNative.getDefault() is called and the method serviceDoneExecuting() is then called on the ActivityManagerProxy returned, with the arguments

    • data.token

    • 0

    • 0

    • 0

    This results in an asynchronous remote procedure call to the implementation of serviceDoneExecuting() in the ActivityManagerService.

4.0 Process: SystemServer

Entry Point: remote procedure call call to the ActivityManagerService implementation of the IActivityManager method publishService()

4.1 publishService(…)

Caller: ActivityThread in the Service process via remote procedure call.

Actor: ActivityManagerService

Definition: ActivityManagerService.java [9627-9685]

    public void publishService(IBinder token, Intent intent, IBinder service)

Argument: IBinder token

  • The ServiceRecord which represents the Service which is publishing the binding.

Argument: Intent intent

  • The Intent for which the IBinder object passed as the service argument is being published.

Argument: IBinder service

  • The proxy for the IBinder object being published, as returned by the call to the Service.onBind() method on the Service Component.

Method

The method begins by explicitly checking whether the token argument is actually a ServiceRecord and throws an IllegalArgumentException if it is not.

It then casts the the token argument to a ServiceRecord.

If the resulting ServiceRecord is null the method does nothing more.

If the resulting ServiceRecord is not null then the method wraps the intent argument in an Intent.FilterComparison instance which is then used as a key into the bindings map of the ServiceRecord.

If a corresponding IntentBindRecord exists and and an IBinder object for it has not already been received it sets the binder instance variable of the IntentBindRecord to the service argument and the requested and received instance variables to true.

The method then iterates over each ConnectionRecord in the connections map of the ServiceRecord.

If the connection represented by the ConnectionRecord was created as the result of binding using an Intent that is filterEqual() to the intent argument then the connected() method is called on the IServiceConnection object (conn) of that ConnectionRecord.

This results in an asynchronous remote procedure call on the object implementing the IServiceConnection interface in the process that is running the client.

Finally the method calls serviceDoneExecutingLocked().

5.0 Process: ServiceClient

Entry Point: remote procedure call to the InnerConnection implementation of the IServiceConnection method connected().

5.1 InnerConnection.connected(…)

Caller: The ActivityManagerService via remote procedure call

Object: LoadedApk.ServiceDispatcher.InnerConnection

Definition: LoadedApk.java [920-925]

    public void connected(ComponentName name, IBinder service) 
                throws 
                    RemoteException

Argument: ComponentName name

Argument: IBinder service

  • The IBinder object to use to interact with the Service if the connection is being established, null if the connection is being torn-down.

Method

If the weak reference to the ServiceDispatcher object, mDispatcher, is not null then the method invokes the connected() method on the instance passing the name and service arguments.

5.2 ServiceDispatcher.connected(…)

Object: LoadedApk.ServiceDispatcher

Definition: LoadedApk.java [992-998]

    public void connected(ComponentName name, IBinder service)

Argument: ComponentName name

Argument: IBinder service

  • The IBinder object to use to interact with the Service if the connection is being established, null if the connection is being torn-down..

Method

If the reference to the Handler, mActivityThread, is not null then the method posts a Runnable to the Handler. When run the Runnable invokes the doConnected() method on the current ServiceDispatcher instance passing it the name and service arguments.

Otherwise the method invokes the doConnected() method directly passing it the name and service arguments.

5.3 doConnected(…)

Object: LoadedApk.ServiceDispatcher

Definition: LoadedApk.java [1021-1066]

    public void doConnected(ComponentName name, IBinder service)

Argument: ComponentName name

Argument: IBinder service

  • The IBinder object to use to interact with the Service if the connection is being established, null if the connection is being torn-down.

Method

The method starts by determining whether there is an existing ConnectionInfo object in the mActiveConnections map using the name argument as the key.

If there is and the IBinder object referenced by the binder instance variable is identical to the service argument the method returns straight away.

If the service argument is not null, that is, a connection is being established, a new ConnectionInfo instance is created with its binder set to the service argument, and the instance is added to the mActiveConnections map using the name argument as the key.

If there was an existing ConnectionInfo object the method onServiceDisconnected() is called on the mConnection object passing the name argument

If the service argument is not null then the method onServiceConnected() is called on the mConnection object passing the name and service arguments.


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

Advertisements

6 Comments »

  1. […] We can use the source code to derive a diagram which shows the Service related objects which should exist in the Service client process and their relationships following a successful call to bindService(). […]

    Pingback by Adventures In Distributed Garbage Collection: Part Nine – Post Bind Service Client State « Just An Application — May 20, 2012 @ 6:01 am

  2. […] which should exist in the Service process and their relationships once the Service client has bound to the […]

    Pingback by Adventures In Distributed Garbage Collection: Part Ten – Post Bind Service State « Just An Application — May 21, 2012 @ 6:00 am

  3. […] related objects that should exist in the System process and their relationships after a client has bound to the […]

    Pingback by Adventures In Distributed Garbage Collection: Part Eleven – Post Bind System Process State « Just An Application — May 22, 2012 @ 6:02 am

  4. […] the ServiceConnection object that was originally passed to the bindService() […]

    Pingback by Adventures In Distributed Garbage Collection: Part Twelve – Unbinding From A Service « Just An Application — May 23, 2012 @ 6:00 am

  5. […] FastnetServiceConnection object would no longer be present in the Java […]

    Pingback by Adventures In Distributed Garbage Collection: Part Thirteen – Post Unbind Service Client State « Just An Application — May 24, 2012 @ 6:10 am

  6. […] of the onBind() method is passed to the System process via a remote procedure call to the publishService() method of the […]

    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

Blog at WordPress.com.

%d bloggers like this: