Site icon AppTractor

Pixel не дал позвонить 911: разбор ошибки в Android и Microsoft Teams

29 ноября пользователь Reddit KitchenPicture5849 опубликовал душераздирающую историю о том, как телефон Pixel не смог позвонить в службу экстренной помощи. Пользователь, которому принадлежит Google Pixel 3 под управлением Android 11, попытался набрать 911, чтобы получить медицинскую помощь для своей бабушки в связи с подозрением на инсульт. После совершения звонка телефон «завис», и что он «не мог ничего делать, кроме как переходить по приложениям с экстренным телефонным звонком, работающим в фоновом режиме».

К счастью, у бабушки пользователя была стационарная связь, поэтому пользователь в конце концов смог позвонить в службу 911, но, тем не менее, ситуация была для пользователя очень тревожной. Общественность явно согласилась с ним, поскольку это сообщение в /r/GooglePixel стало самым популярным постом в сабреддите за все время. После того, как о публикации стало известно, пользователь Reddit воспроизвел ошибку и заявил, что через пять минут после звонка не было ответа от служб экстренной помощи или доказательств того, что звонок состоялся — как из лога телефона на устройстве, так и оператора связи (Verizon).

Команда поддержки Google связалась с пользователем Reddit, чтобы диагностировать проблему, и 8 декабря представитель компании наконец публично ответил на этот вопрос. Согласно расследованию Google, проблема может возникнуть, когда пользователь установил приложение Microsoft Teams, но не вошел в систему, что может привести к «непреднамеренному взаимодействию между приложением Microsoft Teams и базовой операционной системой Android». Вот полное заявление Google, опубликованное в аккаунте PixelCommunity:

На основании нашего расследования нам удалось воспроизвести проблему при ограниченном наборе обстоятельств. Мы считаем, что проблема присутствует только на небольшом количестве устройств с установленным приложением Microsoft Teams, когда пользователь не вошел в систему, и в настоящее время нам известен только один отчет пользователя, связанный с возникновением этой ошибки. Мы определили, что проблема была вызвана непреднамеренным взаимодействием между приложением Microsoft Teams и базовой операционной системой Android. Поскольку эта проблема влияет на вызов службы экстренной помощи, и Google, и Microsoft уделяют ей большое внимание, и мы ожидаем, что обновление приложения Microsoft Teams будет выпущено в ближайшее время — как всегда, мы рекомендуем пользователям следить за обновлениями приложений, чтобы убедиться, что они используют последнюю версию. 4 января мы также представим обновление платформы Android.

Тем временем из соображений осторожности мы предлагаем пользователям с Microsoft Teams, установленным на любом устройстве Android под управлением Android 10 и более поздних версий, выполнить следующие действия:

Если вы не знаете, на какой версии Android вы работаете, подтвердите, что используете Android 10 или более позднюю версию, выполнив следующие действия. Если вы не используете Android 10 или более позднюю версию, эта проблема не влияет на вас.

Если у вас загружено приложение Microsoft Teams, проверьте, вошли ли вы в систему. Если вы вошли в систему, эта проблема не влияет на вас, и мы рекомендуем вам оставаться в системе до тех пор, пока вы не получите обновление приложения Microsoft Teams.

Если у вас загружено приложение Microsoft Teams, но вы не вошли в систему, удалите и переустановите приложение. Пока это решит проблему, для полного решения проблемы по-прежнему требуется обновление приложения Microsoft Teams.

Мы советуем пользователям следить за обновлением приложения Microsoft Teams и выполнить его в кратчайшие сроки. Мы обновим этот пост, как только новая версия Microsoft Teams станет доступна 100% пользователей.

Мы очень серьезно относимся к подобным вопросам и хотим поблагодарить u/KitchenPicture5849 за то, что обратил на это наше внимание.

Понятно, что открытие того, что стороннее приложение, такое как Microsoft Teams, может вмешиваться в такой критический процесс, как набор экстренного номера, многих пользователей расстроило и смутило. Ни при каких обстоятельствах нельзя блокировать экстренный набор номера на устройстве. По закону операторы связи обязаны направлять экстренные вызовы в местные службы экстренной помощи, даже если у устройства нет SIM-карты в их сети.

Так что же на самом деле произошло в этом случае и что именно Google и Microsoft делают для смягчения этой проблемы? Благодаря моему другу Кубе Войцеховски (@Za_Raczke в Твиттере) я нашел подсказки, чтобы собрать вещи воедино. С его помощью я смог найти куски кода, которые вызывают эту проблему, и выяснил, что приложение Microsoft Teams делает не так и как это повлияло на службу экстренных вызовов Android.

Слишком много PhoneAccount

Проблема может быть прослежена до методов adjustAttemptsforEmergency и sortSimPhoneAccountsForEmergency в классе CreateConnectionProcessor. Метод adjustAttemptsforEmergency решает, какой экземпляр PhoneAccount должен обрабатывать экстренный вызов. Согласно документации Google, «приложения, которые могут совершать звонки и хотят, чтобы эти звонки были интегрированы в набор номера и пользовательский интерфейс во время звонка, должны создать экземпляр класса [PhoneAccount] и зарегистрировать его в системе с помощью TelecomManager». По сути, многие приложения Android с функцией телефонных звонков — будь то через стандартную платформу дозвона или настраиваемую службу, подключающуюся к удаленной конечной точке — создают свой экземпляр PhoneAccount. Сюда входит приложение Microsoft Teams, которое использует серверную часть Skype для голосовых вызовов.

Поскольку Microsoft Teams управляет своим собственным Connection вместо телефонного приложения по умолчанию, приложение регистрирует PhoneAccount с флагом CAPABILITY_SELF_MANAGED. Однако, поскольку приложение Teams не может обрабатывать экстренные вызовы, оно не регистрируется с флагом CAPABILITY_PLACE_EMERGENCY_CALLS. Важность этих двух констант станет ясна вскоре.

Если мы вернемся к классу adjustAttemptsForEmergency, первое, что мы заметим, это то, что класс получает список всех зарегистрированных экземпляров PhoneAccount.

Сюда входят экземпляры без определения CAPABILITY_PLACE_EMERGENCY_CALLS, в том числе экземпляры, созданные приложением Microsoft Teams. Следующий блок кода добавляет резервную учетную запись телефона для экстренных случаев на случай, если список экземпляров PhoneAccount пуст, поэтому мы можем двигаться дальше. Мы также можем пропустить следующий блок, который касается тестирования экстренных вызовов через службу тестового подключения.

Однако затем adjustAttemptsForEmergency пытается получить «предпочтительный для пользователя» экземпляр PhoneAccount, который, по мнению службы Telephony, должен обрабатывать экстренные вызовы.

Однако и на этом все не заканчивается, так как Android затем сортирует список PhoneAccount в случае, если существует несколько экземпляров с определенным CAPABILITY_PLACE_EMERGENCY_CALLS, и один из них имеет более высокий рейтинг, чем «предпочитаемый пользователем» PhoneAccount.

Возможно, вы уже увидели одну проблему —  sortSimPhoneAccountsforEmergency вызывается со списком, который содержит все экземпляры PhoneAccount, даже те, у которых нет CAPABILITY_PLACE_EMERGENCY_CALLS. Microsoft Teams даже не должно быть в списке, и тем не менее, это так. Однако, если бы это была основная проблема в этом сбое, то каждый телефон Android с установленной Microsoft Teams не смог бы набрать 911, а это явно не так.

Однако внутри метода sortSimPhoneAccountsforEmergency есть код, который при определенных обстоятельствах может привести к целочисленной ошибке переполнения/потери значимости. Этот метод сортирует список PhoneAccount в возрастающем порядке, выполняя несколько сравнений между каждой учетной записью телефона в списке. Эти сравнения включают проверку того, какой PhoneAccount поддерживает CAPABILITY_SIM_SUBSCRIPTION, что является вышеупомянутой «предпочтительной для пользователя» учетной записью, и какая учетная запись связана с действительным идентификатором подписки и индексом слота SIM-карты. Если два сравниваемых экземпляра PhoneAccount одинаковы, метод затем упорядочит список по имени пакета, метке и, наконец, по хэш-коду. Даже если два сравниваемых экземпляра PhoneAccount имеют одинаковые возможности, имя пакета и метку, они могут иметь разные значения хэш-кода.

Проблема с этой строкой в ​​том виде, в котором она написана, в том, что она может привести к целочисленному переполнению, если значение account1.hashCode() — account2.hashCode() меньше Integer.MIN_VALUE или больше Integer.MAX_VALUE. Обычно существует не так много PhoneAccount для сортировки, и метод обычно никогда не достигает этого блока кода, поскольку другие сравнения, вероятно, уже преуспевают в ранжировании двух экземпляров PhoneAccount, поэтому шансы добиться целочисленного переполнения/потери значимости в этом вычислении действительно очень малы.

Но что, если бы для этого метода были потенциально десятки повторяющихся экземпляров PhoneAccount? В этом случае вероятность получения целочисленного переполнения/потери значимости возрастает. Даже не анализируя декомпилированный код приложения Microsoft Teams, легко убедиться, что в приложении есть ошибка, которая приводит к избыточной регистрации экземпляров PhoneAccount. Каждый раз, когда приложение Microsoft Teams установлено, но пользователь не вошел в систему, каждый холодный запуск приложения приводит к созданию другого экземпляра PhoneAccount.

До установки Microsoft Teams на моем Google Pixel 4 было только два зарегистрированных экземпляра PhoneAccount под управлением Android 12 SQ1A.211205.008. Один экземпляр был построен TelephonyService, а другой — Google Duo.

После установки Microsoft Teams и его запуска (но без входа в систему) появляется третий экземпляр PhoneAccount. Этот экземпляр был сделан Microsoft Teams.

После принудительного закрытия Microsoft Teams и его перезапуска создается еще один экземпляр PhoneAccount.

Повторив последний шаг еще 15 раз, я получил 17 практически дублирующих экземпляров PhoneAccount, созданных Microsoft Teams.

После удаления и повторной установки Microsoft Teams я решил войти в систему сразу после запуска приложения. Затем я принудительно закрыл приложение и повторно запускал его несколько раз. Хотя приложением и был создан второй экземпляр PhoneAccount, после этого экземпляров больше не создавалось.

Я не знаю, в каком выпуске приложения Microsoft Teams впервые появилось такое поведение, но я могу подтвердить, что оно проявляется в версиях 1416/1.0.0.2021163901 и 1416/1.0.0.2021183702 приложения. Первый был загружен в APKMirror 28 октября 2021 года, примерно за месяц до того, как пользователь Reddit обнаружил ошибку. Это последняя версия в Play Store.

Если вы хотите воспроизвести это поведение самостоятельно, установите одну из упомянутых мной версий Teams и выполните следующую команду оболочки ADB, чтобы просмотреть список PhoneAccount:

dumpsys telecom | sed -n ‘/PhoneAccountRegistrar/,/Analytics/p’

Удаление, а затем повторная установка приложения приведет к удалению всех созданных им экземпляров PhoneAccount, что является одним из шагов по смягчению последствий, которые рекомендует Google.

Я также не знаю, как именно пользователь Reddit получил на своем устройстве столько экземпляров PhoneAccount, созданных Microsoft Teams. Я не так часто использую Microsoft Teams, но, судя по тому, что я читал в Интернете, были проблемы, когда приложение часто выводило пользователей из системы. Я также читал отчеты о том, что предприятия могут устанавливать политику для периодического выхода пользователя из системы по соображениям безопасности.

Череда досадных событий

После проверки декомпилированной версии приложения Microsoft Teams мы смогли определить, почему новый экземпляр PhoneAccount появляется каждый раз при перезапуске приложения. Мы обнаружили, что, когда пользователь не вошел в систему, новый, случайно сгенерированный UUID используется для создания экземпляра PhoneAccount, который добавляется в TelecomManager в Android. Это означает, что каждый раз при перезапуске или сбое приложения Teams создается новый UUID для пользователей, которые не вошли в систему, и, таким образом, новый PhoneAccount добавляется в TelecomManager в Android. Поскольку в Teams есть boot broadcast receiver, это также происходит при каждой перезагрузке телефона.

Соответствующий псевдокод:

String userId = MS_Teams_Current_User_ID;

if (StringUtils.isEmptyOrWhiteSpace(userId)) {

userId = UUID.randomUUID().toString();

}

TelecomManager.registerPhoneAccount(PhoneAccount.builder(new PhoneAccountHandle(componentName, userId), applicationName).setCapabilities(capabilities).build());

Здесь userId + componentName составляют PhoneAccountHandle, который представляет собой уникальный идентификатор, используемый для сравнения разных PhoneAccount в AOSP. UserId используется в Teams для идентификации сеанса Teams и не используется явно за пределами приложения.

У пользователей, вошедших в приложение Teams, не будет дублирующих экземпляров PhoneAccount, поскольку userId будет таким же, как и уже зарегистрированный PhoneAccount. Это также объясняет, почему в случае, когда я установил и сразу вошел в Teams, все еще оставалось два экземпляра PhoneAccount, созданных Teams: один был построен со случайно сгенерированным UUID, а другой — с userId учетной записи Teams.

Вот трассировка стека, показывающая, как Teams вызывает метод registerPhoneAccount в PhoneAccountRegistrar при перезапуске приложения.

В любом случае, обилие повторяющихся экземпляров PhoneAccount повышает вероятность возникновения целочисленной ошибки переполнения/потери значимости, когда пользователь пытается совершить экстренный вызов. Я не могу определить, является ли целочисленная ошибка переполнения/потери тем этапом, на котором все идет не так, без изучения того, как эта ошибка влияет на остальную часть стека телефонии. Это требует дальнейшего анализа.

Два патча, и еще больше впереди

Я вполне уверен, что именно из-за этой ошибки целочисленного переполнения/потери значимости все начинает идти не так, поскольку это именно то, на что обращено внимание при изменении кода. Это изменение кода, озаглавленное «Исправить целочисленное переполнение/недостаточное заполнение, вызванное сортировкой дублирующихся телефонных учетных записей во время попытки экстренного вызова», что интересно, было представлено инженером Samsung еще 25 ноября, за четыре дня до того, как появилось обсуждение в Reddit. К сожалению, связанный отчет об ошибке не является общедоступным, поэтому мы не можем понять, как инженеры обнаружили эту проблему. Таким образом, мы не знаем наверняка, был ли отчет об ошибке вызван той же проблемой Microsoft Teams с дублированием PhoneAccount, но это было бы чертовски интересным совпадением, если бы это было не так.

В любом случае это исправление кода решает проблему целочисленного переполнения/потери значимости простым способом. Оно заменяет простое вычитание, используемое для сравнения хэш-кодов, с Integer.compare, которое возвращает только -1, 0 или 1. Стоит отметить, что приложение Teams регистрирует PhoneAccounts только в том случае, если оно работает на уровне API 28+ (Android 9 Pie и более поздние версии), но изменение кода, которое реализовало метод sortSimPhoneAccountsforEmergency в том виде, в котором он был изначально написан, было передано в AOSP в середине 2019 года и было включено в ветку android10-release, поэтому эта ошибка затрагивает только устройства Android под управлением Android 10+.

Однако это не единственное изменение кода, направленное на решение этой проблемы. Другое на днях было внесено в общедоступную главную ветку AOSP. По словам сотрудника Google, отправившего патч, это изменение кода «представляет собой cherry-pick от внутреннего геррита». Он добавляет новые строки в метод adjustAttemptsForEmergency, чтобы отфильтровать экземпляры PhoneAccount, которые являются самоуправляемыми, т. е с определенным CAPABILITY_SELF_MANAGED. Это предотвратит передачу экземпляров PhoneAccount, подобных созданным Microsoft Teams, методу sortSimPhoneAccountsforEmergency, что разумно, поскольку только телефонная служба по умолчанию должна обрабатывать экстренные вызовы.

Google заявляет, что компания представит «обновление платформы Android для экосистемы Android 4 января». Служба Telecomm не входит ни в один из 23 модулей Mainline, перечисленных Google, поэтому я не думаю, что она будет исправлена ​​через Google Play System Update. Таким образом, исправления могут быть доставлены на устройства как часть исправления безопасности 2022–01–01, которое должно начать развертываться на устройствах, когда 3 января 2022 года, в первый понедельник месяца, будет опубликован бюллетень по безопасности Android за январь 2022 года.

В любом случае скоро будет обновление, и не только от Google. Microsoft развернет новую версию Teams, которая, вероятно, решит проблему с созданием дублирующихся экземпляров PhoneAccount. Microsoft может устранить эту ошибку на своей стороне, создав UUID один раз и прочитав его из SharedPreferences.

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

Источник

Exit mobile version