Comprender el proceso de inicio startService() del Servicio de cuatro componentes (basado en Android10)

1. Información general

El proceso de inicio aprendido en el artículo anterior activitycontinuará analizando startService() el proceso de inicio esta vez. En comparación con las actividades, los servicios pueden proporcionar operaciones de ejecución prolongada en segundo plano sin una interfaz. Incluso después de cambiar a segundo plano, el servicio continúa ejecutándose en segundo plano.

1.1 Tres tipos de servicios

  1. 前台服务Sin interfaz, la barra de notificación debe configurarse (dentro de 5 segundos, si no se llama a startForground(), se lanzará ANR). Acciones que el usuario puede percibir y notar directamente, como usar la reproducción de audio

  2. 后台服务Sin interfaz, acciones que el usuario no notará directamente.

  3. 绑定服务Sin interfaz. En el estado vinculado (similar a la arquitectura C/S), el componente puede interactuar con el servicio en este momento, por ejemplo: Llamada RPC, debe desvincularse para desvincularse, el servicio finalizará. Un servicio puede vincularse a varios componentes. Mientras un componente vincula el servicio, el servicio está en un estado vinculado. El servicio se destruirá solo después de que todos los componentes vinculados se hayan desvinculado.

1.2 Ciclo de vida del servicio

El ciclo de vida de un servicio es el siguiente:

imagen.png

1.3 La diferencia entre startService y bindService

Las distinciones del ciclo de vida se han mostrado en el diagrama del ciclo de vida anterior. El primero se usa para hacer un solo trabajo largo y ejecutarlo solo después del inicio. Este último es adecuado para escenarios de interacción RPC que requieren múltiples llamadas a la interfaz y se enfoca en la interacción.

Aunque se distinguen dos métodos, un servicio puede admitir la operación de vinculación cuando se inicia. Es decir, 同时支持两种方式运行.

1.4 Subclases proporcionadas por los servicios del sistema

  • serviceHerede directamente el servicio, escriba onCreate() y otros métodos opcionales de devolución de llamada del ciclo de vida. Todas las devoluciones de llamada se ejecutan en el hilo principal de forma predeterminada
  • IntentServiceEl objeto handlerThread se encapsula internamente y todas las devoluciones de llamada del ciclo de vida se cambian al subproceso secundario.

1.5 Selección de servicios e hilos

Los servicios son de aplicación general 长时间后台工作, como transacciones de red, reproducción de música, E/S de archivos, etc. Los hilos son adecuados para realizar operaciones que consumen mucho tiempo. Por ejemplo, si un servicio sigue el ciclo de vida de un componente como una actividad, puede seleccionar un subproceso.

La actividad hereda ContextWrapper:

2. StartService() en el lado de la aplicación

2.1 ContextImpl.startService()

ContextWrapper.java

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

    // 前台服务
    @Override
    public ComponentName startForegroundService(Intent service) {
        return mBase.startForegroundService(service);
    }

ContextWrapper内部有代理了 ContextImpl,所以我们看看 ContextImpl的 startService():

2.2 ContextImpl.startService()

ContextImpl.java

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

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

2.2.1 startServiceCommon()


 private ComponentName startServiceCommon(Intent service, boolean requireForeground,
            UserHandle user) {
        try {
            validateServiceIntent(service);
            service.prepareToLeaveProcess(this);
            // 直接调用 AMS的 startService方法 , 返回一个 ComponentName 对象。
            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();
        }
    }

直接调用 AMS的 startService方法 , 返回一个 ComponentName 对象。

三、AMS 端 startService

3.1 startService()

ActivityManagerService.java

 @Override
    public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType, boolean requireForeground, String callingPackage, int userId)
            throws TransactionTooLargeException {
            // requireForeground 是否是前台服务 
        enforceNotIsolatedCaller("startService");
       ...
        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
                "*** startService: " + service + " type=" + resolvedType + " fg=" + requireForeground);
        synchronized(this) {
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            ComponentName res;
            try {
            // 调用  startServiceLocked
                res = mServices.startServiceLocked(caller, service,
                        resolvedType, callingPid, callingUid,
                        requireForeground, callingPackage, userId);
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
            return res;
        }
    }

调用 ActiveServices的 startServiceLocked()。

allowBackgroundActivityStarts属性传入false,再内部继续调用同名的方法startServiceLocked():

3.2 ActiveServices.startServiceLocked()

ActiveServices.java

ActiveServices 是系统用来管理服务的类。内部有一系列的集合list,用来存储ServiceRecord 对象。 也就是系统所有的service都由 ActiveServices 来管理。

 ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired, String callingPackage,
            final int userId, boolean allowBackgroundActivityStarts)
            throws TransactionTooLargeException {
            
            // fgRequired 是否是前台服务 
            //  allowBackgroundActivityStarts 为false。
            
            
            final boolean callerFg;
            // 获取当前进程对象 ProcessRecord 
            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;
            }
            
            // 内部通过PMS解析得到 serviceRecord 对象信息 
            ServiceLookupResult res =
            retrieveServiceLocked(service, null, resolvedType, callingPackage,
                    callingPid, callingUid, userId, true, callerFg, false, false);
            if (res == null) {
                return null;
            }
            if (res.record == null) {
                return new ComponentName("!", res.permission != null
                        ? res.permission : "private to package");
            }
        
       ServiceRecord r = res.record;
    
            // ...
        // 继续启动服务
        ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
        return cmp;

}

retrieveServiceLocked()方法内部最终通过PMS来解析得到 ServiceRecord对象,返回ServiceLookupResult。ServiceLookupResult 内部封装了 ServiceRecord 对象。

3.2.1 startServiceInnerLocked()

ActiveServices.java

ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
            boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
        ServiceState stracker = r.getTracker();
        if (stracker != null) {
            stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
        }
        r.callStart = false;
        StatsLog.write(StatsLog.SERVICE_STATE_CHANGED, r.appInfo.uid, r.name.getPackageName(),
                r.name.getClassName(), StatsLog.SERVICE_STATE_CHANGED__STATE__START);
        synchronized (r.stats.getBatteryStats()) {
            r.stats.startRunningLocked();
        }
        // 继续调用
        String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
        
        if (error != null) {
            return new ComponentName("!!", error);
        }

        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;
    }

3.2.2 bringUpServiceLocked()

ActiveServices.java

 private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {
        if (r.app != null && r.app.thread != null) {
            // 1 调用 service.onStartCommand()
            sendServiceArgsLocked(r, execInFg, false);
            return null;
        }

        if (!whileRestarting && mRestartingServices.contains(r)) {
            // If waiting for a restart, then do nothing.
            return null;
        }

       //...

        // We are now bringing the service up, so no longer in the
        // restarting state.
        if (mRestartingServices.remove(r)) {
            clearRestartingIfNeededLocked(r);
        }

        // Make sure this service is no longer considered delayed, we are starting it now.
        if (r.delayed) {
             
            getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
            r.delayed = false;
        }

        // Make sure that the user who owns this service is started.  If not,
        // we don't want to allow it to run.
        if (!mAm.mUserController.hasStartedUserState(r.userId)) {
            String msg = "Unable to launch app "
                    + r.appInfo.packageName + "/"
                    + r.appInfo.uid + " for service "
                    + r.intent.getIntent() + ": user " + r.userId + " is stopped";
            Slog.w(TAG, msg);
            bringDownServiceLocked(r);
            return msg;
        }

          //....
        final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
        final String procName = r.processName;
        HostingRecord hostingRecord = new HostingRecord("service", r.instanceName);
        ProcessRecord app;
        // 是否在单独的进程 不在独立进程
        if (!isolated) {
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
               // 如果进程已经启动
            if (app != null && app.thread != null) {
                try {
                    app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
                    
                    // 启动服务 
                    realStartServiceLocked(r, app, execInFg);
                    
                    return null;
                } catch (TransactionTooLargeException e) {
                    throw e;
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception when starting service " + r.shortInstanceName, e);
                }

                // If a dead object exception was thrown -- fall through to
                // restart the application.
            }
        } else {
            // If this service runs in an isolated process, then each time
            // we call startProcessLocked() we will get a new isolated
            // process, starting another process if we are currently waiting
            // for a previous process to come up.  To deal with this, we store
            // in the service any current isolated process it is running in or
            // waiting to have come up.
            app = r.isolatedProc;
            if (WebViewZygote.isMultiprocessEnabled()
                    && r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {
                hostingRecord = HostingRecord.byWebviewZygote(r.instanceName);
            }
            if ((r.serviceInfo.flags & ServiceInfo.FLAG_USE_APP_ZYGOTE) != 0) {
                hostingRecord = HostingRecord.byAppZygote(r.instanceName, r.definingPackageName,
                        r.definingUid);
            }
        }

        // Not running -- get it started, and enqueue this service record
        // to be executed when the app comes up.
        if (app == null && !permissionsReviewRequired) {
            //如果进程没有启动,那么开启进程,等进程拉起后,会调用AMS.attacthApplication(),再次调用 ActiveServices.attachApplicationLocked(),内部再次调用 realStartServiceLocked()
            if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                    hostingRecord, 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;
            }
        }

        if (r.fgRequired) {
            
            mAm.tempWhitelistUidLocked(r.appInfo.uid,
                    SERVICE_START_FOREGROUND_TIMEOUT, "fg-service-launch");
        }

        if (!mPendingServices.contains(r)) {
            mPendingServices.add(r);
        }

        if (r.delayedStop) {
            // Oh and hey we've already been asked to stop!
            r.delayedStop = false;
            if (r.startRequested) {
               
                stopServiceLocked(r);
            }
        }

        return null;
    }
  • 服务如果已经启动过了,则调用 service.onStartCommand()
  • 如果进程存在,则直接调用 realStartServiceLocked() 启动服务
  • 如果进程不存在,那么久拉起进程。等进程拉起后,会调用AMS.attacthApplication(),内部调用 ActiveServices.attachApplicationLocked(),内部再次调用 realStartServiceLocked()

因此,我们继续看 realStartServiceLocked():

3.2.3 realStartServiceLocked()

/Users/avengong/Library/Android/sdk/sources/android-29/com/android/server/am/ActiveServices.java

注意: 不要被startService开头的方法名字迷惑了。这里的start意思是 拉起app端的service 实例。bindService()启动方式也会调用到这里。

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

        final boolean newService = app.services.add(r);
        // 发送ANR 检测消息 
        bumpServiceExecutingLocked(r, execInFg, "create");
        // 更新AMS中的 processRecord Lru集合
        mAm.updateLruProcessLocked(app, false, null);
        updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
        mAm.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_START_SERVICE);

        boolean created = false;
        try {
            ...
         
            synchronized (r.stats.getBatteryStats()) {
                r.stats.startLaunchedLocked();
            }
            mAm.notifyPackageUse(r.serviceInfo.packageName,
                                 PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
            app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
            // 执行 服务的onCreate() 流程
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
                    app.getReportedProcState());
            r.postNotification();
            // 至此,表示系统侧的 service 创建完毕。 
            created = true;
            
        } catch (DeadObjectException e) {
            Slog.w(TAG, "Application dead when creating service " + r);
            mAm.appDiedLocked(app);
            throw e;
        } finally {
            if (!created) {
                // Keep the executeNesting count accurate.
                final boolean inDestroying = mDestroyingServices.contains(r);
                serviceDoneExecutingLocked(r, inDestroying, inDestroying);

                // Cleanup.
                if (newService) {
                    app.services.remove(r);
                    r.setProcess(null);
                }

                // Retry. 如果没有启动,会再次尝试
                if (!inDestroying) {
                    scheduleServiceRestartLocked(r, false);
                }
            }
        }

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

        requestServiceBindingsLocked(r, execInFg);

        updateServiceClientActivitiesLocked(app, null, true);

        if (newService && created) {
            app.addBoundClientUidsOfNewService(r);
        }

        // If the service is in the started state, and there are no
        // pending arguments, then fake up one so its onStartCommand() will
        // be called.
        if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
            r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                    null, null, 0));
        }
        // 回调onStartCommand()方法 
        sendServiceArgsLocked(r, execInFg, true);

        if (r.delayed) {
          
            getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
            r.delayed = false;
        }

        if (r.delayedStop) {
            // Oh and hey we've already been asked to stop!
            r.delayedStop = false;
            if (r.startRequested) {
                   
                stopServiceLocked(r);
            }
        }
    }
  • 发送ANR延迟检测消息
  • 执行onCreate()流程,回调App端 scheduleCreateService()
  • 执行onStartCommand()流程

3.2.4 bumpServiceExecutingLocked(r, execInFg, "create")

ActiveServices.java

private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
    // ... 
    boolean timeoutNeeded = true;
    if ((mAm.mBootPhase < SystemService.PHASE_THIRD_PARTY_APPS_CAN_START)
            && (r.app != null) && (r.app.pid == android.os.Process.myPid())) {

        timeoutNeeded = false;
    }

    long now = SystemClock.uptimeMillis();
    if (r.executeNesting == 0) {
        r.executeFg = fg;
        ServiceState stracker = r.getTracker();
        if (stracker != null) {
            stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now);
        }
        if (r.app != null) {
            r.app.executingServices.add(r);
            r.app.execServicesFg |= fg;
            if (timeoutNeeded && r.app.executingServices.size() == 1) {
                scheduleServiceTimeoutLocked(r.app);
            }
        }
    } else if (r.app != null && fg && !r.app.execServicesFg) {
        r.app.execServicesFg = true;
        // 发送超时ANR检测消息
        if (timeoutNeeded) {
            scheduleServiceTimeoutLocked(r.app);
        }
    }
    r.executeFg |= fg;
    r.executeNesting++;
    r.executingStart = now;
}

3.2.5 ActiveServices.scheduleServiceTimeoutLocked()

ActiveServices.java


void scheduleServiceTimeoutLocked(ProcessRecord proc) {
    if (proc.executingServices.size() == 0 || proc.thread == null) {
        return;
    }
    Message msg = mAm.mHandler.obtainMessage(
            ActivityManagerService.SERVICE_TIMEOUT_MSG);
    msg.obj = proc;
    mAm.mHandler.sendMessageDelayed(msg,
            proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
}
  • 如果超时还没有移除这个消息,那么就判定为启动service ANR了,执行SERVICE_TIMEOUT_MSG消息逻辑,内部会调用ActiveServices.serviceTimeout() 方法。
  • 前台服务超时时间:SERVICE_TIMEOUT=10s
  • 后天服务超时时间:200s

3.2.6 ActiveServices.serviceTimeout()

ActiveServices.java

void serviceTimeout(ProcessRecord proc) {
    String anrMessage = null;
    synchronized(mAm) {
        ...
        final long now = SystemClock.uptimeMillis();
        final long maxTime =  now -
                (proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
        ServiceRecord timeout = null;
        long nextTime = 0;
        for (int i=proc.executingServices.size()-1; i>=0; i--) {
            ServiceRecord sr = proc.executingServices.valueAt(i);
            if (sr.executingStart < maxTime) {
                timeout = sr;
                break;
            }
            if (sr.executingStart > nextTime) {
                nextTime = sr.executingStart;
            }
        }
        if (timeout != null && mAm.mProcessList.mLruProcesses.contains(proc)) {
            Slog.w(TAG, "Timeout executing service: " + timeout);
            StringWriter sw = new StringWriter();
            PrintWriter pw = new FastPrintWriter(sw, false, 1024);
            pw.println(timeout);
            timeout.dump(pw, "    ");
            pw.close();
            mLastAnrDump = sw.toString();
            mAm.mHandler.removeCallbacks(mLastAnrDumpClearer);
            mAm.mHandler.postDelayed(mLastAnrDumpClearer, LAST_ANR_LIFETIME_DURATION_MSECS);
            anrMessage = "executing service " + timeout.shortInstanceName;
        } else {
            Message msg = mAm.mHandler.obtainMessage(
                    ActivityManagerService.SERVICE_TIMEOUT_MSG);
            msg.obj = proc;
            mAm.mHandler.sendMessageAtTime(msg, proc.execServicesFg
                    ? (nextTime+SERVICE_TIMEOUT) : (nextTime + SERVICE_BACKGROUND_TIMEOUT));
        }
    }
    // 直接执行app的 ANR 流程 
    if (anrMessage != null) {
        proc.appNotResponding(null, null, null, null, false, anrMessage);
    }
}

如果发生ANR,则直接执行app的 ANR 流程,具体怎么执行后续再分析~

疑问,既然发送了ANR判定消息,那么什么时候去移除这个消息呢?

答:在app端创建完service后,会再次告知AMS端执行完成。 这里先看app端如何处理。

四、App 端 scheduleCreateService()

AMS通过Binder跨进程调用到app端,接收的对象为 ActivityThread的静态内部类 ApplicationThread。我们先看onCreate()执行流程。

4.1 ApplicationThread.scheduleCreateService

ActivityThread.java

 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);
        }
  • IBinder token: 对应 ServiceRecord
  • ServiceInfo info:服务信息
  • CompatibilityInfo compatInfo:
  • int processState:进程状态

发送了CREATE_SERVICE一个消息到主线程。

4.2 H.CREATE_SERVICE 消息

ActivityThread.java

 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;

4.3 ActivityThread.handleCreateService()

ActivityThread.java

private void handleCreateService(CreateServiceData data) {
        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        unscheduleGcIdler();
        // LoadedApk 表示已安装的apk的所有信息
        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
        try {
            ///  反射 service实例
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = packageInfo.getAppFactory()
                    .instantiateService(cl, data.info.name, data.intent);
        }
        //...

        try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
            // 创建service 的context 对象
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);
            
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            // attach app信息到service
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
            // 调用 service的 onCreate()方法
            service.onCreate();
            // 把token作为key,存入到 mServices map中
            mServices.put(data.token, service);
            
            try {
                // 告知 AMS service已经启动完毕 
                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 实例对象
  • 创建context,并且attach到service
  • 调用service的onCreate()方法
  • 调用 serviceDoneExecuting() 通知AMS,service已经启动完毕,注意传入的是 SERVICE_DONE_EXECUTING_ANON = 0

五、AMS端 serviceDoneExecuting()

ActivityManagerService.java

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");
        }
        mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
    }
}

调用了 ActiveServices 的方法:

5.1 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) {
          ...
        } else if (type == ActivityThread.SERVICE_DONE_EXECUTING_STOP) {
          ...
        }
        final long origId = Binder.clearCallingIdentity();
        // 继续调用方法
        serviceDoneExecutingLocked(r, inDestroying, inDestroying);
        Binder.restoreCallingIdentity(origId);
    } else {
        Slog.w(TAG, "Done executing unknown service from pid "
                + Binder.getCallingPid());
    }
}

5.2 serviceDoneExecutingLocked()

ActiveServices.java

private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
        boolean finishing) {
    
    r.executeNesting--;
    if (r.executeNesting <= 0) {
        if (r.app != null) {
            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
                    "Nesting at 0 of " + r.shortInstanceName);
            r.app.execServicesFg = false;
            r.app.executingServices.remove(r);
            if (r.app.executingServices.size() == 0) {
                // 移除 ANR超时消息 
                mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
            } else if (r.executeFg) {
                // Need to re-evaluate whether the app still needs to be in the foreground.
                for (int i=r.app.executingServices.size()-1; i>=0; i--) {
                    if (r.app.executingServices.valueAt(i).executeFg) {
                        r.app.execServicesFg = true;
                        break;
                    }
                }
            }
            if (inDestroying) {
                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
                        "doneExecuting remove destroying " + r);
                mDestroyingServices.remove(r);
                r.bindings.clear();
            }
            mAm.updateOomAdjLocked(r.app, true, OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
        }
        r.executeFg = false;
        if (r.tracker != null) {
            final int memFactor = mAm.mProcessStats.getMemFactorLocked();
            final long now = SystemClock.uptimeMillis();
            r.tracker.setExecuting(false, memFactor, now);
            r.tracker.setForeground(false, memFactor, now);
            if (finishing) {
                r.tracker.clearCurrentOwner(r, false);
                r.tracker = null;
            }
        }
        if (finishing) {
            if (r.app != null && !r.app.isPersistent()) {
                r.app.services.remove(r);
                r.app.updateBoundClientUids();
                if (r.whitelistManager) {
                    updateWhitelistManagerLocked(r.app);
                }
            }
            r.setProcess(null);
        }
    }
}

整个流程:

  1. app端开始发起启动服务请求,发往AMS。
  2. AMS端执行创建serviceRecord,同时发送一个ANR延迟消息。通知app端可以创建service。
  3. El lado de la aplicación crea el servicio, ejecuta onCreate(), vuelve a notificar al lado de AMS y elimina el mensaje ANR.

Hasta ahora, el total onCreate()流程执行完毕.

Recuerde el método realStartServiceLocked() en el resumen de 3.2.3 en el lado de AMS, después de ejecutar onCreate() internamente, llamará sendServiceArgsLocked()para ejecutar el onStartCommand()método:

5.3 enviarArgsServicioBloqueados()

private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
        boolean oomAdjusted) throws TransactionTooLargeException {
    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 (DEBUG_SERVICE) {
            Slog.v(TAG_SERVICE, "Sending arguments to: "
                    + r + " " + r.intent + " args=" + si.intent);
        }
        if (si.intent == null && N > 1) {
            // If somehow we got a dummy null intent in the middle,
            // then skip it.  DO NOT skip a null intent when it is
            // the only one in the list -- this is to support the
            // onStartCommand(null) case.
            continue;
        }
        si.deliveredTime = SystemClock.uptimeMillis();
        r.deliveredStarts.add(si);
        si.deliveryCount++;
        if (si.neededGrants != null) {
            mAm.mUgmInternal.grantUriPermissionUncheckedFromIntent(si.neededGrants,
                    si.getUriPermissionsLocked());
        }
        mAm.grantEphemeralAccessLocked(r.userId, si.intent, UserHandle.getAppId(r.appInfo.uid),
                UserHandle.getAppId(si.callingId));
        bumpServiceExecutingLocked(r, execInFg, "start");
        if (!oomAdjusted) {
            oomAdjusted = true;
            mAm.updateOomAdjLocked(r.app, true, OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
        }
        if (r.fgRequired && !r.fgWaiting) {
            if (!r.isForeground) {
                if (DEBUG_BACKGROUND_CHECK) {
                    Slog.i(TAG, "Launched service must call startForeground() within timeout: " + r);
                }
                scheduleServiceForegroundTransitionTimeoutLocked(r);
            } else {
                if (DEBUG_BACKGROUND_CHECK) {
                    Slog.i(TAG, "Service already foreground; no new timeout: " + r);
                }
                r.fgRequired = false;
            }
        }
        int flags = 0;
        if (si.deliveryCount > 1) {
            flags |= Service.START_FLAG_RETRY;
        }
        if (si.doneExecutingCount > 0) {
            flags |= Service.START_FLAG_REDELIVERY;
        }
        args.add(new ServiceStartArgs(si.taskRemoved, si.id, flags, si.intent));
    }

    ParceledListSlice<ServiceStartArgs> slice = new ParceledListSlice<>(args);
    slice.setInlineCountLimit(4);
    Exception caughtException = null;
    try {
        // 执行 scheduleServiceArgs(),最终调用 onStartCommand()方法。
        r.app.thread.scheduleServiceArgs(r, slice);
    } catch (TransactionTooLargeException e) {
        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Transaction too large for " + args.size()
                + " args, first: " + args.get(0).args);
        Slog.w(TAG, "Failed delivering service starts", e);
        caughtException = e;
    } catch (RemoteException e) {
        // Remote process gone...  we'll let the normal cleanup take care of this.
        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while sending args: " + r);
        Slog.w(TAG, "Failed delivering service starts", e);
        caughtException = e;
    } catch (Exception e) {
        Slog.w(TAG, "Unexpected exception", e);
        caughtException = e;
    }

    if (caughtException != null) {
        // Keep nesting count correct
        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;
        }
    }
}

Ejecute scheduleServiceArgs()y finalmente llame al método onStartCommand().

5. ScheduleServiceArgs() en el lado de la aplicación

public final void scheduleServiceArgs(IBinder token, ParceledListSlice args) {
    List<ServiceStartArgs> list = args.getList();

    for (int i = 0; i < list.size(); i++) {
        ServiceStartArgs ssa = list.get(i);
        ServiceArgsData s = new ServiceArgsData();
        s.token = token;
        s.taskRemoved = ssa.taskRemoved;
        s.startId = ssa.startId;
        s.flags = ssa.flags;
        s.args = ssa.args;
        // 发送消息 SERVICE_ARGS
        sendMessage(H.SERVICE_ARGS, s);
    }
}

HCuando se recibe el SERVICE_ARGSmensaje , handleServiceArgs()se llama al método:

5.1 mensaje handleServiceArgs()

private void handleServiceArgs(ServiceArgsData data) {
// 从map中获取 service对象
    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) {
                 // 调用 onStartCommand() 
                res = s.onStartCommand(data.args, data.flags, data.startId);
            } else {
                s.onTaskRemoved(data.args);
                res = Service.START_TASK_REMOVED_COMPLETE;
            }

            QueuedWork.waitToFinish();

            try {
            // 通知AMS start阶段完成
                ActivityManager.getService().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(s, e)) {
                throw new RuntimeException(
                        "Unable to start service " + s
                        + " with " + data.args + ": " + e.toString(), e);
            }
        }
    }
}
  • Se llama al método onStartCommand(), y el método onStart() se llama internamente (obsoleto)
  • Notifique a AMS que la fase de inicio está completa. Finalmente, en el lado de AMS, se llamará a serviceDoneExecuting() y serviceDoneExecutingLocked() se llamará internamente, la misma lógica que antes.

5.1.1 Comando de servicio al iniciar

Servicio.java

public @StartResult int onStartCommand(Intent intent, @StartArgFlags int flags, int startId) {
    //调用onStart() 方法。
    onStart(intent, startId);
    return mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY;
}

onStartCommand()y onStart()también se llaman. En este punto, el serviceinicio está completo.

6. Resumen

Un breve resumen de todo el proceso:

  1. El lado de la aplicación inicia una solicitud de inicio de servicio al lado de AMS
  2. El lado AMS ejecuta la creación de serviceRecord y envía un mensaje de retraso ANR al mismo tiempo. Notifique a la aplicación que se puede crear el servicio y luego llame al método onStartCommand()
  3. El lado de la aplicación crea el servicio, ejecuta onCreate(), vuelve a notificar al lado de AMS y elimina el mensaje ANR. Posteriormente, se procesa el método onStartCommand() y se notifica nuevamente al AMS para que elimine el mensaje ANR.

Supongo que te gusta

Origin juejin.im/post/7116830797562118158
Recomendado
Clasificación