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

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

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

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

Вы можете реализовать любое или все из вышеперечисленных улучшений. Дополнительные сведения см. в комментариях к коду по управлению версиями RIL в https://android.googlesource.com/platform/hardware/ril/+/main/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, соответствующая вашему коду RIL, возвращается во время RIL_REGISTER (а не 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 acquireWakeLock() , decrementWakeLock() clearWakeLock( ) в ril.cpp .

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

В этом сценарии, если ожидается, что ответ, запрошенный RIL, займет значительное время (т. е. ответ на RIL_REQUEST_GET_AVAILABLE_NETWORKS ), пробуждение удерживается в течение длительного времени на стороне процессора приложения. Проблемы с модемом также могут привести к длительному ожиданию.

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

Решение 1. Модем удерживает блокировку пробуждения для запроса RIL и асинхронного ответа.

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

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

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

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

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

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

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

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

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

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

Проверка обновленных Wakelocks

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