USB ETW トレースでのアクティビティ ID GUID の使用

ここでは、アクティビティ ID GUID、イベント トレース プロバイダーでそれらの GUID を追加する方法、およびそれらを Netmon で表示する方法について説明します。

USB ドライバー スタック (2.0 および 3.0) のドライバーは ETW イベント トレース プロバイダーです。Windows 7 では、USB ドライバー スタックからイベント トレースをキャプチャしながら、他のプロバイダー (他のドライバーやアプリケーションなど) からトレースをキャプチャできます。その後で、結合ログを読むことができます (プロバイダーのイベント トレースの Netmon パーサーを作っていることが前提)。

Windows 8 からは、アクティビティ ID GUID を使って、(アプリケーション、クライアント ドライバー、および USB ドライバー スタックからの) イベントをプロバイダーをまたいで関連付けることができます。 イベントが同じアクティビティ ID GUID を持っている場合、Netmon では複数のプロバイダーからのイベントを関連付けることができます。これらの GUID に基づいて、Netmon で、上のレイヤーでインストルメント化されたアクティビティの結果として生じた一連の USB イベントを表示できます。

Netmon で他のプロバイダーからの結合イベント トレースを表示しているときに、アプリケーションからのイベントを右クリックして [Find Conversations] (カンバセーションの検索) -> [NetEvent] を選ぶと、関連付けられているドライバー イベントが表示されます。

次の画像は、アプリケーション、UMDF ドライバー、および Ucx01000.sys (USB ドライバー スタックのドライバーのいずれか) からの関連イベントを示しています。これらのイベントは同じアクティビティ ID GUID を持っています。

JJ151578.netmon_activity(ja-jp,VS.85).png

アプリケーションでアクティビティ ID GUID を追加する方法

EventActivityIdControl を呼び出して、アプリケーションでアクティビティ ID GUID を含めることができます。詳しくは、「イベント トレース関数」をご覧ください。

次のコード例は、アプリケーションでアクティビティ ID GUID を設定し、それを ETW プロバイダー、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());

          ...


}


前の例では、アプリケーションは EventActivityIdControl を呼び出してアクティビティ ID を作り (EVENT_ACTIVITY_CTRL_CREATE_ID)、現在のスレッドに設定しています (EVENT_ACTIVITY_CTRL_SET_ID)。アプリケーションは、ドライバー定義の IOCTL (次のセクションを参照) を送り、そのアクティビティ GUID をユーザー モード ドライバーなどの ETW イベント プロバイダーに指定します。

イベント プロバイダーは、インストルメンテーション マニフェスト ファイル (.MAN ファイル) を発行する必要があります。message compiler (Mc.exe) を実行することで、イベント プロバイダー、イベント属性、チャネル、イベントの定義を含むヘッダー ファイルが生成されます。 この例では、アプリケーションは、失敗が発生した場合、生成されたヘッダー ファイルで定義されている EventWriteReadFail を呼び出してトレース イベント メッセージを書き込みます。

UMDF ドライバーでアクティビティ ID GUID を設定する方法

ユーザー モード ドライバーは、EventActivityIdControl を呼び出してアクティビティ ID GUID を作成および設定します。この呼び出しは、前のセクションで説明したアプリケーションによる呼び出し方法と同様です。これらの呼び出しにより、アクティビティ ID GUID が現在のスレッドに追加され、スレッドがイベントをログに記録する際は常にそのアクティビティ ID GUID が使われます。詳しくは、「アクティビティ識別子の使用」をご覧ください。

次のコード例は、UMDF ドライバーが、IOCTL を通じてアプリケーションによって作成および指定されたアクティビティ ID GUID を設定する方法を示しています。



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

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




アプリケーションによって作られたアクティビティ ID GUID がユーザー モード ドライバー フレームワーク (UMDF) クライアント ドライバーと関連付けられるしくみを見てみましょう。ドライバーは、アプリケーションから IOCTL 要求を受け取ると、プライベート メンバーの GUID をコピーします。ある時点で、アプリケーションは ReadFile を呼び出して読み取り操作を実行します。フレームワークによって要求が作られ、ドライバーのハンドラー ForwardFormattedRequest が呼び出されます。ハンドラーでは、ドライバーが EventActivityIdControl およびイベント メッセージをトレースする EventWriteReadFail を呼び出して、スレッドで以前に保存されたアクティビティ ID GUID を設定します。

  UMDF ドライバーは、インストルメンテーション マニフェスト ファイルを通じて生成されるヘッダー ファイルも含める必要があります。ヘッダー ファイルでは、トレース メッセージを書き込む EventWriteReadFail などのマクロが定義されています。

カーネル モード ドライバーでアクティビティ ID GUID を追加する方法

カーネル モードでは、ドライバーは、ユーザー モードで作られたスレッドまたはドライバーによって作られたスレッドでメッセージをトレースできます。いずれの場合も、ドライバーはスレッドのアクティビティ ID GUID を必要とします。

メッセージをトレースするために、ドライバーは登録ハンドルをイベント プロバイダーとして取得し (EtwRegister を参照)、GUID とイベント メッセージを指定して、EtwWrite を呼び出す必要があります。詳しくは、「カーネル モード ドライバーへのイベント トレースの追加」をご覧ください。

カーネル モード ドライバーでアプリケーションまたはユーザー モード ドライバーによって作られた要求を処理する場合、カーネル モード ドライバーはアクティビティ ID GUID を作ったり設定したりしません。代わりに、I/O マネージャーがアクティビティ ID の伝達の大部分を処理します。ユーザー モード スレッドで要求が開始された場合、I/O マネージャーがその要求用の IRP を作り、現在のスレッドのアクティビティ ID GUID を新しい IRP に自動的にコピーします。カーネル モード ドライバーでそのスレッドでのイベントをトレースする必要がある場合、カーネル モード ドライバーは IoGetActivityIdIrp を呼び出して GUID を取得し、その後で EtwWrite を呼び出す必要があります。

カーネル モード ドライバーでアクティビティ ID GUID を持つ IRP を作る場合は、そのドライバーが EtwActivityIdControl と EVENT_ACTIVITY_CTRL_CREATE_SET_ID を呼び出して新しい GUID を生成できます。その後で、ドライバーは、IoSetActivityIdIrp を呼び出し、次に EtwWrite を呼び出して、新しい GUID を IRP と関連付けることができます。

アクティビティ ID GUID が IRP と共に次の下位ドライバーに渡されます。下位ドライバーが、それらのトレース メッセージをスレッドに追加できます。

関連トピック

Windows の USB イベント トレーシング

 

 

表示:
© 2015 Microsoft