SerVice startup mechanism

  • The ComponentName:

startService

Source code analysis

ams

  @Override
    public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType, boolean requireForeground, String callingPackage, int userId)
            throws TransactionTooLargeException {
            ComponentName res;
            try {
                res = mServices.startServiceLocked(caller, service,
                        resolvedType, callingPid, callingUid,
                        requireForeground, callingPackage, userId);
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
            returnres; }}Copy the code

ActiveServices

    ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
            throws TransactionTooLargeException {
     / /... Leave out most of the code

        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;
      // ArrayList
      
        start() arguments that haven't yet been delivered. There are no arguments to distribute that are ready to be used later by calling onStartConmmand()
      
      //ServiceRecord IBinder
        r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                service, neededGrants, callingUid));
      // startServiceInnerLocked
        ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
        return cmp;
    }


		/ / 2
    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;
        synchronized (r.stats.getBatteryStats()) {
            r.stats.startRunningLocked();
        }
      / / 3
        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 (DEBUG_DELAYED_SERVICE) {
                RuntimeException here = new RuntimeException("here");
                here.fillInStackTrace();
                Slog.v(TAG_SERVICE, "Starting background (first=" + first + ")." + r, here);
            } else if (DEBUG_DELAYED_STARTS) {
                Slog.v(TAG_SERVICE, "Starting background (first=" + first + ")." + r);
            }
            if(first) { smap.rescheduleDelayedStartsLocked(); }}else if (callerFg || r.fgRequired) {
            smap.ensureNotStartingBackgroundLocked(r);
        }

        return r.name;
    }

/ / 4
  private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {
        // Check whether the service is started (the process is not empty, and the process is started). If so, call sendServiceArgsLocked
    // Determine if processRecord for serviceRecord is empty
        if(r.app ! =null&& r.app.thread ! =null) {
          OnServiceStartCommand () onServiceStartCommand()
            sendServiceArgsLocked(r, execInFg, false);
            return null;
        }

     // Omit some code
    
        ProcessRecord app;

        if(! isolated) {// Find the ProcessRecord corresponding to service
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
            if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
                        + " app=" + app);
          	// If the process in which the service is located is not empty and the process is already started
            if(app ! =null&& app.thread ! =null) {
                try {
                    app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
                  // Start the service
                    realStartServiceLocked(r, app, execInFg);
                    return null;
                } catch (TransactionTooLargeException e) {
                    throw e;
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception when starting service " + r.shortName, 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())) {
                hostingType = "webview_service"; }}// Not running -- get it started, and enqueue this service record
        // to be executed when the app comes up.
    	If thread is null, the app process is not ready
        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; }}// Add ServiceRecord to the PendingService list
        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) {
                if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
                        "Applying delayed stop (in bring up): "+ r); stopServiceLocked(r); }}return null;
    }

// realStartServiceLocked
  private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
        if (app.thread == null) {
            throw new RemoteException();
        }
        if (DEBUG_MU)
            Slog.v(TAG_MU, "realStartServiceLocked, ServiceRecord.uid = " + r.appInfo.uid
                    + ", ProcessRecord.uid = " + app.uid);
        r.app = app;
        r.restartTime = r.lastActivity = SystemClock.uptimeMillis();

        final boolean newService = app.services.add(r);
        bumpServiceExecutingLocked(r, execInFg, "create");
        mAm.updateLruProcessLocked(app, false.null);
        updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
        mAm.updateOomAdjLocked();

        boolean created = false;
        try {
            if (LOG_SERVICE_START_STOP) {
                String nameTerm;
                int lastPeriod = r.shortName.lastIndexOf('. ');
                nameTerm = lastPeriod >= 0 ? r.shortName.substring(lastPeriod) : r.shortName;
                EventLogTags.writeAmCreateService(
                        r.userId, System.identityHashCode(r), nameTerm, r.app.uid, r.app.pid);
            }
            synchronized (r.stats.getBatteryStats()) {
                r.stats.startLaunchedLocked();
            }
            mAm.notifyPackageUse(r.serviceInfo.packageName,
                                 PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
            app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
          // thread (IApplicationThread) apt request to create Service
            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) {// Keep the executeNesting count accurate.
                final boolean inDestroying = mDestroyingServices.contains(r);
                serviceDoneExecutingLocked(r, inDestroying, inDestroying);

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

                // Retry.
                if(! inDestroying) { scheduleServiceRestartLocked(r,false); }}}if (r.whitelistManager) {
            app.whitelistManager = true;
        }

        requestServiceBindingsLocked(r, execInFg);

        updateServiceClientActivitiesLocked(app, null.true);

        // 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));
        }
			// Trigger service onstartCommand()
        sendServiceArgsLocked(r, execInFg, true);

        if (r.delayed) {
            if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (new proc): " + r);
            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) {
                if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
                        "Applying delayed stop (from start): "+ r); stopServiceLocked(r); }}}Copy the code

Summary of overall process

  1. Process A calls startService
  2. Add ServiceRecord to pendingStarts
  3. mServices.startServiceLocked
  4. startServiceInnerLocked
  5. bringUpServiceLocked
  6. If sendServiceArgsLocked(r, execInFg, false) is enabled, check whether the process logged by serviceRecord is empty and whether the process is started. , the call onServiceStartCommand
  7. Check whether the process is started. If the process is not started, scheCreateService will be called through APT, and Service will be started through mH in the main thread. After starting, Add service to ArrayMap

    mServices
    ,service>
  8. MPendingService also stores the ServiceRecord that has been started in AMS ActiveServices

bindService

Source code analysis

contextImpl

  private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
            handler, UserHandle user) {
        // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
        IServiceConnection sd;
        if (conn == null) {
            throw new IllegalArgumentException("connection is null");
        }
        if(mPackageInfo ! =null) {
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
        } else {
            throw new RuntimeException("Not supported in system context");
        }
        validateServiceIntent(service);
        try {
            IBinder token = getActivityToken();
            if (token == null && (flags&BIND_AUTO_CREATE) == 0&& mPackageInfo ! =null
                    && mPackageInfo.getApplicationInfo().targetSdkVersion
                    < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                flags |= BIND_WAIVE_PRIORITY;
            }
            service.prepareToLeaveProcess(this);
            // Initiate an AMS call
            int res = ActivityManager.getService().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());
            if (res < 0) {
                throw new SecurityException(
                        "Not allowed to bind to service " + service);
            }
            returnres ! =0;
        } catch (RemoteException e) {
            throwe.rethrowFromSystemServer(); }}Copy the code

ActiveService

  int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, final IServiceConnection connection, int flags,
            String callingPackage, final int userId) throws TransactionTooLargeException {
      

        ActivityRecord activity = null;
        if(token ! =null) {
            activity = ActivityRecord.isInStackLocked(token);
            if (activity == null) {
                Slog.w(TAG, "Binding with unknown activity: " + token);
                return 0; }}int clientLabel = 0;
        PendingIntent clientIntent = null;
        final boolean isCallerSystem = callerApp.info.uid == Process.SYSTEM_UID;


        final booleancallerFg = callerApp.setSchedGroup ! = ProcessList.SCHED_GROUP_BACKGROUND;final booleanisBindExternal = (flags & Context.BIND_EXTERNAL_SERVICE) ! =0;
        final booleanallowInstant = (flags & Context.BIND_ALLOW_INSTANT) ! =0;

        ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(),
                    Binder.getCallingUid(), userId, true, callerFg, isBindExternal, allowInstant);
        if (res == null) {
            return 0;
        }
        if (res.record == null) {
            return -1;
        }
        ServiceRecord s = res.record;

        boolean permissionsReviewRequired = false;

        // If permissions need a review before any of the app components can run,
        // we schedule binding to the service but do not start its process, then
        // we launch a review activity to which is passed a callback to invoke
        // when done to start the bound service's process to completing the binding.
        if (mAm.mPermissionReviewRequired) {
            if (mAm.getPackageManagerInternalLocked().isPermissionsReviewRequired(
                    s.packageName, s.userId)) {

                permissionsReviewRequired = true;

                // Show a permission review UI only for binding from a foreground app
                if(! callerFg) { Slog.w(TAG,"u" + s.userId + " Binding to a service in package"
                            + s.packageName + " requires a permissions review");
                    return 0;
                }

                final ServiceRecord serviceRecord = s;
                final Intent serviceIntent = service;

                RemoteCallback callback = new RemoteCallback(
                        new RemoteCallback.OnResultListener() {
                    @Override
                    public void onResult(Bundle result) {
                        synchronized(mAm) {
                            final long identity = Binder.clearCallingIdentity();
                            try {
                                if(! mPendingServices.contains(serviceRecord)) {return;
                                }
                                // If there is still a pending record, then the service
                                // binding request is still valid, so hook them up. We
                                // proceed only if the caller cleared the review requirement
                                // otherwise we unbind because the user didn't approve.
                                if(! mAm.getPackageManagerInternalLocked() .isPermissionsReviewRequired( serviceRecord.packageName, serviceRecord.userId)) {try {
                                        bringUpServiceLocked(serviceRecord,
                                                serviceIntent.getFlags(),
                                                callerFg, false.false);
                                    } catch (RemoteException e) {
                                        /* ignore - local call */}}else{ unbindServiceLocked(connection); }}finally{ Binder.restoreCallingIdentity(identity); }}}});final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
                intent.putExtra(Intent.EXTRA_PACKAGE_NAME, s.packageName);
                intent.putExtra(Intent.EXTRA_REMOTE_CALLBACK, callback);

                if (DEBUG_PERMISSIONS_REVIEW) {
                    Slog.i(TAG, "u" + s.userId + " Launching permission review for package "
                            + s.packageName);
                }

                mAm.mHandler.post(new Runnable() {
                    @Override
                    public void run(a) {
                        mAm.mContext.startActivityAsUser(intent, newUserHandle(userId)); }}); }}final long origId = Binder.clearCallingIdentity();

        try {
            if (unscheduleServiceRestartLocked(s, callerApp.info.uid, false)) {
                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "BIND SERVICE WHILE RESTART PENDING: "
                        + s);
            }

            if((flags&Context.BIND_AUTO_CREATE) ! =0) {
                s.lastActivity = SystemClock.uptimeMillis();
                if(! s.hasAutoCreateConnections()) {// This is the first binding, let the tracker know.
                    ServiceState stracker = s.getTracker();
                    if(stracker ! =null) {
                        stracker.setBound(true, mAm.mProcessStats.getMemFactorLocked(),
                                s.lastActivity);
                    }
                }
            }

            mAm.startAssociationLocked(callerApp.uid, callerApp.processName, callerApp.curProcState,
                    s.appInfo.uid, s.name, s.processName);
            // Once the apps have become associated, if one of them is caller is ephemeral
            // the target app should now be able to see the calling app
            mAm.grantEphemeralAccessLocked(callerApp.userId, service,
                    s.appInfo.uid, UserHandle.getAppId(callerApp.uid));

            AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
            ConnectionRecord c = new ConnectionRecord(b, activity,
                    connection, flags, clientLabel, clientIntent);

            IBinder binder = connection.asBinder();
            ArrayList<ConnectionRecord> clist = s.connections.get(binder);
            if (clist == null) {
                clist = new ArrayList<ConnectionRecord>();
                s.connections.put(binder, clist);
            }
            clist.add(c);
            b.connections.add(c);
            if(activity ! =null) {
                if (activity.connections == null) {
                    activity.connections = new HashSet<ConnectionRecord>();
                }
                activity.connections.add(c);
            }
            b.client.connections.add(c);
            if((c.flags&Context.BIND_ABOVE_CLIENT) ! =0) {
                b.client.hasAboveClient = true;
            }
            if((c.flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) ! =0) {
                s.whitelistManager = true;
            }
            if(s.app ! =null) {
                updateServiceClientActivitiesLocked(s.app, c, true);
            }
            clist = mServiceConnections.get(binder);
            if (clist == null) {
                clist = new ArrayList<ConnectionRecord>();
                mServiceConnections.put(binder, clist);
            }
            clist.add(c);

            if((flags&Context.BIND_AUTO_CREATE) ! =0) {
                s.lastActivity = SystemClock.uptimeMillis();
                if (bringUpServiceLocked(s, service.getFlags(), callerFg, false, permissionsReviewRequired) ! =null) {
                    return 0; }}if(s.app ! =null) {
                if((flags&Context.BIND_TREAT_LIKE_ACTIVITY) ! =0) {
                    s.app.treatLikeActivity = true;
                }
                if (s.whitelistManager) {
                    s.app.whitelistManager = true;
                }
                // This could have made the service more important.
                mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities
                        || s.app.treatLikeActivity, b.client);
                mAm.updateOomAdjLocked(s.app, true);
            }

            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bind " + s + " with " + b
                    + ": received=" + b.intent.received
                    + " apps=" + b.intent.apps.size()
                    + " doRebind=" + b.intent.doRebind);

            if(s.app ! =null && b.intent.received) {
                // Service is already running, so we can immediately
                // publish the connection.
                try {
                    c.conn.connected(s.name, b.intent.binder, false);
                } catch (Exception e) {
                    Slog.w(TAG, "Failure sending service " + s.shortName
                            + " to connection " + c.conn.asBinder()
                            + " (in " + c.binding.client.processName + ")", e);
                }

                // If this is the first app connected back to this binding,
                // and the service had previously asked to be told when
                // rebound, then do so.
                if (b.intent.apps.size() == 1 && b.intent.doRebind) {
                    requestServiceBindingLocked(s, b.intent, callerFg, true); }}else if(! b.intent.requested) { requestServiceBindingLocked(s, b.intent, callerFg,false);
            }

            getServiceMapLocked(s.userId).ensureNotStartingBackgroundLocked(s);

        } finally {
            Binder.restoreCallingIdentity(origId);
        }

        return 1;
    }

Copy the code

|--AMS
|	|--bindServiceLocked
|	|-- bringUpServiceLocked(serviceRecord,serviceIntent.getFlags(),callerFg, false, false);


Copy the code
  • BindService does not add ServiceRecord to the PendingStarts queue
  • The first step is to define an AidL interface that receives onServiceConnected destruction on the application side
  • Calls are then made to the business layer through this interface

  • The application calls bindService, creates an IServiceConnection in AMS, and passes in serviceConnection. When the service is bound, AMS notifies IServiceConnection, and since IServiceConnection has a reference to serviceConnect, you can call back to serviceconnection’s onServiceConnected ected nodes
  • A (context, serviceconnection) – > IServiceConnection means the same ServiceConnextion, Bind IServiceConnection for different context. The same context and different serviceConnection will correspond to different IServiceConnection

  • If the Service is not created, create the Service
  • Now that the Service is started and its binder object has been published to Ams, you can return it directly to the Serviceconnected ected callback
  • If the service has not already published a binder object to AMS, B.INtent. Requested indicates whether AMS has requested a binder object from the Service
  • Finally, add ServiceRecord to PendingService
 private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
   			// If servicerecord.app! = null, explain realStartServiceLocked, the Service has started
        r.app = app;
        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);
          // Create a service
            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) {// Keep the executeNesting count accurate.
                final boolean inDestroying = mDestroyingServices.contains(r);
                serviceDoneExecutingLocked(r, inDestroying, inDestroying);

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

                // Retry.
                if(! inDestroying) { scheduleServiceRestartLocked(r,false); }}}if (r.whitelistManager) {
            app.whitelistManager = true;
        }
			/ / request Service release Binder handle, of state Richard armitage pp. Thread. ScheduleBindService (r, i.i ntent, getIntent (), the rebind, of state Richard armitage pp. RepProcState);
        requestServiceBindingsLocked(r, execInFg);

        updateServiceClientActivitiesLocked(app, null.true);

     // See if there is a pendingStart to process
        sendServiceArgsLocked(r, execInFg, true);

    }
Copy the code

ActivityThread

 private void handleBindService(BindServiceData data) {
       Service s = mServices.get(data.token);
       if (DEBUG_SERVICE)
           Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);
       if(s ! =null) {
           try {
               data.intent.setExtrasClassLoader(s.getClassLoader());
               data.intent.prepareToEnterProcess();
               try {
   									// service whether data.rebind
                   if(! data.rebind) { IBinder binder = s.onBind(data.intent);// Publish binder handles
                       ActivityManager.getService().publishService(
                               data.token, data.intent, binder);
                   } else {
                     // 
                       s.onRebind(data.intent);
                       ActivityManager.getService().serviceDoneExecuting(
                               data.token, SERVICE_DONE_EXECUTING_ANON, 0.0);
                   }
                   ensureJitEnabled();
               } catch (RemoteException ex) {
                   throwex.rethrowFromSystemServer(); }}catch (Exception e) {
               if(! mInstrumentation.onException(s, e)) {throw new RuntimeException(
                           "Unable to bind to service " + s
                           + " with " + data.intent + ":"+ e.toString(), e); }}}}Copy the code

AMS

 void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
       final long origId = Binder.clearCallingIdentity();
       try {
           if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r
                   + "" + intent + ":" + service);
           if(r ! =null) {
               Intent.FilterComparison filter
                       = new Intent.FilterComparison(intent);
               IntentBindRecord b = r.bindings.get(filter);
               if(b ! =null && !b.received) {
                 
                   b.binder = service;
                   b.requested = true;
                   b.received = true;
                 / / traverse ServiceConnect
                   for (int conni=r.connections.size()-1; conni>=0; conni--) {
                       ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
                       for (int i=0; i<clist.size(); i++) {
                           ConnectionRecord c = clist.get(i);
                        
                           try {
                             // Callback, passing service
                               c.conn.connected(r.name, service, false);
                           } catch (Exception e) {
                               Slog.w(TAG, "Failure sending service " + r.name +
                                     " to connection " + c.conn.asBinder() +
                                     " (in " + c.binding.client.processName + ")", e);
                           }
                       }
                   }
               }

               serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false); }}finally{ Binder.restoreCallingIdentity(origId); }}Copy the code

When is onRebind called

  • ServiceREcord! =null&&IntentRecord.received