Compartir a través de


Uso de GUID de identificador de actividad en seguimientos DE ETW USB

En este tema se proporciona información sobre los GUID de id. de actividad, cómo agregar esos GUID en los proveedores de seguimiento de eventos y verlos en Netmon.

Los controladores de la pila de controladores USB (tanto 2.0 como 3.0) son proveedores de seguimiento de eventos ETW. En Windows 7, al capturar seguimientos de eventos de la pila de controladores USB, puedes capturar seguimientos de otros proveedores, como otros controladores y aplicaciones. A continuación, puede leer el registro combinado (suponiendo que ha creado un analizador de Netmon para los seguimientos de eventos del proveedor).

A partir de Windows 8, puede asociar eventos entre proveedores (desde aplicaciones, controlador cliente y la pila de controladores USB) mediante GUID de identificador de actividad. Los eventos de varios proveedores se pueden asociar en Netmon cuando los eventos tienen el mismo GUID de identificador de actividad. En función de esos GUID, Netmon puede mostrar el conjunto de eventos USB resultantes de una actividad instrumentada en una capa superior.

Al ver seguimientos de eventos combinados de otros proveedores en Netmon, haga clic con el botón derecho en un evento de una aplicación y elija Buscar conversaciones-> NetEvent para ver los eventos de controladores asociados.

En esta imagen se muestran eventos relacionados de una aplicación, un controlador UMDF y Ucx01000.sys (uno de los controladores de la pila de controladores USB). Estos eventos tienen el mismo GUID de identificador de actividad.

Microsoft Network Monitor.

Adición de un GUID de identificador de actividad en una aplicación

Una aplicación puede incluir GUID de identificador de actividad mediante una llamada a EventActivityIdControl. Para obtener más información, vea Funciones de seguimiento de eventos.

En este código de ejemplo se muestra cómo una aplicación puede establecer un GUID de identificador de actividad y enviarlo al proveedor ETW, un controlador 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());

          ...

}

En el ejemplo anterior, una aplicación llama a EventActivityIdControl para crear un identificador de actividad (EVENT_ACTIVITY_CTRL_CREATE_ID) y, a continuación, para establecerlo (EVENT_ACTIVITY_CTRL_SET_ID) para el subproceso actual. La aplicación especifica que el GUID de actividad para el proveedor de eventos ETW, como un controlador en modo de usuario, envíe un IOCTL definido por el controlador (descrito en la sección siguiente).

El proveedor de eventos debe publicar un archivo de manifiesto de instrumentación (. Archivo MAN). Al ejecutar el compilador de mensajes (Mc.exe), se genera un archivo de encabezado que contiene definiciones para el proveedor de eventos, los atributos de evento, los canales y los eventos. En el ejemplo, la aplicación llama a EventWriteReadFail, que se define en el archivo de encabezado generado, para escribir mensajes de evento de seguimiento en caso de error.

Cómo establecer el GUID del identificador de actividad en un controlador UMDF

Un controlador en modo de usuario crea y establece GUID de identificador de actividad llamando a EventActivityIdControl y las llamadas son similares a la forma en que una aplicación las llama, como se describe en la sección anterior. Esas llamadas agregan el GUID del identificador de actividad al subproceso actual y ese GUID de identificador de actividad se usa cada vez que el subproceso registra un evento. Para obtener más información, consulte Uso de identificadores de actividad.

En este código de ejemplo se muestra cómo un controlador UMDF establece el GUID del identificador de actividad creado y especificado por la aplicación a través de 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;
}

Veamos cómo se asocia el GUID del identificador de actividad creado por la aplicación con un controlador cliente del marco de controlador del modo de usuario (UMDF). Cuando el controlador recibe la solicitud IOCTL de la aplicación, copia el GUID en un miembro privado. En algún momento, la aplicación llama a ReadFile para realizar una operación de lectura. El marco crea una solicitud e invoca el controlador del controlador, ForwardFormattedRequest. En el controlador, el controlador establece el GUID del identificador de actividad almacenado anteriormente en el subproceso llamando a EventActivityIdControl y EventWriteReadFail para realizar un seguimiento de los mensajes de evento.

Nota El controlador UMDF también debe incluir el archivo de encabezado que se genera a través del archivo de manifiesto de instrumentación. El archivo de encabezado define macros como EventWriteReadFail que escriben mensajes de seguimiento.

Adición del GUID del identificador de actividad en un controlador en modo kernel

En el modo kernel, un controlador puede realizar un seguimiento de los mensajes en el subproceso que se origina en el modo de usuario o en un subproceso que el controlador crea. En ambos casos, el controlador requiere el GUID del identificador de actividad del subproceso.

Para realizar un seguimiento de los mensajes, el controlador debe obtener el identificador de registro como proveedor de eventos (consulte EtwRegister) y, a continuación, llamar a EtwWrite especificando el GUID y el mensaje de evento. Para obtener más información, vea Agregar seguimiento de eventos a controladores de modo kernel.

Si el controlador en modo kernel controla una solicitud creada por una aplicación o un controlador en modo de usuario, el controlador en modo kernel no crea ni establece un GUID de identificador de actividad. En su lugar, el administrador de E/S controla la mayoría de la propagación del identificador de actividad. Cuando un subproceso en modo de usuario inicia una solicitud, el administrador de E/S crea un IRP para la solicitud y copia automáticamente el GUID del identificador de actividad del subproceso actual en el nuevo IRP. Si el controlador en modo kernel quiere realizar un seguimiento de eventos en ese subproceso, debe obtener el GUID mediante una llamada a IoGetActivityIdIrp y, a continuación, llamar a EtwWrite.

Si el controlador en modo kernel crea un IRP con un GUID de identificador de actividad, el controlador puede llamar a EtwActivityIdControl con EVENT_ACTIVITY_CTRL_CREATE_SET_ID para generar un nuevo GUID. A continuación, el controlador puede asociar el nuevo GUID al IRP mediante una llamada a IoSetActivityIdIrp y, a continuación, llamar a EtwWrite.

El GUID del identificador de actividad se pasa junto con el IRP a los siguientes controladores inferiores. Los controladores inferiores pueden agregar sus mensajes de seguimiento al subproceso.