2013年9月19日 星期四

Android App communication through binder to user-space (IPC)

Ref.
http://wangkuiwu.github.io/2014/09/03/Binder-ServiceManager-Daemon/

[The example is a system app send message through binder to mediaserver audio]
Target:
1.
external/sepolicy/system_app.te

type system_app, domain;
app_domain(system_app)
net_domain(system_app)
### begin issue: ###
binder_use(system_app)
binder_call(system_app, binderservicedomain)
binder_call(system_app, appdomain)
### end issue: ###
binder_service(system_app)

2.
external/sepolicy/service_contexts

media.audio_flinger                       u:object_r:mediaserver_service:s0
### begin issue: ###
media.audio_openal                       u:object_r:mediaserver_service:s0
### end issue: ###
media.audio_policy                        u:object_r:mediaserver_service:s0


3.
device/fsl/matrix_io/matrix_io.mk

...
...
...
SUPPORT_OPENAL := true

ifeq ($(SUPPORT_OPENAL),true)
PRODUCT_PACKAGES += OpenalConfig
PRODUCT_COPY_FILES += \
    frameworks/av/media/libnbaio/default-44100.mhr:system/media/audio/default-44100.mhr \
    frameworks/av/media/libnbaio/default-48000.mhr:system/media/audio/default-48000.mhr \
    frameworks/av/media/libnbaio/eq.txt:system/media/audio/eq.txt
endif

4.
frameworks/av/media/mediaserver

#include "SoundTriggerHwService.h"
#include "RadioService.h"
/*begin issue:*/
#include <media/nbaio/AudioStreamOutSink.h>
/*end issue:*/

MediaPlayerService::instantiate();
        /*begin issue:*/
#ifdef    AL_ALEXT_PROTOTYPES
        OpenAlStreamMessage::instantiate();
#endif
        /*end issue:*/
        ResourceManagerService::instantiate();

5.
frameworks/av/include/media/nbaio/AudioStreamOutSink.h

#ifndef ANDROID_AUDIO_STREAM_OUT_SINK_H
#define ANDROID_AUDIO_STREAM_OUT_SINK_H

#include <hardware/audio.h>
#include "NBAIO.h"
#include <binder/IInterface.h>
#include <binder/IBinder.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>

namespace android
{
#ifdef AL_ALEXT_PROTOTYPES
class IOpenAlStreamMessage: public IInterface
{
    public:
        enum
        {
            APP_MESSAGE = IBinder::FIRST_CALL_TRANSACTION,
        };

        //DECLARE_META_INTERFACE(OpenAlStreamMessage)
        static const android::String16 descriptor;
        static android::sp<IOpenAlStreamMessage> asInterface(const android::sp<android::IBinder>& obj);
        virtual const android::String16& getInterfaceDescriptor() const;
        IOpenAlStreamMessage();
        virtual ~IOpenAlStreamMessage();

        virtual void BindMessage(int command) = 0;
};

/****************************************************/
/****************************************************/
/****************************************************/
class BpOpenAlStreamMessage : public BpInterface<IOpenAlStreamMessage>
{
    public:
        BpOpenAlStreamMessage(const sp<IBinder>& impl) : BpInterface<IOpenAlStreamMessage>(impl)
        {
        }

        virtual void BindMessage(int32_t val);
};
/****************************************************/
/****************************************************/
/****************************************************/
class BnOpenAlStreamMessage : public BnInterface<IOpenAlStreamMessage>
{
public:
    virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
};

class OpenAlStreamMessage :  public BnOpenAlStreamMessage
{
public:
    static  void instantiate();

    OpenAlStreamMessage();
    ~OpenAlStreamMessage();

    virtual void BindMessage(int command);
};
#endif
...
...
...
}   // namespace android

#endif  // ANDROID_AUDIO_STREAM_OUT_SINK_H

6.
frameworks/av/media/libnbaio/AudioStreamOutSink.cpp

namespace android
{
#ifdef    AL_ALEXT_PROTOTYPES
const android::String16 IOpenAlStreamMessage::descriptor("media.audio_openal");
android::sp<IOpenAlStreamMessage> IOpenAlStreamMessage::asInterface(const android::sp<android::IBinder>& obj)
{
    android::sp<IOpenAlStreamMessage> intr;

    if (obj != NULL)
    {
        intr = static_cast<IOpenAlStreamMessage*>(obj->queryLocalInterface(IOpenAlStreamMessage::descriptor).get());
        if (intr == NULL)
        {
            intr = new BpOpenAlStreamMessage(obj);
        }
    }

    return intr;
}
const android::String16& IOpenAlStreamMessage::getInterfaceDescriptor() const
{
    return IOpenAlStreamMessage::descriptor;
}
IOpenAlStreamMessage::IOpenAlStreamMessage()
{
}
IOpenAlStreamMessage::~IOpenAlStreamMessage()
{
}

/****************************************************/
/****************************************************/
/****************************************************/
void BpOpenAlStreamMessage::BindMessage(int32_t val)
{
    Parcel data, reply;
    data.writeInterfaceToken(IOpenAlStreamMessage::getInterfaceDescriptor());
    data.writeInt32(val);
    remote()->transact(APP_MESSAGE, data, &reply);
}

/****************************************************/
/****************************************************/
/****************************************************/
status_t BnOpenAlStreamMessage::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch(code)
    {
        case APP_MESSAGE:
        {
            CHECK_INTERFACE(IOpenAlStreamMessage, data, reply);
            int32_t val;
            val = data.readInt32();
            BindMessage(val);
            return NO_ERROR;
        }
        break;

        default:
            return BBinder::onTransact(code, data, reply, flags);
    }
}

/****************************************************/
/****************************************************/
/****************************************************/
void OpenAlStreamMessage::instantiate()
{
    defaultServiceManager()->addService(String16("media.audio_openal"), new OpenAlStreamMessage());
}

OpenAlStreamMessage::OpenAlStreamMessage()
{
}

OpenAlStreamMessage::~OpenAlStreamMessage()
{
}

void OpenAlStreamMessage::BindMessage(int command)
{
    s_alsa_save =  command; //get message here
}
#endif
...
...
...
}

Client App:
1.
//A new system app
packages/apps/OpenalConfig/AndroidManifest.xml

package="com.android.openalconfig"
    android:sharedUserId="android.uid.system" -->add here
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
...
...
...

2.
packages/apps/OpenalConfig/Android.mk

### begin issue:  ###
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_PRELINK_MODULE := false ###--> add this important
LOCAL_JNI_SHARED_LIBRARIES := libmessagebinder ###--> add this for java load
LOCAL_PACKAGE_NAME := OpenalConfig
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_SDK_VERSION := current
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)

# Use the folloing include to make our test apk.
include $(call all-makefiles-under,$(LOCAL_PATH))
### end issue:  ###

3.
packages/apps/OpenalConfig/jni/Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE := libmessagebinder
LOCAL_CFLAGS := -std=c++11

LOCAL_C_INCLUDES := \
../../../system/core/include \
../../../frameworks/av/include \
../../../frameworks/native/include

LOCAL_SRC_FILES  := \
../cc_src/jniapi.cpp \
../cc_src/interfacefuncs.cpp

### installed app build by ndk toolchain ###
#LOCAL_LDLIBS := \
#-L../../../../out/matrix_io/android/target/product/matrix_io/symbols/system/lib/ \
#-llog \
#-lutils \
#-lbinder

### system app build by mm ###
LOCAL_SHARED_LIBRARIES := \
liblog \
libutils \
libbinder
include $(BUILD_SHARED_LIBRARY)

4.
packages/apps/OpenalConfig/cc_src/jniapi.cpp

#include <jni.h>
#include <android/native_window.h> // requires ndk r5 or newer
#include <android/native_window_jni.h> // requires ndk r5 or newer
#include <binder/IInterface.h>
#include <binder/IBinder.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include "interfacefuncs.h"
#include "jniapi.h"

JNIEXPORT void JNICALL  Java_com_android_openalconfig_OpenalConfig_nativeBindMessage(JNIEnv* env, jobject obj, jint command)
{
    Interface_BindMessage(env, obj, command);
}

5.
packages/apps/OpenalConfig/cc_src/interfacefuncs.h


#ifndef INTERFACEFUNCS_H__
#define INTERFACEFUNCS_H__

namespace android
{

class IOpenAlStreamMessage: public IInterface
{
    public:
        enum
        {
            APP_MESSAGE = IBinder::FIRST_CALL_TRANSACTION,
        };

        //DECLARE_META_INTERFACE(OpenAlStreamMessage)
        static const android::String16 descriptor;
        static android::sp<IOpenAlStreamMessage> asInterface(const android::sp<android::IBinder>& obj);
        virtual const android::String16& getInterfaceDescriptor() const;
        IOpenAlStreamMessage();
        virtual ~IOpenAlStreamMessage();

        virtual void BindMessage(int command) = 0;
};

class BpOpenAlStreamMessage : public BpInterface<IOpenAlStreamMessage>
{
    public:
        BpOpenAlStreamMessage(const sp<IBinder>& impl) : BpInterface<IOpenAlStreamMessage>(impl)
        {
        }

        virtual void BindMessage(int32_t val);
};

}

extern void Interface_BindMessage(JNIEnv* env, jobject obj, jint command);

#endif // AndroidUtils_h__

6.
packages/apps/OpenalConfig/cc_src/interfacefuncs.cpp

#include <stdio.h>
#include <jni.h>
#include <android/log.h>
#include <binder/IInterface.h>
#include <binder/IBinder.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include "interfacefuncs.h"

using namespace android;

static JavaVM*     s_JavaVM = NULL;
static int             s_loop = 0;

extern "C"
{
    JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
    {
        JNIEnv* env;

        if (vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK)
        {
            return -1;
        }

        s_JavaVM = vm; //save to use this for the rest of the app.  Not neccesarily safe to use the Env passed in though.

        return JNI_VERSION_1_4;
    }
}

static JNIEnv* GetJavaEnv()
{
    JNIEnv *env = NULL;
    s_JavaVM->GetEnv((void **)&env, JNI_VERSION_1_4);

    if (!env)
    {
        return NULL;
    }

    return env;
}

/****************************************************/
/****************************************************/
/****************************************************/
const android::String16 IOpenAlStreamMessage::descriptor("media.audio_openal");
android::sp<IOpenAlStreamMessage> IOpenAlStreamMessage::asInterface(const android::sp<android::IBinder>& obj)
{
    android::sp<IOpenAlStreamMessage> intr;

    if (obj != NULL)
    {
        intr = static_cast<IOpenAlStreamMessage*>(obj->queryLocalInterface(IOpenAlStreamMessage::descriptor).get());
        if (intr == NULL)
        {
            intr = new BpOpenAlStreamMessage(obj);
        }
    }

    return intr;
}
const android::String16& IOpenAlStreamMessage::getInterfaceDescriptor() const
{
    return IOpenAlStreamMessage::descriptor;
}
IOpenAlStreamMessage::IOpenAlStreamMessage()
{
}
IOpenAlStreamMessage::~IOpenAlStreamMessage()
{
}

/****************************************************/
/****************************************************/
/****************************************************/
void BpOpenAlStreamMessage::BindMessage(int32_t val)
{
    Parcel data, reply;
    data.writeInterfaceToken(IOpenAlStreamMessage::getInterfaceDescriptor());
    data.writeInt32(val);
    remote()->transact(APP_MESSAGE, data, &reply);
}

/****************************************************/
/****************************************************/
/****************************************************/
void Interface_BindMessage(JNIEnv* env, jobject obj, jint command)
{
    sp<IBinder> binder = defaultServiceManager()->getService(String16("media.audio_openal"));
    sp<IOpenAlStreamMessage> pfunc = interface_cast<IOpenAlStreamMessage>(binder);

    pfunc->BindMessage(command);
}

Download:
http://www.mediafire.com/file/84qu8sdml46a104/binder.tar.gz

沒有留言:

張貼留言