Android开发Android技术知识

Service启动方式追踪

2017-07-16  本文已影响0人  samychen

前言

在安卓开发过程中我们除了Activity之外最常用的组件就是Service,特别是在和用户没有界面交互的终端设备中更是常见,那么Service作为安卓四大组件之一是如何运作的?

我们一般使用Service有两种方式,startService和bindService,这两种方法使用场景各有不同,下面我们从startService来分析Service完整的运作过程。

图1 .启动 流程

什么是ContextImpl

首先给出如下一张XML表认识ContextImpl


图2. 类图

从上面这张图我们可以看到Activity继承了ContextWrapper类,而在ContextWrapper类中,实现了startService方法。在ContextWrapper类中,有一个成员变量mBase,它是一个ContextImpl实例,而ContextImpl类和ContextWrapper类一样继承于Context类。

我们在代码中通过startService(Intent service)来启动一个服务,调用的方法是:

//ContextWrapper类
@Override
public ComponentName startService(Intent service) {
    return mBase.startService(service);
}

可以看出ContextWrapper类的startService方法最终是通过调用ContextImpl类的startService方法来实现的。继续追踪ContextImpl.startService() :

@Override
public ComponentName startService(Intent service) {
    warnIfCallingFromSystemProcess();
    return startServiceCommon(service, mUser);
}

private ComponentName startServiceCommon(Intent service, UserHandle user) {
    try {
        validateServiceIntent(service);
        service.prepareToLeaveProcess(this);
        ComponentName cn = ActivityManagerNative.getDefault().startService(
            mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                        getContentResolver()), getOpPackageName(), user.getIdentifier());
        if (cn != null) {
            if (cn.getPackageName().equals("!")) {
                throw new SecurityException(
                        "Not allowed to start service " + service
                        + " without permission " + cn.getClassName());
            } else if (cn.getPackageName().equals("!!")) {
                throw new SecurityException(
                        "Unable to start service " + service
                        + ": " + cn.getClassName());
            }
        }
        return cn;
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

这里通过 startService——>startServiceCommon,然后在startServiceCommon里通过ActivityManagerNative.getDefault()返回的就是一个ActivityManagerProxy对象,这里使用Binder机制将代理Proxy返回给客户端,而客户端通过将参数写入Proxy类,接着Proxy就会通过Binder去远程调用服务端的具体方法,因此,我们只是借用ActivityManagerProxy来调用ActivityManagerService的方法。所以这里其实是调用了远程ActivityManagerService的startService方法。

到这里就解释完了图1中Service启动过程Activity所在线程所做的操作。接下来我们就看看ActivityManagerService是如何实现的。

AMS如何进一步启动Service

查看ActivityManagerService中的源码:

//ActivityManagerService类
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
        String resolvedType, int userId) {
    //...
    synchronized(this) {
        final int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        final long origId = Binder.clearCallingIdentity();
        ComponentName res = mServices.startServiceLocked(caller, service,
                resolvedType, callingPid, callingUid, userId);
        Binder.restoreCallingIdentity(origId);
        return res;
    }
}

调用mService的startServiceLocked方法,那mService是干嘛的呢?此处的mServices是一个ActiveServices对象,从名字上也能看出该类主要是封装了一些处于活动状态的service组件的方法的调用。那接下来就看看他的startServiceLocked是如何实现的。

ComponentName startServiceLocked(IApplicationThread caller,
        Intent service, String resolvedType,
        int callingPid, int callingUid, int userId) {
    //...
    final boolean callerFg;
    if (caller != null) {
        //mAm 是ActivityManagerService.
        final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
        if (callerApp == null) {
            throw new SecurityException(
                    "Unable to find app for caller " + caller
                    + " (pid=" + Binder.getCallingPid()
                    + ") when starting service " + service);
        }
        callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;
    } else {
        callerFg = true;
    }
    ServiceLookupResult res = retrieveServiceLocked(service, resolvedType, 
                     callingPid, callingUid, userId, true, callerFg);
    if (res == null) {
        return null;
    }
    if (res.record == null) {//权限拒绝.
        return new ComponentName("!", res.permission != null
                ? res.permission : "private to package");
    }

    ServiceRecord r = res.record;
    //
    r.lastActivity = SystemClock.uptimeMillis();
    r.startRequested = true;
    r.delayedStop = false;
    r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
            service, neededGrants));

    final ServiceMap smap = getServiceMap(r.userId);
    boolean addToStarting = false;
    //...
    return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}

最重要的逻辑在于最后一句的startServiceInnerLocked方法,他的内部实现是这样的。

ComponentName startServiceInnerLocked(ServiceMap smap, Intent service,
        ServiceRecord r, boolean callerFg, boolean addToStarting) { 
    //...
    //真正开启service的地方。
    String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false);
    //注意此处反回值是null的时候,证明没有异常.
    if (error != null) {
        return new ComponentName("!!", error);
    }
    //...
    return r.name;
}

startServiceInnerLocked方法内部调用了bringUpServiceLocked方法来进行后续的启动。

private final String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
    boolean whileRestarting) throws TransactionTooLargeException {

    //...
    if (app != null && app.thread != null) {
      try {
        app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
        realStartServiceLocked(r, app, execInFg);
        return null;
      } 

    //...

    return null;
}

在bringUpServiceLocked方法中调用了realStartServiceLocked方法,在Activity的启动过程中我们也曾看过相似的方法,说明到了这里我们也快看到真正的Service启动了,接着来看realStartServiceLocked。

private final void realStartServiceLocked(ServiceRecord r,
    ProcessRecord app, boolean execInFg) throws RemoteException {

  //...

  boolean created = false;
  try {

    //...
    app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
    app.thread.scheduleCreateService(r, r.serviceInfo,
        mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
        app.repProcState);
    r.postNotification();
    created = true;
  } catch (DeadObjectException e) {
    Slog.w(TAG, "Application dead when creating service " + r);
    mAm.appDiedLocked(app);
    throw e;
  } 

  //这里会调用Service的onStartCommand,注意后文要用到
  sendServiceArgsLocked(r, execInFg, true);

  //...

}

这里需要对上面的app.thread做一下特殊的说明。如果你已经了解了Binder的通信机制,那你应该知道一般我们的服务都是由客户端向服务端发出请求,接着服务端向客户端返回结果,这个是单向的通信,但是如果反过来服务端要向客户端发送请求的话,那么同样的,在服务端也应该持有另外一个Proxy,而在客户端也同样需要一个Manager与之对应。

在这里app是要运行 Service 的进程对应的ProcessRecord对象,代表一个应用进程,而thread是一个ApplicationThreadProxy对象,它运行在AMS(现在AMS就是客户端了),而与之对应的服务端则是在应用程序中的ApplicatonThread,还是有点绕,我们用一张图来展示他们的关系。

图3. 应用程序进程与系统服务进程之间的双向通信

ApplicationThread与ApplicationThreadProxy

public interface IApplicationThread extends IInterface```
IApplicationThread其实是一个IBinder类型的接口。并且在这个接口中声明了许多与Activity,Service生命周期相关的方法,那么它的实现类又是谁呢?答案就是ApplicationThreadNative。

public abstract class ApplicationThreadNative extends Binder implements IApplicationThread


private class ApplicationThread extends ApplicationThreadNative


ApplicationThread就是真正意义上的服务端,它的父类ApplicationThreadNative就是将具体的操作将给它来执行的。

class ApplicationThreadProxy implements IApplicationThread

在客户端运行的ApplicationThreadProxy在哪里呢?其实如果理解了Binder机制,那么我们应该知道他就是ApplicationThreadNative的内部类,客户端(AMS)就是通过它与service所在的进程进行通信的。因此我们接着要看的当然是ApplicationThread的scheduleCreateService了

#### ApplicationThread.scheduleCreateService

public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
updateProcessState(processState, false);
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;

        sendMessage(H.CREATE_SERVICE, s);
    }
可以看到在scheduleCreateService方法中发送了一个message,其消息类型为CREATE_SERVICE,它是在H类中定义的一个常量,而H类其实就是继承于Handler的,它专门用来处理发送过来的请求。接下来就来看看它是如何处理创建service这个消息的。
#### H.handleMessage

public void handleMessage(Message msg) {
switch (msg.what) {
...
case CREATE_SERVICE:
handleCreateService((CreateServiceData)msg.obj); //【见流程15】
break;
case BIND_SERVICE:
handleBindService((BindServiceData)msg.obj);
break;
case UNBIND_SERVICE:
handleUnbindService((BindServiceData)msg.obj);
break;
...
}
}

可以看到handleMessage处理了很多类型的消息,包括service的创建、绑定、解绑、销毁等等,我们直接看创建的逻辑,也就是handleCreateService方法。不过有一个问题,那就是Handler创建之前必须要创建Looper,否则会报错,那么Looper是在哪里创建的呢?答案就是ActivityThread的main方法。

public static void main(String[] args) {
//...
//在主线程创建Looper
Looper.prepareMainLooper();

    ActivityThread thread = new ActivityThread();
    thread.attach(false);

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }

    AsyncTask.init();
    Looper.loop();

    throw new RuntimeException("Main thread loop unexpectedly exited");
}
我们可以看到Looper就是在这里创建的,而Handler也是在Service进程中的主线程,也就是说它处理消息也是在主线程,那么Service的创建自然也就是在主线程中。可是ActivityThread是什么鬼呢?其实刚才的ApplicationThread就是它的内部类。
接下来继续看Handler如何处理消息。

private void handleCreateService(CreateServiceData data) {
unscheduleGcIdler();
LoadedApk packageInfo = getPackageInfoNoCheck(data.info.applicationInfo, data.compatInfo);

java.lang.ClassLoader cl = packageInfo.getClassLoader();
//通过反射创建目标服务对象
Service service = (Service) cl.loadClass(data.info.name).newInstance();
...

try {
    //创建ContextImpl对象
    ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
    context.setOuterContext(service);
    //创建Application对象
    Application app = packageInfo.makeApplication(false, mInstrumentation);
    service.attach(context, this, data.info.name, data.token, app,
            ActivityManagerNative.getDefault());
    //调用服务onCreate()方法
    service.onCreate();
    mServices.put(data.token, service);
    //调用服务创建完成
    ActivityManagerNative.getDefault().serviceDoneExecuting(
            data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (Exception e) {
    ...
}

}

在这里Handler通过反射机制拿到Service对象,于是就调用了service的onCreate方法,所以Service就算是启动了。我们通过层层的寻找总算是见到了onCreate的庐山真面目。

上面流程图没有onStartCommand?不急,我们刚才在sendServiceArgsLocked方法中还有另外一个sendServiceArgsLocked方法没有讲到,他就是onStartCommand的入口,我们看看他是如何实现的。

private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
boolean oomAdjusted) {
final int N = r.pendingStarts.size();
if (N == 0) {
return;
}

    while (r.pendingStarts.size() > 0) {
        try {
            //与调用scheduleCreateService方法一样,远程调用ApplicationThread的scheduleServiceArgs方法
            r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
        } catch (RemoteException e) {
            // Remote process gone...  we'll let the normal cleanup take
            // care of this.
            if (DEBUG_SERVICE) Slog.v(TAG, "Crashed while scheduling start: " + r);
            break;
        } catch (Exception e) {
            Slog.w(TAG, "Unexpected exception", e);
            break;
        }
    }
}
这里依旧调用了远程服务端ApplicationThread的方法来执行后面的逻辑,其实通过上面分析onCreate的逻辑大家应该能够知道调用onStartCommand也是大同小异的,具体的调用逻辑就交给大家去分析啦!
#### 后记

  到这里呢,我们就把Service的启动流程完整的讲解了一遍,bindService的启动过程也是类似的。
上一篇下一篇

猜你喜欢

热点阅读