Home > Uncategorized > Using Android IPC binders from native code

## Using Android IPC binders from native code

This is a follow-up (with actual code examples) to a post I wrote a while ago on how to use the Android IPC system from native C++ code. The code is hosted on GitHub at Android IPC binder demo. A number of readers have asked for sample code after reading the previous post, so hopefully this helps.

When executed without any arguments, the binary acts as a service (named “Demo”). When executed with an integer argument (ex: “binder 743”), the binary acts as a client that searches for the “Demo” service, binds to it, and exercises its API. To keep things simple, there’s virtually no error checking. Some debug messages are sent to stdout, and others to logcat.

The suggested way to run this demo to have 3 windows open and issue the following commands in them:

1. adb logcat -v time binder_demo:* *:S

Now for a brief explanation of the code. The IInterface, BpInterface, and BnInterface classes are provided by the Android framework.

We start by defining an interface (think AIDL) that will be shared between the service and the client:

class IDemo : public IInterface {
public:
enum {
PUSH,
};
// Sends a user-provided value to the service
virtual void        push(int32_t data)          = 0;
// Sends a fixed alert string to the service
// Requests the service to perform an addition and return the result
virtual int32_t     add(int32_t v1, int32_t v2) = 0;

DECLARE_META_INTERFACE(Demo);
};

// This implementation macro would normally go in a cpp file
IMPLEMENT_META_INTERFACE(Demo, "Demo");


Next we define the server end, which is made up of 2 classes: BnDemo, and its derived class, Demo. BnDemo extracts the arguments from the data Parcel sent by the client, calls the appropriate virtual function (implemented in the Demo class) to do the heavy-lifting, and packs the returned values (if any) into a reply Parcel to be sent back to the client.

class BnDemo : public BnInterface<IDemo> {
virtual status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags = 0);
};

status_t BnDemo::onTransact(uint32_t code, const Parcel& data,

data.checkInterface(this);

switch(code) {
return NO_ERROR;
} break;
case PUSH: {
push(inData);
return NO_ERROR;
} break;
return NO_ERROR;
} break;
default:
}
}



This is the Demo class, which would normally do the real work on the service side of the binder.

class Demo : public BnDemo {
virtual void push(int32_t data) {
// Do something with the data the client pushed
}
}
virtual int32_t add(int32_t v1, int32_t v2) {
return v1 + v2;
}
};


Now we define a service proxy, to be used on the client side. Notice again that any data the client needs to send to the service is packed in a Parcel and results (if any) are also returned in a Parcel.

class BpDemo : public BpInterface<IDemo> {
public:
BpDemo(const sp<IBinder>& impl) : BpInterface<IDemo>(impl) { }

virtual void push(int32_t push_data) {
data.writeInterfaceToken(IDemo::getInterfaceDescriptor());
data.writeInt32(push_data);
}

data.writeInterfaceToken(IDemo::getInterfaceDescriptor());
}

virtual int32_t add(int32_t v1, int32_t v2) {
data.writeInterfaceToken(IDemo::getInterfaceDescriptor());
data.writeInt32(v1);
data.writeInt32(v2);

int32_t res;
return res;
}
};


Finally, we start the service as follows:

        defaultServiceManager()->addService(String16("Demo"), new Demo());


And the client can now connect to the service and call some of the provided functions:

    sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("Demo"));
sp<IDemo> demo = interface_cast<IDemo>(binder);

demo->push(65);


There’s a lot more that could be said, but I’m not planning on writing the book on the subject. If you’ve made it this far, you should be able to figure out the rest. The full compilable code is at BinderDemo.

Categories: Uncategorized Tags:
1. September 1st, 2012 at 16:52 | #1

Hey, I got BinderDemo working. Fan-tas-tic. But I need to run the server instance as root. Otherwise the client will not get a binder instance. Is this correct? Thanks,
Timur

2. April 25th, 2013 at 03:32 | #2

hi,
may I ask how to compile this code?
I got NDK, but still missing some library, I think this belong to framework.
So I got framework code, but how to set environment to compile in command line?

Thanks.

3. June 11th, 2013 at 17:14 | #3

HI,
I’m trying to create a native service on Android, which is similar to your demo. But when I try to compile the codes, it seems that there are some libs missing. Could you give out some details on how you compile the codes?

• June 12th, 2013 at 20:33 | #4

Make sure you have the Android NDK properly installed, and that you can build one of the sample NDK applications first, before attempting to build BinderDemo.

4. June 27th, 2013 at 11:32 | #5

Can I have the service written on native side and Java client use this service?

• June 28th, 2013 at 00:29 | #6

You should be able to.

5. October 3rd, 2013 at 01:59 | #7

Can I have the service written on Java side and let a native client to use it?

6. February 12th, 2014 at 10:52 | #8

There are couple minor modifications required to make it work on latest KitKat:
– LOGD macro is now ALOGD
– text output is now under #include , not in utils
– frameworks/native/include has to be added to LOCAL_C_INCLUDES

Thank you for the great example!

7. November 18th, 2014 at 00:04 | #9

Thank you for your wonderful explanation. I was very much in in need of the binder framework in android NDK. helped me a lot 🙂