Service启动流程(AOSP 11)

1,410 阅读5分钟

Service启动流程:

Android四大组件的Service主要用于在后台执行长时间的任务,它没有自己的界面,Service启动之后,将在后台一直运行。应用组件也可以bindService,与Service进行交互甚至是IPC。

startService:

通常在AndroidManifest文件中声明完Service后,应用组件可以通过Context.startService这个方法传入Intent,启动意图Service;Context中的实现交给了mBase,在前面对Activity的工作流程分析中,分析过mBase的时机就是ContextImpl对象;所以startService的实现都是在ContextImpl中,一系列的实现都是调用startServiceCommon:

    private ComponentName startServiceCommon(Intent service, boolean requireForeground,
            UserHandle user) {
        try {
            // 在LOLLIPOP(5.1)之前会校验intent的getComponent()和package都为空则抛异常
            validateServiceIntent(service);
            service.prepareToLeaveProcess(this);
            // 调用AMS的startService方法
            ComponentName cn = ActivityManager.getService().startService(
                    mMainThread.getApplicationThread(), service,
                    service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
                    getOpPackageName(), getAttributionTag(), user.getIdentifier());
            // ...
            return cn;
        } catch (RemoteException e) {
            // 从捕获的异常也可以知道这里其实是应用进程通过RPC机制,调用AMS的相关方法
            throw e.rethrowFromSystemServer();
        }
    }

ActivityManagerService.startService:

    public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType, boolean requireForeground, String callingPackage,
            String callingFeatureId, int userId)
            throws TransactionTooLargeException {
        // ...
        synchronized(this) {
            // 保存调用进程的pid,uid
            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;
        }
    }

mService是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 {
        // ...
        // 查询传入的intent对应Service记录
        // 如果没有找到,则通过PMS去找
        ServiceLookupResult res =
            retrieveServiceLocked(service, null, resolvedType, callingPackage,
                    callingPid, callingUid, userId, true, callerFg, false, false);
        if (res == null) {
            return null;
        }
        // 如果对应的Service记录没有找到
        // 1.没有权限
        // 2.对应的service就是对外暴露的
        if (res.record == null) {
            return new ComponentName("!", res.permission != null
                    ? res.permission : "private to package");
        }
				// 和之前的ActivityRecord类似,这个结构体代表着一个应用Service
        ServiceRecord r = res.record;
				// ...
        // 省略复杂的校验逻辑,延迟启动等逻辑
        // 启动Service的核心
      	// smap是一个handler对象,Service的延迟启动也就是通过这个Handler
        // 发送一个延迟消息,等时机到了,再调用startServiceInnerLocked
        ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
        // ...
        return cmp;
    }

startServiceInnerLocked实现如下:

    ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
            boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
        // 一些tracker工作
        String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
        if (error != null) {
            return new ComponentName("!!", error);
        }
        // ...
        return r.name;
    }

bringUpServiceLocked中关于Service启动的核心逻辑在后半段:

        // 判断service是否在独立进程中
				final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
        // 获取service想要运行的进程的processName
        final String procName = r.processName;
        HostingRecord hostingRecord = new HostingRecord("service", r.instanceName);
        ProcessRecord app;
				// 
        if (!isolated) {
            // 获取App的进程记录
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
            if (app != null && app.thread != null) {
                try {
                    // 把Service所声明的packageName添加到进程记录中
                    app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
                    // 真正启动Service,和Activity类似,到了realXXXLocked,
                    // 快看到AMS通知应用进程ActivityThread干活的时机了
                    realStartServiceLocked(r, app, execInFg);
                    // 如果启动成功,这里就直接return了
                    return null;
        } else {
            // 如果Service声明需要在独立的进程运行
            app = r.isolatedProc;
            // ...
            // 创建HostingRecord对象,指定其mHostingZygote字段为APP_ZYGOTE(int值2)
            if ((r.serviceInfo.flags & ServiceInfo.FLAG_USE_APP_ZYGOTE) != 0) {
                hostingRecord = HostingRecord.byAppZygote(r.instanceName, r.definingPackageName,
                        r.definingUid);
            }
        }

        // 如果Service对应的App进程还没有被创建,会先记录这个Service,
        // 然后等Service要求的进程启动之后,再去启动这个Service
        if (app == null && !permissionsReviewRequired) {
            // 而新进程的启动,和Activity涉及到新进程启动是一样的。
            if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                    hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, false, isolated, false)) == null) {
                // ...
            }
            if (isolated) {
                r.isolatedProc = app;
            }
        }
        // ...
        // 到这里,这个ServiceRecord记录其实还没有被启动,那么就添加到mPendingServices这个list中
        // 等到了新进程的attachApplicationLocked的时候,会去取出mPendingServices
        // 再次调用realStartServiceLocked,完成Service的启动。
        if (!mPendingServices.contains(r)) {
            mPendingServices.add(r);
        }
				// ...
        return null;
    }

其实通过前面对Activity启动流程的分析,我们这里也能大概猜到realStartServiceLocked中做的事儿其实就是发送事务给应用进程,进行Service的创建和启动:

// 我们关心的核心代码:
app.thread.scheduleCreateService(r, r.serviceInfo,
	mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
	app.getReportedProcState());

app是IApplicationThread,thread是IActivityThread,实现都是在应用进程中,那么应用进程的ActivityThread中,scheduleCreateService做的事儿就是创建一个包含了要创建的Service的信息的CreateServiceData对象,然后发送一个消息给H:

sendMessage(H.CREATE_SERVICE, s);
--> H这个Handler的handlerMessage中对CREATE_SERVICE这条消息的处理
handleCreateService

handleCreateService的实现如下:

    private void handleCreateService(CreateServiceData data) {
        // LoadedApk是当前进程的一些信息封装
        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
        try {
						// 创建Service的context对象
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            // 如果还没有Application对象,创建Application对象
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            // 获取应用进程的ClassLoader
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            // loadClass(data.info.name).newInstance,Service对象就创建出来了
            service = packageInfo.getAppFactory()
                    .instantiateService(cl, data.info.name, data.intent);
            // 将应用进程的ResourceLoader都添加给Service
            context.getResources().addLoaders(
                    app.getResources().getLoaders().toArray(new ResourcesLoader[0]));
            context.setOuterContext(service);
            // attch还能做啥...
            // 将上面创建的contextImpl对象赋值给Service的mBase字段
            // 完成比如ActivityThread,Application对象的赋值,还有AMS也传给了Service
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
            // 执行Service的onCreate回调
            service.onCreate();
            // 将这个启动的service放入进程的mService记录中
            mServices.put(data.token, service);
            try {
                // 通知AMS,service创建完了,恢复一下Binder的id等工作
                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);
            }
        }
    }

至此,Service的启动就算是完成了,可以看到,大体工作和Activity其实极为相似,而我们也可以看到一些经常被“谈论”的问题,service的onCreate是执行在应用进程的主线程的(H这个Handler关联的不就是ActivityThread所谓主线程的Looper么,handleCreateService当然是执行在主线程),所以Service不等于子线程。

再者,Service的启动流程和Activity实在是有太多相似(一致)的地方,怪不得,有一种说法称Service其实是一种无界面的Activity😹,也是能嗅到很多相似的味道的。