В Android 7.0 был проведен рефакторинг уровня радиоинтерфейса (RIL) с использованием набора функций для улучшения функциональности RIL. Для реализации этих функций требуются изменения в коде партнеров, которые являются необязательными, но приветствуются. Изменения в рефакторинге обратно совместимы, поэтому предыдущие реализации рефакторизованных функций продолжают работать.
В рамках рефакторинга RIL были внесены следующие улучшения:
- Коды ошибок RIL. Включает в себя добавление определенных кодов ошибок в дополнение к существующему коду
GENERIC_FAILURE. Это помогает в устранении неполадок, предоставляя более конкретную информацию о причине ошибок. - Версионирование RIL. Обеспечивает более точную и удобную в настройке информацию о версиях.
- RIL-связь с использованием блокировок пробуждения. Повышает эффективность работы батареи устройства.
Вы можете реализовать любое из вышеперечисленных улучшений или все сразу. Для получения более подробной информации обратитесь к комментариям к коду, касающимся версионирования RIL, в файле https://android.googlesource.com/platform/hardware/ril/+/android17-release/include/telephony/ril.h .
Внедрить улучшенные коды ошибок RIL.
Практически все вызовы RIL-запросов могут возвращать код ошибки GENERIC_FAILURE в ответ на сообщение об ошибке. Это проблема, характерная для всех запрашиваемых ответов, возвращаемых производителями оборудования, что может затруднить отладку проблемы, описанной в отчете об ошибке, если один и тот же код ошибки GENERIC_FAILURE возвращается вызовами RIL по разным причинам. Производителям может потребоваться значительное время, чтобы даже определить, какая часть кода могла вернуть код GENERIC_FAILURE .
В Android 7.x и выше производители могут возвращать уникальное значение кода ошибки, связанное с каждой отдельной ошибкой, которая в настоящее время классифицируется как GENERIC_FAILURE . Производители, которые не хотят публично раскрывать свои пользовательские коды ошибок, могут возвращать ошибки в виде уникального набора целых чисел (например, от 1 до x), сопоставляемых как OEM_ERROR_1 и OEM_ERROR_X . Производители должны убедиться, что каждый такой замаскированный код ошибки соответствует уникальной причине ошибки в коде. Использование конкретных кодов ошибок может ускорить отладку RIL при возврате производителем общих ошибок, поскольку определение точной причины ошибки GENERIC_FAILURE часто занимает слишком много времени (а иногда это вообще невозможно).
Кроме того, в ril.h добавлены дополнительные коды ошибок для перечислений RIL_LastCallFailCause и RIL_DataCallFailCause , чтобы код поставщика мог избежать возврата общих ошибок, таких как CALL_FAIL_ERROR_UNSPECIFIED и PDP_FAIL_ERROR_UNSPECIFIED .
Проверка кодов ошибок RIL с расширенными возможностями
После добавления новых кодов ошибок для замены кода GENERIC_FAILURE убедитесь, что вызов RIL возвращает новые коды ошибок вместо GENERIC_FAILURE .
Внедрить расширенное версионирование RIL.
В более старых версиях Android версионирование RIL было проблематичным: сама версия была неточной, механизм сообщения версии 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 и асинхронного ответа.

- Отправляется запрос RIL, и модем получает блокировку пробуждения для обработки этого запроса.
- Модем отправляет подтверждение, которое заставляет Java-сервер уменьшить счетчик блокировки пробуждения и освободить его, когда значение счетчика станет равным 0.
Примечание: Время ожидания блокировки пробуждения для последовательности запрос-подтверждение будет меньше, чем используемое в настоящее время время ожидания, поскольку подтверждение должно быть получено достаточно быстро.
- После обработки запроса модем отправляет прерывание коду поставщика, который получает блокировку пробуждения и отправляет ответ в ril.cpp, который, в свою очередь, получает блокировку пробуждения и отправляет ответ на сторону Java.
- Когда ответ достигает Java-стороны, устанавливается блокировка пробуждения (wakelock), и вызывающей стороне возвращается ответ.
- После обработки ответа всеми модулями подтверждение отправляется (через сокет) обратно в
ril.cpp, который затем освобождает блокировку пробуждения, полученную на шаге 3.
Решение 2: Модем не удерживает блокировку пробуждения, и ответ происходит быстро (синхронный запрос и ответ RIL). Синхронное или асинхронное поведение жестко запрограммировано для конкретной команды RIL и определяется для каждого вызова отдельно.

- Запрос RIL отправляется путем вызова функции
acquireWakeLock()на стороне Java. - Коду поставщика не нужно получать блокировку пробуждения, и он может быстро обработать запрос и ответить.
- Когда Java-сервер получает ответ, вызывается метод
decrementWakeLock(), который уменьшает счетчик блокировки пробуждения и освобождает блокировку пробуждения, если значение счетчика равно 0.
Сценарий: незапрошенный ответ RIL
В этом сценарии незапрошенные ответы RIL содержат флаг типа wakelock, указывающий, необходимо ли получить блокировку пробуждения для ответа поставщика. Если флаг установлен, устанавливается блокировка пробуждения по таймеру, и ответ отправляется через сокет на сторону Java. По истечении таймера блокировка пробуждения снимается. Время блокировки пробуждения может быть слишком долгим или слишком коротким для разных незапрошенных ответов RIL.

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

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