В Android 7.0 был переработан уровень радиоинтерфейса (RIL) с использованием набора функций, улучшающих его работу. Чтобы реализовать эти функции, необходимо изменить код партнера. Это необязательно, но мы рекомендуем сделать это. Изменения, связанные с рефакторингом, обратно совместимы, поэтому предыдущие реализации рефакторинговых функций продолжат работать.
Рефакторинг RIL включает следующие улучшения:
- Коды ошибок RIL. Позволяет использовать определенные коды ошибок
в дополнение к существующему коду
GENERIC_FAILURE. Это помогает устранять неполадки, поскольку предоставляет более точную информацию о причинах ошибок. - Управление версиями 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 и более поздних версий производители устройств могут возвращать отдельный код ошибки <0x0A>для каждой ошибки, которая в настоящее время относится к категории GENERIC_FAILURE. Производители устройств, которые не хотят публично раскрывать свои коды ошибок, могут возвращать ошибки в виде набора целых чисел (например, от 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
В более ранних версиях Android были проблемы с управлением версиями RIL: сама версия была неточной, механизм ее определения был неясным (из-за чего некоторые поставщики сообщали неправильную версию), а обходной способ оценки версии был неточным.
В Android 7.x и более поздних версий в файле ril.h перечислены все значения версии RIL, описаны соответствующие версии RIL и перечислены все изменения для каждой версии. При внесении изменений, соответствующих версии RIL, поставщики должны обновить версию в коде и вернуть эту версию в RIL_REGISTER.
Проверка расширенного управления версиями RIL
Убедитесь, что во время RIL_REGISTER возвращается версия RIL, соответствующая коду RIL (а не RIL_VERSION, определенная в ril.h).
Реализация связи RIL с помощью блокировок спящего режима
Временные блокировки пробуждения используются в 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 уменьшается значение счетчика блокировки спящего режима. Когда оно достигает нуля, блокировка снимается.
Примечание. Время ожидания блокировки пробуждения для последовательности "запрос-подтверждение" будет меньше, чем используемое в настоящее время время ожидания, поскольку подтверждение должно быть получено достаточно быстро.
- После обработки запроса модем отправляет прерывание коду поставщика, который получает блокировку пробуждения и отправляет ответ в ril.cpp, который, в свою очередь, получает блокировку пробуждения и отправляет ответ на сторону Java.
- Когда ответ достигает стороны Java, блокировка пробуждения активируется и ответ возвращается вызывающей стороне.
- После того как все модули обработают ответ, подтверждение отправляется (через сокет) обратно в
ril.cpp, который затем освобождает блокировку пробуждения, полученную на шаге 3.
Решение 2. Модем не удерживает блокировку пробуждения, а ответ приходит быстро (синхронный запрос и ответ RIL). Синхронное или асинхронное поведение жестко задано для определенной команды RIL и определяется для каждого вызова.

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

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

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