前言

Service启动与上一篇说的入口Activity启动类似,主要分成ContextImpl到ActivityManagerService调用和ActivityThread启动Service这两个过程

ContextImpl到AMS的调用过程

这个过程比较简单,如图所示

Android 怎么启动另一个应用的service_架构师

启动Service肯定是从startService开始,这个方法是在ContextWrapper中实现的,在这个方法中调用了ContextImpl的startService方法。

在ContextImpl中经过startServiceCommon,最终通过IActivityManager的startService方法来通知AMS启动一个Service。

ActivityThread启动Service

这部分过程如图:

Android 怎么启动另一个应用的service_封装_02

上一个过程最终是调用了AMS的startService方法,这个过程就是从这开始的,这里会调用ActiveService的startServiceLocked,代码如下:

ComponentName startServiceLocked(...) throws TransactionTooLargeException {
        
    ...

    ServiceLookupResult res =
        retrieveServiceLocked(service, resolvedType, callingPackage,
                callingPid, callingUid, userId, true, callerFg, false);  //1
    if (res == null) {
        return null;
    }
    if (res.record == null) {
        return new ComponentName("!", res.permission != null
                ? res.permission : "private to package");
    }

    ServiceRecord r = res.record;  //1

    ...

    ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
    return cmp;
}

代码1处通过retrieveServiceLocked方法会先查找参数service对应的ServiceRecord;如果没有回调用PackageManagerService取获取参数service对应的Service信息并封装到ServiceRecord。最后将ServiceRecord封装成ServiceLookupResult返回。可以看到这里与上一篇讲的Activity很类似,ServiceRecord就像ActivityRecord一样用来描述一个Service。

代码2就是从ServiceLookupResult取出ServiceRecord,然后调用startServiceInnerLocked。

startServiceInnerLocked方法会调用bringUpServiceLocked方法,这个方法代码如下:

private String bringUpServiceLocked(...) throws TransactionTooLargeException {
        
    ...

    final String procName = r.processName;  //1
    String hostingType = "service";
    ProcessRecord app;

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

        ...

        if (app != null && app.thread != null) { //3
            try {
                app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
                realStartServiceLocked(r, app, execInFg); //4
                return null;
            } catch (TransactionTooLargeException e) {
                throw e;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting service " + r.shortName, e);
            }

        }
    } else {          
        ...
    }

    if (app == null && !permissionsReviewRequired) { //5
        if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,  //6
                hostingType, r.name, false, isolated, false)) == 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);
            return msg;
        }
        if (isolated) {
            r.isolatedProc = app;
        }
    }

    ...

    return null;
}

代码1得到进程名称。代码2调用AMS的getProcessRecordLocked查询与该Service对应的ProcessRecord,ProcessRecord一看名字就应该能猜出来了,主要是描述运行的应用程序进程信息。所以代码2的目的就是获取该Service对应的应用程序进程。

代码3处判断如果应用程序进程存在,则执行代码4,通过realStartServiceLocked方法来启动Service。

如果不存在就会跳到代码5,再次判断不存在则在代码6处调用AMS的startProcessLocked来创建对应的应用程序信息。

在realStartServiceLocked方法中调用了IApplicationThread的scheduleCreateService方法,它的实现是ActivityThread内部类ApplicatioinThread,这块跟Activity启动几乎一样。

scheduleCreateService将service的启动参数封装后通过Handler进行通知。最终会在ActivityThread处理,处理方法是handleCreateService,代码如下:

private void handleCreateService(CreateServiceData data) {
    unscheduleGcIdler();

    LoadedApk packageInfo = getPackageInfoNoCheck(
            data.info.applicationInfo, data.compatInfo);  //1
    Service service = null;
    try {
        java.lang.ClassLoader cl = packageInfo.getClassLoader();  //2
        service = packageInfo.getAppFactory()
                .instantiateService(cl, data.info.name, data.intent);  //3
    } catch (Exception e) {
        ...
    }

    try {
        if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);

        ContextImpl context = ContextImpl.createAppContext(this, packageInfo);//4
        context.setOuterContext(service);

        Application app = packageInfo.makeApplication(false, mInstrumentation);
        service.attach(context, this, data.info.name, data.token, app,
                ActivityManager.getService());  //5
        service.onCreate();  //6
        mServices.put(data.token, service);  //7
        ...
    } catch (Exception e) {
        ...
    }
}

代码2会获取类加载器,然后代码3从之前封装的对象中获取Service信息,创建service;代码4获取上下文;代码5通过service的attach方法来初始化service;代码6则调用了service的onCreate方法;代码7将service加入ActivithThread的成员变量mServices中,以便后续使用。