Рефакторинг RIL

В Android 7.0 был проведён рефакторинг уровня радиоинтерфейса (RIL) с использованием набора функций для улучшения функциональности RIL. Для реализации этих функций требуется внесение изменений в код партнёра, что необязательно, но рекомендуется. Изменения, внесенные в результате рефакторинга, обратно совместимы, поэтому предыдущие реализации рефакторинговых функций продолжают работать.

Рефакторинг RIL включает следующие улучшения:

  • Коды ошибок RIL. Включает специальные коды ошибок в дополнение к существующему коду GENERIC_FAILURE . Это помогает в устранении ошибок, предоставляя более конкретную информацию о причине их возникновения.
  • Управление версиями RIL. Обеспечивает более точную и простую настройку информации о версиях.
  • Связь RIL с использованием блокировок сна. Улучшает работу аккумулятора устройства.

Вы можете реализовать любое или все из перечисленных выше улучшений. Подробнее см. комментарии к коду о версиях RIL в https://android.googlesource.com/platform/hardware/ril/+/android16-release/include/telephony/ril.h .

Реализовать расширенные коды ошибок RIL

Почти все запросы RIL могут возвращать код ошибки GENERIC_FAILURE в ответ на ошибку. Эта проблема свойственна всем запрошенным ответам, возвращаемым OEM-производителями, что может затруднить отладку проблемы на основе отчёта об ошибке, если один и тот же код ошибки GENERIC_FAILURE возвращается вызовами RIL по разным причинам. Поставщикам может потребоваться значительное время, чтобы даже определить, какая часть кода могла вернуть код GENERIC_FAILURE .

В Android 7.x и выше OEM-производители могут возвращать отдельное значение кода ошибки, связанное с каждой отдельной ошибкой, которая в настоящее время классифицируется как GENERIC_FAILURE . OEM-производители, которые не хотят публично раскрывать свои пользовательские коды ошибок, могут возвращать ошибки в виде отдельного набора целых чисел (например, от 1 до x), сопоставленных как OEM_ERROR_1 с OEM_ERROR_X . Поставщики должны гарантировать, что каждый такой замаскированный код ошибки сопоставляется с уникальной причиной ошибки в коде. Использование конкретных кодов ошибок может ускорить отладку RIL всякий раз, когда OEM-производитель возвращает общие ошибки, поскольку часто может потребоваться слишком много времени, чтобы определить точную причину кода ошибки GENERIC_FAILURE (а иногда ее вообще невозможно выяснить).

Кроме того, ril.h добавляет больше кодов ошибок для перечислений RIL_LastCallFailCause и RIL_DataCallFailCause , чтобы код поставщика мог избежать возврата общих ошибок, таких как CALL_FAIL_ERROR_UNSPECIFIED и PDP_FAIL_ERROR_UNSPECIFIED .

Проверка расширенных кодов ошибок RIL

После добавления новых кодов ошибок для замены кода GENERIC_FAILURE убедитесь, что новые коды ошибок возвращаются вызовом RIL вместо GENERIC_FAILURE .

Реализовать расширенное управление версиями RIL

Управление версиями RIL в старых версиях Android было проблематичным: сама версия была неточной, механизм сообщения версии RIL был неясен (из-за чего некоторые поставщики сообщали неверную версию), а обходной путь для оценки версии был склонен к неточности.

В Android 7.x и выше ril.h документирует все значения версии RIL, описывает соответствующую версию RIL и перечисляет все изменения для этой версии. При внесении изменений, соответствующих версии RIL, поставщики должны обновить свою версию в коде и вернуть эту версию в RIL_REGISTER .

Проверить расширенное управление версиями RIL

Убедитесь, что во время RIL_REGISTER возвращается версия RIL, соответствующая вашему коду RIL (а не RIL_VERSION определенная в ril.h ).

Реализовать RIL-коммуникацию с использованием wakelocks

Временные блокировки сна используются в RIL-коммуникациях неточно, что негативно сказывается на времени работы аккумулятора. В Android 7.x и более поздних версиях производительность можно повысить, классифицировав запросы RIL и обновив код для разной обработки блокировок сна для разных типов запросов.

Классифицировать запросы RIL

Запросы RIL могут быть как запрошенными, так и незапрошенными. Поставщики должны дополнительно классифицировать запрошенные запросы по одному из следующих критериев:

  • синхронный . Запросы, ответ на которые не занимает значительного времени. Например, RIL_REQUEST_GET_SIM_STATUS .
  • асинхронные . Запросы, ответ на которые занимает значительное время. Например, RIL_REQUEST_QUERY_AVAILABLE_NETWORKS .

Асинхронные запросы RIL могут занимать значительное время. После получения подтверждения от кода поставщика RIL Java снимает блокировку пробуждения, что может привести к переходу процессора приложения из состояния ожидания в состояние ожидания. Когда ответ от кода поставщика становится доступен, RIL Java (процессор приложения) снова захватывает блокировку пробуждения, обрабатывает ответ и возвращается в состояние ожидания. Такой переход из состояния ожидания в состояние ожидания может потреблять много энергии.

Если время отклика недостаточно велико, удержание блокировки пробуждения и пребывание в состоянии бездействия в течение всего времени, необходимого для ответа, может быть более энергоэффективным, чем переход в состояние ожидания со снятием блокировки пробуждения и выходом из него после получения ответа. Поставщикам следует использовать специфичные для платформы измерения энергопотребления для определения порогового значения времени T , при котором мощность, потребляемая при нахождении в состоянии бездействия в течение всего времени T превышает мощность, потребляемую при переходе из состояния бездействия в состояние ожидания и обратно в то же время T Если время T известно, команды RIL, выполнение которых занимает больше времени T можно классифицировать как асинхронные, а остальные команды — как синхронные.

Сценарии коммуникации RIL

На следующих диаграммах показаны общие сценарии коммуникации RIL и представлены решения по изменению кода для обработки запрошенных и незапрошенных запросов RIL.

Примечание: Подробную информацию о реализации функций, используемых в следующих диаграммах, см. в методах acquireWakeLock() , decrementWakeLock() и clearWakeLock( ) в ril.cpp .

Сценарий: запрос RIL и запрошенный асинхронный ответ

В этом сценарии, если ожидается, что ответ на запрос RIL займет значительное время (например, ответ на RIL_REQUEST_GET_AVAILABLE_NETWORKS ), блокировка пробуждения будет удерживаться процессором приложения в течение длительного времени. Проблемы с модемом также могут привести к длительному ожиданию.

Рисунок 1. Асинхронный ответ, запрошенный RIL.

Решение 1: Модем удерживает wakelock для запроса RIL и асинхронного ответа.

Рисунок 2. Блокировка сна, удерживаемая модемом.
  1. Запрос RIL отправляется, и модем устанавливает блокировку сна для обработки этого запроса.
  2. Модем отправляет подтверждение, которое заставляет сторону Java уменьшать счетчик пробуждений и освобождать его, когда значение счетчика становится равным 0.

    Примечание: длительность тайм-аута wakelock для последовательности «запрос-подтверждение» будет меньше текущей используемой длительности тайм-аута, поскольку подтверждение должно быть получено достаточно быстро.

  3. После обработки запроса модем отправляет прерывание коду поставщика, который получает wakelock и отправляет ответ ril.cpp, который, в свою очередь, получает wakelock и отправляет ответ стороне Java.
  4. Когда ответ достигает стороны Java, срабатывает wakelock и ответ возвращается вызывающей стороне.
  5. После обработки ответа всеми модулями подтверждение отправляется (через сокет) обратно в ril.cpp , который затем снимает wakelock, полученный на шаге 3.

Решение 2: Модем не удерживает блокировку сна, и ответ быстрый (синхронный запрос и ответ RIL). Синхронное или асинхронное поведение жёстко запрограммировано для конкретной команды RIL и определяется на основе каждого вызова.

Рисунок 3. Блокировка пробуждения не удерживается модемом.
  1. Запрос RIL отправляется путем вызова acquireWakeLock() на стороне Java.
  2. Коду поставщика не нужно получать wakelock, он может обрабатывать запросы и быстро отвечать.
  3. Когда сторона Java получает ответ, вызывается decrementWakeLock() , который уменьшает счетчик wakelock и снимает wakelock, если значение счетчика равно 0.

Сценарий: незапрошенный ответ RIL

В этом сценарии незапрошенные ответы RIL содержат флаг типа «wakelock», который указывает, требуется ли запрашивать «wakelock» для ответа поставщика. Если флаг установлен, устанавливается временная «wakelock», и ответ отправляется через сокет в сторону Java. По истечении времени таймера «wakelock» снимается. Временная «wakelock» может быть слишком длинной или слишком короткой для различных незапрошенных ответов RIL.

Рисунок 4. Незапрошенный ответ RIL.

Решение: Подтверждение отправляется из кода Java на собственную сторону ( ril.cpp ) вместо удержания временной блокировки на собственной стороне при отправке незапрошенного ответа.

Рисунок 5. Использование ack вместо временной блокировки пробуждения.

Проверить переработанные wakelock-ы

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