关于Activity的四大组件之一Service, 这里面有几样东西可以分析呢?
1. 关于Service的启动,根据不同的需求可以分为有两种:一种是通过调用StartService,另一种就是BindService。
第一个话题,怎么去使用,然后这两种方法分别是怎么启动的,也就是说启动流程是怎么样的。(代码,UML图)
有什么区别呢?
2. 关于这两种 不同的方式,Service处理完成事务之后 怎么销毁?
3. 关于Service的ANR会在什么时候产生呢?
4. Service是时候被加载进AMS的,也就是说我要去start一个Service的时候,系统是怎么知道有没有这个Service呢?
第一,关于Service的声明还有如何加载到AMS中。
1. 首先Service必须要在应用的AndroidManifest.xml中申明
...
...
1) 当我们安装一个apk的时候,PMS会去解析新装的apk的package的一系列的信息。具体的过程需要debug查看代码,我们这里先指关注PackageParser.parsePackage()
private Package parsePackage(
Resources res, XmlResourceParser parser, int flags, String[] outError)
throws XmlPullParserException, IOException {
... ...
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (tagName.equals("application")) {
if (foundApp) {
... ...
foundApp = true;
if (!parseApplication(pkg, res, parser, attrs, flags, outError)) {
return null;
}
} else if (tagName.equals("permission")) {
... ...
} else if (tagName.equals("permission-tree")) {
... ...
} else if (tagName.equals("uses-permission")) {
... ...
}
return pkg;
}
2) PackageParser.parseApplication()
在parse Manifest中的Application的标签时,如果我们在里面声明了Service就会通过 owner.services.add(s);把这个service添加到对应package的services数组中,然后PMS会去遍历所有的packages中的service,通过mServices.addService(s);把它加到PMS中的mServices的数组中。这样我们的Service便在PMS中有了记录。
在PMS中一个Package就对应一个应用程序,里面记录着apk相关的所有东西,包括package的名字,进程名,里面的Activity,service,receive等等。
private boolean parseApplication(Package owner, Resources res,
XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
throws XmlPullParserException, IOException {
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
if (tagName.equals("activity")) {
... ...
owner.activities.add(a);
} else if (tagName.equals("receiver")) {
... ...
owner.receivers.add(a);
} else if (tagName.equals("service")) {
Service s = parseService(owner, res, parser, attrs, flags, outError);
if (s == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
owner.services.add(s);
第二,通过StartService()去启动一个Service
1. ContextImpl.StartService(Intent service)
StartService会直接去调用startServiceAsUser,而startServiceAsUser则会通过ActivityManagerNative通过binder去调用AMS的startService()
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceAsUser(service, mUser);
}
@Override
public ComponentName startServiceAsUser(Intent service, UserHandle user) {
try {
service.setAllowFds(false);
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
......
return cn;
} catch (RemoteException e) {
return null;
}
}
这个函数中caller就是一个binder对象,
servcie就是传过来的Intent
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, int userId) {
synchronized(this) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
checkValidCaller(callingUid, userId);
final long origId = Binder.clearCallingIdentity();
ComponentName res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
}
1) 首先根据caller去查找出与之对应的ProcessRecord对象 callerApp.
2) retrieveServiceLocked(service, resolvedType, callingPid, callingUid, userId, true); //
3) bringUpServiceLocked(r, service.getFlags(), false) //
ComponentName startServiceLocked(IApplicationThread caller,
Intent service, String resolvedType,
int callingPid, int callingUid, int userId) {
if (caller != null) {
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
}
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType,
callingPid, callingUid, userId, true);
if (res == null) {
return null;
}
... ...
ServiceRecord r = res.record;
NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked(
callingUid, r.packageName, service, service.getFlags(), null);
if (unscheduleServiceRestartLocked(r)) {
if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: " + r);
}
r.startRequested = true;
r.callStart = false;
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
service, neededGrants));
r.lastActivity = SystemClock.uptimeMillis();
synchronized (r.stats.getBatteryStats()) {
r.stats.startRunningLocked();
}
String error = bringUpServiceLocked(r, service.getFlags(), false);
if (error != null) {
return new ComponentName("!!", error);
}
return r.name;
}
1)先在mServiceMap中去查找是否它所在的进程里面已经有这个ServiceRecord了,如果有就直接取出来付给r.
如果传递过来的service是指定类名的,那么service.getComponent()就不等于null,于是就通过mServiceMap.getServiceByName(service.getComponent(), userId); 去寻找.
通过IntentFilter到userId对应的进程里面去查找是否已经有了。
2)如果mServiceMap中还不存在就去new一个新的ServiceRecord
首先会去通过AppGlobals.getPackageManager().resolveService()(service, resolvedType, ActivityManagerService.STOCK_PM_FLAGS, userId) 到PMS里去查找是有符合Intent的已经在PMS加载过的Service的信息。这个函数会返回一个ResolveInfo。
如果找到了对应的Service,就会new ServiceRecord(mAm, ss, name, filter, sInfo, res);并且把它放到mServiceMap说明当前已经有这个Service了,最后把找到的这个ServiceRecord封装到new ServiceLookupResult(r, null)中作为一个结果返回。
private ServiceLookupResult retrieveServiceLocked(Intent service,
String resolvedType, int callingPid, int callingUid, int userId,
boolean createIfNeeded) {
ServiceRecord r = null;
if (service.getComponent() != null) {
r = mServiceMap.getServiceByName(service.getComponent(), userId);
}
if (r == null) {
Intent.FilterComparison filter = new Intent.FilterComparison(service);
r = mServiceMap.getServiceByIntent(filter, userId);
}
if (r == null) {
try {
ResolveInfo rInfo =
AppGlobals.getPackageManager().resolveService(
service, resolvedType,
ActivityManagerService.STOCK_PM_FLAGS, userId);
ServiceInfo sInfo =
rInfo != null ? rInfo.serviceInfo : null;
... ...
ComponentName name = new ComponentName(
sInfo.applicationInfo.packageName, sInfo.name);
if (userId > 0) {
if (mAm.isSingleton(sInfo.processName, sInfo.applicationInfo,
sInfo.name, sInfo.flags)) {
userId = 0;
}
sInfo = new ServiceInfo(sInfo);
sInfo.applicationInfo = mAm.getAppInfoForUser(sInfo.applicationInfo, userId);
}
r = mServiceMap.getServiceByName(name, userId);
if (r == null && createIfNeeded) {
Intent.FilterComparison filter = new Intent.FilterComparison(
service.cloneFilter());
ServiceRestarter res = new ServiceRestarter();
BatteryStatsImpl.Uid.Pkg.Serv ss = null;
BatteryStatsImpl stats = mAm.mBatteryStatsService.getActiveStatistics();
synchronized (stats) {
ss = stats.getServiceStatsLocked(
sInfo.applicationInfo.uid, sInfo.packageName,
sInfo.name);
}
r = new ServiceRecord(mAm, ss, name, filter, sInfo, res);
res.setService(r);
mServiceMap.putServiceByName(name, UserHandle.getUserId(r.appInfo.uid), r);
mServiceMap.putServiceByIntent(filter, UserHandle.getUserId(r.appInfo.uid), r);
// Make sure this component isn't in the pending list.
int N = mPendingServices.size();
for (int i=0; i
3.3 ActiveServices.bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean whileRestarting)
获取ServiceRecord所在的application是否已经启动,如果启动了就直接调用realStartServiceLocked(r, app); 如果没有启动就先去mAm.startProcessLocked启动对应的process,然后把需要start的service添加到mPendingServices中,等到进程起来之后会调用attachApplicationLocked去启动相应的service,当然还是调用realStartServiceLocked(sr, proc);
private final String bringUpServiceLocked(ServiceRecord r,
int intentFlags, boolean whileRestarting) {
... ...
if (DEBUG_SERVICE) Slog.v(TAG, "Bringing up " + r + " " + r.intent);
... ...
// Make sure that the user who owns this service is started. If not,
// we don't want to allow it to run.
if (mAm.mStartedUsers.get(r.userId) == null) {
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, true);
return msg;
}
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
final String procName = r.processName;
ProcessRecord app;
if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid);
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);
realStartServiceLocked(r, app);
return null;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
} else {
// If this service runs in an isolated process, then each time
// we call startProcessLocked() we will get a new isolated
// process, starting another process if we are currently waiting
// for a previous process to come up. To deal with this, we store
// in the service any current isolated process it is running in or
// waiting to have come up.
app = r.isolatedProc;
}
// Not running -- get it started, and enqueue this service record
// to be executed when the app comes up.
if (app == null) {
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
"service", r.name, false, isolated)) == 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, true);
return msg;
}
if (isolated) {
r.isolatedProc = app;
}
}
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
return null;
}
1) app.thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo)); 通过app.thread.scheduleCreateService去调用ActivityThread的scheduleCreateService。在ActivityThread的中通过handle去发送和处理“CREATE_SERVICE”的消息。调用handleCreateService
2) requestServiceBindingLock() //这个函数在BindService的时候才会起作用
3) sendServiceArgsLocked(r, true); //处理传递给Service的Intent带来的参数
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app) throws RemoteException {
r.app = app;
r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
app.services.add(r);
bumpServiceExecutingLocked(r, "create");
mAm.updateLruProcessLocked(app, true);
boolean created = false;
try {
mAm.mStringBuilder.setLength(0);
r.intent.getIntent().toShortString(mAm.mStringBuilder, true, false, true, false);
EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE,
r.userId, System.identityHashCode(r), r.shortName,
mAm.mStringBuilder.toString(), r.app.pid);
synchronized (r.stats.getBatteryStats()) {
r.stats.startLaunchedLocked();
}
mAm.ensurePackageDexOpt(r.serviceInfo.packageName);
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo));
r.postNotification();
created = true;
} finally {
... ...
}
requestServiceBindingsLocked(r);
// If the service is in the started state, and there are no
// pending arguments, then fake up one so its onStartCommand() will
// be called.
if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
null, null));
}
sendServiceArgsLocked(r, true);
}
在Client端,实例化对应的Service并通过attach,把相关的属性给它。通过mServices.put(data.token, service);把自己加到当前进程的mServices中。
此时就会调用service.onCreate(); 并且通过mServices.put(data.token, service); 把ActiveServices里面的ServiceRecord传过来的Token与本地Service对象放到mServices的Map中。
最后会通过ActivityManagerNative.getDefault().serviceDoneExecuting(token, 0, 0, 0);去通知ActiveServices。
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.
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
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);
ContextImpl context = new ContextImpl();
context.init(packageInfo, null, this);
Application app = packageInfo.makeApplication(false, mInstrumentation);
context.setOuterContext(service);
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
service.onCreate();
mServices.put(data.token, service);
try {
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, 0, 0, 0);
} catch (RemoteException e) {
// nothing to do.
}
} catch (Exception e) {
... ...
}
}
3.3.1.3 ActiveServices.sendServiceArgsLocked(ServiceRecord r,boolean oomAdjusted)
在startServiceLocked函数中bringupService之前,已经调用了r.pendingStarts.add去添加了一个pendingStarts,所以这里的pendingStarts.size()是大于0的。
1. 通过r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent); 发送Message给Client端处理。
private final void sendServiceArgsLocked(ServiceRecord r,
boolean oomAdjusted) {
final int N = r.pendingStarts.size();
if (N == 0) {
return;
}
while (r.pendingStarts.size() > 0) {
try {
ServiceRecord.StartItem si = r.pendingStarts.remove(0);
si.deliveredTime = SystemClock.uptimeMillis();
r.deliveredStarts.add(si);
si.deliveryCount++;
if (si.neededGrants != null) {
mAm.grantUriPermissionUncheckedFromIntentLocked(si.neededGrants,
si.getUriPermissionsLocked());
}
int flags = 0;
if (si.deliveryCount > 1) {
flags |= Service.START_FLAG_RETRY;
}
if (si.doneExecutingCount > 0) {
flags |= Service.START_FLAG_REDELIVERY;
}
r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
} catch (RemoteException e) {
....
}
}
1. 调用s.onStartCommand去做相关的操作,onStartCommand会返回一个integer. The integer is a value that describes how the system should continue the service in the event that the system kills it.
2. 告诉AMS已经完成了ActivityManagerNative.getDefault().serviceDoneExecuting(data.token, 1, data.startId, res); 在ActiveServices.serviceDoneExecutingLocked中会对onStartCommand返回的值作出对应的处理。
private void handleServiceArgs(ServiceArgsData data) {
Service s = mServices.get(data.token);
if (s != null) {
try {
if (data.args != null) {
data.args.setExtrasClassLoader(s.getClassLoader());
}
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 {
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, 1, data.startId, res);
} catch (RemoteException e) {
// nothing to do.
}
ensureJitEnabled();
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
"Unable to start service " + s
+ " with " + data.args + ": " + e.toString(), e);
}
}
}
}
ActiveServices.serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res)
void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) {
boolean inStopping = mStoppingServices.contains(r);
if (r != null) {
if (type == 1) {
// This is a call from a service start... take care of
// book-keeping.
r.callStart = true;
switch (res) {
case Service.START_STICKY_COMPATIBILITY:
case Service.START_STICKY: {
// We are done with the associated start arguments.
r.findDeliveredStart(startId, true);
// Don't stop if killed.
r.stopIfKilled = false;
break;
}
case Service.START_NOT_STICKY: {
// We are done with the associated start arguments.
r.findDeliveredStart(startId, true);
if (r.getLastStartId() == startId) {
// There is no more work, and this service
// doesn't want to hang around if killed.
r.stopIfKilled = true;
}
break;
}
case Service.START_REDELIVER_INTENT: {
// We'll keep this item until they explicitly
// call stop for it, but keep track of the fact
// that it was delivered.
ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
if (si != null) {
si.deliveryCount = 0;
si.doneExecutingCount++;
// Don't stop if killed.
r.stopIfKilled = true;
}
break;
}
case Service.START_TASK_REMOVED_COMPLETE: {
// Special processing for onTaskRemoved(). Don't
// impact normal onStartCommand() processing.
r.findDeliveredStart(startId, true);
break;
}
default:
throw new IllegalArgumentException(
"Unknown service start result: " + res);
}
if (res == Service.START_STICKY_COMPATIBILITY) {
r.callStart = false;
}
}
final long origId = Binder.clearCallingIdentity();
serviceDoneExecutingLocked(r, inStopping);
Binder.restoreCallingIdentity(origId);
} else {
Slog.w(TAG, "Done executing unknown service from pid "
+ Binder.getCallingPid());
}
}
serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping)
private void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
if (DEBUG_SERVICE) Slog.v(TAG, "<<< DONE EXECUTING " + r
+ ": nesting=" + r.executeNesting
+ ", inStopping=" + inStopping + ", app=" + r.app);
else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG, "<<< DONE EXECUTING " + r.shortName);
r.executeNesting--;
if (r.executeNesting <= 0 && r.app != null) {
if (DEBUG_SERVICE) Slog.v(TAG,
"Nesting at 0 of " + r.shortName);
r.app.executingServices.remove(r);
if (r.app.executingServices.size() == 0) {
if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG,
"No more executingServices of " + r.shortName);
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
}
if (inStopping) {
if (DEBUG_SERVICE) Slog.v(TAG,
"doneExecuting remove stopping " + r);
mStoppingServices.remove(r);
r.bindings.clear();
}
mAm.updateOomAdjLocked(r.app);
}
}
到此StartService()启动结束,startService会返回一个ComponentName,而这个实际上就是ServiceRecord.name。
4. stopService
如果一个service通过start开始,想要destroy它只有两个方法,一个是通过调用自己的stopSelf(), 另一个就是通过ContextImpl.stopService(Intent service).
而这两个方法最终会走到ActiveServices的stopServiceTokenLocked 和 stopServiceLocked, 这两个方法都是去查找在ActivieServices中对应的ServiceRecord,找到之后最终调用bringDownServiceLocked去destroy相关的工作。
1. r.app.thread.scheduleStopService(r); 通过Binder调用Client端的销毁工作。
private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
... ...
if (DEBUG_SERVICE) Slog.v(TAG, "Bringing down " + r + " " + r.intent);
EventLog.writeEvent(EventLogTags.AM_DESTROY_SERVICE,
r.userId, System.identityHashCode(r), r.shortName,
(r.app != null) ? r.app.pid : -1);
mServiceMap.removeServiceByName(r.name, r.userId);
mServiceMap.removeServiceByIntent(r.intent, r.userId);
r.totalRestartCount = 0;
unscheduleServiceRestartLocked(r);
// Also make sure it is not on the pending list.
int N = mPendingServices.size();
for (int i=0; i
调用s.onDestroy()
private void handleStopService(IBinder token) {
Service s = mServices.remove(token);
if (s != null) {
try {
if (localLOGV) Slog.v(TAG, "Destroying service " + s);
s.onDestroy();
Context context = s.getBaseContext();
if (context instanceof ContextImpl) {
final String who = s.getClassName();
((ContextImpl) context).scheduleFinalCleanup(who, "Service");
}
try {
ActivityManagerNative.getDefault().serviceDoneExecuting(
token, 0, 0, 0);
} catch (RemoteException e) {
// nothing to do.
}
} catch (Exception e) {
... ...
}
}
//Slog.i(TAG, "Running services: " + mServices);
}