Ch26 Error Reporting and Application Recovery

前面一章介紹了WER, 這一張講解WER相關的API跟使用

The Windows Error Reporting Console

當process因為未處理的例外終止時,WER會建立一個report, 並透過安全的channels送到MS的server來查看是否有解決的方法

使用者可以在下圖的位子看到歷史紀錄我們可以在報告中看到UnhandledExceptionFileter所接收到的Exception_record 內的 ExceptionInformation的大部分內容, 像是例外代碼

WER在建立report的時候會產生4個檔案, 並在之後把他們刪除

AppCompat.txt
用XML格式儲存process load的modules
Memory.hdmp
針對faulting process產生的user mode dump. 包含stack, heap, handle table. 使用到的flag如下
MiniDumpWithDataSegs
MiniDumpWithProcessThreadData
MiniDumpWithHandleData
MiniDumpWithPrivateReadWriteMemory
MiniDumpWithUnloadedModules
MiniDumpWithFullMemoryInfo
MiniDump.mdmp
User-mode minidump of the faulting process, with following flags:
MiniDumpWithDataSegs
MiniDumpWithUnloadedModules
MiniDumpWithProcessThreadData
Version.txt
windows的版本資訊
Windows NT Version 6.0 Build: 6000 

Product (0x6): Windows Vista (TM) Business Edition: Business 

BuildString: 6000.16386.x86fre.vista_rtm.061101-2205 

Flavor: Multiprocessor Free 

Architecture: X86 

LCID: 1033

Programmatic Windows Error Reporting

werapi.h (Kernel32.dll)內定義了一些function讓我們可以針對process做WER相關的設定

HRESULT WerSetFlags(DWORD dwFlags)
flag with prefix WER_FAULT_REPORTING detail
FLAG_NOHEAP = 1 當report產生時, 不會包含heap內容, 可用來降低report大小
FLAG_DISABLE_THREAD_SUSPENSION = 4 預設WER會停住所有的thread來避免資料損毀, 這個flag則會讓執行續繼續執行, 是個危險的flag
FLAG_QUEUE = 2 選擇這個flag會產生local report而不送到MS.
FLAG_QUEUE_UPLOAD = 8 選擇這個flag會產生local report且送到MS.

最後兩個是依照目前的Consent setting來顯示

FLAG_QUEUE
FLAG_QUEUE_UPLOAD 會跳出視窗詢問使用者是否上傳,

如果想要查看設定, 可以用

HRESULT WerGetFlags(HANDLE hProcess, PDWORD pdwFlags);

hProcess是你要查的process handle, 必須有PROCESS_VM_READ的權限, 可以用GetCurrnetProcess來取得
要注意的是在用WerGetFlag一定要和WerSetFlags搭配使用, 否則會回傳WER_E_NOT_FOUND的error

避免產生&傳送報告

HRESULT WerAddExcludedApplication(PCWSTR pwzExeName, BOOL bAllUsers);

pwzExeName : exe的檔案名稱, 也可以是full path name
bAllUsers是設定針對特定登入的使用者來exclude report或是對於所有的使用者. 如果這個設定True的話, 這個application必須是處在administrator的權限下執行才有辦法, 不然他會回傳E_ACCESSDENIED

不過就算關掉了WER的report, WerFault.exe還是會跳出視窗讓使用者選擇是要debug或關閉

如果要把上面的設定關掉(還原WER功能), 呼叫下面API

HRESULT WerRemoveExcludedApplication(PCWSTR pwzExeName, BOOL bAllUsers);

這兩個API都定義在werapi.h內(wer.dll)

Creating and Customizing a Problem Report

接下來要講如何客製化problem report, 這個報告不一定是在例外發生的時候才產生, 只要有遇到問題都可以建立, 而且產生報告並不需要中斷process

透過WER的方式就可以取代Windows Event Log, 同時也不需要特地去加密你的內容

不過WER是有大小跟數量限制的, 設定值在這

HKEY_CURRENT_USER\Software\Microsoft\Windows\Windows Error Reporting
Registry setting 描述
MaxArchiveCount 歷史檔案的數量上限, 範圍在 1 ~ 5000, 預設是1000
MaxQueueCount 本地端儲存準備上傳到MS的報告的queue size, 範圍是1 ~ 500, 預設50

Customizing All Problem Reports Within a Process

有的時候我們會想要客製化WER的內容, 像是

  1. 有自訂一的unhandled exception filter
  2. 想要在沒有例外產生的時候建立報告
  3. 想要在報告加額外的資訊

可以使用

HRESULT WerRegisterMemoryBlock(PVOID pvAddress, DWORD dwSize);

來指定特定區段的資料寫到每一個report中
pvAddress就是memory block的位址
dwSize則是要寫入的大小
這個區段的資料永遠都會寫到minidump中, 方便檢驗數值, 可以重複使用這個function來加入多個data block!

如果是針對特定檔案要被WER蒐集到, 可以使用

HRESULT WerRegisterFile(
   PCWSTR pwzFilename,
   WER_REGISTER_FILE_TYPE regFileType,
   DWORD dwFlags);

pwzFilename是檔案名稱, 如果不是完整路徑的話就會在working directory下找,
regFileType 是用來標示是否包含隱私資料, 有標註的話就不會送到MS

type value
WerRegFileTypeUserDocument 1, The document in use by the application at the time of the event. This document is only collected if the Watson server asks for it.
WerRegFileTypeOther 2

dwFlags, 其他設定

DELETE_WHEN_DONE = 1
ANONYMOUS_DATA = 2
代表這個檔案不包含任何個資, 假如沒有設定的話, 第一次WER會跳出視窗詢問使用者是否上傳, 一旦確認就會被標記成ANONYMOUS_DATA. 所有的ANONYMOUS_DATA會在consent setting = 3的時候自動被上傳, 不會詢問使用者.

同樣可以重複使用這個api來蒐集多個檔案的資料, 但是總數是有上限的!!
WER_MAX_REGISTERED_ENTRIES = 512
代表不論是file或是data block, 你的總數量不可超過512
否則會收到error

if (HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER)

假如要取消註冊的話, 呼叫下面

HRESULT WerUnregisterMemoryBlock(PVOID pvAddress);
HRESULT WerUnregisterFile(PCWSTR pwzFilePath);

建立客製化的報告

接下來要講如何客製化problem report, 這個報告不一定是在例外發生的時候才產生, 只要有遇到問題都可以建立, 而且產生報告並不需要中斷process

透過WER的方式就可以取代Windows Event Log, 同時也不需要特地去加密你的內容

不過WER是有大小跟數量限制的, 設定值在這

HKEY_CURRENT_USER\Software\Microsoft\Windows\Windows Error Reporting
Registry setting 描述
MaxArchiveCount 歷史檔案的數量上限, 範圍在 1 ~ 5000, 預設是1000
MaxQueueCount 本地端儲存準備上傳到MS的報告的queue size, 範圍是1 ~ 500, 預設50

被傳送到MS的報告的歷史紀錄會以檔案形式儲存在ReportArchive資料夾, 但是附加的檔案不會被存在這

WIN ?
AppData\Local\Microsoft\Windows\WER\ReportArchive 

Win10
C:\ProgramData\Microsoft\Windows\WER\ReportArchive

至於尚未被傳送的報告會被存在ReportQueu資料夾

\Local\ Microsoft\Windows\WER\ReportQueue

Win10
C:\ProgramData\Microsoft\Windows\WER\ReportQueue

但是上面兩個位子的報告都沒有辦法在現行的WER API被存取到

相關的設定可以參考這兩組registry底下的資訊

HKEY_CURRENT_USER\Software\Microsoft\Windows\Windows Error Reporting
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\Windows Error Reporting

MSDN資料:
https://msdn.microsoft.com/zh-tw/library/windows/desktop/bb513638(v=vs.85).aspx

客製化與建立WER問題報告

有幾個api可以使用

  1. WerReportCreate 已建立一個新的問題報告
  2. WerReportSetParameter 呼叫多次或不使用, 可設定參數
  3. WerReportAddDump 加一個minidump到報告
  4. WerReportAddFile 用來添加使用者的其他檔案到報告中
  5. WerReportSetUIOption 可以客製化UI,會在WerReportSubmit 被呼叫的時候顯示給使用者
  6. WerReportSubmit 是用來提交報告, 會依據系統設定來處理看是不是跳出詢問視窗
  7. WerReportCloseHandle 關閉報告

可以從這張圖看出這些function確切的效果

而這些WER*開頭的api都是unicode格式, 所以沒有再區分A版或W版
回傳值都是HRESULT

WerReportCreate

用來建立report, 如果成功的話會在最後一個參數phReportHandle回傳report的handle

HRESULT WINAPI WerReportCreate(
  _In_     PCWSTR                  pwzEventType,
  _In_     WER_REPORT_TYPE         repType,
  _In_opt_ PWER_REPORT_INFORMATION pReportInformation,
  _Out_    HREPORT                 *phReportHandle
);

用來建立report, 成功的話會在phReportHandle回傳report handle

參數說明
pwzEventType是一個unicode字串, 是事件的名稱

以前如果這個報告想要在Windows Quality Web site 上看到(此網站已關閉, 合併到https://sysdev.microsoft.com/zh-TW/Hardware/signup/), 事件的名稱必須要是WinQual上註冊過的; 現在則是純粹的名稱用途
補充說明WinQual, 曾經是一個微軟提供使用者註冊Windows Logo program用的服務,並且可以存取WER的資料, 但此系統已退休並且由Windows Dev Center整併功能. Windows Logo Program沒查到是啥,但他也退休了, 現由 Windows Hardware Certification Program取代, 簡單講就是一個認證你的程式是微軟認可的一個機制.
Windows Quality Online Services (Winqual) was a Microsoft web service providing a developer dashboard to certification for the Microsoft Windows logo programs and access to the Windows Error Reporting (WER) data. In preparation for Windows 8 the Winqual site was retired [1] and its features were rolled together with an interface for creating a developer account and managing your Windows Store Apps called Windows Dev Center.[2]

End-users may have accessed the Winqual site through windows error reporting response links or other references to the infrastructure in the Windows Error Reporting systems.
The Windows Hardware Certification Kit (Windows HCK) is a test framework used to certify hardware devices for Windows. To qualify for a Windows certification, previously known as Windows logo, your product must pass testing using the Windows HCK.
This Windows HCK User’s Guide provides instructions on how to build a test environment, automate driver and system testing, and create a submission package required to obtain Windows Logo.
Reference:

https://msdn.microsoft.com/en-us/library/windows/hardware/jj124227.aspx https://msdn.microsoft.com/en-us/library/windows/hardware/dn641155(v=vs.85).aspx
https://sysdev.microsoft.com/zh-TW/Hardware/signup/
https://en.wikipedia.org/wiki/Winqual

回到參數
repType

repType 描述
WerReportNonCritical = 0 報告會自動加到queue內並依照consent setting看是否上傳到MS
WerReportCritical = 1 報告會加到local queue並詢問使用者是否要上傳, 如果需要的話會結束程式
WerReportApplicationCrash = 2 和1同, 但UI顯示為application名稱而非檔案名稱
WerReportApplicationHang = 3 同2, 但是使用時機不同

pReportInformation 是一個指向WER_REPORT_INFORMATION結構的指標, 裡面全部都只有WCHAR

typedef struct _WER_REPORT_INFORMATION {
  DWORD  dwSize;                      // The size of this structure, in bytes.       
  HANDLE hProcess;                    // A handle to the process for which the report is being generated. If this member is NULL, this is the calling process.
  WCHAR  wzConsentKey[64];            // The name used to look up consent settings. If this member is empty, the default is the name specified by the pwzEventType parameter of WerReportCreate.
  WCHAR  wzFriendlyEventName[128];    // The display name. If this member is empty, the default is the name specified by pwzEventType parameter of WerReportCreate.
  WCHAR  wzApplicationName[128];      // The name of the application. If this parameter is empty, the default is the base name of the image file.
  WCHAR  wzApplicationPath[MAX_PATH]; // The full path to the application.
  WCHAR  wzDescription[512];          // A description of the problem. This description is displayed in Problem Reports and Solutions on Windows Vista or the problem reports pane of the Action Center on Windows 7.
  HWND   hwndParent;                  // A handle to the parent window.
} WER_REPORT_INFORMATION, *PWER_REPORT_INFORMATION;

WerReportSetParameter

可以用來設定report內的特定事件的參數, 是一系列的key/value.

HRESULT WINAPI WerReportSetParameter(
  _In_     HREPORT hReportHandle,    // handle from WerReportCreate
  _In_     DWORD   dwparamID,        // indicates which key/value pair you want to set. Max 10 pairs
  _In_opt_ PCWSTR  pwzName,          // A pointer to a Unicode string that contains the name of the parameter. if NULL, the name will be Px based on dwparamID.
  _In_     PCWSTR  pwzValue          // The parameter value.
);

dwParamID的數值意義如下表, 如果在非範圍內的ID會回傳E_INVALIDARG
如果針對特定ID不停地設定, 最後呼叫WerReportSubmit會回傳error 0x8008FF05. ((但是這個error不見啦!!!!!查不到了
要注意的是如果你定義了Px, 則必須設定 0~X中間所有的值.

ID 描述
0 0
1 出事的application名稱
2 版本
3 時間戳記time stamp
4 出事的module名稱
5 出事的module版本
6 application建立的時間
7 exception code
8 offset in byte標示module內的錯誤位址, 是透過extended instruction Pointer( EIP) 計算出來的
9 9

回傳值會是S_OK 或這兩種
E_HANDLE : invalid handle
WER_E_LENGTH_EXCEEDED : 如果有任何字串格式的參數長度超過限制

WerReportAddDump

如果要在WER產生的時候同時產生minidump, 用這個

HRESULT WINAPI WerReportAddDump(
  _In_     HREPORT                    hReportHandle,
  _In_     HANDLE                     hProcess,    // 當前要建立report的這個process的handle, 必須要STANDARD_RIGHTS_READ & PROCESS_QUERY_INFORMATION 權限, 可以用GetCurrentProcess回傳的就會有全部的權限 
  _In_opt_ HANDLE                     hThread,     // 當前要建立report的這個thread的handle, 只有dumpType是WerDumpTypeMicro才需要, 其餘給NULL
  _In_     WER_DUMP_TYPE              dumpType,  
  _In_opt_ PWER_EXCEPTION_INFORMATION pExceptionParam,  // A pointer to a WER_EXCEPTION_INFORMATION structure 
  _In_opt_ PWER_DUMP_CUSTOM_OPTIONS   pDumpCustomOptions, // A pointer to a WER_DUMP_CUSTOM_OPTIONS structure. 如果NULL就會用預設
  _In_     DWORD                      dwFlags      
);

dumpType是一系列由不同功能flag所組成的type, 會和PWER_DUMP_CUSTOM_OPTIONS 一起使用

title detail
Type WerDumpTypeHeapDump
Detail dump包含其他進階的資料, 不會傳送給Watson server.
flag MiniDumpWithDataSegs
MiniDumpWithProcessThreadData
MiniDumpWithProcessThreadData
MiniDumpWithHandleData
MiniDumpWithPrivateReadWriteMemory
MiniDumpWithUnloadedModules
MiniDumpWithFullMemoryInfo
MiniDumpWithThreadInfo (Windows 7 and later)
MiniDumpWithTokenInformation (Windows 7 and later)
MiniDumpWithPrivateWriteCopyMemory (Windows 7 and later)
Type WerDumpTypeMicroDump
Detail 只有stack的dump
MiniDumpWithDataSegs
MiniDumpWithUnloadedModules
MiniDumpWithProcessThreadData
MiniDumpWithoutOptionalData
Type WerDumpTypeMiniDump
Detail minidump, will send the mini dump to the server.
MiniDumpWithDataSegs
MiniDumpWithUnloadedModules
MiniDumpWithProcessThreadData
MiniDumpWithTokenInformation (Windows 7 and later)

pExceptionParam則是_WER_EXCEPTION_INFORMATION結構的指標

typedef struct _WER_EXCEPTION_INFORMATION {
  PEXCEPTION_POINTERS pExceptionPointers;  // GetExceptionInformation 的回傳值
  BOOL                bClientPointers;
} WER_EXCEPTION_INFORMATION, *PWER_EXCEPTION_INFORMATION;

bClientPointers

A process (calling process) can provide error reporting functionality for another process (client process). If this member is TRUE, the exception pointer is located inside the address space of the client process. If this member is FALSE, the exception pointer is located inside the address space of the calling process.
typedef struct _WER_DUMP_CUSTOM_OPTIONS {
  DWORD dwSize;
  DWORD dwMask;
  DWORD dwDumpFlags;
  BOOL  bOnlyThisThread;
  DWORD dwExceptionThreadFlags;
  DWORD dwOtherThreadFlags;
  DWORD dwExceptionThreadExFlags;
  DWORD dwOtherThreadExFlags;
  DWORD dwPreferredModuleFlags;
  DWORD dwOtherModuleFlags;
  WCHAR wzPreferredModuleList[WER_MAX_PREFERRED_MODULES_BUFFER];
} WER_DUMP_CUSTOM_OPTIONS, *PWER_DUMP_CUSTOM_OPTIONS;

ref:
https://msdn.microsoft.com/en-us/library/windows/desktop/bb513632(v=vs.85).aspx

dwFlags 可以用來節省硬碟空間, 設為WER_DUMP_NOHEAP_ONQUEUE就不會包含heap dump.也可以是0

WerReportAddFile

他跟前面的add arbitrary file功能很類似, 但在report中這個api內可以加更多的file,超過512個

WerRegisterFile : Registers a file to be collected when WER creates an error report.
WerReportAddFile : Adds a file to the specified report.
HRESULT WINAPI WerReportAddFile(
  _In_ HREPORT       hReportHandle,  // A handle to the report.
  _In_ PCWSTR        pwzPath,        // full path to the file to be added. 可使用環境變數, 長度上限為max_path
  _In_ WER_FILE_TYPE repFileType,
  _In_ DWORD         dwFileFlags     // has the same meaning as it does for the WerRegisterFile function,
);

WER_FILE_TYPE

TYPE DETAIL
WerFileTypeMicrodump = 1 A limited minidump that contains only a stack trace.
WerFileTypeMinidump = 2 A minidump file.
WerFileTypeHeapdump = 3 An extended minidump that contains additional data such as the process memory.
WerFileTypeUserDocument = 4 The document in use by the application at the time of the event. The document is added only if the server is asks for this type of document.
WerFileTypeOther = 5 Any other type of file. This file will always get added to the cab (but only if the server asks for a cab).

dwFileFlags

FLAGS 描述
WER_FILE_ANONYMOUS_DATA 表示檔案沒有包含個資
WER_FILE_DELETE_WHEN_DONE 當報告SUBMIT後自動刪除檔案

Modifying Dialog Box Strings: WerReportSetUIOption

HRESULT WerReportSetUIOption(
   HREPORT hReport,          // report handle
   WER_REPORT_UI repUITypeID,// indicates the user-interface element whose text is going to change
   PCWSTR pwzValue);         //Unicode String will shown

有一些是不能更動的, 能改的部分如圖

Submitting a Problem Report: WerReportSubmit

功能: Submits the specified report.

HRESUSubmits the specified report.LT WerReportSubmit(
   HREPORT hReport,        // report handle
   WER_CONSENT consent,    // WerConsentNotAsked, WerConsentApproved, or WerConsentDenied
   DWORD dwFlags,
   PWER_SUBMIT_RESULT pSubmitResult  // check submit status
   );

雖然說是否上傳report是由Consent registry setting決定,但顯示哪種UI是由WER_CONSENT決定

WerConsentApproved : 顯示詢問視窗


WerConsentNotAsked 當和 Consent setting is 1 同時使用 ( which means always show below)

when choose ask me ... in first dialog, pops up above to let the user decide whether the report should be sent to Microsoft and look for a possible solution before closing the application.

dwFlags

https://msdn.microsoft.com/en-us/library/windows/desktop/bb513628(v=vs.85).aspx

PWER_SUBMIT_RESULT

![](/assets/WerReportSubmitResult.png

通常結果是看submitResult, 但只有在回傳WER_SUBMIT_OUTOFPROCESS_ASYNC 的時候不能看

這代表WerReportSubmit 在報告處理結束以前就回傳了,這個可以用來觀測別的PROCESS
是否有問題,向scm會拿來觀察SERVICE HANG

WerReportCloseHandle

HRESULT WerReportCloseHandle(HREPORT hReportHandle);

記得close handle

Automatic Application Restart and Recovery

WER提供自動重新啟動的功能,但必須註冊

HRESULT RegisterApplicationRestart(
   PCWSTR pwzCommandline,   //Unicode string identifying the command line that WER should use to restart the application. pass NULL if no need args.
   DWORD dwFlags  //control when/condition to restart, 0 is always
   );

dwFlags

如果不想用, 可以反註冊

HRESULT UnregisterApplicationRestart();

Support for Application Recovery

假如想要讓WER在process在terminat時callback, 可以用下面這個:

Windows Via C/C++ - Books24x7

HRESULT RegisterApplicationRecoveryCallback(
   APPLICATION_RECOVERY_CALLBACK pfnRecoveryCallback,
   PVOID pvParameter,
   DWORD dwPingInterval,
   DWORD dwFlags); // Reserved; pass 0

pfnRecoveryCallback是從這邊拿到的 (pvParameter)

DWORD WINAPI ApplicationRecoveryCallback(PVOID pvParameter);

使用後會顯示下面的視窗

Sample Code

https://msdn.microsoft.com/en-us/library/cc303699.aspx

results matching ""

    No results matching ""