Android 进阶 - Service实例

写本文主要是为了深入了解进程间的Binder通讯,在《Android 入门 -应用启动分析》一文中提到,启动一个应用是当前应用进程通过Binder向ActivityManagerService服务请求操作,从而完成进程到最终的Activity的启动,严格说来,那篇文章不能算入门文章,因为写这篇文章时,我甚至连服务是什么都不了解。本文将通过一个实例来简单说明如何在Android中使用Service。

1. UpperService服务实例

如果要创建一个新的Service,需要以下步骤:
  1. 新建aidl文件,会生成一个基于IBinder服务存根的抽象类;
  2. 写服务的实现类,基于Service,并实现onBind函数和存根抽象类;
  3. 在AndroidManifset.xml中注册该服务;
本例将实现一个转换为大写的服务程序,并在客户端来调用它。

1.1 创建aidl文件

在创建aidl文件之前,假定你已经创建了一个Android ApplicationProject的工程,包名为:com.example.upperservice。新建一个文本文件,贴入以下内容:
package com.example.upperservice;
interface IUpperService {
 String upper(in String toName);
}
将该文件保存到com.example.upperservice包下,取名为IUpperService.aidl。注意,文件名必须是IUpperService,与interface名称保持一致,可见,aidl文件其实是一个接口定义文件,语法和javainterface基本一致,所以,是很容易编写的。
IUpperServer接口中定义了一个upper方法,此方法完成将toName转换为大写的功能。
文件保存后,buildproject,将在gen目录自动生成IUpperService.java文件。下面是IUpperService.java的代码:
package com.example.upperservice;

public interface IUpperService extends android.os.IInterface {
	/** 本地(服务端) IPC 实现存根,本类是抽象类,需要实现upper抽象方法,当然,你的aidl接口文件定义了多少个操作,就要实现多少个. */
	public static abstract class Stub extends android.os.Binder implements com.example.upperservice.IUpperService {
		private static final java.lang.String DESCRIPTOR = "com.example.upperservice.IUpperService";

		/** Construct the stub at attach it to the interface. */
		public Stub() {
			this.attachInterface(this, DESCRIPTOR); //将存根连接到interface
		}

		/**
		 * 生成一个本地的调用代理,如果将IUpperService打包给第三方,可以调用此函数,直接call服务.
		 */
		public static com.example.upperservice.IUpperService asInterface(android.os.IBinder obj) {
			if ((obj == null)) {
				return null;
			}
			android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
			if (((iin != null) && (iin instanceof com.example.upperservice.IUpperService))) {
				return ((com.example.upperservice.IUpperService) iin);
			}
			return new com.example.upperservice.IUpperService.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 INTERFACE_TRANSACTION: {
				reply.writeString(DESCRIPTOR);
				return true;
			}
			case TRANSACTION_upper: {//服务端处理upper调用
				data.enforceInterface(DESCRIPTOR);
				java.lang.String _arg0;
				_arg0 = data.readString();
				java.lang.String _result = this.upper(_arg0);//转至upper抽象方法,要在Service类中实现此方法,完成真正的upper处理
				reply.writeNoException();
				reply.writeString(_result);
				return true;
			}
			}
			return super.onTransact(code, data, reply, flags);
		}
		// 本地代理类,私有的,asInerface就是返回的这个类实例,供外部调用。我们也可以直接把这段代码拷贝到客户端,也可以直接调用远程的服务。
		private static class Proxy implements com.example.upperservice.IUpperService {
			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 java.lang.String upper(java.lang.String toName) throws android.os.RemoteException {
				android.os.Parcel _data = android.os.Parcel.obtain();
				android.os.Parcel _reply = android.os.Parcel.obtain();
				java.lang.String _result;
				try {
					_data.writeInterfaceToken(DESCRIPTOR);
					_data.writeString(toName);
					mRemote.transact(Stub.TRANSACTION_upper, _data, _reply, 0);
					_reply.readException();
					_result = _reply.readString();
				} finally {
					_reply.recycle();
					_data.recycle();
				}
				return _result;
			}
		}

		static final int TRANSACTION_upper = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
	}
	//引出的抽象方法,派生类实现
	public java.lang.String upper(java.lang.String toName) throws android.os.RemoteException;
}
上面的代码做了注解,这个自动生成的代码,其实是生成了客户调用和客户实现之间的代码,用这个文件既可以写本地服务的实现,也可以写客户端的调用代码。

1.2 创建Service类

新建一个com.example.upperservice.UpperService.java,代码如下:
public class UpperService extends Service {
	public static final String TAG = "UPPER_SERVICE";
	final IUpperService.Stub binder = new IUpperService.Stub() {

		@Override
		public String upper(String toName) throws RemoteException {
			return toName == null ? null : toName.toUpperCase();
		}
	}; 

	@Override
	public IBinder onBind(Intent arg0) {
		Log.i(TAG, "onBind");
		return binder;
	}
}
上面的代码很简单,先是生成一个基于IUpperService.Stub的实例,并实现其抽象方法upper,然后,实现Service.onBind函数,返回此binder。服务端代码就完成了。

1.3 注册Service

在AndroidManifset.xml中注册此服务。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.upperservice"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="19"
        android:targetSdkVersion="19" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.upperservice.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service android:name=".UpperService" >
            <intent-filter>
                <action android:name="com.example.upperservice.UpperService" />
            </intent-filter>
        </service>
    </application>

</manifest>
见service的定义段。
到此为止,服务端全部搞定。写一个Android服务真的是非常简单。

2 客户端调用实例

上面的IUpperService.java代码的注解中,已经说明了客户端如何调用。客户端调用服务端的步骤如下:
  1. 创建一个服务调用代理Proxy。
  2. 创建基于ServiceConnection的连接;
  3. 绑定服务,并在ServiceConnection.onServiceConnected,获取IBinder的服务调用接口,实例化Proxy;
  4. 调用Proxy中的方法调用远程服务;

2.1 创建服务调用代理

创建一个UpperServiceProxy类,代码如下:
public class UpperServiceProxy {
	static final int TRANSACTION_upper = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
	private static final java.lang.String DESCRIPTOR = "com.example.upperservice.IUpperService";
	android.os.IBinder remote;

	public UpperServiceProxy(android.os.IBinder remote) {
		this.remote = remote;
	}

	public String upper(String v) throws RemoteException {
		android.os.Parcel _data = android.os.Parcel.obtain();
		android.os.Parcel _reply = android.os.Parcel.obtain();
		java.lang.String _result;
		try {
			_data.writeInterfaceToken(DESCRIPTOR);
			_data.writeString(v);
			remote.transact(TRANSACTION_upper, _data, _reply, 0);
			_reply.readException();
			_result = _reply.readString();
		} finally {
			_reply.recycle();
			_data.recycle();
		}
		return _result;
	}
}
上面的代码,其实是拷贝IUpperService.java中的Proxy的部分代码,因为我在另一应用中调用,不想麻烦引出IUpperService.java类,这样写我们更能知道调用的细节。upper其实就是一个transact的Binder调用,只不过在调用之前按Binder的规范序列化数据,调用之后,再按Binder规范读取处理的返回数据。

2.2 创建服务连接

本实例是放在MainActivity中的一个变量,代码如下:
UpperServiceProxy proxy;
ServiceConnection con = new ServiceConnection() {

	@Override
	public void onServiceDisconnected(ComponentName name) {
	}

	@Override
	public void onServiceConnected(ComponentName name, IBinder service) {
		proxy = new UpperServiceProxy(service);
	}
};
当服务连接之后,创建proxy变量,此后,可以通过proxy调用服务。

2.3 绑定服务

在MainActivity.onCreate中,加入如个代码:
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		...
		bindService(new Intent("com.example.upperservice.UpperService"), con, Context.BIND_AUTO_CREATE);
	}
通过bindService方法绑定服务,需要指定服务的action名称,当服务绑定完成后,会触发调用con.onServiceConnected函数,从而设置proxy。

2.4 调用服务

调用服务就很简单了,直接调用proxy中的方法就行了。如:

	Button button = (Button) rootView.findViewById(R.id.button1);
	button.setOnClickListener(new OnClickListener() {
	
		@Override
		public void onClick(View v) {
			try {
				if(proxy!=null) System.out.println(proxy.upper("Hello World!"));
			} catch (RemoteException e) {
				e.printStackTrace();
			}
	
		}
	});

3. 升级UpperService为系统服务

Android系统中有许多的系统服务,如:ActivityManagerSerivce,PowerManagerService等,这些会在系统启动时就加载,并且调用方式有小小差别。现在说明如何建立一个UpperService的系统服务。

3.1 IUpperService.aidl

将此文件放入到andorid-source/frameworks/base/core/java/android/os/目录下,如:
package android.os;
interface IUpperService {
	String upper(in String toName);
}

4.2 修改frameworks/base/Android.mk

在此文件下加入代码如下:
# FRAMEWORKS_BASE_SUBDIRS comes from build/core/pathmap.mk
LOCAL_SRC_FILES := $(call find-other-java-files,$(FRAMEWORKS_BASE_SUBDIRS))

# EventLogTags files.
LOCAL_SRC_FILES += \
       core/java/android/content/EventLogTags.logtags \
       core/java/android/speech/tts/EventLogTags.logtags \
       core/java/android/webkit/EventLogTags.logtags \

## READ ME: ########################################################
##
## When updating this list of aidl files, consider if that aidl is
## part of the SDK API.  If it is, also add it to the list below that
## is preprocessed and distributed with the SDK.  This list should
## not contain any aidl files for parcelables, but the one below should
## if you intend for 3rd parties to be able to send those objects
## across process boundaries.
##
## READ ME: ########################################################
LOCAL_SRC_FILES += \
	core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl \
	core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl \
	core/java/android/accounts/IAccountManager.aidl \
...
LOCAL_SRC_FILES += core/java/android/os/IUpperService.aidl 
# FRAMEWORKS_BASE_JAVA_SRC_DIRS comes from build/core/pathmap.mk
LOCAL_SRC_FILES += core/java/android/os/IUpperService.aidl为新添加的代码

3.3 编写服务类

framework\base\services\java\com\android\server\UpperService.java,代码如下:
package com.android.server;

import android.content.Context;

public class UpperService extends IUpperService.Stub {
	private final Context mContext;
	public UpperService(Context context){
		mContext = context;
	}
	@Override
	public String upper(String toName)  {
		return toName == null ? null : toName.toUpperCase();
	}
	
	public void systemReady() {
    }
}

3.4 服务注册

将服务注册到SystemServer中,这样可以在系统启动时启动服务了。通过修改SystemServer.java实现。
frameworks/base/services/java/com/android/server/SystemServer.java
class ServerThread {
	...
    public void initAndLoop() {
    	...
    	try{
    		// 添加代码开始
    		Slog.i(TAG, "UPPER SERVICE");
    		ServiceManager.addService("upper",new com.android.server.UpperService(context));
    		// 添加代码结束
            Slog.i(TAG, "Display Manager");
            display = new DisplayManagerService(context, wmHandler);
            ServiceManager.addService(Context.DISPLAY_SERVICE, display, true);
    		...
        } catch (RuntimeException e) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting core service", e);
        }
    
    	...
    }
	...
}

3.5 编译

# cd /Volumes/android/source
# . build/envsetup.sh
# lunch
# make update-api
# make -j16 
# make -j16 
make update-api是由于系统的API没有更新,需要先更新,才能make。

3.6 客户端调用

系统服务都是通过ServiceManager.getService()来获取IBinder的,但在Android应用中,不知道有什么办法访问到ServiceManager. 我又不想再写一个类放到Android源码中引出,再重新编译,所以,只好采取反射的方法来获取IBinder。编写调用代理类如下:
public class UpperServiceProxy {
	static final int TRANSACTION_upper = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
	private static final java.lang.String DESCRIPTOR = "android.os.IUpperService";
	android.os.IBinder remote;

	public UpperServiceProxy() {
		try {
			// 采用反射的方法调用ServiceManager.getService("upper"),获取IBinder接口
			Method method = Class.forName("android.os.ServiceManager").getMethod("getService", String.class);
			this.remote = (android.os.IBinder) method.invoke(null, "upper");
		} catch (Throwable e) {
			e.printStackTrace();
		}
	}

	public String upper(String v) throws RemoteException {
		android.os.Parcel _data = android.os.Parcel.obtain();
		android.os.Parcel _reply = android.os.Parcel.obtain();
		java.lang.String _result;
		try {
			_data.writeInterfaceToken(DESCRIPTOR);
			_data.writeString(v);
			remote.transact(TRANSACTION_upper, _data, _reply, 0);
			_reply.readException();
			_result = _reply.readString();
		} finally {
			_reply.recycle();
			_data.recycle();
		}
		return _result;
	}
}
从上面的代码可以看出,Android无论是系统级服务还是用户级服务,采用的机制都是一样的,只不过系统级服务可以在启动时加载,调用时直接使用ServiceManager.getService()来获取IBinder接口,而用户级服务则需要先绑定服务接口。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值