Service工作过程
- 服务是一种运行在后台的组件,可能我们一般情况是见不到服务的具象表现的,但是他在我们的android开发中却是不可或缺的东西,下来我们就来结合源码具体分析一下他的工作过程
- 如果对service的使用还是不太了解的话,烦请移驾这里
Service运行状态
- 我们知道,service分为两种工作状态,启动状态(主要用于后台数据的计算),绑定状态(主要用于其他组件和Service之间的交互),需要注意的是,Service这两种状态是可以共存的,
- 通过Context的startService可以启动一个Service
startService(new Intent(this,LocalService.class));
- 通过context的bindService方法可以以绑定的方式启动一个Service
bindService(new Intent(this, LocalService.class),mConnection, Context.BIND_AUTO_CREATE)
Service的启动过程
- 从我们写的startService方法追进去发现来到的是ContextWrapper的startService方法
public ComponentName startService(Intent service) {
return mBase.startService(service);
}
- 这个base就是context类型变量,可是这个context是一个抽象类,
- 这里我通过查阅资料得知,我们在创建Activity的时候会将Activity与一个ContextImpl对象相关联,而此对象是继承自Context的,所以我们应该猜的到,这里的mBase就是前面说的contextImpl对象,我们来到ContextImpl里面查看他的startService方法
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, false, mUser);
}
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), requireForeground,
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());
} else if (cn.getPackageName().equals("?")) {
throw new IllegalStateException(
"Not allowed to start service " + service + ": " + cn.getClassName());
}
}
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
- 可以看到,Service最终是通过ActivityManagerService的startService方法来启动的
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, boolean requireForeground, String callingPackage, int userId)
throws TransactionTooLargeException {
enforceNotIsolatedCaller("startService");
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
if (callingPackage == null) {
throw new IllegalArgumentException("callingPackage cannot be null");
}
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"*** startService: " + service + " type=" + resolvedType + " fg=" + requireForeground);
synchronized(this) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
ComponentName res;
try {
res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid,
requireForeground, callingPackage, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
return res;
}
}
- 可以看到,在ActivityManagerService的内部,其实是通过MService这个对象来启动Service的
- 而MService是ActiveServices类型的对象,这里要说的是,这个ActiveServices是辅助ActivityManagerService管理Service的类,我们继续看ActiveServices的startServiceLocked方法
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
throws TransactionTooLargeException {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service
+ " type=" + resolvedType + " args=" + service.getExtras());
final boolean callerFg;
if (caller != null) {
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
if (callerApp == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + callingPid
+ ") when starting service " + service);
}
callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
} else {
callerFg = true;
}
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false);
if (res == null) {
return null;
}
if (res.record == null) {
return new ComponentName("!", res.permission != null
? res.permission : "private to package");
}
ServiceRecord r = res.record;
if (!mAm.mUserController.exists(r.userId)) {
Slog.w(TAG, "Trying to start service with non-existent user! " + r.userId);
return null;
}
// If this isn't a direct-to-foreground start, check our ability to kick off an
// arbitrary service
if (!r.startRequested && !fgRequired) {
// Before going further -- if this app is not allowed to start services in the
// background, then at this point we aren't going to let it period.
final int allowed = mAm.getAppStartModeLocked(r.appInfo.uid, r.packageName,
r.appInfo.targetSdkVersion, callingPid, false, false);
if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
Slog.w(TAG, "Background start not allowed: service "
+ service + " to " + r.name.flattenToShortString()
+ " from pid=" + callingPid + " uid=" + callingUid
+ " pkg=" + callingPackage);
if (allowed == ActivityManager.APP_START_MODE_DELAYED) {
// In this case we are silently disabling the app, to disrupt as
// little as possible existing apps.
return null;
}
// This app knows it is in the new model where this operation is not
// allowed, so tell it what has happened.
UidRecord uidRec = mAm.mActiveUids.get(r.appInfo.uid);
return new ComponentName("?", "app is in background uid " + uidRec);
}
}
NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked(
callingUid, r.packageName, service, service.getFlags(), null, r.userId);
// If permissions need a review before any of the app components can run,
// we do not start the service and launch a review activity if the calling app
// is in the foreground passing it a pending intent to start the service when
// review is completed.
if (mAm.mPermissionReviewRequired) {
if (!requestStartTargetPermissionsReviewIfNeededLocked(r, callingPackage,
callingUid, service, callerFg, userId)) {
return null;
}
}
if (unscheduleServiceRestartLocked(r, callingUid, false)) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "START SERVICE WHILE RESTART PENDING: " + r);
}
r.lastActivity = SystemClock.uptimeMillis();
r.startRequested = true;
r.delayedStop = false;
r.fgRequired = fgRequired;
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
service, neededGrants, callingUid));
final ServiceMap smap = getServiceMapLocked(r.userId);
boolean addToStarting = false;
if (!callerFg && !fgRequired && r.app == null
&& mAm.mUserController.hasStartedUserState(r.userId)) {
ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) {
// If this is not coming from a foreground caller, then we may want
// to delay the start if there are already other background services
// that are starting. This is to avoid process start spam when lots
// of applications are all handling things like connectivity broadcasts.
// We only do this for cached processes, because otherwise an application
// can have assumptions about calling startService() for a service to run
// in its own process, and for that process to not be killed before the
// service is started. This is especially the case for receivers, which
// may start a service in onReceive() to do some additional work and have
// initialized some global state as part of that.
if (DEBUG_DELAYED_SERVICE) Slog.v(TAG_SERVICE, "Potential start delay of "
+ r + " in " + proc);
if (r.delayed) {
// This service is already scheduled for a delayed start; just leave
// it still waiting.
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Continuing to delay: " + r);
return r.name;
}
if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
// Something else is starting, delay!
Slog.i(TAG_SERVICE, "Delaying start of: " + r);
smap.mDelayedStartList.add(r);
r.delayed = true;
return r.name;
}
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Not delaying: " + r);
addToStarting = true;
} else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
// We slightly loosen when we will enqueue this new service as a background
// starting service we are waiting for, to also include processes that are
// currently running other services or receivers.
addToStarting = true;
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
"Not delaying, but counting as bg: " + r);
} else if (DEBUG_DELAYED_STARTS) {
StringBuilder sb = new StringBuilder(128);
sb.append("Not potential delay (state=").append(proc.curProcState)
.append(' ').append(proc.adjType);
String reason = proc.makeAdjReason();
if (reason != null) {
sb.append(' ');
sb.append(reason);
}
sb.append("): ");
sb.append(r.toString());
Slog.v(TAG_SERVICE, sb.toString());
}
} else if (DEBUG_DELAYED_STARTS) {
if (callerFg || fgRequired) {
Slog.v(TAG_SERVICE, "Not potential delay (callerFg=" + callerFg + " uid="
+ callingUid + " pid=" + callingPid + " fgRequired=" + fgRequired + "): " + r);
} else if (r.app != null) {
Slog.v(TAG_SERVICE, "Not potential delay (cur app=" + r.app + "): " + r);
} else {
Slog.v(TAG_SERVICE,
"Not potential delay (user " + r.userId + " not started): " + r);
}
}
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
return cmp;
}
- 这里我直接贴源码,简单的分析我们可以知道,这个方法其实做的是简单的检查处理,服务是否已经启动,我们传进来的参数是否符合标准,以及相对应的一些权限问题等,在这一部分做完之后,在方法的最后,调用了ActiveServices的startServiceInnerLocked方法
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
synchronized (r.stats.getBatteryStats()) {
r.stats.startRunningLocked()
}
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false)
if (error != null) {
return new ComponentName("!!", error)
}
if (r.startRequested && addToStarting) {
boolean first = smap.mStartingBackground.size() == 0
smap.mStartingBackground.add(r)
r.startingBgTimeout = SystemClock.uptimeMillis() + mAm.mConstants.BG_START_TIMEOUT
if (DEBUG_DELAYED_SERVICE) {
RuntimeException here = new RuntimeException("here")
here.fillInStackTrace()
Slog.v(TAG_SERVICE, "Starting background (first=" + first + "): " + r, here)
} else if (DEBUG_DELAYED_STARTS) {
Slog.v(TAG_SERVICE, "Starting background (first=" + first + "): " + r)
}
if (first) {
smap.rescheduleDelayedStartsLocked()
}
} else if (callerFg || r.fgRequired) {
smap.ensureNotStartingBackgroundLocked(r)
}
return r.name
}
- 其中参数ServiceRecord主要做的是Service的状态记录
- 这个方法并没有做Service的启动工作,通过上下文分析,我们发现他将工作交给了ActiveService的bringUpServiceLocked方法
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
if (r.app != null && r.app.thread != null) {
sendServiceArgsLocked(r, execInFg, false);
return null;
}
if (!whileRestarting && mRestartingServices.contains(r)) {
return null;
}
if (DEBUG_SERVICE) {
Slog.v(TAG_SERVICE, "Bringing up " + r + " " + r.intent + " fg=" + r.fgRequired);
}
if (mRestartingServices.remove(r)) {
clearRestartingIfNeededLocked(r);
}
if (r.delayed) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (bring up): " + r);
getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
if (!mAm.mUserController.hasStartedUserState(r.userId)) {
String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
+ r.intent.getIntent() + ": user " + r.userId + " is stopped";
Slog.w(TAG, msg);
bringDownServiceLocked(r);
return msg;
}
try {
AppGlobals.getPackageManager().setPackageStoppedState(
r.packageName, false, r.userId);
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ r.packageName + ": " + e);
}
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
final String procName = r.processName;
String hostingType = "service";
ProcessRecord app;
if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
+ " app=" + app);
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
realStartServiceLocked(r, app, execInFg);
return null;
} catch (TransactionTooLargeException e) {
throw e;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}
}
} else {
app = r.isolatedProc;
if (WebViewZygote.isMultiprocessEnabled()
&& r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {
hostingType = "webview_service";
}
}
if (app == null && !permissionsReviewRequired) {
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
hostingType, r.name, false, isolated, false)) == null) {
String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
+ r.intent.getIntent() + ": process is bad";
Slog.w(TAG, msg);
bringDownServiceLocked(r);
return msg;
}
if (isolated) {
r.isolatedProc = app;
}
}
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
if (r.delayedStop) {
r.delayedStop = false;
if (r.startRequested) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
"Applying delayed stop (in bring up): " + r);
stopServiceLocked(r);
}
}
return null;
}
- 这个方法的话,感觉重点是对真正启动前的一些处理,比如说启动延迟,或者说启动前的错误发生处理,和一些机制的设置
- 然后来到ActiveService的realStartServiceLocked方法
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
if (app.thread == null) {
throw new RemoteException();
}
if (DEBUG_MU)
Slog.v(TAG_MU, "realStartServiceLocked, ServiceRecord.uid = " + r.appInfo.uid
+ ", ProcessRecord.uid = " + app.uid);
r.app = app;
r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
final boolean newService = app.services.add(r);
bumpServiceExecutingLocked(r, execInFg, "create");
mAm.updateLruProcessLocked(app, false, null);
updateServiceForegroundLocked(r.app, false);
mAm.updateOomAdjLocked();
boolean created = false;
try {
if (LOG_SERVICE_START_STOP) {
String nameTerm;
int lastPeriod = r.shortName.lastIndexOf('.');
nameTerm = lastPeriod >= 0 ? r.shortName.substring(lastPeriod) : r.shortName;
EventLogTags.writeAmCreateService(
r.userId, System.identityHashCode(r), nameTerm, r.app.uid, r.app.pid);
}
synchronized (r.stats.getBatteryStats()) {
r.stats.startLaunchedLocked();
}
mAm.notifyPackageUse(r.serviceInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_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 {
if (!created) {
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
if (newService) {
app.services.remove(r);
r.app = null;
}
if (!inDestroying) {
scheduleServiceRestartLocked(r, false);
}
}
}
if (r.whitelistManager) {
app.whitelistManager = true;
}
requestServiceBindingsLocked(r, execInFg);
updateServiceClientActivitiesLocked(app, null, true);
if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
null, null, 0));
}
sendServiceArgsLocked(r, execInFg, true);
if (r.delayed) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (new proc): " + r);
getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
if (r.delayedStop) {
r.delayedStop = false;
if (r.startRequested) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
"Applying delayed stop (from start): " + r);
stopServiceLocked(r);
}
}
}
- 在这个方法里面,首先调用app.thread.scheduleCreateService来创建Service并调用其onCreate
- 这里跟分析Activity启动过程的时候一样app.Thread其实就是ApplicationThread,他是ActivityThread的内部类,我们来到他的scheduleCreateService方法
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);
}
- 可以看到,通过Handler去了ActivityThread去创建了,我们找到具体的地方
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
- 来到ActivityThread的handleCreateService方法
private void handleCreateService(CreateServiceData data) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler()
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo)
Service service = null
try {
//通过类加载器创建Service
java.lang.ClassLoader cl = packageInfo.getClassLoader()
service = (Service) cl.loadClass(data.info.name).newInstance()
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to instantiate service " + data.info.name
+ ": " + e.toString(), e)
}
}
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name)
ContextImpl context = ContextImpl.createAppContext(this, packageInfo)
context.setOuterContext(service)
Application app = packageInfo.makeApplication(false, mInstrumentation)
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService())
//onCreate方法被调用
service.onCreate()
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)
}
}
}
- 可见,刚开始是通过类加载器创建Service
- 创建好之后,给它设置必要的属性数据,然后调用create方法
- 从这里出来之后,我们就会回到ActiveService的realStartServiceLocked方法
- 再重新贴一下这个方法的代码
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
......
requestServiceBindingsLocked(r, execInFg);
updateServiceClientActivitiesLocked(app, null, true);
if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
null, null, 0));
}
sendServiceArgsLocked(r, execInFg, true);
if (r.delayed) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (new proc): " + r);
getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
if (r.delayedStop) {
r.delayedStop = false;
if (r.startRequested) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
"Applying delayed stop (from start): " + r);
stopServiceLocked(r);
}
}
}
- 来到ActiveService的sendServiceArgsLocked方法
- 这个方法就中间一句关键代码
r.app.thread.scheduleServiceArgs(r, slice)
- 在ApplicationThread的scheduleServiceArgs方法
public final void scheduleServiceArgs(IBinder token, ParceledListSlice args) {
List<ServiceStartArgs> list = args.getList()
for (int i = 0
ServiceStartArgs ssa = list.get(i)
ServiceArgsData s = new ServiceArgsData()
s.token = token
s.taskRemoved = ssa.taskRemoved
s.startId = ssa.startId
s.flags = ssa.flags
s.args = ssa.args
sendMessage(H.SERVICE_ARGS, s)
}
}
case SERVICE_ARGS:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceStart: " + String.valueOf(msg.obj)))
handleServiceArgs((ServiceArgsData)msg.obj)
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER)
break
- ActivityThread的handleServiceArgs方法
private void handleServiceArgs(ServiceArgsData data) {
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) {
res = s.onStartCommand(data.args, data.flags, data.startId)
} else {
s.onTaskRemoved(data.args)
res = Service.START_TASK_REMOVED_COMPLETE
}
QueuedWork.waitToFinish()
try {
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_START, data.startId, res)
} catch (RemoteException e) {
throw e.rethrowFromSystemServer()
}
ensureJitEnabled()
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
"Unable to start service " + s
+ " with " + data.args + ": " + e.toString(), e)
}
}
}
}
- 可以看到到这里同样会根据Service的不同状态来调用不同的生命周期方法
- 好了,到这里Service的启动就说完了,接下来看看他的绑定
Service的绑定过程
- 还是一样,我们还是从我们平常写的bindService方法出发
- 点进去还是来到了ContextWrapper的bindService方法
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
return mBase.bindService(service, conn, flags);
}
- 可见,这里跟我们刚才看的一样,直接来到ContextImpl的bindService方法
public boolean bindService(Intent service, ServiceConnection conn,int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),Process.myUserHandle());
}
- ContextImpl的bindServiceCommon方法
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) {
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);
int res = ActivityManager.getService().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();
}
}
if (mPackageInfo != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
- 先通过这个方法将客户端的ServiceConnection对象转换成ServiceDispatcher.InnerConnection对象,之所以不能直接使用ServiceConnection对象,是因为服务的绑定可能是跨进程的,因此ServiceConnection对象必须借助于Binder才能让远程服务器回调自己的方法,而ServiceDispatcher的内部类InnerConnection刚好充当了Binder这个角色,那么ServiceDispatcher的作用是什么呢,其实ServiceDispatcher起着连接ServiceConnection和InnerConnection的作用,这个过程由LoadedApk的getServiceDispatcher方法来完成
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) {
if (DEBUG) Slog.d(TAG, "Returning existing dispatcher " + sd + " for conn " + c);
sd = map.get(c);
}
if (sd == null) {
sd = new ServiceDispatcher(c, context, handler, flags);
if (DEBUG) Slog.d(TAG, "Creating new dispatcher " + sd + " for conn " + c);
if (map == null) {
map = new ArrayMap<>();
mServices.put(context, map);
}
map.put(c, sd);
} else {
sd.validate(context, handler);
}
return sd.getIServiceConnection();
}
}
- 其中,mServices是一个ArrayMap,它存储了一个应用当前活动的ServiceConnection和ServiceDispatcher的映射关系,他的定义如下
private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
= new ArrayMap<>();
- 系统首先会查找是否存在相同的ServiceConnection,如果不存在就创建一个ServiceDispatcher对象
- 然后映射关系是,MService存的是Context和map的映射,也就是一个context对应一个Map
- 每个map管理自身的ServiceConnection和ServiceDispatcher,其中,前者是key后者是value
- 当到最后Service和客户端(也就是我们的组件),系统会通过InnerConnection来调用ServiceConnection的onServiceConnected方法,这个过程可能是跨进程的,当ServiceDispatcher创建好之后,getServiceDispatcher会返回其保存的InnerConnection对象
- 嗯,在中间,老套路,来到ActivityManagerService的bindService
public int bindService(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String callingPackage,
int userId) throws TransactionTooLargeException {
enforceNotIsolatedCaller("bindService");
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
if (callingPackage == null) {
throw new IllegalArgumentException("callingPackage cannot be null");
}
synchronized(this) {
return mServices.bindServiceLocked(caller, token, service,
resolvedType, connection, flags, callingPackage, userId);
}
}
- 还是通过mServices管理Service,来到ActiveService的 bindServiceLocked方法
- 这个方法太长,我删掉大部分
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String callingPackage, final int userId) throws TransactionTooLargeException {
............
if (!mAm.getPackageManagerInternalLocked()
.isPermissionsReviewRequired(
serviceRecord.packageName,
serviceRecord.userId)) {
try {
bringUpServiceLocked(serviceRecord,
serviceIntent.getFlags(),
callerFg, false, false)
} catch (RemoteException e) {
}
} else {
unbindServiceLocked(connection)
}
.............
if (s.app != null && b.intent.received) {
// Service is already running, so we can immediately
// publish the connection.
try {
c.conn.connected(s.name, b.intent.binder, false)
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " + s.shortName
+ " to connection " + c.conn.asBinder()
+ " (in " + c.binding.client.processName + ")", e)
}
// If this is the first app connected back to this binding,
// and the service had previously asked to be told when
// rebound, then do so.
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)
}
getServiceMapLocked(s.userId).ensureNotStartingBackgroundLocked(s)
} finally {
Binder.restoreCallingIdentity(origId)
}
return 1
}
- 可以看到,这里先将service启动,然后将Service的操作句柄返回给我们去操作
- 这里的bringUpServiceLocked方法就不再跟进了,我们在前面的时候已经看过了,这个方法内部主要做的是Service的创建,数据的初始化以及onCreate方法的调用
- 接下来看看,分析后面的注释可以知道,最终的bindService是通过requestServiceBindingLocked方法来做的,点开ActiveService的requestServiceBindingLocked方法
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
if (r.app == null || r.app.thread == null) {
return false;
}
if (DEBUG_SERVICE) Slog.d(TAG_SERVICE, "requestBind " + i + ": requested=" + i.requested
+ " rebind=" + rebind);
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) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r, e);
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
throw e;
} catch (RemoteException e) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r);
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
return false;
}
}
return true;
}
- 根据上个方法的调用发现,如果是第一次调用绑定的话,就可以成功绑定,不然就不会执行下面的绑定方法
- 执行的是ApplicationThread的scheduleBindService方法
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);
}
- 通过Handler来到ActivityThread线程
case BIND_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind")
handleBindService((BindServiceData)msg.obj)
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER)
break
- ActivityThread的handleBindService的方法
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()
try {
if (!data.rebind) {
IBinder binder = s.onBind(data.intent)
ActivityManager.getService().publishService(
data.token, data.intent, binder)
} else {
s.onRebind(data.intent)
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0)
}
ensureJitEnabled()
} 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)
}
}
}
}
- 我们可以发现,只有rebind参数为false的时候,onBinder方法才会被调用,然后ActivityManagerService会调用publishService方法来将我们从onBInd方法中得到的BInder对象送给我们
- 我们来看一下这个ActivityManagerService的publishService的具体逻辑吧
public void publishService(IBinder token, Intent intent, IBinder service) {
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);
}
}
- ActiveService的publishServiceLocked方法
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
ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni)
for (int i=0
ConnectionRecord c = clist.get(i)
if (!filter.equals(c.binding.intent.intent)) {
if (DEBUG_SERVICE) Slog.v(
TAG_SERVICE, "Not publishing to: " + c)
if (DEBUG_SERVICE) Slog.v(
TAG_SERVICE, "Bound intent: " + c.binding.intent.intent)
if (DEBUG_SERVICE) Slog.v(
TAG_SERVICE, "Published intent: " + intent)
continue
}
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c)
try {
c.conn.connected(r.name, service, false)
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " + r.name +
" to connection " + c.conn.asBinder() +
" (in " + c.binding.client.processName + ")", e)
}
}
}
}
serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false)
}
} finally {
Binder.restoreCallingIdentity(origId)
}
}
c.conn.connected(r.name, service, false)
- 而这个c.conn我们之前讨论过,他的具体实现类型时ServiceDispatcher.InnerConnection,这里的Service就是onBInd方法返回的BInder对象
- 这里的话看来是需要到ServiceDispatcher.InnerConnection这个方法里面看了,不过在android studio 里面全局搜索了下,发现没搜到,额,这怎么办
- 无奈,可能android studio看不到这部分的源码吧,那只能去找系统源码了,这里肯定来不及下载,通过网上搜索,发现了这个源码阅读的网站 http://androidxref.com/,这里大概说一下这个网站的使用方法
- 网站的首页是这样的
- 左边右边应该都是源码的版本,随便点一个,比如说我点7.0.0版本
- 左边是五个搜索框,右边是选择在源码的哪个目录下搜索
- 这里我列个表列举一下这些目录的含义
目录名 |
描述 |
abi |
应用程序二进制接口 |
art |
全新的Art运行环境 |
bionic |
系统c库 |
bootable |
启动引导相关代码 |
build |
存放系统编译规则及generic等基础开发包配置 |
cts |
Android兼容性测试套件标准 |
dalvik |
Dalvik虚拟机 |
developers |
开发者目录 |
development |
应用程序开发相关 |
device |
设备相关配置 |
docs |
参考文档目录 |
external |
开源模组相关文件 |
frameworks |
应用程序框架,Android系统核心部分,由java和C++编写 |
hardware |
主要是硬件抽象层的代码 |
libcore |
核心库的相关文件 |
libnativehelper |
动态库,实现JNI库的基础 |
ndk |
NDK相关代码,帮助开发人员在应用程序中嵌入C/C++代码 |
out |
编译完成之后的代码输出在此目录 |
pdk |
Plug Development Kit的缩写,本地开发套件 |
platform_testing |
平台测试 |
prebuilts |
X86和arm架构下预编译的一些资源 |
sdk |
SDK和模拟器 |
packages |
应用程序包 |
system |
底层文件系统库,应用和组件 |
toolchain |
工具链文件 |
tools |
工具文件 |
makefile |
全局MakeFile文件,用来定义编译规则 |
- 可以看到,我们目前的代码应该主要就在frameworks目录下了
- 接下来我们再看看左边的五个搜索框的含义
- Full Search: 进行全文搜索,会匹配所有的单词、字符串、标识符以及数字等,例如在frameworks 下通过 Full Search 搜索”mediacodec“
- Definition:搜索符号定义相关的代码,例如搜索 ondraw 函数的定义
- Symbol:搜索符号,例如可以搜索类中的成员变量等,比如通过 Symbol 搜索FEATURE_NO_TITLE
- File Path:搜索源码文件名中包含给定字符串的文件,例如想要搜索文件名包含mediacodec的源码文件,则可以在 File Path 中填入 mediacodec 进行搜索,
- 最后一个没用过
- 不只是上面的单个搜索
- 比如我们可以搜索mediacodec.cpp中的start函数
- 这里的这个网站的功能我就不细说了,毕竟我们的目的不是研究这个,接下来去搜索ServiceDispatcher.InnerConnection这个
- 这里我们直接点击右下边那个变量定义那里,就可以直接定位到这个类的相应位置了
- 最后找到的ServiceDispatcher.InnerConnection的定义如下
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) {
1391 if (mActivityThread != null) {
1392 mActivityThread.post(new RunConnection(name, service, 0));
1393 } else {
1394 doConnected(name, service);
1395 }
1396 }
- 这里的数字是从这个网站复制过来就是这个样子,这里自动忽略吧
-
- ServiceDispatcher的mActivityThread是一个Handler,其实他就是ActivityThread中的H,从ServiceDispatcher的创建过程来说,MActivityThread不会为空,所以RunConnection方法就会H的post方法运行在主线程中,这样一来,客户端ServiceConnection中的方法就是在主线程中被回调的,我们看一下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;
}
- 很明显,这个RunConnection的run方法也调用了ServiceDispatcher的doConnection方法
public void doConnected(ComponentName name, IBinder service, boolean dead) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;
synchronized (this) {
if (mForgotten) {
return;
}
old = mActiveConnections.get(name);
if (old != null && old.binder == service) {
return;
}
if (service != null) {
info = new ConnectionInfo();
info.binder = service;
info.deathMonitor = new DeathMonitor(name, service);
try {
service.linkToDeath(info.deathMonitor, 0);
mActiveConnections.put(name, info);
} catch (RemoteException e) {
mActiveConnections.remove(name);
return;
}
} else {
mActiveConnections.remove(name);
}
if (old != null) {
old.binder.unlinkToDeath(old.deathMonitor, 0);
}
}
if (old != null) {
mConnection.onServiceDisconnected(name);
}
if (dead) {
mConnection.onBindingDied(name);
}
if (service != null) {
mConnection.onServiceConnected(name, service);
}
}
- 由于ServiceDispatcher内部保存了客户端的ServiceConnection对象,所以他可以很方便的调用ServiceConnection对象的onServiceConnection方法
- 那么到这里,也就到了我们写的ServiceConnection类的onServiceConnection方法了
- 到这里,Service的绑定过程就完了