这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战
之前的学习记录都是在自己的本地,借着掘金的这次8月活动的机会,也挑战一下自己。各位看官点点赞,小弟先谢过。
前言
我们知道Service分为两种工作状态,一种是启动状态,一种是绑定状态。前者适用于后台计算,后者适用于Service与其他组件的交互。 Service的两种生命周期
-
startService方式:onCreate()--->onStartCommand() --->onDestroy();
-
bindService方式:onCreate()--->onBind() --->onUnbind()--->onDestroy();
Service的启动过程
从Activity的startServic开始旅程。点击会进入ContextWrapper类的startService方法
android.content.ContextWrapper
@Override
public ComponentName startService(Intent service) {
return mBase.startService(service);
}
mBase是ContextImpl类型,在Activity启动过程中,执行attach方法时进行关联。具体代码在文字末尾附加 ContextWrapper的大部分操作都是通过mBase实现。这就是桥接模式 下面去看看具体实现
android.appContextImpl
class ContextImpl extends Context {
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, false, mUser);
}
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
......
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
getOpPackageName(), getAttributionTag(), user.getIdentifier());
}
}
ActivityManager.getService()获取的就是ActivityManageService,一般简称AMS,源码中出现很频繁,还不清楚的可以去看看我之前的文章。
继续去看AMS下的startService
com.android.server.am.ActivityManagerService
final ActiveServices mServices;
......
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, boolean requireForeground, String callingPackage,
String callingFeatureId, int userId)
throws TransactionTooLargeException {
......
ComponentName res;
try {
关键代码
res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid,
requireForeground, callingPackage, callingFeatureId, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
return res;
}
}
如果是打开AS跟着看代码的小伙伴,可以滚动鼠标看看上下的方法,其实都是和Service相关的,所以记住AMS这个类吧。
mServices是ActiveServices类型的,后续的Service操作由它完成。
com.android.server.am.ActiveServices
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage,
@Nullable String callingFeatureId, final int userId,
boolean allowBackgroundActivityStarts) throws TransactionTooLargeException {
......
关键代码
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
if (!r.mAllowWhileInUsePermissionInFgs) {
r.mAllowWhileInUsePermissionInFgs =
shouldAllowWhileInUsePermissionInFgsLocked(callingPackage, callingPid,
callingUid, service, r, allowBackgroundActivityStarts);
}
return cmp;
}
在startServiceLocked中调用startServiceInnerLocked
com.android.server.am.ActiveServices
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
ServiceState stracker = r.getTracker();
if (stracker != null) {
stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
}
r.callStart = false;
......
关键代码
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
......
return r.name;
}
bringUpServiceLocked方法内部挺长的,看的迷迷糊糊,忽然看的一个realStartServiceLocked方法。看这名字,应该就是真正启动Service的地方了吧。
com.android.server.am.ActiveServices
private final void realStartServiceLocked(ServiceRecord r,ProcessRecord app, boolean execInFg) throws RemoteException {
......
//内部将会执行onStartCreate
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
app.getReportedProcState());
......
//内部将会执行onStartCommond
sendServiceArgsLocked(r, execInFg, true);
......
}
app.thread 和ActivityManager.getService()一样,也是很常见的引用,就是ApplicationThread对象
Service的onCreate
接下来去ApplicationThread看看scheduleCreateService做了些什么,看过文章的小伙伴,就该知道,多半又是去发消息了。
android.app.ActivityThread
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);
}
在内部类H中,对这个消息的处理是
case CREATE_SERVICE:
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
("serviceCreate: " + String.valueOf(msg.obj)));
}
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
熟悉的套路,去ApplicationThread发消息,H去处理具体实现。
android.app.ActivityThread
@UnsupportedAppUsage
private void handleCreateService(CreateServiceData data) {
unscheduleGcIdler();
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
创建ContextImpl对象
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
获取application
Application app = packageInfo.makeApplication(false, mInstrumentation);
java.lang.ClassLoader cl = packageInfo.getClassLoader();
通过反射获取service
service = packageInfo.getAppFactory()
.instantiateService(cl, data.info.name, data.intent);
// Service resources must be initialized with the same loaders as the application
// context.
context.getResources().addLoaders(
app.getResources().getLoaders().toArray(new ResourcesLoader[0]));
context.setOuterContext(service);
将ContextImpl于Service建立链接,与Activity类似
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
执行Service的onCreate
service.onCreate();
将当前Service添加到mServices中
mServices.put(data.token, service);
try {
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to create service " + data.info.name
+ ": " + e.toString(), e);
}
}
}
真的干活还得是靠你啊。。。梳理一下
- 创建ContextImpl对象
- 创建Application,当然这个东西全局只有一个,在Appliction初始化中介绍过
- 通过反射获取service
- 将ContextImpl于Service建立链接
- 执行Service的onCreate
- 将当前Service添加到mServices中,定义如下 至此,Service的onCreat 执行了,也就意味着Service启动了。
final ArrayMap<IBinder, Service> mServices = new ArrayMap<>();
Service的onStartCommond
在前面的代码realStartServiceLocked方法内部,下面还有一个关键方法sendServiceArgsLocked
com.android.server.am.ActiveServices
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
boolean oomAdjusted) throws TransactionTooLargeException {
......
try {
r.app.thread.scheduleServiceArgs(r, slice);
} catch (TransactionTooLargeException e) {
......
}
......
}
执行了ApplicationThread的scheduleServiceArgs方法
android.app.ActivityThread
内部类ApplicationThread中:
public final void scheduleServiceArgs(IBinder token, ParceledListSlice args) {
List<ServiceStartArgs> list = args.getList();
for (int i = 0; i < list.size(); i++) {
......
sendMessage(H.SERVICE_ARGS, s);
}
}
内部类H中:
case SERVICE_ARGS:
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
("serviceStart: " + String.valueOf(msg.obj)));
}
handleServiceArgs((ServiceArgsData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
private void handleServiceArgs(ServiceArgsData data) {
// 从mServices取出Service实例
Service s = mServices.get(data.token);
if (s != null) {
try {
if (data.args != null) {
data.args.setExtrasClassLoader(s.getClassLoader());
data.args.prepareToEnterProcess();
}
int res;
if (!data.taskRemoved) {
执行onStartCommand
res = s.onStartCommand(data.args, data.flags, data.startId);
} else {
s.onTaskRemoved(data.args);
res = Service.START_TASK_REMOVED_COMPLETE;
}
......
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
"Unable to start service " + s
+ " with " + data.args + ": " + e.toString(), e);
}
}
}
}
在handleServiceArgs中, 先是从mServices中取出之前创建好的Service,然后执行Service的onStartCommand方法。这也就说明了,onStartCommand确实是在onCreate之后执行的。
Service的绑定过程
与Service的启动过程一样,bindService在ContextImpl中实现,内部会调用bindServiceCommon
android.content.ContextWrapper
@Override
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null,
getUser());
}
内部调用的是bindServiceCommon方法,需要我们重点关注一下
android.content.ContextImpl
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
String instanceName, Handler handler, Executor executor, UserHandle user) {
// Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
IServiceConnection sd;
......
①将conn参数传入getServiceDispatcher,获取IServiceConnection类型的对象 sd
if (mPackageInfo != null) {
if (executor != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags);
} else {
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);
②通过AMS完成绑定操作
int res = ActivityManager.getService().bindIsolatedService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, instanceName, 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();
}
}
bindServiceCommon方法比较长,主要做了两件事:
- 将ServiceConnection对象conn转换成ServiceDispatcher.InnerConnection类型对象sd
- 通过AMS完成绑定操作 我知道只看上面代码得出做了上述的两件事的结论是比较懵逼的,无妨,我们进到具体代码来说明。
将ServiceConnection类型转换成ServiceDispatcher.InnerConnection
首先,来确定为什么说IServiceConnection的实例sd实际上是ServiceDispatcher.InnerConnection类型。
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags);
点击getServiceDispatcher可以发现在类LoadedApk中,这个类我们也不陌生,因为Application的创建就在这个类里。
android.app.LoadedApk
public final IServiceConnection getServiceDispatcher(ServiceConnection c,
Context context, Handler handler, int flags) {
return getServiceDispatcherCommon(c, context, handler, null, flags);
}
private IServiceConnection getServiceDispatcherCommon(ServiceConnection c,
Context context, Handler handler, Executor executor, int flags) {
synchronized (mServices) {
LoadedApk.ServiceDispatcher sd = null;
......
return sd.getIServiceConnection();
}
}
这边最后进入的是ServiceDispatcher类里的getIServiceConnection方法
android.app.LoadedApk
static final class ServiceDispatcher{
private final ServiceDispatcher.InnerConnection mIServiceConnection;
IServiceConnection getIServiceConnection() {
return mIServiceConnection;
}
}
问题得到解释,getIServiceConnection方法最后返回的mIServiceConnection是ServiceDispatcher.InnerConnection类型。 新的问题又来了,为什么要这么大费周章的去将ServiceConnection转换成ServiceDispatcher.InnerConnection呢? 《Android开发艺术探索》是这么解释的:
之所以不能直接使用ServiceConnection对象,这是因为服务的绑定可能是跨进程的,因此ServiceConnection对象必须借助于Binder才能让远程服务端回调自己的方法,而ServiceDispatcher的内部类InnerConnection刚好充当Binder这个角色,那么ServiceDispatcher的作用起着链接ServiceConnection和InnerConnection的作用。
ActivityManagerSerice完成绑定
我们已经熟悉的指导ActivityManager.getService()其实获取的就是ActivityManagerSerice(AMS)对象,所以去里面找bindIsolatedService即可
com.android.server.am.ActivityManagerSerice
final ActiveServices mServices;
......
public int bindIsolatedService(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String instanceName,
String callingPackage, int userId) throws TransactionTooLargeException {
......
synchronized(this) {
return mServices.bindServiceLocked(caller, token, service,
resolvedType, connection, flags, instanceName, callingPackage, userId);
}
}
流程来到ActiveServices中
com.android.server.am.ActiveServices
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String instanceName, String callingPackage, final int userId)
throws TransactionTooLargeException {
......
内部执行onCreate
bringUpServiceLocked(serviceRecord,serviceIntent.getFlags(),callerFg, false, false);
......
内部执行onBind
requestServiceBindingLocked(s, b.intent, callerFg, true);
......
}
这里的流程和Serice启动的流程其实类似,第一步都是创建Service,然后执行启动或者绑定方法。bringUpServiceLocked内部就是执行Service的OnCreate,requestServiceBindingLocked内部则是执行绑定。
com.android.server.am.ActiveServices
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
......
realStartServiceLocked(r, app, execInFg);
......
}
可以看到在bringUpServiceLocked内部,同样执行了realStartServiceLocked 方法,这个方法在分析Service启动流程中已经看到过,就是执行Service的onCreate。接着看
com.android.server.am.ActiveServices
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
......
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.getReportedProcState());
......
}
同样的套路,去ApplicationThread发个消息,去H中执行。
android.app.ActivityThread
public final void scheduleBindService(IBinder token, Intent intent,
boolean rebind, int processState) {
......
sendMessage(H.BIND_SERVICE, s);
}
在内部类H中,对这个消息的处理是
case BIND_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
handleBindService((BindServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
看看handleBindService具体做了啥吧
android.app.ActivityThread
private void handleBindService(BindServiceData data) {
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();
//这里的代码就是说明,为什么我们常说Service只能绑定一次了
try {
if (!data.rebind) {
IBinder binder = s.onBind(data.intent);
系统告知客户端已经成功链接Service了
ActivityManager.getService().publishService(
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
"Unable to bind to service " + s
+ " with " + data.intent + ": " + e.toString(), e);
}
}
}
}
handleBindService做了两件事,
- 执行onBind
- 通知客户端已经完成了Service的绑定 当我自己分析到这的时候,我以为已经结束了。后面在《Android开发艺术》看到:onBind是Service的方法,客户端自己并不知道已经链接成功了,所以才有后面的通过AMS去通知客户端的操作。
所以继续分析呗:如何通知客服端,服务已经绑定成功。直接去AMS找
com.android.server.am.ActivityManagerService
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是ActiveServices类型
mServices.publishServiceLocked((ServiceRecord)token, intent, service);
}
}
com.android.server.am.ActiveServices
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
......
c.conn.connected(r.name, service, false);
} catch (Exception e) {
}
}
这个conn是之前提过的ServiceDispatcher.InnerConnection类型
android.app.LoadedApk
static final class ServiceDispatcher {
private final ServiceConnection mConnection;
......
public void connected(ComponentName name, IBinder service, boolean dead) {
if (mActivityExecutor != null) {
mActivityExecutor.execute(new RunConnection(name, service, 0, dead));
} else if (mActivityThread != null) {
mActivityThread.post(new RunConnection(name, service, 0, dead));
} else {
关键代码
doConnected(name, service, dead);
}
}
public void doConnected(ComponentName name, IBinder service, boolean dead) {
......
mActivityThread.post(new RunConnection(name, service, 0, dead));
}
}
mActivityThread内部有个Handler类型的H,所以这个方法直接post到主线程执行。RunConnection定义如下
private final class RunConnection implements Runnable {
RunConnection(ComponentName name, IBinder service, int command, boolean dead) {
mName = name;
mService = service;
mCommand = command;
mDead = dead;
}
public void run() {
if (mCommand == 0) {
//关键代码
doConnected(mName, mService, mDead);
} else if (mCommand == 1) {
doDeath(mName, mService);
}
}
final ComponentName mName;
final IBinder mService;
final int mCommand;
final boolean mDead;
}
public void doConnected(ComponentName name, IBinder service, boolean dead) {
if (service != null) {
mConnection.onServiceConnected(name, service);
}
}
mConnection就是我们一使用bindService传入的第二个参数,至此客户端的onServiceConnected执行,Service的绑定过程分析完成。
如果你对mConnection.onServiceConnected(name, service);这个行代码为何代表客户端已经执行onServiceConnected的结论还有疑问,文章末尾会加以解析
附加:mBase是个啥
android.content.ContextWrapper
mBase的赋值
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
android.app.Activity
@UnsupportedAppUsage
final void attach(Context context, ...) {
attachBaseContext(context);
......
}
而我们知道attach方法是在ActivityThread的performLaunchActivity内调用
android.app.ActivityThread
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
......
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
......
所以mBase就是ContextImpl类型
activity.attach(appContext,...);
......
}