Samuel Skånberg
Samuel Skånberg

Reputation: 96

How to connect to a binder C++ service in java?

I want to create a binder service in C++ and be able to bind to that service from java. My question is how? I have mimicked the implementation in frameworks/base/camera/tests/CameraServiceTest/ CameraServiceTest.cpp. It compiles nicely without any warnings and I can run it. But how do I connect to it?

The code for the service is here:

/* Imitating frameworks/base/camera/tests/CameraServiceTest/
CameraServiceTest.cpp */

#include <binder/IInterface.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <binder/IBinder.h>

using namespace android;


class IPokeService : public IInterface {
        protected:
                enum {
                        POKE = IBinder::FIRST_CALL_TRANSACTION
                };

        public:
                DECLARE_META_INTERFACE(PokeService);
                virtual void poke() = 0;
};

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

class BpPokeService : public BpInterface<IPokeService> {
        public:
                BpPokeService(const sp<IBinder>& impl) :
BpInterface<IPokeService>(impl) {
                }

                virtual void poke() {
                        Parcel data, reply;
                        remote()->transact(POKE, data, &reply);
                }
};

IMPLEMENT_META_INTERFACE(PokeService, "PokeService");

status_t BnPokeService::onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags) {
        switch(code) {
                case POKE: {
                          poke();
                          return NO_ERROR;
                } break;
                default:
                        return BBinder::onTransact(code, data, reply, flags);
        }
}

class PokeService : public BnPokeService {
        virtual void poke() {
                printf("Poked\n");
        }
};

int main(int argc, char **argv)
{
        defaultServiceManager()->addService(String16("PokeService"), new
PokeService());
        ProcessState::self()->startThreadPool();

        android::ProcessState::self()->startThreadPool();
        LOGI("Poke service is now ready");
        IPCThreadState::self()->joinThreadPool();

        return 0;
}

And here is my Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES := main.cpp

LOCAL_CFLAGS += -DPLATFORM_ANDROID

LOCAL_MODULE := poke

# for now, until I do a full rebuild.
LOCAL_PRELINK_MODULE := false

LOCAL_SHARED_LIBRARIES += liblog
LOCAL_SHARED_LIBRARIES += libutils libui libcutils
LOCAL_SHARED_LIBRARIES += libbinder

include $(BUILD_EXECUTABLE)

The service won't show up when I do a listing in java:

Context context = getBaseContext();
ActivityManager am = (ActivityManager)
context.getSystemService(Activity.ACTIVITY_SERVICE);

List<RunningServiceInfo> serviceInfos = am.getRunningServices(50);

for (RunningServiceInfo service : serviceInfos) {
        Log.i("Service", "Process " + service.process + " with component " + service.service.getClassName());
}

That will only give me from logcat:

I/Service (  715): Process system with component
com.android.internal.service.wallpaper.ImageWallpaper
I/Service (  715): Process com.android.phone with component
com.android.phone.BluetoothHeadsetService
I/Service (  715): Process com.android.inputmethod.latin with
component com.android.inputmethod.latin.LatinIME

Any help would be appreciated!

Kind regards, Samuel

Upvotes: 3

Views: 7702

Answers (2)

srinivas
srinivas

Reputation: 21

You can't get Service handle by using getSystemService() because your's is not a default system service. To work with your service you need to Use JNI and Call the

sm = defaultServiceManager();       
binder=sm->getService(String16("SERVICENAME"));
itf=interface_cast<IMul>(binder);

Yoou can call any API exposed by interface with itf Interface pointer.

Upvotes: 2

Chris Stratton
Chris Stratton

Reputation: 40337

My understanding is that you can't, because there isn't any way provided for the client application to get a target handle to you.

If you were writing a privileged native service, you could register with the binder driver under your chosen name, but presumably you aren't an oem in possession of the system certificate for the device.

A typical java-type service causes handle generation based on intents rather than a binder service name, but you'd have to do a lot of discouraged faking of the existing interface to binder in order to be able to handle that from native code rather than from java.

If you don't want to go back up through jni and do it from java, it's probably better to use unix domain sockets rather than binder.

(sorry if I'm using the wrong terms - I was looking into this in extreme detail a month ago, found a couldn't do what I wanted and dropped it)

Upvotes: 2

Related Questions