Modelos de roscado

Los métodos marcados como oneway no se bloquean. Para los métodos que no están marcados como oneway , la llamada de método de un cliente se bloqueará hasta que el servidor haya completado la ejecución o llame a una devolución de llamada síncrona (lo que ocurra primero). Las implementaciones de métodos de servidor pueden llamar como máximo a una devolución de llamada síncrona; las llamadas de devolución de llamada adicionales se descartan y se registran como errores. Si se supone que un método debe devolver valores a través de una devolución de llamada y no llama a su devolución de llamada, esto se registra como un error y se notifica como un error de transporte al cliente.

Subprocesos en modo de transferencia

En el modo de transferencia, la mayoría de las llamadas son sincrónicas. Sin embargo, para preservar el comportamiento previsto de que las llamadas oneway no bloqueen al cliente, se crea un subproceso para cada proceso. Para obtener más información, consulte la descripción general de HIDL .

Subprocesos en HAL encuadernados

Para atender las llamadas RPC entrantes (incluidas las devoluciones de llamada asincrónicas de HAL a los usuarios de HAL) y las notificaciones de muerte, se asocia un subproceso con cada proceso que usa HIDL. Si un solo proceso implementa múltiples interfaces HIDL y/o controladores de notificación de muerte, su grupo de subprocesos se comparte entre todos ellos. Cuando un proceso recibe una llamada de método entrante de un cliente, elige un subproceso libre del grupo de subprocesos y ejecuta la llamada en ese subproceso. Si no hay un hilo libre disponible, se bloquea hasta que haya uno disponible.

Si el servidor tiene solo un subproceso, las llamadas al servidor se completan en orden. Un servidor con más de un subproceso puede completar llamadas fuera de servicio incluso si el cliente tiene solo un subproceso. Sin embargo, para un objeto de interfaz determinado, se garantiza que se ordenarán las llamadas oneway (consulte Modelo de subprocesamiento del servidor ). Para un servidor de subprocesos múltiples que aloja múltiples interfaces, las llamadas oneway a diferentes interfaces pueden procesarse simultáneamente entre sí o con otras llamadas de bloqueo.

Se enviarán varias llamadas anidadas en el mismo subproceso de hwbinder. Por ejemplo, si un proceso (A) realiza una llamada sincrónica desde un subproceso hwbinder al proceso (B), y luego el proceso (B) realiza una llamada sincrónica al proceso (A), la llamada se ejecutará en el subproceso hwbinder original. en (A) que está bloqueado en la llamada original. Esta optimización hace posible tener un único servidor de subprocesos capaz de manejar llamadas anidadas, pero no se extiende a los casos en los que las llamadas viajan a través de otra secuencia de llamadas IPC. Por ejemplo, si el proceso (B) hizo una llamada a binder/vndbinder que llamó a un proceso (C) y luego el proceso (C) vuelve a llamar a (A), no se puede servir en el subproceso original en (A).

Modelo de subprocesamiento del servidor

Excepto por el modo de transferencia, las implementaciones de servidor de las interfaces HIDL viven en un proceso diferente al del cliente y necesitan uno o más subprocesos en espera de llamadas de método entrantes. Estos subprocesos son el conjunto de subprocesos del servidor; el servidor puede decidir cuántos subprocesos quiere ejecutar en su grupo de subprocesos y puede usar un tamaño de grupo de subprocesos de uno para serializar todas las llamadas en sus interfaces. Si el servidor tiene más de un subproceso en el grupo de subprocesos, puede recibir llamadas entrantes simultáneas en cualquiera de sus interfaces (en C++, esto significa que los datos compartidos deben bloquearse cuidadosamente).

Las llamadas unidireccionales en la misma interfaz se serializan. Si un cliente de subprocesos múltiples llama al method1 y al method2 en la interfaz IFoo y al method3 en la interfaz IBar , el method1 y el method2 siempre se serializarán, pero el method3 puede ejecutarse en paralelo con el method1 y el method2 .

Un único subproceso de ejecución del cliente puede provocar la ejecución simultánea en un servidor con varios subprocesos de dos maneras:

  • Las llamadas oneway no se bloquean. Si se ejecuta una llamada oneway y luego se llama una no oneway , el servidor puede ejecutar la llamada oneway y la llamada no oneway simultáneamente.
  • Los métodos del servidor que devuelven datos con devoluciones de llamada sincrónicas pueden desbloquear al cliente tan pronto como se llama a la devolución de llamada desde el servidor.

Para la segunda forma, cualquier código en la función del servidor que se ejecute después de que se llame a la devolución de llamada puede ejecutarse simultáneamente, y el servidor manejará las llamadas posteriores del cliente. Esto incluye código en la función del servidor y destructores automáticos que se ejecutan al final de la función. Si el servidor tiene más de un subproceso en su conjunto de subprocesos, surgen problemas de simultaneidad incluso si las llamadas provienen de un único subproceso de cliente. (Si cualquier HAL atendida por un proceso necesita múltiples subprocesos, todas las HAL tendrán múltiples subprocesos porque el grupo de subprocesos se comparte por proceso).

Tan pronto como el servidor llama a la devolución de llamada proporcionada, el transporte puede llamar a la devolución de llamada implementada en el cliente y desbloquearlo. El cliente procede en paralelo con lo que sea que haga la implementación del servidor después de llamar a la devolución de llamada (que puede incluir la ejecución de destructores). El código en la función del servidor después de que la devolución de llamada ya no bloquee al cliente (siempre que el grupo de subprocesos del servidor tenga suficientes subprocesos para manejar las llamadas entrantes), pero puede ejecutarse simultáneamente con futuras llamadas del cliente (a menos que el grupo de subprocesos del servidor tenga solo un subproceso ).

Además de las devoluciones de llamadas sincrónicas, las llamadas oneway de un cliente de un solo subproceso pueden ser manejadas simultáneamente por un servidor con múltiples subprocesos en su grupo de subprocesos, pero solo si esas llamadas oneway se ejecutan en diferentes interfaces. Las llamadas oneway en la misma interfaz siempre se serializan.

Nota: Recomendamos encarecidamente que las funciones del servidor regresen tan pronto como hayan llamado a la función de devolución de llamada.

Por ejemplo (en C++):

Return<void> someMethod(someMethod_cb _cb) {
    // Do some processing, then call callback with return data
    hidl_vec<uint32_t> vec = ...
    _cb(vec);
    // At this point, the client's callback will be called,
    // and the client will resume execution.
    ...
    return Void(); // is basically a no-op
};

Modelo de subprocesamiento del cliente

El modelo de subprocesamiento en el cliente difiere entre llamadas sin bloqueo (funciones que están marcadas con la palabra clave oneway ) y llamadas con bloqueo (funciones que no tienen especificada la palabra clave oneway ).

Bloqueo de llamadas

Para el bloqueo de llamadas, el cliente bloquea hasta que ocurra uno de los siguientes:

  • Ocurre un error de transporte; el objeto Return contiene un estado de error que se puede recuperar con Return::isOk() .
  • La implementación del servidor llama a la devolución de llamada (si hubo una).
  • La implementación del servidor devuelve un valor (si no hubo un parámetro de devolución de llamada).

En caso de éxito, el servidor siempre llama a la función de devolución de llamada que el cliente pasa como argumento antes de que la función regrese. La devolución de llamada se ejecuta en el mismo subproceso en el que se realiza la llamada a la función, por lo que los implementadores deben tener cuidado con los bloqueos durante las llamadas a la función (y evitarlos por completo cuando sea posible). Una función sin una declaración de generates o una palabra clave oneway todavía está bloqueando; el cliente se bloquea hasta que el servidor devuelve un objeto Return<void> .

Llamadas unidireccionales

Cuando una función se marca oneway , el cliente regresa inmediatamente y no espera a que el servidor complete su invocación de llamada de función. En la superficie (y en conjunto), esto significa que la llamada a la función toma la mitad del tiempo porque está ejecutando la mitad del código, pero cuando se escriben implementaciones que son sensibles al rendimiento, esto tiene algunas implicaciones de programación. Normalmente, el uso de una llamada unidireccional hace que la persona que llama continúe programada, mientras que el uso de una llamada síncrona normal hace que el programador se transfiera inmediatamente del proceso de la persona que llama al destinatario de la llamada. Esta es una optimización del rendimiento en el aglutinante. Para los servicios en los que la llamada unidireccional debe ejecutarse en el proceso de destino con una prioridad alta, se puede cambiar la política de programación del servicio receptor. En C++, el uso del método libhidltransport de setMinSchedulerPolicy con las prioridades y políticas del programador definidas en sched.h garantiza que todas las llamadas al servicio se ejecuten al menos con la política y la prioridad de programación establecidas.