Android 7.0 рефакторил Radio Interface Layer (RIL), используя набор функций для улучшения функциональности RIL. Для реализации этих функций требуются изменения в партнерском коде, которые необязательны, но приветствуются. Изменения рефакторинга обратно совместимы, поэтому предыдущие реализации рефакторинговых функций продолжают работать.
Рефакторинг RIL включает следующие улучшения:
- Коды ошибок RIL. Включает определенные коды ошибок в дополнение к существующему коду
GENERIC_FAILURE
. Это помогает в устранении ошибок, предоставляя более конкретную информацию о причине ошибок. - Управление версиями RIL. Предоставляет более точную и простую в настройке информацию о версиях.
- Связь RIL с использованием wakelocks. Улучшает работу батареи устройства.
Вы можете реализовать любые или все из вышеперечисленных улучшений. Для получения более подробной информации обратитесь к комментариям кода по управлению версиями 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
Временные wakelock-ы используются в RIL-коммуникации неточным образом, что негативно влияет на производительность батареи. В Android 7.x и выше вы можете повысить производительность, классифицируя запросы RIL и обновляя код для обработки wakelock-ов по-разному для разных типов запросов.
Классифицировать запросы RIL
Запросы RIL могут быть запрошенными или незапрошенными. Поставщики должны дополнительно классифицировать запрошенные запросы как одно из следующих:
- синхронный . Запросы, ответ на которые не занимает значительного времени. Например,
RIL_REQUEST_GET_SIM_STATUS
. - асинхронный . Запросы, ответ на которые занимает значительное время. Например,
RIL_REQUEST_QUERY_AVAILABLE_NETWORKS
.
Асинхронные запрошенные запросы RIL могут занять значительное время. После получения подтверждения от кода поставщика RIL Java снимает блокировку пробуждения, что может привести к переходу процессора приложения из состояния ожидания в состояние ожидания. Когда ответ доступен из кода поставщика, RIL Java (процессор приложения) повторно получает блокировку пробуждения, обрабатывает ответ, а затем возвращается в состояние ожидания. Такое перемещение из состояния ожидания в состояние ожидания и обратно может потреблять много энергии.
Если время отклика недостаточно велико, удержание wakelock и пребывание в состоянии бездействия в течение всего времени, необходимого для ответа, может быть более энергоэффективным, чем переход в состояние ожидания путем снятия wakelock и пробуждения при получении ответа. Поставщики должны использовать специфичные для платформы измерения мощности для определения порогового значения времени T , когда мощность, потребляемая при нахождении в состоянии бездействия в течение всего времени T , больше мощности, потребляемой при переходе из состояния бездействия в состояние приостановки и в состояние бездействия за то же время T Когда время T известно, команды RIL, которые занимают больше времени T можно классифицировать как асинхронные, а оставшиеся команды — как синхронные.
Сценарии коммуникации RIL
На следующих диаграммах показаны распространенные сценарии коммуникации RIL и представлены решения по изменению кода для обработки запрошенных и незапрошенных запросов RIL.
Примечание: Подробную информацию о реализации функций, используемых в следующих диаграммах, см. в методах acquireWakeLock()
, decrementWakeLock()
и clearWakeLock(
) в ril.cpp
.
Сценарий: запрос RIL и запрошенный асинхронный ответ
В этом сценарии, если ожидается, что запрошенный ответ RIL займет значительное время (т. е. ответ на RIL_REQUEST_GET_AVAILABLE_NETWORKS
), wakelock удерживается в течение длительного времени на стороне процессора приложения. Проблемы с модемом также могут привести к длительному ожиданию.
Решение 1: Модем удерживает wakelock для запроса RIL и асинхронного ответа.
- Отправляется запрос RIL, и модем получает блокировку сна для обработки этого запроса.
- Модем отправляет подтверждение, которое заставляет сторону Java уменьшать счетчик wakelock и освобождать его, когда значение счетчика становится равным 0.
Примечание: длительность тайм-аута wakelock для последовательности request-ack будет меньше текущей используемой длительности тайм-аута, поскольку подтверждение должно быть получено достаточно быстро.
- После обработки запроса модем отправляет прерывание коду поставщика, который получает wakelock и отправляет ответ ril.cpp, который, в свою очередь, получает wakelock и отправляет ответ стороне Java.
- Когда ответ достигает стороны Java, срабатывает wakelock и ответ возвращается вызывающей стороне.
- После обработки ответа всеми модулями подтверждение отправляется (через сокет) обратно в
ril.cpp
, который затем снимает блокировку пробуждения, полученную на шаге 3.
Решение 2: Модем не удерживает wakelock, и ответ быстрый (синхронный запрос и ответ 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 идентифицированы как синхронные или асинхронные. Поскольку потребление энергии батареи может зависеть от оборудования/платформы, поставщикам следует провести внутреннее тестирование, чтобы выяснить, приводит ли использование новой семантики wakelock для асинхронных вызовов к экономии энергии батареи.