前面一层中,都是通过Java层调用到JNI层中,而JNI层向下到C++层并未介绍。
本节首先分析Java层的一个函数在C++层MediaPlayer中的过程。(路径为:/frameworks/av/media/libmedia/mediaplayer.cpp)
下面用 mp->setDataSource() 后,从C++层的setDataSource()
来看看C/S模式的过程
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;
//通过IMediaPlayerService获取service端的MediaPlayerService
const sp<IMediaPlayerService> service(getMediaPlayerService());
if (service != 0) {
//如果Service不为空,则调用service的create函数
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;
}
setDataSource获取到了 IMediaPlayerService
,我们都知道,这种带I的类名, 一般都是服务端的类在 客户端的代理,我们调用它的方法,实际上是调用 服务端的 这个去掉I的类的方法,所以我们要去 /frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp 里面,走它service的create流程。而这个时候,代码的角度也从 C(Client)来到了 S(service)层:
sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client,
audio_session_t audioSessionId)
{
//获取进程
pid_t pid = IPCThreadState::self()->getCallingPid();
int32_t connId = android_atomic_inc(&mNextConnId);
//表示校验调用仿的uid,用来进行身份验证
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());
//把构造的Client强引用对象赋值成 弱引用对象
wp<Client> w = c;
{
Mutex::Autolock lock(mLock);
//mClient声明为 SortedVector< wp >
mClients.add(w);
}
return c;
}
create总结:
将传入的clientId以及 Pid、ConnId进行身份验证,创建出一个 Client端在Service端的引用,并将该强引用转换成弱引用。
创建的过程是 通过一个 IPCThreadState
,每一个线程都有一个IPCThreadState
实例等级在Linux线程的上下文附属数据中。主要负责Binder的读取、写入和请求处理。
其实就是在Service层获取一个Client的引用而已。拿到Client不就可以相互通信了吗~
而这个Client又是具体指代什么,我们在头文件查看和从上一节的C/S图中发现,Client是继承BnMediaPlayer,并包含了IMediaPlayer相关接口。
总结一下,继承关系为 Client -> BnMediaPlayer -> IMediaPlayer。create中,创建了一个Client并将这个Client添加到了全局列表mClients,这个mClients是一个 SortedVector,紧接着在Client中执行了 player->setDataSource(url,headers),即Client::setDataSource。可以直接认为 player==client
那么在C++中,这个 Client和MediaPlayer又是什么关系呢?
//判断是否通过contentprovider提供的数据
if (strncmp(url, "content://", 10) == 0) {
// get a filedescriptor for the content Uri and
// pass it to the setDataSource(fd) method
String16 url16(url);
int fd = android::openContentProviderFile(url16);
if (fd < 0)
{
ALOGE("Couldn't open fd for %s", url);
return UNKNOWN_ERROR;
}
//通过标识符去设置
status_t status = setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus
close(fd);
return mStatus = status;
} else {
player_type playerType = MediaPlayerFactory::getPlayerType(this, url);
sp<MediaPlayerBase> p = setDataSource_pre(playerType);
if (p == NULL) {
return NO_INIT;
}
return mStatus =
setDataSource_post(
p, p->setDataSource(httpService, url, headers));
}
}
而Client中的函数都是和 下面图(上一节中看过)对应的:
在一开始的代码中,最后执行了 err =attachNewPlayer(player)
status_t MediaPlayer::attachNewPlayer(const sp<IMediaPlayer>& player)
{
status_t err = UNKNOWN_ERROR;
//IMediaPlayer就是Client声明在客户端处的代理类
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;
}
clear_l();
//赋值给代理类,mPlayer在MediaPlayer.h中声明,
p = mPlayer;
mPlayer = player;
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的setDataSource,会调用到attachNewPlayer()
,这个函数最终会调用服务器端Client对应的函数。
这时候出现IMediaPlayer.h
,mediaplayer.h
,ImediaPlayerClient.h
,看的人都晕了,这个时候来分别看一下:
而IMediaPlayer.h中都是虚函数,所以它的功能是作为 MediaPlayer功能的接口。
接下来来看看IMediaPlayerClient.h:
namespace android {
enum {
NOTIFY = IBinder::FIRST_CALL_TRANSACTION,
};
class BpMediaPlayerClient: public BpInterface<IMediaPlayerClient>
{
public:
explicit BpMediaPlayerClient(const sp<IBinder>& impl)
: BpInterface<IMediaPlayerClient>(impl)
{
}
virtual void notify(int msg, int ext1, int ext2, const Parcel *obj)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerClient::getInterfaceDescriptor());
data.writeInt32(msg);
data.writeInt32(ext1);
data.writeInt32(ext2);
if (obj && obj->dataSize() > 0) {
data.appendFrom(const_cast<Parcel *>(obj), 0, obj->dataSize());
}
remote()->transact(NOTIFY, data, &reply, IBinder::FLAG_ONEWAY);
}
};
IMPLEMENT_META_INTERFACE(MediaPlayerClient, "android.media.IMediaPlayerClient");
// ----------------------------------------------------------------------
status_t BnMediaPlayerClient::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch (code) {
case NOTIFY: {
CHECK_INTERFACE(IMediaPlayerClient, data, reply);
int msg = data.readInt32();
int ext1 = data.readInt32();
int ext2 = data.readInt32();
Parcel obj;
if (data.dataAvail() > 0) {
obj.appendFrom(const_cast<Parcel *>(&data), data.dataPosition(), data.dataAvail());
}
notify(msg, ext1, ext2, &obj);
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
}
来总结一下上面的代码:
在内部定义一个 BpMediaPlayerClient
,也就是Client的父类。然后有一个onTranscat()
,它是Binder通信中的回到函数。
所以说前面的player是C/S模式,IMediaPlayerClient.h的功能时一个MediaPlayer客户端的接口。
综上所述: