本文旨在记录一下自己学习 Android Service 源码时的笔记。
startService
首先看一下大致的流程图
上图中,AMS代表ActivityManagerService, AS代表ActiveServices。 这里假设Service的启动者(ProcessA)和 Service(ProcessB)不在同一个进程, 当然 startService 方式更多情况下还是用在自己进程内部。 这里只列出一些我认为比较主要的函数,忽略了异常情况下的处理, 例如延迟start, 找不到对应进程等。 图中颜色加深的几个关键方法:
1) AS.retrieveServiceLocked: 从PackageManager查询要启动的Service信息
2)AMS.checkAllowBackgroundLocked: 检查是否允许从后台启动Service
3)AS.bringUpServiceLocked: 对Service和Process的情况进行判度并处理,下面的那几个判断流程都是在该函数里
4)AMS.startProcessLocked: 启动Service对应的进程
5)AS.realStartServiceLocked: 使用IApplicationThread接口向Service进程发送create消息
6)AS.sendServiceArgsLocked: 使用IApplicationThread接口向Service进程发送start消息
7)Service.onStartCommand & Service.onCreate: Service callback
下面开始代码分析。
Context.startService
--> ContextImpl.startService
--> ContextImpl.startServiceCommon
前面经过Context和它的Wrapper模式下的调用栈, 进入ContextImpl.startServiceCommon
private ComponentName startServiceCommon(Intent service, UserHandle user) {
try {
//判断Intent中是否符合要求, Android L以上版本需要显示调用Service
validateServiceIntent(service);
//跨进程安全检查
service.prepareToLeaveProcess(this);
//调用AMS接口
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), getOpPackageName(), user.getIdentifier());
......
}
return cn;
} catch (RemoteException e) {
......
}
}
startServiceCommon会先做一些检查,其中 Intent.prepareToLeaveProcess对跨进程做安全性检查,例如在N以后的版本,在StrictMode下,不能使用scheme为"file://"的URI进行数据传输,必须使用FileProvider代替
public void prepareToLeaveProcess(boolean leavingPackage) {
......
switch (mAction) {
......
default:
// N以上版本对scheme为"file://" 的URI需要用FileProvider代替
mData.checkFileUriExposed("Intent.getData()");
}
}
然后调用服务端 AMS.startService,在此我们省去 Binder 调用流程,直接进入ActivityManagerService
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, String callingPackage, int userId)
throws TransactionTooLargeException {
......
synchronized(this) {
......
ComponentName res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid, callingPackage, userId);
......
return res;
}
}
AMS.startService先对参数检查, 然后调用ActiveServices.startServiceLocked
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, String callingPackage, final int userId)
throws TransactionTooLargeException {
......
// 1. 查询待启动Service的信息
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false);
......
// 2. 检查是否可以在后台启动
if (!r.startRequested) {
try {
final int allowed = mAm.checkAllowBackgroundLocked(
r.appInfo.uid, r.packageName, callingPid, true);
if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
......
return null;
} finally {
......
}
}
}
......
r.startRequested = true;
......
//startService可以多次向Service传递信息,每次的信息都是一个StartItem,对应着一个StartId
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
service, neededGrants));
// 3. 下面的部分用于判断是否需要延迟启动Service
final ServiceMap smap = getServiceMap(r.userId);
// addToStarting值决定是否将待启动的Service加入后台启动队列ServiceMap.mStartingBackground
// 这里只是判断, 它将被传入最后的startServiceInnerLocked, 在那里使用
// 另外一个队列ServiceMap.mDelayedStartList则是延迟启动队列
boolean addToStarting = false;
if (!callerFg && r.app == null && mAm.mUserController.hasStartedUserState(r.userId)) {
//通过AMS查询Service对应的进程信息
ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
//若Service对应的进程未启动,或优先级过低,则需要将Service加入后台启动队列
if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) {
......
//若当前用户启动的后台服务数量已超上限,则延迟启动服务
if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
smap.mDelayedStartList.add(r);
r.delayed = true;
return r.name;
}
addToStarting = true;
} else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
......
addToStarting = true;
}
......
return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}
startServiceLocked 做了一些前期准备:
1. 查询待启动Service的信息
2. 检查是否可以在后台启动
3. 检查是否需要延迟启动Service
这里第1步涉及到AMS对已启动Service信息的存储数据结构,我们在后面 AMS对Service的存储 里一起分析.
第2步, O 上有一些改动, 具体可以看后面 Background Service in Android O 部分.
第3步将判断待启动的Service是否需要在 Background start, 或者是 Delay start, 总体规则就是如果进程未启动或者优先级低,则 Background start, 如果连 Background start 队列都已满,则加入 Delay 队列。 这一部分的看的不是很明白,特别是两个队列的关系, 我本以为是两个优先级的队列,但是看后面的处理函数ServiceMap.rescheduleDelayedStarts,好像不是, 以后有机会再看看。
检查完成之后进入startServiceInnerLocked
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
......
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
......
// 这里会根据前面传进来的addToStarting值处理延迟Service
if (r.startRequested && addToStarting) {
boolean first = smap.mStartingBackground.size() == 0;
smap.mStartingBackground.add(r);
r.startingBgTimeout = SystemClock.uptimeMillis() + BG_START_TIMEOUT;
if (first) {
smap.rescheduleDelayedStarts();
}
} else if (callerFg) {
smap.ensureNotStartingBackground(r);
}
return r.name;
}
真正的工作在 bringUpServiceLocked 里
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
......
// Case 1. 如果Service已经启动过,直接发送start
if (r.app != null && r.app.thread != null) {
sendServiceArgsLocked(r, execInFg, false);
return null;
}
......
// Case 2. Service没启动过
// 真正启动之前再做一些检查并处理, 例如service是否还有delay标志,service所处的进程时否结束了
......
final String procName = r.processName;
ProcessRecord app;
if (!isolated) {
// 查询Service对应的进程信息
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (app != null && app.thread != null) {
try {
......
// Case 2.1 查询到进程, 则直接start Service
realStartServiceLocked(r, app, execInFg);
return null;
}
......
}
} else {
......
}
// Case 2.2 查询不到进程,则需要先start Process
if (app == null && !permissionsReviewRequired) {
//真正启动进程
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
"service", r.name, false, isolated, false)) == null) {
......
// Case 2.2.1 进程启动失败, stop service
bringDownServiceLocked(r);
return msg;
}
......
}
// Case 2.2.2 进程启动成功,把Service添加到mPendingServices中
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
return null;
}
bringUpServiceLocked 分几种情况处理:
1 如果Service已经启动过,调sendServiceArgsLocked发送start请求
2 如果Service还未启动过, 查询Serviced对应进程,看看进程是否已经启动
2.1 进程已启动, 调用realStartServiceLocked,创建Service
2.2 进程未启动, 调用AMS.startProcessLocked启动进程
2.2.1 进程启动失败, 调用bringDownServiceLocked结束Service
2.2.2 进程启动成功, 将Service信息保存到mPendingServices,等待后面进程回调对其进行处理
这里我们简单对2.2.2的情况说明一些,进程启动成功后会调用AMS.attachApplicationLocked,在这里将mPendingServices里属于该进程的Service启动,调用的也是realStartServiceLocked
boolean attachApplicationLocked(ProcessRecord proc, String processName)
throws RemoteException {
......
for (int i=0; i
也就是说2.1和2.2.2最后都是进入realStartServiceLocked
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
......
try {
......
// 发送create请求
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
created = true;
} catch (DeadObjectException e) {
......
} finally {
......
}
......
// 发送bind请求,对于startService,bind队列并没有增加
// 所以在这种情况下requestServiceBindingsLocked相当于空函数
// 后面分析bindService的时候我们再来看这个函数
requestServiceBindingsLocked(r, execInFg);
......
// 构造start参数StartItem
if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
null, null));
}
// 发送start请求,同前面bringUpServiceLocked的Case 1
sendServiceArgsLocked(r, execInFg, true);
......
}
realStartServiceLocked是通知客户端创建和启动Service的地方
1 调用ApplicationThead.scheduleCreateService通知客户端创建服务
2 调用requestServiceBindingsLocked发送bind请求,使用于bindService情况
3 调用sendServiceArgsLocked发送start请求,使用于startService情况
这几个步骤最后其实都差不多,都是AMS通过ApplicationThread对应的接口通知ActivityThread,以第一种情况为例,省去Binder调用流程,大致如下:
ApplicationThread.scheduleCreateService
--> ActivityThread.H.handleMessage(CREATE_SERVICE)
--> ActivityThread.handleCreateService
private void handleCreateService(CreateServiceData data) {
......
Service service = null;
try {
// 使用反射创建 Service 实例
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
......
}
try {
......
// 调用onCreate回调,然后保存起来
service.onCreate();
mServices.put(data.token, service);
//通知AMS创建完成
try {
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
}
......
} catch (Exception e) {
......
}
}
ActivityThread.handleCreateService创建Service实例,调用onCreate,并保存Service.
sendServiceArgsLocked流程差不多,最后由ActivityThread.handleServiceArgs处理,调用onStartCommon
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
boolean oomAdjusted) throws TransactionTooLargeException {
......
while (r.pendingStarts.size() > 0) {
ServiceRecord.StartItem si = null;
try {
......
si = r.pendingStarts.remove(0);
// 记录start次数
si.deliveryCount++;
int flags = 0;
// 我们可以利用onStartCommand的flag参数来判断是否是第一次start
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);
}
......
}
}
private void handleServiceArgs(ServiceArgsData data) {
// 前面onCreate的时候已经保存了Service在mServices里,现在可以取出
Service s = mServices.get(data.token);
if (s != null) {
try {
......
if (!data.taskRemoved) {
res = s.onStartCommand(data.args, data.flags, data.startId);
} else {
......
}
......
} catch (Exception e) {
......
}
}
}
至此Context.startService完成
bindService
bindService流程同startService差不多,主要多了两个点, 一个是AMS除了要保存Service信息,还要保存caller app和ServiceConnection信息(用于交互), 这个由ServiceRecord.retrieveAppBindingLocked负责; 另外就是bind完成要使用IActivityManager.publishService接口通知AMS,从而让ServiceConnection.onServiceConnected执行
下面开始看代码
Context.bindService
--> ContextImpl.bindServiceCommon
--> AMS.bindService
--> AS.bindServiceLocked
前面的跟startService的差不多, 进入AS.bindServiceLocked
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String callingPackage, final int userId) throws TransactionTooLargeException {
......
// 从ServiceMap查找ServiceRecord
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(),
Binder.getCallingUid(), userId, true, callerFg, isBindExternal);
ServiceRecord s = res.record;
......
try {
......
// 从ServiceRecord查找Client应用信息
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
// 构造ServiceConnection信息
ConnectionRecord c = new ConnectionRecord(b, activity,
connection, flags, clientLabel, clientIntent);
......
// 将ServiceConnection保存
IBinder binder = connection.asBinder();
ArrayList clist = s.connections.get(binder);
if (clist == null) {
clist = new ArrayList();
s.connections.put(binder, clist);
}
clist.add(c);
b.connections.add(c);
clist = mServiceConnections.get(binder);
if (clist == null) {
clist = new ArrayList();
mServiceConnections.put(binder, clist);
}
clist.add(c);
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
......
// bringUpService会通知客户端onbind
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
permissionsReviewRequired) != null) {
return 0;
}
......
}
......
} finally {
......
}
}
bindServiceLocked流程比较简单,先查找或者构造调用者app和ServiceConnection信息,存储于ServiceRecord, 然后调用bringUpServiceLocked.
bringUpServiceLocked包含了startService和bindService的逻辑,startService的部分前面已经分析过, 这里看bindSerivce有关的流程:
bringUpServiceLocked
--> realStartServiceLocked
--> requestServiceBindingsLocked
// 对ServiceRecord.bindings里的元素依次调用requestServiceBindingLocked
private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
throws TransactionTooLargeException {
for (int i=r.bindings.size()-1; i>=0; i--) {
IntentBindRecord ibr = r.bindings.valueAt(i);
if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
break;
}
}
}
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
......
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
......
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.repProcState);
......
} catch (TransactionTooLargeException e) {
......
} catch (RemoteException e) {
......
}
}
return true;
}
requestServiceBindingsLocked则通过Binder最后进入ActivityThread.handleBindService:
ApplicationThread.scheduleBindService
--> ActivityThread.H.handleMessage(BIND_SERVICE)
--> ActivityThread.handleBindService
private void handleBindService(BindServiceData data) {
// 前面Service onCreate的时候已被保存在mServices
Service s = mServices.get(data.token);
......
if (s != null) {
......
try {
if (!data.rebind) {
// 执行onBind回调
IBinder binder = s.onBind(data.intent);
// 通知AMS bind完成
ActivityManagerNative.getDefault().publishService(
data.token, data.intent, binder);
} else {
......
}
.
} catch (RemoteException ex) {
......
}
} catch (Exception e) {
......
}
}
handleBindService执行Service.onBind,并将结果通过AMS.publishService发送给AMS
AMS.publishService
--> AS.publishServiceLocked
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
......
try {
if (r != null) {
Intent.FilterComparison filter = new Intent.FilterComparison(intent);
IntentBindRecord b = r.bindings.get(filter);
if (b != null && !b.received) {
// 记录Service和状态
b.binder = service;
b.requested = true;
b.received = true;
// 找出所有符合的ServiceConnection执行onServiceConnected
for (int conni=r.connections.size()-1; conni>=0; conni--) {
ArrayList clist = r.connections.valueAt(conni);
for (int i=0; i
publishService通知ServiceConnection执行onServiceConnected,至此bindService结束
AMS对Service的存储(stopService/unbindService)
AMS里把所有启动的Service存放在ActiveServices.mServiceMap, 这是一个SparseArray,可以看成一个Map,其key是调用者的userId,也就是说AMS将系统中所有启动过的Service按调用者的userId分组. 为了方便分析,这里简单的将userId等同于appId,即简单的等同于一个应用.
而ServiceMap本身是存储了两个Map mServicesByName
和 mServicesByIntent
, 分别代表显式和隐式调用的Service信息
class ServiceMap extends Handler {
final ArrayMap mServicesByName = new ArrayMap<>();
final ArrayMap mServicesByIntent = new ArrayMap<>();
......
}
这里我们只取隐式的mServicesByIntent
来分析,它的key是Intent.FilterComparison,可以把它看成是一个override了equals方法的Intent,我们选取最为常见的action作为Intent的代表,当然两个Intent是否相等还要由 Data, Category 等比较决定,但是不影响我们对这里数据结构的分析. 所以最终我们发现,其实AMS用组合(caller appId, action)作为key来存储已启动的Service.
我们假设 Music 应用有一个 PlaybackService, 注册的action有两个.
现在在Settings和Video两个应用分别startService,其中Settings有两处,用了两个不同的action启动
// In Settings process
startService(new Intent("com.haha.music.action.PLAYBACK1"));
...
startService(new Intent("com.haha.music.action.PLAYBACK2"));
// In Video process
startService(new Intent("com.haha.music.action.PLAYBACK1"));
最后内存里的情况如下:
了解了ServiceMap的结构之后,我们看startService/stopService时对Service的查找, 就是retrieveServiceLocked函数
private ServiceLookupResult retrieveServiceLocked(Intent service,
String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal) {
ServiceRecord r = null;
// 得到当前用户的userId
userId = mAm.mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
ActivityManagerService.ALLOW_NON_FULL_IN_PROFILE, "service", null);
// 从ServiceMap中查找
ServiceMap smap = getServiceMap(userId);
final ComponentName comp = service.getComponent();
if (comp != null) {
r = smap.mServicesByName.get(comp);
}
if (r == null && !isBindExternal) {
Intent.FilterComparison filter = new Intent.FilterComparison(service);
r = smap.mServicesByIntent.get(filter);
}
// 如果Map里找不到则要开始构造这个ServiceRecord并保存起来
if (r == null) {
try {
// PKMS根据参数得到对应Pkg中Serivce的ResolveInfo
ResolveInfo rInfo = AppGlobals.getPackageManager().resolveService(service,
resolvedType, ActivityManagerService.STOCK_PM_FLAGS
| PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId);
ServiceInfo sInfo = rInfo != null ? rInfo.serviceInfo : null;
ComponentName name = new ComponentName(
sInfo.applicationInfo.packageName, sInfo.name);
r = smap.mServicesByName.get(name);
if (r == null && createIfNeeded) {
......
r = new ServiceRecord(mAm, ss, name, filter, sInfo, callingFromFg, res);
smap.mServicesByName.put(name, r);
smap.mServicesByIntent.put(filter, r);
......
}
} catch (RemoteException ex) {
......
}
}
if (r != null) {
return new ServiceLookupResult(r, null);
}
return null;
}
AS.retrieveServiceLocked其实就是从mServiceMap里查找对应的ServiceRecord,如果找不到就构造一个. 到此,这里的数据对startService/stopService已经够用.
但是对bindService/unbindService, AMS还得记录Client和ServiceConnection,这个由ServiceRecord.bindings
和ServiceRecord.connections
来负责. 通过简化, 我们可以认为ServiceRecord.bindings用来存储调用者应用信息, key为action, value为caller app信息(AppBinderRecord)队列. ServiceRecord.connections存储ServiceConnection, key为ServiceConnection在AMS的代表(binder). 这部分逻辑主要在retrieveAppBindingLocked和bindServiceLocked
public AppBindRecord retrieveAppBindingLocked(Intent intent,
ProcessRecord app) {
Intent.FilterComparison filter = new Intent.FilterComparison(intent);
IntentBindRecord i = bindings.get(filter);
if (i == null) {
i = new IntentBindRecord(this, filter);
bindings.put(filter, i);
}
AppBindRecord a = i.apps.get(app);
if (a != null) {
return a;
}
a = new AppBindRecord(this, i, app);
i.apps.put(app, a);
return a;
}
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String callingPackage, final int userId) throws TransactionTooLargeException {
......
try {
......
// 从ServiceRecord查找Client应用信息
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
// 构造ServiceConnection信息
ConnectionRecord c = new ConnectionRecord(b, activity,
connection, flags, clientLabel, clientIntent);
......
// 将ServiceConnection保存在ServiceRecord.connections
IBinder binder = connection.asBinder();
ArrayList clist = s.connections.get(binder);
if (clist == null) {
clist = new ArrayList();
s.connections.put(binder, clist);
}
clist.add(c);
b.connections.add(c);
// 除了每个ServiceRecord保存着自己的connection队列
// ActiveServices里还有一个所有connection的队列
clist = mServiceConnections.get(binder);
if (clist == null) {
clist = new ArrayList();
mServiceConnections.put(binder, clist);
}
clist.add(c);
......
} finally {
......
}
}
上面是属于Service/ServiceConnection/Caller app的创建和保存,位于startService/bindService.
下面我们看看它们的删除, 这个位于stopService和unbindService
private void stopServiceLocked(ServiceRecord service) {
......
// 设置 startRequested 标志
service.startRequested = false;
......
// 注意这里的最后两个参数值,都是false
bringDownServiceIfNeededLocked(service, false, false);
}
// unbindService调用流程:
// AMS.unbindService --> AS.unbindServiceLocked --> AS.removeConnectionLocked
void removeConnectionLocked(
ConnectionRecord c, ProcessRecord skipApp, ActivityRecord skipAct) {
......
AppBindRecord b = c.binding;
......
// remove ServiceRecord.connectins里的记录
ArrayList clist = s.connections.get(binder);
if (clist != null) {
clist.remove(c);
if (clist.size() == 0) {
s.connections.remove(binder);
}
}
......
// remove ActiveServices.mServiceConnections里的记录
clist = mServiceConnections.get(binder);
if (clist != null) {
clist.remove(c);
if (clist.size() == 0) {
mServiceConnections.remove(binder);
}
}
if (!c.serviceDead) {
......
// 调用onUnbind
if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
&& b.intent.hasBound) {
try {
......
s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
} catch (Exception e) {
......
}
}
if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
boolean hasAutoCreate = s.hasAutoCreateConnections();
......
// 最后调用bringDownServiceIfNeededLocked, 注意这里最后两个参数
// 第一个为true, 第二个为s.hasAutoCreateConnections()
bringDownServiceIfNeededLocked(s, true, hasAutoCreate);
}
}
}
stopService相对比较简单,就是设置一下startRequested为false, 然后调用bringDownServiceIfNeededLocked, 注意这里传入的最后两个参数值,都是false
unbindService先找到要unbind的ServiceConnection, 调用removeConnectionLocked对其内部各种数据清理(主要是ServiceRecord.bindings, connections, ActiveServices.mServiceConnections), 然后使用ApplicationThread.scheduleUnbindService通知客户端onUnbind, 最后也是调用bringDownServiceIfNeededLocked, 注意这里传入的最后两个参数值,但是其传入的是true和s.hasAutoCreateConnections()
可以看到stop/unbind最终都会调用bringDownServiceIfNeededLocked
private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn,
boolean hasConn) {
if (isServiceNeeded(r, knowConn, hasConn)) {
return;
}
......
bringDownServiceLocked(r);
}
如果isServiceNeeded返回false就会执行bringDownServiceLocked,先看一下这个函数
private final void bringDownServiceLocked(ServiceRecord r) {
......
final ServiceMap smap = getServiceMap(r.userId);
smap.mServicesByName.remove(r.name);
smap.mServicesByIntent.remove(r.intent);
......
if (r.app != null) {
......
if (r.app.thread != null) {
......
try {
......
r.app.thread.scheduleStopService(r);
} catch (Exception e) {
......
}
} else {
......
}
} else {
......
}
......
}
bringDownServiceLocked其实就是清理ActiveServices.mServiceMap里的数据,并且通知Service.onDestory
回过头看isServiceNeeded
private final boolean isServiceNeeded(ServiceRecord r, boolean knowConn, boolean hasConn) {
// Are we still explicitly being asked to run?
if (r.startRequested) {
return true;
}
// Is someone still bound to us keepign us running?
if (!knowConn) {
hasConn = r.hasAutoCreateConnections();
}
if (hasConn) {
return true;
}
return false;
}
//ServiceRecord.java
public boolean hasAutoCreateConnections() {
for (int conni=connections.size()-1; conni>=0; conni--) {
// unbindService --> removeConnectionLocked的时候会remove对应的connection
// 所以剩下的还在connections中的就是还没unbind的
ArrayList cr = connections.valueAt(conni);
for (int i=0; i
结合上面stopService和unbindService调用时传给它的参数值, 我们知道isServiceNeeded的逻辑等同于r.startRequested && r.hasAutoCreateConnections()
r.startRequested在startService时置为true, stopService置为false, r.hasAutoCreateConnections()则在没有client bindService的时候返回false, 所以就是说bringDownServiceLocked,即Service.onDestory只有在调用过stopService(或者没调用过startService)和所有connection都被unbind之后才会被执行
Background Service in Android O
现在Android对 Background Task(Service/Broadcast等)的限制已经越来越严格, 对Service而言,当进程处于后台时, Android O 已经不允许 startService, 上面是N的代码,我们简单看下 O preview的流程
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, String callingPackage, final int userId)
throws TransactionTooLargeException {
......
if (!r.startRequested && !fgRequired) {
final int allowed = mAm.getAppStartModeLocked(r.appInfo.uid, r.packageName,
r.appInfo.targetSdkVersion, callingPid, false, false);
}
......
}
startServiceLocked 关于对于Service是否允许后台start的判断在O上有了变化,这里使用的是AMS.getAppStartModeLocked
int getAppStartModeLocked(int uid, String packageName, int packageTargetSdk,
int callingPid, boolean alwaysRestrict, boolean disabledOnly) {
......
if (uidRec == null || alwaysRestrict || uidRec.idle) {
......
if (ephemeral) {
......
} else {
......
//alwaysRestrict为false,所以调用appServicesRestrictedInBackgroundLocked
final int startMode = (alwaysRestrict)
? appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk)
: appServicesRestrictedInBackgroundLocked(uid, packageName,
packageTargetSdk);
//当Service的startMode不是Normal
if (startMode == ActivityManager.APP_START_MODE_DELAYED) {
......
if (proc != null &&
//并且进程不是处于后台
!ActivityManager.isProcStateBackground(proc.curProcState)) {
//那么就把startMode改为Normal
return ActivityManager.APP_START_MODE_NORMAL;
}
}
//否则返回原模式
return startMode;
}
}
......
}
这里fgRequired参数在Context.startService时为false, 而Context.startForegroundService为true, 所以这里调用的是appRestrictedInBackgroundLocked
// 处于 Persistent/background whitelist/device idle white list 这三种情况下的 app 不受 background 限制
int appServicesRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
// Persistent app?
if (mPackageManagerInt.isPackagePersistent(packageName)) {
return ActivityManager.APP_START_MODE_NORMAL;
}
// Non-persistent but background whitelisted?
if (uidOnBackgroundWhitelist(uid)) {
return ActivityManager.APP_START_MODE_NORMAL;
}
// Is this app on the battery whitelist?
if (isOnDeviceIdleWhitelistLocked(uid)) {
return ActivityManager.APP_START_MODE_NORMAL;
}
// None of the service-policy criteria apply, so we apply the common criteria
return appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk);
}
int appRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
// Apps that target O+ are always subject to background check
if (packageTargetSdk >= Build.VERSION_CODES.O) {
return ActivityManager.APP_START_MODE_DELAYED_RIGID;
}
......
}
appRestrictedInBackgroundLocked对处于Persistent/background whitelist/device idle white list下的apps不设置Background limit,而其他的当targetSdkVersion >= O时, 则会限制
在Developer Guide的Background Execution Limits文章中, Google 建议是用 JobScheduler 来取代 Background task. 另外目前 Android O preview 版本还提供了 Context.startForegroundService, 按照其说法调用该接口创建Service后,需要在5秒(ANR interval)内调用 Service.startForeground(),否则 Service 就会被 stop 并且应用进程将 ANR.
目前 Android O 处于 preview 阶段,不知道后续还会不会出现变化,因为看网上有一些文章提到 NotificationManager.startServiceInForeground(), 但是官网上已经找不到该接口了