Partager via


Utilisation de GUID d’ID d’activité dans les traces ETW USB

Cette rubrique fournit des informations sur les GUID d’ID d’activité, comment ajouter ces GUID dans les fournisseurs de trace d’événements et les afficher dans Netmon.

Les pilotes de la pile de pilotes USB (2.0 et 3.0) sont des fournisseurs de trace d’événements ETW. Dans Windows 7, lors de la capture des traces d’événements à partir de la pile de pilotes USB, vous pouvez capturer des traces à partir d’autres fournisseurs, tels que d’autres pilotes et applications. Vous pouvez ensuite lire le journal combiné (en supposant que vous avez créé un analyseur Netmon pour les traces d’événements de votre fournisseur).

À partir de Windows 8, vous pouvez associer des événements entre des fournisseurs (à partir d’applications, de pilote client et de la pile de pilotes USB) à l’aide de GUID d’ID d’activité. Les événements de plusieurs fournisseurs peuvent être associés dans Netmon lorsque les événements ont le même GUID d’ID d’activité. En fonction de ces GUID, Netmon peut vous montrer l’ensemble des événements USB résultant d’une activité instrumentée sur une couche supérieure.

Lors de l’affichage des traces d’événements combinées d’autres fournisseurs dans Netmon, cliquez avec le bouton droit sur un événement à partir d’une application et choisissez Rechercher des conversations -> NetEvent pour voir les événements de pilote associés.

Cette image montre les événements associés d’une application, d’un pilote UMDF et d'Ucx01000.sys (l’un des pilotes de la pile de pilotes USB). Ces événements ont le même GUID d’ID d’activité.

moniteur réseau microsoft.

Comment ajouter un GUID d’ID d’activité dans une application

Une application peut inclure des GUID d’ID d’activité en appelant EventActivityIdControl. Pour plus d’informations, consultez Fonctions de suivi d’événements.

Cet exemple de code montre comment une application peut définir un GUID d’ID d’activité et l’envoyer au fournisseur ETW, un pilote UMDF.

EventActivityIdControl(EVENT_ACTIVITY_CTRL_CREATE_ID, &activityIdStruct.ActivityId); 
EventActivityIdControl(EVENT_ACTIVITY_CTRL_SET_ID,    &activityIdStruct.ActivityId); 

if (!DeviceIoControl(hRead,
                     IOCTL_OSRUSBFX2_SET_ACTIVITY_ID,
                     &activityIdStruct,         // Ptr to InBuffer
                     sizeof(activityIdStruct),  // Length of InBuffer
                     NULL,                      // Ptr to OutBuffer
                     0,                         // Length of OutBuffer
                     NULL,                      // BytesReturned
                     0))                        // Ptr to Overlapped structure
{         

          wprintf(L"Failed to set activity ID - error %d\n", GetLastError());
}

...

success = ReadFile(hRead, pinBuf, G_ReadLen, (PULONG) &nBytesRead, NULL);

if(success == 0) 
{
          wprintf(L"ReadFile failed - error %d\n", GetLastError());

          EventWriteReadFail(0, GetLastError());

          ...

}

Dans l’exemple précédent, une application appelle EventActivityIdControl pour créer un ID d’activité (EVENT_ACTIVITY_CTRL_CREATE_ID), puis pour le définir (EVENT_ACTIVITY_CTRL_SET_ID) pour le thread actif. L’application spécifie ce GUID d’activité au fournisseur d’événements ETW, tel qu’un pilote en mode utilisateur, en envoyant un IOCTL défini par le pilote (décrit dans la section suivante).

Le fournisseur d’événements doit publier un fichier manifeste d’instrumentation (. Fichier MAN). En exécutant le compilateur de messages (Mc.exe), un fichier d’en-tête contenant des définitions pour le fournisseur d’événements, les attributs d’événement, les canaux et les événements est généré. Dans l’exemple, l’application appelle EventWriteReadFail, qui sont définis dans le fichier d’en-tête généré, pour écrire des messages d’événement de trace en cas de défaillance.

Comment définir le GUID d’ID d’activité dans un pilote UMDF

Un pilote en mode utilisateur crée et définit des GUID d’ID d’activité en appelant EventActivityIdControl et les appels sont similaires à la façon dont une application les appelle, comme décrit dans la section précédente. Ces appels ajoutent le GUID d’ID d’activité au thread actuel et ce GUID d’ID d’activité est utilisé chaque fois que le thread journalise un événement. Pour plus d’informations, consultez Utilisation d’identificateurs d’activité.

Cet exemple de code montre comment un pilote UMDF définit le GUID d’ID d’activité qui a été créé et spécifié par l’application via un IOCTL.

VOID
STDMETHODCALLTYPE
CMyControlQueue::OnDeviceIoControl(
    _In_ IWDFIoQueue *FxQueue,
    _In_ IWDFIoRequest *FxRequest,
    _In_ ULONG ControlCode,
    _In_ SIZE_T InputBufferSizeInBytes,
    _In_ SIZE_T OutputBufferSizeInBytes
    )
/*++

Routine Description:

    DeviceIoControl dispatch routine

Arguments:

    FxQueue - Framework Queue instance
    FxRequest - Framework Request  instance
    ControlCode - IO Control Code
    InputBufferSizeInBytes - Lenth of input buffer
    OutputBufferSizeInBytes - Lenth of output buffer

    Always succeeds DeviceIoIoctl
Return Value:

    VOID

--*/
{
    ...

    switch (ControlCode)
    {

        ....

        case IOCTL_OSRUSBFX2_SET_ACTIVITY_ID:
        {
            if (InputBufferSizeInBytes < sizeof(UMDF_ACTIVITY_ID))
            {
                hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
            }
            else
            {
                FxRequest->GetInputMemory(&memory );
            }

            if (SUCCEEDED(hr)) 
            {
                buffer = memory->GetDataBuffer(&bigBufferCb);
                memory->Release();

                m_Device->SetActivityId(&((PUMDF_ACTIVITY_ID)buffer)->ActivityId);
                hr = S_OK;
            }

            break;
        }
    } 
}

VOID
 SetActivityId(
        LPCGUID ActivityId
        )
    {
        CopyMemory(&m_ActivityId, ActivityId, sizeof(m_ActivityId));
    }

void
CMyReadWriteQueue::ForwardFormattedRequest(
    _In_ IWDFIoRequest*                         pRequest,
    _In_ IWDFIoTarget*                          pIoTarget
    )
{
...
    pRequest->SetCompletionCallback(
        pCompletionCallback,
        NULL
        );

...
    hrSend = pRequest->Send(pIoTarget,
                            0,  //flags
                            0); //timeout

...
    if (FAILED(hrSend))
    {
        contextHr = pRequest->RetrieveContext((void**)&pRequestContext);

        if (SUCCEEDED(contextHr)) {

            EventActivityIdControl(EVENT_ACTIVITY_CTRL_SET_ID, &pRequestContext->ActivityId);

            if (pRequestContext->RequestType == RequestTypeRead)
            {
                EventWriteReadFail(m_Device, hrSend);
            }

            delete pRequestContext;
        }

        pRequest->CompleteWithInformation(hrSend, 0);
    }

    return;
}

Voyons comment le GUID d’ID d’activité créé par l’application est associé à un pilote client UMDF ( User-Mode Driver Framework ). Lorsque le pilote reçoit la demande IOCTL de l’application, il copie le GUID dans un membre privé. À un moment donné, l’application appelle ReadFile pour effectuer une opération de lecture. L’infrastructure crée une requête et appelle le gestionnaire du pilote, ForwardFormattedRequest. Dans le gestionnaire, le pilote définit le GUID d’ID d’activité précédemment stocké sur le thread en appelant EventActivityIdControl et EventWriteReadFail pour suivre les messages d’événement.

Note Le pilote UMDF doit également inclure le fichier d’en-tête généré via le fichier manifeste d’instrumentation. Le fichier d’en-tête définit des macros telles que EventWriteReadFail qui écrivent des messages de trace.

Comment ajouter un GUID d’ID d’activité dans un pilote en mode noyau

En mode noyau, un pilote peut suivre les messages sur le thread qui provient du mode utilisateur ou un thread créé par le pilote. Dans ces deux cas, le pilote nécessite le GUID d’ID d’activité du thread.

Pour suivre les messages, le pilote doit obtenir le handle d’inscription en tant que fournisseur d’événements (voir EtwRegister), puis appeler EtwWrite en spécifiant le GUID et le message d’événement. Pour plus d’informations, consultez Ajout du suivi d'événements aux pilotes en mode noyau.

Si votre pilote en mode noyau gère une requête qui a été créée par une application ou un pilote en mode utilisateur, le pilote en mode noyau ne crée pas et ne définit pas de GUID d’ID d’activité. Au lieu de cela, le gestionnaire d’E/S gère la majeure partie de la propagation de l’ID d’activité. Lorsqu’un thread en mode utilisateur lance une demande, le gestionnaire d’E/S crée un IRP pour la demande et copie automatiquement le GUID d’ID d’activité du thread actuel dans le nouvel IRP. Si le pilote en mode noyau souhaite suivre les événements sur ce thread, il doit obtenir le GUID en appelant IoGetActivityIdIrp, puis appeler EtwWrite.

Si votre pilote en mode noyau crée un IRP avec un GUID d’ID d’activité, le pilote peut appeler EtwActivityIdControl avec EVENT_ACTIVITY_CTRL_CREATE_SET_ID pour générer un nouveau GUID. Le pilote peut ensuite associer le nouveau GUID à l’IRP en appelant IoSetActivityIdIrp , puis en appelant EtwWrite.

Le GUID d’ID d’activité est transmis avec l’IRP aux pilotes inférieurs suivants. Les pilotes inférieurs peuvent ajouter leurs messages de trace au thread.