startService和bindService
- Service的启动方式主要有两种,分别是startService和bindService
- 使用startService启动时是单独开一个服务,与Activity没有任何关系,而bindService方式启动时,Service会和Activity进行绑定,当对应的activity销毁时,对应的Service也会销毁
- startService多次,onStart()会执行多次,onCreate()只执行一次,onStartCommand()也会执行多次。bindService多次,onCreate()与onBind()都只会调用一次。
- Service中的onBind()方法是抽象方法,Service类本身就是抽象类,所以onBind()方法是必须重写的,即使我们用不到。
- bindService启动的服务和调用者之间是典型的Client-Server模式。调用者是client,Service则是Server
端。Service只有一个,但绑定到Service上面的Client可以有一个或很多个。bindService启动服务的生 命周期与其绑定的client息息相关。 - 调用Context.startService方式启动Service时,如果Android面临内存匮乏,可能会销毁当前运行的
Service,待内存充足时可以重建Service。而Service被Android系统强制销毁并再次重建的行为依赖于Service的onStartCommand()方法的返回值
- START_STICKY: 如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由 于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。 如果在此期间没有任何启动命令被传 递到service,那么参数Intent将为null。
- START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务
- START_REDELIVER_INTENT:重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。
- START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。
Service的启动过程
ContextWrapper.startService() & ContextImpl.startService()
- 启动Service是通过调用startService实现的,其方法实现在Context的实现类ContextWrapper中
Context mBase;
@Override
public ComponentName startService(Intent service) {
return mBase.startService(service);
}
- Context mBase 指的是什么呢?ActivityThread启动Activity时会调用performLaunchActivity创建Activity的上下文环境
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
//创建上下文对象appContext
ContextImpl appContext = createBaseContextForActivity(r);
...
try {
...
if (activity != null) {
...
//将appContext传入Activity的attach方法中,将Activity与appContext关联
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback,
r.assistToken);
...
}
...
} catch ...
return activity;
}
//其中createBaseContextForActivity实现如下
private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
...
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
...
return appContext;
}
- 从上面代码可以看出,Activity的attach方法中将ContextImpl赋值给ContextWrapper的成员变量mBase,因此mBase具体指向就是ContextImpl;
- 那么来看一下ContextImpl的startService方法
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, false, mUser);
}
//其中调用了startServiceCommon代码如下
private ComponentName startServiceCommon(Intent service, boolean requireForeground, UserHandle user) {
try {
...
//
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
getOpPackageName(), getAttributionTag(), user.getIdentifier());
...
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
- 上面代码调用ActivityManager.getService()获取到ActivityManagerService,并调用其startService方法
AMS.startService()
- ActivityManagerService.startService代码如下
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, boolean requireForeground, String callingPackage,
String callingFeatureId, int userId) throws TransactionTooLargeException {
...
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, callingFeatureId, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
return res;
}
}
ActiveServices.startServiceLocked
- 上面调用了mServices.startServiceLocked方法,其中mServices的类型是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);
...
return cmp;
}
//startServiceLocked其中又调用了startServiceInnerLocked
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
...
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
...
return r.name;
}
//startServiceInnerLocked中又调用了bringUpServiceLocked
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired) throws TransactionTooLargeException {
...
//ServiceRecord的processName的值赋值给procName, 用来描述Service想要在哪个进程运行,默认是当前进程,
//我们也可以在AndroidManifes配置文件中设置android:process属性来新开启一个进程运行Service
final String procName = r.processName;
ProcessRecord app;
if (!isolated) {
//将procName和Service的uid传入到AMS的getProcessRecordLocked方法,
//来查询是否存在一个与Service对应的ProcessRecord类型的对象app,
//ProcessRecord主要用来记录运行的应用程序进程的信息.
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
//如果用来运行Service的应用程序进程存在,则调用realStartServiceLocked方法
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
realStartServiceLocked(r, app, execInFg);
return null;
} catch ...
}
} else {
app = r.isolatedProc;
...
}
//如果用来运行Service的应用程序进程不存在,或应用程序之间的组件调用不需要检查权限,
//满足则调用AMS的startProcessLocked方法来创建对应的应用程序进程。
if (app == null && !permissionsReviewRequired) {
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, false, isolated, false)) == null) {
String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
+ r.intent.getIntent() + ": process is bad";
bringDownServiceLocked(r);
return msg;
}
...
}
...
return null;
}
//realStartServiceLocked方法代码如下
private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, boolean execInFg) throws RemoteException {
...
try {
...
//app.thread的实现是ActivityThread的内部类ApplicationThread
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
app.getReportedProcState());
r.postNotification();
created = true;
}
...
}
ActivityThread.ApplicationThread.scheduleCreateService()
- scheduleCreateService代码如下
public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
updateProcessState(processState, false);
//将要启动的信息封装成CreateServiceData 对象并传给sendMessage方法
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;
//sendMessage向H发送CREATE_SERVICE消息
sendMessage(H.CREATE_SERVICE, s);
}
ActivityThread.sendMessage() & ActivityThread.H.handleMessage()
- scheduleCreateServiceActivity调用sendMessage向H发送CREATE_SERVICE消息,Thread.H.handleMessage根据消息类型,调用handleCreateService方法
class H extends Handler {
...
public void handleMessage(Message msg) {
switch (msg.what) {
...
case CREATE_SERVICE:
...
//根据消息类型,调用handleCreateService方法
handleCreateService((CreateServiceData)msg.obj);
...
break;
...
}
...
}
}
ActivityThread.handleCreateService
- ActivityThread.H.handleMessage方法根据消息类型,调用了handleCreateService方法
private void handleCreateService(CreateServiceData data) {
...
//获取要启动Service的应用程序的LoadedApk,LoadedApk是一个APK文件的描述类
LoadedApk packageInfo = getPackageInfoNoCheck(data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
...
//创建Service的上下文环境ContextImpl对象
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
Application app = packageInfo.makeApplication(false, mInstrumentation);
//通过调用LoadedApk的getClassLoader方法来获取类加载器
java.lang.ClassLoader cl = packageInfo.getClassLoader();
//根据CreateServiceData对象中存储的Service信息,将Service加载到内存中
service = packageInfo.getAppFactory().instantiateService(cl, data.info.name, data.intent);
...
//调用attach方法来初始化Service
service.attach(context, this, data.info.name, data.token, app, ActivityManager.getService());
//调用Service的onCreate方法,这样Service就启动
service.onCreate();
//将启动的Service加入到ActivityThread的成员变量mServices中,其中mServices是ArrayMap类型
mServices.put(data.token, service);
...
} catch...
}
- 最终在ActivityThread.handleCreateService中创建service,并调用 attach 和 onCreate 方法
Service的绑定过程
ContextWrapper.bindService() & ContextImpl.bindService
- 绑定Service是通过调用bindService()实现的,其方法实现在Context的实现类ContextWrapper中
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
return mBase.bindService(service, conn, flags);
}
- 之前已经说过mBase具体指向就是ContextImpl,那么来看一下ContextImpl.bindService
@Override
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null,
getUser());
}
- bindService中调用了bindServiceCommon,代码如下
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
String instanceName, Handler handler, Executor executor, UserHandle user) {
IServiceConnection sd;
...
//调用了LoadedApk类型的对象mPackageInfo的getServiceDispatcher方法,
//主要作用是将ServiceConnection封装为IServiceConnection类型的对象sd,
//从IServiceConnection的名字就能得知它实现了Binder机制,这样Service的绑定就支持了跨进程
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();
...
//调用AMS的bindService方法
int res = ActivityManager.getService().bindIsolatedService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, instanceName, getOpPackageName(), user.getIdentifier());
...
return res != 0;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
AMS.bindIsolatedService()
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) {
//调用ActiveServices类型的对象mServices的bindServiceLocked方法
return mServices.bindServiceLocked(caller, token, service,
resolvedType, connection, flags, instanceName, callingPackage, userId);
}
}
ActiveServices.bindServiceLocked()
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String instanceName, String callingPackage, final int userId) throws TransactionTooLargeException {
...
try {
...
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
//调用bringUpServiceLocked方法,在bringUpServiceLocked方法中又会调用realStartServiceLocked方法,
//最终由ActivityThread来调用Service的onCreate方法启动Service,
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
permissionsReviewRequired) != null) {
return 0;
}
}
...
//s.app != null 表示Service已经运行,其中s是ServiceRecord类型对象,app是ProcessRecord类型对象
//b.intent.received表示当前应用程序进程的Client端已经接收到绑定Service时返回的Binder,
//这样应用程序进程的Client端就可以通过Binder来获取要绑定的Service的访问接口
if (s.app != null && b.intent.received) {
try {
//调用c.conn的connected方法,其中c.conn指的是IServiceConnection,
//它的具体实现为ServiceDispatcher.InnerConnection,其中ServiceDispatcher是LoadedApk的内部类,
//InnerConnection的connected方法内部会调用H的post方法向主线程发送消息,从而解决当前应用程序进程和Service跨进程通信的问题,
c.conn.connected(s.name, b.intent.binder, false);
} catch ...
if (b.intent.apps.size() == 1 && b.intent.doRebind) {
//如果当前应用程序进程的Client端第一次与Service进行绑定的,并且Service已经调用过onUnBind方法,
requestServiceBindingLocked(s, b.intent, callerFg, true);
}
} else if (!b.intent.requested) {
//如果应用程序进程的Client端没有发送过绑定Service的请求,rebind为false,表示不是重新绑定
requestServiceBindingLocked(s, b.intent, callerFg, false);
}
...
} finally {
Binder.restoreCallingIdentity(origId);
}
return 1;
}
- 上面最终调用了ActiveServices.requestServiceBindingLocked代码如下
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
...
//i.requested表示是否发送过绑定Service的请求
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
...
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.getReportedProcState());
...
} catch ...
}
return true;
}
- 上面代码requestServiceBindingLocked中调用了ActivityThread.ApplicationThread.scheduleBindService
ActivityThread.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;
//向H发送BIND_SERVICE消息
sendMessage(H.BIND_SERVICE, s);
}
ActivityThread.sendMessage() & ActivityThread.H.handleMessage()
class H extends Handler {
...
public void handleMessage(Message msg) {
switch (msg.what) {
...
case BIND_SERVICE:
...
//根据消息类型,调用handleBindService方法
handleBindService((BindServiceData)msg.obj);
...
break;
...
}
...
}
}
ActivityThread.handleBindService()
private void handleBindService(BindServiceData data) {
//从mServices中获取要绑定的Service
Service s = mServices.get(data.token);
if (s != null) {
//如果取到了
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
try {
//判断是否rebind
if (!data.rebind) {
//调用Service的onBind方法,这样Service处于绑定状态了
IBinder binder = s.onBind(data.intent);
//调用AMS的publishService方法
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 ...
} catch ...
}
}
- handleBindService中调用了Service的onBind方法,又调用了AMS的publishService方法
AMS.publishService()
public void publishService(IBinder token, Intent intent, IBinder service) {
...
synchronized(this) {
...
//调用了ActiveServices类型的mServices对象的publishServiceLocked方法
mServices.publishServiceLocked((ServiceRecord)token, intent, service);
}
}
ActiveServices.publishServiceLocked()
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
...
if (r != null) {
...
if (b != null && !b.received) {
...
for (int conni = connections.size() - 1; conni >= 0; conni--) {
...
for (int i=0; i<clist.size(); i++) {
...
try {
//c.conn指的是IServiceConnection,它的具体实现为ServiceDispatcher.InnerConnection,
//其中ServiceDispatcher是LoadedApk的内部类
c.conn.connected(r.name, service, false);
} catch...
}
}
}
...
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
- publishServiceLocked中调用了LoadedApk.ServiceDispatcher.InnerConnection.connected()
LoadedApk.ServiceDispatcher.InnerConnection.connected()
public void connected(ComponentName name, IBinder service, boolean dead)
throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {
sd.connected(name, service, dead);
}
}
- 上面代码调用了ServiceDispatcher 类型的sd对象的connected方法
LoadedApk.ServiceDispatcher.connected()
public void connected(ComponentName name, IBinder service, boolean dead) {
if (mActivityExecutor != null) {
mActivityExecutor.execute(new RunConnection(name, service, 0, dead));
} else if (mActivityThread != null) {
//调用Handler类型的对象mActivityThread的post方法,mActivityThread实际上指向的是H。
//因此,通过调用H的post方法将RunConnection对象的内容运行在主线程中
mActivityThread.post(new RunConnection(name, service, 0, dead));
} else {
doConnected(name, service, dead);
}
}
- connected最终调用了doConnected方法
LoadedApk.ServiceDispatcher.doConnected()
public void doConnected(ComponentName name, IBinder service, boolean dead) {
...
if (old != null) {
mConnection.onServiceDisconnected(name);
}
if (dead) {
mConnection.onBindingDied(name);
}
if (service != null) {
//调用了ServiceConnection类型的对象mConnection的onServiceConnected方法,
//这样在客户端中实现了ServiceConnection接口的类的onServiceConnected方法就会被执行
mConnection.onServiceConnected(name, service);
} else {
mConnection.onNullBinding(name);
}
}
为什么bindService可以跟Activity生命周期联动?
- bindService 方法执行时,LoadedApk 会记录 ServiceConnection 信息。
- Activity 执行 finish 方法时,会通过 LoadedApk 检查 Activity 是否存在未注销/解绑的 BroadcastReceiver和 ServiceConnection,如果有,那么会通知 AMS 注销/解绑对应的 BroadcastReceiver 和 Service,并打印异常信息,告诉用户应该主动执行注销/解绑的操作。
如何保证Service不被杀死?
1. 提供进程优先级,降低进程被杀死的概率
- 方法一:监控手机锁屏解锁事件,在屏幕锁屏时启动1个像素的 Activity,在用户解锁时将 Activity 销毁掉。
- 方法二:启动前台service。
- 方法三:提升service优先级:在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = "1000"这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时适用于广播。
2. 在进程被杀死后,进行拉活
- 方法一:注册高频率广播接收器,唤起进程。如网络变化,解锁屏幕,开机等
- 方法二:双进程相互唤起。
- 方法三:依靠系统唤起。
- 方法四:onDestroy方法里重启service:service + broadcast 方式,就是当service走ondestory的时候,发送一个自定义的广播,当收到广播的时候,重新启动service;
3. 依靠第三方
- 根据终端不同,在小米手机(包括 MIUI)接入小米推送、华为手机接入华为推送;其他手机可以考虑接入腾讯信鸽或极光推送与小米推送做 A/B Test。
参考
我是今阳,如果想要进阶和了解更多的干货,欢迎关注微信公众号 “今阳说” 接收我的最新文章
|