На прошлой неделе на Хабре был популярный пост о странностях в поведении приложения Яндекс.Метро под Андроид. Мы очень серьёзно относимся к вопросам приватности наших пользователей и корректности поведения наших программ и по итогам поста провели внутреннее расследование.
Его результатом стал не только подробный рассказ о происходившем, который можно прочитать ниже, но и обновление Яндекс.Метро для Android, в котором мы исправили ошибки, приводившие к описанному поведению. Сейчас оно раскатывается в сторе. Напомним, что приложение в фоновом режиме могло отправлять данные на сервера Яндекса. Мы в изначальном посте сразу же ответили, что это баг и такое поведение не было заложено в Метро.
За прошедшее время мы нашли причины, которые привели к подобной ситуации, и сейчас проверяем все наши приложения на предмет таких ошибок.
Мы хотим извиниться перед всеми, кого затронула эта проблема, сказать спасибо автору оригинального поста merced2001, а также всем пользователям, которые помогали выяснять подробности и задавали хорошие вопросы. В самом начале — очень краткие ответы на те, которые были явно заданы в том посте.
Как связан постоянный сбор информации о моем местоположении с работой Вашей карты метро?
Никак. Отправка данных, когда приложение не запущено, — ошибка. Мы исправили её в обновлении, которое выкатывается сегодня. Сбор информации в тот момент, когда приложение запущено, нужен, подробнее — ниже.
Зачем вам круглосуточные сведения о моем местоположении?
Они нам не нужны, и мы исправили приложение, чтобы такого больше не было.
Теперь подробнее.
То, что приложения Яндекса общаются с серверами Яндекса и передают статистические данные — нормальное поведение, которое описано в пользовательском соглашении. В случае Яндекс.Метро соединение с сетью нужно в следующих случаях:
Но то, что приложение отправляло данные, будучи запущено в фоне, действительно очень неприятная ошибка. Ещё не разобравшись, в чём причина, мы сразу сказали, что это баг и так быть не должно.
Как же возникла эта ошибка? Отправка статистики была вставлена в обработчик Application.onCreate(), который вызывается каждый раз при инициализации любого из процессов Метро, не учитывая, что бывают не только запуски приложения пользователем, но и фоновые вызовы процессов приложения. О том, зачем на Андроиде приложению вообще работать в фоне, я объясню чуть ниже.
Мы исправили эту ошибку в Метро и теперь проводим аудит всех остальных наших приложений, чтобы найти и, если обнаружим, убрать отправку статистики, когда приложение запускается в фоновом режиме. Тут ещё стоит отличать запуск приложения фоновыми процессами от вполне легитимной ситуации работы приложения в фоне. Например, Яндекс.Музыка играет в фоне песни, а Яндекс.Диск — синхронизирует фотографии. Эти действия требуют обращения в сеть, что нормально. Но если приложение было запущено пользователем, затем он из него вышел, система его выгрузила, а потом по какому-либо событию загрузила в фоне, то, конечно, статистика отправляться не должна.
Есть одно исключение из этого правила, которое нам заранее известно, — Яндекс.Метрика для приложений. Это наша система статистики, которую создатели приложений могут внедрить в свои продукты. Она не пытается работать с сетью в каждом приложении, в котором установлена, а выбирает одно приложение на телефоне как ведущее, создаёт в его рамках отдельным процессом сервис, через который все остальные приложения отправляют свою статистику. Таким «главным» приложением может быть выбрано любое из тех, где есть Метрика (в том числе и Метро). Тогда в фоне запросы через него уходить продолжат — но лишь те, которые отправляет активное приложение с Яндекс.Метрикой.
Многие из вас понимают, как устроена ОС Андроид, и знают, что вызов отдельных процессов приложений в фоне — это совершенно нормальное её поведение. Приложения могут подписываться на разные события и вызываться при их наступлении, обрабатывать поступающие данные и переставать работать. Например, Яндекс.Почта подписана на пуши от сервера о факте прихода нового письма. Она запускается, получает письмо, показывает нотификацию и по клику на неё позволяет прочитать письмо. Yandex.Store подписывается на события установки любых приложений.
Яндекс.Метро было подписано на событие загрузки системы, потому что в нём есть опциональная возможность включить поисковый виджет в области нотификаций, который должен загружаться вместе со стартом системы. Процесс Метро запускается в процессе загрузки ОС, проверяет состояние этой опции и, если виджет не включен, выходит, заканчивая свою работу.
Однако невзирая на то, что это в целом нормально, мы считаем, приложения не должны запускаться слишком часто — в некоторых жалобах говорили о том, что Метро запускается в фоне раз в минуту! Это явно неправильно — нужно экономить батарейку и другие ресурсы телефона. Поэтому в процессе разбора возникшей ситуации мы начали проверку всех наших приложений, чтобы постараться сократить количество фоновых запусков.
Действительно, часть запросов некоторые наши приложения до сих пор отправляют по HTTP. Мы понимаем, что это неправильно, и постепенно переводим весь портал Яндекса, включая приложения, на HTTPS. Сразу предупредим подозрения — это не для того, чтобы скрыть факты сбора данных, — соединения вы всё равно можете увидеть, скажем, в firewall. Это для того, чтобы предотвратить перехват ваших данных третьими лицами и защитить ответы Яндекса от модификаций злоумышленниками.
Его результатом стал не только подробный рассказ о происходившем, который можно прочитать ниже, но и обновление Яндекс.Метро для Android, в котором мы исправили ошибки, приводившие к описанному поведению. Сейчас оно раскатывается в сторе. Напомним, что приложение в фоновом режиме могло отправлять данные на сервера Яндекса. Мы в изначальном посте сразу же ответили, что это баг и такое поведение не было заложено в Метро.
За прошедшее время мы нашли причины, которые привели к подобной ситуации, и сейчас проверяем все наши приложения на предмет таких ошибок.
Мы хотим извиниться перед всеми, кого затронула эта проблема, сказать спасибо автору оригинального поста merced2001, а также всем пользователям, которые помогали выяснять подробности и задавали хорошие вопросы. В самом начале — очень краткие ответы на те, которые были явно заданы в том посте.
Как связан постоянный сбор информации о моем местоположении с работой Вашей карты метро?
Никак. Отправка данных, когда приложение не запущено, — ошибка. Мы исправили её в обновлении, которое выкатывается сегодня. Сбор информации в тот момент, когда приложение запущено, нужен, подробнее — ниже.
Зачем вам круглосуточные сведения о моем местоположении?
Они нам не нужны, и мы исправили приложение, чтобы такого больше не было.
Теперь подробнее.
Почему приложение отправляет данные
То, что приложения Яндекса общаются с серверами Яндекса и передают статистические данные — нормальное поведение, которое описано в пользовательском соглашении. В случае Яндекс.Метро соединение с сетью нужно в следующих случаях:
- для геолокации пользователя — мы показываем текущее положение на карте метро, позволяя строить маршруты;
- для обновления карт Метро, что происходит достаточно часто — особенно в Москве;
- для сбора статистики использования приложения, которая позволяет его улучшать.
Но то, что приложение отправляло данные, будучи запущено в фоне, действительно очень неприятная ошибка. Ещё не разобравшись, в чём причина, мы сразу сказали, что это баг и так быть не должно.
Как же возникла эта ошибка? Отправка статистики была вставлена в обработчик Application.onCreate(), который вызывается каждый раз при инициализации любого из процессов Метро, не учитывая, что бывают не только запуски приложения пользователем, но и фоновые вызовы процессов приложения. О том, зачем на Андроиде приложению вообще работать в фоне, я объясню чуть ниже.
Мы исправили эту ошибку в Метро и теперь проводим аудит всех остальных наших приложений, чтобы найти и, если обнаружим, убрать отправку статистики, когда приложение запускается в фоновом режиме. Тут ещё стоит отличать запуск приложения фоновыми процессами от вполне легитимной ситуации работы приложения в фоне. Например, Яндекс.Музыка играет в фоне песни, а Яндекс.Диск — синхронизирует фотографии. Эти действия требуют обращения в сеть, что нормально. Но если приложение было запущено пользователем, затем он из него вышел, система его выгрузила, а потом по какому-либо событию загрузила в фоне, то, конечно, статистика отправляться не должна.
Есть одно исключение из этого правила, которое нам заранее известно, — Яндекс.Метрика для приложений. Это наша система статистики, которую создатели приложений могут внедрить в свои продукты. Она не пытается работать с сетью в каждом приложении, в котором установлена, а выбирает одно приложение на телефоне как ведущее, создаёт в его рамках отдельным процессом сервис, через который все остальные приложения отправляют свою статистику. Таким «главным» приложением может быть выбрано любое из тех, где есть Метрика (в том числе и Метро). Тогда в фоне запросы через него уходить продолжат — но лишь те, которые отправляет активное приложение с Яндекс.Метрикой.
Работа приложений в фоне
Многие из вас понимают, как устроена ОС Андроид, и знают, что вызов отдельных процессов приложений в фоне — это совершенно нормальное её поведение. Приложения могут подписываться на разные события и вызываться при их наступлении, обрабатывать поступающие данные и переставать работать. Например, Яндекс.Почта подписана на пуши от сервера о факте прихода нового письма. Она запускается, получает письмо, показывает нотификацию и по клику на неё позволяет прочитать письмо. Yandex.Store подписывается на события установки любых приложений.
Яндекс.Метро было подписано на событие загрузки системы, потому что в нём есть опциональная возможность включить поисковый виджет в области нотификаций, который должен загружаться вместе со стартом системы. Процесс Метро запускается в процессе загрузки ОС, проверяет состояние этой опции и, если виджет не включен, выходит, заканчивая свою работу.
Однако невзирая на то, что это в целом нормально, мы считаем, приложения не должны запускаться слишком часто — в некоторых жалобах говорили о том, что Метро запускается в фоне раз в минуту! Это явно неправильно — нужно экономить батарейку и другие ресурсы телефона. Поэтому в процессе разбора возникшей ситуации мы начали проверку всех наших приложений, чтобы постараться сократить количество фоновых запусков.
HTTPS vs. HTTP
Действительно, часть запросов некоторые наши приложения до сих пор отправляют по HTTP. Мы понимаем, что это неправильно, и постепенно переводим весь портал Яндекса, включая приложения, на HTTPS. Сразу предупредим подозрения — это не для того, чтобы скрыть факты сбора данных, — соединения вы всё равно можете увидеть, скажем, в firewall. Это для того, чтобы предотвратить перехват ваших данных третьими лицами и защитить ответы Яндекса от модификаций злоумышленниками.