Service有两种工作状态,一种是启动状态,主要用于执行后台计算; 另一种是绑定状态,主要用于和其它组件的交互。而且这两种状态是可以共存的,关于Service的使用可以看之前的文章《Android里服务Service的使用》。今天主要是对Service的启动状态和绑定状态的工作原理进行介绍。
Service的启动过程
要启动一个Service就是使用startService()方法,示例如:
Intent intent = new Intent(this, MyService.class);
startService(intent);
所以就从startService()方法入手:
ContextWrapper.java
public class ContextWrapper extends Context {
Context mBase;
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
@Override
public ComponentName startService(Intent service) {
return mBase.startService(service);
}
}
可以看到,startService()方法是通过mBase对象再调用startService()方法去进行,那么mBase是什么对象?那就要看下attachBaseContent()方法是谁调用的了。还记得《Android应用程序启动详解(二)之Application和Activity的启动过程》中介绍“Activity的启动过程”时,讲过Activity被创建时会通过attach()方法来初始化一系列重要属性吗?该方法的第一行执行代码就是调用了attachBaseContent()方法,而传入的Context参数是一个ComtextImpl对象,再来重温一下源码:
Activity.java
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window) {
attachBaseContext(context);
……
}
ContextThemeWrapper.java
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
}
上面的super.attachBaseContext就会调到了ContextWrapper。所以我们便知mBase就是ComptextImpl对象,那来看看ComptextImpl的startService()方法的源码:
ContextImpl.java
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, mUser);
}
private ComponentName startServiceCommon(Intent service, UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
// 关键代码
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), getOpPackageName(), user.getIdentifier());
if (cn != null) {
if (cn.getPackageName().equals("!")) {
throw new SecurityException(
"Not allowed to start service " + service
+ " without permission " + cn.getClassName());
} else if (cn.getPackageName().equals("!!")) {
throw new SecurityException(
"Unable to start service " + service
+ ": " + cn.getClassName());
}
}
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
在ComptextImpl中,startService()方法调用了startServiceCommon()方法,请看关键代码行,此处通过ActivityManagerNative.getDefault()获得个对象,然后再调用其startService()。看过我之前的文章《Android应用程序启动详解(一)之Android系统和Android应用的启动过程》应该知道,这是返回了一个IBinder对象。它是通过Binder实现进程间通信的。而这个IBinder对象就是ActivityManagerService,好了直接看下ActivityManagerService中startService()方法做了啥事情:
ActivityManagerService.java
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, String callingPackage, int userId)
throws TransactionTooLargeException {
……
synchronized(this) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
// 关键代码
ComponentName res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid, callingPackage, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
}
代码中的mServices是一个ActiveServices对象,ActiveServices类是一个辅助ActivityManagerService进行Service管理的类,包括Service的启动、绑定和停止等。继续看代码:
ActiveServices.java
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, String callingPackage, final int userId)
throws TransactionTooLargeException {
……
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false);
……
ServiceRecord r = res.record;
……
// 关键代码
return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}
startServiceLocked()方法代码够多,我们只看最关键的最后一句,它又调用了startServiceInnerLocker()方法,而且传入了一个ServiceRecord对象参数:
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
……
// 关键代码
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
……
return r.name;
}
上述代码中,startServiceInnerLocked又将ServiceRecord对象传给了bringUpServiceLocked方法:
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
……
if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
……
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
// 关键代码
realStartServiceLocked(r, app, execInFg);
return null;
}
……
}
}
……
return null;
}
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
……
try {
……
// 关键代码1:创建Service对象
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
created = true;
} catch (DeadObjectException e) {
Slog.w(TAG, "Application dead when creating service " + r);
mAm.appDiedLocked(app);
throw e;
} finally {
……
}
……
// 关键代码2:调用Service的其它方法,比如onStartCommand
sendServiceArgsLocked(r, execInFg, true);
……
}
realStartServiceLocked方法做了两件大事,请看关键代码1, app.thread.scheduleCreateService()方法那就是进行Service对象的创建,这里app.thread是一个IApplicationThread对象,它实际上是一个Binder,它的具体实现是ApplicationThread; 而关键代码2中的sendServiceArgsLocked()方法内部再调用了Service的其它方法,比如onStartCommand等。先来看看ApplicationThread的代码:
ActivityThread.java
public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
updateProcessState(processState, false);
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;
sendMessage(H.CREATE_SERVICE, s);
}
这样也是老套路了跟Application 和 Activity的创建相似,通过发送消息,这里发了一个CREATE_SERVICE消息,继续看看消息接收地方做了啥事情:
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case CREATE_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));
// 关健代码
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
}
……
}
private void handleCreateService(CreateServiceData data) {
unscheduleGcIdler();
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
// 关键代码1:创建Service对象
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
……
}
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
// 关键代码2:创建ContextImpl对象
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
// 关键代码3:调用attach方法初始化属性和关联comtextImpl对象
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
// 关键代码4:调用onCreate()方法
service.onCreate();
mServices.put(data.token, service);
try {
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
……
}
}
HandleCreateService()方法内容很精彩,首先在关键代码1中通过类加载器创建了Service对象,接着在关键代码2中创建了ContextImpl对象,然后在关键代码3中调用attach()方法来初始化Service的一系列变量属性,其中包括了comtextImpl,最后就是调用了其onCreate()方法。
所以,Service创建后第一个调用的方法是onCreate(),然后再回看下realStartServiceLocked()方法中的关键代码为2中的sendServiceArgsLocked()方法,刚才简单提到它会调用Service的其它方法,比如onStartCommand,源码:
ActiveServices.java
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
boolean oomAdjusted) throws TransactionTooLargeException {
……
while (r.pendingStarts.size() > 0) {
Exception caughtException = null;
ServiceRecord.StartItem si = null;
try {
……
// 关键代码
r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
}
……
}
}
方法内也是一个套路,所以我们直接看ApplicationThread的scheduleServiceArgs()方法
ActivityThread.java
public final void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId,
int flags ,Intent args) {
ServiceArgsData s = new ServiceArgsData();
s.token = token;
s.taskRemoved = taskRemoved;
s.startId = startId;
s.flags = flags;
s.args = args;
sendMessage(H.SERVICE_ARGS, s);
}
在SERVICE_ARGS消息接收地方调用了handleServiceArgs()方法:
private void handleServiceArgs(ServiceArgsData data) {
Service s = mServices.get(data.token);
if (s != null) {
try {
……
if (!data.taskRemoved) {
// 关键代码
res = s.onStartCommand(data.args, data.flags, data.startId);
} else {
s.onTaskRemoved(data.args);
res = Service.START_TASK_REMOVED_COMPLETE;
}
……
} catch (Exception e) {
……
}
}
}
好了,到这终于完成了整个Service的启动过程分析。我们终于知道在启动Service后会有onCreate和onStartCommand的回调是怎么回事,而onCreate()方法只有在创建后才回调一次,所以再次调用StartService()方法来启动Service时就不会再回调onCreate,而只有onStartCommand的回调。
Service的绑定过程
我们知道,要绑定一个Service就是使用bindService()方法,示例如:
private MyService.MyBinder myBinder;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBinder = (MyService.MyBinder) service;
myBinder.XXX();
}
};
……
Intent intent = new Intent(this, MyService.class);
//startService(intent);
bindService(intent, mConnection, BIND_AUTO_CREATE);
所以我们就从bindService()方法入手,我们从启动过程中知道mBase是一个ComtextImpl对象,那么直接看ComtextImpl类中的bindService:
ContextImpl.java
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
Process.myUserHandle());
}
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
handler, UserHandle user) {
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
if (mPackageInfo != null) {
// 关键代码1
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
} else {
throw new RuntimeException("Not supported in system context");
}
validateServiceIntent(service);
try {
IBinder token = getActivityToken();
if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
&& mPackageInfo.getApplicationInfo().targetSdkVersion
< android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
flags |= BIND_WAIVE_PRIORITY;
}
service.prepareToLeaveProcess(this);
// 关键代码2
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
if (res < 0) {
throw new SecurityException(
"Not allowed to bind to service " + service);
}
return res != 0;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
请看关键代码1,它通过一个ServiceConnection对象传入mPackageInfo的getServiceDispatcher方法,然后返回一个IServiceConnection对象,此以象其实是一个ServiceDispatcher.InnerConnection对象,因为服务的绑定有可能是跨进程,所以必须借助ServiceDispatcher.InnerConnection,因为它就是一个Binder的角色。请看代码:
LoadedApk.java
private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
= new ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>>();
public final IServiceConnection getServiceDispatcher(ServiceConnection c,
Context context, Handler handler, int flags) {
synchronized (mServices) {
LoadedApk.ServiceDispatcher sd = null;
ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
if (map != null) {
sd = map.get(c);
}
if (sd == null) {
sd = new ServiceDispatcher(c, context, handler, flags);
if (map == null) {
map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
mServices.put(context, map);
}
map.put(c, sd);
} else {
sd.validate(context, handler);
}
return sd.getIServiceConnection();
}
}
代码中可看到从mServices中获取了一个map,这个map就是返回当前Service中ServiceConnection和ServiceDispatcher的映射关系,然后返回ServiceDispatcher的InnerConnection。
回看bindServiceCommon的关键代码2,这也是老套路了,调用了ActivityManagerService中的bindService方法去处理服务的绑定:
ActivityManagerService.java
public int bindService(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String callingPackage,
int userId) throws TransactionTooLargeException {
enforceNotIsolatedCaller("bindService");
……
synchronized(this) {
// 关键代码
return mServices.bindServiceLocked(caller, token, service,
resolvedType, connection, flags, callingPackage, userId);
}
}
ActiveServices.java
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String callingPackage, final int userId) throws TransactionTooLargeException {
……
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
// 关键代码1
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
permissionsReviewRequired) != null) {
return 0;
}
}
……
if (s.app != null && b.intent.received) {
……
// 关键代码2
if (b.intent.apps.size() == 1 && b.intent.doRebind) {
requestServiceBindingLocked(s, b.intent, callerFg, true);
}
} else if (!b.intent.requested) {
requestServiceBindingLocked(s, b.intent, callerFg, false);
}
getServiceMap(s.userId).ensureNotStartingBackground(s);
} finally {
Binder.restoreCallingIdentity(origId);
}
return 1;
}
关键代码1中调用了bringUpServiceLocked()方法,跟启动过程中的startServiceInnerLocked()方法调用bringUpServiceLocked()方法逻辑一样,后面就是创建Service并执行其onCreate方法。我们就不再重复了,来看看关键代码2中的requestServiceBindingLocked()方法,它就是实现Service的绑定过程的逻辑地方:
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
if (r.app == null || r.app.thread == null) {
// If service is not currently running, can't yet bind.
return false;
}
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
bumpServiceExecutingLocked(r, execInFg, "bind");
r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
// 关键代码
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.repProcState);
if (!rebind) {
i.requested = true;
}
i.hasBound = true;
i.doRebind = false;
} catch (TransactionTooLargeException e) {
……
} catch (RemoteException e) {
……
}
}
return true;
}
我们知道,app.thread的实现就是ApplicationThread,来看看干了什么事情:
ActivityThread.java
public final void scheduleBindService(IBinder token, Intent intent,
boolean rebind, int processState) {
updateProcessState(processState, false);
BindServiceData s = new BindServiceData();
s.token = token;
s.intent = intent;
s.rebind = rebind;
if (DEBUG_SERVICE)
Slog.v(TAG, "scheduleBindService token=" + token + " intent=" + intent + " uid="
+ Binder.getCallingUid() + " pid=" + Binder.getCallingPid());
sendMessage(H.BIND_SERVICE, s);
}
又是老套路了,发送一个BIND_SERVICE消息,来继续看看接收消息地方:
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
……
case BIND_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
handleBindService((BindServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
}
……
}
private void handleBindService(BindServiceData data) {
// 关键代码1
Service s = mServices.get(data.token);
if (DEBUG_SERVICE)
Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
try {
if (!data.rebind) {
// 关键代码2
IBinder binder = s.onBind(data.intent);
// 关键代码3
ActivityManagerNative.getDefault().publishService(
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
ensureJitEnabled();
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
} catch (Exception e) {
……
}
}
}
上述代码中,关键代码1中通过token获取到了Service对象,接着在关键代码2中调用其onBinde()方法并返回一个IBinder对象,原则上来说,Service的onBind()方法被调用后,Service就已经处于绑定状态了,然后就是通知客户端的回调,我们知道在Service绑定后会回调一个onServiceConnected方法,这个过程就是关键代码3里实现了。前面多次提到,ActivityManagerNative.getDefault()就是返回ActivityManagerService,所以来看看ActivityManagerService的publishService的代码:
ActivityManagerService.java
public void publishService(IBinder token, Intent intent, IBinder service) {
// Refuse possible leaked file descriptors
if (intent != null && intent.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
synchronized(this) {
if (!(token instanceof ServiceRecord)) {
throw new IllegalArgumentException("Invalid service token");
}
mServices.publishServiceLocked((ServiceRecord)token, intent, service);
}
}
ActiveServices.java
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r
+ " " + intent + ": " + service);
if (r != null) {
Intent.FilterComparison filter
= new Intent.FilterComparison(intent);
IntentBindRecord b = r.bindings.get(filter);
if (b != null && !b.received) {
b.binder = service;
b.requested = true;
b.received = true;
for (int conni=r.connections.size()-1; conni>=0; conni--) {
ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
for (int i=0; i<clist.size(); i++) {
ConnectionRecord c = clist.get(i);
……
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);
try {
// 关键代码
c.conn.connected(r.name, service);
} catch (Exception e) {
……
}
}
}
}
serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
关键代码中,c.conn是一个IServiceConnection对象,从前面我们知道,它其实就是ServiceDispatcher.InnerConnection,所以这里调用了其connected方法可以看回ServiceDispatcher.InnerConnection的定义地方:
LoadedApk.java
private static class InnerConnection extends IServiceConnection.Stub {
final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
InnerConnection(LoadedApk.ServiceDispatcher sd) {
mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
}
public void connected(ComponentName name, IBinder service) throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {
// 关键代码
sd.connected(name, service);
}
}
}
从关键代码行可以看到,又调用了ServiceDispatcher的connected方法:
public void connected(ComponentName name, IBinder service) {
if (mActivityThread != null) {
// 关键代码
mActivityThread.post(new RunConnection(name, service, 0));
} else {
doConnected(name, service);
}
}
mActivityThread是一个Handler,其实它是ActivityThread中的H,所以它不会为nul,那这样一来,RunConnection就可以经由H的post方法从而运行在主线程中,来看看RunConnection的定义:
private final class RunConnection implements Runnable {
RunConnection(ComponentName name, IBinder service, int command) {
mName = name;
mService = service;
mCommand = command;
}
public void run() {
if (mCommand == 0) {
// 关键代码
doConnected(mName, mService);
} else if (mCommand == 1) {
doDeath(mName, mService);
}
}
final ComponentName mName;
final IBinder mService;
final int mCommand;
}
关键代码行又调用了doConnected方法:
public void doConnected(ComponentName name, IBinder service) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;
……
// If there was an old service, it is now disconnected.
if (old != null) {
mConnection.onServiceDisconnected(name);
}
// If there is a new service, it is now connected.
if (service != null) {
// 关键代码
mConnection.onServiceConnected(name, service);
}
}
上述方法内,mConnection对象就是客户端的ServiceConnection对象,所以到此处就是回调到客户端的onServiceConnected方法。也就是整个绑定过程完成了。
总结
- 当Service启动后就会执行onCreate和onStartCommand的回调,而onCreate()方法只有在创建后才回调一次,再次调用StartService()方法只有onStartCommand的回调。
- 多次调用bindService()绑定同一个Service时,Service的onBind()方法只会执行一次,除非Service被终止。
- 当onBind()方法被执行后,Service就已经处于绑定状态了,然后再回调一个onServiceConnected方法给客户端。