Just An Application

May 17, 2012

Adventures In Distributed Garbage Collection: Part Six – Service Creation

1.0 Service Component Creation

An Android Service is specified by an Android Application in its manifest and usually, although not necessarily, runs in that Application’s process.

The component that implements a Service is created in the appropriate process if it does not already exist when an attempt is made to either

  • start that Service explicitly, or

  • bind to it if the client sets the BIND_AUTO_CREATE flag when doing so

The creation of the component is initiated by the ActivityManagerService in response to the attempt to start it or bind to it.

2.0 Process: System

Actor: ActivityManagerService

2.1 Starting A Service

A Service is started either via a remote procedure call to the method

    public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType)

which is defined by the IActivityManager interface, or via an internal call in the ActivityManagerService itself to the method

    ComponentName startServiceInPackage(int uid, Intent service, String resolvedType)

Each method in turn calls startServiceLocked() to do the actual work.

2.1.1 startServiceLocked()

The method calls retrieveServiceLocked() to obtain a ServiceRecord for the Service to be started, and bringUpServiceLocked() to create and start the Service if necessary.

2.2 Binding To A Service

A client binds to a Service via a remote procedure call to the ActivityManagerService implementation of the method

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

defined by the IActivityManager interface.

Like startServiceLocked(), the implementation of the bindService() method calls retrieveServiceLocked() to obtain a ServiceRecord for the Service to be accessed, and bringUpServiceLocked() to create the Service if necessary.

2.3 Methods

2.3.1 retrieveServiceLocked(…)

Definition: ActivityManagerService.java [8634-8701]

    private ServiceLookupResult retrieveServiceLocked(Intent service, String resolvedType, int callingPid, int callingUid)

Argument: Intent service

  • The Intent specifing the Service to retrieve the ServiceRecord for.

Argument: String resolvedType

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

Argument: int callingPid

  • The id of the process attempting to access the Service.

Argument: int callingUid

  • The user id associated with the process attempting to access the Service.

Method

The method first attempts to obtain a ServiceRecord for the Service specified by the service Intent argument.

If a component is specified by the Intent then it is used as a key into the mServices map.

If a component is not specified or no matching ServiceRecord is found then the service argument is wrapped in an Intent.FilterComparison instance which is then used as a key into the mServicesByIntent map.

If a matching ServiceRecord is not found then one is created and it is added to the mServices and mServicesByIntent maps

A check is then performed using the existing or newly created ServiceRecord to see whether the process attempting to access the Service has permission to do so.

2.3.2 bringUpServiceLocked(…)

Definition: ActivityManagerService.java [8962-9014]

    private final boolean bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean whileRestarting)

Argument: ServiceRecord r

  • The ServiceRecord which represents the Service to be created and started if necessary.

Argument: int intentFlags

  • The set of flags returned by a call to the getFlags() method on the Intent used to bind to or start the Service.

Argument: boolean whileRestarting

  • true if the Service is being restarted.

Method

If the Service is already running then the method sendServiceArgsLocked() is called.

If the process in which the Service should be run is already running but the Service is not then the method realStartServiceLocked() is called.

If the process in which the Service should be run is not already running then the method startProcessLocked() is called to start it. If that method is successful then the ServiceRecord is added to the mPendingServices list.

When the process starts, the method attachApplicationLocked() calls the method realStartServiceLocked() on each ServiceRecord in the mPendingServices list.

2.3.3 realStartServiceLocked(…)

Definition: ActivityManagerService.java [8803-8851]

    private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app) 
                       throws 
                           RemoteException

Argument: ServiceRecord r

  • The ServiceRecord which represents the Service to be started.

Argument: ProcessRecord app

  • The ProcessRecord which represents the process in which the Service should be started.

Method

The method starts by adding the ServiceRecord to the services set of the ProcessRecord.

It then calls bumpServiceExecutingLocked() with "create" as the why argument.

It then calls the method

   void scheduleCreateService(IBinder token, ServiceInfo info) throws RemoteException;

on the IApplicationThread instance held by the ProcessRecord passing the ServiceRecord instance r as the first argument.

This results in an asynchronous remote procedure call to the implementation of this method in the process in which the Service is to be started.

The method then calls requestServiceBindingsLocked() followed by sendServiceArgsLocked().

2.3.4 bumpServiceExecutingLocked(…)

Definition: ActivityManagerService.java [8703-8719]

   private final void bumpServiceExecutingLocked(ServiceRecord r, String why)

Argument: ServiceRecord r

  • The ServiceRecord which represents the Service to be started.

Argument: String why

  • The action the Service is being asked to execute. This is used for debugging purposes only.

Method

This method performs the book-keeping necessary to record that the given Service is about to start performing a specific action requested by the ActivityManagerService.

If the Service is not already performing other actions then the ServiceRecord will be added to the executingSevices set held by the ProcessRecord which represents the process in which the Service is running.

2.3.5 requestServiceBindingsLocked(…)

Definition: ActivityManagerService.java [8793-8801]

   private final void requestServiceBindingsLocked(ServiceRecord r)

Argument: ServiceRecord r

  • The ServiceRecord which represents the Service the method should act upon

Method

If the Service represented by ServiceRecord is not running then the method returns at once.

Otherwise, for each IntentBindRecord in the ServiceRecord‘s bindings map it requests an IBinder object for use by the clients which bound to the Service using the corresponding Intent.

2.3.6 sendServiceArgsLocked(…)

Definition: ActivityManagerService.java [8721-8768]

   private final void sendServiceArgsLocked(ServiceRecord r, boolean oomAdjusted)

Argument: ServiceRecord r

  • The ServiceRecord which represents the Service …

Argument: boolean oomAdjusted

  • true if the Out-of-memory behaviour of the process running the Service has already been adjusted, false otherwise.

Method

If the Service has been expicitly started one or more times then the method will invoke the onStartCommand() method on the Service implementation via a remote procedure call one or more times.

3.0 Process: Service

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

3.1 scheduleCreateService(…)

Caller: ActivityManagerService via remote procedure call

Actor: ApplicationThread

Definition: ActivityThread.java [493-499]

    public final void scheduleCreateService(IBinder token, ServiceInfo info)

Argument: IBinder token

  • The proxy for the ServiceRecord which represents the Service to be created.

Argument: ServiceInfo info

  • The ServiceInfo for the Service to be created.

Method

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

        ...

        private static final class CreateServiceData {
            IBinder     token;
            ServiceInfo info;
            Intent      intent;
            ...
        }
		
        ...

and then sends it to the ActivityThread as the payload of a message. This message is handled by the method ActivityThread.handleCreateService().

3.2 handleCreateService(…)

Actor: ActivityThread

Definition: ActivityThread.java [1916-1960]

    private final void handleCreateService(CreateServiceData data)

Argument: CreateServiceData data

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

Method

The method first loads the class that implements the Service to be created and then creates an instance of that class.

It then calls attach() on the newly created instance followed by onCreate().

It then adds the Service instance to the mServices map using the using IBinder object held in data.token as the key.

It then calls the IActivityManager method serviceDoneExecuting() on the ActivityManagerProxy instance returned by the static method ActivityManagerNative.getDefault().

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

3.3 attach(…)

Actor: Service Component

Definition: Service.java [654-666]

    public final void attach(
                          Context        context,
                          ActivityThread thread, 
                          String         className, 
                          IBinder        token,
                          Application    application, 
                          Object         activityManager)

Argument: Context context

  • The Context for use by the Service.

Argument: ActivityThread thread

  • The ActivityThread.

Argument: String className

  • The name of the class which implements the Service.

Argument: IBinder token

Argument: Application application

  • The Application which defines the Service.

Argument: Object activityManager

  • The proxy for the ActivityManagerService.

Method

The method sets up the Context for the Service using the context argument and then initializes each of the instance variables with the corresponding argument, for example,

        ...

        mClassName   = className;
        mToken       = token;
        mApplication = application;
		
        ...

4.0 Process: System

Actor: ActivityManagerService

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

4.1 serviceDoneExecuting(…)

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

Definition: ActivityManagerService.java [9727-9795]

    public void serviceDoneExecuting(IBinder token, int type, int startId, int res)

Argument: IBinder token

  • The ServiceRecord which represents the Service which has finished executing a specific action at the request of the ActivityManagerService.

Argument: int type

  • The type of the action the Service has finished executing. In practice 1 if the action was “start”, 0 otherwise.

Argument: int startId

  • Identifier used when the action was “start”. For other actions this is always 0.

Argument: int res

  • The result of the action the Service has finished executing. Only ever used when the action was “start”. For other actions this is always 0.

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 if the type argument is 1, indicating that the action was "start", various book-keeping is done using the startId and the res arguments.

If the type argument is not 1 then nothing is done and the startId and res arguments are ignored.

Finally the method calls serviceDoneExecutingLocked().

4.2 serviceDoneExecutingLocked(…)

Definition: ActivityManagerService.java [9797-9820]

    public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping)

Argument: ServiceRecord r

  • The ServiceRecord which represents the Service which has finished executing a specific action.

Argument: boolean inStopping

  • true if the Service is stopping, false otherwise.

Method

This method does the opposite of bumpServiceExecutingLocked(). It performs the book-keeping necessary to record that the given Service has finished a specific action requested by the ActivityManagerService.

If the Service is not performing any other actions then the ServiceRecord will be removed from the executingSevices set held by the
ProcessRecord which represents the process in which the Service is running.


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

Blog at WordPress.com.