一、Android系统中具有两层服务:

1. C++层的核心服务(Core Service)

2. Java层的系统服务(SDK-based Service)

核心服务(Core Service)是Android框架里最接近内核的部分,通常运行在独立的进程(Process)里,使用C++实现,是让上层Java应用程序使用驱动和硬件设备的重要管道。在开机过程中,就可以启动核心服务,让众多应用程序来共同使用。

Java层服务顾名思义即为从 Java层提供的服务,它与 C++层的服务不同之处在于其服务进程的运行由 ServiceManager统一维护。

以MediaPlayerService为例,两种服务的关系如下图:



二、下面分别总结一下如何在Android系统中添加核心服务和Java层服务


1. 添加C++层的核心服务(Core Service)

假设要添加一个服务DemoService

(1)创建相关的目录

进入android源码的frameworks/base目录,新建自己的目录,假设为demoService,再在这个目录中建立两个子目录demoServer和libDemoService

demoServer目录存放服务的启动程序文件,编译后将生成为可执行文件,在系统启动的时候运行

libDemoService目录存放服务的实现文件,编译后将生成为动态链接库,由可执行程序调用

(2)编写服务的实现文件

进入libDemoService目录,创建三个文件:DemoService.h、DemoService.cpp和Android.mk

DemoService.h的内容如下:

#ifndef ANDROID_DEMOSERVICE_H
#define ANDROID_DEMOSERVICE_H
#include <utils/threads.h>
#include <utils/RefBase.h>
#include <utils/Log.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>

namespace android {
	class DemoService : public BBinder {//继承BBinder,实现本地接口
	public:
		static void instantiate();
		DemoService();
		virtual ~DemoService();
		virtual status_t onTransact(uint32_t, const Parcel&, Parcel*, uint32_t);
	};
};//namespace
#endif

DemoService.cpp的内容如下:

#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include "DemoService.h"
namespace android {
	
	//把自己注册到ServiceManager中
	void DemoService::instantiate() {
		defaultServiceManager()->addService(
            String16("demo.service"), new DemoService());
	}

	DemoService::DemoService() {
		ALOGV("DemoService created");
	}

	DemoService::~DemoService() {
		ALOGV("DemoService destroyed");
	}

	//服务具体的本地实现,功能实现都应该放在这里面,通过传入执行代码(code)的不同来执行不同的操作,上层映射为不同的API。
	status_t DemoService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
		switch(code) {
		case XX: {//根据code的不同执行不同的操作
				xxxxxxx
			}
			break;
		case YY: {
				yyyyyyy
			}
			break;
		default:
			return BBinder::onTransact(code, data, reply, flags);
		}
	}
};//namespace 
  注意在DemoService::instantiate()中调用 defaultServiceManager()->addService(String16("demo.service"), new DemoService()),将名字为"demo.service"的服务注册到ServiceManager中。ServiceManager根据名字返回给客户端相应的服务,如果找不到该名字对应的服务,则返回空。



Android.mk的内容如下:

LOCAL_PATH:= $(call my-dir)

#
# libDemoService
#

include $(CLEAR_VARS)

LOCAL_SRC_FILES :=			\
	DemoService.cpp			\

$(JNI_H_INCLUDE)

LOCAL_SHARED_LIBRARIES :=	\
	libcutils				\
	libutils				\
	libbinder				\
	libandroid_runtime		\

LOCAL_PRELINK_MODULE := false
LOCAL_MODULE := libDemo
include $(BUILD_SHARED_LIBRARY)	# 表示编译为动态库


编译:mmm frameworks/base/demoService/libDemoService/,生成libDemo.so库文件

(3)编写可执行程序文件

进入demoServer目录,创建两个文件:DemoServer.cpp和Android.mk

DemoServer.cpp的内容如下:

#include <sys/types.h>
#include <unistd.h>
#include <grp.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include "../libDemoService/DemoService.h"

using namespace android;

int main(int argc, char** argv)
{
	sp<ProcessState> proc(ProcessState::self());
	sp<IServiceManager> sm = defaultServiceManager();//获取ServiceManager的代理接口
	ALOGI("ServiceManager: %p", sm.get());
	DemoService::instantiate();//把自己添加到ServiceManager中
	ProcessState::self()->startThreadPool();
	IPCThreadState::self()->joinThreadPool();
} 
  以上为底层服务的标准操作。关键是调用DemoService::instantiate()把DemoService服务注册到ServiceManager中。



Android.mk的内容如下:

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES :=			\
    DemoServer.cpp			\

LOCAL_SHARED_LIBRARIES :=	\
	libDemo					\
	libutils				\
	libbinder				\

LOCAL_MODULE:= DemoServer
include $(BUILD_EXECUTABLE)	# 编译为可执行文件

编译:mmm frameworks/base/demoService/demoServer/,生成可执行文件DemoServer.

(4)实现服务进程开机自动运行

将编译生成的可执行文件DemoServer和动态链接库文件libDemo.so分别拷贝到开发板的/system/bin和system/lib目录(模拟器上相当于make snod)

修改启动脚本<android source>/system/core/rootdir/init.rc文件,使之在开机时启动服务DemoServer

## 将/system/bin/DemoServer作为一个服务启动,服务的名称为DemoService(这个名称只是为了方便自己识别而已)
service DemoService /system/bin/DemoServer




2.添加Java层的系统服务(SDK-based Service)

(1)定义服务的接口

Binder机制要求提供服务的一方必须实现一个具有跨进程访问能力的接口,以便使用服务的一方可以通过这个服务接口来访问它,因此,在实现服务之前,我们首先要定义它的服务接口。Android系统提供了一种描述语言来定义具有跨进程访问能力的服务接口,这种描述语言称为Android接口描述语言(Android Interface Definition Language,AIDL)。以AIDL定义的服务接口文件是以aidl为后缀名的,在编译时,编译系统会将它们转换成一个java文件,然后再对它们进行编译。

在目录/frameworks/base/core/java/android/app下增加IDemoManager.aidl

package android.app;

interface IDemoManager {
    ……
    void setVolume(int iValue);
    int getVolume();
    ……
}

注意,这是一个aidl文件,编译后会生成一个IDemoManager.java。我们来看一下这个文件的内容隐藏着什么奥秘,可以这么神奇地支持进程间通信。

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: frameworks/base/core/java/android/app/IDemoManager.aidl
 */
package android.app;

public interface IDemoManager extends android.os.IInterface
{
	/** Local-side IPC implementation stub class. */
	public static abstract class Stub extends android.os.Binder implements android.app.IDemoManager
	{
		private static final java.lang.String DESCRIPTOR = "android.app.IDemoManager";
		/** Construct the stub at attach it to the interface. */
		public Stub()
		{
			this.attachInterface(this, DESCRIPTOR);
		}
		/**
		 * Cast an IBinder object into an android.app.IDemoManager interface,
		 * generating a proxy if needed.
		 */
		public static android.app.IDemoManager asInterface(android.os.IBinder obj)
		{
			if ((obj==null)) {
				return null;
			}
			android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
			if (((iin!=null)&&(iin instanceof android.app.IDemoManager))) {
				return ((android.app.IDemoManager)iin);
			}
			return new android.app.IDemoManager.Stub.Proxy(obj);
		}
		
		@Override
		public android.os.IBinder asBinder()
		{
			return this;
		}
		
		@Override
		public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
		{
			switch (code)
			{
				……
				case TRANSACTION_setVolume:
				{
					data.enforceInterface(DESCRIPTOR);
					int _arg0;
					_arg0 = data.readInt();
					this.setVolume(_arg0);
					reply.writeNoException();
					return true;
				}
				case TRANSACTION_getVolume:
				{
					data.enforceInterface(DESCRIPTOR);
					int _result = this.getVolume();
					reply.writeNoException();
					reply.writeInt(_result);
					return true;
				}
				……
			}
			return super.onTransact(code, data, reply, flags);
		}
		
		private static class Proxy implements android.app.IDemoManager
		{
			private android.os.IBinder mRemote;
			
			Proxy(android.os.IBinder remote)
			{
				mRemote = remote;
			}
			
			@Override
			public android.os.IBinder asBinder()
			{
				return mRemote;
			}
			
			public java.lang.String getInterfaceDescriptor()
			{
				return DESCRIPTOR;
			}
			
			……
			
			@Override
			public void setVolume(int iValue) throws android.os.RemoteException
			{
				android.os.Parcel _data = android.os.Parcel.obtain();
				android.os.Parcel _reply = android.os.Parcel.obtain();
				try {
					_data.writeInterfaceToken(DESCRIPTOR);
					_data.writeInt(iValue);
					mRemote.transact(Stub.TRANSACTION_setVolume, _data, _reply, 0);
					_reply.readException();
				}
				finally {
					_reply.recycle();
					_data.recycle();
				}
			}
			
			@Override
			public int getVolume() throws android.os.RemoteException
			{
				android.os.Parcel _data = android.os.Parcel.obtain();
				android.os.Parcel _reply = android.os.Parcel.obtain();
				int _result;
				try {
					_data.writeInterfaceToken(DESCRIPTOR);
					mRemote.transact(Stub.TRANSACTION_getVolume, _data, _reply, 0);
					_reply.readException();
					_result = _reply.readInt();
				}
				finally {
					_reply.recycle();
					_data.recycle();
				}
				return _result;
			}
			
			……
		}
		
		……
		static final int TRANSACTION_setVolume = (android.os.IBinder.FIRST_CALL_TRANSACTION + 331);
		static final int TRANSACTION_getVolume = (android.os.IBinder.FIRST_CALL_TRANSACTION + 367);
		……
	}
	
	……
	public void setVolume(int iValue) throws android.os.RemoteException;
	public int getVolume() throws android.os.RemoteException;
	……
}

我们可以看到IDemoManager.aidl这个文件编译后的真面目,原来就是根据IDemoManager接口的定义生成相应的Stub和Proxy类,这个就是我们熟悉的Binder机制的内容了,即实现这个DemoManagerService的server必须继承于这里的IDemoManager.Stub类,而这个DemoManagerService的远程接口就是这里的IDemoManager.Stub.Proxy对象获得的IDemoManager接口。接下来的内容,我们就可以看到IDemoManager.Stub和IDemoManager.Stub.Proxy是怎么创建或者使用的。



(2)在目录frameworks/base/services/java/com/android/server中增加服务类DemoManagerService,继承IDemoManager.Stub,并实现其中的函数

package com.android.server;

import android.app.IDemoManager;
import android.app.DemoManager;
import android.content.Context;
import android.util.Log;
import android.util.Slog;
……

public abstract class DemoManagerService extends IDemoManager.Stub {
	
	private static final String TAG = "DemoManagerService";
	protected final Context mContext;
	……
	
	public DemoManagerService(Context context) {
        mContext = context;
        Slog.w(TAG, "DemoManagerService is constructed!");
    }

    protected void finalize() throws Throwable {
        try {
        } finally {
            close();
            super.finalize();
        }
    }
	
	……
	public void setVolume(int iValue){
		Slog.v(TAG, "SetVolume");
		pushInteger(iValue);
		invoke("SetVolume");
	}
	public int getVolume(){
		boolean result;

		Slog.v(TAG, "GetVolume");
		result = invoke("GetVolume");

		if(result == true){
			return getInteger();
		}
		return 0;
	}
	……
}

(3)启动服务

在frameworks/base/services/java/com/android/server/SystemServer.java文件中,定义了SystemServer类。SystemServer对象是在系统启动的时候创建的,它被创建的时候会启动一个线程来创建系统中的服务,并且把它们添加到Service Manager中去,所以,这里将DemoManagerService也加入其中

……
import com.android.server.DemoManagerService;
import com.android.server.DemoManagerServicePolicy;

class ServerThread {
	
	……
	
	public void initAndLoop() {
		……
		DemoManagerService demo = null;
		……
		
		Slog.i(TAG, "demo Manager");
		demo = new DemoManagerServicePolicy(context);
		ServiceManager.addService(Context.DEMO_SERVICE, demo);
		ActivityManagerService.self().setDemoManager(demo);
		
		……
		
		final DemoManagerService demoF = demo;
		……
		
		try {
			if (demoF != null) demoF.systemReady();
		} catch (Throwable e) {
			reportWtf("Notifying DemoManagerService running", e);
		}
		……
	}
	……
}

public class SystemServer {
    
	……

    /**
     * Called to initialize native system services.
     */
    private static native void nativeInit();

    public static void main(String[] args) {

        ……

        // Initialize native services.
        nativeInit();

        // This used to be its own separate thread, but now it is
        // just the loop we run on the main thread.
        ServerThread thr = new ServerThread();
        thr.initAndLoop();
    }
}


我们可以看到,在ServerThread.initAndLoop函数中,创建了DemoManagerService并添加到Service Manager中。



(4)在/frameworks/base/core/java/android/content/Context.java中增加表示服务名称的字符串常量

public static final String DEMO_SERVICE = "demo";

(5)在/frameworks/base/core/java/android/app中增加DemoManager.java

package android.app;
……

public class DemoManager {
	……
	private final IDemoManager mService;
	
	/**
     * package private on purpose
     */
    DemoManager(IDemoManager service) {
        mService = service;
    }
	
	……
	public void setVolume(int iValue){
		try{
			mService.setVolume(iValue);
		}catch(RemoteException ex){
		}
	}
	public int getVolume(){
		try{
			return mService.getVolume();
		}catch(RemoteException ex){
		}
		return 0;
	}
	……
}

(6)在/frameworks/base/core/java/android/app/ContextImpl.java文件的ContextImpl类的静态块中增加

package android.app;

……

class ReceiverRestrictedContext extends ContextWrapper {
	……
}

/**
 * Common implementation of Context API, which provides the base
 * context object for Activity and other application components.
 */
class ContextImpl extends Context {
	……
	
	static {
		……
		registerService(DEMO_SERVICE, new StaticServiceFetcher() {
                public Object createStaticService() {
                    IBinder b = ServiceManager.getService(DEMO_SERVICE);
                    IDemoManager service = IDemoManager.Stub.asInterface(b);
                    return new DemoManager(service);
                }});
		……
	}
	
	……
}

(7)在/frameworks/base/Android.mk中

LOCAL_SRC_FILES += \ 
  下增加 
  
core/java/android/app/IDemoManager.aidl \


(8)这样,重新编译出SDK,然后基于此SDK开发应用程序就可以使用刚刚增加的服务了。

比如,在应用程序中:

import android.app.DemoManager;
……
DemoManager tm = (DemoManager) getSystemService(DEMO_SERVICE);
tm.getVolume();
……