android 系统级 service详解

一、android 系统级 service简要说明

android系统级的服务包含了Android Service 和Native Service .

Android Service 也称作 Java Service ,是用JAVA语言编写的,实现在框架层。

Native Service 也称作 System Service ,是用C++语言编写的,实现在Runtime层。

对于这两种service来说,两个对等service通讯都是利用binder,只不过一种利用*.aidl,一种利用IInterface编写序列化代码而已,本质是一样的,下面先介绍native service的编写及两个native service如何通讯的过程。

二、native service的特点

A、因为底层核心服务是 Android 框架里最接近 Linux/Driver 的部分。为了充分发挥硬件设备的差异化特性,核心服务是让上层 Java 应用程序来使用 Driver/HW Device 特色的重要管道。

B、在开机过程中,就可以启动核心服务 ( 例如汉字输入法服务等 ) ,让众多应用程序来共享之。

C、由于共享,所以能有效降低程序的大小及统一的接口变化 。

三、如何实现一个Android service

3.1.以 AlarmManagerService为例进行说明

Java层服务顾名思义即为从 Java层提供的服务,它与 C++层的服务不同之处在于其服务进程的运行由系统( ServiceManager)统一维护。在文件 frameworks/base/services/java/com/android/server/SystemServer.java 中我们可以看到以下代码:

AlarmManagerService alarm = new AlarmManagerService (context );
ServiceManager .addService (Context .ALARM_SERVICE , alarm );

这个操作在系统启动时完成,由 ServiceManager 负责创建服务进程并运行之。

在目录/frameworks/base/core/java/android/app中IAlarmManager.aidl文件.

在目录frameworks/base/services/java/com/android/server中AlarmManagerService的aidl的实现类,

在目录frameworks/base/services/java/com/android/server增加 service的实现文件.

3.2.实验测试添加java 系统级服务步骤

3.2.1 增加aidl文件

在目录frameworks/base/core/java/android/app下增加中文件IDvbService.aidl.

package android.app;

interface IDvbService {
	int countTest(in int testvalue);
}

3.2.2 创建服务类

在目录frameworks/base/services/java/com/android/server中增加DvbManagerService实现IDvbService.aidl类。

package com.android.server;

import android.content.Context;
import android.util.Slog;
import android.app.IDvbService;

class DvbManagerService extends IDvbService.Stub {

    private static final String TAG = "DvbManagerService";
    private static final boolean localLOGV = false;

    private final Context mContext;

    public DvbManagerService(Context context) {
        super();
        mContext = context;
        Slog.w(TAG, "DvbManagerService");
    }

    public int countTest(int value){
    	return value*2;
    }

}

3.2.3 将服务添加到ServiceManager

在文件 frameworks/base/services/java/com/android/server /SystemServer.java 类中run()方法中增加

try {
	Slog.i(TAG, "Alarm DvbManagerService");
	DvbManagerService dvb = new DvbManagerService(context);
	ServiceManager.addService(Context.DVB_SERVICE, dvb);
} catch (Throwable e) {
	reportWtf("starting DvbManagerService", e);
}

3.2.4 在Context中增加该服务对应的常量

在文件frameworks/base/core/java/android/content/Context.java中增加

public static final String DVB_SERVICE = "dvb";//dvb

3.2.5 在框架添加封装管理类

在文件frameworks/base/core/java/android/app中增加DvbManager.java

package android.app;

import android.content.Context;
import android.content.Intent;
import android.os.RemoteException;
import android.os.ServiceManager;

public class DvbManager{
    private final IDvbService mService;

    /**
     * package private on purpose
     */
    DvbManager(IDvbService service) {
        mService = service;
    }

    public int count(int value) {
        try {
        	return mService.countTest(value);
        } catch (RemoteException ex) {
        }
        return -1;
    }
}

3.2.6 增加获取封装管理类的方法

在文件frameworks/base/core/java/android/app/ContextImpl.java中新增加属性

private static DvbManager sDvbManager;//dvb

在getSystemService(String name)方法中增加

else if (DVB_SERVICE.equals(name)) {//dvb
	return getDvbManager();
} 

另外增加方法

    private DvbManager getDvbManager() {//dvb
        synchronized (sSync) {
            if (sDvbManager == null) {
                IBinder b = ServiceManager.getService(DVB_SERVICE);
                IDvbService service = IDvbService.Stub.asInterface(b);
                sDvbManager = new DvbManager(service);
            }
        }
        return sDvbManager;
    }

也可以不进行上述的两个操作而直接在static代码块里面添加。

registerService(ACCOUNT_SERVICE, new StaticServiceFetcher() {
	public Object createService() {
		IBinder b = ServiceManager.getService(DVB_SERVICE);
		IAccountManager service = IAccountManager.Stub.asInterface(b);
		return new DvbManager(service);
	}
});

Note :如果在封装的管理类中需要传入Context参数,如下,请看加粗部分的区别:

registerService(ACCOUNT_SERVICE, new ServiceFetcher() {
	public Object createService(ContextImpl ctx) {
		IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);
		IAccountManager service = IAccountManager.Stub.asInterface(b);
		return new AccountManager(ctx, service);
	}
});

3.2.7 在Android.mk里面进行配置

在frameworks/base/Android.mk中LOCAL_SRC_FILES += \ 下增加一行

core/java/android/app/IDvbService.aidl \

3.2.8 应用中调用

在应用调用如下:

导入import android.app.DvbManager;

用法

DvbManager dvb=(DvbManager)getSystemService(DVB_SERVICE);
int count = dvb.count(9);
Log.i(“DvbManager”,”count = ” + count ) ;

3.2.9 编译过程

编译如下:

(1)首先编译 frameworks

. build/envsetup.sh

choosecombo

make -j4  framework

编译后会生成framework.jar

(2)然后编译frameworks/base/services/java的service

make -j4  frameworks/base/services/java

编译后会生成services.jar

(3)编译应用

因为服务是自定义的,所有必须在自定义的sdk中编译才能使用。

四、如何实现一个native service

要点如下:

a、核心服务通常在独立的进程 (Process) 里执行。

b、必须提供 IBinder 接口,让其它程序可以进行跨进程的绑定 (Binding) 和呼叫。

c、因为共享,所以必须确保多线程安全 (Thread-safe) 。

d、以 C++ 类别定义,诞生其对象,透过 SM 之协助,将该对象参考值传给 IServiceManager::addService() 函数,就加入到 Binder Driver 里了。

e、应用程序可透过 SM 之协助而远距绑定该核心服务,此时 SM 会回传 IBinder 接口给应用程序。

f、应用程序可透过 IBinder::transact() 函数来与核心服务互传数据。

下面以具体实例讲解一下具体的每个步骤如何实现完成

先说明一个测试例子的模块结构:

serviceTestA 是一个普通的过程,提供两个整数的乘法及除法运算

serviceTestB 是一个普通的过程,提供两个整数的加法及减法运算

TestService 是一个测试进程的程序,主要验证两个服务进程的接口函数,其中的代码可以放在任何一个进程进行访问调用

4.1 编写服务进程

serviceTestA.h 头文件定义:

#ifndef __SERVICE_TEST_A__
#define __SERVICE_TEST_A__

#include <utils/RefBase.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>
#include <utils/threads.h>

namespace android {
//继承BBinder类,从而提供IBinder 接口
class serviceTestA: public BBinder {
public:
	serviceTestA();
	virtual ~serviceTestA();
	static int instantiate(); //建立唯一类实例
	virtual status_t onTransact(uint32_t, const Parcel&, Parcel*, uint32_t);
private:
// protected by mLock 多线程安全
	mutable Mutex mLock;
};
}
#endif /* __SERVICE_TEST_A__ */

serviceTestA.cpp 实现文件:

#include <cutils/log.h>
#include <cutils/properties.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include <serviceTestA/serviceTestA.h>
namespace android {
	enum{
		CALCULATE_MUL_NUM = 0,
		CALCULATE_DIV_NUM ,
	};

	int serviceTestA::instantiate() {
		LOGI("serviceTestA instantiate");
		int r = defaultServiceManager()->addService(String16("service.TestA"),
		new serviceTestA());
		LOGI("serviceTestA r = %d/n", r);
		return r;
	}

	serviceTestA::serviceTestA() {
		LOGI("serviceTestA created");
	}

	serviceTestA::~serviceTestA(){
		LOGI("serviceTestA destroyed");
	}

	status_t serviceTestA::onTransact(uint32_t code, const Parcel&data, Parcel*reply, uint32_t flags){
		LOGI("serviceTestA::onTransact code = %d",code);
		Mutex::Autolock _l(mLock);
		switch(code){
			case CALCULATE_MUL_NUM:{
					int a = data.readInt32();
					int b = data.readInt32();
					int sum = a * b ;
					LOGI("sum mul value = %d",sum);
					reply->writeInt32(sum);
					return NO_ERROR;
				}
				break;
			case CALCULATE_DIV_NUM:{
				int a = data.readInt32();
				int b = data.readInt32();
				int sum = a / b ;
				LOGI("sum div value = %d",sum);
				reply->writeInt32(sum);
				return NO_ERROR;
			}
				break;
			default:
				return BBinder::onTransact(code, data, reply, flags);
		}
		return 0;
	}
}

Android.mk 文件:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= serviceTestA.cpp
LOCAL_SHARED_LIBRARIES:= libutils libutils libbinder
LOCAL_C_INCLUDES := $(TOP)/frameworks/base/include
LOCAL_MODULE:= libServiceTestA
LOCAL_PRELINK_MODULE:= false
include $(BUILD_SHARED_LIBRARY)

这里生成libServiceTestA动态库,方例升级服务程序

编写独立的进程程序:

它的用途是:诞生一个 serviceTestA 类别之对象,然后将该对象参考存入 Binder Driver 里。

#include <sys/types.h>
#include <unistd.h>
#include <cutils/log.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include <serviceTestA/serviceTestA.h>

using namespace android;

int main(int argc, char *argv[]) {
	sp < ProcessState > proc(ProcessState::self());
	sp < IServiceManager > sm = defaultServiceManager();
	LOGI("ServiceManager: %p", sm.get());
	serviceTestA::instantiate(); // 这是重点。。。。
	ProcessState::self()->startThreadPool();
	IPCThreadState::self()->joinThreadPool();
	return 0;
}

Android.mk 文件:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= main.cpp
LOCAL_SHARED_LIBRARIES:= libutils libServiceTestA
LOCAL_MODULE:= serviceTestA
include $(BUILD_EXECUTABLE)

这里最重要的是调用:serviceTestA::instantiate();

其先执行到 new serviceTestA() ,就诞生一个 serviceTestA 类别之对象;

接着,呼叫 defaultServiceManager() 函数取得 SM 的 IServiceManager 接口;

再呼叫 IServiceManager::addService() 将该对象参考存入 Binder Driver 里,并且同时存入

到ServiceManager中注册并管理,如此其它进程才能通过ServiceManager::getService找到相应服务进程

以上代码同理,serviceTestB服务进程也一样的这样建立,不再复述。

4.2 测试服务进程

testService.cpp编写:

#include <cutils/log.h>
#include <cutils/properties.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include <serviceTestA/serviceTestA.h>
#include <serviceTestB/serviceTestB.h>

using namespace android;

enum {
	CALCULATE_ADD_NUM = 0, CALCULATE_SUB_NUM,
};

enum {
	CALCULATE_MUL_NUM = 0, CALCULATE_DIV_NUM,
};

int main(int argc, char *argv[]) {
	sp < IBinder > TestAbinder;
	sp < IBinder > TestBbinder;
	Parcel data, reply;
	int sum = 0;
	LOGI("testService main is call...");
	sp < IServiceManager > sm = defaultServiceManager();

	while (1) {
		TestAbinder = sm->getService(String16("service.TestA"));
		LOGE("TestA::getAddService %p/n", sm.get());
		if (TestAbinder == 0) {
			LOGE("TestAService not published, waiting...");
			usleep(1000000);
			continue;
		} else {
			LOGI("TestA::getAddService success...");
			break;
		}
	}

	while (1) {
		TestBbinder = sm->getService(String16("service.TestB"));
		LOGE("TestB::getAddService %p/n", sm.get());
		if (TestBbinder == 0) {
			LOGE("TestBService not published, waiting...");
			usleep(1000000);
			continue;
		} else {
			LOGI("TestB::getAddService success...");
			break;
		}
	}

//测试两个service中的函数
	data.writeInt32(1000);
	data.writeInt32(200);
	LOGI("BpAddService::create remote()->transact()/n");
	TestAbinder->transact(CALCULATE_MUL_NUM, data, &reply);
	sum = reply.readInt32();
	LOGI("CALCULATE_ADD_NUM value = %d", sum);

	data.writeInt32(1000);
	data.writeInt32(200);
	LOGI("BpAddService::create remote()->transact()/n");
	TestAbinder->transact(CALCULATE_DIV_NUM, data, &reply);
	sum = reply.readInt32();
	LOGI("CALCULATE_SUB_NUM value = %d", sum);

	data.writeInt32(1000);
	data.writeInt32(200);
	LOGI("BpAddService::create remote()->transact()/n");
	TestBbinder->transact(CALCULATE_ADD_NUM, data, &reply);
	sum = reply.readInt32();
	LOGI("CALCULATE_MUL_NUM value = %d", sum);

	data.writeInt32(1000);
	data.writeInt32(200);
	LOGI("BpAddService::create remote()->transact()/n");
	TestBbinder->transact(CALCULATE_SUB_NUM, data, &reply);
	sum = reply.readInt32();
	LOGI("CALCULATE_DIV_NUM value = %d", sum);

	return 0;
}

这里最重要的就是通过defaultServiceManager得到默认的sm,然后通过getService得到sp<IBinder>对象,即可操作相应服务进程的接口函数,整个过程还是相当清晰的。

最后附上测试的结果打印:

# ./TestService
./TestService
# logcat
logcat
--------- beginning of /dev/log/main
I/        ( 1379): testService main is call...
E/        ( 1379): TestA::getAddService 0xa680/n
I/        ( 1379): TestA::getAddService success...
E/        ( 1379): TestB::getAddService 0xa680/n
I/        ( 1379): TestB::getAddService success...
I/        ( 1379): BpAddService::create remote()->transact()/n
I/        ( 1371): serviceTestA::onTransact code = 0
I/        ( 1371): sum mul value = 200000
I/        ( 1379): CALCULATE_MUL_NUM value = 200000
I/        ( 1379): BpAddService::create remote()->transact()/n
I/        ( 1371): serviceTestA::onTransact code = 1
I/        ( 1371): sum div value = 5
I/        ( 1379): CALCULATE_DIV_NUM value = 5
I/        ( 1379): BpAddService::create remote()->transact()/n
I/        ( 1374): serviceTestB::onTransact code = 0
I/        ( 1374): sum add value = 1200
I/        ( 1379): CALCULATE_ADD_NUM value = 1200
I/        ( 1379): BpAddService::create remote()->transact()/n
I/        ( 1374): serviceTestB::onTransact code = 1
I/        ( 1374): sum sub value = 800
I/        ( 1379): CALCULATE_SUB_NUM value = 800

结果表明完全正确

文档版请点击下载。《如何创建android系统服务》 ,Hasen个人博客来攒个人气。

时间: 2024-10-10 18:14:43

android 系统级 service详解的相关文章

Android系统五大布局详解Layout

我们知道Android系统应用程序一般是由多个Activity组成,而这些Activity以视图的形式展现在我们面前, 视图都是由一个一个的组件构成的.组件就是我们常见的Button.TextEdit等等.那么我们平时看到的Android手机中那些漂亮的界面是怎么显示 出来的呢?这就要用到Android的布局管理器了,网上有人比喻的很好:布局好比是建筑里的框架,组件按照布局的要求依次排列,就组成了用于看见的漂亮界面了. 在分析布局之前,我们首先看看控件:Android中任何可视化的控件都是从an

android开发之service详解

service作为android的四大组件之一,其重要性可想而知,在开发中,我们经常把一些不需要与用户进行交互的工作放在service中来完成,service运行在后台,这样有些人可能会产生错觉,以为service是运行在新线程中,其实不然,service也运行在主线程中,因此不能在service中进行耗时操作,否则会报ANR异常,但是我们可以在service中新开线程来进行耗时操作,比如下载等等. 先来说说service的两种绑定方式,一种是通过Context.startService()来启

Android 四大组件之Service详解

                   Android四大组件之Service详解    来这实习已经10多天了,今天整理整理学习时的Android笔记.正所谓好记性不如烂笔头,今天来说说service组件. service可以在和多场合的应用中使用,比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务嘛,总是藏在后头的. Service是在一段不定的时间运行在后台,不和用户交互应用组件.每个

Android四大组件--Activity详解

Android四大组件--Activity详解 分类: android android应用android开发 本文的主要内容包括1.activity的建立.配置和使用:2.activity的跳转和传值:3.startActivityForResult:4.activity的生命周期. 1.activity的建立.配置和使用 Activity是一个应用中的组件,它为用户提供一个可视的界面,方便用户操作,比如说拔打电话.照相.发邮件或者是浏览地图等.每个activity会提供一个可视的窗口,一般情况

Android之Zygote启动详解

我们知道Android系统是基于Linux内核的,在Linux系统中所有的进程都是init进程的子进程.Zygote也一样它是在系统启动的过程中由init进程创建的,在系统启动脚本init.rc中: <span style="font-size:14px;">@init.rc service zygote /syste/bin/app_process -Xzygote /system/bin -zygote --start-system-server class main

Android 接口回调机制详解

在使用接口回调的时候发现了一个经常犯的错误,就是回调函数里面的实现有可能是用多线程或者是异步任务去做的,这就会导致我们期望函数回调完毕去返回一个主函数的结果,实际发现是行不通的,因为如果回调是多线程的话你是无法和主函数同步的,也就是返回的数据是错误的,这是非常隐秘的一个错误.那有什么好的方法去实现数据的线性传递呢?先介绍下回调机制原理. 回调函数 回调函数就是一个通过函数指针调用的函数.如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数

Android Google Map v2详解之:开发环境配置

Android Google Map v2详解之:开发环境配置                                       --转载请注明出处:coder-pig 说在前面: 说到地图定位,现在越来越多的社交app都加入了地图和定位的功能模块,用户很多的时候 也会用到这些东东,比如,到外面吃饭,次次吃饭前都要拍下照片发到朋友圈,定个位,然后发条说说, 炫耀一下自己今天吃了什么高大上的东东,炫耀和攀比心理我懂,不过,一次下班去吃饭,看到一妹子 吃饭,拍照+发朋友圈,足足用了大概20

Android开发之BroadcastReceiver详解

BroadcastReceiver,顾名思义就是"广播接收者"的意思,它是Android四大基本组件之一,这种组件本质上是一种全局的监听器,用于监听系统全局的广播消息.它可以接收来自系统和应用的的广播. 由于BroadcastReceiver是一种全局的监听器,因此它可以非常方便地实现系统不同组件之间的通信.比如Activity与通过startService()方法启动的Service之间通信,就可以借助于BroadcastReceiver来实现. BroadcastReceiver简

给 Android 开发者的 RxJava 详解

作者:扔物线 前言 我从去年开始使用 RxJava ,到现在一年多了.今年加入了 Flipboard 后,看到 Flipboard 的 Android 项目也在使用 RxJava ,并且使用的场景越来越多 .而最近这几个月,我也发现国内越来越多的人开始提及 RxJava .有人说『RxJava 真是太好用了』,有人说『RxJava 真是太难用了』,另外更多的人表示:我真的百度了也谷歌了,但我还是想问: RxJava 到底是什么? 鉴于 RxJava 目前这种既火爆又神秘的现状,而我又在一年的使用