Как стать автором
Обновить

Интеграция FATFS библиотеки для организации чтения дискового устройства на iOS

Время на прочтение5 мин
Количество просмотров4.7K

Введение


Статья посвящена внедрению open source библиотеки на iOS для чтения/записи данных с MFI дискового устройства на основе FAT12/FAT16/FAT32/Exfat. Представлен способ построения архитектуры приложения, на основе FATFS библиотеки, а также методы отладки и тестирования проводных MFI-устройств. Статья практически не содержит кода из-за соблюдения NDA.

Постановка задачи


Главной целью было создание некого универсального SDK (.framework), способного работать с производителями различных устройств дискового доступа по протоколу MFI, использующих единый стандарт по API.



На рисунке представлена обобщенная структурная схема такого фреймворка. В зависимости от протокола устройства выбирается та или иная библиотека взаимодействия с устройством. В зависимости от того, какая файловая система (FS) используется на диске, выбирается соответствующий алгоритм работы с диском: FAT/exFat/Other FS. При этом, к устройству могут иметь доступ несколько приложений (использующих данный SDK), находящихся в памяти устройства однако запись/чтение единовременно может выполнять только одно. Данный SDK подразумевает использование его во многопоточном приложении c конкурентными задачами чтения и записи.

Поиск решения


Первоначально в качестве базовой библиотеки для реализации FS FAT32 была выбрана реализация FAT32, созданная Apple. Однако, сложность интеграции стандартного API для устройства доступа вследствие привязки к конкретной платформе заставила пойти в направлении поиска готового решения с раздельным абстрактным API для физического уровня доступа c MFI устройством через библиотеку производителя. Были рассмотрены также EFSL и FATFS open source реализации FAT32. FATFS была выбрана вследствие нескольких причин:

• текущая поддержка библиотеки
• независимость платформы и простота портирования
• широкий спектр параметров конфигурации
• поддержка exFAT
• абстрактный уровень доступа для медиа драйверов

Вследствие проблем получения логов работы приложения, учитывая, что физически разъем был занят и не было возможности подключения к XCode, была подключена библиотека NSLogger, позволяющая передавать логи по Wi-Fi почти в real time режиме. Тем не менее, проблема отладки такой библиотеки имела место быть. Было решено разработать симулятор MFI устройства, который обращался к некой области на диске iOS/MAC устройства и эмулировал чтение/запись по тому же API, что и реальное устройство.

Проблемы интеграции


Портирование на Obj-C


FATFS написан на чистом С, а интегрировать приходилось в библиотеку написанной на ObjC. Несмотря на то, что ObjC напрямую поддерживает интеграцию C функций, возникали проблемы с сигнатурами функций и с использованием некоторых типов переменных.

Поддержка Unicode


Опция Unicode адекватно работала только с параметром кодировки Obj-C NSUTF16LittleEndianStringEncoding, несмотря на то, что согласно заявленным требованиям поддерживалось дополнительно UTF-16BE и UTF-8. Все методы, работающие с именами файлов необходимо было сделать потокобезопасными для корректной работы FAT32.

Thread safe


Опция потокобезопасности, активизируемая по параметру FS_REENTRANT и реализуемая через функции ff_req_grant, ff_rel_grant, ff_del_syncobj потребовала дополнительной имплементации через POSIX. Без включенной опции потокобезопасности наблюдалось повреждение таблицы файловой системы и как следствие — потеря данных. Файловый дескриптор pthread_t не сразу удалось корректно имплементировать вследствие того, что функции ff_ для синхронизации потоков передавали данные по значению, а не по ссылке. После замены на ссылочные значения – проблем с потокобезопасностью выполнения операций не возникало.

Кеширование


Во избежание потери данных при копировании и повреждении таблицы файлов, применялось синхронизация кэша данных записываемого файла с помощью функции f_sync. Учитывая, что размер дискового пространства мог быть более 16 Гб, некоторые базовые типы переменных пришлось поменять на «long log». FATFS изначально проектировалась с расчетом на встраиваемые устройства, характеризующиеся ограниченным размером памяти и низкой производительностью. Как следствие функции чтения/записи выполнялись по одному кластеру дискретно в единицу времени, что существенно ниже непрерывного чтения/записи. Подобная же проблема возникла при чтении структуры каталогов при наличии в директории более 100 файлов. Чтение/запись одного файла линейно росла с увеличением количества файлов, как показано на рисунке. По оси “x”отражено количество файлов в директории, а по оси “y” — время чтения в секундах. Типы кривых на графике для: V2 Sim Fat –симулятор дискового устройства, V1 Fat файловая система FAT32, для которой отсутствует данная проблема (не FATFS), V2 Fat64/128 FATFS c размером диска 64 и 128 Гб, соответственно.



Структурная схема работы кэша в таком SDK представлена на рисунке ниже. Таким образом кэшировалась не только файловая структура, но и сектора для низкоуровневых функций чтения/записи медиа устройства, вследствие отсутствия аппаратного кэша.



Уникальный доступ приложения к устройству


Приложения с интегрированным SDK не должны одновременно иметь доступ к внешнему дисковому устройству. Правила которым должно подчиняться приложение с используемым SDK должно выглядеть как показано ниже на диаграмме состояний.



Для установления правил доступа к устройству был имплементирован механизм основанный на Darwin Notification Center позволяющий с помощью уведомлений разрешать или блокировать работу с устройством приложения когда с устройством работает еще одно приложение с данным SDK. При первом запуске приложения отправляется запрос всем приложениям, подписанным на получение определенных уведомлений. Каждое приложение публикует свое состояние для остальных приложений, чтобы новое приложение могло перейти в адекватное состояние. В случае, если устройство свободно, приложение переходит в состояние USING. Состояние PENDING является промежуточным для BUSY и WAIT на тот случай, когда устройство не доступно или занято. В случае сбоя в коммуникациях используется состояние INVALID. После завершения использования устройства приложение переходит в состояние INACTIVE.

Тестирование Фреймворка


Написание Unit Tests для всех функций библиотеки было критически необходимо вследствие жёстких детерминированных требований к поведению API для конечных пользователей. Первоначально все тесты выполнялись на симуляторе дискового устройства. Однако, симулятор и библиотеку для низкоуровневого доступа диска писали разные люди, не имеющие возможности взаимодействия, в связи с чем поведение симулятора не всегда совпадало с поведением драйвера устройства. Для этого была разработана схема тестирования на реальном устройстве, представленная ниже. Тестируемый framework интегрировался в приложение, написанное с использованием Private API, а установка производилась через Xcode Server Over-the-Air installation. Private API позволяло выводить приложение из Background состояния приложения по Push Notification и запускать необходимые тесты. Результаты тестов отправлялись по REST протоколу на сервер статистики, где впоследствии они представлялись в виде графиков и таблиц. В библиотеку также включены Activity Tracing функции для получения более подробного crash лога.



Заключение


Несмотря на серьезные недостатки FATFS opensourse библиотеки, требующие доработки, другой альтернативы с возможностью использования Fat32 и ExFat, а также с абстрактным уровнем поддержки media drivers — найти не удалось. При корректной модификации библиотеки с подключенными дополнительными функциями кеширования и буферного чтения/записи, функции копирования и чтения файлов FAT32 API ниже скорости копирования LBA блоков медиа драйвера производителя железа всего на 10-15%. Для новичков в области разработки и интеграции файловых систем — FATFS может являться вполне достойным выбором.

Полезные ссылки


FatFs — Generic FAT File System Module
Microsoft EFI FAT32 File System Specification
Darwin Notification Concepts
About Continuous Integration in Xcode
Теги:
Хабы:
Всего голосов 13: ↑13 и ↓0+13
Комментарии1

Публикации

Истории

Работа

Swift разработчик
27 вакансий
iOS разработчик
20 вакансий

Ближайшие события