加载中…
个人资料
Steven天天Helloworld
Steven天天Helloworld
  • 博客等级:
  • 博客积分:0
  • 博客访问:4,491
  • 关注人气:4
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
相关博文
推荐博文
正文 字体大小:

android平台自己编写的framework级service server

(2012-08-16 09:33:28)
分类: Android驱动学习笔记
本文注释主要参考一本棒子的android书籍,《android框架揭秘》。
代码参考Michael Richarddson公布在github上的Android-HelloWorldService代码。

首先,android的service framework由三部分构成:
1.服务接口
2.服务
3.服务代理

首先,看服务接口:
先看头文件:
#ifndef IHELLOWORLDSEVICE_H
#define IHELLOWORLDSEVICE_H

#include <binder/IInterface.h>

namespace android{
enum{
    HW_HELLOWORLD = IBinder::FIRST_CALL_TRANSACTION,
};

class IHelloWorldService: public IInterface{
public:
    //服务接口宏
    DECLARE_META_INTERFACE(HelloWorldService);------------<1>
    //服务函数
    virtual status_t helloWorld(const char *str)=0;---------<2>
};//class IHelloWorldService
};//namespace android

#endif

-------------IHelloWorldService.h
<1>这是一个声明接口宏,宏扩展以后,生成虚函数的声明,表示了服务接口所要完成的基本功能
<2>这是自己编写的服务的服务接口。

#include <helloworld/IHelloWorldService.h>
#include <helloworld/BpHelloWorldService.h>

namespace android{

//接口宏
            IMPLEMENT_META_INTERFACE(HelloWorldService,"android.apps.IHelloWorldService");------<1>
};  //namespace android
---------------IHelloWorldService.cpp
<3>这是一个android service framework提供的一个编写接口定义的接口宏,这里会扩展成一系列的函数定义,可以实现的<1>中声明的服务,<1><3>一般配对使用。

helloworld服务
首先,要实现RPC的stub实务服务,即解决RPC传输,和RPC解析任务的函数,下面是头文件:
#ifndef BNHELLOWORLDSERVICE_H_
#define BNHELLOWORLDSERVICE_H_

#include <binder/Parcel.h>
#include <helloworld/IHelloWorldService.h>

namespace android{
class BnHelloWorldService : public BnInterface<IHelloWorldService>{
public:
    //重定义BBinder类的onTransact()方法
    virtual status_t onTransact(-------------------<4>传输函数
            uint32_t code,
            const Parcel& data,
            Parcel* reply,
            uint32_t flags=0);
};
};//namespace android

#endif
---------------------------BnHelloWorldService.h
BnService的主要工作就是解析RPC数据,并定位具体服务,这里很明显,就是一个onTransact()的函数重定义,这个函数是完成传输transact实务的函数。

下面是完成具体实务的stub函数的cpp文件:
#include <helloworld/BnHelloWorldService.h>
#include <binder/Parcel.h>

namespace android{

status_t BnHelloWorldService::onTransact(
        uint32_t code,
        const Parcel &data,
        Parcel *reply,
        uint32_t flags){
    switch(code){-------------------------<5>
    case HW_HELLOWORLD:{
        //确认是正确的请求
        CHECK_INTERFACE(IHelloWorldService,data,reply);
        const char *str;
        //读取来自服务的用户端的字符串
        str = data.readCString();
        //调用输出方法,向标准输出设备输出接收到的字符串
        reply->writeInt32(helloWorld(str));
        return NO_ERROR;
    }break;
    default:
        return BBinder::onTransact(code,data,reply,flags);
    }
}
};//namespace android
-------------------------BnHelloWorldService.cpp
<5>这个switch关键字,完成的就是RPC数据解析的任务,通过具体的RPC码code,转向具体的服务。

最后,helloworld服务类,还是先看头文件:
#ifndef HELLOWORLDSERVICE_H
#define HELLOWORLDSERVICE_H

#include <binder/Parcel.h>
#include <helloworld/BnHelloWorldService.h>
#include <utils/Log.h>

namespace android{
class HelloWorldService : public BnHelloWorldService{
    public:
    //初始化HelloWorldService向上系统注册服务
    static void instantiate();-----------------<6>
    //具体实现服务接口的方法
    virtual status_t helloWorld(const char *str);-----------<7>
    virtual status_t onTransact(
            uint32_t code,
            const Parcel& data,
            Parcel* reply,
            uint32_t flags);
    private:
    HelloWorldService();-----------<8>
    virtual ~HelloWorldService();
};
};//namespace android

#endif
-----------------------HelloWorldService.h
<6>这个是实现“单例模式”的一种编程方法,与<8>配合,实现一个类只有一个对象。因为一个服务只有一个服务实体,因此要采用“单例模式”。
<7>这个是本地调用服务实例的入口函数,这里执行具体的实务。

下面是这个HelloWorldService.h的具体实现代码:

#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include <helloworld/BnHelloWorldService.h>
#include <helloworld/HelloWorldService.h>
#include <utils/Log.h>

namespace android{
void HelloWorldService::instantiate(){
    printf("instantiate start...\n");-----------------这里加入了调试print代码
    defaultServiceManager()->addService(
            String16("android.app.IHelloWorldService"),new HelloWorldService);-----<8>
    printf("addservice over.\n");
}
status_t HelloWorldService::helloWorld(const char* str){
    printf("%s \n",str);
    return NO_ERROR;
}
HelloWorldService::HelloWorldService(){
    printf("HelloWorldService is created\n");------------------这里加入了print调试代码
    printf("and helloworld need to test!\n");
}
HelloWorldService::~HelloWorldService(){
    printf("HelloWorldService is destroyed\n");
}
//---------------------------------------------------------------------------------

status_t HelloWorldService::onTransact(
        uint32_t code,
        const Parcel& data,
        Parcel* reply,
        uint32_t flags){
    return BnHelloWorldService::onTransact(code,data,reply,flags);-------<9>
}
//----------------------------------------------------------------------------------

};//namespace android
----------------HelloWorldService.cpp
<8>这里通过成员函数控制类的入口,然后在成员函数中调用构造函数,如黑体标识,实现对象的“单例模式”。
<9>这里把数据让下一层的BnHelloWorldService实现。

最后,实现helloworld服务代理BpHelloWorldService
首先,头文件:
#ifndef BPHELLOWORLDSERVICE_H_
#define BPHELLOWORLDSERVICE_H_

#include <binder/Parcel.h>
#include <helloworld/IHelloWorldService.h>

namespace android{
class BpHelloWorldService: public BpInterface<IHelloWorldService>{
public:
    BpHelloWorldService(const sp<IBinder>& impl);
    virtual status_t helloWorld(const char *str);
};
};//namespace android

#endif
-------------------------BpHelloWorldService.h

#include <binder/Parcel.h>
#include <helloworld/BpHelloWorldService.h>

这里没有太多好说的,声明了一个构造函数,和一个代理服务函数,来给上层调用RPC提供接口。

namespace android{
status_t BpHelloWorldService::helloWorld(const char *str){
    Parcel data,reply;
    //将服务接口名称保存到发送数据中
    data.writeInterfaceToken(
            IHelloWorldService::getInterfaceDescriptor());
    //将输出字符串保存在发送数据中
    data.writeCString(str);
    //调用BpBinder类的transact()方法
    status_t status=remote()->transact(HW_HELLOWORLD,data,&reply);
    if(status != NO_ERROR){
    }else{
        //读取helloWorld()方法的调用结果
        status = reply.readInt32();
    }
    return status;
}

BpHelloWorldService::BpHelloWorldService(const sp<IBinder>& impl):
        BpInterface<IHelloWorldService>(impl){}
};//namespace android
------------------------BpHelloWorldService.cpp
上面的函数的具体执行,写在了注释中,其实,所有的BpSevice大同小异,框架都和上面差不多,解决的问题其实就是把RPC转换成可以传输的格式,进行传输。

这样,一个helloworld service就编写好了,下面我们还要再写一个服务端和客户端的启动程序。
首先,下面是一个服务端启动程序:
#include<binder/IPCThreadState.h>
#include<binder/ProcessState.h>
#include<binder/IServiceManager.h>
#include<utils/Log.h>

#include<helloworld/HelloWorldService.h>

using namespace android;

int main(){
    printf("begin!\n");
    HelloWorldService::instantiate();
    printf("instantiate.\n");
    ProcessState::self()->startThreadPool();
    printf("startThreadPool.\n");
    IPCThreadState::self()->joinThreadPool();
    printf("jointhreadpool.\n");

    return 0;
}
------------------helloworldservice.cpp
其实代码很简单,这里加入了我后来用来调试的print代码,大多数的Service的启动程序差不多,可以参考Audio服务的启动,会发现基本程序大差不差,首先,初始化服务,然后,生成transact线程,然后,把它插入干活进程队列中。

下面是客户端启动进程:
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>

#include <utils/Log.h>
#include <utils/RefBase.h>
#include <helloworld/IHelloWorldService.h>


using namespace android;

int main(int argc, char *argv[]) {
    sp<IServiceManager> sm = defaultServiceManager();------------<10>
    if(sm!=0)printf("get the sm seccess.\n");-------------插入的测试print代码
    printf("get the sm.\n");
    sp<IBinder> b;
    printf("get the IBinder\n");
    sp<IHelloWorldService> sHelloWorldService;
    printf("get sHelloWorldService.\n");

    do{
        b=sm->getService(String16("android.app.IHelloWorldService"));
        printf("getting the setvice.\n");
        if(b!=0){
            printf("get the service success.\n");
            break;
        }
        usleep(5000000);
        printf("weak up.\n");
    }while(true);-----------------循环申请服务,发送RPC数据

    sHelloWorldService = interface_cast<IHelloWorldService>(b);-----------<11>
    printf("interface cast\n");
    sHelloWorldService->helloWorld("hello,world");

    return(0);
}
-----------------helloworldclient.cpp

<10>获得远程的Service Manager的BpServiceManager的实例,以与Service Manager通信。
<11>这里interface_cast不是一个简单转换,是一个复杂的函数,由android framework service框架提供模板,可以把一个服务接口,转换成一个IBinder对象,这里把一个接口类转换为Bpinder对象,用于与Helloworld Service通信。
这样代码就全部完成。

代码完成是工程的一半。下一步是如何把它编译进android镜像。
下一篇,介绍,我自己用android 提供的 make工具,如何编译上面的service代码。

0

阅读 评论 收藏 转载 喜欢 打印举报/Report
  • 评论加载中,请稍候...
发评论

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

      

    新浪BLOG意见反馈留言板 电话:4000520066 提示音后按1键(按当地市话标准计费) 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有