Android Service原理分析之startService(一)

萝らか妹 提交于 2020-12-19 06:28:05

1. Service概述

Service作为Android四大组件之一,在开发过程中非常常用,它虽然没有ui,但是同样可以在后台做很多重要的事情,我们平时使用启动service主要通过startService以及bindService来启动service以便已经相关操作。本文将介绍startService的原理,后续将分别介绍bindService的原理,以及在Android O上对service的新增限制管控。
注:本文基于Android 8.1
2. Service分类

    从启动方式上,可以分别通过startService以及bindService启动,两者之间最重要的区别在于bindService可以建立binder连接,更加方便通信。
    从运行方式上,可以分为前台service(foregroundService,下面简称fg-service)与后台service,两者的区别在于有前台service的进程对应的优先级会更高,不容易被系统清理掉,但是前台service需要在通知栏里面显示一个常驻的通知。

3. startService时序图

startService的启动大致分为三种情况:

    对应进程不存在(先启动进程然后启动service并执行onCreate和onStartCommand)
    进程存在但是service不存在(启动service并执行onCreate和onStartCommand)
    进程和service都存在(只执行onStartCommand)

上面的时序图主要针对进程存在,但是service不存在的情况,其他两种在主要流程上没有太大区别,关键在于其中有一些特殊判断,在文章过程中也会提到。
4. 源码解析
4.1 ContextImpl.startService

    public ComponentName startService(Intent service) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, false, mUser);
    }
    
        public ComponentName startForegroundService(Intent service) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, true, mUser);
    }
    // 最终的入口都在这个方法中
    // foreground service只是传参requireForeground为true,普通service为false
    private ComponentName startServiceCommon(Intent service, boolean requireForeground,
            UserHandle user) {
        try {
            validateServiceIntent(service);
            service.prepareToLeaveProcess(this);
            // binder call至ams
            ComponentName cn = ActivityManager.getService().startService(
                mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                            getContentResolver()), requireForeground,
                            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());
                } else if (cn.getPackageName().equals("?")) {
                    throw new IllegalStateException(
                            "Not allowed to start service " + service + ": " + cn.getClassName());
                }
            }
            return cn;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

   

最终通过startServiceCommon调用至ams,注意这里返回值有进行特殊处理,然后抛出了一些异常,主要返回值的component的packageName有"!","!!","?"三种,后面在介绍源码过程中可以看到具体是哪里会返回这些异常。
"!":权限校验没通过,不允许启动
"!!":无法启动
"?":不允许启动
4.2 ActivityManagerService.startService

    public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType, boolean requireForeground, String callingPackage, int userId)
            throws TransactionTooLargeException {
        enforceNotIsolatedCaller("startService");
        // 进行一些简单的校验
        if (service != null && service.hasFileDescriptors() == true) {
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }
        // callingPackage不能为空
        if (callingPackage == null) {
            throw new IllegalArgumentException("callingPackage cannot be null");
        }
        synchronized(this) {
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            ComponentName res;
            try {
                // mService正是ActiveServices对象
                res = mServices.startServiceLocked(caller, service,
                        resolvedType, callingPid, callingUid,
                        requireForeground, callingPackage, userId);
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
            return res;
        }
    }


这块只是简单校验之后,就调用到了ActiveServices.startServiceLocked。
参数解析:
caller:发起startService的进程对应的IApplicationThread对象
service:要启动的service的intent
resolvedType:service类型,启动的时候可以设置data已经schema等
requireForeground:是否发起启动foregroundService
callingPackage:发起startService的进程的packageName
userId:当前用户id
4.3 ActiveServices.startServiceLocked

    ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
            throws TransactionTooLargeException {
        final boolean callerFg;
        // 获取发起binder call的caller进程,如果不存在则抛异常
        if (caller != null) {
            final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
            if (callerApp == null) {
                throw new SecurityException(
                        "Unable to find app for caller " + caller
                        + " (pid=" + callingPid
                        + ") when starting service " + service);
            }
            // 根据当前这个进程所处的调度环境判断是前台还是后台
            callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
        } else {
            callerFg = true;
        }
        // 拿到要启动的service的信息
        // 主要是从packageManagerService中查询,然后缓存起来
        // 其中还进行了一些权限的校验,4.4小节详细介绍
        ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType, callingPackage,
                    callingPid, callingUid, userId, true, callerFg, false);
        // 没有查到要启动的service,直接return了
        if (res == null) {
            return null;
        }
        // 这里就能看到前面提到的返回component的package为“!”的情况了
        // 原因是没有对应的servicerecord,没有的原因会在下面4.4小节中进一步介绍
        if (res.record == null) {
            return new ComponentName("!", res.permission != null
                    ? res.permission : "private to package");
        }
        // 拿到要启动的serviceRecord,这个就是我们在manifest中注册的service组件对应在系统中封装起来的对象
        ServiceRecord r = res.record;
        // 判断user是否存在
        if (!mAm.mUserController.exists(r.userId)) {
            return null;
        }
        // 是否要启动fg-service
        if (!r.startRequested && !fgRequired) {
            // 这块是校验如果要启动的service是一个后台service
            // 那么需要看是否拥有后台启动的权限,不允许就无法后台启动
            final int allowed = mAm.getAppStartModeLocked(r.appInfo.uid, r.packageName,
                    r.appInfo.targetSdkVersion, callingPid, false, false);
            if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
                // 新升级到O的应用可能会遇到这问题,因为不允许后台情况下的app启动后台service
                Slog.w(TAG, "Background start not allowed: service "
                        + service + " to " + r.name.flattenToShortString()
                        + " from pid=" + callingPid + " uid=" + callingUid
                        + " pkg=" + callingPackage);
                if (allowed == ActivityManager.APP_START_MODE_DELAYED) {
                    return null;
                }
                // 不允许启动,此处封装component的packageName为“?”,对应前面提到的,会抛出相关异常
                UidRecord uidRec = mAm.mActiveUids.get(r.appInfo.uid);
                return new ComponentName("?", "app is in background uid " + uidRec);
            }
        }
        ...
        // 如果这个service正在调度重启,那么取消重启,因为马上要启动了
        if (unscheduleServiceRestartLocked(r, callingUid, false)) {
            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "START SERVICE WHILE RESTART PENDING: " + r);
        }
        r.lastActivity = SystemClock.uptimeMillis();
        r.startRequested = true;
        r.delayedStop = false;
        r.fgRequired = fgRequired;
        r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                service, neededGrants, callingUid));
        final ServiceMap smap = getServiceMapLocked(r.userId);
        boolean addToStarting = false;
        // 如果调用者在后台,且不是启动的前台service,判断是否需要delay
        if (!callerFg && !fgRequired && r.app == null
                && mAm.mUserController.hasStartedUserState(r.userId)) {
            ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
            if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) {
                if (r.delayed) {
                    return r.name;
                }
                if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
                    smap.mDelayedStartList.add(r);
                    r.delayed = true;
                    return r.name;
                }
                addToStarting = true;
            } else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
                addToStarting = true;
            }
        }
        ...
        // 准备启动service了
        ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
        return cmp;
    }

 
小结:

    校验caller
    拿到serviceRecord,进一步校验
    校验是否有可以后台启动
    是否需要delay
    startServiceInnerLocked

4.4 ActiveServices.retrieveServiceLocked

    private ServiceLookupResult retrieveServiceLocked(Intent service,
            String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
            boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal) {
        ServiceRecord r = null;
        // 获取user
        userId = mAm.mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
                ActivityManagerService.ALLOW_NON_FULL_IN_PROFILE, "service", null);
        // 根据userId获取ServiceMap
        // 有一个user为key,ServiceMap为v的map,保存了所有的service信息
        // 每个user对应一个
        // ServiceMap是一个handler对象,用的looper是ActivityManager线程
        // 其中主要保存的都是存放service的各map,以不同的方式存储的Servicerecord
        ServiceMap smap = getServiceMapLocked(userId);
        final ComponentName comp = service.getComponent();
        // 通过component从ServiceMap查询
        if (comp != null) {
            r = smap.mServicesByName.get(comp);
        }
        ...
        if (r == null) {
            try {
                // 如果没能查到,那需要从PackageManager去查询了
                ResolveInfo rInfo = mAm.getPackageManagerInternalLocked().resolveService(service,
                        resolvedType, ActivityManagerService.STOCK_PM_FLAGS
                                | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                        userId, callingUid);
                ServiceInfo sInfo =
                    rInfo != null ? rInfo.serviceInfo : null;
                if (sInfo == null) {
                    Slog.w(TAG_SERVICE, "Unable to start service " + service + " U=" + userId +
                          ": not found");
                    return null;
                }
                // 封装ComponentName
                ComponentName name = new ComponentName(
                        sInfo.applicationInfo.packageName, sInfo.name);
                // FLAG_EXTERNAL_SERVICE类型的service必须有人去bind
                // 这块就不贴具体实现了,startService过程中这个逻辑不会走到
                ...

                if (userId > 0) {
                    if (mAm.isSingleton(sInfo.processName, sInfo.applicationInfo,
                            sInfo.name, sInfo.flags)
                            && mAm.isValidSingletonCall(callingUid, sInfo.applicationInfo.uid)) {
                        userId = 0;
                        smap = getServiceMapLocked(0);
                    }
                    sInfo = new ServiceInfo(sInfo);
                    sInfo.applicationInfo = mAm.getAppInfoForUser(sInfo.applicationInfo, userId);
                }
                r = smap.mServicesByName.get(name);
                // 拿到ServiceRecord,如果没有需要新建
                if (r == null && createIfNeeded) {
                    ...
                    // 这块主要就是ServiceRecord对象创建以及放入ServiceMap中
                }
            }
        }
        if (r != null) {
            ...
            // 这块主要是做一些权限校验,包括export(manifest中指定是否允许其他进程启动)
            // 以及自己指定的service权限
            if (!mAm.mIntentFirewall.checkService(r.name, service, callingUid, callingPid,
                    resolvedType, r.appInfo)) {
                return null;
            }
            // 查找成功
            return new ServiceLookupResult(r, null);
        }
        // 没有查找成功返回null
        // 上面一节有提到,如果这里返回null则会再进一步返回到ContextImpl中抛出异常
        return null;
    }

   

这块做了两件事:

    查找ServiceRecord,如果不存在则创建
    权限检查

4.5 ActiveServices.startServiceInnerLocked

    ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
            boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
        ...
        r.callStart = false;
        synchronized (r.stats.getBatteryStats()) {
            r.stats.startRunningLocked();
        }
        // bringUpServiceLocked这个是启动service的核心
        String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
        if (error != null) {
            return new ComponentName("!!", error);
        }
        // 下面主要是进行delay
        if (r.startRequested && addToStarting) {
            boolean first = smap.mStartingBackground.size() == 0;
            smap.mStartingBackground.add(r);
            r.startingBgTimeout = SystemClock.uptimeMillis() + mAm.mConstants.BG_START_TIMEOUT;
            if (first) {
                smap.rescheduleDelayedStartsLocked();
            }
        } else if (callerFg || r.fgRequired) {
            smap.ensureNotStartingBackgroundLocked(r);
        }
        return r.name;
    }

   
这里没做什么事,主要实现都在bringUpServiceLocked
4.6 ActiveServices.bringUpServiceLocked

    private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {
        // 从上面的时序图可以知道sendServiceArgsLocked中主要是要调度执行service的onStartCommand
        // 这里怎么直接就执行了呢?
        // 原因在于判断条件,对于没有执行onCreate的service,r.app是null,所以不会执行这个流程
        // 也就是没有启动过的service不会走这里,只有启动过的service才会
        // 所以对于已经启动过的service,重复startService只会走onStartCommand,就是因为这里,然后return
        if (r.app != null && r.app.thread != null) {
            sendServiceArgsLocked(r, execInFg, false);
            return null;
        }
        // 如果不是调度重启,且已经在restart列表中,return
        // 只有调度重启的地方调用过来whileRestarting为true
        if (!whileRestarting && mRestartingServices.contains(r)) {
            return null;
        }
        // 从restart中移除,因为马上要执行启动了
        if (mRestartingServices.remove(r)) {
            clearRestartingIfNeededLocked(r);
        }
        ...
        // 这中间是一些简单的状态判断,有兴趣可以自己查看源码

        final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
        final String procName = r.processName;
        String hostingType = "service";
        ProcessRecord app;
        if (!isolated) {
            // 进程存在那就直接走真正启动service的逻辑了
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
            if (app != null && app.thread != null) {
                try {
                    app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
                    realStartServiceLocked(r, app, execInFg);
                    return null;
                } catch (TransactionTooLargeException e) {
                    throw e;
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception when starting service " + r.shortName, e);
                }
            }
        } else {
            // isolated进程处理,O上webview进程属于这种类型,加以特殊处理,标记hostingType
            // hostingType主要用于启动进程的时候
            app = r.isolatedProc;
            if (WebViewZygote.isMultiprocessEnabled()
                    && r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {
                hostingType = "webview_service";
            }
        }

        // 进程不存在,那还得先启动进程
        if (app == null && !permissionsReviewRequired) {
            if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                    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;
            }
        }
        ...
        // 因为要启动进程,所以需要记一下这次启动进程的原因是因为需要启动这个service
        // 等到进程启动成功之后,在进程attachApplicationLocked的时候会再去启动这个serivice
        if (!mPendingServices.contains(r)) {
            mPendingServices.add(r);
        }
        return null;
    }

   

小结:

    如果service已经存在那么直接调度sendServiceArgsLocked(将会执行service.onStartCommand)
    处理service重启相关数据结构
    进程存在,则realStartServiceLocked
    进程不存在则先启动进程并把service保存在mPendingServices

4.7 ActiveServices.realStartServiceLocked

    private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
        r.app = app;
        r.restartTime = r.lastActivity = SystemClock.uptimeMillis();

        final boolean newService = app.services.add(r);
        // 这里主要是计算设置service的timeout
        // 因为service的执行是计算在ANR机制中的,这里就是开始计时
        bumpServiceExecutingLocked(r, execInFg, "create");
        mAm.updateLruProcessLocked(app, false, null);
        // 如果是前台service需要更新并记录当前前台serivice的状态
        updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
        // 更新进程优先级
        mAm.updateOomAdjLocked();

        boolean created = false;
        try {
            synchronized (r.stats.getBatteryStats()) {
                r.stats.startLaunchedLocked();
            }
            mAm.notifyPackageUse(r.serviceInfo.packageName,
                                 PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
            // 设置process的状态为start service
            // 这样在更新进程优先级的时候会有对应的处理,其实就是会提升优先级
            app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
            // 到APP的进程中了,执行IApplicationThread.scheduleCreateService
            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;
        } finally {
            if (!created) {
                final boolean inDestroying = mDestroyingServices.contains(r);
                serviceDoneExecutingLocked(r, inDestroying, inDestroying);
                if (newService) {
                    app.services.remove(r);
                    r.app = null;
                }
                if (!inDestroying) {
                    scheduleServiceRestartLocked(r, false);
                }
            }
        }

        if (r.whitelistManager) {
            app.whitelistManager = true;
        }

        requestServiceBindingsLocked(r, execInFg);
        // 更新绑定的activity,这块主要针对bindService
        updateServiceClientActivitiesLocked(app, null, true);
        // 如果需要执行service的start则加入到pendingStarts
        // r.startRequested在startServiceLocked就标记了
        // 且startServiceLocked时就已经加入到pendingStarts
        if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
            r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                    null, null, 0));
        }
        // 这里将会执行service.onStartCommand
        sendServiceArgsLocked(r, execInFg, true);
        ...
        // delay相关
    }

   

小结:

    开始计算service “create”的ANR计时
    调用到app进程创建并执行service的onCreate
    sendServiceArgsLocked

4.8 ActiveServices.sendServiceArgsLocked

    private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
            boolean oomAdjusted) throws TransactionTooLargeException {
        // startServiceLocked时已经加入到pendingStarts
        final int N = r.pendingStarts.size();
        if (N == 0) {
            return;
        }
        ArrayList<ServiceStartArgs> args = new ArrayList<>();
        while (r.pendingStarts.size() > 0) {
            ServiceRecord.StartItem si = r.pendingStarts.remove(0);
            if (si.intent == null && N > 1) {
                continue;
            }
            si.deliveredTime = SystemClock.uptimeMillis();
            r.deliveredStarts.add(si);
            si.deliveryCount++;
            if (si.neededGrants != null) {
                mAm.grantUriPermissionUncheckedFromIntentLocked(si.neededGrants,
                        si.getUriPermissionsLocked());
            }
            mAm.grantEphemeralAccessLocked(r.userId, si.intent,
                    r.appInfo.uid, UserHandle.getAppId(si.callingId));
            // 再次开始ANR的计时,不过此处计时是“start”
            bumpServiceExecutingLocked(r, execInFg, "start");
            if (!oomAdjusted) {
                oomAdjusted = true;
                mAm.updateOomAdjLocked(r.app, true);
            }
            //  O上开始,调用startForegroundService需要5s内调用startForeground
            // 如果调用startForegroundService就处于r.fgRequired
            // 此处是如果发现需要调用startForeground但是没调,则认为超时了
            if (r.fgRequired && !r.fgWaiting) {
                if (!r.isForeground) {
                    scheduleServiceForegroundTransitionTimeoutLocked(r);
                } else {
                    r.fgRequired = false;
                }
            }
            int flags = 0;
            if (si.deliveryCount > 1) {
                flags |= Service.START_FLAG_RETRY;
            }
            if (si.doneExecutingCount > 0) {
                flags |= Service.START_FLAG_REDELIVERY;
            }
            // 创建ServiceStartArgs
            args.add(new ServiceStartArgs(si.taskRemoved, si.id, flags, si.intent));
        }

        ParceledListSlice<ServiceStartArgs> slice = new ParceledListSlice<>(args);
        slice.setInlineCountLimit(4);
        Exception caughtException = null;
        try {
            // 调度到APP进程执行scheduleServiceArgs(将会执行service.onStartCommand)
            r.app.thread.scheduleServiceArgs(r, slice);
        } catch (TransactionTooLargeException e) {
            scheduleServiceArgs
            ...
        }
        // 如果发生了异常需要停掉service
        if (caughtException != null) {
            final boolean inDestroying = mDestroyingServices.contains(r);
            for (int i = 0; i < args.size(); i++) {
                serviceDoneExecutingLocked(r, inDestroying, inDestroying);
            }
            if (caughtException instanceof TransactionTooLargeException) {
                throw (TransactionTooLargeException)caughtException;
            }
        }
    }

   

小结:

    开始service“start”的ANR计时
    创建ServiceStartArgs
    调度到app进程执行service的onStartCommand

4.9 ActivityThread.handleCreateService

    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);
    }
    
public void handleMessage(Message msg) {
switch (msg.what) {
    ...
    case CREATE_SERVICE:
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));
    handleCreateService((CreateServiceData)msg.obj);
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    break;
    ...
}    

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

        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
        try {
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = (Service) cl.loadClass(data.info.name).newInstance();
        } catch (Exception e) {
            if (!mInstrumentation.onException(service, e)) {
                throw new RuntimeException(
                    "Unable to instantiate service " + data.info.name
                    + ": " + e.toString(), e);
            }
        }

        try {
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);
            // 创建application
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            // 执行service attach
            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);
            }
        }
    }
    


app进程中binder线程调度过来之后,发送消息到主线程执行handleCreateService,在handleCreateService中终于看到了我们熟悉的onCreate了
处理完了service的生命周期,还要告诉ams,我处理完了,因为那边还在进行service的ANR计时呢
4.10 ActivityThread.handleServiceArgs

    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) {
                    // 执行service的onStartCommand方法
                    res = s.onStartCommand(data.args, data.flags, data.startId);
                } else {
                    s.onTaskRemoved(data.args);
                    res = Service.START_TASK_REMOVED_COMPLETE;
                }
                // 这里在前面讲解SharedPreferences的时候有提到,是在等待sp的任务写入完成
                QueuedWork.waitToFinish();
                try {
                    ActivityManager.getService().serviceDoneExecuting(
                            data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
                ensureJitEnabled();
            } catch (Exception e) {
                if (!mInstrumentation.onException(s, e)) {
                    throw new RuntimeException(
                            "Unable to start service " + s
                            + " with " + data.args + ": " + e.toString(), e);
                }
            }
        }
    }

   

scheduleServiceArgs中同样是发送消息到app主线程然后执行scheduleServiceArgs
scheduleServiceArgs中执行service.onStartCommand,然后告诉AMS执行完毕
4.11 ActivityManagerService.serviceDoneExecuting

    public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
        synchronized(this) {
            if (!(token instanceof ServiceRecord)) {
                Slog.e(TAG, "serviceDoneExecuting: Invalid service token=" + token);
                throw new IllegalArgumentException("Invalid service token");
            }
            // ActiveSercices.serviceDoneExecutingLocked
            mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
        }
    }

   

4.12 ActiveServices.serviceDoneExecutingLocked

    void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) {
        boolean inDestroying = mDestroyingServices.contains(r);
        if (r != null) {
            if (type == ActivityThread.SERVICE_DONE_EXECUTING_START) {
                r.callStart = true;
                // 这里的res是onStartCommand的返回值
                switch (res) {
                    case Service.START_STICKY_COMPATIBILITY:
                    case Service.START_STICKY: {
                        r.findDeliveredStart(startId, true);
                        r.stopIfKilled = false;
                        break;
                    }
                    case Service.START_NOT_STICKY: {
                        r.findDeliveredStart(startId, true);
                        if (r.getLastStartId() == startId) {
                            r.stopIfKilled = true;
                        }
                        break;
                    }
                    case Service.START_REDELIVER_INTENT: {
                        ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
                        if (si != null) {
                            si.deliveryCount = 0;
                            si.doneExecutingCount++;
                            r.stopIfKilled = true;
                        }
                        break;
                    }
                    case Service.START_TASK_REMOVED_COMPLETE: {
                        r.findDeliveredStart(startId, true);
                        break;
                    }
                    default:
                        throw new IllegalArgumentException(
                                "Unknown service start result: " + res);
                }
                if (res == Service.START_STICKY_COMPATIBILITY) {
                    r.callStart = false;
                }
            } else if (type == ActivityThread.SERVICE_DONE_EXECUTING_STOP) {
                if (!inDestroying) {
                    if (r.app != null) {
                        Slog.w(TAG, "Service done with onDestroy, but not inDestroying: "
                                + r + ", app=" + r.app);
                    }
                } else if (r.executeNesting != 1) {
                    Slog.w(TAG, "Service done with onDestroy, but executeNesting="
                            + r.executeNesting + ": " + r);
                    r.executeNesting = 1;
                }
            }
            final long origId = Binder.clearCallingIdentity();
            serviceDoneExecutingLocked(r, inDestroying, inDestroying);
            Binder.restoreCallingIdentity(origId);
        } else {
            Slog.w(TAG, "Done executing unknown service from pid "
                    + Binder.getCallingPid());
        }
    }

    

    其中的res处理:
    如果是START_STICKY_COMPATIBILITY或者START_STICKY那么如果进程挂掉了,service依旧会重启,很多app会利用这个进行保活。
    在其中的serviceDoneExecutingLocked会把前面的计时消息给remove掉,如果service的生命周期在规定时间内执行完毕,就不会ANR了。

总结

    startService过程中如果进程不存在会创建进程
    service不存在时默认情况下会先执行service的onCreate,再执行service的onStartCommand
    service存在时只会执行service的onStartCommand
    service的onCreate和onStartCommand都会被ANR计时监控,规定时间内没有处理完就会超时
    onStartCommand处理之后还要等待sp写入完毕才会返回ams,所以不适合在onStartCommand中做大量的sp操作,即使是用的是apply异步进行
    onStartCommand的返回值可以控制service是否在进程被kill之后依旧重启service

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!