本文学习自高焕堂老师的Android从程序员到架构师之路系列教学视频
98 - 认识Android核心服务a
1. 区分核心服务与App服务
• 在Android平台,上层App的SDK-based Service与底层的核心服务有很大的区别,只是许多人都将它们混在一起了。
• 于此,兹说明Android里有2种服务:
1. 应用层的应用服务,通称为SDK-based Service(或称为 App服务)。
2. 系统层的核心服务,通称为Core Service(或称为System Service)。
App服务
• 至于App服务(即SDK-based Service)则属于App的一部份,是开机完成后,用户加载并开启某App时,才会启动该App里的服务。这种App服务的特征是,它会定义成为Service的一个子类别。
• 如下图的myService子类别,它继承Android应用框架里的Service基类。
• 在Android开机过程中,就会启动数十个核心服务。当开机完成时,全部核心服务也都启动完成了。
• 接着,才能启动App,并执行之。所以,核心服务的启动时间早于App的启动时间。
• AMS(ActivityManagerService)启动一个App的时候,就会通过Socket请求Zygote来fork一个进程给这个即将要启动的App。
• 也就是说,当App服务启动时,核心服务早已经启动存在了。
• 因此,myService可以透过MediaPlayer和JNI来绑定(Bind)和调用核心服务MediaPlayerService。
• 其中的myService就是一个App服务;而MediaPlayerService就是一个核心服务。到此,已经初步介绍了核心服务的特性,让你能对分辨核心服务和App服务的微妙区别了。
2. 回忆App服务
• 核心服务是系统层的「前装型」服务
–大多以C++类别实现,有些以Java类别实现。
–可透过ServiceManager来建立和绑定(Bind)核心服务。
–绑定后,可透过IBinder接口去执行其函数。
• App服务是应用层的「后装型」服务
–以Java层的Service的应用子类别实现。所有的App服务都是由ActivityManagerService核心服务所掌管。
–在应用层(如Activity)可调用Android框架里Context类别的startService()和bindService()函数去绑定App服务。
–绑定后,可透过IBinder接口去执行其函数。
99 - 认识Android核心服务b
3. 区分两种核心服务:Android Service与Native Service
• 核心服务可以用Java撰写;也可以用C++撰写。
• 以Java撰写的核心服务通称为Android Service(例如AudioService和SensorService等);
• 以C++撰写的核心服务则通称为Native Service (例如MediaPlayerService和CameraService等)。
• Android Service又称为Java Service,是实现于应用框架层(Framework)里的。
• 这里所讲的Service是系统服务(System Service),又称为Server;其与App开发上所讨论的Service不同。
• Android Service以Java撰写。
• Native Service则是实现于Runtime层里的Server。在系统服务开发上,我们有二个途径,一个是写成Android Service、其再透过JNI与HAL驱动沟通;另一个途径是,跳过Android Service,让App透过JNI直接与Native Service沟通。
4. 核心服务的特性
• 其中,核心服务属于Android平台的系统服务模块,在开机过程,就会启动数十个核心服务;例如MediaPlayerService、AudioService、SensorService等。
• 关于核心服务的启动,就是在开机时,加载Linux kernel部分,进行Kernel-Space的初始化,然后加载硬件驱动程序,就启动了Linux系统。随后切换至User-Space,创建init进程,读取 init.rc文档,依据其内容的指示而先启动Native Service,再启动Android Service。就完成核心服务的启程序了。
• 由Linux内核启动用户空间的Init进程 解析脚本文件:Init.rc
Init.rc是Android的初始化脚本
• 由Init进程创建ServiceManager和Zygote进程。
• 由Zygote创建(VM和)SystemServer进程。
核心服务的特性
• 核心服务通常在特定的进程里执行。
• 必须提供IBinder接口,让App进行跨进程的绑定(Bind)和呼叫。
• 因为共享,所以必须确保多线裎安全(Thread-safe)
• 以C++类别或Java类别定义,诞生其对象,请ServiceManager(简称SM)将该对象参考值加入到Binder Driver里。
• App可请SM协助而远距绑定某核心服务,此时SM会传IBinder接口给App。
• App可透过IBinder::transact()函数来与核心服务互传讯息。
• 核心服务启动在先,应用程序启动在后。
• 核心服务能以C++撰写;也可以用Java撰写(如AudioService)。
• 核心服务与App服务不同,App服务不会加入到Binder Driver里。
100 - 认识Android核心服务c
5. 简介几个Android Service
• 在Android Service里,常见的有如ActivityManager、LocationManager等。兹针对其中的几个常见服务介绍如下:
• Activity Manager(活动管理器):提供所有的应用程序的生命周期,以及Activity之间的互动之服务。
• WindowManager(窗口管理器):提供由关频幕窗口之管理服务。
• ResourceManager(资源管理器):管理程序使用的各项资源,例如:字符串、图片、UI布局(Layout)定义档。
• LocationManager(位置管理器):提供位置服务(Location-based Service)。
• TelephonyManager(电话管理器):提供有关手机通话的服务,例如关闭电话等。
• 其它服务。
6. 简介几个Native Service
• Native Service是以C++语言所撰写的核心服务。
• 在Native Service里,大家比较熟悉得有如ServiceManager、MediaPlayerService、Zygote、CameraService等等。
• 兹针对其中的几个常见服务介绍如下:
• ServiceManager(服务管理器):协助登录与绑定系统服务。
• ServiceManager是Android平台里的一个基本模块。在Android系统启动过程中,它就会被登录到Binder Kernel里,成为天字第一号的可提供远距服务之模块。
• 使用C/C++撰写Android的NativeService模块时,可以透过defaultServiceManager()函数来取得ServiceManager模块的IServiceManager接口之指针。例如,在CameraService.cpp程序里的instantiate()函数,其内容如下:
// CameraService.cpp
void CameraService::instantiate() {
defaultServiceManager()->addService(
String16("media.camera"), new CameraService());
}
• 它使用了defaultServiceManager()函数来取得ServiceManager模块,然后呼叫其IServiceManager接口里的addService()函数来将自己对象(即CameraService类别之对象)传给ServiceManager模块,请它登录到Binder Kernel里,成为一个可提供远距服务之模块(即CameraService模块)。
• Zygote服务:Android最内层有个Zygote服务。它是Android Java层的孵化器。Zygote就在幕后复制孵化(Fork)出一个子进程来给这些Java层的系统服务或应用程序。所以,Android的应用程序,以及上述的各项服务,也都是由zygote所繁殖出来的。Zygote服务的架构位置如下图:
• CameraService(摄像服务):其实作于libcameraservice.so共享库里,与底层Camera 硬件的 HAL驱动程序衔接,藉由Linux的 videodev接口来撷取视讯。
• 其它服务。
7. 天字第一号的核心服务: ServiceManager
• 天字第一号的核心服务就是ServiceManager(简称SM)。当Android系统启动时,就会优先将之登记到Binder Driver里,如下图:
• 随后,陆续会有更多的核心服务呼叫SM的addService()函数去登录到BD里。例如,ActivityManagerService也是透过SM而登录到BD里。再如,MediaPlayerService也继续透过SM去登录到BD里,如下图:
• 当Android系统启动完成(主要核心服务也启动完成)之后,就可以启动及执行应用程序了。
• 执行应用程序时,各App服务(亦即Service的子类)都由ActivityManagerService来掌管。
• 例如,App里的myActivity等类别可以使用bindService()来绑定(Bind)到myService服务,然后透过IBinder接口而远程呼叫到myService。之后,myService再透过JNI而呼叫到MediaPlayerService,进而呼叫到更底层的驱动模块。
101 - 认识Android核心服务d
8. 核心服务的共通API:IBinder接口
• 就以ServiceManager(简称SM)为例子,由于SM跑在自己的进程里,为了让别的模块可以来呼叫它的服务,它必需提供共通的IBinder接口,才能让其它进程里的模块来进行IPC沟通。如下图:
• 此刻,如果另一个进程里的C++ Client想与SM互动时,就会透过更底层的ProcesState服务在自己的进程里,诞生一个BpBinder对象,作为BinderDriver的分身(即Proxy对象)。
• 让C++ Client能透过BpBinder而与Binder Driver互动,进而跨进程地与SM沟通,所以BpBinder也间接地扮演SM的分身的角色。如下图所示:
9. BBinder基类实现IBinder接口
• 在C++层实现核心服务时,可继承BBinder父类别而拥有IBinder接口;然后透过ServiceManager而登录到Binder Kernel里,如下图:
• 由于核心服务通常执行于独立的进程里,所以它的Client模块(如下图的MediaPlayer.cpp类别)通常在另一个进程里,与MediaPlayerService之间是跨进程的,如下图:
• C++层的Client模块(如下图的MediaPlayer.cpp类别)就透过ServiceManager来绑定核心服务,如下图:
• Java层的Client模块(如下图的myActivity.java类别)也能透过ServiceManager来绑定核心服务,如下图:
• 同样的C++层机制,也能绑定Java层的SDK-Service。如下图:
102 - 撰写你的第一个核心服务a
1. 为什么要写核心服务呢?
• 为什么需要学习撰写核心服务呢? 其常见的理由是:
1. 核心服务是 Android 框架裡最接近Linux/Driver 的部分。为了充分发挥硬件设备的差異化特性,核心服务是让上层Java 应用程序來使用Driver/HW Device 特色的重要管道。
2. 在开机过程中,就可以启动核心服务(例如汉字输入法服务等),让众多应用程序來共享之。
3. 由于共享,所以能有效降低 Java 应用程序的大小(Size)。
2. 亲自开发一个Native Service:SQRService
• 此核心服务命名为SQRService,它做简单的整數平方(Square)运算。其开发要点为:
1.核心服务通常在特定的进程(Process)裡执行。
2. 必须提供 IBinder 接口,让应用程序可以进行跨进程的绑定(Binding)和调用。
3. 因为共享,所以必须确保多线裎安全(Thread-safe)。
4. 以 C++類定义,诞生其对象,透过SM 之协助,将该对象參考值传给IServiceManager::addService()函數,就加入到Binder Driver 裡了。
5. 应用程序可透过 SM之协助而远距绑定该核心服务,此时SM会回传IBinder接口给应用程序。
6. 应用程序可透过 IBinder::transact()函數來与核心服务互传资料。
亲自撰写
阶段一:撰写服务 以C++撰写一个SQRService
• 步骤1.1: 以C++撰写一个SQRService,它的工作是将一个数值(例如5)做开平方的运算,然后传出其计算结果(例如5的平方值为25)。于是,撰写一个C++类别(名称为SQRService),如下述的程序码:
// SQRService.h
#include <stdint.h>
#include <sys/types.h>
#include <utils/Parcel.h>
#ifndef ANDROID_MISOO_SQRSERVICE_H
#define ANDROID_MISOO_SQRSERVICE_H
#include <utils.h>
#include <utils/KeyedVector.h>
#include <ui/SurfaceComposerClient.h>
namespace android {
class SQRService : public BBinder
{
public:
static int instantiate();
virtual status_t onTransact(uint32_t, const Parcel&,
Parcel*, uint32_t);
SQRService();
virtual ~SQRService();
};
};
#endif
在java层,Binder类实现了IBinder接口
在C++层,BBinder类实现IBinder接口
// SQRService.cpp
#include <utils/IServiceManager.h>
#include <utils/IPCThreadState.h>
#include <utils/RefBase.h>
#include <utils/IInterface.h>
#include <utils/Parcel.h>
#include "SQRService.h"
namespace android {
enum {
SQUARE = IBinder::FIRST_CALL_TRANSACTION,
};
int SQRService::instantiate(){
LOGE("SQRService instantiate");
int r = defaultServiceManager()->addService(
String16("misoo.sqr"), new SQRService());
LOGE("SQRService r = %d\n", r);
return r;
}
SQRService::SQRService(){ LOGV("SQRService created"); }
SQRService::~SQRService(){ LOGV("SQRService destroyed"); }
status_t SQRService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
switch(code) {
case SQUARE: {
int num = data.readInt32();
reply->writeInt32(num * num);
LOGE("onTransact::CREATE_NUM.. n=%d\n", num);
return NO_ERROR;
}
break;
default:
LOGE("onTransact::default\n");
return BBinder::onTransact(code, data, reply, flags);
}}
}; // namespace android
• 步骤1.2: 撰写完成之后,就可以编辑一个Make档案,如下:
// Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
SQRService.cpp
LOCAL_C_INCLUDES := \
$(JNI_H_INCLUDE)
LOCAL_SHARED_LIBRARIES := \
libutils
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE := libSQRS01
include $(BUILD_SHARED_LIBRARY)
• 执行此Android.mk 就可进行编译(Compile)和连结(Link),来产出libSQRS01.so 共享库。
• 步骤1.3: 使用 C++撰写可独立执行的addserver.cpp 程序。此程序先创建SQRService的对象,然后将它Binder Driver 裡。此addserver.cpp 的内容如下:
暂时不该写init.rc文档,以及重新启动设备,先使用addserver程序来测试这个核心服务
// addserver.cpp
#include <sys/types.h>
#include <unistd.h>
#include <grp.h>
#include <utils/IPCThreadState.h>
#include <utils/ProcessState.h>
#include <utils/IServiceManager.h>
#include <utils/Log.h>
#include <private/android_filesystem_config.h>
#include "../libadd/SQRService.h"
//#include <libadd/SQRService.h>
using namespace android;
int main(int argc, char** argv)
{
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
LOGI("ServiceManager: %p", sm.get());
SQRService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
• 上述步骤,分别建立了libSQRS01.so 和addserver 可执行程序。
• 然后将libSQRS01.so 放入Android 仿真器的/system/lib 裡。并且,将addserver 程序放入Android仿真器的/system/bin 裡。
• 执行 addserver 程序,就将SQRService 对象加入Binder Driver 裡。
103 - 撰写你的第一个核心服务b
先不要杀掉addserver进程
3. 撰写SQR.CPP 來使用SQRService
阶段二:撰写一个本地层client,以c++撰写一个SQR.CPP
• 在本节里,兹撰写一个SQR.CPP程序使用SQRService。
• 步骤2.1:使用 C++开发一个名为SQR.cpp的C++层应用程序,它透过ServiceManager去绑定(Bind)了SQRService。
• 然后调用IBinder::transact()函数,进而调用SQRService核心服务的onTransact()去进行「平方」的服务。其架构图如下:
• 于是,使用C++撰写一个SQR类,如下:
// SQR.h
#ifndef ANDROID_MISOO_SQR_H
#define ANDROID_MISOO_SQR_H
namespace android {
class SQR {
private:
const void getSQRService();
public:
SQR();
int execute(int n);
};
}; //namespace
#endif // ANDROID_MISOO_SQR_H
// SQR.cpp
#include <utils/IServiceManager.h>
#include <utils/IPCThreadState.h>
#include "SQR.h"
namespace android {
sp<IBinder> m_ib;
SQR::SQR(){
getSQRService();
}
const void SQR::getSQRService(){
sp<IServiceManager> sm = defaultServiceManager();
m_ib = sm->getService(String16("misoo.sqr"));
LOGE("SQR:getSQRService %p\n",sm.get());
if (m_ib == 0)
LOGW("SQRService not published, waiting...");
return;
}
int SQR::execute(int n) {
Parcel data, reply;
data.writeInt32(n);
LOGE("SQR::execute\n");
m_ib->transact(0, data, &reply);
int num = reply.readInt32();
return num;
}
}; //namespace BpBinder
• 在构造式SQR()里调用getSQRService來获得服务(亦即绑定服务)。
• 取得服务时 ServiceManager 传回BpBinder 的IBinder 接口。
• 而execute()函数则实际调用Ibinder接口的transat()函数,并转而调用onTransact()函数。
4. 撰写Java层Client來使用核心服务
阶段三:撰写一个java层client,以java撰写一个sqr01.java
• Java层的应用程序可以透过JNI NativeCode来调用上图里的SQR类别,进而取得SQRService的服务。其架构图如下:
• 步骤3.1: 使用C语言撰写JNI Native Code,来当作Java应用程序与SQR.cpp之间的桥梁,如下:
/* com_misoo_service_sqr01.cpp */
#include "com_misoo_service_sqr01.h"
#include <utils/Log.h>
#include <utils/IPCThreadState.h>
#include <utils/ProcessState.h>
#include "../core_service/SQRService.h"
#include "SQR.h"
using namespace android;
JNIEXPORT jint JNICALL
Java_com_misoo_service_sqr01_execute(JNIEnv *env, jobject thiz,
jint x) {
char s[] = "Java_com_misoo_service_sqr01_execute!!!";
LOGE("%s X = %d\n", s, x);
SQR* sqrObj = new SQR();
int num = sqrObj->execute(x);
return num;
}
• 执行 Android.mk 档,产出libSQRS01_jni.so 共享程序库,就可以加载手机或模拟器裡执行了。
• 执行时,Native 函數调用SQR,转而调用BpBinder,如下图所示。
• 设计Java层的应用类别来调用上述的JNI Native Code,就完成串接Java应用程序与硬件驱动的目标了。
• 于是,撰写一个与JNI Native Code相对应的Java类别:
// sqr01.java
package com.misoo.service;
public class sqr01
{
static
{ System.loadLibrary("libSQRS01_jni"); }
public static native int execute(int x);
}
• 当此sqr01类别被加载到内存时,就会把libSQRS01_jni.so也加载进来,于是sqr01类别就与libSQRS01_jni.so结合起来了;而且sqr01.execute()函数就能调用到libSQRS01_jni.so里的JNI Native函数了。
104 - 撰写你的第一个核心服务c
5. 撰写一个Java层Activity
这不是好的架构设计
• 此时,C/C++层都是被动的、被调用的,这是古典的架构思维,其控制点在App上。
新潮架构设计
• 新潮架构设计思维:如何将控制点下移到C/C++层呢? 例如,下移到JNI本地层。
• C层拥有控制点的必备表现是:
1. 从C创建Java对象
2. 从C调用Java层函数
阶段四:撰写一个java层Activity,撰写一个Android的myActivity.java
议题:
• 接下来,一个典型的议题是:如果myActivity想使用SQRService服务,该如何规划呢?
方案一:
• 最简单的途径是:让myActivity透过sqr01.java,再经由JNI本地函数去调用到SQRService的onTranscat()函数。如下图:
方案二:善用BinderProxy对象
• 由myActivity透过JNI Native函数去绑定核心服务。
• 然后,在Java层诞生一个BpBinder对象的分身:即BinderProxy对象。如下图:
方案二的实现:
• C层拥有控制点的必备表现是:
1. 从C创建Java对象
2. 从C调用Java层函数
• 步骤4.1: 此时,myActivity必须透过JNI Native函数去绑定核心服务,然后由JNI Native函数在Java层诞生一个BpBinder对象的分身:即BinderProxy对象。如下图:
架构设计:sqr05的角色
• myActivity不宜含有native函数,于是委托sqr05来提供native函数,创建Java对象,然后回传接口给myActivity。
使用javaObjectForIBinder()函数
• 在Android里,提供了一个JNI Native 模块,内涵一个javaObjectForIBinder()函数,它能协助诞生Java层的BinderProxy对象,做为BpBinder对象的分身。
• 撰写JNI Native模块
// sqr05.java
// ………
public class sqr05
{
static
{ System.loadLibrary("SQRS05_jni"); }
public native final IBinder bindCoreService();
}
/* com_misoo_service_sqr05.cpp */
//...........
sp<IBinder> m_ib;
JNIEXPORT jobject JNICALL
Java_com_misoo_service_sqr05_bindCoreService(JNIEnv *env, jobject
thiz){
LOGE("bindCoreService");
sp<IServiceManager> sm = defaultServiceManager();
m_ib = sm->getService(String16("misoo.sqr"));
LOGE("SM:getService %p\n",sm.get());
if (m_ib == 0){
LOGW("SQRService not published, waiting..."); return 0;
}
jobject jbi = javaObjectForIBinder(env, m_ib);
if (jbi == 0) { LOGE("javaObjectForIBinder jbi = 0"); return 0; }
return jbi;
}
• 由javaObjectForIBinder()诞生Java层的BinderProxy对象。
• BinderProxy对象里的mObject属性指向BpBinder的IBinder接口。
• JNI Native模块里的gBinderProxyOffsets.mObject公用属性存有BinderProxy类别里的mObject属性的ID值(不是指针)。如下图:
• 于是,在从myActivity类别里,就能透过BinderProxy对象而调用JNI Native模块,转而远距调用SQRService核心服务了。如下图:
• 撰写myActivity
// myActivity.java
// ……..ndroid.os.IBinder;
public class myActivity extends Activity implements OnClickListener {
private Button btn, btn2;
@Override
//………
}
public void onClick(View v) {
switch(v.getId()){
• 撰写myActivity
case 101:
sqr05 sqr = new sqr05();
IBinder m_ib = sqr.bindCoreService();
int code = 0;
Parcel data = Parcel.obtain();
data.writeInt(11);
Parcel reply = Parcel.obtain();
int flags = 0;
try {
m_ib.transact(code, data, reply, flags);
} catch (Exception e) { e.printStackTrace(); }
setTitle("Value = " + String.valueOf(reply.readInt()));
break;
case 102: finish(); break;
}
}}
• myActivity执行到指令:
sqr05 sqr = new sqr05();
IBinder m_ib = sqr.bindCoreService();
• 就委托sqr05来调用Native的bindCoreService()函数:
Java_com_misoo_service_sqr05_bindCoreService(JNIEnv*, jobject)
• 这bindCoreService()函数内含指令:
sp<IServiceManager> sm = defaultServiceManager();
m_ib = sm->getService(String16("misoo.sqr"));
• 于是,bindCoreService()函数绑定了SQRService核心服务。
• 再执行指令:
jobject jbi = javaObjectForIBinder(env, m_ib);
• 这bindCoreService()函数就诞生了Java层的BinderProxy对象。
• 最后执行到指令: return jbi;
• 这bindCoreService()函数就将BinderProxy对象的IBinder接口回传给myActivity类别。
• 于是,myActivity类别可以透过此IBinder接口而调用BinderProxy的transact()函数,转而调用SQRService核心服务的
onTransact()函数。
• 实现了下图的结构了
106 - 撰写你的第一个核心服务e
6. 优化设计
• 撰写myActivity的人,也撰写sqr05.java及其 JNI 本地函数(下图),这增加了myActivity撰写人的负担。该如何呢?
• 可以将sqr05.java部分写在myActivity的基类里,让myActivity来继承之,就迎刃而解了。
架构设计思维
// myActivity.java
// ……..
class mySqr extends sqr05 {
public static void bindCS(ServiceConnection conn){
IBinder ib = sqr.bindCoreService();
conn.onServiceConnected(null, ib);
}}
public class myActivity extends Activity implements OnClickListener {
private IBinder m_ib;
private mySqr sqr;
@Override public void onCreate(Bundle savedInstanceState) {
//……..
sqr = new mySqr();
sqr.bindCS(mConnection);
}
private ServiceConnection mConnection
= new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder ibinder) {
m_ib = ibinder;
}
@Override
public void onServiceDisconnected( ComponentName name) { }
};
public void onClick(View v) {
// ………
m_ib.transact(code, data, reply, flags);
// ………
}
}
• 这bindCS()包装了基类的bindCoreService()本地函数。bindCS()反过来调用myActivity的onServiceConnected()函数。
107 - Native核心服务的Proxy-Stub设计模式a
1. 复习:Java层的Proxy-Stub设计模式
为什么要Stub类呢?
为什么要proxy-stub模式呢?
proxy-stub模式:Binder应用范例
• onTransact()就是EIT造形里的<I>
• 这是标准的EIT造形,其<I>是支持<基类/子类>之间IoC调用的接口。
• 运用曹操(Stub)类,形成两层EIT(两层框架)。
Binder应用范例:编码与译码
• 编好码之后,就将这编码值当做第1个参数传给IBinder接口的transact()函数。
• 于是编码值就跨进程地传递到myBinder类里的onTransact()函数了。
例如myBinder的代码:
public class myBinder extends Binder{
@Override public boolean onTransact( int code, Parcel data,
Parcel reply, int flags) throws android.os.RemoteException {
switch( code ){
case 1:
// 将Message丢到子线程的MQ to play MP3
Message msg = myService.h.obtainMessage(1,1,1, “Play”);
myService.h.sendMessage(msg); break;
case 2:
// 将Message丢到子线程的MQ to stop playing
msg = myService.h.obtainMessage(1,1,1, “Stop”);
myService.h.sendMessage(msg); break;
}
return true;
}}
• 其代码就是对code进行“译码”动作。
• 如果code值為1就執行<Play>動作;如果code值為2就執行<Stop>動作。
Proxy类担任编码。Stub类担任译码
• 回想,之前介绍过,在Java应用框架层里,使用了AIDL架构实现Proxy-Stub设计模式来封装IBinder接口,以便产生更亲切贴心的新接口。
• 并且担任<编码>和<译码>的工作。
大大增加了app开发者的负担
108 - Native核心服务的Proxy-Stub设计模式b
2. 从IBinder接口说起
在java层,Binder类实现了IBinder接口
在C++层,BBinder类实现IBinder接口
Proxy类在哪里呢? App Service
Proxy类在哪里呢? Native Core Service
Native Service 都有通用性API:即IBinder接口
• 在撰写Native Service时,因为它必须提供
IBinder接口给远程的Client来调用,所以
通常都会继承BBinder框架基类,如下:
class MyNativeService extends BBinder
{
//……….
}
• 此时,MyNativeService提供了IBinder接口,让Client模块来从远程调用。如下图所述:
如何协助产生Proxy_Stub类?
• 在 Java层使用aidl.exe工具来生成ProxyStub类;
• 在C/C++层使用模板(Template)来协助产生Proxy_Stub类。
109 - Native核心服务的Proxy-Stub设计模式c
3. 使用模板,产生Stub类,BnInterface<I>模板
如何考虑<人>的<分工>
• 由框架开发者来撰写Proxy-Stub类,才能减轻开发者的负担。
• 框架分为:<天子框架>和<曹操框架>。
• 因此,应该由两者(天子或曹操)之一来撰写Proxy-Stub类。
接口知识取得的难题
• 但是,有个难题:接口的内容必须等到<买主>来了才会知道。
• 在框架开发阶段,买主还没来,接口的知识无法取得,又如何定义接口呢? 没有接口定义,又如何撰写Stub和Proxy类呢?
• 好办法是:“强龙(天子或曹操)撰写代码(在先) ;然后,地头蛇(App开发者)定义接口(在后)。”
在编程上,有什么技术可以实现这个办法?
• 技术之一是:類別模板(class template)
例如,强龙撰写模板:
template< class T >
class SomeClass
{
private:
T data;
public:
SomeClass() { }
void set(T da)
{ data = da; }
};
• 地头蛇利用模板来生成一个类:
• 由于接口(interface)是一种特殊的类(class),所以也可以定义模板如下:
SomeClass<Integer> x;
template<interface I>
class BinderProxy
{
// ………
};
• 地头蛇利用模板来生成一个类:
BinderProxy<IPlayer> proxy;
Android提供的:BnInterface<I>和BpInterface<I>模板
• Android SDK提供了BnInterface<T>类模板,此模板定义于frameworks/base/include/binder/IInterface.h文件中,如下:
template<typename INTERFACE>
class BnInterface :public INTERFACE, public BBinder {
public:
virtual sp<IInterface> queryLocalInterface(const
String16& _descriptor);
virtual String16 getInterfaceDescriptor() const;
protected:
virtual IBinder* onAsBinder();
};
• 基于这个模板,并定义接口如下:
class IMyService :public IInterface {
public:
DECLARE_META_INTERFACE(MyService);
virtual void sv1(…) = 0;
virtual void sv1(…) = 0;
virtual void sv1(…) = 0;
};
• 此时可使用BnInterafce<T>模板来产生BnInterafce<IMyService>类别。如下:BnInterface<IMyService>
• 它一方面继承了Binder框架基类来得到IBinder接口。同时。也继承了IMyService接口所定义的sv1(), sv2()和sv3()函数。
• 基于这个模板产生的类别,就可衍生出Stub类别,如下:
class BnMyService : public BnInterface<IMyService>
{
//………..
}
• 如下图所示:
• 基于这个Stub类别(即BnMyService),我们只要撰写MyNativeService类别,它来继承上述的BnMyService类别即可,如下定义:
class MyNativeService : public BnMyService
{
//………..
}
• 如下图所示:
110 - Native核心服务的Proxy-Stub设计模式d
4. 举例:以既有的Native Service为例
5. 使用模板,产生Proxy类
6. 让Client使用Proxy类的新接口
111 - Native核心服务的Proxy-Stub设计模式e
112 - 亲自开发SQRService的Proxy-Stub设计模式a
113 - 亲自开发SQRService的Proxy-Stub设计模式b
114 - 亲自开发SQRService的Proxy-Stub设计模式c
115 - Android Service的Proxy-Stub设计模式a
116 - Android Service的Proxy-Stub设计模式b
117 - Android Service的Proxy-Stub设计模式c
118 - 核心服务Callback的IBinder接口a
119 - 核心服务Callback的IBinder接口b
版权声明:本文为gordon_sun原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。