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

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

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

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

Вы можете реализовать любые или все вышеперечисленные улучшения. Дополнительные сведения см. в комментариях к коду версий RIL на https://android.googlesource.com/platform/hardware/ril/+/master/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. Модем удерживает блокировку для запроса RIL и асинхронного ответа.

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

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

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

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

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

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

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

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

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

Рисунок 5. Использование ack вместо синхронизированной wakelock.

Проверка переработанных вейклоков

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