Calling an IPC Method

Here are the steps a calling class should make to call your remote interface:

1. Declare a variable of the interface type that your .aidl file defined.

2. Implement ServiceConnection.

3. Call Context.bindServiceQ, passing in your ServiceConnection implementation.

4. In your implementation of ServiceConnection.onServiceConnectedQ, you will receive an IBinder instance (called service).

CallYourInterfaceName .Stub.asInterface((IBinder) service) to cast the returned parameter to YourInterface type.

5. Call the methods that you defined on your interface. You should always trap DeadObjectException exceptions, which are thrown when the connection has broken; this will be the only exception thrown by remote methods.

6. To disconnect, call Context.unbindService() with the instance of your interface. A few comments on calling an IPC service:

• Objects are reference counted across processes.

• You can send anonymous objects as method arguments.

Here is some sample code demonstrating calling an AIDL-created service, taken from the Remote Activity sample in the ApiDemos project.

public class RemoteServiceBinding extends Activity {

/** The primary interface we will be calling on

the service. */

IRemoteService mService = null;

/** Another interface we use on the service. */

ISecondary mSecondaryService = null;

Button mKillButton;

TextView mCallbackText;

private boolean mIsBound;

//Standard initialization of this activity. Set up //user to poke it before doing anything.

the UI, then wait for the

Warning: Don't forget the security implications of receiving data from other processes. In this case, the rect will read four numbers from the parcel, but it is up to you to ensure that these are within the acceptable range of values for whatever the caller is trying to do. See Security and Permissions for more on how to keep your application secure from malware.

@Override protected void onCreate(Bundle savedlnstanceState) { super.onCreate(savedlnstanceState); setContentView(R.layout.remote service binding); // Watch for button clicks.

Button button = (Button)findViewByld(R.id.bind);

button.setOnClickListener(mBindListener);

button = (Button)findViewByld(R.id.unbind);

button.setOnClickListener(mUnbindListener);

mKillButton = (Button)findViewByld(R.id.kill);

mKillButton.setOnClickListener(mKillListener);

mKillButton.setEnabled(false);

mCallbackText = (TextView)findViewByld(R.id.callback); mCallbackText.setText("Not attached.");

//Class for interacting with the main interface of the service.

private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) {

// This is called when the connection with the service has been established, // giving us the service object we can use to interact with the service. We are // communicating with our service through an IDL interface, so get a client-side // representation of that from the raw service object.

mService = IRemoteService.Stub.aslnterface(service); mKillButton.setEnabled(true); mCallbackText.setText("Attached."); // We want to monitor the service for as long as we are connected to it. try {

mService.registerCallback(mCallback);

} catch (RemoteException e) { // In this case the service has crashed before we could even do anything with // it; we can count on soon being disconnected (and then reconnected if it can

// be restarted)so there is no need to do anything here. }

// As part of the sample, tell the user what happened.

Toast.makeText(RemoteServiceBinding.this, R.string.remote service connected,

Toast.LENGTH_SHORT).show();

public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been // unexpectedly disconnected -- that is, its process crashed. mService = null; mKillButton.setEnabled(false); mCallbackText.setText("Disconnected.");

// As part of the sample, tell the user what happened.

Toast.makeText(RemoteServiceBinding.this, R.string.remote service disconnected,

Toast.LENGTH_SHORT).show();

//Class for interacting with the secondary interface of the service.

private ServiceConnection mSecondaryConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) {

// Connecting to a secondary interface is the same as any other interface.

mSecondaryService = ISecondary.Stub.aslnterface(service); mKillButton.setEnabled(true);

public void onServiceDisconnected(ComponentName className) { mSecondaryService = null; mKillButton.setEnabled(false);

private OnClickListener mBindListener = new OnClickListener() { public void onClick(View v) { //Establish a couple connections with the service, binding by interface names. //This allows other applications to be installed that replace the remote service //by implementing the same interface.

bindService(new Intent(IRemoteService.class.getName()), mConnection, Context.BIND_AUTO_CREATE); bindService(new Intent(ISecondary.class.getName()), mSecondaryConnection, Context.BIND_AUTO_CREATE); mIsBound = true;

mCallbackText.setText("Binding.");

private OnClickListener mUnbindListener = new OnClickListener() { public void onClick(View v) { if (mIsBound) {

// If we have received the service, and hence registered with it, then now is // the time to unregister.

mService.unregisterCallback(mCallback); } catch (RemoteException e) {

// There is nothing special we need to do if the service

// Detach our existing connection.

unbindService(mConnection); unbindService(mSecondaryConnection); mKillButton.setEnabled(false); mIsBound = false;

mCallbackText.setText("Unbinding.");

private OnClickListener mKillListener = new OnClickListener() { public void onClick(View v) {

// To kill the process hosting our service, we need to know its // PID. Conveniently our service has a call that will return // to us that information. if (mSecondaryService != null) { try {

int pid = mSecondaryService.getPid(); // Note that, though this API allows us to request to kill any process based on // its PID, the kernel will still impose standard restrictions on which PIDs you // are actually able to kill. Typically this means only the process running your // application and any additional processes created by that app as shown here; //packages sharing a common UID will also be able to kill each other's processes

Process.killProcess(pid);

mCallbackText.setText("Killed service process."); } catch (RemoteException ex) {

// Recover gracefully from the process hosting the server dying. // Just for purposes of the sample, put up a notification.

Toast.makeText(RemoteServiceBinding.this, R.string.remote call failed, Toast.LENGTH_SHORT).show();

// Code showing how to deal with callbacks.

// This implementation is used to receive callbacks from the remote service.

private IRemoteServiceCallback mCallback = new IRemoteServiceCallback.Stub()

* This is called by the remote service regularly to tell us about

* new values. Note that IPC calls are dispatched through a thread

* pool running in each process, so the code executing here will

* NOT be running in our main thread like most other things -- so,

* to update the UI, we need to use a Handler to hop over there. */

public void valueChanged(int value) {

mHandler.sendMessage(mHandler.obtainMessage(BUMP MSG, value, 0));

private static final int BUMP_MSG = 1;

private Handler mHandler = new Handler() {

@Override public void handleMessage(Message

msg) {

switch (msg.what) {

case BUMP MSG:

mCallbackText.setText("Received

from service: " + msg.arg1);

break;

default:

super.handleMessage(msg);

}

}

};

}

0 0

Post a comment