# Как взаимодействуют Player и Indexer [Читать на сайте](https://roadio.link/tldr/ru/player-indexer/) Player отвечает за воспроизведение и взаимодействие с человеком, а Indexer — за подготовку библиотеки. Они входят в одно приложение Riff, но работают в двух отдельных процессах Android. Процесс — это выполняющаяся часть программы со своей памятью и своим временем жизни: Android может остановить один процесс, пока другой продолжает работать. ## Кто за что отвечает? Player показывает экраны, воспроизводит звук, управляет очередью и сохраняет настройки, плейлисты и историю прослушивания. Indexer обнаруживает файлы, извлекает сведения о них, определяет идентичность содержимого, выполняет анализ и формирует готовые каталоги альбомов, исполнителей и жанров. Player может фильтровать и сортировать эти каталоги для показа, но правила объединения файлов в альбомы выполняет Indexer. Каждый процесс владеет своими изменяемыми данными и не открывает изменяемую базу другого. Обработка библиотеки выполняется отдельно от критических задач воспроизведения и подчинена непрерывности звука. Это разделение закреплено в [контракте архитектуры](https://wiki.271.pics/Riff/LATEST/runtime-architecture). ## Зачем нужен AIDL и как происходит вызов? Два процесса не могут обращаться к памяти друг друга так, как части программы внутри одного процесса. Им нужен явно определённый способ обмена: какие запросы разрешены, какие параметры передаются и какой ответ можно получить. В Riff этот способ описан через AIDL — Android Interface Definition Language, язык описания интерфейсов Android. Файлы `.aidl` задают перечень операций и типы данных. При сборке Android создаёт код для упаковки параметров, передачи через системный механизм Binder и восстановления на принимающей стороне. Программисты реализуют действия, которые должны выполняться при каждом вызове. При подключении Player получает интерфейс сервиса Indexer. Вызов его метода выглядит для программного кода как обращение к функции, но параметры проходят через Binder в другой процесс. Там получатель выполняет предусмотренное действие. AIDL описывает форму обращения, а Binder обеспечивает передачу между процессами. [Документация Android](https://developer.android.com/develop/background-work/services/aidl). В проекте есть два встречных интерфейса. `IIndexerArtifactService` позволяет Player обращаться к Indexer: установить канал связи, запросить данные библиотеки и управлять согласованными операциями. `IPlayerArtifactCallback` позволяет Indexer обращаться обратно к Player: отправлять уведомления, состояние работы и подтверждения. Обратный интерфейс нужен, потому что результат часто появляется позже запроса; Player не должен непрерывно спрашивать, завершилась ли работа. Связь предназначена для компонентов самого Riff. Сервис Indexer не предоставляется посторонним приложениям. Обмен происходит на устройстве и не требует интернета. ## Как стороны понимают, что команда выполнена? После подключения стороны устанавливают сеанс обмена. В AIDL для этого предусмотрен `openReliableChannel`: Player передаёт свой обратный интерфейс и идентификатор текущего экземпляра. Сеанс отличает сообщения действующих процессов от запоздавших сообщений после перезапуска. Поверх Binder контракт Riff задаёт собственные правила надёжной доставки. Команда содержит идентификатор сеанса, последовательный номер, тип и параметры. Получатель выполняет определённое для команды действие и возвращает ACK — подтверждение с результатом. В каждом направлении одновременно только одна команда ожидает подтверждения. Отправка вызова ещё не означает выполнения действия. Часть AIDL-вызовов помечена `oneway`: отправитель продолжает работу, не ожидая ответа на этот вызов. Отдельное подтверждение Riff сообщает о принятом или выполненном действии согласно смыслу команды. Если подтверждение не пришло, отправитель повторяет тот же пакет с тем же номером. Получатель распознаёт повтор и возвращает сохранённый результат, не выполняя действие второй раз. Потеря подтверждения не должна повторно запускать изменение данных. Для продолжительных операций принятие запроса и окончательный результат передаются отдельно: подтверждение начала не означает завершения всей работы. При восстановлении связи между прежними экземплярами незавершённый обмен сохраняется. Новый экземпляр устанавливает новый сеанс; старые команды не переносятся в него автоматически. Обработка сообщений и ожидание подтверждений выполняются отдельно от интерфейса и критических задач воспроизведения. [Контракт надёжного обмена](https://wiki.271.pics/Riff/LATEST/reliable-player-indexer-ipc). ## Как передаётся большая библиотека? Библиотека передаётся отдельно от коротких управляющих сообщений. Indexer подготавливает неизменяемый комплект из четырёх согласованных файлов: сведения о медиа, альбомах, исполнителях и жанрах. Этот комплект представляет одну принятую версию библиотеки. Сначала Indexer полностью записывает файлы и сведения для проверки целостности. После этого он одним атомарным переключением делает комплект текущим: для потребителя существует либо прежний полный комплект, либо новый. Смешивать альбомы одной версии с медиа другой запрещено. Через AIDL Player получает файловый дескриптор — предоставленный Android доступ к конкретному уже открытому файлу только для чтения. Вместе с ним передаются номер поколения, размер, версии формата и контрольная сумма для проверки содержимого. Player не должен самостоятельно искать переданный файл по общему пути. Пока он обрабатывает уведомление, Indexer может подготовить следующую версию. Дескриптор сохраняет доступ именно к переданному файлу, даже если его прежнее имя уже удалено. Player проверяет комплект и принимает его целиком. Пока идёт проверка, прежняя принятая библиотека остаётся активной. Неполный или повреждённый кандидат её не заменяет. При запуске Indexer сначала предоставляет существующий корректный комплект, если он есть, затем начинает новое сканирование. [Контракт публикации](https://wiki.271.pics/Riff/LATEST/immutable-publication). ## Когда появляются результаты сканирования? Indexer последовательно обнаруживает источники, извлекает сведения и идентификаторы, затем выполняет необходимый анализ. Он отправляет Player готовый текст состояния: этап, число обработанных объектов и скорость. Player показывает этот текст. Изменение числа обработанных файлов ещё не означает появления нового комплекта библиотеки. Обновления публикуются только в завершённых, проверенных состояниях. Первая промежуточная публикация изменённых данных предусмотрена через 30 секунд от начала обработки, последующие — через 60 секунд после предыдущей успешной публикации, на безопасной границе завершённой работы. Долгая операция сначала завершается; частичный результат не публикуется. По окончании прохода оставшиеся изменения публикуются сразу. Ошибка сканирования сохраняет последний принятый Player комплект. [Этапы и публикации](https://wiki.271.pics/Riff/LATEST/indexer-staging). ## Что происходит при сбое Indexer? Перед обработкой конкретного источника Indexer регистрирует попытку в небольшом журнале в памяти Player и получает подтверждение. После завершения он сообщает об окончании попытки, и соответствующая запись удаляется. Если Indexer действительно погиб, оставшаяся запись помогает осторожно проверить подозрительный источник после нового обнаружения файлов. Незавершённая попытка сама по себе ещё не признаётся ошибкой источника. Потерянное сообщение или задержка также не означают повреждения файла. Player хранит сведения о попытке, но не сканирует и не разбирает медиа. Журнал находится только в памяти. Если погибают оба процесса, он теряется и новый сеанс начинает обычную обработку. [Контракт восстановления](https://wiki.271.pics/Riff/LATEST/indexer-source-failures). ## Как согласуется изменение доступа к папкам? Перед изменением разрешений на выбранные папки Player просит уже подключённый Indexer завершить текущую обработку со старыми разрешениями и подтвердить готовность. Затем Player меняет разрешения и запрашивает один новый полный проход. Если барьер завершения не выполнен, разрешения остаются прежними. Так Indexer не продолжает обработку с доступом, который уже изменился. При первом выборе папок из состояния без разрешений активного прохода ещё нет: Player сохраняет выбор, подключает Indexer и запускает начальную обработку. [Правила изменения папок](https://wiki.271.pics/Riff/LATEST/indexer-staging#6-saf-draft-and-rescan-boundary).