В 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: Модем удерживает wakelock для запроса RIL и асинхронного ответа.

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

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

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

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