Упорядочивание драйверов фильтра устройств
Корпорация Майкрософт разработала метод декларативного добавления фильтров путем выражения намерения фильтра, а не положения стека, известного как упорядочивание драйверов фильтров устройств.
Необходимость упорядочения драйверов фильтра устройств
До Windows 10 версии 1903 единственный поддерживаемый способ регистрации драйвера фильтра устройств был добавлен в запись реестра (с помощью директивы AddReg). Однако этот метод манипуляции с реестром не обеспечивает гибкость, чтобы указать точное положение для регистрации определенного фильтра.
Регистрация фильтра с помощью директивы AddReg просто добавляет фильтр в конец списка фильтров. Этот подход использует список значений, в которых имеет значение порядка и определяет место загрузки фильтра в стеке.
Использование одного списка упорядоченных значений меньше идеала, особенно если AddReg добавляется только в конец, так как есть негативные последствия, когда несколько драйверов добавляют фильтры на одно устройство.
В сценарии, где имеется по крайней мере одно расширение INF, если INFs неправильно используют AddReg (другими словами, не используют флаг добавления), они могут удалить фильтр, добавленный другим INF.
Кроме того, можно добавить фильтры нескольких расширений, а относительный порядок этих фильтров может быть важным; однако платформа самонастраивающийся (PnP) не гарантирует порядок установки расширений. Результатом является то, что порядок "добавлений" не гарантируется.
Реализация упорядочения драйверов фильтра устройств
Чтобы предоставить гибкий декларативный метод для регистрации фильтров устройств, корпорация Майкрософт разработала метод декларативного добавления фильтров путем выражения намерения фильтра, а не положения стека. Решение предоставляет авторам функций возможность выразить в inf упорядоченный набор позиций (называемых уровнями), в который фильтр может регистрироваться.
Помимо определенного уровня, фильтр может декларативно регистрировать просто как фильтр верхнего или нижнего уровня.
Инфраструктура основана на новом методе регистрации фильтра, чтобы определить, какие драйверы заказа должны быть включены в стек устройств. Новый метод не нарушает совместимость для старого способа добавления фильтров. Однако он позволяет новым фильтрам перейти к более надежному и гибкому механизму регистрации.
Этот метод включен, если базовый INF определяет упорядоченный список одного или нескольких уровней. Как базовые INF,так и любые расширения INFs могут регистрировать декларативный фильтр с помощью новой директивы INF, которая указывает имя службы и уровень, к которому принадлежит фильтр. Верхние и нижние фильтры представлены собственным упорядоченным списком уровней.
Эти верхние и нижние списки фильтров создаются путем сортировки всех драйверов фильтров по их уровню. Порядок фильтров на каждом уровне должен считаться произвольным, где зависимость не может приниматься в порядке фильтров в пределах определенного уровня. В сценариях, где должен быть гарантирован относительный порядок двух фильтров, они должны быть зарегистрированы на разных уровнях.
Рассмотрим следующий пример драйвера устройства:
Базовый INF драйвера устройства объявляет два верхних уровня фильтра A и B (в этом порядке). В связанном расширении INF базы два фильтра добавляются в каждый из двух уровней.
Результатом установки драйвера устройства является порядок стека устройств, который объединяет списки драйверов фильтров при соблюдении требуемого расположения и упорядочивания. Результирующий порядок стека устройств гарантирует, что любой фильтр, размещенный на уровне "A", поставляется перед любым фильтром на уровне "B". Однако на каждом уровне порядок произвольный.
Как показано в примере, Фильтр3 может прийти до Filter5 или он может прийти после Filter5. В любом случае Фильтр3 и Filter5 будут поступать до фильтров на следующем уровне "B".
При проектировании ряда уровней, на которые могут быть зарегистрированы фильтры, а не для создания ряда уровней для упорядочения, уровни должны быть названы и упорядочены таким образом, чтобы они сопоставлялись с намерением фильтра. Например, устройство ввода-вывода может определить уровень шифрования, для которого должен быть зарегистрирован любой фильтр шифрования. Это позволяет легко понять и управлять фильтром и сделать стек более надежным для критических изменений в драйвере функций.
Примечание.
Даже без уровней, определенных базовым INF, декларативный фильтр может регистрироваться как просто верхний или нижний. Если уровни не определены, это логически эквивалентно добавлению фильтра в конец значения реестра UpperFilters/LowerFilters. При определении уровней один из уровней должен быть помечен как уровень по умолчанию в базовом драйвере, и в этом случае фильтр будет зарегистрирован в этом уровне.
Сценарии
Рассмотрим драйвер устройства ввода-вывода, который шифрует данные, поступающие через стек. Типичная реализация может использовать более низкий драйвер фильтра непосредственно под драйвером функции для этого. Чтобы убедиться, что фильтр шифрования помещается в точное положение, в котором требуется автор драйвера, они могут использовать декларативные фильтры, как показано ниже:
Base INF устанавливает два уровня нижних фильтров, "Шифрование" и "Мониторинг" (по умолчанию). "Мониторинг" (по умолчанию) в этом примере — это остальные более низкие фильтры, которые могут существовать для этого конкретного устройства. Явным образом разместив драйвер фильтра Encrypt на уровне "Шифрование", драйвер гарантирует, что полученный порядок стека устройств будет помещать драйвер фильтра Encrypt перед любыми другими более низкими фильтрами и сразу после драйвера функции.
Давайте рассмотрим пример еще один шаг. Представьте себе новую версию драйвера, и автор встроил шифрование в драйвер функции. Это удаляет необходимость отдельного драйвера фильтра Encrypt. Автору просто нужно удалить уровень, содержащий фильтр "Encrypt" из базового INF-файла, и когда драйвер обновляется, стек динамически создается.
Если фильтр объявляет себя явным уровнем, который не существует, фильтр не заканчивается в стеке устройств. В этом примере база INF была обновлена, и даже если INF расширения остается той же, результирующий стек устройств исключает фильтр Encrypt, так как он не был включен в объявление уровней BASE INF.
Уровень фильтра по умолчанию
Чтобы создать окончательный стек фильтров, все источники сведений о фильтре объединяются в один список. Важно отметить, что логика слияния выполняется при создании стека устройств. Если новый фильтр добавляется путем установки нового или обновленного базового драйвера или драйвера расширения, устройства будут перезапущены во время установки и забрать новый список фильтров.
Некоторые источники фильтров не имеют сведений о позиции, а именно фильтры, добавленные с помощью устаревших значений реестра UpperFilters/LowerFilters, или с помощью декларативного синтаксиса только позиций (описано ниже).
Чтобы поддерживать эффективное слияние при отсутствии сведений о позиции, необходимо определить дополнительную часть информации с помощью базового INF: уровня фильтра по умолчанию. Уровень фильтра по умолчанию — это положение, в котором будут вставляться фильтры, отсутствующие сведения о уровне или позиции.
Например, уровни фильтров могут быть определены в базовом INF как:
Level Order: A, B, C
DefaultFilterLevel: C
Указание уровня по умолчанию в качестве конечного уровня указывает, что любой фильтр, который не содержит сведений о позиции, будет добавлен в список фильтров. Кроме того, автор драйвера может иметь стек всегда заканчиваться фильтрами, явно зарегистрированными на уровне C:
Level Order: A, B, C
DefaultFilterLevel: B
Из-за заданного по умолчанию уровня фильтра B все дополнительные фильтры без сведений о позиции будут вставлены между фильтрами A и фильтрами C.
Синтаксис
Регистрация фильтров
Дополнительные сведения см. в разделе INF DDInstall.Filters и документации по директиве AddFilter.
[DDInstall.Filters]
AddFilter = <FilterName>, [Flags], FilterSection
FilterLevel OR FilterPosition может быть указан одним из двух способов:
Вариант 1:
[FilterSection]
FilterLevel=<LevelName>
Вариант 2.
[FilterSection]
FilterPosition=Upper/Lower
Это можно сделать как в базовом, так и в расширении INF.
[DDInstall.Filters]
FilterName — это имя службы в системе.
Флаги в настоящее время неиспользуются и должны оставаться пустыми или иметь значение 0.
FilterSection — это раздел, описывающий фильтр.
[Раздел фильтра]
Раздел фильтра должен содержать именно одну из следующих двух директив: FilterLevel или FilterPosition.
FilterLevel — это определенное место для вставки фильтра устройства в стек, определенного базовым INF. На каждом уровне порядок фильтров является произвольным.
FilterPosition используется в том случае, если класс имеет одно конкретное место для вставки сторонних фильтров.
Определение уровней фильтра
[DDInstall.HW]
AddReg = FilterLevel_Definition
[FilterLevel_Definition]
HKR,,UpperFilterLevels,%REG_MULTI_SZ%,"LevelA","LevelB","LevelC"
HKR,,UpperFilterDefaultLevel,,"LevelC"
HKR,,LowerFilterLevels,%REG_MULTI_SZ%,"LevelD","LevelE","LevelF"
HKR,,LowerFilterDefaultLevel,,"LevelE"
Это можно сделать только базовым драйвером.
Полный декларативный список фильтров для конкретного устройства можно получить путем запроса следующих свойств:
DEVPKEY_Device_CompoundUpperFilters
DEVPKEY_Device_CompoundLowerFilters
Регистрация прежних эквивалентных фильтров
Давайте рассмотрим, как выполнить устаревший подход при попытке добавить верхний фильтр с помощью INF:
[DDInstall.HW]
AddReg = Filters
[Filters]
HKR,,"UpperFilters", 0x00010008, "MyFilter"
Этот синтаксис добавит "MyFilter" в конец списка верхних фильтров.
С новым синтаксисом, представленным выше, приведенный выше раздел логически аналогичен следующему:
[DDInstall.Filters]
AddFilter = MyFilter,,MyUpperFilterInstall
[MyUpperFilterInstall]
FilterPosition = Upper
Это указывает, что фильтр MyFilter должен быть добавлен в список верхних фильтров. Если базовый INF-файл имеет указанные уровни фильтров, при использовании FilterPosition будет регистрировать фильтр на уровне по умолчанию для этой позиции.
Если уровни фильтров не указаны, этот фильтр будет зарегистрирован в качестве верхнего фильтра в произвольном порядке.