背景介绍
Android中处处是c/s结构。binder则是实现c/s间跨进程通信的工具。之前介绍的bindService和system_server都是基于binder实现的c/s结构。但是前面这两种都是Java端到Java端的。本文重点再讲解下Java端到C++端的情况。
在Android中新增一个native service
下面以mediaserver为例,讲解下如何新增一个native service并对外提供binder service服务。
1.创建native service对应的init.rc文件
native service在Android中通常由init来启动。因此首先需要创建一个对应的rc文件,用于定义该native service的群组,优先级,启动方式等。
例如:
frameworks/av/media/mediaserver/mediaserver.rc
service media /system/bin/mediaserver
class main
user media
group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm
ioprio rt 4
writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
2.创建service的main文件
native service作为一个daemon进程的启动入口同样是main函数。main函数的初始化有如下几个关键步骤:
frameworks/av/media/mediaserver/main_mediaserver.cpp
int main(int argc __unused, char **argv __unused)
{
signal(SIGPIPE, SIG_IGN);
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm(defaultServiceManager());
ALOGI("ServiceManager: %p", sm.get());
InitializeIcuOrDie();
MediaPlayerService::instantiate();
ResourceManagerService::instantiate();
registerExtensions();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
3.实现并注册Bnservice
frameworks/av/media/libmediaplayerservice/MediaPlayerService.h
class MediaPlayerService : public BnMediaPlayerService
{
}
frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
void MediaPlayerService::instantiate() {
defaultServiceManager()->addService(
String16("media.player"), new MediaPlayerService());
}
MediaPlayerService::MediaPlayerService()
{
ALOGV("MediaPlayerService created");
mNextConnId = 1;
MediaPlayerFactory::registerBuiltinFactories();
}
4.实现Bpservice
frameworks/av/media/libmedia/IMediaPlayerService.cpp
#include <stdint.h>
#include <sys/types.h>
#include <binder/Parcel.h>
#include <binder/IMemory.h>
#include <media/IMediaCodecList.h>
#include <media/IMediaHTTPService.h>
#include <media/IMediaPlayerService.h>
#include <media/IMediaRecorder.h>
#include <media/IOMX.h>
#include <media/IRemoteDisplay.h>
#include <media/IRemoteDisplayClient.h>
#include <media/IStreamSource.h>
#include <utils/Errors.h> // for status_t
#include <utils/String8.h>
namespace android {
enum {
CREATE = IBinder::FIRST_CALL_TRANSACTION,
CREATE_MEDIA_RECORDER,
CREATE_METADATA_RETRIEVER,
ADD_BATTERY_DATA,
PULL_BATTERY_DATA,
LISTEN_FOR_REMOTE_DISPLAY,
GET_CODEC_LIST,
};
class BpMediaPlayerService: public BpInterface<IMediaPlayerService>
{
public:
explicit BpMediaPlayerService(const sp<IBinder>& impl)
: BpInterface<IMediaPlayerService>(impl)
{
}
virtual sp<IMediaMetadataRetriever> createMetadataRetriever()
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
remote()->transact(CREATE_METADATA_RETRIEVER, data, &reply);
return interface_cast<IMediaMetadataRetriever>(reply.readStrongBinder());
}
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());
}
virtual sp<IMediaRecorder> createMediaRecorder(const String16 &opPackageName)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
data.writeString16(opPackageName);
remote()->transact(CREATE_MEDIA_RECORDER, data, &reply);
return interface_cast<IMediaRecorder>(reply.readStrongBinder());
}
virtual void addBatteryData(uint32_t params) {
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
data.writeInt32(params);
remote()->transact(ADD_BATTERY_DATA, data, &reply);
}
virtual status_t pullBatteryData(Parcel* reply) {
Parcel data;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
return remote()->transact(PULL_BATTERY_DATA, data, reply);
}
virtual sp<IRemoteDisplay> listenForRemoteDisplay(const String16 &opPackageName,
const sp<IRemoteDisplayClient>& client, const String8& iface)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
data.writeString16(opPackageName);
data.writeStrongBinder(IInterface::asBinder(client));
data.writeString8(iface);
remote()->transact(LISTEN_FOR_REMOTE_DISPLAY, data, &reply);
return interface_cast<IRemoteDisplay>(reply.readStrongBinder());
}
virtual sp<IMediaCodecList> getCodecList() const {
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
remote()->transact(GET_CODEC_LIST, data, &reply);
return interface_cast<IMediaCodecList>(reply.readStrongBinder());
}
};
IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.media.IMediaPlayerService");
// ----------------------------------------------------------------------
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());
audio_session_t audioSessionId = (audio_session_t) data.readInt32();
sp<IMediaPlayer> player = create(client, audioSessionId);
reply->writeStrongBinder(IInterface::asBinder(player));
return NO_ERROR;
} break;
case CREATE_MEDIA_RECORDER: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
const String16 opPackageName = data.readString16();
sp<IMediaRecorder> recorder = createMediaRecorder(opPackageName);
reply->writeStrongBinder(IInterface::asBinder(recorder));
return NO_ERROR;
} break;
case CREATE_METADATA_RETRIEVER: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
sp<IMediaMetadataRetriever> retriever = createMetadataRetriever();
reply->writeStrongBinder(IInterface::asBinder(retriever));
return NO_ERROR;
} break;
case ADD_BATTERY_DATA: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
uint32_t params = data.readInt32();
addBatteryData(params);
return NO_ERROR;
} break;
case PULL_BATTERY_DATA: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
pullBatteryData(reply);
return NO_ERROR;
} break;
case LISTEN_FOR_REMOTE_DISPLAY: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
const String16 opPackageName = data.readString16();
sp<IRemoteDisplayClient> client(
interface_cast<IRemoteDisplayClient>(data.readStrongBinder()));
if (client == NULL) {
reply->writeStrongBinder(NULL);
return NO_ERROR;
}
String8 iface(data.readString8());
sp<IRemoteDisplay> display(listenForRemoteDisplay(opPackageName, client, iface));
reply->writeStrongBinder(IInterface::asBinder(display));
return NO_ERROR;
} break;
case GET_CODEC_LIST: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
sp<IMediaCodecList> mcl = getCodecList();
reply->writeStrongBinder(IInterface::asBinder(mcl));
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
// ----------------------------------------------------------------------------
} // namespace android
frameworks/av/media/libmedia/include/media/IMediaPlayerService.h
#ifndef ANDROID_IMEDIAPLAYERSERVICE_H
#define ANDROID_IMEDIAPLAYERSERVICE_H
#include <utils/Errors.h> // for status_t
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>
#include <system/audio.h>
#include <media/IMediaPlayerClient.h>
#include <media/IMediaPlayer.h>
#include <media/IMediaMetadataRetriever.h>
namespace android {
class IMediaCodecList;
struct IMediaHTTPService;
class IMediaRecorder;
class IOMX;
class IRemoteDisplay;
class IRemoteDisplayClient;
struct IStreamSource;
class IMediaPlayerService: public IInterface
{
public:
DECLARE_META_INTERFACE(MediaPlayerService);
virtual sp<IMediaRecorder> createMediaRecorder(const String16 &opPackageName) = 0;
virtual sp<IMediaMetadataRetriever> createMetadataRetriever() = 0;
virtual sp<IMediaPlayer> create(const sp<IMediaPlayerClient>& client,
audio_session_t audioSessionId = AUDIO_SESSION_ALLOCATE) = 0;
virtual sp<IMediaCodecList> getCodecList() const = 0;
// Connects to a remote display.
// 'iface' specifies the address of the local interface on which to listen for
// a connection from the remote display as an ip address and port number
// of the form "x.x.x.x:y". The media server should call back into the provided remote
// display client when display connection, disconnection or errors occur.
// The assumption is that at most one remote display will be connected to the
// provided interface at a time.
virtual sp<IRemoteDisplay> listenForRemoteDisplay(const String16 &opPackageName,
const sp<IRemoteDisplayClient>& client, const String8& iface) = 0;
// codecs and audio devices usage tracking for the battery app
enum BatteryDataBits {
// tracking audio codec
kBatteryDataTrackAudio = 0x1,
// tracking video codec
kBatteryDataTrackVideo = 0x2,
// codec is started, otherwise codec is paused
kBatteryDataCodecStarted = 0x4,
// tracking decoder (for media player),
// otherwise tracking encoder (for media recorder)
kBatteryDataTrackDecoder = 0x8,
// start to play an audio on an audio device
kBatteryDataAudioFlingerStart = 0x10,
// stop/pause the audio playback
kBatteryDataAudioFlingerStop = 0x20,
// audio is rounted to speaker
kBatteryDataSpeakerOn = 0x40,
// audio is rounted to devices other than speaker
kBatteryDataOtherAudioDeviceOn = 0x80,
};
virtual void addBatteryData(uint32_t params) = 0;
virtual status_t pullBatteryData(Parcel* reply) = 0;
};
// ----------------------------------------------------------------------------
class BnMediaPlayerService: public BnInterface<IMediaPlayerService>
{
public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
};
}; // namespace android
#endif // ANDROID_IMEDIAPLAYERSERVICE_H
总结
以上就是新增一个native service并实现binder服务的全部过程。