Android中的服务比较多,可以说整个Android都是基于C-S架构来工作的,搞清楚每一个服务的核心,如何添加服务,就能快速理解Android的工作机制。
Android的服务主要分为Java Service和Native Service,其中Java Servcie又可以分为 应用层的Service和framework层的service
先说应用层的Service的添加
如果service的客户端和服务端在同一个进程中,那非常简单,在同一个apk中实现一个继承于Service的类,然后在主线程中用startservcie()调用这个service即可。注意,service必须注册在AndroidManifest.xml中
如果servcie的客户端和服务端不在同一个进程中,就稍微复杂一些,需要用到aidl技术
下面有一个简单的例子
客户端进程提供两个数字给服务端,服务端进程负责计算出两个数字之和,并返回给客户端。
先看服务端
服务端中要自己创建一个ICalcServcie.aidl文件,内容如下,该文件中声明的函数,都是后面即将暴露给客户端的函数,aidl写完保存以后,eclipse会自动编译出一个ICalcService.java文件
package com.example.aidldemoservice;
interface ICalcService {
int add(int value1, int value2);
}
ICalcServcie.aidl文件中定义的接口的具体实现在CalcService.java中,该类实现了函数的具体逻辑,并且重写了onBind,把mBinder作为返回值。实际上,在客户端调用该服务时,返回给它的就是这个mBinder
package com.example.aidldemoservice;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class CalcService extends Service{
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return mBinder;
}
private final ICalcService.Stub mBinder = new ICalcService.Stub() {
@Override
public int add(int value1, int value2) throws RemoteException {
// TODO Auto-generated method stub
return value1 + value2;
}
};
}
在AndroidMinifest.XML中注册Service
<service
android:name=".CalcService">
<intent-filter >
<action android:name="com.example.aidldemoservice.service"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
到此,服务端的任务就完成了,就等着客户端进程来调用了
客户端进程:
客户端代码要包含服务端中的ICalcService.aidl文件,而且包名也要和服务端一样,然后就是客户端的activity的编写了
主要过程如下:
package com.example.aiddemoclient;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import com.example.aidldemoservice.ICalcService;
public class MainActivity extends ActionBarActivity implements OnClickListener{
private Button btCalc;
private TextView tvResult;
private EditText etValue1;
private EditText etValue2;
ICalcService mService;
MyServiceConnection myServiceConnection;
private final class MyServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
mService = ICalcService.Stub.asInterface((IBinder)service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
mService = null;
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btCalc = (Button)findViewById(R.id.buttonCalc);
tvResult = (TextView)findViewById(R.id.result);
etValue1 = (EditText)findViewById(R.id.value1);
etValue2 = (EditText)findViewById(R.id.value2);
btCalc.setOnClickListener(this);
myServiceConnection = new MyServiceConnection();
Intent intent = new Intent("com.example.aidldemoservice.service");
bindService(intent,myServiceConnection,Context.BIND_AUTO_CREATE);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
int v1, v2, res = -1;
v1 = Integer.parseInt(etValue1.getText().toString());
v2 = Integer.parseInt(etValue2.getText().toString());
try {
res = mService.add(v1,v2);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
tvResult.setText(Integer.valueOf(res).toString());
}
}
重点是要自己实现一个接口ServiceConnection,在这个接口中复写onServiceConnected和onServiceDisconnected,在onServiceConnected中,
mService = ICalcService.Stub.asInterface((IBinder)service);
这句话非常关键,正是它获得了远端的service的bindier,然后,mService才可以调用远端的add方法
res = mService.add(v1,v2);
接着是系统层的service
其实和应用层类似,我们以WindowManagerService(WMS)和PackageManagerService(PMS)为例来分析一下
/** {@hide} */
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
static final String TAG = "WindowManager";
static final boolean DEBUG = false;
static final boolean DEBUG_ADD_REMOVE = false;
static final boolean DEBUG_FOCUS = false;
static final boolean DEBUG_FOCUS_LIGHT = DEBUG_FOCUS || false;
static final boolean DEBUG_ANIM = false;
static final boolean DEBUG_KEYGUARD = false;
/**
* Keep track of all those .apks everywhere.
*
* This is very central to the platform's security; please run the unit
* tests whenever making modifications here:
*
mmm frameworks/base/tests/AndroidTests
adb install -r -f out/target/product/passion/data/app/AndroidTests.apk
adb shell am instrument -w -e class com.android.unit_tests.PackageManagerTests com.android.unit_tests/android.test.InstrumentationTestRunner
*
* {@hide}
*/
public class PackageManagerService extends IPackageManager.Stub {
static final String TAG = "PackageManager";
static final boolean DEBUG_SETTINGS = false;
static final boolean DEBUG_PREFERRED = false;
static final boolean DEBUG_UPGRADE = false;
private static final boolean DEBUG_INSTALL = false;
private static final boolean DEBUG_REMOVE = false;
private static final boolean DEBUG_BROADCASTS = false;
可以看出WMS和PMS都是继承与XX.stub类,这个和应用层服务有点儿类似,对了,这里也是用了aidl文件。WMS对应的文间是IWindowManager.aidl,PMS对应的文件是IPackageManager.aidl,作用前面讲过,规定了哪些接口可以暴露给其他进程,WMS和PMS实现了这些接口。
SystemServer.java中
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
PMS.java中
ServiceManager.addService("package", m);
系统的服务通常都是先放到ServiceManager(SMgr)中统一管理的
当其他进程需要使用时,
WindowManagerGlobal.java
public static IWindowManager getWindowManagerService() {
synchronized (WindowManagerGlobal.class) {
if (sWindowManagerService == null) {
sWindowManagerService = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
try {
sWindowManagerService = getWindowManagerService();
ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale());
} catch (RemoteException e) {
Log.e(TAG, "Failed to get WindowManagerService, cannot set animator scale", e);
}
}
return sWindowManagerService;
}
}
得到WMS远端的binder,传给客户进程使用
ActivityThread.java
public static IPackageManager getPackageManager() {
if (sPackageManager != null) {
//Slog.v("PackageManager", "returning cur default = " + sPackageManager);
return sPackageManager;
}
IBinder b = ServiceManager.getService("package");
//Slog.v("PackageManager", "default service binder = " + b);
sPackageManager = IPackageManager.Stub.asInterface(b);
//Slog.v("PackageManager", "default service = " + sPackageManager);
return sPackageManager;
}
得到PMS的binder,传给客户进程使用
客户进程得到对应服务的binder后,就可以使用aidl文件中定义的函数了。
关于Native Service,下篇再说