llcrashloggermac.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:8k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llcrashloggermac.cpp
  3.  * @brief Mac OSX crash logger implementation
  4.  *
  5.  * $LicenseInfo:firstyear=2003&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2003-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */
  32. #include "llcrashloggermac.h"
  33. #include <Carbon/Carbon.h>
  34. #include <iostream>
  35. #include <sstream>
  36. #include "boost/tokenizer.hpp"
  37. #include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME
  38. #include "llerror.h"
  39. #include "llfile.h"
  40. #include "lltimer.h"
  41. #include "llstring.h"
  42. #include "lldir.h"
  43. #include "llsdserialize.h"
  44. #define MAX_LOADSTRING 100
  45. const char* const SETTINGS_FILE_HEADER = "version";
  46. const S32 SETTINGS_FILE_VERSION = 101;
  47. // Windows Message Handlers
  48. BOOL gFirstDialog = TRUE; // Are we currently handling the Send/Don't Send dialog?
  49. LLFILE *gDebugFile = NULL;
  50. WindowRef gWindow = NULL;
  51. EventHandlerRef gEventHandler = NULL;
  52. std::string gUserNotes = "";
  53. bool gSendReport = false;
  54. bool gRememberChoice = false;
  55. IBNibRef nib = NULL;
  56. OSStatus dialogHandler(EventHandlerCallRef handler, EventRef event, void *userdata)
  57. {
  58. OSStatus result = eventNotHandledErr;
  59. OSStatus err;
  60. UInt32 evtClass = GetEventClass(event);
  61. UInt32 evtKind = GetEventKind(event);
  62. if((evtClass == kEventClassCommand) && (evtKind == kEventCommandProcess))
  63. {
  64. HICommand cmd;
  65. err = GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL, sizeof(cmd), NULL, &cmd);
  66. if(err == noErr)
  67. {
  68. //Get the value of the checkbox
  69. ControlID id;
  70. ControlRef checkBox = NULL;
  71. id.signature = 'remb';
  72. id.id = 0;
  73. err = GetControlByID(gWindow, &id, &checkBox);
  74. if(err == noErr)
  75. {
  76. if(GetControl32BitValue(checkBox) == kControlCheckBoxCheckedValue)
  77. {
  78. gRememberChoice = true;
  79. }
  80. else
  81. {
  82. gRememberChoice = false;
  83. }
  84. }
  85. switch(cmd.commandID)
  86. {
  87. case kHICommandOK:
  88. {
  89. char buffer[65535]; /* Flawfinder: ignore */
  90. Size size = sizeof(buffer) - 1;
  91. ControlRef textField = NULL;
  92. id.signature = 'text';
  93. id.id = 0;
  94. err = GetControlByID(gWindow, &id, &textField);
  95. if(err == noErr)
  96. {
  97. // Get the user response text
  98. err = GetControlData(textField, kControlNoPart, kControlEditTextTextTag, size, (Ptr)buffer, &size);
  99. }
  100. if(err == noErr)
  101. {
  102. // Make sure the string is terminated.
  103. buffer[size] = 0;
  104. gUserNotes = buffer;
  105. llinfos << buffer << llendl;
  106. }
  107. // Send the report.
  108. QuitAppModalLoopForWindow(gWindow);
  109. gSendReport = true;
  110. result = noErr;
  111. }
  112. break;
  113. case kHICommandCancel:
  114. QuitAppModalLoopForWindow(gWindow);
  115. result = noErr;
  116. break;
  117. default:
  118. result = eventNotHandledErr;
  119. }
  120. }
  121. }
  122. return(result);
  123. }
  124. LLCrashLoggerMac::LLCrashLoggerMac(void)
  125. {
  126. }
  127. LLCrashLoggerMac::~LLCrashLoggerMac(void)
  128. {
  129. }
  130. bool LLCrashLoggerMac::init(void)
  131. {
  132. bool ok = LLCrashLogger::init();
  133. if(!ok) return false;
  134. if(mCrashBehavior != CRASH_BEHAVIOR_ASK) return true;
  135. // Real UI...
  136. OSStatus err;
  137. err = CreateNibReference(CFSTR("CrashReporter"), &nib);
  138. if(err == noErr)
  139. {
  140. err = CreateWindowFromNib(nib, CFSTR("CrashReporter"), &gWindow);
  141. }
  142. if(err == noErr)
  143. {
  144. // Set focus to the edit text area
  145. ControlRef textField = NULL;
  146. ControlID id;
  147. id.signature = 'text';
  148. id.id = 0;
  149. // Don't set err if any of this fails, since it's non-critical.
  150. if(GetControlByID(gWindow, &id, &textField) == noErr)
  151. {
  152. SetKeyboardFocus(gWindow, textField, kControlFocusNextPart);
  153. }
  154. }
  155. if(err == noErr)
  156. {
  157. ShowWindow(gWindow);
  158. }
  159. if(err == noErr)
  160. {
  161. // Set up an event handler for the window.
  162. EventTypeSpec handlerEvents[] = 
  163. {
  164. { kEventClassCommand, kEventCommandProcess }
  165. };
  166. InstallWindowEventHandler(
  167. gWindow, 
  168. NewEventHandlerUPP(dialogHandler), 
  169. GetEventTypeCount (handlerEvents), 
  170. handlerEvents, 
  171. 0, 
  172. &gEventHandler);
  173. }
  174. return true;
  175. }
  176. void LLCrashLoggerMac::gatherPlatformSpecificFiles()
  177. {
  178. updateApplication("Gathering hardware information...");
  179. char path[MAX_PATH];
  180. FSRef folder;
  181. if(FSFindFolder(kUserDomain, kLogsFolderType, false, &folder) == noErr)
  182. {
  183. // folder is an FSRef to ~/Library/Logs/
  184. if(FSRefMakePath(&folder, (UInt8*)&path, sizeof(path)) == noErr)
  185. {
  186. struct stat dw_stat;
  187. std::string mBuf;
  188. bool isLeopard = false;
  189. // Try the 10.3 path first...
  190. std::string dw_file_name = std::string(path) + std::string("/CrashReporter/Second Life.crash.log");
  191. int res = stat(dw_file_name.c_str(), &dw_stat);
  192. if (res)
  193. {
  194. // Try the 10.2 one next...
  195. dw_file_name = std::string(path) + std::string("/Second Life.crash.log");
  196. res = stat(dw_file_name.c_str(), &dw_stat);
  197. }
  198. if(res)
  199. {
  200. //10.5: Like 10.3+, except it puts the crash time in the file instead of dividing it up
  201. //using asterisks. Get a directory listing, search for files starting with second life,
  202. //use the last one found.
  203. std::string old_file_name, current_file_name, pathname, mask;
  204. pathname = std::string(path) + std::string("/CrashReporter/");
  205. mask = "Second Life*";
  206. while(gDirUtilp->getNextFileInDir(pathname, mask, current_file_name, false))
  207. {
  208. old_file_name = current_file_name;
  209. }
  210. if(old_file_name != "")
  211. {
  212. dw_file_name = pathname + old_file_name;
  213. res=stat(dw_file_name.c_str(), &dw_stat);
  214. isLeopard = true;
  215. }
  216. }
  217. if (!res)
  218. {
  219. std::ifstream fp(dw_file_name.c_str());
  220. std::stringstream str;
  221. if(!fp.is_open()) return;
  222. str << fp.rdbuf();
  223. mBuf = str.str();
  224. if(!isLeopard)
  225. {
  226. // Crash logs consist of a number of entries, one per crash.
  227. // Each entry is preceeded by "**********" on a line by itself.
  228. // We want only the most recent (i.e. last) one.
  229. const char *sep = "**********";
  230. const char *start = mBuf.c_str();
  231. const char *cur = start;
  232. const char *temp = strstr(cur, sep);
  233. while(temp != NULL)
  234. {
  235. // Skip past the marker we just found
  236. cur = temp + strlen(sep); /* Flawfinder: ignore */
  237. // and try to find another
  238. temp = strstr(cur, sep);
  239. }
  240. // If there's more than one entry in the log file, strip all but the last one.
  241. if(cur != start)
  242. {
  243. mBuf.erase(0, cur - start);
  244. }
  245. }
  246. mCrashInfo["CrashLog"] = mBuf;
  247. }
  248. else
  249. {
  250. llwarns << "Couldn't find any CrashReporter files..." << llendl;
  251. }
  252. }
  253. }
  254. }
  255. bool LLCrashLoggerMac::mainLoop()
  256. {
  257. OSStatus err = noErr;
  258. if(err == noErr && mCrashBehavior == CRASH_BEHAVIOR_ASK)
  259. {
  260. RunAppModalLoopForWindow(gWindow);
  261. }
  262. else if (mCrashBehavior == CRASH_BEHAVIOR_ALWAYS_SEND)
  263. {
  264. gSendReport = true;
  265. }
  266. if(gRememberChoice)
  267. {
  268. if(gSendReport) saveCrashBehaviorSetting(CRASH_BEHAVIOR_ALWAYS_SEND);
  269. else saveCrashBehaviorSetting(CRASH_BEHAVIOR_NEVER_SEND);
  270. }
  271. if(gSendReport)
  272. {
  273. setUserText(gUserNotes);
  274. sendCrashLogs();
  275. }
  276. if(gWindow != NULL)
  277. {
  278. DisposeWindow(gWindow);
  279. }
  280. if(nib != NULL)
  281. {
  282. DisposeNibReference(nib);
  283. }
  284. return true;
  285. }
  286. void LLCrashLoggerMac::updateApplication(const std::string& message)
  287. {
  288. LLCrashLogger::updateApplication();
  289. }
  290. bool LLCrashLoggerMac::cleanup()
  291. {
  292. return true;
  293. }