Модель резьбы

Методы, помеченные как 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 is called,
    // and the client resumes execution.
    ...
    return Void(); // is basically a no-op
};

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

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

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

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

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

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

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

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