Binder(三)

接着上一篇,MediaPlayerService已经被注册到ServiceManager中了,本篇将接着分析MediaPlayerService服务的获取,以及通过MediaPlayerService服务创建播放器2个流程。

<Binder(一)>一篇知道,MediaPlayer.java调用setDataSource方法,最终会调用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) {
        //1,获取IMediaPlayerService服务
        const sp<IMediaPlayerService>& service(getMediaPlayerService());
        if (service != 0) {
            //2,让远程服务创建播放器
            sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
            if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
                    //通过IMediaPlayer操作播放器
                (NO_ERROR != player->setDataSource(httpService, url, headers))) {
                player.clear();
            }
            err = attachNewPlayer(player);
        }
    }
    return err;
}

我们先看getMediaPlayerService()函数的执行过程。

IMediaDeathNotifier::getMediaPlayerService()
{
    ALOGV("getMediaPlayerService");
    Mutex::Autolock _l(sServiceLock);
    if (sMediaPlayerService == 0) {
        //获取IServiceManager
        sp<IServiceManager> sm = defaultServiceManager();
        sp<IBinder> binder;
        do {
            //使用String16("media.player")获取服务
            binder = sm->getService(String16("media.player"));
            if (binder != 0) {
                break;
            }
            //如果服务还未注册,等待
            usleep(500000); // 0.5 s
        } while (true);

        if (sDeathNotifier == NULL) {
            sDeathNotifier = new DeathNotifier();
        }
        binder->linkToDeath(sDeathNotifier);
        //将IBinder保存到BpMediaPlayerService的成员变量mRemote中
        sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
    }

    return sMediaPlayerService;
}

defaultServiceManager()返回BpServiceManager。

class BpServiceManager : public BpInterface<IServiceManager>
{
public:
    BpServiceManager(const sp<IBinder>& impl)
        : BpInterface<IServiceManager>(impl)
    {
    }

    virtual sp<IBinder> getService(const String16& name) const
    {
        unsigned n;
        //最多查询5次
        for (n = 0; n < 5; n++){
            
            sp<IBinder> svc = checkService(name);
            if (svc != NULL) return svc;
            ALOGI("Waiting for service %s...\n", String8(name).string());
            sleep(1);
        }
        return NULL;
    }
//发送查找指令
 virtual sp<IBinder> checkService( const String16& name) const
    {
        Parcel data, reply;
        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
        data.writeString16(name);
        //发送CHECK_SERVICE_TRANSACTION指令
        remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
        //读取响应数据
        return reply.readStrongBinder();
    }

transact会通过BpBinder(0)发送数据给ServiceManager查找名字为"media.player"的Service,在上一篇分析过,ServiceManager会通过svcmgr_handler函数来处理请求。

int svcmgr_handler(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    ......

    switch(txn->code) {
    //获取某个Service,通过msg来取
    case SVC_MGR_GET_SERVICE:
    case SVC_MGR_CHECK_SERVICE:
        //s为对应Service名字
        s = bio_get_string16(msg, &len);
        if (s == NULL) {
            return -1;
        }
        //查找Service,返回handle值
        handle = do_find_service(bs, s, len, txn->sender_euid, txn->sender_pid);
        //不为0则找到
        if (!handle)
            break;
        //写入reply回传给客户端
        bio_put_ref(reply, handle);
        return 0;

do_find_service根据"media.player"进行查找,并返回它的句柄handle。

uint32_t do_find_service(struct binder_state *bs, const uint16_t *s, size_t len, uid_t uid, pid_t spid)
{
    struct svcinfo *si;
    //检查权限
    if (!svc_can_find(s, len, spid)) {
        ALOGE("find_service('%s') uid=%d - PERMISSION DENIED\n",
             str8(s, len), uid);
        return 0;
    }
    //查找服务
    si = find_svc(s, len);
     //si不为null,handle大于0
    if (si && si->handle) {
        if (!si->allow_isolated) {
          
            uid_t appid = uid % AID_USER;
            if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
                return 0;
            }
        }
        //成功返回handle
        return si->handle;
    } else {
        return 0;
    }
}

继续看查找的关键函数find_svc。

struct svcinfo *find_svc(const uint16_t *s16, size_t len)
{
    struct svcinfo *si;
    //遍历
    for (si = svclist; si; si = si->next) {
        if ((len == si->len) &&
            !memcmp(s16, si->name, len * sizeof(uint16_t))) {
            return si;
        }
    }
    return NULL;
}

Service整个查找过程,就是根据Service名去遍历svcinfo链表,找到svcinfo结构体后,将svcinfo的handle值写入缓存,回传给客户端。

我们回头看reply.readStrongBinder()这个方法如何解析响应数据,和返回需要的服务对象。reply是一个Parcel类。

sp<IBinder> Parcel::readStrongBinder() const
{
    sp<IBinder> val;
    unflatten_binder(ProcessState::self(), *this, &val);
    return val;
}

status_t unflatten_binder(const sp<ProcessState>& proc,
    const Parcel& in, sp<IBinder>* out)
{
   //读取数据
    const flat_binder_object* flat = in.readObject(false);
    //此时为BINDER_TYPE_HANDLE类型
    if (flat) {
        switch (flat->type) {
            case BINDER_TYPE_BINDER:
                *out = reinterpret_cast<IBinder*>(flat->cookie);
                return finish_unflatten_binder(NULL, *flat, in);
            case BINDER_TYPE_HANDLE:
                //传入handle
                *out = proc->getStrongProxyForHandle(flat->handle);
                return finish_unflatten_binder(
                    static_cast<BpBinder*>(out->get()), *flat, in);
        }
    }
    return BAD_TYPE;
}
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;

    AutoMutex _l(mLock);
    //构建一个entry
    handle_entry* e = lookupHandleLocked(handle);
    if (e != NULL) {
        IBinder* b = e->binder;
        if (b == NULL || !e->refs->attemptIncWeak(this)) {
            //此时handle不为0
            if (handle == 0) {
                 Parcel data;
                //ping下驱动是否通
                status_t status = IPCThreadState::self()->transact(
                        0, IBinder::PING_TRANSACTION, data, NULL, 0);
                if (status == DEAD_OBJECT)
                   return NULL;
            }
            //根据handle创建了一个BpBinder
            b = new BpBinder(handle); 
            e->binder = b;
            if (b) e->refs = b->getWeakRefs();
          //将创建的BpBinder返回
            result = b;
        } else {
             result.force_set(b);
            e->refs->decWeak(this);
        }
    }
    return result;
}

这里的流程和获取IServiceManger是相同的,只是此时的handle大于0,它通过ProcessState创建了一个BpBinder(handle)。

回到IMediaDeathNotifier::getMediaPlayerService函数,BpBinder(handle)同样通过interface_cast进行了强转,强转流程可以看前面IServiceManger的获取流程。

也就是说,最终客户端得到一个BpMediaPlayerService,它的成员变量mRemote持有一个BpBinder(handle),有了这个handle句柄,就能通过Binder驱动和MediaPlayerService进行通讯了。

流程1到此分析完成,即当前已获取到了IMediaPlayerService。继续分析流程2,IMediaPlayerService调用了create函数,创建播放器。

 virtual sp<IMediaPlayer> create(
            const sp<IMediaPlayerClient>& client, int audioSessionId) {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
        data.writeStrongBinder(client->asBinder());
        data.writeInt32(audioSessionId);
        //获取mRemote,发送创建指令CREATE,
        remote()->transact(CREATE, data, &reply);
        //返回播放器引用
        return interface_cast<IMediaPlayer>(reply.readStrongBinder());
    }

通过remote()获取mRemote,即BpBinder(0)发送CREATE创建指令。上一篇分析过,MediaPlayerService在MediaServer中创建,并开启了两个线程循环执行talkWithDriver函数,循环读写消息,假设其中一个线程收到CREATE这个指令,最终将执行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));
        
            if (result != NO_ERROR) break;
            ......

            Parcel reply;
            status_t error;
           //转为BBinder对象,实际就是BnMediaPlayerService
            if (tr.target.ptr) {
                sp<BBinder> b((BBinder*)tr.cookie);
                error = b->transact(tr.code, buffer, &reply, tr.flags);

            } else {
                error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
            }

BpXXX对应着服务端在客户端的业务代理,而Bn则对应服务端本地的业务处理类,因此每个服务端都包含一个BnXXX内部类,它继承模板类BnInterface和BBinder对象。

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

};
template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder
{
public:
    virtual sp<IInterface>      queryLocalInterface(const String16& _descriptor);
    virtual const String16&     getInterfaceDescriptor() const;

protected:
    virtual IBinder*            onAsBinder();
};

而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;
}

onTransact用于处理消息数据,它是一个虚函数,由继承关系知道,它实现在BnMediaPlayerService中。

status_t BnMediaPlayerService::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch (code) {
          ......
        case CREATE: {
            CHECK_INTERFACE(IMediaPlayerService, data, reply);
            sp<IMediaPlayerClient> client =
                interface_cast<IMediaPlayerClient>(data.readStrongBinder());
            int audioSessionId = data.readInt32();
            //创建播放器
            sp<IMediaPlayer> player = create(client, audioSessionId);
            //将播放器转为Binder类型的数据,写入响应缓冲区
            reply->writeStrongBinder(player->asBinder());
            return NO_ERROR;
        } break;
     ......
        default:
            return BBinder::onTransact(code, data, reply, flags);
    }
}

如上,BnMediaPlayerService将会创建一个播放器,返回给MediaPlayer.cpp客户端,这个MediaPlayer.cpp的远程服务端是一个MediaPlayerService的内部类,为Client,它继承自IMediaPlayer。

sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client,
        int audioSessionId)
{
    pid_t pid = IPCThreadState::self()->getCallingPid();
    int32_t connId = android_atomic_inc(&mNextConnId);
   //创建Client对象,它是BnMediaPlayer的子类
    sp<Client> c = new Client(
            this, pid, connId, client, audioSessionId,
            IPCThreadState::self()->getCallingUid());

    wp<Client> w = c;
    {
        Mutex::Autolock lock(mLock);
        mClients.add(w);
    }
    return c;
}

Client是MediaPlayerService的内部类,它继承自BnMediaPlayer,也就是IMediaPlayer的服务端,函数返回后,也就是客户端得到Client的远程对象代理,那么紧接着会执行Client的setDataSource函数。

status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)
{
    ALOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
    struct stat sb;
    int ret = fstat(fd, &sb);
    if (ret != 0) {
   
        return UNKNOWN_ERROR;
    }


    if (offset >= sb.st_size) {
        ALOGE("offset error");
        ::close(fd);
        return UNKNOWN_ERROR;
    }
    if (offset + length > sb.st_size) {
        length = sb.st_size - offset;
        ALOGV("calculated length = %lld", length);
    }
  //获取到当前适合播放该视频源的播放器类型
    player_type playerType = MediaPlayerFactory::getPlayerType(this,
                                                               fd,
                                                               offset,
                                                               length);
   // 根据得到的播放器类型去创建对应的播放器实例:
    sp<MediaPlayerBase> p = setDataSource_pre(playerType);
    if (p == NULL) {
        return NO_INIT;
    }
   
    setDataSource_post(p, p->setDataSource(fd, offset, length));
    return mStatus;
}

这里分两步执行,先获取到适合播放该视频源的播放器类型,再根据这个类型去创建播放器。MediaPlayerFactory保存的工厂类,在MediaPlayerService构造时就注册好了。

MediaPlayerService::MediaPlayerService()
{
    ALOGV("MediaPlayerService created");
    mNextConnId = 1;

    mBatteryAudio.refCount = 0;
    for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
        mBatteryAudio.deviceOn[i] = 0;
        mBatteryAudio.lastTime[i] = 0;
        mBatteryAudio.totalTime[i] = 0;
    }

    mBatteryAudio.deviceOn[SPEAKER] = 1;

    const sp<IServiceManager> sm(defaultServiceManager());
    if (sm != NULL) {
        const String16 name("batterystats");
        sp<IBatteryStats> batteryStats =
                interface_cast<IBatteryStats>(sm->getService(name));
        if (batteryStats != NULL) {
            batteryStats->noteResetVideo();
            batteryStats->noteResetAudio();
        }
    }
    //注册播放器工厂类
    MediaPlayerFactory::registerBuiltinFactories();
}

构造函数最后一行注册了所有类型播放器工厂。

void MediaPlayerFactory::registerBuiltinFactories() {
    Mutex::Autolock lock_(&sLock);

    if (sInitComplete)
        return;

    registerFactory_l(new StagefrightPlayerFactory(), STAGEFRIGHT_PLAYER);
    registerFactory_l(new NuPlayerFactory(), NU_PLAYER);
    registerFactory_l(new SonivoxPlayerFactory(), SONIVOX_PLAYER);
    registerFactory_l(new TestPlayerFactory(), TEST_PLAYER);

    sInitComplete = true;
}

我们回头看根据类型获取播放器的函数setDataSource_pre。

sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre(
        player_type playerType)
{
     //根据类型创建播放器
    sp<MediaPlayerBase> p = createPlayer(playerType);
    if (p == NULL) {
        return p;
    }

    if (!p->hardwareOutput()) {
        mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(),
                mPid, mAudioAttributes);
        static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
    }

    return p;
}

sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)
{
  
    sp<MediaPlayerBase> p = mPlayer;
    if ((p != NULL) && (p->playerType() != playerType)) {
        ALOGV("delete player");
        p.clear();
    }
    //通过工厂类创建播放器
    if (p == NULL) {
        p = MediaPlayerFactory::createPlayer(playerType, this, notify);
    }

    if (p != NULL) {
        p->setUID(mUID);
    }

    return p;
}

关键代码所示,MediaPlayerFactory工厂类获取播放器。

sp<MediaPlayerBase> MediaPlayerFactory::createPlayer(
        player_type playerType,
        void* cookie,
        notify_callback_f notifyFunc) {
    sp<MediaPlayerBase> p;
    IFactory* factory;
    status_t init_result;
    Mutex::Autolock lock_(&sLock);

    if (sFactoryMap.indexOfKey(playerType) < 0) {
        ALOGE("Failed to create player object of type %d, no registered"
              " factory", playerType);
        return p;
    }
    //从sFactoryMap获取对应的工厂类
    factory = sFactoryMap.valueFor(playerType);
    CHECK(NULL != factory);

    //通过IFactory内部类的不同实现类,创建不同的MediaPlayer
    p = factory->createPlayer();

    if (p == NULL) {
        ALOGE("Failed to create player object of type %d, create failed",
               playerType);
        return p;
    }

    init_result = p->initCheck();
    if (init_result == NO_ERROR) {
        p->setNotifyCallback(cookie, notifyFunc);
    } else {
        p.clear();
    }

    return p;
}

在注册工厂类时已经将各类型工厂加入到成员sFactoryMap中,此时根据类型获取到特定的工厂,并通过createPlayer创建播放器,安卓有2种类型的播放器,以NuPlayerFactory为例来看下创建的函数。

class NuPlayerFactory : public MediaPlayerFactory::IFactory {
  public:
    virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
                               const char* url,
                               float curScore) {
        static const float kOurScore = 0.8;

        if (kOurScore <= curScore)
            return 0.0;

        if (!strncasecmp("http://", url, 7)
                || !strncasecmp("https://", url, 8)
                || !strncasecmp("file://", url, 7)) {
            size_t len = strlen(url);
            if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
                return kOurScore;
            }

            if (strstr(url,"m3u8")) {
                return kOurScore;
            }

            if ((len >= 4 && !strcasecmp(".sdp", &url[len - 4])) || strstr(url, ".sdp?")) {
                return kOurScore;
            }
        }

        if (!strncasecmp("rtsp://", url, 7)) {
            return kOurScore;
        }

        return 0.0;
    }

    virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
                               const sp<IStreamSource>& /*source*/,
                               float /*curScore*/) {
        return 1.0;
    }
    //创建播放器
    virtual sp<MediaPlayerBase> createPlayer() {
        ALOGV(" create NuPlayer");
        return new NuPlayerDriver;
    }
};

到此播放器便创建完成,

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,440评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,814评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,427评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,710评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,625评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,014评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,511评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,162评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,311评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,262评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,278评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,989评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,583评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,664评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,904评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,274评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,856评论 2 339

推荐阅读更多精彩内容