- PVSM.RU - https://www.pvsm.ru -

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

Введение

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

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

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

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

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

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

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

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

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

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

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

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

Поддержка Unicode

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

Thread safe

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

Кеширование

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

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

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

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

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

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

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

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

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

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

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

Заключение

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

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

FatFs — Generic FAT File System Module [15]
Microsoft EFI FAT32 File System Specification [16]
Darwin Notification Concepts [12]
About Continuous Integration in Xcode [17]

Автор: evgzor

Источник [18]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/ios/226582

Ссылки в тексте:

[1] MFI: https://developer.apple.com/programs/mfi/

[2] FATFS: http://elm-chan.org/fsw/ff/00index_e.html

[3] NDA: https://ru.wikipedia.org/wiki/%D0%A1%D0%BE%D0%B3%D0%BB%D0%B0%D1%88%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BE_%D0%BD%D0%B5%D1%80%D0%B0%D0%B7%D0%B3%D0%BB%D0%B0%D1%88%D0%B5%D0%BD%D0%B8%D0%B8

[4] EFSL: http://microsin.ru/content/view/1031/44/

[5] NSLogger: https://github.com/fpillet/NSLogger/wiki

[6] Unicode: http://elm-chan.org/fsw/ff/en/appnote.html#unicode

[7] NSUTF16LittleEndianStringEncoding: https://developer.apple.com/reference/foundation/1497293-anonymous/nsutf16littleendianstringencoding?language=objc

[8] FS_REENTRANT: http://elm-chan.org/fsw/ff/en/config.html#fs_reentrant

[9] ff_req_grant, ff_rel_grant, ff_del_syncobj: http://elm-chan.org/fsw/ff/en/appnote.html#reentrant

[10] pthread_t: https://ru.wikipedia.org/wiki/POSIX_Threads

[11] f_sync: http://elm-chan.org/fsw/ff/en/sync.html

[12] Darwin Notification Center: https://developer.apple.com/library/content/documentation/Darwin/Conceptual/MacOSXNotifcationOv/DarwinNotificationConcepts/DarwinNotificationConcepts.html

[13] Xcode Server Over-the-Air installation: https://developer.apple.com/library/content/documentation/IDEs/Conceptual/AppDistributionGuide/DistributingEnterpriseProgramApps/DistributingEnterpriseProgramApps.html

[14] Activity Tracing: https://www.objc.io/issues/19-debugging/activity-tracing/

[15] FatFs — Generic FAT File System Module: http://www.elm-chan.org/fsw/ff/00index_e.html

[16] Microsoft EFI FAT32 File System Specification: https://msdn.microsoft.com/en-us/windows/hardware/gg463080.aspx

[17] About Continuous Integration in Xcode: https://developer.apple.com/library/content/documentation/IDEs/Conceptual/xcode_guide-continuous_integration/

[18] Источник: https://habrahabr.ru/post/318634/?utm_source=habrahabr&utm_medium=rss&utm_campaign=sandbox