- 浏览: 160226 次
- 性别:
- 来自: 深圳
最新评论
-
yong7356:
学习了。。。。。。。。。。。。
Android 如何建立AIDL -
910310lenfeng:
小有收获
Paint方法setXfermode -
ihopethatwell:
修改/data/data 权限,修改那几处?
Android——init.rc脚本 -
lyltiger:
http://www.qianxk.com wifi分析
Android Wifi模块分析(二) -
liuborama:
...
Android2.2下实现Ethernet上网
(一) 概述
android的binder机制提供一种进程间通信的方法,使不同一个进程可以以类似远程过程调用的形式调用另一个进程所提供的功能。binder机制在Java环境和C/C++环境都有提供。
android的代码中,与C/C++的binder包括一些类型和接口的定义和实现,相关的代码在下面这几个文件中:
frameworks\base\include\utils\IInterface.h
frameworks\base\include\utils\Binder.h
frameworks\base\include\utils\BpBinder.h
frameworks\base\include\utils\IBinder
frameworks\base\include\utils\Parcel.h
frameworks\base\include\utils\IPCThreadState.h
frameworks\base\include\utils\ProcessState.h
frameworks\base\libs\utils\Binder.cpp
frameworks\base\libs\utils\BpBinder.cpp
frameworks\base\libs\utils\IInterface.cpp
frameworks\base\libs\utils\IPCThreadState.cpp
frameworks\base\libs\utils\Parcel.cpp
frameworks\base\libs\utils\ProcessState.cpp
为了了解这些类、接口之间的关系以及binder的实现机制,最好是结合一个例子来进行研究。我选择的例子是android自带的媒体播放器的实现。其媒体播放器的相关代码在下面这些目录中:
frameworks\base\include\media
frameworks\base\media
使用startUML的反向工程功能分析上面这些代码,并进行了一定的整理之后,得到下面这幅类图(点击可查看原尺寸图片)。
android的媒体播放功能分成两部分,一部分是媒体播放应用,一部分是媒体播放服务(MediaServer,在系统启动时由init所启动,具可参考init.rc文件)。这两部分分别跑在不同的进程中。媒体播放应用包括Java程序和部分C++代码,媒体播放服务是C++代码,并且需要调用外部模块opencore来实现真正的媒体播放。媒体播放应用和媒体播放服务之间需要通过binder机制来进行相互调用,这些调用包括:
(1)媒体播放应用向媒体播放服务发控制指令
(2)媒体播放服务向媒体播放应用发事件通知(notify)
媒体播放服务对外提供多个接口,在上面得图中包括其中的2个接口:IMediaService和IMediaPlayer,IMediaplayer用于创建和管理播放实例,而IMediaplayer接口则是播放接口,用于实现指定媒体文件的播放以及播放过程的控制。
上面的图中还有媒体播放应用向媒体播放服务提供的1个接口:IMediaPlayerClient,用于接收notify。
这些接口因为需要跨进程调用,因此需要用到binder机制。每个接口包括两部分实现,一部分是接口功能的真正实现(BnInterface),这部分运行在接口提供进程中;另一部分是接口的proxy(BpInterface),这部分运行在调用接口的进程中。binder的作用就是让这两部分之间建立联系。下图是整个播放器的一个概要说明。
媒体播放器比较复杂一些,总共实现了3个接口,不过要了解binder的机制,只需要研究其中一个接口就足够了。在这里选择IMediaPlayerService接口来看一下。
IMediaPlayerService接口包括六个功能函数:create(url)、create(fd)、decode(url)、 decode(fd)、createMediaRecord()、createMetadataRetriever()。在这里不介绍这些函数是做什么的,我们只关注如何通过binder还提供这些函数接口。
(二) 接口定义
(1) 定义接口类
首先定义IMediaPlayerService类,这是一个接口类(C++的术语应该叫纯虚类)。该接口类定义在文件frameworks\base\include\media\IMediaPlayerService.h。代码如下:
class IMediaPlayerService: public IInterface
{
public:
DECLARE_META_INTERFACE(MediaPlayerService);
virtual sp createMediaRecorder(pid_t pid) = 0;
virtual sp createMetadataRetriever(pid_t pid) = 0;
virtual sp create(pid_t pid, const sp& client, const char* url) = 0;
virtual sp create(pid_t pid, const sp& client, int fd, int64_t offset, int64_t length) = 0;
virtual sp decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
virtual sp decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
};
可以看到,在这个接口类中定义了IMediaPlayerService需要提供的6个函数接口,因为是接口类,所以定义为纯虚函数。需要注意这个接口类的名称有严格要求,必须是以大写字母I开始。
重点关注在这些函数前面的一个宏定义: DECLARE_META_INTERFACE(MediaPlayerService)。这个宏定义必须要有,其中封装了实现binder所需要的一些类成员变量和成员函数通过这些成员函数可以为一个binder实现创建proxy。这个宏定义在问价frameworks\base\include \utils\IInterface.h里,在后面还会讲到。这个宏定义的参数必须是接口类的名称去除字母I后剩下的部分。
另外说明一下,可以看到接口类中所定义的函数的返回值都是sp的形式,看起来有点怪异。sp是android中定义的一个模板类,用于实现智能指针功能。sp就是IMediaPlayer的智能指针,可以简单地把它看成是标准C++中的指针定义即 IMediaPlayer* 即可。
(2) 定义和实现binder类
binder类包括两个,一个是接口实现类,一个接口代理类。接口代理类继承自BpInterface,接口实现类继承自BnInterface。这两个基类都是模板类,封装了binder的进程间通信机制,这样使用者无需关注底层通信实现细节。
对于IMediaPlayerService接口,其binder接口实现类为BnMediaPlayerService,接口代理类为 BpMediaPlayerService。需注意这两个类的名称有严格要求,必须以Bn和Bp开头,并且后面的部分必须是前面所定义的接口类的名称去除字母''''I’。比如前面所定义的接口类为IMediaPlayerService,去除字母I后是MediaPlayerService,所以两个 binder类的名称分别是BnMediaPlayerService和BpMediaPlayerService。为什么有这样的要求?原因就在前面提到的宏定义DECLARE_META_INTERFACE()和另一个宏定义IMPLEMENT_META_INTERFACE()里面。有兴趣的话可以去看一下,这两个宏定义都在文件frameworks\base\include\utils\IInterface.h里。
BpMediaPlayerService是一个最终实现类。定义并且实现在在文件frameworks\base\media\libmidia \IMediaPlayerService.cpp中。在看BpMediaPlayerService的代码之前,先看一下在 IMediaPlayerService.cpp文件的开始部分的一个枚举定义:
enum {
CREATE_URL = IBinder::FIRST_CALL_TRANSACTION,
CREATE_FD,
DECODE_URL,
DECODE_FD,
CREATE_MEDIA_RECORDER,
CREATE_METADATA_RETRIEVER,
};
这些6个枚举定义对应于IMediaPlayerService接口所提供的6个功能函数,可以称为这些功能函数的功能代码,用于在进程之间进行RPC是标识需要调用哪个函数。如果不想定义这些枚举值,在后面需要用到这些值的地方直接写上1,2,3,4,5,6也是可以的,不过……一个合适的程序员会这么干吗?
下面看一下BpMediaPlayerService的代码。
(3) BpMediaPlayerService代码分析
class BpMediaPlayerService: public BpInterface
{
public:
BpMediaPlayerService(const sp& impl)
: BpInterface(impl)
{
}
virtual sp createMetadataRetriever(pid_t pid)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
data.writeInt32(pid);
remote()->transact(CREATE_METADATA_RETRIEVER, data, &reply);
return interface_cast(reply.readStrongBinder());
}
virtual sp create(pid_t pid, const sp& client, const char* url)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
data.writeInt32(pid);
data.writeStrongBinder(client->asBinder());
data.writeCString(url);
remote()->transact(CREATE_URL, data, &reply);
return interface_cast(reply.readStrongBinder());
}
virtual sp createMediaRecorder(pid_t pid)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
data.writeInt32(pid);
remote()->transact(CREATE_MEDIA_RECORDER, data, &reply);
return interface_cast(reply.readStrongBinder());
}
virtual sp create(pid_t pid, const sp& client, int fd, int64_t offset, int64_t length)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
data.writeInt32(pid);
data.writeStrongBinder(client->asBinder());
data.writeFileDescriptor(fd);
data.writeInt64(offset);
data.writeInt64(length);
remote()->transact(CREATE_FD, data, &reply);
return interface_cast(reply.readStrongBinder());
}
virtual sp decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
data.writeCString(url);
remote()->transact(DECODE_URL, data, &reply);
*pSampleRate = uint32_t(reply.readInt32());
*pNumChannels = reply.readInt32();
*pFormat = reply.readInt32();
return interface_cast(reply.readStrongBinder());
}
virtual sp decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
data.writeFileDescriptor(fd);
data.writeInt64(offset);
data.writeInt64(length);
remote()->transact(DECODE_FD, data, &reply);
*pSampleRate = uint32_t(reply.readInt32());
*pNumChannels = reply.readInt32();
*pFormat = reply.readInt32();
return interface_cast(reply.readStrongBinder());
}
};
首先可以看到,这个类继承自模板类BpInterface,指定类型为接口类IMediaPlayerService。BpInterface模板类定义在文件IInterface.h。看一下BpInterface的定义就可以发现,BpMediaPlayerService这样定义了以后,事实上间接继承了IMediaPlayerService,从而可以提供IMediaPlayerService接口所定义的接口函数。 BpMediaPlayerService需要实现这些接口函数。在一个简单的构造函数之后,就是这些接口函数的实现。可以看到,所有的接口函数的实现方法都是一致的,都是通过binder所提供的机制将参数仍给binder的实现类,并获取返回值。这也就是这个类之所以成为代理类的原因。下面具体看一下一个接口函数。这里选的是函数create(url)。
virtual sp create(pid_t pid, const sp& client, const char* url)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
data.writeInt32(pid);
data.writeStrongBinder(client->asBinder());
data.writeCString(url);
remote()->transact(CREATE_URL, data, &reply);
return interface_cast(reply.readStrongBinder());
}
这个接口函数的参数指定了一个URL,函数将为这个URL创建一个播放器实例用于播放该URL。
函数首先定义了两个局部变量data和reply,变量的类型都是Parcel。Parcel是一个专为binder通信的数据传送而定义的类,该类提供了对多种类型的数据的封装功能,同时提供多个数据读取和写入函数,用于多种类型的数据的写入和读取,支持的数据类型既包括简单数据类型,也包括对象。这里定义的变量data是用于封装create()函数调用所需要的输入参数,而reply则是用于封装调用的返回数据(包括输出参数的值和函数返回值)。
函数首先向data中写入各种数据。第一个写入的是接口的一个描述字符串,binder的实现类中会用这个字符串来对接口做验证,防止调用错误。这个字符串也可以不写,如果不写,在binder实现类中相应的也就不要做验证了。跟在描述字符串后面写入的是该接口函数所需要的各种的输入参数。需要说明的是,Pacel提供一种先入先出的数据存储方式,即数据的写入顺序和读取顺序必须严格一致,否则将会出错。
完成数据写入后,函数调用remote()->transact()用于完成binder通信。transact()函数的第一个参数就是前面提到过的功能代码。transact()的功能是将data中的数据传给binder的实现类,函数调用结束后,reply中将包含返回数据。首先来看看 remote()成员函数。前面讲到过BpMediaPlayerService通过继承BpInterface模板类间接继承了 IMediaPlayerService接口类,其实BpInterface类是一个有两个父类的多重继承子类,另一个父类是 BpRefbase(frameworks\base\include\utils\Binder.h)。remote()就是继承自BpRefBase 类的一个成员函数,该函数返回BpRefBase类中定义的一个私有属性mRemote。mRemote是对IBinder接口类的子类BpBinder 的一个对象的引用(参考前面的类关系图)。transact()函数在IBinder接口类中定义(frameworks\base\include \utils\Binder.h),并在BpBinder类中实现(frameworks\base\include\utils \BpBinder.h、frameworks\base\libs\utils\BpBinder.cpp)。在transact()函数中将调用 IPCThreadState类的transact()函数,并进而通过Lniux内核中的android共享内存驱动来实现进程间通信。不过这些细节这里就不多说了。在这里BpBinder类对象是一个关键,是实现Binder代理的核心之一。BpBinder类可以看成是一个通信handle(类似于网络编程中的socket),用于实现进程间通信。接下来需要研究的是这个BpBinder类对象(即mRemote成员变量的值)是从哪里来的。
回过头来BpMediaPlayerService的构造函数(看前面的代码)。该构造函数的参数是一个IBinder对象的引用。mRemote的值就是在这里传进来的这个对象。那么这个对象又是怎么来的呢?要搞清楚这一点就需要找到创建BpMediaPlayerService类的实例的代码,这个代码就就跟在该类的定义代码的下面。继续看IMediaPlayerService.cpp文件,在BpMediaPlayerService类定义的后面,是下面这样一行代码:
IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.hardware.IMediaPlayerService");
这行代码调用了一个宏定义IMPLEMENT_META_INTERFACE()。这个宏定义与前面提到过的 DECLARE_META_INTERFACE()相呼应。看名字就知道,IMPLEMENT_META_INTERFACE()宏是对 DECLARE_META_INTERFACE()所定义的成员函数的具体实现。这个宏的第一个参数与DECLARE_META_INTERFACE() 的参数需完全一样,第二参数是接口的描述字符串(这个字符串前面也已经讲到过了)。描述字符串不重要,重要的是宏里面定义的一个静态成员函数 asInterface()。BpMediaPlayerService的类实例是在IMediaPlayerService的静态成员函数 asInterface()中创建的,在IInterface.h中定义了一个内联函数interface_cast(),对这个成员函数进行了封装。通过看代码容易知道,BpMediaPlayerService的构造函数的参数是通过interface_cast()的参数传进来的。
好,下面就该看看这个interface_cast()是在哪里调用的,它的参数到底是什么。找到frameworks\base\media \libmedia\mediaplayer.cpp文件,其中的MediaPlayer::getMediaPlayerService()的实现代码:
const sp& MediaPlayer::getMediaPlayerService()
{
Mutex::Autolock _l(sServiceLock);
if (sMediaPlayerService.get() == 0) {
sp sm = defaultServiceManager();
sp binder;
do {
binder = sm->getService(String16("media.player"));
if (binder != 0)
break;
LOGW("MediaPlayerService not published, waiting...");
usleep(500000); // 0.5 s
} while(true);
if (sDeathNotifier == NULL) {
sDeathNotifier = new DeathNotifier();
}
binder->linkToDeath(sDeathNotifier);
sMediaPlayerService = interface_cast(binder);
}
LOGE_IF(sMediaPlayerService==0, "no MediaPlayerService!?");
return sMediaPlayerService;
}
看一下上面这段代码中的红色字体部分。结合前面的分析,可知BpBinder类的对象实例是从android的服务管理器的getService()函数中获取,进一步追进去,会发现下面这样一段代码:
{
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
return reply.readStrongBinder();
}
Android的服务管理器是一个单独的进程,也向外提供接口。这段代码的含义,是通过Android的服务管理器的接口代理,请求调用服务管理器的 checkService()接口函数,查找指定的服务(上面就是查找media.player服务),查找成功后返回一个BpBinder类的对象实例,用于供IMediaPlayerService代理使用。这个对象BpBinder是在Parcel::readStrongBinder()函数里面创建的。那么到底是怎么创建出来的呢?在这里没有必要追到ServiceManager的实现代码里去,毕竟我们只是想知道BpBinder的对象是如何创建的,我们可以换一个例子来看。回到前面的BpMediaPlayerService::create()函数的实现,是不是很眼熟。没错,在那个函数里也创建了一个BpBinder类对象,那个对象是是给IMediaPlayer接口代理使用的。虽然接口不同,但是创建原理是一样的。我们继续,下面该到binder的另一个类——实现类的代码了。
(3) BnMediaPlayerService代码分析
BnMediaPlayerService类的定义在文件frameworks\base\include\media \IMediaPlayService.h,实现则与BpMediaPlayerService一样是在文件frameworks\base\media \libmidia\IMediaPlayerService.cpp中。类定义的代码如下:
class BnMediaPlayerService: public BnInterface
{
public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
};
这个类继承自BnInterface模板类,约束类型为IMediaPlayerService。看一下BnInterface模板类的定义(IInterface.h)就可以知道,BnMediaPlayerService间接继承了IMediaPlayerService接口类。不过 BnInterface类并没有实现IMediaPlayerService所定义的6个接口函数,因此BnInterface还是一个纯虚类。这些接口需要在BnMediaPlayerService的子类中真正实现,这个子类就是MediaPlayerService(frameworks\base \media\libmidiaservice\MediaPlayerService.h,frameworks\base\media \libmidiaservice\MediaPlayerService.cpp)。在BnMediaPlayerService的成员函数 onTransact()中,需要调用这6个接口函数。BnMediaPlayerService中主要就是定义并实现了onTransact()函数。当在代理那边调用了transact()函数后,这边的onTransact()函数就会被调用。BnMediaPlayerService的实现代码如下:
#define CHECK_INTERFACE(interface, data, reply) \
do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
LOGW("Call incorrectly routed to " #interface); \
return PERMISSION_DENIED; \
} } while (0)
status_t BnMediaPlayerService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case CREATE_URL: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
pid_t pid = data.readInt32();
sp client = interface_cast(data.readStrongBinder());
const char* url = data.readCString();
sp player = create(pid, client, url);
reply->writeStrongBinder(player->asBinder());
return NO_ERROR;
} break;
case CREATE_FD: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
pid_t pid = data.readInt32();
sp client = interface_cast(data.readStrongBinder());
int fd = dup(data.readFileDescriptor());
int64_t offset = data.readInt64();
int64_t length = data.readInt64();
sp player = create(pid, client, fd, offset, length);
reply->writeStrongBinder(player->asBinder());
return NO_ERROR;
} break;
case DECODE_URL: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
const char* url = data.readCString();
uint32_t sampleRate;
int numChannels;
int format;
sp player = decode(url, &sampleRate, &numChannels, &format);
reply->writeInt32(sampleRate);
reply->writeInt32(numChannels);
reply->writeInt32(format);
reply->writeStrongBinder(player->asBinder());
return NO_ERROR;
} break;
case DECODE_FD: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
int fd = dup(data.readFileDescriptor());
int64_t offset = data.readInt64();
int64_t length = data.readInt64();
uint32_t sampleRate;
int numChannels;
int format;
sp player = decode(fd, offset, length, &sampleRate, &numChannels, &format);
reply->writeInt32(sampleRate);
reply->writeInt32(numChannels);
reply->writeInt32(format);
reply->writeStrongBinder(player->asBinder());
return NO_ERROR;
} break;
case CREATE_MEDIA_RECORDER: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
pid_t pid = data.readInt32();
sp recorder = createMediaRecorder(pid);
reply->writeStrongBinder(recorder->asBinder());
return NO_ERROR;
} break;
case CREATE_METADATA_RETRIEVER: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
pid_t pid = data.readInt32();
sp retriever = createMetadataRetriever(pid);
reply->writeStrongBinder(retriever->asBinder());
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
首先是一个宏定义CHECK_INTERFACE(),这个宏定义的作用是检查接口的描述字符串,这个前面也提到过,不需细说。然后就是 onTrasact()函数的实现。这个函数的结构也很简单,就是根据参数code的值分别执行不同的功能调用。code的取值就是前面提到过的接口功能代码。函数的参数除了code,还包括Parcel类的两个对象data和reply,分别用于传送输入参数和返回数据,与transact()函数的参数相对应。还有一个参数flag在这里用不上,不讨论。对应我们前面所选择的接口函数的例子create(url),看看这边对应的实现:
case CREATE_URL: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
pid_t pid = data.readInt32();
sp client = interface_cast(data.readStrongBinder());
const char* url = data.readCString();
sp player = create(pid, client, url);
reply->writeStrongBinder(player->asBinder());
return NO_ERROR;
}
首先是从data对象中依次取出各项输入参数,然后调用接口函数create()(将在子类MediaPlayerService中实现),最后向reply中写入返回数据。这个函数返回后,代理那边的transact()也会跟着返回。
那么onTransact()函数是怎么被调用的呢?通过查看BnInterface模板类的定义可以看到,这个类也是一个多重继承类,另一个父类是 BBinder(frameworks\base\include\utils\Binder.h,frameworks\base\libs \utils\Binder.cpp)。BBinder类继承自IBinder,也实现了transact()函数,在这个函数中调用 onTransact()函数。而BBinder对象的transact()函数则是在IPCThreadState类的 executeCommand()成员函数中调用的。这已经涉及到较底层的实现,在这里不再多说。
上面这部分代码还与前面提到过的BpBinder对象的创建有关系。看其中的红色字体部分,通过create()函数调用会创建一个 IMediaPlayer接口类的子类的对象,这个对象其实是MediaPlayerService::Client类(可以看一下 MediaPlayerService的定义)的对象实例,而MediaPlayerService::Client类是继承自 BnMediaPlayer类的,与BnMediaPlayerService类类似,BnMediaPlayer其实也是一个binder实现类(是 BBinder的子类,进而也是IBinder的子类)。在上述代码中,通过Parcel的writeStrongBinder()函数将这个对象写入 reply,而在代理侧,通过Parcel的readStrongBinder()函数读取则可以得到一个BpBinder的对象。至于类的具体创建过程已经封装在Parcel类的定义中,这里就不再多说了。
(4) 接口功能的真正实现
到这里两个binder类就已经定义完了,下面就是IMediaPlayerService接口函数的真正实现。前面已经说过这些函数在类 MediaPlayerService中实现。这个类继承自BnMediaPlayerService,也间接地继承了 IMediaPlayerService接口类定义的6个功能函数,只需要按照正常方式实现这6个功能函数即可,当然为了实现这6个函数就需要其它一大堆的东西,不过这些具体的实现方法已经与binder机制无关,不再多说。
在MediaPlayerService类中定义了一个静态函数instantiate(),在这个函数中创建MediaPlayerService的对象实例,并将这个对象注册到服务管理器中。这样需要使用的时候就可以从服务管理器获取IMediaPlayerService的代理对象。这个 instantiate()是在MediaServer程序的main()函数中调用的。
void MediaPlayerService::instantiate() {
defaultServiceManager()->addService(
String16("media.player"), new MediaPlayerService());
}
(三) 总结一下
说了这么多,总结一下。下图是binder机制的层次模型。
如果一个服务需要通过binder机制对外提供跨进程的接口,需要做下面这些事情。
(1) 第一步,需要为这个接口定义一个继承自IInterface的接口类,假设叫做IMyService。
(2) 第二步,需要定义两个binder类,其中一个是代理类BpMyService,需继承自BpInterface;另一个是实现类BnMyService,需继承自BnInterface。
(3) 第三步,定义BnMyService的子类,这个子类可以是任何名字,比如就叫MyService,在其中真正实现接口所提供的各个函数。
(4) 第四步,创建MyService的实例,注册到服务管理器(如IMediaPlayerService),也可以在其它接口的函数中创建(如上面的IMediaPlayer)。
发表评论
-
SystemServer进程的启动
2012-05-02 16:43 50319.4 SystemServer进程的启 ... -
如何向android的framework里添加新类
2011-08-19 16:23 1267http://xxw8393.blog.163.c ... -
java和C设置的系统属性-互相访问
2011-06-23 11:29 1263JAVA import android.os.Syst ... -
Android——init.rc脚本
2011-06-16 10:01 5061http://java-admin.iteye.com/blo ... -
android 增加内部flash时容易忘记的一点-数据库操作-删除文件
2011-05-31 15:06 3083其他中间层做好后,发现在Gallery中无法删除flash(或 ... -
MIPS android 编译总结
2011-05-24 09:29 2003http://www.huomo.cn/developer/a ... -
Android Wifi模块分析(六)
2011-05-09 18:08 1083Android Wifi模块分析(六 ... -
Android Wifi模块分析(五)
2011-05-09 18:05 1047Android Wifi模块分析(五) 本文来自:http: ... -
Android Wifi模块分析(四)
2011-05-09 14:13 1178Android Wifi模块分析(四) 2010-02-08 ... -
Android Wifi模块分析(三)
2011-05-09 14:10 1490Android Wifi模块分析(三) 本文来自:http: ... -
Android Wifi模块分析(一)
2011-05-09 14:09 1696Android Wifi模块分析(一 ... -
Android Wifi模块分析(二)
2011-05-09 14:07 2054Android Wifi模块分析(二) 本文来自:http: ... -
Android Wifi模块分析(总览)
2011-05-09 14:05 1706Android Wifi模块分析(总览) 本文来自:http ... -
关于Android2.2定制出厂默认输入法的一些心得
2011-05-04 14:10 2298有些输入法预制到系统中时默认情况下是不能直接使用的,要在设置- ... -
Android2.2下实现Ethernet上网
2011-05-03 16:19 1673最近在做Android2.2实现Ethernet上网,在网上找 ... -
AIDL(android 接口描述语言)
2011-04-29 10:21 1032http://www.devdiv.com/foru ... -
Android自带音乐播放器专辑图片相同的问题
2011-04-19 16:41 2102音乐播放器是从MediaProvi ... -
Android 多媒体扫描过程
2011-04-18 10:25 1227本文来自:http://yueguc.iteye.com/bl ...
相关推荐
androidbinder学习笔记(图文).pdf
总结来说,Android Binder入门学习需要理解以下几个关键点: 1. **Binder机制**:是Android系统实现进程间通信的基础,允许不同进程的对象交互。 2. **代理模式**:在Binder机制中,客户端通过代理对象间接调用...
《Android群英传笔记》是一本...总的来说,《Android群英传笔记》是Android开发者的一份珍贵参考资料,它涵盖了Android开发的各个关键领域,通过深入学习,你将能够提升自己的专业技能,成为一名真正的Android群英。
由于无法查看提供的图片内容,我将依据标题、描述和标签的信息,结合对Android Binder机制的知识,提供一份详细的Binder笔记。 Binder机制是Android系统中用于进程间通信(IPC)的一种重要机制。它是Android系统的...
6. **服务和服务绑定**:Android服务用于在后台执行长时间运行的任务,课程会介绍如何创建和管理服务,以及如何通过Binder机制进行服务间的通信。 7. **通知和广播接收器**:这部分将讲述如何使用通知来与用户交互...
在Android学习过程中,涵盖了许多关键知识点,这些知识点构成了Android...以上就是Android学习笔记的主要内容,涵盖了从基础概念到高级特性的全方位知识体系。通过深入理解和实践,开发者能够熟练掌握Android应用开发。
在“android service 学习笔记(下)”中,主要讨论了如何利用AIDL(Android Interface Definition Language)进行跨进程通信(IPC, Inter-Process Communication)。 AIDL是一种接口描述语言,它的作用是在Android...
【Android 源码分析与学习笔记】 在深入探索 Android 开发的过程中,源码阅读是提升技术水平的关键步骤。Android 源码包含了操作系统层面、框架层以及应用开发接口等各个层次的实现细节,有助于开发者理解系统行为...
在Android应用开发中,Activity和Intent是两...开发者需要深入学习这两个概念,以便更好地设计和实现功能丰富的Android应用。在实际开发中,不断实践和调试,结合源码阅读,将有助于提升对Android系统运行机制的理解。
### Android艺术开发探索读书笔记(1-3章) #### 概述 《Android艺术开发探索》一书深入探讨了Android应用开发的核心技术和实践方法。本书第1至3章重点介绍了Activity生命周期、启动模式以及Android IPC机制等内容...
这份"Android-notes.zip"压缩包显然包含了作者关于Android环境设置和开发学习的一些笔记,是初学者和有经验的开发者都非常宝贵的参考资料。以下是一些可能涵盖的关键知识点: 1. **Android Studio安装与配置**:...
Android作为目前最流行的操作系统之一,拥有庞大...在这个过程中,资料如《Android学习路线指南》、《我对Android的理解》以及《Android学习路线:如何成长为高级工程师》等,都是帮助开发者系统学习和成长的重要参考。
在Android学习过程中,掌握核心概念和技术是至关重要的。这篇学习记录着重关注了Android系统的源码分析和实用工具的运用,这对于提升开发技能和理解系统运行机制有着极大的帮助。以下是基于标题和标签提炼出的一些...
13. **Android组件间通信**:理解Binder机制,学习如何使用IntentService、BroadcastReceiver、ContentProvider等组件进行跨进程通信。 以上只是部分可能涵盖的内容,具体的"Android基础笔记"可能会根据课程深度和...
本学习笔记将深入探讨AIDL的基本概念、使用方法及其在实际开发中的应用。 首先,我们需要理解AIDL的定义:它是Android提供的一种接口定义语言,允许我们定义服务(Service)如何公开其接口给其他应用程序组件,即使...
本笔记将深入探讨AIDL的基本概念、使用方法以及其在Android应用开发中的重要性。 首先,理解AIDL的初衷非常重要。在多进程环境下,Android系统中的两个或更多进程之间无法直接共享对象,因此需要一种机制来交换数据...
本笔记将深入探讨Android插件化开发的相关知识,帮助你掌握这一核心技能。 1. **插件化开发原理** 插件化开发的核心思想是将应用的主要功能分解为可独立编译、运行的模块,这些模块称为插件。主程序(宿主)负责...