Android Binder框架实现之Binder Native Service的Java调用流程

Android Binder框架实现之Binder Native Service的Java调用流程


Android Binder框架实现目录:

Android Binder框架实现之Binder的设计思想
Android Binder框架实现之何为匿名/实名Binder
Android Binder框架实现之Binder中的数据结构
Android Binder框架实现之Binder相关的接口和类
Android Binder框架实现之Parcel详解之基本数据的读写
Android Binder框架实现之Parcel read/writeStrongBinder实现
Android Binder框架实现之servicemanager守护进程
Android Binder框架实现之defaultServiceManager()的实现
Android Binder框架实现之Native层addService详解之请求的发送
Android Binder框架实现之Native层addService详解之请求的处理
Android Binder框架实现之Native层addService详解之请求的反馈
Android Binder框架实现之Binder服务的消息循环
Android Binder框架实现之Native层getService详解之请求的发送
Android Binder框架实现之Native层getService详解之请求的处理
Android Binder框架实现之Native层getService详解之请求的反馈
Android Binder框架实现之Binder Native Service的Java调用流程
Android Binder框架实现之Java层Binder整体框架设计
Android Binder框架实现之Framework层Binder服务注册过程源码分析
Android Binder框架实现之Java层Binder服务跨进程调用源码分析
Android Binder框架实现之Java层获取Binder服务源码分析




引言


  在前面的篇章中,是基于C/C++层和Binder驱动层对Binder机制进行了介绍。本文将以Java的视角,从Java引用开始,逐步的分析Java Client端是如何与Binder Native Server进行交互的。本文的例子还是选取MediaPlayer。如果单纯的是调用逻辑,不需要这么复杂,因为MediaPlayer牵涉到了许多的业务逻辑,所以Android里面的封装比较复杂,如果是简单的Java层调用Binder Native Service可以参见我的博客Java直接调用Native Binder Service的介绍。

注意:本篇的介绍是基于Android 7.xx平台为基础的,其中牵涉的路径如下:

frameworks/native/libs/binder/IServiceManager.cpp
frameworks/native/libs/binder/Static.cpp
frameworks/native/libs/binder/ProcessState.cpp
kernel/drivers/staging/android/binder.c
kernel/include/linux/list.h
kernel/drivers/staging/android/uapi/binder.h
external/kernel-headers/original/uapi/linux/android/binder.h
frameworks/native/include/binder/ProcessState.h
frameworks/native/include/binder/BpBinder.h
frameworks/native/libs/binder/BpBinder.cpp
frameworks/native/include/binder/IPCThreadState.h
frameworks/native/libs/binder/IPCThreadState.cpp
frameworks/native/include/binder/IInterface.h
frameworks/native/libs/binder/IInterface.cpp
frameworks/native/include/binder/IBinder.h
frameworks/native/libs/binder/Binder.cpp
frameworks/av/media/mediaserver/main_mediaserver.cpp
frameworks/native/cmds/servicemanager/service_manager.c



1.MediaPlayer简单使用实例

下面我们以最简单的MediaPlayer播放音乐为实例,来演示MediaPlayer的使用。

    private void playMusic() {
        try {
            MediaPlayer mp = new MediaPlayer();
            mp.setDataSource("/sdcard/binder.mp3");//看来我是疯了,
            mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
            mp.prepare();
            mp.start();
        } catch (Exception e) {
            e.printStackTrace();
        }   
    } 

源码超级简单,只需要关注testMediaPlayer()部分即可。首先,新建一个MediaPlayer对象。接着,设置数据源和音频流类型。最后,调用prepare()进行准备之后,再通过start()进行播放。当然这个只是演示代码,在实际的MediaPlayer应用开发中,不止如此。

下面,我们就对该过程进行分析,看看该Binder机制是如何参与其中的。




2.MediaPlayer客户端进程调用流程分析

我们将该MediaPlayer示例App看作一个MediaPlayer客户端进程,接下来,就看看这个MediaPlayer客户端进程是如何通过Binder机制来和MediaPlayerService通信的。重点需要关注的是mp.setDataSource()的实现。


2.1 MediaPlayer的构造函数

Java世界里,对一个类的分析一般从构造函数开始,当然我们的MediaPlayer也不例外。

    private static native final void native_init();
    private native final void native_setup(Object mediaplayer_this);
    private native final void native_finalize();
    private long mNativeContext; // accessed by native methods
    
    public MediaPlayer() {
		...
        native_setup(new WeakReference<MediaPlayer>(this));
    }

    static {
        System.loadLibrary("media_jni");//加载so库
        native_init();//初始化
    }

该代码在frameworks/base/media/java/android/media/MediaPlayer.java中。在MediaPlayer的默认构造方法中,会调用本地方法native_setup()。而且在native_setup()之前,会调用静态方法加载so库并且调用native_init()进行初始化。下面就看看native_init()和native_setup()各自的代码。


2.2 native_init()和native_setup()的注册信息

static const JNINativeMethod gMethods[] = {
	...
    {"_setDataSource",      "(Ljava/io/FileDescriptor;JJ)V",    (void *)android_media_MediaPlayer_setDataSourceFD},
	...
    {"_start",              "()V",                              (void *)android_media_MediaPlayer_start},
   	...
    {"native_init",         "()V",                              (void *)android_media_MediaPlayer_native_init},
    {"native_setup",        "(Ljava/lang/Object;)V",            (void *)android_media_MediaPlayer_native_setup},
    ...
};

static int register_android_media_MediaPlayer(JNIEnv *env)
{
    return AndroidRuntime::registerNativeMethods(env,
                "android/media/MediaPlayer", gMethods, NELEM(gMethods));
}

jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{
    JNIEnv* env = NULL;
    jint result = -1;

    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
        ALOGE("ERROR: GetEnv failed\n");
        goto bail;
    }
    assert(env != NULL);
	...
    if (register_android_media_MediaPlayer(env) < 0) {
        ALOGE("ERROR: MediaPlayer native registration failed\n");
        goto bail;
    }
    ...
    /* success -- return valid version number */
    result = JNI_VERSION_1_4;

bail:
    return result;

代码在frameworks/base/media/jni/android_media_MediaPlayer.cpp中,这里教读者一个比较快的查找Java类对应的JNI文件的文件名的快捷方式,譬如我们这里的MediaPlayer的类的全程是android.media.MediaPlayer,然后将.切换成_可以得到android_media_MediaPlayer然后再在后面加上.cpp就是对应的文件名了。这个查找方法在Android中很管用,不信的话读者可以多找几个类试试。gMethods是JNI本地方法的注册表;在Dalvik虚拟机启动之后,会调用JNI_OnLoad();进而将上面的方法注册到系统中。这里,我们只需要了解native_init()与android_media_MediaPlayer_native_init()对应,而native_setup()和android_media_MediaPlayer_native_setup()对应即可。


2.3 native_init()的实现

通过前面的章节,我们知道native_init()与android_media_MediaPlayer_native_init()对应,下面就看看native_init()的实现。

static void
android_media_MediaPlayer_native_init(JNIEnv *env)
{
    jclass clazz;

    clazz = env->FindClass("android/media/MediaPlayer");
    if (clazz == NULL) {
        return;
    }
    fields.context = env->GetFieldID(clazz, "mNativeContext", "J");
    if (fields.context == NULL) {
        return;
    }
    ...
}

该代码在frameworks/base/media/jni/android_media_MediaPlayer.cpp中。
env->FindClass(“android/media/MediaPlayer”)会加载Java层的MediaPlayer类;进而将fields.context初始化为MediaPlayer类中的mNativeContext成员。


2.4 native_setup()的实现

由于native_setup()和android_media_MediaPlayer_native_setup()对应,下面就看看native_setup()的实现。

static void
android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{	
	...
    sp<MediaPlayer> mp = NULL;
   	mp = new MediaPlayer();
	...
    setMediaPlayer(env, thiz, mp);
}

该函数会新建一个MediaPlayer对象,然后调用setMediaPlayer()来保存该MediaPlayer对象。下面看看setMediaPlayer()是如何保存MediaPlayer对象的。


2.5 setMediaPlayer()

static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player)
{
    Mutex::Autolock l(sLock);
    sp<MediaPlayer> old = (MediaPlayer*)env->GetLongField(thiz, fields.context);
    if (player.get()) {
        player->incStrong((void*)setMediaPlayer);
    }
    if (old != 0) {
        old->decStrong((void*)setMediaPlayer);
    }
    env->SetLongField(thiz, fields.context, (jlong)player.get());
    return old;
}

通过SetIntField()会将MediaPlayer对象保存到fields.context中。而在前面的,我们将fields.context初始化为MediaPlayer类(Java层)中的mNativeContext成员。这也就意味着,设置了Java层的MediaPlayer中的mNativeContext成员的值为C++层MediaPlayer对象。
至此,就分析完了MediaPlayer的构造函数。下面继续看MediaPlayer客户端进程示例代码中的mp.setDataSource("/sdcard/binder.mp3")。


2.6 setDataSource()

    public void setDataSource(String path)
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
        setDataSource(path, null, null);
    }

    public void setDataSource(String path, Map<String, String> headers)
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException
    {
		...
        setDataSource(path, keys, values);
    }
    private void setDataSource(String path, String[] keys, String[] values)
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
		...
        final File file = new File(path);
        if (file.exists()) {
            FileInputStream is = new FileInputStream(file);
            FileDescriptor fd = is.getFD();
            setDataSource(fd);
            is.close();
        } else {
            ...
        }
    }
    public void setDataSource(FileDescriptor fd)
            throws IOException, IllegalArgumentException, IllegalStateException {
        setDataSource(fd, 0, 0x7ffffffffffffffL);
    }

    public void setDataSource(FileDescriptor fd, long offset, long length)
            throws IOException, IllegalArgumentException, IllegalStateException {
        _setDataSource(fd, offset, length);
    }

    private native void _setDataSource(FileDescriptor fd, long offset, long length)
            throws IOException, IllegalArgumentException, IllegalStateException;

该代码在frameworks/base/media/java/android/media/MediaPlayer.java中。setDataSource()最终会调用到本地方法setDataSource()。在前面的gMethods本地方法注册表中,将setDataSource()和android_media_MediaPlayer_setDataSourceFD()匹配。下面,看看_setDataSource()的实现。


2.7 android_media_MediaPlayer_setDataSourceFD()

static void
android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
{
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
	...
    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
	...
    process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
}

该代码在frameworks/base/media/jni/android_media_MediaPlayer.cpp中。该函数会先通过getMediaPlayer()获取MediaPlayer对象,然后在执行mp->setDataSource()时会调用MediaPlayer的setDataSource()方法。


2.8 getMediaPlayer()

static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz)
{
    Mutex::Autolock l(sLock);
    MediaPlayer* const p = (MediaPlayer*)env->GetLongField(thiz, fields.context);
    return sp<MediaPlayer>(p);
}

前面在native_setup()中,将fields.context设置为MediaPlayer对象。这里就是返回fields.context中保存的MediaPlayer对象。


2.9 MediaPlayer::setDataSource

status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
{
    ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
    status_t err = UNKNOWN_ERROR;
    //通过getMediaPlayerService()获取MediaPlayerService的代理BpMediaPlayerService。
    const sp<IMediaPlayerService> service(getMediaPlayerService());
    if (service != 0) {
    	// 通过BpMediaPlayerService创建一个IMediaPlayer客户端
        sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
        if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
            (NO_ERROR != player->setDataSource(fd, offset, length))) {
            player.clear();
        }
        err = attachNewPlayer(player);
    }
    return err;
}

该代码在frameworks/av/media/libmedia/mediaplayer.cpp中,该代码主要做了如下几个事情:
(1) 它会新建一个service对象,而service是通过getMediaPlayerService()获取到的。getMediaPlayerService()已经在"getService请求"时,详细分析过了。它会返回IMediaPlayerService的代理,即BpMediaPlayerService对象。
(2) 接着,会调用service->create()返回一个IMediaPlayer对象。下面看看这个MediaPlayer进程是如何通过BpMediaPlayerService这个远程代理来获取IMediaPlayer对象的。


2.10 BpMediaPlayerService::create()

    virtual sp<IMediaPlayer> create(
            const sp<IMediaPlayerClient>& client, audio_session_t audioSessionId) {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
        data.writeStrongBinder(IInterface::asBinder(client));
        data.writeInt32(audioSessionId);

        remote()->transact(CREATE, data, &reply);
        return interface_cast<IMediaPlayer>(reply.readStrongBinder());
    }

该代码在frameworks/av/media/libmedia/IMediaPlayerService.cpp中。
这里无非是CREATE请求数据打包之后发送给Binder驱动,再由Binder驱动转发给MediaPlayerService进程。数据的发送和解析,在前面介绍"addService"和"getService"时已经多次介绍过了;这里就不再展开说明了。

Binder驱动在收到MediaPlayer的数据之后,会将添加一个事务到MediaPlayerService的待处理事务列表中,然后唤醒MediaPlayerService。下面就从MediaPlayerService被唤醒之后开始说明。


2.11 Binder驱动中binder_thread_read()的源码

又回到了让我魂牵梦绕的binder_thread_read()中。

static int binder_thread_read(struct binder_proc *proc,
			      struct binder_thread *thread,
			      binder_uintptr_t binder_buffer, size_t size,
			      binder_size_t *consumed, int non_block)
{
	...
	if (wait_for_proc_work) {
		...
		if (non_block) {
			...
		} else
			//阻塞式读取,阻塞等待事务的发生,此时会被唤醒
			ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
	} else {
		...
	}
	...
	while (1) {
		uint32_t cmd;
		struct binder_transaction_data tr;
		struct binder_work *w;
		struct binder_transaction *t = NULL;

		//如果当前线程的“待完成工作”不为空,则取出待完成工作
		if (!list_empty(&thread->todo))
			w = list_first_entry(&thread->todo, struct binder_work, entry);
		else if (!list_empty(&proc->todo) && wait_for_proc_work)
			w = list_first_entry(&proc->todo, struct binder_work, entry);
		else {
			...
		}

		...

		switch (w->type) {
		case BINDER_WORK_TRANSACTION: {
			t = container_of(w, struct binder_transaction, work);
		} break;
			...
		}

		if (!t)
			continue;

		//此时t-buffer-target_node是目标节点。
		//这里,ediaPlayer的CREATE请求的目标是MediaPlayerService,因此target_node是MediaPlayerService对应的节点;
		if (t->buffer->target_node) {
			// 事务目标对应的Binder实体(即,MediaPlayerService对应的Binder实体)
			struct binder_node *target_node = t->buffer->target_node;
			 // Binder实体在用户空间的地址。
            // MediaPlayerService的ptr为本地Binder的弱引用,即BBinder的弱引用
			tr.target.ptr = target_node->ptr;
			 // Binder实体在用户空间的其它数据
            // MediaPlayerService的cookie为本地Binder本身,即BBinder对象
			tr.cookie =  target_node->cookie;
			t->saved_priority = task_nice(current);
			if (t->priority < target_node->min_priority &&
			    !(t->flags & TF_ONE_WAY))
				binder_set_nice(t->priority);
			else if (!(t->flags & TF_ONE_WAY) ||
				 t->saved_priority > target_node->min_priority)
				binder_set_nice(target_node->min_priority);
			cmd = BR_TRANSACTION;
		} else {
			...
		}
		//交易码,即CREATE
		tr.code = t->code;
		tr.flags = t->flags;
		tr.sender_euid = from_kuid(current_user_ns(), t->sender_euid);

		if (t->from) {
			struct task_struct *sender = t->from->proc->tsk;
			tr.sender_pid = task_tgid_nr_ns(sender,
							task_active_pid_ns(current));
		} else {
			tr.sender_pid = 0;
		}

		//数据大小
		tr.data_size = t->buffer->data_size;
		//数据中对象的偏移数组的大小(即对象的个数)
		tr.offsets_size = t->buffer->offsets_size;
		//数据
		tr.data.ptr.buffer = (binder_uintptr_t)(
					(uintptr_t)t->buffer->data +
					proc->user_buffer_offset);
		//数据中对象的偏移数组
		tr.data.ptr.offsets = tr.data.ptr.buffer +
					ALIGN(t->buffer->data_size,
					    sizeof(void *));

		//将cmd指令写入到ptr,即传递到用户空间
		if (put_user(cmd, (uint32_t __user *)ptr))
			return -EFAULT;
		//将tr数据拷贝到用户空间
		ptr += sizeof(uint32_t);
		if (copy_to_user(ptr, &tr, sizeof(tr)))
			return -EFAULT;
		ptr += sizeof(tr);

		...
		//删除已处理的事务
		list_del(&t->work.entry);
		t->buffer->allow_user_free = 1;
		//设置回复信息
		if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {
			...
		} else {
			t->buffer->transaction = NULL;
			kfree(t);
			binder_stats_deleted(BINDER_STAT_TRANSACTION);
		}
		break;
	}

done:
	//更新bwr.read_comsumed的值
	*consumed = ptr - buffer;
	...
	return 0;
}

MediaPlayerService被唤醒之后,binder_has_thread_work()为true。因为MediaPlayerService的待处理事务队列中有个待处理事务(即,MediaPlayer添加的CREATE请求)。
(1) 进入while循环后,首先取出待处理事务。
(2) 事务的类型是BINDER_WORK_TRANSACTION,得到对应的binder_transaction*类型指针t之后,跳出switch语句。很显然,此时t不为NULL,因此继续往下执行。下面的工作的目的,是将t中的数据转移到tr中(tr是事务交互数据包结构体binder_transaction_data对应的指针),然后将指令和tr数据都拷贝到用户空间,让MediaPlayerService读取后进行处理。

这里,共添加了两个指令到bwr.read_consumed中:BR_NOOP和BR_TRANSACTION。其中,BR_TRANSACTION指令对应的数据中包含了CREATE请求的数据。

接下来,binder_thread_read()返回到binder_ioctl()中;binder_ioctl()将数据拷贝到用户空间之后,便返回到用户空间继续执行。
而在Android Binder机制(九) Binder服务的消息循环中介绍过,MediaPlayerService是通过调用IPCThreadState::joinThreadPool()进入消息循环的,而joinThreadPool()又会通过getAndExecuteCommand()调用到talkWithDriver()来和Binder驱动交互的。因此,Binder驱动返回到用户空间之后,会进入talkWithDriver()。


2.12 IPCThreadState::talkWithDriver()

status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    ...
    do {
        ...
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        else
            ...
        ...
    } while (err == -EINTR);

    ...

    if (err >= NO_ERROR) {
        // 清空已写的数据
        if (bwr.write_consumed > 0) {
            if (bwr.write_consumed < (ssize_t)mOut.dataSize())
                mOut.remove(0, bwr.write_consumed);
            else
                mOut.setDataSize(0);
        }
        // 设置已读数据
        if (bwr.read_consumed > 0) {
            mIn.setDataSize(bwr.read_consumed);
            mIn.setDataPosition(0);
        }
        ...
        return NO_ERROR;
    }

    return err;
}

此时MediaPlayerService从Binder驱动中返回后,继续处理,talkWithDriver()会清除已经发送的数据。然后,便返回到getAndExecuteCommand()中。


2.13 IPCThreadState::getAndExecuteCommand()

status_t IPCThreadState::getAndExecuteCommand()
{
    status_t result;
    int32_t cmd;

    // 和Binder驱动交互
    result = talkWithDriver();
    if (result >= NO_ERROR) {
        ...
        // 读取mIn中的数据
        cmd = mIn.readInt32();
        ...

        // 调用executeCommand()对数据进行处理。
        result = executeCommand(cmd);
        ...
    }

    return result;
}

getAndExecuteCommand()会取出Binder反馈的指令,然后再调用executeCommand()根据指令进行解析。前面说过,Binder驱动共反馈了BR_NOOP和BR_TRANSACTION两个指令。而BR_NOOP指令什么也不会做。因此,我们直接分析BR_TRANSACTION指令。


2.14 IPCThreadState::executeCommand()

status_t IPCThreadState::executeCommand(int32_t cmd) 
{
    BBinder* obj; 
    RefBase::weakref_type* refs;
    status_t result = NO_ERROR;

    switch (cmd) {
        ...
        case BR_TRANSACTION:
        {
            binder_transaction_data tr;
            result = mIn.read(&tr, sizeof(tr));
            ...

            Parcel buffer;
            buffer.ipcSetDataReference(
                reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                tr.data_size,
                reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
                tr.offsets_size/sizeof(size_t), freeBuffer, this);

            ...

            Parcel reply;
            ...
            if (tr.target.ptr) {
                sp<BBinder> b((BBinder*)tr.cookie);
                const status_t error = b->transact(tr.code, buffer, &reply, tr.flags);
                if (error < NO_ERROR) reply.setError(error);

            } else {
                ...
            }

            if ((tr.flags & TF_ONE_WAY) == 0) {
                sendReply(reply, 0);
            } else {
                ...
            }
            ...

        }
        break;

        ...
    }

    ...
    return result;
}

进入BR_TRANSACTION分支后,首先通过mIn.read()读取事务数据。接着,调用ipcSetDataReference()将事务数据解析出来。很显然,tr.target.ptr不为空,它的值是"MediaPlayerService的BBinder的弱引用"。然后,就将tr.cookie转换为BBinder*对象b;而b实际上是MediaPlayerService的本地Binder实例,即BnMediaPlayerService的实例。最终,通过b->transact()进行事务处理。

下面看看BBinder的transact()代码。

status_t BBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    data.setDataPosition(0);

    status_t err = NO_ERROR;
    switch (code) {
        case PING_TRANSACTION:
            reply->writeInt32(pingBinder());
            break;
        default:
            err = onTransact(code, data, reply, flags);
            break;
    }

    if (reply != NULL) {
        reply->setDataPosition(0);
    }

    return err;
}

该代码在frameworks/native/libs/binder/Binder.cpp中。此时的code是CREATE,因此,它会调用onTransact()对事务进行处理。而BnMediaPlayerService重写了onTransact()方法;因此会调用到BnMediaPlayerService的onTransact()方法。在Binder机制中也是根据这种方式来实现不同Server的对各自的的请求进行区分处理的:Server的本地Binder实现类,通过覆盖onTransact()方法来处理事务。

下面看看BnMediaPlayerService的onTransact()方法。


2.15 BnMediaPlayerService::onTransact()

status_t BnMediaPlayerService::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch (code) {
        case CREATE: {
            ...
            sp<IMediaPlayerClient> client =
                interface_cast<IMediaPlayerClient>(data.readStrongBinder());
            int audioSessionId = data.readInt32();
            sp<IMediaPlayer> player = create(client, audioSessionId);
            reply->writeStrongBinder(player->asBinder());
            return NO_ERROR;
        } break;
        ...
    }
    ...
}

说明:该代码在frameworks/av/media/libmedia/IMediaPlayerService.cpp中。
(1) 先通过interface_cast宏获取IMediaPlayerClient对象,该对象是BpMediaPlayerClient实例。BpMediaPlayerClient定义在frameworks/av/media/libmedia/IMediaPlayer.cpp中。
(2) 接着,通过create()创建IMediaPlayerService对象。该create()的实现是在BnMediaPlayerService的子类MediaPlayerService.cpp中,即在frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp中实现。在create()中会新建一个Client,并返回。
(3) 最后,将这个Client通过Binder返回给MediaPlayer。

后面的流程就不再多说了。本文的核心是Binder机制,而不是MediaPlayer的框架,让我们了解MediaPlayer进程是如何与MediaPlayerService交互即可!而目前,通过CREATE请求,我们已经知道了MediaPlayer是如何和MediaPlayerService进行事务交互的。后面的内容更多的涉及到MediaPlayerService的框架,它不是本章的重点;感兴趣的读者可以自行研究。




写在最后

  在前面的章节,主要讲解了C/C++层Binder服务的添加和获取,本篇主要讲解了Java层怎么获取Native Binder Service,在后续的篇章里面会继续讲解怎么通过Java层Binder服务的添加和获取。这个的难度不是很大,因为绝大部分的还是在底层实现的,然后通过JNI再封装一层罢了。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值