美文网首页
Binder(一)

Binder(一)

作者: JackyWu15 | 来源:发表于2020-01-17 19:57 被阅读0次

    《Binder简介》一篇中,我们了解了Binder进程间通讯的大致执行原理,从这一篇开始,通过分析源码来认识Binder底层的调用过程。

    Binder结构

    Binder采用C/S结构的通讯方式,提供服务的为Server进程,访问的进程为Client进程,一个Server进程可以运行多个组件来为Client服务,这些组件称为Service组件。Client和Server进程都维护了自己的一个Binder线程池,因此,Client可以并发访问,Server也可以并发提供服务。每个Service组件在启动时,都会添加进ServiceManager中,它用来对组件进行统一管理。Client和Service组件由应用程序实现。ServiceManager和Binder驱动由系统实现。

    /dev/binder是Binder驱动对外暴露的设备文件,Client和Server进程,通过系统调用open、mmap和ioctl来访问/dev/binder文件,进而访问Binder驱动。我们知道,在Linux中,通过操作文件的方式,便能间接控制设备,因此,操作/dev/binder文件,就相当于在操作Binder驱动了。

    image.png

    MediaPlayer

    之所以选择MediaPlayer作为理解Binder的切入点,原因有二:一是媒体播放这种需求比较常见;二是,MediaPlayer (Client)需要通过底层MediaServer(Server)管理运行的组件MediaPlayerService,来实现上层播放功能,而MediaServer包含了许多重要的Service组件,如:

    • AudioFlinger:音频系统中的核心服务。
    • AudioPolicyService:音频系统中关于音频策略的重要任务。
    • CameraService:摄像/照相的重要服务。
    • MediaPlayerService:多媒体系统中的重要服务。

    但此篇主要分析上层MediaPlayer如何通过底层,来远程关联服务端的播放器,没有涉及过多的Binder知识,若熟悉此流程的读者可以跳过。

    MediaPlayer通常有2种创建方式:

      MediaPlayer mediaPlayer = new MediaPlayer();
      try {
           mediaPlayer.setDataSource( "http://xxxx" );
           mediaPlayer.prepareAsync();
      } catch (IOException e) {
           e.printStackTrace();
      }
      mediaPlayer.start();
    
    MediaPlayer mediaPlayer = MediaPlayer.create( context, R.raw.test);
    mediaPlayer.start();
    

    无论哪种方式,其调用执行流程都是相同的,我们以第一种为例开始分析,先看MediaPlayer 构造方法。

    public class MediaPlayer implements SubtitleController.Listener
    {
    
      static {
            System.loadLibrary("media_jni");
            native_init();
        }
    
     public MediaPlayer() {
          //构建AudioAttributes
           super((new Builder()).build(), 2);
    
            Looper looper;
            //myLooper不为null,构建EventHandler
            if ((looper = Looper.myLooper()) != null) {
                mEventHandler = new EventHandler(this, looper);
            //获取主线程Looper不为null,构建EventHandler
            } else if ((looper = Looper.getMainLooper()) != null) {
                mEventHandler = new EventHandler(this, looper);
            } else {
                mEventHandler = null;
            }
    
            this.mTimeProvider = new MediaPlayer.TimeProvider(this);
            this.mOpenSubtitleSources = new Vector();
            //构建弱引用,执行native_setup
            this.native_setup(new WeakReference(this));
            this.baseRegisterPlayer();
        }
    
    

    EventHandler用于处理底层回调过来的状态,用来回调用户设置的监听器。下面再分析。我们注意到静态代码块中加载了libmedia_jni.so,并调用native_init进行了初始化,它在android_media_MediaPlayer.cpp中。

    static void
    android_media_MediaPlayer_native_init(JNIEnv *env)
    {
        jclass clazz;
        //获取Java的MediaPlayer类
        clazz = env->FindClass("android/media/MediaPlayer");
        if (clazz == NULL) {
            return;
        }
        //获取mNativeContext变量id,保存到fields.context 
        fields.context = env->GetFieldID(clazz, "mNativeContext", "J");
        if (fields.context == NULL) {
            return;
        }
       //获取postEventFromNative方法id,保存到fields.post_event 
        fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
                                                   "(Ljava/lang/Object;IIILjava/lang/Object;)V");
        if (fields.post_event == NULL) {
            return;
        }
    
        fields.surface_texture = env->GetFieldID(clazz, "mNativeSurfaceTexture", "J");
        if (fields.surface_texture == NULL) {
            return;
        }
    
        //获取ProxyInfo类
        clazz = env->FindClass("android/net/ProxyInfo");
        if (clazz == NULL) {
            return;
        }
    
        fields.proxyConfigGetHost =
            env->GetMethodID(clazz, "getHost", "()Ljava/lang/String;");
    
        fields.proxyConfigGetPort =
            env->GetMethodID(clazz, "getPort", "()I");
    
        fields.proxyConfigGetExclusionList =
            env->GetMethodID(clazz, "getExclusionListAsString", "()Ljava/lang/String;");
    }
    

    先看fields是什么。

    struct fields_t {
        jfieldID    context;
        jfieldID    surface_texture;
    
        jmethodID   post_event;
    
        jmethodID   proxyConfigGetHost;
        jmethodID   proxyConfigGetPort;
        jmethodID   proxyConfigGetExclusionList;
    };
    static fields_t fields;
    

    初始化的工作就是将MediaPlayer.java中定义的一些字段或方法的ID保存到fields_t 这个结构体中。这是一种通过本地去初始化Java层的类成员的方法,比如mNativeContext字段,随后底层将构造一个本地MediaPlayer对象,将这个对象的地址保存到mNativeContext变量中,也就是说,每创建一个Java类的MediaPlayer对象,也将绑定了一个Native层的MediaPlayer对象。

    因此,从Native角度来说,我们平时使用的MediaPlayer.java像是底层暴露的一个接口类,实际的实现逻辑都是由底层处理的。由于Java层、Jni层和C++层用的名字都是MediaPlayer,为了描述方便,后面将用MediaPlayer.java、MediaPlayer.jni和MediaPlayer.cpp来做区分。

    我们再回头看MediaPlayer.java构造方法中,被调用的native_setup方法,它将当前对象以及对象弱引用传递给底层。

    static void
    android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
    {
       //构件MediaPlayer.cpp对象
        sp<MediaPlayer> mp = new MediaPlayer();
        if (mp == NULL) {
            jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
            return;
        }
    
        // 构建JNIMediaPlayerListener对象,传入了Java层对象引用和弱引用
        sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
        //保存到MediaPlayer.cpp对象中
        mp->setListener(listener);
    
        //将MediaPlayer.cpp对象保存到MediaPlayer.java的mNativeContext字段中
        setMediaPlayer(env, thiz, mp);
    }
    

    先来看MediaPlayer.cpp对象的构建。

    MediaPlayer::MediaPlayer()
    {
        ALOGV("constructor");
        mListener = NULL;
        mCookie = NULL;
        mStreamType = AUDIO_STREAM_MUSIC;//默认音频流类型
        mAudioAttributesParcel = NULL;
        mCurrentPosition = -1;
        mSeekPosition = -1;
        mCurrentState = MEDIA_PLAYER_IDLE;//初始状态为idle空闲状态
        mPrepareSync = false;
        mPrepareStatus = NO_ERROR;
        mLoop = false;  //不循环播放
        mLeftVolume = mRightVolume = 1.0;
        mVideoWidth = mVideoHeight = 0;
        mLockThreadId = 0;
        mAudioSessionId = AudioSystem::newAudioUniqueId();
        AudioSystem::acquireAudioSessionId(mAudioSessionId, -1);
        mSendLevel = 0;
        mRetransmitEndpointValid = false;
    }
    

    MediaPlayer.cpp构造函数只是对一些字段做了初始化,如设置默认的流类型为音频流,初始状态为空闲状态。

    JNIMediaPlayerListener声明了一个notify()函数,用于底层产生错误时,通知MediaPlayer.java抛出异常的。

    class JNIMediaPlayerListener: public MediaPlayerListener
    {
    public:
        JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
        ~JNIMediaPlayerListener();
        virtual void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
    private:
        JNIMediaPlayerListener();
        jclass      mClass;   //MediaPlayer.java对象引用的全局引用
        jobject     mObject;    //MediaPlayer.java对象弱引用的全局引用
    };
    
    JNIMediaPlayerListener::JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
    {
       // 获取MediaPlayer.java
        jclass clazz = env->GetObjectClass(thiz);
        if (clazz == NULL) {
            ALOGE("Can't find android/media/MediaPlayer");
            jniThrowException(env, "java/lang/Exception", NULL);
            return;
        }
        //创建对象引用的全局引用
        mClass = (jclass)env->NewGlobalRef(clazz);
        //创建对象弱引用的全局引用
        mObject  = env->NewGlobalRef(weak_thiz);
    }
    
    JNIMediaPlayerListener::~JNIMediaPlayerListener()
    {
         //释放引用
        JNIEnv *env = AndroidRuntime::getJNIEnv();
        env->DeleteGlobalRef(mObject);
        env->DeleteGlobalRef(mClass);
    }
    
    void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj)
    {
        JNIEnv *env = AndroidRuntime::getJNIEnv();
        if (obj && obj->dataSize() > 0) {
            jobject jParcel = createJavaParcelObject(env);
            if (jParcel != NULL) {
                Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
                nativeParcel->setData(obj->data(), obj->dataSize());
    
                //调用MediaPlayer.java对象的postEventFromNative静态方法
                env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
                        msg, ext1, ext2, jParcel);
                env->DeleteLocalRef(jParcel);
            }
        } else {
            env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
                    msg, ext1, ext2, NULL);
        }
        if (env->ExceptionCheck()) {
            ALOGW("An exception occurred while notifying an event.");
            LOGW_EX(env);
            env->ExceptionClear();
        }
    }
    

    JNIMediaPlayerListener为对象的引用和弱引用创建全局引用并保存起来。如果notify函数被调用了,将回调MediaPlayer.java的postEventFromNative方法。

     private static void postEventFromNative(Object mediaplayer_ref,
                                                int what, int arg1, int arg2, Object obj)
        {
          //获取弱引用
            MediaPlayer mp = (MediaPlayer)((WeakReference)mediaplayer_ref).get();
            if (mp == null) {
                return;
            }
    
            if (what == MEDIA_INFO && arg1 == MEDIA_INFO_STARTED_AS_NEXT) {
               mp.start();
            }
            //发送消息给EventHandler
            if (mp.mEventHandler != null) {
                Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj);
                mp.mEventHandler.sendMessage(m);
            }
        }
    

    EventHandler处理的状态比较多,我们只贴几个常见的。

      private class EventHandler extends Handler
        {
            private MediaPlayer mMediaPlayer;
            public EventHandler(MediaPlayer mp, Looper looper) {
                super(looper);
                mMediaPlayer = mp;
            }
    
            @Override
            public void handleMessage(Message msg) {
                //MediaPlayer.cpp为null
                if (mMediaPlayer.mNativeContext == 0) {
                    return;
                }
                //准备成功回调
                switch(msg.what) {
                case MEDIA_PREPARED:
                    scanInternalSubtitleTracks();
                    if (mOnPreparedListener != null)
                        mOnPreparedListener.onPrepared(mMediaPlayer);
                    return;
              //播放完成回调
                case MEDIA_PLAYBACK_COMPLETE:
                    if (mOnCompletionListener != null)
                        mOnCompletionListener.onCompletion(mMediaPlayer);
                    stayAwake(false);
                    return;
              //停止回调
                case MEDIA_STOPPED:
                    if (mTimeProvider != null) {
                        mTimeProvider.onStopped();
                    }
                    break;
               //暂停回调
                case MEDIA_STARTED:
                case MEDIA_PAUSED:
                    if (mTimeProvider != null) {
                        mTimeProvider.onPaused(msg.what == MEDIA_PAUSED);
                    }
                    break;
            ......
    

    在MediaPlayer.jni的native_setup函数中,JNIMediaPlayerListener对象被构建后,会先保存在MediaPlayer.cpp对象中,紧接着执行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);
        }
        //给fields.context设置新的MediaPlayer.cpp
        env->SetLongField(thiz, fields.context, (jlong)player.get());
        return old;
    }
    

    到这里,Java层的MediaPlayer.java对象便通过mNativeContext变量,绑定了底层的MediaPlayer.cpp对象。

    接着看setDataSource方法。

     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;
    

    _setDataSource的绑定使用动态注册方式实现。

    static JNINativeMethod gMethods[] = {
        {
            "nativeSetDataSource",
            "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;"
            "[Ljava/lang/String;)V",
            (void *)android_media_MediaPlayer_setDataSourceAndHeaders
        },
        //_setDataSource映射到android_media_MediaPlayer_setDataSourceFD
        {"_setDataSource",       "(Ljava/io/FileDescriptor;JJ)V",    (void *)android_media_MediaPlayer_setDataSourceFD},
        {"_setVideoSurface",    "(Landroid/view/Surface;)V",        (void *)android_media_MediaPlayer_setVideoSurface},
        {"_prepare",            "()V",                              (void *)android_media_MediaPlayer_prepare},
        {"prepareAsync",        "()V",                              (void *)android_media_MediaPlayer_prepareAsync},
        {"_start",              "()V",                              (void *)android_media_MediaPlayer_start},
        {"_stop",               "()V",                              (void *)android_media_MediaPlayer_stop},
    

    因此,我们看android_media_MediaPlayer_setDataSourceFD这个函数。

    static void
    android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
    {
        //获取MediaPlayer.cpp对象
        sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
        if (mp == NULL ) {
            jniThrowException(env, "java/lang/IllegalStateException", NULL);
            return;
        }
    
        if (fileDescriptor == NULL) {
            jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
            return;
        }
        int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
        ALOGV("setDataSourceFD: fd %d", fd);
      
        //调用MediaPlayer.cpp对象的setDataSource函数   
        process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
    }
    
    //获取MediaPlayer.java对象里绑定的MediaPlayer.cpp对象
    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);
    }
    

    调用MediaPlayer.cpp对象如果出现错误或异常,都会通过process_media_player_call来通知上层的MediaPlayer.java对象,如何通知在上面已经分析过,它会调用MediaPlayer.cpp对象的成员JNIMediaPlayerListener的notify方法。

    static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message)
    {
        if (exception == NULL) {  
            if (opStatus != (status_t) OK) {
                sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
                if (mp != 0) mp->notify(MEDIA_ERROR, opStatus, 0);
            }
        } else {  
            if ( opStatus == (status_t) INVALID_OPERATION ) {
                jniThrowException(env, "java/lang/IllegalStateException", NULL);
            } else if ( opStatus == (status_t) PERMISSION_DENIED ) {
                jniThrowException(env, "java/lang/SecurityException", NULL);
            } else if ( opStatus != (status_t) OK ) {
                if (strlen(message) > 230) {               
                   jniThrowException( env, exception, message);
                } else {
                   char msg[256];         
                   sprintf(msg, "%s: status=0x%X", message, opStatus);
                   jniThrowException( env, exception, msg);
                }
            }
        }
    }
    

    调用process_media_player_call函数时,调用了MediaPlayer.cpp对象的setDataSource函数。

    status_t MediaPlayer::setDataSource(
            const sp<IMediaHTTPService> &httpService,
            const char *url, const KeyedVector<String8, String8> *headers)
    {
        ALOGV("setDataSource(%s)", url);
        status_t err = BAD_VALUE;
        if (url != NULL) {
            //通过ServiceManager找到MediaPlayerService,初始化service对象
            const sp<IMediaPlayerService>& service(getMediaPlayerService());
            if (service != 0) {
                //通过Binder机制向MediaPlayerService请求创建IMediaPlayer对象
                sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
                if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
                    //调用IMediaPlayer的setDataSource
                    (NO_ERROR != player->setDataSource(httpService, url, headers))) {
                    player.clear();
                }
                //关联远程播放器
                err = attachNewPlayer(player);
            }
        }
        return err;
    }
    

    getMediaPlayerService便是通过Binder机制,从ServiceManger中获取到一个MediaPlayerService,并创建创建IMediaPlayer对象,这个函数在IMediaDeathNotifier.cpp中实现。

    IMediaDeathNotifier::getMediaPlayerService()
    {
        ALOGV("getMediaPlayerService");
        Mutex::Autolock _l(sServiceLock);
        if (sMediaPlayerService == 0) {
            //获取ServiceManger
            sp<IServiceManager> sm = defaultServiceManager();
            sp<IBinder> binder;
            do {
                //获取binder
                binder = sm->getService(String16("media.player"));
                if (binder != 0) {
                    break;
                }
                ALOGW("Media player service not published, waiting...");
                usleep(500000); // 0.5 s
            } while (true);
    
            if (sDeathNotifier == NULL) {
                sDeathNotifier = new DeathNotifier();
            }
            binder->linkToDeath(sDeathNotifier);
            //将binder强转为IMediaPlayerService
            sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
        }
        ALOGE_IF(sMediaPlayerService == 0, "no media player service!?");
        //返回IMediaPlayerService
        return sMediaPlayerService;
    }
    

    从ServiceManger中获取到Binder并将其强转成IMediaPlayerService类型。在MediaServer创建时,MediaPlayerService便注册在MediaServer中了,注册过程我们将在下一篇分析。获取到IMediaPlayerService后,紧接着调用create函数创建IMediaPlayer对象。

    MediaPlayer.cpp实际上是IMediaPlayerClient类型的,即C端,显然IMediaPlayerService就是S端了。

    sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client,
            int audioSessionId)
    {
       //每个线程只有一个IPCThreadState对象,它保存了进程ProcessState对象,负责binder的读取、写入和请求
        pid_t pid = IPCThreadState::self()->getCallingPid();
        int32_t connId = android_atomic_inc(&mNextConnId);
        //创建Client
        sp<Client> c = new Client(
                this, pid, connId, client, audioSessionId,
                IPCThreadState::self()->getCallingUid());
    
        ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid,
             IPCThreadState::self()->getCallingUid());
        //转弱引用
        wp<Client> w = c;
        {
            Mutex::Autolock lock(mLock);
          //保存到SortedVector中
            mClients.add(w);
        }
        return c;
    }
    

    这个Client是MediaPlayerService的内部类,而且它被添加到MediaPlayerService的全局列表mClients中,这也说明了上层MediaPlayer.java可以同时有多个。

    private:
    
        class Client : public BnMediaPlayer {
            // IMediaPlayer interface
            virtual void            disconnect();
            virtual status_t        setVideoSurfaceTexture(
                                            const sp<IGraphicBufferProducer>& bufferProducer);
            virtual status_t        prepareAsync();
            virtual status_t        start();
            virtual status_t        stop();
            virtual status_t        pause();
            virtual status_t        isPlaying(bool* state);
            virtual status_t        seekTo(int msec);
            virtual status_t        getCurrentPosition(int* msec);
            virtual status_t        getDuration(int* msec);
            virtual status_t        reset();
            virtual status_t        setAudioStreamType(audio_stream_type_t type);
            virtual status_t        setLooping(int loop);
            virtual status_t        setVolume(float leftVolume, float rightVolume);
            virtual status_t        invoke(const Parcel& request, Parcel *reply);
            virtual status_t        setMetadataFilter(const Parcel& filter);
            virtual status_t        getMetadata(bool update_only,
                                                bool apply_filter,
                                                Parcel *reply);
            virtual status_t        setAuxEffectSendLevel(float level);
            virtual status_t        attachAuxEffect(int effectId);
            virtual status_t        setParameter(int key, const Parcel &request);
            virtual status_t        getParameter(int key, Parcel *reply);
            virtual status_t        setRetransmitEndpoint(const struct sockaddr_in* endpoint);
            virtual status_t        getRetransmitEndpoint(struct sockaddr_in* endpoint);
            virtual status_t        setNextPlayer(const sp<IMediaPlayer>& player);
    

    我们看到,这个Client的函数定义和MediaPlayer.cpp和MediaPlayer.java是一一对应的,它的继承关系为Client->BnMediaPlayer->IMediaPlayer,也就是说,Client本质是一个IMediaPlayer,它可以创建和控制播放器。Binder通讯中会经常见到Bnxxx和Bpxxx,它们的区别以及继承关系会在下一篇分析。

    再回到MediaPlayer::setDataSource函数,可以看到实际将调用IMediaPlayer的setDataSource函数。

    status_t MediaPlayerService::Client::setDataSource(
            const sp<IMediaHTTPService> &httpService,
            const char *url,
            const KeyedVector<String8, String8> *headers)
    {
        //路径不能为null
        ALOGV("setDataSource(%s)", url);
        if (url == NULL)
            return UNKNOWN_ERROR;
        //路径类型
        if ((strncmp(url, "http://", 7) == 0) ||
            (strncmp(url, "https://", 8) == 0) ||
            (strncmp(url, "rtsp://", 7) == 0)) {
            if (!checkPermission("android.permission.INTERNET")) {
                return PERMISSION_DENIED;
            }
        }
    
          //是否内容提供者提供数据
        if (strncmp(url, "content://", 10) == 0) {
            String16 url16(url);
            int fd = android::openContentProviderFile(url16);
            if (fd < 0)
            {
                ALOGE("Couldn't open fd for %s", url);
                return UNKNOWN_ERROR;
            }
            setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus
            close(fd);
            return mStatus;
        } else {
            //根据url获取播放器类型
            player_type playerType = MediaPlayerFactory::getPlayerType(this, url);
            //创建对应的播放器
            sp<MediaPlayerBase> p = setDataSource_pre(playerType);
            if (p == NULL) {
                return NO_INIT;
            }
            //对调用播放器的setDataSource
            setDataSource_post(p, p->setDataSource(httpService, url, headers));
            return mStatus;
        }
    }
    

    安卓的播放器实际有两种,StagefrightPlayer和NuPlayer,前者是对AwesomePlayer的封装。这里的创建使用抽象工厂模式,播放器对应的工厂对象,在MediaPlayerService构造函数中初始化,维护在MediaPlayerService的成员Map中。

    远程服务端的播放器通过资源路径创建完毕,MediaPlayer.cpp将通过关联远程Client(IMediaPlayer)来关联这个播放器,通过调用MediaPlayer.cpp的attachNewPlayer实现。

    status_t MediaPlayer::attachNewPlayer(const sp<IMediaPlayer>& player)
    {
        status_t err = UNKNOWN_ERROR;
        sp<IMediaPlayer> p;
        { 
          //加锁
            Mutex::Autolock _l(mLock);
            //出错
            if ( !( (mCurrentState & MEDIA_PLAYER_IDLE) ||
                    (mCurrentState == MEDIA_PLAYER_STATE_ERROR ) ) ) {
                ALOGE("attachNewPlayer called in state %d", mCurrentState);
                return INVALID_OPERATION;
            }
            // Client(IMediaPlayer)保存到成员变量mPlayer 中
            clear_l();
            p = mPlayer;
            mPlayer = player;
            //状态置为MEDIA_PLAYER_INITIALIZED
            if (player != 0) {
                mCurrentState = MEDIA_PLAYER_INITIALIZED;
                err = NO_ERROR;
            } else {
                ALOGE("Unable to create media player");
            }
        }
    
        if (p != 0) {
            p->disconnect();
        }
    
        return err;
    }
    

    到此,上层应用便和底层的播放器进行了绑定,MediaPlayer.java调用prepare和start等方法,都将通过底层的播放器去执行具体的逻辑。

    这一篇只分析了播放器的创建和关联流程,其中还留下了许多疑问,并且Binder的远程调用具体过程,也还没有分析到,这些都将再下一篇进行讲解。

    最后,从底层的角度出发,对各个类以及各层之间的关系做下总结:

    • MediaPlayerService是服务端,它主要功能是创建Client对象并维护了一个Client列表,以供客户端调用。

    • Client实现了IMediaPlayer定义的子类,它相当于播放器对外暴露的接口,操作Client就能操作播放器。

    • MediaPlayer.cpp是相对于MediaPlayerService的客户端,同时它相当于暴露给MediaPlayer.jni的接口,它通过Binder机制,远程调用运行在MediaPlayerService里的Client(IMediaPlayer),来操作播放器。

    • 同样,MediaPlayer.jni相当于底层暴露给应用层MediaPlayer.java的接口。

    相关文章

      网友评论

          本文标题:Binder(一)

          本文链接:https://www.haomeiwen.com/subject/sjltzctx.html