Упорядочивание драйверов фильтра устройств

Корпорация Майкрософт разработала метод декларативного добавления фильтров, выражающих намерение фильтра, а не его положение в стеке, что называется упорядочиванием драйверов фильтров устройств.

Необходимость упорядочения драйверов фильтра устройств

До Windows 10 версии 1903 единственный поддерживаемый способ регистрации драйвера фильтра устройств был добавлен в запись реестра (с помощью директивы AddReg). Однако этот метод манипуляции с реестром не обеспечивает гибкость, чтобы указать точное положение для регистрации определенного фильтра.

Регистрация фильтра с помощью директивы AddReg просто добавляет фильтр в конец списка фильтров. Этот подход использует список значений, где важен порядок и определяет место загрузки фильтра в стеке фильтров.

Использование одного списка упорядоченных значений далеко от идеала, особенно когда AddRegтолько добавляетв конец, так как есть негативные последствия, когда более одного драйвера добавляют фильтры на то же устройство.

В сценарии, где задействовано по крайней мере одно Extension INF, если INFs неправильно используют AddReg (другими словами, не используют флаг добавления), они могут удалить фильтр, добавленный другим INF.

Кроме того, несколько INF-файлов расширений могут добавлять фильтры, и относительный порядок этих фильтров может быть важен; однако платформа Plug and Play (PnP) не гарантирует порядок установки этих расширений. Результатом является то, что порядок "добавлений" не гарантируется.

Реализация упорядочивания драйверов фильтра устройств

Чтобы предоставить гибкий декларативный метод для регистрации фильтров устройств, корпорация Майкрософт разработала метод декларативного добавления фильтров путем выражения намерения фильтра, а не положения стека. Решение предоставляет авторам драйверов функций возможность выразить в файле INF упорядоченный набор позиций (называемых уровнями), в который фильтр может регистрироваться.

Помимо определенного уровня, фильтр может декларативно регистрировать просто как фильтр верхнего или нижнего уровня.

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

Метод активируется, когда базовый INF файл задает упорядоченный список одного или нескольких уровней. Как базовые INF,так и любые расширения INFs могут регистрировать декларативный фильтр с помощью новой директивы INF, которая указывает имя службы и уровень, к которому принадлежит фильтр. Верхние и нижние фильтры представлены собственным упорядоченным списком уровней.

Эти верхние и нижние списки фильтров создаются путем сортировки всех драйверов фильтров по их уровню. Порядок фильтров на каждом уровне должен считаться произвольным, и не следует полагаться на порядок фильтров в пределах определенного уровня. В сценариях, где должен быть гарантирован относительный порядок двух фильтров, они должны быть зарегистрированы на разных уровнях.

Рассмотрим следующий пример драйвера устройства:

Установка драйверов устройств, показанная как порядок стека устройств, который объединяет списки драйверов фильтров при соблюдении требуемого расположения и упорядочивания.

Базовый INF драйвера устройства объявляет два верхних уровня фильтра A и B (в этом порядке). В расширении INF, связанном с базовым INF, два фильтра добавляются на каждый из двух уровней.

Результатом установки драйвера устройства является порядок стека устройств, который объединяет списки драйверов фильтров при соблюдении требуемого расположения и упорядочивания. Результирующий порядок стека устройств гарантирует, что любой фильтр, размещенный на уровне "A", оказывается перед любым фильтром на уровне "B". Однако на каждом уровне порядок произвольный.

Как показано в примере, Фильтр3 может прийти до Filter5 или он может прийти после Filter5. В любом случае Фильтр3 и Фильтр5 будут идти перед фильтрами на уровне "B".

При проектировании серии уровней для регистрации фильтров, вместо того чтобы создавать уровни ради упорядочивания, они должны быть названы и упорядочены таким образом, чтобы соответствовать назначению фильтра. Например, устройство ввода-вывода может определить уровень шифрования, для которого должен быть зарегистрирован любой фильтр шифрования. Это позволяет легко понять назначение фильтра и управлять им, а также делает стек более устойчивым к серьезным изменениям в драйвере функций.

Замечание

Даже без уровней, определенных базовым INF, декларативный фильтр может регистрироваться как просто верхний или нижний. Если уровни не определены, это логически эквивалентно добавлению фильтра в конец значения реестра UpperFilters/LowerFilters. При определении уровней один из уровней должен быть помечен как уровень по умолчанию в базовом драйвере, и в этом случае фильтр будет зарегистрирован в этом уровне.

Сценарии

Рассмотрим драйвер устройства ввода-вывода, который шифрует данные, поступающие через стек. Типичная реализация может использовать более низкий драйвер фильтра непосредственно под драйвером функции для этого. Чтобы убедиться, что фильтр шифрования помещается в точное положение, в котором требуется автор драйвера, они могут использовать декларативные фильтры, как показано ниже:

Схема, показывающая, что явное размещение драйвера фильтра

Base INF устанавливает два уровня нижних фильтров, "Шифрование" и "Мониторинг" (по умолчанию). "Мониторинг" (по умолчанию) в этом примере — это остальные более низкие фильтры, которые могут существовать для этого конкретного устройства. Явным образом разместив драйвер фильтра Encrypt на уровне "Шифрование", драйвер гарантирует, что полученный порядок стека устройств будет помещать драйвер фильтра Encrypt перед любыми другими более низкими фильтрами и сразу после драйвера функции.

Давайте рассмотрим пример подробнее. Представьте себе, что выходит новая версия драйвера и автор встроил шифрование в функциональный драйвер. Это удаляет необходимость отдельного драйвера фильтра Encrypt. Автору просто нужно удалить уровень, содержащий фильтр "Encrypt" из базового INF-файла, и когда драйвер обновляется, стек динамически создается.

Если фильтр объявляет, что он находится на явном уровне, которого не существует, то этот фильтр не включается в стек устройств. В этом примере Базовый INF был обновлён, и даже если INF расширения остаётся неизменным, результирующий стек устройств исключает фильтр Encrypt, так как он не был включен в объявление уровней Базового 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 будет регистрировать фильтр на уровне по умолчанию для этой позиции.

Если уровни фильтров не указаны, этот фильтр будет зарегистрирован в качестве верхнего фильтра в произвольном порядке.

См. также

Раздел INF DDInstall.Filters

Директива AddFilter