startService startup process---Service has been started

At the end of the Service startup process (startService) , three situations that may exist during the call startServiceare analyzed. This article analyzes the first situation—the Service has been started.

The Service startup process (startService) has already explained that the function will be executed when the Service has been started sendServiceArgsLocked(r, false). Next, we will analyze this function in sections.

private final void sendServiceArgsLocked(ServiceRecord r,
        boolean oomAdjusted) {
    final int N = r.pendingStarts.size();
    if (N == 0) {
        return;
    }  

The key to understanding this part of you is r.pendingStartsthat the system will startServicesave all calls to the Service and have not yet been executed in pendingStartsthe ArrayList data structure. If r.pendingStarts.size()==0, it means that for the Service, all startServicecalls to it have been executed, so there is no need to Continue to execute the following logic.

while (r.pendingStarts.size() > 0) {
    try {
        ServiceRecord.StartItem si = r.pendingStarts.remove(0);
        if (DEBUG_SERVICE) Slog.v(TAG, "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;
        }  

This part still needs to be well understood, the ServiceRecord.StartItemexample represents a startServicecall. First `r.pendingStartstake out the first one from it, and then judge if its intent is null, if it is null, it means that this startServiceneed not be executed.

si.deliveredTime = SystemClock.uptimeMillis();
r.deliveredStarts.add(si);
si.deliveryCount++;
.....
int flags = 0;
if (si.deliveryCount > 1) {
    flags |= Service.START_FLAG_RETRY;
}
if (si.doneExecutingCount > 0) {
    flags |= Service.START_FLAG_REDELIVERY;
}
r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);  

In this part of the code, we see a r.deliveredStartsstructure. As mentioned earlier, the calls that have not been r.pendingStartsactually executed are saved , and the ones that have been actually executed are recorded . Next, there will be a cross-process call of Binder, and you can see the function directly by entering ActivityThread.startServicer.deliveredStartsstartService调用scheduleServiceArgs

public final void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId,
        int flags ,Intent args) {
        ServiceArgsData s = new ServiceArgsData();
        s.token = token;
        s.taskRemoved = taskRemoved;
        s.startId = startId;
        s.flags = flags;
        s.args = args;

        queueOrSendMessage(H.SERVICE_ARGS, s);
    }  

If you read my previous Activity startup process, you should be familiar with such a function. This function will eventually call the following logic:

private void queueOrSendMessage(int what, Object obj, int arg1, int arg2) {
    synchronized (this) {
        if (DEBUG_MESSAGES) Slog.v(
            TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
            + ": " + arg1 + " / " + obj);
        Message msg = Message.obtain();
        msg.what = what;
        msg.obj = obj;
        msg.arg1 = arg1;
        msg.arg2 = arg2;
        mH.sendMessage(msg);
    }
}  

We'll go directly to mHthe handleMessagefunction

case SERVICE_ARGS:
  handleServiceArgs((ServiceArgsData)msg.obj);  

ok, then go down, I feel like I'm getting to the point right now, haha

private void handleServiceArgs(ServiceArgsData data) {
    Service s = mServices.get(data.token);
    if (s != null) {
        try {
            if (data.args != null) {
                data.args.setExtrasClassLoader(s.getClassLoader());
            }
            int res;
            if (!data.taskRemoved) {
                res = s.onStartCommand(data.args, data.flags, data.startId);
            } else {
                s.onTaskRemoved(data.args);
                res = Service.START_TASK_REMOVED_COMPLETE;
            }

            QueuedWork.waitToFinish();

            try {
                ActivityManagerNative.getDefault().serviceDoneExecuting(
                        data.token, 1, data.startId, res);
            } catch (RemoteException e) {
                // nothing to do.
            }
            ensureJitEnabled();
        } catch (Exception e) {
            if (!mInstrumentation.onException(s, e)) {
                throw new RuntimeException(
                        "Unable to start service " + s
                        + " with " + data.args + ": " + e.toString(), e);
            }
        }
    }
}

Have you seen onStartCommandthe trace? Yes, after this is executed onStartCommand, there is another very important function call serviceDoneExecuting. We all know that onStartCommanda flag will be returned after the function is executed. This flag determines the restart behavior of the Service, but the system How to manage the restart behavior of the Service? This function will open a new analysis later.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324649605&siteId=291194637