文档章节

Android Service原理分析之startService(一)

天王盖地虎626
 天王盖地虎626
发布于 06/20 18:51
字数 3894
阅读 8
收藏 1

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

 

本文转载自:https://blog.csdn.net/u011733869/article/details/84001744

天王盖地虎626

天王盖地虎626

粉丝 32
博文 527
码字总数 20708
作品 0
南京
私信 提问
android基础知识05:四大组件之service 01

本文主要介绍service相关内容。包括两篇文章: android基础知识05:四大组件之service 01 android基础知识05:四大组件之service 02:远程调用 android基础知识05:四大组件之service 03:实...

迷途d书童
2012/03/23
323
0
Android O 后台startService限制简析

Android O 推出出了Background Execution Limits,减少后台应用内存使用及耗电,一个很明显的应用就是不准后台应用通过startService启动服务,这里有两个问题需要弄清楚,第一:什么状态下s...

看书的小蜗牛
06/04
0
0
startService与bindService的区别

Android执行Service有两种方法,一种是startService,一种是bindService。下面让我们一起来聊一聊这两种执行Service方法的区别。 1、生命周期上的区别 执行startService时,Service会经历onC...

亭子happy
2015/02/08
13.4K
0
Android插件化快速入门与实例解析(VirtualApk)必须了解一下

 集成一个第三方相册功能,只需集成一个插件APK到项目中,无需集成额外代码,并且支持随时更新相册功能,无需发布版本更新,无需AndroidManifest中声明四大组件,这就是插件化。   插件化...

android自学
2018/07/22
0
0
Andriod经典之作(你必须知道 Service 用法)

1、Service的种类 按运行地点分类:应用本地服务(Local)远程服务(Remote) 应用本地服务(Local) 1) 区别:该服务依附在主进程上, 2) 优点:服务依附在主进程上而不是独立的进程,这样在...

rich_xu
2013/11/14
839
2

没有更多内容

加载失败,请刷新页面

加载更多

Jenkins World 贡献者峰会及专家答疑展位

本文首发于:Jenkins 中文社区 原文链接 作者:Marky Jackson 译者:shunw Jenkins World 贡献者峰会及专家答疑展位 本文为 Jenkins World 贡献者峰会活动期间的记录 Jenkins 15周岁啦!Jen...

Jenkins中文社区
33分钟前
8
0
杂谈:面向微服务的体系结构评审中需要问的三个问题

面向微服务的体系结构如今风靡全球。这是因为更快的部署节奏和更低的成本是面向微服务的体系结构的基本承诺。 然而,对于大多数试水的公司来说,开发活动更多的是将现有的单块应用程序转换为...

liululee
48分钟前
7
0
OSChina 周二乱弹 —— 我等饭呢,你是不是来错食堂了?

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @ 自行车丢了:给主编推荐首歌 《クリスマスの夜》- 岡村孝子 手机党少年们想听歌,请使劲儿戳(这里) @烽火燎原 :国庆快来,我需要长假! ...

小小编辑
今天
520
9
玩转 Springboot 2 之热部署(DevTools)

Devtools 介绍 SpringBoot 提供了热部署的功能,那啥是热部署累?SpringBoot官方是这样说的:只要类路径上的文件发生更改,就会自动重新启动应用程序。在IDE中工作时,这可能是一个有用的功能...

桌前明月
今天
6
0
CSS--列表

一、列表标识项 list-style-type none:去掉标识项 disc:默认实心圆 circle:空心圆 squire:矩形 二、列表项图片 list-style-img: 取值:url(路径) 三、列表项位置 list-style-position:...

wytao1995
今天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部