Потоковые модели

Методы, помеченные как oneway , не блокируются. Для методов, не помеченных как oneway , вызов метода клиента будет блокироваться до тех пор, пока сервер не завершит выполнение или не вызовет синхронный обратный вызов (в зависимости от того, что наступит раньше). Реализации серверных методов могут вызывать не более одного синхронного обратного вызова; дополнительные вызовы обратного вызова отбрасываются и регистрируются как ошибки. Если метод должен возвращать значения через обратный вызов и не вызывает свой обратный вызов, это регистрируется как ошибка и сообщается клиенту как ошибка транспорта.

Потоки в транзитном режиме

В режиме транзитной передачи большинство вызовов являются синхронными. Однако, чтобы сохранить запланированное поведение, при котором oneway вызовы не блокируют клиента, для каждого процесса создается поток. Подробности смотрите в обзоре HIDL .

Потоки в связанных HAL

Для обслуживания входящих вызовов RPC (включая асинхронные обратные вызовы от HAL к пользователям HAL) и уведомлений о смерти с каждым процессом, использующим HIDL, связан пул потоков. Если один процесс реализует несколько интерфейсов HIDL и/или обработчиков уведомлений о смерти, его пул потоков используется всеми из них. Когда процесс получает входящий вызов метода от клиента, он выбирает свободный поток из пула потоков и выполняет вызов в этом потоке. Если свободного потока нет, он блокируется до тех пор, пока он не станет доступным.

Если на сервере есть только один поток, вызовы на сервер выполняются по порядку. Сервер с более чем одним потоком может выполнять вызовы вне очереди, даже если у клиента есть только один поток. Однако для данного объекта интерфейса oneway вызовы гарантированно будут упорядочены (см. Модель потоков сервера ). Для многопоточного сервера, на котором размещено несколько интерфейсов, oneway вызовы к различным интерфейсам могут обрабатываться одновременно друг с другом или с другими блокирующими вызовами.

Несколько вложенных вызовов будут отправлены в один и тот же поток hwbinder. Например, если процесс (A) выполняет синхронный вызов из потока hwbinder в процесс (B), а затем процесс (B) выполняет синхронный обратный вызов в процесс (A), вызов будет выполнен в исходном потоке hwbinder. в (A), который заблокирован при исходном вызове. Эта оптимизация позволяет иметь однопоточный сервер, способный обрабатывать вложенные вызовы, но она не распространяется на случаи, когда вызовы проходят через другую последовательность вызовов IPC. Например, если процесс (B) выполнил вызов связывателя/vndbinder, который вызвал процесс (C), а затем процесс (C) вызывает обратно в (A), он не может быть обслужен в исходном потоке в (A).

Модель потоков сервера

За исключением режима passthrough, серверные реализации интерфейсов HIDL находятся в другом процессе, чем клиент, и нуждаются в одном или нескольких потоках, ожидающих входящих вызовов методов. Эти потоки представляют собой пул потоков сервера; сервер может решить, сколько потоков он хочет запустить в своем пуле потоков, и может использовать размер пула потоков, равный единице, для сериализации всех вызовов на своих интерфейсах. Если сервер имеет более одного потока в пуле потоков, он может одновременно принимать входящие вызовы на любом из своих интерфейсов (в C++ это означает, что общие данные должны быть тщательно заблокированы).

Односторонние вызовы в один и тот же интерфейс сериализуются. Если многопоточный клиент вызывает method1 и method2 в интерфейсе IFoo и method3 в интерфейсе IBar , method1 и method2 всегда будут сериализованы, но method3 может выполняться параллельно с method1 и method2 .

Один клиентский поток выполнения может вызвать одновременное выполнение на сервере с несколькими потоками двумя способами:

  • oneway вызовы не блокируются. Если выполняется oneway вызов, а затем вызывается oneway вызов, сервер может одновременно выполнить oneway вызов и oneway вызов.
  • Методы сервера, которые передают данные обратно с помощью синхронных обратных вызовов, могут разблокировать клиента, как только обратный вызов будет вызван с сервера.

Во втором случае любой код в серверной функции, который выполняется после вызова обратного вызова, может выполняться одновременно, при этом сервер обрабатывает последующие вызовы от клиента. Сюда входит код функции сервера и автоматические деструкторы, которые выполняются в конце функции. Если сервер имеет более одного потока в своем пуле потоков, проблемы параллелизма возникают, даже если вызовы поступают только из одного клиентского потока. (Если для какого-либо HAL, обслуживаемого процессом, требуется несколько потоков, все HAL будут иметь несколько потоков, поскольку пул потоков является общим для каждого процесса.)

Как только сервер вызывает предоставленный обратный вызов, транспорт может вызвать реализованный обратный вызов на клиенте и разблокировать клиента. Клиент продолжает действовать параллельно с тем, что делает реализация сервера после вызова обратного вызова (который может включать запуск деструкторов). Код в функции сервера после обратного вызова больше не блокирует клиент (пока в пуле потоков сервера достаточно потоков для обработки входящих вызовов), но может выполняться одновременно с будущими вызовами от клиента (если только в пуле потоков сервера нет только одного потока). ).

Помимо синхронных обратных вызовов, oneway вызовы от однопоточного клиента могут обрабатываться одновременно сервером с несколькими потоками в пуле потоков, но только если эти oneway вызовы выполняются на разных интерфейсах. oneway вызовы на одном и том же интерфейсе всегда сериализуются.

Примечание. Мы настоятельно рекомендуем серверным функциям возвращаться сразу после вызова функции обратного вызова.

Например (в 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
};

Модель потоков клиента

Модель потоков на клиенте различается между неблокирующими вызовами (функции, отмеченные ключевым словом oneway ) и блокирующими вызовами (функции, для которых не указано ключевое слово oneway ).

Блокировка вызовов

При блокировке вызовов клиент блокируется до тех пор, пока не произойдет одно из следующих событий:

  • Возникает ошибка транспорта; Объект Return содержит состояние ошибки, которое можно получить с помощью Return::isOk() .
  • Реализация сервера вызывает обратный вызов (если он был).
  • Реализация сервера возвращает значение (если не было параметра обратного вызова).

В случае успеха функция обратного вызова, которую клиент передает в качестве аргумента, всегда вызывается сервером до возврата самой функции. Обратный вызов выполняется в том же потоке, в котором выполняется вызов функции, поэтому разработчики должны быть осторожны с удержанием блокировок во время вызовов функций (и вообще избегать их, когда это возможно). Функция без оператора generates или oneway ключевого слова по-прежнему блокируется; клиент блокируется до тех пор, пока сервер не вернет объект Return<void> .

Односторонние звонки

Когда функция помечена oneway , клиент немедленно возвращается и не ждет, пока сервер завершит вызов функции. На первый взгляд (и в совокупности) это означает, что вызов функции занимает половину времени, поскольку выполняется половина кода, но при написании реализаций, чувствительных к производительности, это имеет некоторые последствия для планирования. Обычно использование одностороннего вызова приводит к тому, что вызывающий объект продолжает планироваться, тогда как использование обычного синхронного вызова приводит к немедленному переходу планировщика от вызывающего процесса к вызываемому процессу. Это оптимизация производительности в связующем. Для служб, где односторонний вызов должен быть выполнен в целевом процессе с высоким приоритетом, политика планирования принимающей службы может быть изменена. В C++ использование метода setMinSchedulerPolicy libhidltransport с приоритетами и политиками планировщика, определенными в sched.h , гарантирует, что все вызовы службы выполняются как минимум с установленной политикой и приоритетом планирования.