An overview of the

The Service startup process is similar to the Activity startup process. For those unfamiliar with the Activity startup process, check out my previous blog about the Android App startup process

Start the Service process

Context.startService()

Start with context.startService(). Start with context.startService()

## ContextWrapper.java public class ContextWrapper extends Context { public ComponentName startService(Intent service) {  return mBase.startService(service); // mBase is ContextImpl}}Copy the code

This method in turn calls contextimpl.startService

## ContextImpl.java class ContextImpl extends Context { @Override public ComponentName startService(Intent service) { warnIfCallingFromSystemProcess(); return startServiceCommon(service, mUser); } private ComponentName startServiceCommon(Intent service, UserHandle user) { try { ... ComponentName cn = ActivityManagerNative.getDefault().startService( mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(getContentResolver()), getOpPackageName(), user.getIdentifier()); . return cn; } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); }}Copy the code

. We see the last call ActivityManagerNative getDefault () startService, including ActivityManagerNative. GetDefault () is ActivityManagerService, at this time This completes the process from the calling process to the system_server process, where information is transferred through Binder

AMS.startService

So what does AMS do

## ActivityManagerService.java public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType, boolean requireForeground, String callingPackage, Int userId) throws TransactionTooLargeException {... synchronized (this) {final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); ComponentName res; try { res = mServices.startServiceLocked(caller, service, resolvedType, callingPid, callingUid, requireForeground, callingPackage, userId); } finally { Binder.restoreCallingIdentity(origId); } return res; }}Copy the code

This method again calls ActivityService#startServiceLocked

    ## ActivityService.java
    ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
            throws TransactionTooLargeException {
            
            ···
        ServiceLookupResult res =
            retrieveServiceLocked(service, 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;
        }
            
            
            
Copy the code

The call to ActivityService#startServiceInnerLocked continues

## ActivityService.java ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r, boolean callerFg, Boolean addToStarting) throws TransactionTooLargeException {... String error = bringUpServiceLocked (r, service.getFlags(), callerFg, false, false); if (error ! = null) { return new ComponentName("!!" , error); }... return r.n ame; }Copy the code

The call to ActivityService#bringUpServiceLocked continues

  private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {...if(! isolated) { 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 Service process exists
            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.}}// If the process does not exist
        if (app == null && !permissionsReviewRequired) {
            // Start the running thread
            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; }}return null;
    }
Copy the code

This method does two main things

  • If the Service process already exists, it is called directlyrealStartServiceLocked
  • If the Service process does not exist, execute it directlystartProcessLockedMethod creation process, goes through layers of calls, and eventually gets called toAMS.attachApplicationLockedMethod, and then executerealStartServiceLockedmethods

AMS.attachApplicationLocked

private final boolean attachApplicationLocked(IApplicationThread thread, int pid) {
    ...
    thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
            profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
            app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
            isRestrictedBackupMode || !normalMode, app.persistent,
            newConfiguration(mConfiguration), app.compat, getCommonServicesLocked(app.isolated), mCoreSettingsObserver.getCoreSettingsLocked()); .if(! badApp) {try {
            // Find all the services that need to run in the process
            didSomething |= mServices.attachApplicationLocked(app, processName);
        } catch (Exception e) {
            badApp = true; }}...return true;
}
Copy the code

Continue to call the AS. AttachApplicationLocked

 boolean attachApplicationLocked(ProcessRecord proc, String processName)
            throws RemoteException {
        boolean didSomething = false; .if (mPendingServices.size() > 0) {
            ServiceRecord sr = null;
            try {
                for (int i=0; i<mPendingServices.size(); i++) {
                    sr = mPendingServices.get(i);
                    if(proc ! = sr.isolatedProc && (proc.uid ! = sr.appInfo.uid || ! processName.equals(sr.processName))) {continue;
                    }

                    mPendingServices.remove(i);
                    i--;
                    proc.addPackage(sr.appInfo.packageName, sr.appInfo.longVersionCode,
                            mAm.mProcessStats);
                    / / start the Service
                    realStartServiceLocked(sr, proc, sr.createdFromFg);
                    didSomething = true; . }}Copy the code

This method calls realStartServiceLocked


    private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {... app.thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo), app.repProcState); r.postNotification(); created =true; . }Copy the code

This method calls the internal app. Thread. ScheduleCreateService, and app. The thread is IApplicationThread type, ActivityThread is an internal class called ApplicationThread, which is a Binder. This method is called ApplicationThread#scheduleCreateService

    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);
        }
Copy the code

This method actually sends a message to the Handler, the inner class H of the ActivityThread

  class H extends Handler {
   public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case CREATE_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));
                    handleCreateService((CreateServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break; }}Copy the code

The handleCreateService method is eventually called

 private void handleCreateService(CreateServiceData data) {
 

        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
        try {
            // Get the class loader
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            // Load the Service instance
            service = packageInfo.getAppFactory()
                    .instantiateService(cl, data.info.name, data.intent);
        }

        try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
            // Create the Service Context
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);

            Application app = packageInfo.makeApplication(false, mInstrumentation);
            // Initialize the Service
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
            // Call the Service's onCreate method
            service.onCreate();
            mServices.put(data.token, service);
            try {
                ActivityManager.getService().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0.0);
            } catch (RemoteException e) {
                throwe.rethrowFromSystemServer(); }}catch (Exception e) {
            if(! mInstrumentation.onException(service, e)) {throw new RuntimeException(
                    "Unable to create service " + data.info.name
                    + ":"+ e.toString(), e); }}}Copy the code

At this point the Service is started

conclusion

The whole StartService process, from the perspective of the process of Service startup process

  • ProcessAProcess usingBinderForm tosyster_serverThe process bystartServicerequest
  • syster_serverAfter receiving the request, the process sends thezygoteA process sends a request to create a process
  • zygoteprocessforkOut of a new process, in and out of a new processActivityThreadthemainmethods
  • New process passesBindertosyster_serverThe process byattachApplicationrequest
  • syster_serverAfter receiving the request, the process passes through a series of preparationsBinderSend to the new processscheduleCreateServicerequest
  • The new process receives the request and passesHandlersendCREATE_SERVICEThe message
  • The main thread receives the message and is createdServiceAnd the callbackonCreate

Reference: gityuan.com/2016/03/06/…