Freigeben über


Verwenden von Aktivitäts-ID-GUIDs in USB-ETW-Ablaufverfolgungen

Dieses Thema enthält Informationen zu Aktivitäts-ID-GUIDs, wie Sie diese GUIDs in den Ereignisablaufverfolgungsanbietern hinzufügen und in Netmon anzeigen.

Treiber im USB-Treiberstapel (sowohl 2.0 als auch 3.0) sind ETW-Ereignisablaufverfolgungsanbieter. In Windows 7 können Sie beim Erfassen von Ereignisablaufverfolgungen aus dem USB-Treiberstapel Ablaufverfolgungen von anderen Anbietern wie anderen Treibern und Anwendungen erfassen. Sie können dann das kombinierte Protokoll lesen (vorausgesetzt, Sie haben einen Netmon-Parser für die Ereignisablaufverfolgungen Ihres Anbieters erstellt).

Ab Windows 8 können Sie Ereignisse anbieterübergreifend (von Anwendungen, Clienttreibern und USB-Treiberstapeln) mithilfe von Aktivitäts-ID-GUIDs zuordnen. Ereignisse von mehreren Anbietern können in Netmon zugeordnet werden, wenn die Ereignisse über die gleiche Aktivitäts-ID-GUID verfügen. Basierend auf diesen GUIDs kann Netmon Ihnen den Satz von USB-Ereignissen anzeigen, die aus einer instrumentierten Aktivität auf einer oberen Ebene resultieren.

Wenn Sie kombinierte Ereignisablaufverfolgungen anderer Anbieter in Netmon anzeigen, klicken Sie mit der rechten Maustaste auf ein Ereignis aus einer Anwendung, und wählen Sie Unterhaltungen suchen –> NetEvent aus, um die zugehörigen Treiberereignisse anzuzeigen.

Diese Abbildung zeigt Ihnen verwandte Ereignisse aus einer Anwendung, einem UMDF-Treiber und Ucx01000.sys (einem der Treiber im USB-Treiberstapel). Diese Ereignisse weisen die gleiche Aktivitäts-ID-GUID auf.

Microsoft-Netzwerkmonitor.

Hinzufügen einer Aktivitäts-ID-GUID in einer Anwendung

Eine Anwendung kann Aktivitäts-ID-GUIDs enthalten, indem EventActivityIdControl aufgerufen wird. Weitere Informationen finden Sie unter Ereignisablaufverfolgungsfunktionen.

Dieser Beispielcode zeigt, wie eine Anwendung eine Aktivitäts-ID-GUID festlegen und an den ETW-Anbieter, einen UMDF-Treiber, senden kann.

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());

          ...

}

Im vorherigen Beispiel ruft eine Anwendung EventActivityIdControl auf, um eine Aktivitäts-ID (EVENT_ACTIVITY_CTRL_CREATE_ID) zu erstellen und dann (EVENT_ACTIVITY_CTRL_SET_ID) für den aktuellen Thread festzulegen. Die Anwendung gibt diese Aktivitäts-GUID an den ETW-Ereignisanbieter an, z. B. einen Benutzermodustreiber, indem sie eine vom Treiber definierte IOCTL sendet (im nächsten Abschnitt beschrieben).

Der Ereignisanbieter muss eine Instrumentierungsmanifestdatei () veröffentlichen. MAN-Datei). Durch Ausführen des Nachrichtencompilers (Mc.exe) wird eine Headerdatei generiert, die Definitionen für den Ereignisanbieter, Ereignisattribute, Kanäle und Ereignisse enthält. Im Beispiel ruft die Anwendung EventWriteReadFail auf, die in der generierten Headerdatei definiert sind, um Ablaufverfolgungsereignismeldungen im Falle eines Fehlers zu schreiben.

Festlegen der Aktivitäts-ID-GUID in einem UMDF-Treiber

Ein Benutzermodustreiber erstellt und legt Aktivitäts-ID-GUIDs durch Aufrufen von EventActivityIdControl , und die Aufrufe ähneln der Art und Weise, wie sie von einer Anwendung aufgerufen wird, wie im vorherigen Abschnitt beschrieben. Diese Aufrufe fügen dem aktuellen Thread die Aktivitäts-ID-GUID hinzu, und diese Aktivitäts-ID-GUID wird verwendet, wenn der Thread ein Ereignis protokolliert. Weitere Informationen finden Sie unter Verwenden von Aktivitätsbezeichnern.

Dieser Beispielcode zeigt, wie ein UMDF-Treiber die Aktivitäts-ID-GUID festlegt, die von der Anwendung über eine IOCTL erstellt und angegeben wurde.

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;
}

Sehen wir uns an, wie die aktivitäts-ID-GUID, die von der Anwendung erstellt wurde, einem UMDF-Clienttreiber (User-Mode Driver Framework ) zugeordnet wird. Wenn der Treiber die IOCTL-Anforderung von der Anwendung empfängt, kopiert er die GUID in ein privates Mitglied. Irgendwann ruft die Anwendung ReadFile auf, um einen Lesevorgang auszuführen. Das Framework erstellt eine Anforderung und ruft den Handler forwardFormattedRequest des Treibers auf. Im Handler legt der Treiber die zuvor gespeicherte Aktivitäts-ID-GUID im Thread fest, indem Er EventActivityIdControl und EventWriteReadFail aufruft, um Ereignismeldungen nachzuverfolgen.

Hinweis Der UMDF-Treiber muss auch die Headerdatei enthalten, die über die Instrumentierungsmanifestdatei generiert wird. Die Headerdatei definiert Makros wie EventWriteReadFail, die Ablaufverfolgungsmeldungen schreiben.

Hinzufügen einer Aktivitäts-ID-GUID in einem Kernelmodustreiber

Im Kernelmodus kann ein Treiber Nachrichten in dem Thread nachverfolgen, der aus dem Benutzermodus oder einem Thread stammt, den der Treiber erstellt. In beiden Fällen benötigt der Treiber die Aktivitäts-ID-GUID des Threads.

Zum Nachverfolgen von Nachrichten muss der Treiber das Registrierungshandle als Ereignisanbieter abrufen (siehe EtwRegister) und dann EtwWrite aufrufen, indem er die GUID und die Ereignisnachricht angibt. Weitere Informationen finden Sie unter Hinzufügen von Ereignisablaufverfolgung zu Kernel-Mode Treibern.

Wenn Ihr Kernelmodustreiber eine Anforderung verarbeitet, die von einer Anwendung oder einem Benutzermodustreiber erstellt wurde, erstellt und legt der Kernelmodustreiber keine Aktivitäts-ID-GUID fest. Stattdessen verarbeitet der E/A-Manager den größten Teil der Aktivitäts-ID-Weitergabe. Wenn ein Benutzermodusthread eine Anforderung initiiert, erstellt der E/A-Manager ein IRP für die Anforderung und kopiert automatisch die Aktivitäts-ID-GUID des aktuellen Threads in das neue IRP. Wenn der Kernelmodustreiber Ereignisse in diesem Thread nachverfolgen möchte, muss er die GUID abrufen, indem Er IoGetActivityIdIrp aufruft und dann EtwWrite aufruft.

Wenn Ihr Kernelmodustreiber ein IRP mit einer Aktivitäts-ID-GUID erstellt, kann der Treiber EtwActivityIdControl mit EVENT_ACTIVITY_CTRL_CREATE_SET_ID aufrufen, um eine neue GUID zu generieren. Der Treiber kann dann die neue GUID dem IRP zuordnen, indem er IoSetActivityIdIrp aufruft und dann EtwWrite aufruft.

Die Aktivitäts-ID-GUID wird zusammen mit dem IRP an die nächstniedrigten Treiber übergeben. Die niedrigeren Treiber können dem Thread ihre Ablaufverfolgungsmeldungen hinzufügen.