Verstehen Sie den startService() Startprozess des vier Komponenten Service (basierend auf Android10)

1. Übersicht

Der im vorherigen Artikel erlernte Startvorgang wird dieses Mal den Startvorgang activityweiter analysieren . startService() Im Vergleich zu Aktivitäten können Dienste lang andauernde Operationen im Hintergrund ohne Schnittstelle bereitstellen. Auch nach dem Wechsel in den Hintergrund läuft der Dienst im Hintergrund weiter.

1.1 Drei Arten von Diensten

  1. 前台服务Keine Schnittstelle, die Benachrichtigungsleiste muss gesetzt sein (innerhalb von 5s, wenn startForground() nicht aufgerufen wird, wird ANR geworfen). Aktionen, die der Benutzer direkt wahrnehmen und bemerken kann, z. B. die Verwendung der Audiowiedergabe

  2. 后台服务Keine Schnittstelle, Aktionen, die der Benutzer nicht direkt bemerkt.

  3. 绑定服务Keine Schnittstelle. Im gebundenen Zustand (ähnlich der C/S-Architektur) kann die Komponente zu diesem Zeitpunkt mit dem Dienst interagieren, wie z. B.: RPC-Aufruf, muss zum Aufheben der Bindung gelöst werden, der Dienst wird beendet. Ein Dienst kann an mehrere Komponenten gebunden werden.Solange eine Komponente den Dienst bindet, befindet sich der Dienst in einem gebundenenZustand. Der Dienst wird erst zerstört, nachdem alle gebundenen Komponenten gelöst wurden.

1.2 Servicelebenszyklus

Der Lebenszyklus eines Dienstes ist wie folgt:

Bild.png

1.3 Der Unterschied zwischen startService und bindService

Die Unterschiede im Lebenszyklus sind im obigen Lebenszyklusdiagramm dargestellt. Ersteres wird verwendet, um einen langen Einzeljob zu erledigen und ihn nach dem Start alleine auszuführen. Letzteres eignet sich für RPC-Interaktionsszenarien, die mehrere Aufrufe der Schnittstelle erfordern, und konzentriert sich auf die Interaktion.

Obwohl zwei Methoden unterschieden werden, kann ein Dienst die Bindungsoperation unterstützen, wenn er gestartet wird. Das heißt, 同时支持两种方式运行.

1.4 Von Systemdiensten bereitgestellte Unterklassen

  • serviceErben Sie den Dienst direkt, schreiben Sie onCreate() und andere optionale Lifecycle-Callback-Methoden. Alle Rückrufe werden standardmäßig im Hauptthread ausgeführt
  • IntentServiceDas handlerThread-Objekt wird intern gekapselt, und alle Lebenszyklus-Callbacks werden an den untergeordneten Thread geleitet.

1.5 Auswahl von Diensten und Threads

Dienste sind allgemein anwendbar 长时间后台工作, wie Netzwerktransaktionen, Musik abspielen, Datei-I/O usw. Threads eignen sich zur Durchführung zeitaufwändiger Operationen. Wenn beispielsweise ein Dienst dem Lebenszyklus einer Komponente wie einer Aktivität folgt, können Sie einen Thread auswählen.

Aktivität erbt ContextWrapper:

2. StartService() auf der App-Seite

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. Die App-Seite erstellt den Dienst, führt onCreate() aus, benachrichtigt die AMS-Seite erneut und entfernt die ANR-Nachricht.

Soweit das Ganze onCreate()流程执行完毕.

Erinnern Sie sich an die Methode realStartServiceLocked() in der Zusammenfassung von 3.2.3 auf der AMS-Seite, nach der internen Ausführung von onCreate() wird sie aufgerufen sendServiceArgsLocked(), um die onStartCommand()Methode auszuführen:

5.3 sendServiceArgsLocked()

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

Execute scheduleServiceArgs()und rufen Sie schließlich die Methode onStartCommand() auf.

5. ScheduleServiceArgs() auf der App-Seite

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

HSERVICE_ARGSWenn die Nachricht empfangen wird, wird die handleServiceArgs()Methode aufgerufen:

5.1 handleServiceArgs()-Nachricht

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);
            }
        }
    }
}
  • Die Methode onStartCommand() wird aufgerufen, und die Methode onStart() wird intern aufgerufen (veraltet)
  • Benachrichtigen Sie AMS, dass die Startphase abgeschlossen ist. Schließlich wird auf der AMS-Seite serviceDoneExecuting() aufgerufen, und serviceDoneExecutingLocked() wird intern aufgerufen, dieselbe Logik wie zuvor.

5.1.1 Service.onStartCommand

Dienst.java

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

onStartCommand()und onStart()heißen auch. An diesem Punkt ist die serviceInbetriebnahme abgeschlossen.

6. Zusammenfassung

Eine kurze Zusammenfassung des gesamten Prozesses:

  1. Die App-Seite initiiert eine Dienststartanforderung an die AMS-Seite
  2. Die AMS-Seite führt die Erstellung von serviceRecord aus und sendet gleichzeitig eine ANR-Verzögerungsnachricht. Benachrichtigen Sie die App, dass der Dienst erstellt werden kann, und rufen Sie dann die Methode onStartCommand() auf
  3. Die App-Seite erstellt den Dienst, führt onCreate() aus, benachrichtigt die AMS-Seite erneut und entfernt die ANR-Nachricht. Anschließend wird die Methode onStartCommand() verarbeitet und das AMS erneut benachrichtigt, die ANR-Nachricht zu entfernen.

Ich denke du magst

Origin juejin.im/post/7116830797562118158
Empfohlen
Rangfolge