36 #include <nsAutoLock.h>
37 #include <nsServiceManagerUtils.h>
38 #include <nsCRTGlue.h>
40 #include <nsIFileURL.h>
41 #include <nsAutoPtr.h>
42 #include <nsThreadUtils.h>
43 #include <nsNetUtil.h>
45 #include <nsIIOService.h>
46 #include <nsIPrefService.h>
47 #include <nsIPrefBranch2.h>
48 #include <nsIInputStream.h>
49 #include <nsILineInputStream.h>
56 #define DEFAULT_MAP_SIZE 20
60 extern PRLogModuleInfo* gMetadataLog;
61 #define TRACE(args) PR_LOG(gMetadataLog, PR_LOG_DEBUG, args)
62 #define LOG(args) PR_LOG(gMetadataLog, PR_LOG_WARN, args)
73 mBlacklistFile(nsnull),
76 mOutputStream(nsnull),
79 TRACE((
"sbMetadataCrashTracker[0x%.8x] - ctor",
this));
86 TRACE((
"sbMetadataCrashTracker[0x%.8x] - dtor",
this));
90 nsAutoLock::DestroyLock(mLock);
97 NS_ASSERTION(NS_IsMainThread(),
98 "sbMetadataCrashTracker::Init: MUST NOT INIT OFF OF MAIN THREAD!");
100 return NS_ERROR_ALREADY_INITIALIZED;
104 mLock = nsAutoLock::NewLock(
105 "sbMetadataCrashTracker file lock");
106 NS_ENSURE_TRUE(mLock, NS_ERROR_OUT_OF_MEMORY);
110 NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
114 NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
116 rv = GetProfileFile(NS_LITERAL_STRING(
"metadata-url-io.blacklist"),
117 getter_AddRefs(mBlacklistFile));
118 NS_ENSURE_SUCCESS(rv, rv);
121 rv = ReadBlacklist();
123 NS_ERROR(
"sbMetadataCrashTracker::Init failed to load blacklist!");
127 nsAutoLock lock(mLock);
129 rv = GetProfileFile(NS_LITERAL_STRING(
"metadata-io.log"),
130 getter_AddRefs(mLogFile));
131 NS_ENSURE_SUCCESS(rv, rv);
135 rv = ProcessExistingLog();
137 NS_ERROR(
"sbMetadataCrashTracker::Init failed to process existing log!");
142 nsCOMPtr<nsIPrefBranch> prefService =
143 do_GetService(
"@mozilla.org/preferences-service;1", &rv);
144 NS_ENSURE_SUCCESS( rv, rv);
146 prefService->GetCharPref(
"songbird.metadata.simulate.crash.url",
147 getter_Copies(mSimulateCrashURL));
154 NS_ENSURE_STATE(mLogFile);
161 nsAutoLock lock(mLock);
163 nsCOMPtr<nsIFileOutputStream> fileStream =
164 do_CreateInstance(
"@mozilla.org/network/file-output-stream;1", &rv);
165 NS_ENSURE_SUCCESS(rv, rv);
168 rv = fileStream->Init(mLogFile, ioFlags, -1, 0);
169 NS_ENSURE_SUCCESS(rv, rv);
171 mOutputStream = do_QueryInterface(fileStream, &rv);
172 NS_ENSURE_SUCCESS(rv, rv);
182 nsAutoLock lock(mLock);
185 mOutputStream->Close();
186 mOutputStream = nsnull;
187 mLogFile->Remove(PR_FALSE);
190 mURLToIndexMap.Clear();
202 if (!mOutputStream) {
204 NS_ENSURE_SUCCESS(rv, rv);
207 nsAutoLock lock(mLock);
212 PRUint32 index = mCounter++;
213 mURLToIndexMap.Put(aURL, index);
218 output.AppendInt(index);
223 PRUint32 bytesWritten;
224 rv = mOutputStream->Write(output.BeginReading(),
227 NS_ENSURE_SUCCESS(rv, rv);
231 if (!mSimulateCrashURL.IsEmpty()) {
232 if (output.Find(mSimulateCrashURL, PR_TRUE) != -1) {
233 LOG((
"LogURLBegin forcing a crash for %s", output.BeginReading()));
247 NS_ENSURE_STATE(mOutputStream);
250 nsAutoLock lock(mLock);
254 PRBool success = mURLToIndexMap.Get(aURL, &index);
255 NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
256 mURLToIndexMap.Remove(aURL);
260 output.AppendInt(index);
263 PRUint32 bytesWritten;
264 rv = mOutputStream->Write(output.BeginReading(),
267 NS_ENSURE_SUCCESS(rv, rv);
275 PRBool* aIsBlackListed)
279 *aIsBlackListed = mURLBlacklist.Get(aURL, nsnull);
291 NS_ASSERTION(NS_IsMainThread(),
292 "sbMetadataCrashTracker::AddBlacklistURL"
293 " Unexpectedly called off main thread");
294 mURLBlacklist.Put(aURL, PR_TRUE);
302 sbMetadataCrashTracker::ProcessExistingLog()
304 NS_ENSURE_STATE(mLogFile);
308 PRBool exists = PR_FALSE;
309 rv = mLogFile->Exists(&exists);
310 NS_ENSURE_SUCCESS(rv, rv);
318 nsCOMPtr<nsIInputStream> inputStream;
319 rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), mLogFile);
320 NS_ENSURE_SUCCESS(rv, rv);
321 nsCOMPtr<nsILineInputStream> lineStream(do_QueryInterface(inputStream, &rv));
322 NS_ENSURE_SUCCESS(rv, rv);
324 nsDataHashtable<nsCStringHashKey, nsCString> indexToURLMap;
327 PRBool more = PR_TRUE;
330 PRBool hashSuccess = PR_FALSE;
332 rv = lineStream->ReadLine(line, &more);
333 if (NS_SUCCEEDED(rv) && line.Length() >= 2) {
334 switch (line.First()) {
337 PRInt32 separatorIndex = line.FindChar(
' ', 1);
338 if (separatorIndex > 0 && separatorIndex < (PRInt32)(line.Length() - 1)) {
340 url = Substring(line, separatorIndex + 1);
342 line = Substring(line, 1, separatorIndex - 1);
344 indexToURLMap.Put(line, url);
346 TRACE((
"sbMetadataCrashTracker::ProcessExistingLog " \
347 "- found Begin record '%s', '%s'",
348 line.BeginReading(), url.BeginReading()));
350 NS_ERROR(
"Found Begin record without URL");
362 hashSuccess = indexToURLMap.Get(line, nsnull);
364 TRACE((
"sbMetadataCrashTracker::ProcessExistingLog " \
365 "- found End record '%s'", line.BeginReading()));
366 indexToURLMap.Remove(line);
368 NS_ERROR(
"Found End record without matching Begin");
374 NS_ERROR(
"Invalid sbMetadataCrashTracker log file");
377 }
while (NS_SUCCEEDED(rv) && more);
378 inputStream->Close();
382 if (indexToURLMap.Count() > 0) {
383 indexToURLMap.EnumerateRead(AddURLsToBlacklist, &mURLBlacklist);
384 rv = WriteBlacklist();
385 NS_ENSURE_SUCCESS(rv, rv);
386 TRACE((
"sbMetadataCrashTracker::ProcessExistingLog - " \
387 " found %d suspect URLs", indexToURLMap.Count()));
389 TRACE((
"sbMetadataCrashTracker::ProcessExistingLog - no suspect URLs"));
393 mLogFile->Remove(PR_FALSE);
398 PLDHashOperator PR_CALLBACK
399 sbMetadataCrashTracker::AddURLsToBlacklist(nsCStringHashKey::KeyType aKey,
403 if (aEntry.IsEmpty()) {
404 NS_ERROR(
"Attempted to add an empty string to the blacklist");
405 return PL_DHASH_NEXT;
407 nsDataHashtable<nsCStringHashKey, PRBool>* blacklistHash =
408 static_cast<nsDataHashtable<nsCStringHashKey, PRBool>*
>(aUserData);
409 NS_ENSURE_TRUE(blacklistHash, PL_DHASH_STOP);
411 blacklistHash->Put(aEntry, PR_TRUE);
412 return PL_DHASH_NEXT;
415 PLDHashOperator PR_CALLBACK
416 sbMetadataCrashTracker::WriteBlacklistURLToFile(nsCStringHashKey::KeyType aKey,
421 if (aKey.IsEmpty()) {
422 NS_ERROR(
"Attempted to add an empty string to the blacklist file");
423 return PL_DHASH_NEXT;
425 nsIOutputStream* outputStream =
426 static_cast<nsIOutputStream*
>(aUserData);
427 NS_ENSURE_TRUE(outputStream, PL_DHASH_STOP);
430 output.AppendLiteral(
"\n");
432 PRUint32 bytesWritten;
433 rv = outputStream->Write(
output.BeginReading(),
436 NS_ENSURE_SUCCESS(rv, PL_DHASH_STOP);
438 return PL_DHASH_NEXT;
442 sbMetadataCrashTracker::ReadBlacklist()
444 NS_ENSURE_STATE(mBlacklistFile);
448 PRBool exists = PR_FALSE;
449 rv = mBlacklistFile->Exists(&exists);
450 NS_ENSURE_SUCCESS(rv, rv);
456 nsCOMPtr<nsIInputStream> inputStream;
457 rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), mBlacklistFile);
458 NS_ENSURE_SUCCESS(rv, rv);
459 nsCOMPtr<nsILineInputStream> lineStream(do_QueryInterface(inputStream, &rv));
460 NS_ENSURE_SUCCESS(rv, rv);
462 PRBool more = PR_TRUE;
466 rv = lineStream->ReadLine(line, &more);
467 NS_ENSURE_SUCCESS(rv, rv);
468 NS_ENSURE_TRUE(more, NS_ERROR_FAILURE);
469 NS_ENSURE_TRUE(line.First() ==
'#', NS_ERROR_UNEXPECTED);
473 rv = lineStream->ReadLine(line, &more);
474 if (NS_SUCCEEDED(rv) && !line.IsEmpty()) {
475 PRBool blacklisted = PR_TRUE;
476 mURLBlacklist.Put(line, blacklisted);
477 LOG((
"sbMetadataCrashTracker::ReadBlacklist() - found %s",
478 line.BeginReading()));
480 }
while (NS_SUCCEEDED(rv) && more);
482 inputStream->Close();
488 sbMetadataCrashTracker::WriteBlacklist()
490 NS_ENSURE_STATE(mBlacklistFile);
494 nsCOMPtr<nsIFileOutputStream> fileStream =
495 do_CreateInstance(
"@mozilla.org/network/file-output-stream;1", &rv);
496 NS_ENSURE_SUCCESS(rv, rv);
499 rv = fileStream->Init(mBlacklistFile, ioFlags, -1, 0);
500 NS_ENSURE_SUCCESS(rv, rv);
502 nsCOMPtr<nsIOutputStream> outputStream = do_QueryInterface(fileStream, &rv);
503 NS_ENSURE_SUCCESS(rv, rv);
506 nsCString
output(
"# URLs listed in this file are suspected of " \
507 "crashing Songbird, and will be ignored.\n");
509 PRUint32 bytesWritten;
510 rv = outputStream->Write(
output.BeginReading(),
513 NS_ENSURE_SUCCESS(rv, rv);
516 mURLBlacklist.EnumerateRead(WriteBlacklistURLToFile, outputStream);
518 outputStream->Close();
523 sbMetadataCrashTracker::GetProfileFile(
const nsAString&
aName, nsIFile** aFile)
525 NS_ENSURE_ARG_POINTER(aFile);
529 nsCOMPtr<nsIProperties> directoryService(
530 do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
531 NS_ENSURE_SUCCESS(rv, rv);
534 nsCOMPtr<nsIFile>
file;
535 rv = directoryService->Get(
"ProfD", NS_GET_IID(nsIFile),
536 getter_AddRefs(file));
537 NS_ENSURE_SUCCESS(rv, rv);
540 rv = file->Append(aName);
541 NS_ENSURE_SUCCESS(rv, rv);