在 Android 系统中,四大组件中,Service 的重要性也是不言而喻的,它可以长时间在后台生存,执行一些复杂的或者耗时的工作。即便用户切换到了其他应用,Service 仍将在后台继续运行。此外,组件可通过绑定到 Service 与之进行交互,甚至是执行进程间通信 (IPC)。

Service 的分类

我们一般将 Service 分为三大类:后台 Service 、绑定 Service 和前台 Service 。其中,后台 Service 和绑定 Service 是『不可见 Service』,前台 Service 是『可见 Service』。

后台 Service

后台 Service (Background Service)一般是用来执行一些用户不会直接注意到的操作,比如解压数据包,比如进行网络请求。

需要注意的是,API 26(Android 8.0)之后,如果应用本身没有在前台运行,系统会对后台可执行的操作增加一些限制。这些限制有两个方面:

  1. 后台 Service 限制。这些限制不适用于前台 Service,因为前台 Service 更容易引起用户注意。

    在后台运行的 Service 会消耗资源,这有可能会造成不良的用户体验,所以 Android 对应用状态进行了区分:前台应用后台应用。满足下面任意条件,即可视为前台应用:

    • 具有可见的 Activity
    • 具有前台 Service
    • 另一个前台应用已关联到该应用,比如说输入法在应用中弹出,应用正在与屏幕识别和读取功能交互等等。

    如果上面的条件都不满足,应用就会被视为后台应用

    当应用处于前台时,可以随意创建和运行前台、后台 Service。当进入后台时,会有几分钟的时间,应用仍然可以创建和使用 Service,这个时间一过,应用就会被视为处于空闲状态,这时,系统将停止应用的后台 Service

    但是,大多数情况下,可以使用 JobScheduler 来完成 Service 能完成的操作。对于 JobScheduler 的解析,在
    这篇文章里

  2. 广播限制。除了一些特殊的例外情况,应用无法使用 AndroidManifest 注册隐式广播。但是仍然可以在运行时注册广播,并且可以使用 AndroidManifest 注册专门针对它们的显式广播。具体的限制如下:

    • 应用不能在 AndroidManifest 中为隐式广播注册广播接收器。例如ACTION_PACKAGE_REPLACED广播。显式广播不受影响。
    • 应用可以使用Context.registerReceiver()为任意广播(不管是显式还是隐式)注册接收器。
    • 需要签名权限的广播不受此限制所限,因为这些广播只会发送到使用相同证书签名的应用,而不是发送到设备上的所有应用。

    同样地,之前使用隐式广播的应用也可以使用 JobScheduler + 动态注册广播接收器来实现类似的功能。

绑定 Service

当系统组件与 Service 进行绑定时, Service 就处于『绑定状态』。绑定 Service 会以 C/S 模式提供接口,以便组件与 Service 进行交互、发送请求、接收结果,甚至是跨进程通信(IPC)来执行这些操作。绑定 Service 只会在与某个系统组件绑定时才会运行。多个组件可同时绑定到该 Service ,全部取消绑定后,该 Service 才会被销毁。

但是,绑定 Service 并不是说不能以正常的方式来运行,一个 Service ,它既可以是启动 Service (以无限期运行),也同时支持绑定,看你要覆写哪种方法了:onStartCommand()是让组件来启动 Service 后会回调的方法,而onBind()是以绑定方式启动 Service 后回调的方法。但无论是哪种 Service ,都可以使用 Intent 来启动它。

前台 Service

前台 Service (Foreground Service)可以被用户看到。通常前台 Service 必须在通知栏显示一个通知,比如各种音乐 APP:

即使用户停止与 App 的交互, Service 也依然会继续运行。

为什么要使用 Service

如上所述,使用 Service 有诸多限制,而且还分什么前台后台绑定,用子线程它不香吗?

这里要看使用场景。

Service 是一种即便用户不与它交互,也能一直运行在后台的组件,它默认是运行在主线程上的。因此,Service 适合执行短期的、不阻塞的、不与用户交互的任务。如果你必须要在主线程之外执行一些操作,比如密集性的网络通信、比如进行大量数据的初始化和解析,那你最好还是选择在 Service 中新建一个线程来做这件事。

Service 的食用指南

覆写方法

使用 Service 的时候,我们必须要自定义一个继承 Service 的类,并覆写下面几种重要的方法:

  • onStartCommand(Intent intent, int flags, int startId)

    当另一个组件(如 Activity)请求启动 Service 时,一般会通过调用startService()来启动,此时,系统会执行onStartCommand()方法(具体如何调用的,查看这一章节),如果此时有 Intent 传入,则可以进行一些初始化的工作。通常情况下,这个方法被调用的时候, Service 已经启动了。如果是要覆写该方法的话,那你得使用stopSelf()stopService()来停止 Service 。如果只想提供一个绑定 Service ,则无需覆写此方法。

    你可能会注意到,在覆写时,还有个onStart()方法,如果查看源码的话,在onStartCommand()中直接调用了onStart()。该方法在 Android 4.0.3之后就被废弃了,现在都采用直接覆写onStartCommand()方法了。

它的第一个参数是一个 Intent,是启动 Service 时组件传递过来的 Intent,可以用于初始化。这个 Intent 有可能为 null,哪怕你明明传递了非 null 的 Intent。具体原因在下面会讲到。

它的第二个参数是一个 int 值,是启动 Service 时系统给的额外参数,一般情况下是0,也有可能是START_FLAT_REDELIVERY(Intent 之前传递过)和START_FLAG_RETRY(之前的 Intent 没有正确传递过来,重试传递)的或值

它的第三个参数也是一个 int 值,叫startId,它用来唯一标识一次启动请求,会在stopSelfResult(int)这个方法中用到这个值,用以终止当前 Service。它和stopService()是有区别的,stopService()方法一旦被调用,就直接一刀砍死 Service,毫不留情;但stopSelfResult()会检查startId,如果在调用stopSelfResult()的时候又来了个启动的请求,此时startId发生了变化,它就会大喊一声『刀下留人~~~~』,Service 就不会死掉了。

它的返回值也是一个 int 值,有下面几种选择:

  • START_STICKY:被系统清理后,会保留 Service 的启动状态,但不保留 Intent,系统重启 Service 后会重新调用onStartCommand()方法,但如果这期间没有收到任何 Intent,那传入的 Intent 就是 null,需要小心处理。
  • START_STICKY_COMPATIBILITYSTART_STICKY 的兼容版本,但是不能保证onStartCommand()会被调用。
  • START_NOT_STICKY:被系统清理后,不保留 Service 状态。
  • START_REDELIVER_INTENT:被系统清理后,会保留 Service 状态,同时会保留 Intent,系统重启 Service 后会重新调用onStartCommand()方法,此时会传入之前保留的 Intent。

默认情况下,onStartCommand()会返回START_STICKY_COMPATIBILITY或者START_STICKY

  • onBind(Intent intent)

    当以绑定方式启动 Service 时,系统会调用这个方法(具体如何调用的,查看这一章节),如果此时有 Intent 传入,则可以进行一些初始化的工作。如果要实现与 Client 端通信,那么这个方法必须要返回一个 IBinder 的接口;如果该 Service 不希望与 Client 端通信,可以直接返回 null。

  • onCreate()

    这一看就是生命周期回调方法。这个方法会在onStartCommand()onBind()之前被调用。如果 Service 已经在运行了,而再次尝试启动 Service 的话,这个方法不会再被调用

  • onDestroy()

    生命周期回调方法,在 Service 被销毁之前调用。可以在这里面做一些回收线程、注销 BroadcastReceiver 之类的工作。

    值得注意的是,Service 在一般情况下不会被销毁,如果这个 Service 是前台 Service ,那它几乎永远不会终止(运行在某些国产OS上除外,说砍就砍没得商量🔪);如果 Service 被绑定到前台 Activity 上,它也不太可能会终止;如果系统在低内存且必须回收资源以保证前台 Activity 与用户的交互的情况下终止了 Service ,那么在这种情况缓解时会立即重启 Service ——当然,要看onStartCommand()中你返回了个啥。

声明 Service

如果想要该 Service 可用,必须在 AndroidManifest 中注册这个 Service ,如下:

<manifest ...>
  <application ...>
    <service android:name=".CustomService" />
  </application>
</manifest>

<service>标签中,还有很多其他的属性可以设置,我们来介绍几个比较重要的。

  • android:name:这是唯一必需的属性,用于指定 Service 的类名。在维护代码的过程中,尽量保持这个类名不变,以避免一些用显式 Intent 启动 Service 的代码碰钉子。

显式 Intent

隐式 Intent 指的是不指定特定处理者的 Intent,谁都可以接收和处理;而显式 Intent 指定了接收者,除了指定的接收者外,任何应用都无法接收和使用这个 Intent,使得应用更加安全。
从 Android 5.0 开始,如果使用隐式 Intent 调用bindService(),就会抛出异常:
java.lang.IllegalArgumentException: Service Intent must be explicit

  • android:enabled:表示系统是否可以实例化该 Service 。默认为true,表示可以。如果设置了false,可以通过调用PackageManager.setComponentEnabledSetting()方法动态开启。

  • android:exported:表示其他的应用能否调用该 Service 或者与之交互。该属性的默认值取决于该 Service 是否包含 Intent Filter。如果没有任何 Filter 则表示 Service 只能通过指定确切的类名来调用,也意味着该 Service 是『应用内部专享』,因为其他的应用不知道它的类名(正常情况下)。在这种情况下,默认值是false;反之如果有任意一个 Filter 则表明 Service 可以供外部使用,这时默认值是true

    另外,要限制这个 Service 的暴露,将该字段设置为 false 并不是唯一的方式。还可以使用权限控制android:permission来限制哪些外部应用可以与 Service 交互。下面会讲到。

  • android:permission:组件启动 Service 或绑定到 Service 所必需的权限的名称。如果startService()bindService()stopService()的调用者尚未获得此权限,那该方法将不起作用,且系统不会将 Intent 对象传送给 Service ,也即无法完成交互。如果未设置该属性,则系统将会将其设置为<application>标签中permission属性所设置的权限(注意:不是<uses-permisson>标签)。如果两个属性都没设置,则 Service 不受权限保护。

  • android:process:将运行 Service 的进程名称。正常情况下,应用的所有组件都会在为应用创建的默认进程中运行。该名称与应用包名相同<application> 元素的process属性可为所有组件设置默认进程名称。不过,组件可以使用自己的process属性替换默认值,从而将应用散布到多个进程中。

    如果为此属性分配的名称以冒号:开头,则系统会在需要时创建应用专用的新进程,并且 Service 会在该进程中运行。如果进程名称以小写字符开头,则 Service 将在使用该名称的全局进程中运行,前提是它拥有相应的权限。如此一来,不同应用中的组件便可共享进程,从而减少资源使用。

启动 Service

启动 Service 有两种方法,上面讲过了,startService()bindService()方法。我们还是分开来讲。

通过startService()启动的 Service

Intent intent = new Intent(this, CustomService.class);
startService(intent);

这种方式启动 Service ,系统将会调用onStartCommand()方法。这种 Service 在启动之后,其生命周期将独立于它的启动者。例如一个 Activity 通过这种方式启动了 Service ,哪怕 Activity 不可见了、甚至被销毁了, Service 也会继续运行。因此,我们应该在 Service 完成工作后,调用它的stopSelf()来停止运行,或者由其他的组件调用stopService()来停止该 Service 。

在调用该方法时,可以传递一个 Intent 对象给 Service , Service 会在onStartCommand()中接收到这个 Intent。多次通过这种方式启动,会多次调用到onStartCommand()方法。这通常被用来向 Service 传递数据

此处必须再强调一次, Service 启动后,是工作在主线程上的。如果交给 Service 去做一些密集性的、耗时的、阻塞的任务,可能会影响 Activity 的性能。如果要使用 Service 做这些事,你可以在 Service 中新建线程来做这些事。

通过bindService()启动的 Service

ServiceConnection conn = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName className,
                  IBinder service) {
        LocalBinder binder = (LocalBinder) service;
        mService = binder.getService();
        mBound = true;
    }

    @Override
    public void onServiceDisconnected(ComponentName arg0) {
        mBound = false;
    }
}
Intent intent = new Intent(this, CustomService.class);
bindService(intent, conn, Context.BIND_AUTO_CREATE);

组件可以通过上述方式与 Service 进行长期绑定。这种 Service 在一般情况下,不允许组件通过调用startService()方法来启动它。它通常只在为其他应用组件提供服务时处于活动状态,并不会无限期地在后台运行。

这种启动方式多用在与 Activity 或者其他组件的交互,以及通过进程间通信(IPC)与其他应用产生交互。

一旦绑定,Service 就会启动,如果当前没有任何组件与 Service 是绑定状态,那 Service 就会被系统销毁,所以,对于这种 Service ,我们**不必调用stopSelf()或者stopService()**。

上面我们也说过,同一个 Service 可以同时被多个组件绑定

在以这种方式绑定 Service 时,系统会调用onBind()方法,我们需要自己实现onBind()回调方法,返回一个 IBinder 对象,供 Client 来与 Service 进行交互。多次绑定同一个 Service ,并不会重复调用onBind()方法,系统会在第一次绑定时生成 IBinder 对象,并对其进行缓存,在之后的绑定中,直接返回这个对象给 Client。

ServiceConnection 会监控与 Service 的连接状态,如上面代码所示,它有两个需要覆写的方法:onServiceConnected()onServiceDisconnected()。前者会传递一个 IBinder 对象进来,Client 这时需要强转成自己需要的 Binder 对象,并可以调用该对象的方法,完成与 Service 的通信。后者则是与 Service 主动解绑或丢失链接时的回调。

启动前台 Service

上面的两种 Service 都是『后台 Service 』,换言之,它们不会被用户可见。如果要启动用户可见的『前台 Service 』,需要调用startForegroundService()方法。

Intent intent = new Intent(this, CustomService.class);
startForegroundService(intent);

使用这种方法启动 Service ,就意味着 Service 在启动之后,就会立刻调用它的startForeground(int, Notification)方法,用于在通知栏中创建通知。

final int ONGOING_NOTIFICATION_ID = 1;  // 该值不可为0

Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent =
        PendingIntent.getActivity(this, 0, notificationIntent, 0);

Notification notification =
          new Notification.Builder(this, CHANNEL_DEFAULT_IMPORTANCE)
    .setContentTitle(getText(R.string.notification_title))
    .setContentText(getText(R.string.notification_message))
    .setSmallIcon(R.drawable.icon)
    .setContentIntent(pendingIntent)
    .setTicker(getText(R.string.ticker_text))
    .build();

startForeground(ONGOING_NOTIFICATION_ID, notification);

使用前台 Service 可以变相实现『保活』,因为系统几乎不会考虑将它停止,哪怕内存空间不足。但是这并不代表我们可以滥用前台 Service ,因为每一个 Service 都会消耗系统资源。

如果要移除前台 Service,需要手动调用stopForeground(bool),参数表示是否要同时移除通知栏的通知。这个方法不会终止 Service。如果使用了stopServie()来终止 Service,那么通知栏中的通知也会随之被移除。

IntentService

IntentService 是 Service 的子类,它包含一个 HandlerThread,这意味着它并不是在主线程上工作的,可以将一些具有顺序性的、不需要同时处理的任务交给 IntentService 来处理。

要使用这个类,我们只需要实现它的onHandleIntent()方法,该方法会接收每个启动请求中的 Intent,并交给 HandlerThread 去处理。

值得注意的是,使用 IntentService 时,如果你需要重写onStartCommand()方法,在处理完自己的工作后,必须要调用return super.onStartCommand()方法来返回,以保证在onHandleIntent()中能正确接收到 Intent。

IntentService 在处理完所有请求后会停止 Service ,所以,不必调用stopSelf()方法

IntentService 在 API 30 中被废弃了。

Service 的生命周期

盗个官网的图,美滋儿滋儿:

左边是使用startService()调用的生命周期,右边是bindService()

可见,Service 的生命周期很简单,与 Activity 相比简直是小巫见格格巫。下面的代码,就可以监控 Service 的所有生命周期:

public class CustomService extends Service {
    int startMode;       // indicates how to behave if the service is killed
    IBinder binder;      // interface for clients that bind
    boolean allowRebind; // indicates whether onRebind should be used

    @Override
    public void onCreate() {
        // Service 创建时回调
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 服务已启动,每一次使用 startService() 启动服务时回调
        return mStartMode;
    }
    @Override
    public IBinder onBind(Intent intent) {
        // 一个 Client 正在尝试调用 bindService() 绑定该服务
        return mBinder;
    }
    @Override
    public boolean onUnbind(Intent intent) {
        // 一个 Client 正在尝试调用 unbindService() 与该服务解绑
        return mAllowRebind;
    }
    @Override
    public void onRebind(Intent intent) {
        // 一个 Client 在解绑后又尝试重新绑定
    }
    @Override
    public void onDestroy() {
        // Service 销毁之前回调
    }
}

看出来了吗?与 Activity 不一样的地方是,每一个生命周期方法,都不需要调用超类的生命周期方法

Service详解

好,来到这篇文章最核心最复杂的部分了。我们先提出几个问题,然后带着问题去理解这部分。

Service 是如何启动的?

传递给 Service 的 Intent 是如何交到 Service 手中的?

IntentService 是如何实现的?

我们来逐个解释。

普通 Service 的启动过程

我们都知道,启动 Service 最常用的方法是Context.startService(),我们就从这儿入手,看看 Service 的启动过程是怎样的:

// android.content.Context.java

public abstract ComponentName startService(Intent service);

Service 继承自 ContextWrapper,所以

Context 是一个抽象类,它的主要实现在 ContextImpl 类里:

// android.app.ContextImpl.java

@Override
public ComponentName startService(Intent service) {
    warnIfCallingFromSystemProcess(); // 检查当前进程的 uid 是否与 Process.SYSTEM_UID 相等
    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());
            ...
            return cn;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

由上面的代码可以看出,Context 将启动 Service 的任务转交给了 ActivityManager。同时交给 ActivityManager 的,还有当前 App 的主线程。这里可以解释为什么 Service 启动时会默认在主线程执行任务。

有人要杠了:这不明明是 Service 嘛,为啥交给 ActivityManager 来启动?先别杠,我们继续往下深入:

// android.app.ActivityManager.java

public static IActivityManager getService() {
    return IActivityManagerSingleton.get();
}

这里使用单例模式返回了 IActivityManager 的 Binder 对象,也即真正的startService()工作是在 ActivityManagerService 中完成的。

// com.android.server.ActivityManagerService

public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
    ...
    ActiveServices mServices;
    ...
    @Override
    public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType, boolean requireForeground, String callingPackage, int userId)
            throws TransactionTooLargeException {
        ...
        // 使用 synchronized 来保证创建 Service 时的线程安全
        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;
        }
    }
    ...
}

继续看ActiveServices.startServiceLocked()方法:

// com.android.server.am.ActiveServices.java

ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
        int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
        throws TransactionTooLargeException {
    return startServiceLocked(caller, service, resolvedType, callingPid, callingUid, fgRequired,
            callingPackage, userId, false);
}

ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
        int callingPid, int callingUid, boolean fgRequired, String callingPackage,
        final int userId, boolean allowBackgroundActivityStarts)
        throws TransactionTooLargeException {
    ...
    // 各种启动前的检查、如 App 是否存在、AndroidManifest 中是否注册、权限是否合理
    ...
    // 将 Intent 包装进了 ServiceRecord 的新实例中
    r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
              service, neededGrants, callingUid));
    if (fgRequired) {
        // 前台服务启动成功
        ServiceState stracker = r.getTracker();
        if (stracker != null) {
            stracker.setForeground(true, mAm.mProcessStats.getMemFactorLocked(),
                    r.lastActivity);
        }
        mAm.mAppOpsService.startOperation(AppOpsManager.getToken(mAm.mAppOpsService),
                AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, true);
    }
    ...
    ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
    return cmp;
}

ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
        boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
    ...
    // 记录一次运行,方便系统计算电量与运行时间的关系
    synchronized (r.stats.getBatteryStats()) {
        r.stats.startRunningLocked();
    }
    String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
    ...
    return r.name;
}

private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
        boolean whileRestarting, boolean permissionsReviewRequired)
        throws TransactionTooLargeException {
    ...
    // 还是各种检查

    // Service 正在被启动,此时它不能被 force stop
    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);
    }

    ...
    ProcessRecord app;

    if (!isolated) {
        app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);

        if (app != null && app.thread != null) {
            try {
                app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
                // 这里开始启动服务
                realStartServiceLocked(r, app, execInFg);
                return null;
            } catch (TransactionTooLargeException e) {
                throw e;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting service " + r.shortInstanceName, e);
            }

            // If a dead object exception was thrown -- fall through to
            // restart the application.
        }
    } else {
        ...
    }

    ...
    return null;
}

private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
    ...
    // 好熟悉的一句话,在 AMS 中,也是使用了 ActivityThread 中的 scheduleXXX 来实现的创建 Activity 的功能
    app.thread.scheduleCreateService(r, r.serviceInfo,
            mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
            app.getReportedProcState());
    ...
    // 这里开始向 Service 发送 Intent,也即调用 onStartCommand() 方法
    sendServiceArgsLocked(r, execInFg, true);
    ...
}

private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
            boolean oomAdjusted) throws TransactionTooLargeException {
    ...
    r.app.thread.scheduleServiceArgs(r, slice);
    ...
}

可以看到,与 AMS 创建 Activity 的过程很相似,都是通过 ActivityThread 来完成最后的创建工作,之前所有的检查工作,都是为了保证安全性,同时记录一些 Service 的启动信息,以便进行后期管理。

scheduleCreateService()scheduleCreateArgs()分别向 ActivityThread 中的 Handler 发送了CREATE_SERVICESERVICE_ARGS事件,并分别调用到handleCreateService()handleServiceArgs((ServiceArgsData)msg.obj)方法:

// android.app.ActivityThread.java

private void handleCreateService(CreateServiceData data) {
    ...
    LoadedApk packageInfo = getPackageInfoNoCheck(
            data.info.applicationInfo, data.compatInfo);
    Service service = null;
    try {
        // 利用反射创建 Service 的实例
        java.lang.ClassLoader cl = packageInfo.getClassLoader();
        service = packageInfo.getAppFactory()
                .instantiateService(cl, data.info.name, data.intent);
    } 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());

        // 调用了 Service 的 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);
        }
    }
}

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) {
                // 调用了 onStartCommand 生命周期方法
                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();
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(s, e)) {
                throw new RuntimeException(
                        "Unable to start service " + s
                        + " with " + data.args + ": " + e.toString(), e);
            }
        }
    }
}

至此,Service 完成了创建和 Intent 的传递。我们用一张时序图,来展示整个过程:

绑定 Service 的启动过程

还是从入口方法Context.bindService()开始看:

// android.app.ContextImpl.java

@Override
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
    warnIfCallingFromSystemProcess(); // 检查当前进程的 uid 是不是 Process.SYSTEM_UID
    return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null, getUser());
}

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
        String instanceName, Handler handler, Executor executor, UserHandle user) {
    ...
    int res = ActivityManager.getService().bindIsolatedService(
        mMainThread.getApplicationThread(), getActivityToken(), service,
        service.resolveTypeIfNeeded(getContentResolver()),
        sd, flags, instanceName, getOpPackageName(), user.getIdentifier());
    ...
}

与上面相同,还是来到了 ActivityManagerService 中,省略部分代码:

// com.android.server.ActivityManagerService

public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
    ...
    ActiveServices mServices;
    ...
    public int bindIsolatedService(IApplicationThread caller, IBinder token, Intent service,
        String resolvedType, IServiceConnection connection, int flags, String instanceName,
        String callingPackage, int userId) throws TransactionTooLargeException {
        ...
        synchronized(this) {
            return mServices.bindServiceLocked(caller, token, service,
                resolvedType, connection, flags, instanceName, callingPackage, userId);
        }
    }
    ...
}

这里与普通 Service 不同的是,它没有返回 ComponentName,而是返回了一个 int 值。

// com.android.server.am.ActiveServices.java

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
        String resolvedType, final IServiceConnection connection, int flags,
        String instanceName, String callingPackage, final int userId)
        throws TransactionTooLargeException {
    ...
    // 各种检查
    ...

    // 这里有个很重要的操作。
    // 如果在应用的任何组件运行之前,需要让用户检查是否可以给予权限,这时会先计划一个绑定服务,但是并不启用它,
    // 然后启动 review Activity,并给它一个 callback,用户交互完成后,再完成服务的绑定工作
    if (mAm.getPackageManagerInternalLocked().isPermissionsReviewRequired(
            s.packageName, s.userId)) {

        permissionsReviewRequired = true;

        final ServiceRecord serviceRecord = s;
        final Intent serviceIntent = service;

        RemoteCallback callback = new RemoteCallback(
                new RemoteCallback.OnResultListener() {
            @Override
            public void onResult(Bundle result) {
                synchronized(mAm) {
                    final long identity = Binder.clearCallingIdentity();
                    try {
                        if (!mPendingServices.contains(serviceRecord)) {
                            return;
                        }
                        // If there is still a pending record, then the service
                        // binding request is still valid, so hook them up. We
                        // proceed only if the caller cleared the review requirement
                        // otherwise we unbind because the user didn't approve.
                        if (!mAm.getPackageManagerInternalLocked()
                                .isPermissionsReviewRequired(
                                        serviceRecord.packageName,
                                        serviceRecord.userId)) {
                            try {
                                // 用户通过了权限验证,则创建 Service 实例
                                bringUpServiceLocked(serviceRecord,
                                        serviceIntent.getFlags(),
                                        callerFg, false, false);
                            } catch (RemoteException e) {
                                /* ignore - local call */
                            }
                        } else {
                            unbindServiceLocked(connection);
                        }
                    } finally {
                        Binder.restoreCallingIdentity(identity);
                    }
                }
            }
        });

        final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
        intent.putExtra(Intent.EXTRA_PACKAGE_NAME, s.packageName);
        intent.putExtra(Intent.EXTRA_REMOTE_CALLBACK, callback);

        mAm.mHandler.post(new Runnable() {
            @Override
            public void run() {
                mAm.mContext.startActivityAsUser(intent, new UserHandle(userId));
            }
        });
    }

    final long origId = Binder.clearCallingIdentity();

    try {
        ...
        // 如果这时 Service 还没有被创建,则创建 Service 实例
        if ((flags&Context.BIND_AUTO_CREATE) != 0) {
            s.lastActivity = SystemClock.uptimeMillis();
            if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                    permissionsReviewRequired) != null) {
                return 0;
            }
        }
        ...
        if (s.app != null && b.intent.received) {
            // Service 已经在运行了,就可以直接进行 connect
            // 此处的 connected 是 IServiceConnection.aidl 中定义的,这个方法由 LoadedApk 来实现,具体查看『关于 Context』一文,此处略过
            // 最后会调用到 ServiceConnection.onServiceConnected() 方法,完成了绑定工作
            try {
                c.conn.connected(s.name, b.intent.binder, false);
            } catch (Exception e) {
                Slog.w(TAG, "Failure sending service " + s.shortInstanceName
                        + " to connection " + c.conn.asBinder()
                        + " (in " + c.binding.client.processName + ")", e);
            }

            // 如果是重新绑定
            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;
}

private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
        boolean execInFg, boolean rebind) throws TransactionTooLargeException {
    ...
    r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
            r.app.getReportedProcState());
    ...
}

继续交给 ActivityThread 去做这件事,经过发送BIND_SERVICE的消息后,来到了ActivityThread.handleBindService()方法:

// android.app.ActivityThread

private void handleBindService(BindServiceData data) {
    Service s = mServices.get(data.token);

    if (s != null) {
        try {
            data.intent.setExtrasClassLoader(s.getClassLoader());
            data.intent.prepareToEnterProcess();
            try {
                if (!data.rebind) {
                    // 调用 Servcie 对象的 onBind 生命周期方法
                    IBinder binder = s.onBind(data.intent);
                    ActivityManager.getService().publishService(
                            data.token, data.intent, binder);
                } else {
                    // 调用 Servcie 对象的 onRebind 生命周期方法
                    s.onRebind(data.intent);
                    ActivityManager.getService().serviceDoneExecuting(
                            data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                }
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(s, e)) {
                throw new RuntimeException(
                        "Unable to bind to service " + s
                        + " with " + data.intent + ": " + e.toString(), e);
            }
        }
    }
}

又回到了 ActivityManagerService 中。这里我们看到了两个方法publishService()serviceDoneExecuting()。追踪下去,发现publishService()方法最终还是调用了 LoadedApk.connected() 方法;而serviceDoneExecuting()方法并没有,因为这个方法是在 rebind 的情况下才会调用,刚才在 ActiveServices.bindServiceLocked 已经针对 rebind 情况调用过一次 LoadedApk.connected() 了。

至此,绑定 Service 的启动完成。

同样地,我们使用一张时序图来展示一下这个过程:

IntentService 原理解析

IntentService 的特点就不再赘述了,我们直接看它关键的代码,然后再解释它的原理:

public abstract class IntentService extends Service {
    // 有自己的 Looper
    private volatile Looper mServiceLooper;
    // 有自定义的 Handler
    private volatile ServiceHandler mServiceHandler;
    private String mName;
    private boolean mRedelivery;

    // 将 Handler 绑定到初始化的线程中
    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }

    // 传入 name 以供内部的 HandlerThread 使用,方便进行调试
    public IntentService(String name) {
        super();
        mName = name;
    }

    // 设置 intent 是否会被重新传递
    //
    // 如果设置为 true,onStartCommand() 会返回 Serivce.START_REDELIVER_INTENT,这种情况下,
    // 如果 onHandleIntent() 还没有执行完返回,进程就死掉了,这时进程会被重启然后重新传递刚才的 intent。
    // 如果之前发送了多个 intent (其他的在等待),只有最近发送的一个能保证被送达(其他的不一定了)。
    // 
    // 如果设置为 false onStartCommand() 会返回 Serivce.START_NOT_STICKY,如果进行死掉,intent 也就随风消散了
    //
    public void setIntentRedelivery(boolean enabled) {
        mRedelivery = enabled;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        // 新建了一个局部的 HandlerThread,也即不允许外部直接管理这个线程的状态。
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

    // 不要重写这个方法
    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }

    // 除非你需要绑定这个服务,否则不用重写这个方法
    @Override
    @Nullable
    public IBinder onBind(Intent intent) {
        return null;
    }

    // 唯一需要重写的的方法,在这里可以处理调用者发送来的数据
    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);
}

可见这个类并不是很神秘:

  1. 继承了 Service 类;
  2. 重写了onCreate()方法,并在其中定义了一个局部的 HandlerThread,并不允许外部直接访问;
  3. 定义了一个 ServiceHandler 并与新建的 HandlerThread 绑定;
  4. 重写了onStart()方法,在每次启动服务调用到onStartCommand()的时候,调用onStart(),并将消息传递给 ServiceHandler;
  5. 定义了一个抽象方法onHandleIntent(Intent)供子类使用,用于真正处理请求。

这个类虽然很常用,但是 Google 决定在 Android R(Android 11)中,将会废弃这个类,原因与最开始提到的『后台操作限制』相同,一个总是在后台运行的服务,必然会造成资源的消耗与浪费。Android 现在大力推宠的是 androidx 中的 WorkManagerJobIntentService,我将会在其他的文章里讲解。