Proceso de inicio del servicio Android

El contenido de este artículo es principalmente del libro "Descifrado avanzado de Android". Por lo tanto, es posible que no le proporcione mucha ayuda. El propósito de escribir este artículo es simplemente tener una impresión cuando vuelva a estudiar y brindarme una comodidad.

El proceso de inicio del servicio se divide en dos partes, a saber, el proceso de invocación de ContextImpl a ActivityManagerService y el proceso en el que ActivityThread inicia el Servicio.

1. El proceso de llamada de ContextImpl a ActivityManagerService

Cuando iniciamos el servicio en la actividad, primero llamamos al método startService, que se implementa en la clase ContextWrapper, y solo hay una línea de código en el cuerpo del método:

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

 Ahora echemos un vistazo a a qué se refiere el objeto mBase de tipo Context. En el proceso de ActivityThread que inicia Activity, se llama al método createBaseContextForActivity en el método performLaunchActivity de ActivityThread para crear un objeto de contexto de tipo ContextImpl. Luego, pase el objeto de contexto creado AppContext al método app.attach. Eche un vistazo a lo que se hace en el método createBaseContextForActivity. el código se muestra a continuación:

private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
        
        // 代码省略。。。

        // 调用createActivityContext创建上下文对象

        ContextImpl appContext = ContextImpl.createActivityContext(
                this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);

       
        // 代码省略。。。

        return appContext;
    }

Se puede ver que el objeto appContext pasado al método activity.attach es de tipo ContextImpl. En el método attach de la clase Activity, se llama al método attachBaseContext de la clase ContextWrapper. El código del método es el siguiente:

protected void attachBaseContext(Context base) {
    if (mBase != null) {
        throw new IllegalStateException("Base context already set");
    }

    // 将传递进来的ContextImpl(继承自Context)类型的base对象赋值给了mBase变量

    mBase = base;
}

Por lo tanto, mBase se refiere específicamente a ContextImpl. Por lo tanto, nuestro proceso de iniciar el servicio comienza con la clase ContextImpl. el código se muestra a continuación:

@Override 
public ComponentName startService (servicio de intención) { 
    warnIfCallingFromSystemProcess (); 
    // 调用 了 startServiceCommon 方法
    return startServiceCommon (servicio, falso, mUser); 
}

Se puede ver en el código que el método startServiceCommon se devuelve en el método ContextImpl.startService. Ahora echemos un vistazo a lo que se hace con este método.

private ComponentName startServiceCommon(Intent service, boolean requireForeground,
            UserHandle user) {
        try {
            
            ComponentName cn = ActivityManager.getService().startService(
                mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                            getContentResolver()), requireForeground,
                            getOpPackageName(), user.getIdentifier());

            // 代码省略。。。

            return cn;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

El conocido código ActivityManager.getService (). StartService (....); aparece en este método. Aquellos familiarizados con el proceso de inicio de la actividad deben saber que este código realmente llamará al método startService en ActivityManagerService. En este punto, el proceso de llamada de ContextImpl a AMS ha terminado. El diagrama de secuencia es el siguiente:

En segundo lugar, el proceso de servicio de inicio de ActivityThread

Después del proceso anterior, la lógica del código se ejecuta en el método startService de AMS. Este método llama al método startServiceLocked de ActiveServices. El código es el siguiente:

ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
            throws TransactionTooLargeException {
        
        // 代码省略。。。

        // 注释1:查找是否有与参数service对应的ServiceRecord
        ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType, callingPackage,
                    callingPid, callingUid, userId, true, callerFg, false);
        if (res == null) {
            return null;
        }
        if (res.record == null) {
            return new ComponentName("!", res.permission != null
                    ? res.permission : "private to package");
        }

        // 注释2:得到参数service对应的ServiceRecord
        ServiceRecord r = res.record;

       
        // 代码省略。。。。

        // 注释3
        ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
        return cmp;
    }

Nota 1, se llama al método retrieveServiceLocked, su función es averiguar si existe un ServiceRecord correspondiente al servicio de parámetros. La implementación del código es la siguiente:

private ServiceLookupResult retrieveServiceLocked(Intent service,
            String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
            boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal) {
        
        if (r == null) {
            try {
                
                // 注释1:

                ResolveInfo rInfo = mAm.getPackageManagerInternalLocked().resolveService(service,
                        resolvedType, ActivityManagerService.STOCK_PM_FLAGS
                                | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                        userId, callingUid);
                
                // 注释2

                r = new ServiceRecord(mAm, ss, name, filter, sInfo, callingFromFg, res);
                   
        }
        if (r != null) {
            
            // 代码省略。。。
            
            // 注释3
            return new ServiceLookupResult(r, null);
        }
        return null;
    }

Nota 1, eventualmente llamará a PackageManagerService para obtener la información de servicio correspondiente al servicio de parámetros. En la Nota 2, encapsule la información de servicio correspondiente al servicio de parámetros obtenido en el primer paso en ServiceRecord. Nota 3, devuelva ServiceRecord al método startServiceLocked de ActiveServices en forma de un objeto ServiceLookupResult. En el comentario 2 del método startServiceLocked, el ServiceRecord correspondiente al servicio de parámetros se obtiene a través del ServiceLookupResult devuelto en el comentario 1 y se pasa al método startServiceInnerLocked en el comentario 3. El código de este método llama principalmente al método bringUpServiceLocked, que no se mostrará aquí. Mire directamente el código del método bringUpServiceLocked:

private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {
        
        // 代码省略。。。

        // 注释1
       
        final String procName = r.processName;
        String hostingType = "service";
        ProcessRecord app;

        if (!isolated) {

            // 注释2

            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
           
            // 注释3

            if (app != null && app.thread != null) {
                try {
                    app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);

                    // 注释4

                    realStartServiceLocked(r, app, execInFg);
                    return null;
                } catch (TransactionTooLargeException e) {
                    throw e;
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception when starting service " + r.shortName, e);
                }
                
            }
        } else {          
            // 。。。。
        }

        // Not running -- get it started, and enqueue this service record
        // to be executed when the app comes up.
        // 注释5
        if (app == null && !permissionsReviewRequired) {
            // 注释6
            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;
    }

Nota 1, obtenga el valor processName de ServiceRecord y asígnelo a procName, donde processName se usa para describir en qué proceso desea ejecutar el servicio, y el valor predeterminado es el proceso actual. Nota 2: Pase el procName y el uid del Servicio al método getProcessRecordLocked de AMS para consultar si hay una aplicación de objeto de tipo ProcessRecord correspondiente al Servicio. ProcessRecord se utiliza principalmente para describir la información del proceso de la aplicación en ejecución. La sentencia en la Nota 3 indica que el proceso de aplicación utilizado para ejecutar el Servicio existe, y el método realStartServiceLocked en la Nota 4 será llamado en este momento. La sentencia de la Nota 5 indica que el proceso de solicitud correspondiente al Servicio aún no se ha creado y el código de la Nota 6 se llamará en este momento. Note 6 llama al método startProcessLocked de AMS para crear el proceso de solicitud correspondiente al Servicio. Ahora veamos el método realStartServiceLocked en la nota 4, el código es el siguiente:

private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {

        // 注释1

        if (app.thread == null) {
            throw new RemoteException();
        }
        
        try {
            
            // 注释2

            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 {
            // 代码省略。。。
        }

       // 代码省略。。。
    }

Este método tiene mucho código, pero solo hay dos cosas que debemos tener en cuenta. Nota 1, debe prestar atención, en este momento, si no se ha creado el proceso de solicitud correspondiente al Servicio, se lanzará una excepción. Nota 2, llame al método scheduleCreateService de app.thread. Y app.thread es de tipo IApplicationThread, y su implementación es la clase interna ApplicationThread de ActivityThread. El código del método es el siguiente:

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

Este método encapsula la información necesaria para iniciar el servicio en CreateServiceData y envía un mensaje CREATE_SERVICE a la clase H a través del método sendMessage. Observamos directamente el procesamiento de CREATE_SERVICE en el método handleMessage de la clase H:

private 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方法

                    handleCreateService((CreateServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;                
            }
            
    }

El procesamiento de CREATE_SERVICE es llamar al método handleCreateService. El código del método es el siguiente:

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();
        
        // 注释1

        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
        try {
            // 注释2
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = (Service) cl.loadClass(data.info.name).newInstance();
        } catch (Exception e) {
            //.....
        }

        try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
            // 注释3
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            // 注释4
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
            // 注释5
            service.onCreate();
            // 注释6
            mServices.put(data.token, service);
            try {
                ActivityManager.getService().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } catch (Exception e) {
           // 。。。
        }
    }

Este método hace algo de lo anterior. Nota 1: Obtenga el LoadedApk de la aplicación del Servicio para iniciar. Nota 2, obtenga el cargador de clases y cree una instancia de servicio basada en el cargador de clases. Nota 3, cree el objeto ContextImpl del contexto de servicio. Nota 4, llame al método adjunto del servicio para inicializar el servicio y pase el contexto del objeto ContextImpl creado en el paso anterior. En este método de servicio, se llama al método attachBaseContext de ContextWrapper y el contexto del parámetro se asigna a mBase. Note 5 llama al método del ciclo de vida onCreate del servicio, de modo que el Servicio se inicia. Nota 6, agregue el Servicio iniciado a la variable miembro mServices de ActivityThread, donde mServices es una colección ArrayMap con IBinder como clave y Service como valor.

En este punto, el proceso de inicio del servicio ha terminado y finalmente se adjunta el diagrama de secuencia de este proceso para finalizar este artículo.

En este punto, el artículo ha terminado. Me gustaría agradecer al autor del libro "Descifrado avanzado de Android".

Supongo que te gusta

Origin blog.csdn.net/zhourui_1021/article/details/105617527
Recomendado
Clasificación