nsresult nsProfileCollector::LogOS(nsIMetricsEventItem *profile) { nsCOMPtr<nsIWritablePropertyBag2> properties; nsMetricsUtils::NewPropertyBag(getter_AddRefs(properties)); NS_ENSURE_STATE(properties); char buf[SYS_INFO_BUFFER_LENGTH]; if (PR_GetSystemInfo(PR_SI_SYSNAME, buf, sizeof(buf)) != PR_SUCCESS) { MS_LOG(("Failed to get OS name")); return NS_ERROR_FAILURE; } properties->SetPropertyAsACString(NS_LITERAL_STRING("name"), nsDependentCString(buf)); MS_LOG(("Logged os name=%s", buf)); if (PR_GetSystemInfo(PR_SI_RELEASE, buf, sizeof(buf)) != PR_SUCCESS) { MS_LOG(("Failed to get OS version")); return NS_ERROR_FAILURE; } properties->SetPropertyAsACString(NS_LITERAL_STRING("version"), nsDependentCString(buf)); MS_LOG(("Logged os version=%s", buf)); nsresult rv = nsMetricsUtils::AddChildItem( profile, NS_LITERAL_STRING("os"), properties); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; }
already_AddRefed<nsIMetricsEventItem> nsProfileCollector::ExtensionEnumerator::CreateExtensionItem( nsIUpdateItem *extension) { nsCOMPtr<nsIMetricsEventItem> extensionItem; mMetricsService->CreateEventItem(NS_LITERAL_STRING("extension"), getter_AddRefs(extensionItem)); NS_ENSURE_TRUE(extensionItem, nsnull); nsCOMPtr<nsIWritablePropertyBag2> properties; nsMetricsUtils::NewPropertyBag(getter_AddRefs(properties)); NS_ENSURE_TRUE(properties, nsnull); nsString id, version; extension->GetId(id); NS_ENSURE_TRUE(!id.IsEmpty(), nsnull); nsCString hashedID; nsresult rv = mMetricsService->HashUTF16(id, hashedID); NS_ENSURE_SUCCESS(rv, nsnull); properties->SetPropertyAsACString( NS_LITERAL_STRING("extensionid"), hashedID); extension->GetVersion(version); if (!version.IsEmpty()) { properties->SetPropertyAsAString(NS_LITERAL_STRING("version"), version); } MS_LOG(("Logged extension extensionid=%s (hashed to %s) version=%s", NS_ConvertUTF16toUTF8(id).get(), hashedID.get(), NS_ConvertUTF16toUTF8(version).get())); nsCString resourceID("urn:mozilla:item:"); resourceID.Append(NS_ConvertUTF16toUTF8(id)); nsCOMPtr<nsIRDFResource> itemResource; mRDFService->GetResource(resourceID, getter_AddRefs(itemResource)); NS_ENSURE_TRUE(itemResource, nsnull); nsCOMPtr<nsIRDFNode> itemDisabledNode; mExtensionsDS->GetTarget(itemResource, mDisabledResource, PR_TRUE, getter_AddRefs(itemDisabledNode)); nsCOMPtr<nsIRDFLiteral> itemDisabledLiteral = do_QueryInterface(itemDisabledNode); if (itemDisabledLiteral) { const PRUnichar *value = nsnull; itemDisabledLiteral->GetValueConst(&value); if (nsDependentString(value).Equals(NS_LITERAL_STRING("true"))) { properties->SetPropertyAsBool(NS_LITERAL_STRING("disabled"), PR_TRUE); MS_LOG(("Logged extension disabled=true")); } } extensionItem->SetProperties(properties); nsIMetricsEventItem *item = nsnull; extensionItem.swap(item); return item; }
void nsUICommandCollector::GetEventKeyId(nsIDOMEvent *event, nsString &keyId) const { // The source event will give us the original event in the case where a new // event was dispatched due to a command= attribute. nsCOMPtr<nsIDOMXULCommandEvent> commandEvent = do_QueryInterface(event); if (!commandEvent) { // nsIDOMXULCommandEvent is only in Gecko 1.8.1+ return; } nsCOMPtr<nsIDOMEvent> sourceEvent; commandEvent->GetSourceEvent(getter_AddRefs(sourceEvent)); if (!sourceEvent) { return; } nsCOMPtr<nsIDOMEventTarget> sourceEventTarget; sourceEvent->GetTarget(getter_AddRefs(sourceEventTarget)); nsCOMPtr<nsIDOMElement> sourceElement = do_QueryInterface(sourceEventTarget); if (!sourceElement) { return; } nsString namespaceURI, localName; sourceElement->GetNamespaceURI(namespaceURI); sourceElement->GetLocalName(localName); if (namespaceURI.Equals(NS_LITERAL_STRING("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul")) && localName.Equals(NS_LITERAL_STRING("key"))) { sourceElement->GetAttribute(NS_LITERAL_STRING("id"), keyId); MS_LOG(("Key Id: %s", NS_ConvertUTF16toUTF8(keyId).get())); } }
nsresult nsUICommandCollector::HandleTabMoveEvent(nsIDOMEvent* event) { PRUint32 window; if (NS_FAILED(GetEventWindow(event, &window))) { return NS_OK; } // Fill a property bag with what we want to log nsCOMPtr<nsIWritablePropertyBag2> properties; nsMetricsUtils::NewPropertyBag(getter_AddRefs(properties)); NS_ENSURE_STATE(properties); nsresult rv; rv = properties->SetPropertyAsUint32(NS_LITERAL_STRING("window"), window); NS_ENSURE_SUCCESS(rv, rv); rv = properties->SetPropertyAsAString(NS_LITERAL_STRING("action"), NS_LITERAL_STRING("comand")); NS_ENSURE_SUCCESS(rv, rv); // TabMove events just have a dummy target id of "TabMove_Event". rv = SetHashedValue(properties, NS_LITERAL_STRING("targetidhash"), NS_LITERAL_STRING("TabMove_Event")); NS_ENSURE_SUCCESS(rv, rv); nsMetricsService *ms = nsMetricsService::get(); NS_ENSURE_STATE(ms); rv = ms->LogEvent(NS_LITERAL_STRING("uielement"), properties); NS_ENSURE_SUCCESS(rv, rv); MS_LOG(("Successfully logged UI Event")); return NS_OK; }
nsresult nsUICommandCollector::HandlePopupShowingEvent(nsIDOMEvent* event) { PRUint32 window; if (NS_FAILED(GetEventWindow(event, &window))) return NS_OK; nsString targetId, targetAnonId; if (NS_FAILED(GetEventTargets(event, targetId, targetAnonId))) return NS_OK; NS_ASSERTION(!targetId.IsEmpty(), "can't have an empty target id"); if (!targetId.Equals(NS_LITERAL_STRING("identity-popup")) && !targetId.Equals(NS_LITERAL_STRING("editBookmarkPanel"))) return NS_OK; // Fill a property bag with what we want to log nsCOMPtr<nsIWritablePropertyBag2> properties; nsMetricsUtils::NewPropertyBag(getter_AddRefs(properties)); NS_ENSURE_STATE(properties); nsresult rv; rv = properties->SetPropertyAsUint32(NS_LITERAL_STRING("window"), window); NS_ENSURE_SUCCESS(rv, rv); rv = properties->SetPropertyAsAString(NS_LITERAL_STRING("action"), NS_LITERAL_STRING("popupshowing")); NS_ENSURE_SUCCESS(rv, rv); rv = SetHashedValue(properties, NS_LITERAL_STRING("targetidhash"), targetId); NS_ENSURE_SUCCESS(rv, rv); if (!targetAnonId.IsEmpty()) { rv = SetHashedValue(properties, NS_LITERAL_STRING("targetanonidhash"), targetAnonId); NS_ENSURE_SUCCESS(rv, rv); } nsMetricsService *ms = nsMetricsService::get(); NS_ENSURE_STATE(ms); nsCOMPtr<nsIMetricsEventItem> item; ms->CreateEventItem(NS_LITERAL_STRING("uielement"), getter_AddRefs(item)); NS_ENSURE_STATE(item); item->SetProperties(properties); // Actually log it rv = ms->LogEvent(item); NS_ENSURE_SUCCESS(rv, rv); MS_LOG(("Successfully logged UI popupshowing Event")); return NS_OK; }
nsresult nsProfileCollector::LogMemory(nsIMetricsEventItem *profile) { nsCOMPtr<nsIWritablePropertyBag2> properties; nsMetricsUtils::NewPropertyBag(getter_AddRefs(properties)); NS_ENSURE_STATE(properties); PRUint64 size = PR_GetPhysicalMemorySize(); if (size == 0) { MS_LOG(("Failed to get physical memory size")); return NS_ERROR_FAILURE; } PRUint64 sizeMB = size >> 20; properties->SetPropertyAsUint64(NS_LITERAL_STRING("mb"), sizeMB); MS_LOG(("Logged memory mb=%ull", sizeMB)); nsresult rv = nsMetricsUtils::AddChildItem( profile, NS_LITERAL_STRING("memory"), properties); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; }
void nsUICommandCollector::RemoveEventListeners(nsIDOMEventTarget *window) { for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(kEvents); ++i) { // Using NS_LITERAL_STRING in const data is not allowed, so convert here. // This is not performance-sensitive. nsresult rv; rv = window->RemoveEventListener(NS_ConvertASCIItoUTF16(kEvents[i].event), this, PR_TRUE); if (NS_FAILED(rv)) { MS_LOG(("Couldn't remove event listener %s", kEvents[i])); } } }
nsresult nsProfileCollector::LogCPU(nsIMetricsEventItem *profile) { nsCOMPtr<nsIWritablePropertyBag2> properties; nsMetricsUtils::NewPropertyBag(getter_AddRefs(properties)); NS_ENSURE_STATE(properties); char buf[SYS_INFO_BUFFER_LENGTH]; if (PR_GetSystemInfo(PR_SI_ARCHITECTURE, buf, sizeof(buf)) != PR_SUCCESS) { MS_LOG(("Failed to get architecture")); return NS_ERROR_FAILURE; } properties->SetPropertyAsACString(NS_LITERAL_STRING("arch"), nsDependentCString(buf)); MS_LOG(("Logged CPU arch=%s", buf)); nsresult rv = nsMetricsUtils::AddChildItem( profile, NS_LITERAL_STRING("cpu"), properties); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; }
nsresult nsProfileCollector::LogDisplay(nsIMetricsEventItem *profile) { nsCOMPtr<nsIWritablePropertyBag2> properties; nsMetricsUtils::NewPropertyBag(getter_AddRefs(properties)); NS_ENSURE_STATE(properties); nsCOMPtr<nsIScreenManager> screenManager = do_GetService("@mozilla.org/gfx/screenmanager;1"); NS_ENSURE_STATE(screenManager); nsCOMPtr<nsIScreen> primaryScreen; screenManager->GetPrimaryScreen(getter_AddRefs(primaryScreen)); NS_ENSURE_STATE(primaryScreen); PRInt32 left, top, width, height; nsresult rv = primaryScreen->GetRect(&left, &top, &width, &height); NS_ENSURE_SUCCESS(rv, rv); properties->SetPropertyAsInt32(NS_LITERAL_STRING("xsize"), width); properties->SetPropertyAsInt32(NS_LITERAL_STRING("ysize"), height); MS_LOG(("Logged display xsize=%d ysize=%d", width, height)); PRUint32 numScreens = 0; if (NS_SUCCEEDED(screenManager->GetNumberOfScreens(&numScreens))) { properties->SetPropertyAsUint32(NS_LITERAL_STRING("screens"), numScreens); MS_LOG(("Logged display screens=%d", numScreens)); } else { MS_LOG(("Could not get number of screens")); } rv = nsMetricsUtils::AddChildItem(profile, NS_LITERAL_STRING("display"), properties); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; }
nsresult nsUICommandCollector::GetEventWindow(nsIDOMEvent *event, PRUint32 *window) const { nsCOMPtr<nsIDOMEventTarget> target; event->GetTarget(getter_AddRefs(target)); nsCOMPtr<nsIDOMNode> targetNode = do_QueryInterface(target); if (!targetNode) { MS_LOG(("Warning: couldn't get window id because target is not a node")); return NS_ERROR_FAILURE; } *window = nsMetricsUtils::FindWindowForNode(targetNode); return NS_OK; }
/* static */ PLDHashOperator nsUICommandCollector::RemoveCommandEventListener( const nsIDOMWindow* key, PRUint32 windowID, void* userArg) { nsCOMPtr<nsIDOMEventTarget> windowTarget = do_QueryInterface(const_cast<nsIDOMWindow *>(key)); if (!windowTarget) { MS_LOG(("Error casting domeventtarget")); return PL_DHASH_NEXT; } nsUICommandCollector* collector = static_cast<nsUICommandCollector*> (userArg); collector->RemoveEventListeners(windowTarget); return PL_DHASH_NEXT; }
void nsUICommandCollector::AddEventListeners(nsIDOMEventTarget *window) { for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(kEvents); ++i) { // Attach a capturing event listener to the window. // Use capturing instead of bubbling so that we still record // the event even if propagation is canceled for some reason. // Using NS_LITERAL_STRING in const data is not allowed, so convert here. // This is not performance-sensitive. nsresult rv; rv = window->AddEventListener(NS_ConvertASCIItoUTF16(kEvents[i].event), this, PR_TRUE); if (NS_FAILED(rv)) { MS_LOG(("Couldn't add event listener %s", kEvents[i])); } } }
// nsIDOMEventListener NS_IMETHODIMP nsUICommandCollector::HandleEvent(nsIDOMEvent* event) { // First check that this is an event type that we expect. // If so, call the appropriate handler method. nsString type; nsresult rv = event->GetType(type); NS_ENSURE_SUCCESS(rv, rv); for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(kEvents); ++i) { if (NS_ConvertASCIItoUTF16(kEvents[i].event).Equals(type)) { return (this->*(kEvents[i].handler))(event); } } MS_LOG(("UICommandCollector: Unexpected event type %s received", NS_ConvertUTF16toUTF8(type).get())); return NS_ERROR_UNEXPECTED; }
already_AddRefed<nsIMetricsEventItem> nsProfileCollector::PluginEnumerator::CreatePluginItem(nsIDOMPlugin *plugin) { nsCOMPtr<nsIMetricsEventItem> pluginItem; mMetricsService->CreateEventItem(NS_LITERAL_STRING("plugin"), getter_AddRefs(pluginItem)); NS_ENSURE_TRUE(pluginItem, nsnull); nsCOMPtr<nsIWritablePropertyBag2> properties; nsMetricsUtils::NewPropertyBag(getter_AddRefs(properties)); NS_ENSURE_TRUE(properties, nsnull); nsString name, filename; plugin->GetName(name); plugin->GetFilename(filename); nsCString hashedName, hashedFilename; nsresult rv = mMetricsService->HashUTF16(name, hashedName); NS_ENSURE_SUCCESS(rv, nsnull); rv = mMetricsService->HashUTF16(filename, hashedFilename); NS_ENSURE_SUCCESS(rv, nsnull); properties->SetPropertyAsACString(NS_LITERAL_STRING("name"), hashedName); properties->SetPropertyAsACString(NS_LITERAL_STRING("filename"), hashedFilename); MS_LOG(("Logged plugin name=%s (hashed to %s) filename=%s (hashed to %s)", NS_ConvertUTF16toUTF8(name).get(), hashedName.get(), NS_ConvertUTF16toUTF8(filename).get(), hashedFilename.get())); // TODO(bryner): log the version, if there's a way to find it pluginItem->SetProperties(properties); nsIMetricsEventItem *item = nsnull; pluginItem.swap(item); return item; }
nsresult nsUICommandCollector::GetEventTargets(nsIDOMEvent *event, nsString &targetId, nsString &targetAnonId) const { // This code deals with both anonymous and explicit (non-anonymous) content. // // For explicit content, we just return the id of the event target in // targetId, and leave targetAnonId empty. If there is no id, then // we return failure. // // For anonymous content, we return the id of the event target (after // retargeting), in targetId. We return the anonid of the event's // originalTarget in targetAnonId, so that XBL child elements can be // distinguished. If there is no anonid, then we return failure. // Note that the originalTarget is set after text node retargting, but // before any XBL retargeting. // // We assume that if the originalTarget has no id, we're dealing with // anonymous content (this isn't always true, but it's good enough for what // this code does). nsCOMPtr<nsIDOMNSEvent> nsEvent = do_QueryInterface(event); NS_ENSURE_STATE(nsEvent); nsCOMPtr<nsIDOMEventTarget> originalTarget; nsEvent->GetOriginalTarget(getter_AddRefs(originalTarget)); NS_ENSURE_STATE(originalTarget); nsString origElementId; nsCOMPtr<nsIDOMElement> origElement(do_QueryInterface(originalTarget)); if (origElement) { origElement->GetAttribute(NS_LITERAL_STRING("id"), origElementId); origElement->GetAttribute(NS_LITERAL_STRING("anonid"), targetAnonId); } nsCOMPtr<nsIDOMEventTarget> target; event->GetTarget(getter_AddRefs(target)); NS_ENSURE_STATE(target); nsCOMPtr<nsIDOMElement> targetElement(do_QueryInterface(target)); if (targetElement) { targetElement->GetAttribute(NS_LITERAL_STRING("id"), targetId); } MS_LOG(("Original Target Id: %s, Original Target Anonid: %s, Target Id: %s", NS_ConvertUTF16toUTF8(origElementId).get(), NS_ConvertUTF16toUTF8(targetAnonId).get(), NS_ConvertUTF16toUTF8(targetId).get())); if (targetId.IsEmpty()) { // There's nothing useful to log in this case -- even if we have an anonid, // it's not possible to determine its position in the document. MS_LOG(("Warning: skipping logging because of empty target ID")); return NS_ERROR_FAILURE; } if (origElementId.IsEmpty()) { // We're dealing with anonymous content, so don't continue if we didn't // find an anonid. if (targetAnonId.IsEmpty()) { MS_LOG(("Warning: skipping logging because of empty anonid")); return NS_ERROR_FAILURE; } } else { // We're dealing with normal explicit content, so don't return an anonid. targetAnonId.SetLength(0); } return NS_OK; }
nsresult nsProfileCollector::LogInstall(nsIMetricsEventItem *profile) { nsCOMPtr<nsIWritablePropertyBag2> properties; nsMetricsUtils::NewPropertyBag(getter_AddRefs(properties)); NS_ENSURE_STATE(properties); nsCOMPtr<nsIXULAppInfo> appInfo = do_GetService(XULAPPINFO_SERVICE_CONTRACTID); NS_ENSURE_STATE(appInfo); nsCString buildID; appInfo->GetAppBuildID(buildID); properties->SetPropertyAsACString(NS_LITERAL_STRING("buildid"), buildID); MS_LOG(("Logged install buildid=%s", buildID.get())); nsCOMPtr<nsIExtensionManager> em = do_GetService("@mozilla.org/extensions/manager;1"); NS_ENSURE_STATE(em); nsCOMPtr<nsIUpdateItem> item; nsresult rv = em->GetItemForID(NS_LITERAL_STRING("*****@*****.**"), getter_AddRefs(item)); NS_ENSURE_SUCCESS(rv, rv); // get the metrics extension version nsAutoString extversion; rv = item->GetVersion(extversion); NS_ENSURE_SUCCESS(rv, rv); properties->SetPropertyAsAString(NS_LITERAL_STRING("extversion"), extversion); MS_LOG(("Logged install extversion=%s", NS_ConvertUTF16toUTF8(extversion).get())); // get the application version nsCString appversion; appInfo->GetVersion(appversion); properties->SetPropertyAsACString(NS_LITERAL_STRING("appversion"), appversion); MS_LOG(("Logged install appversion=%s", appversion.get())); // get the application locale nsCOMPtr<nsILocaleService> ls = do_GetService(NS_LOCALESERVICE_CONTRACTID); NS_ENSURE_STATE(ls); nsCOMPtr<nsILocale> locale(nsnull); rv = ls->GetApplicationLocale(getter_AddRefs(locale)); NS_ENSURE_SUCCESS(rv, rv); nsAutoString l; rv = locale->GetCategory(NS_LITERAL_STRING("NSILOCALE_CTYPE"), l); NS_ENSURE_SUCCESS(rv, rv); properties->SetPropertyAsAString(NS_LITERAL_STRING("locale"), l); MS_LOG(("Logged install locale=%s", NS_ConvertUTF16toUTF8(l).get())); // The file defaults/pref/channel-prefs.js is exlucded from any // security update, so we can use its creation time as an indicator // of when this installation was performed. nsCOMPtr<nsIFile> prefsDirectory; NS_GetSpecialDirectory(NS_APP_PREF_DEFAULTS_50_DIR, getter_AddRefs(prefsDirectory)); nsCOMPtr<nsILocalFile> channelPrefs = do_QueryInterface(prefsDirectory); NS_ENSURE_STATE(channelPrefs); rv = channelPrefs->Append(NS_LITERAL_STRING("channel-prefs.js")); NS_ENSURE_SUCCESS(rv, rv); nsCString nativePath; channelPrefs->GetNativePath(nativePath); PRFileInfo64 fileInfo; if (PR_GetFileInfo64(nativePath.get(), &fileInfo) == PR_SUCCESS) { // Convert the time to seconds since the epoch PRInt64 installTime = fileInfo.creationTime / PR_USEC_PER_SEC; static const int kSecondsPerDay = 60 * 60 * 24; // Round down to the nearest full day installTime = ((installTime / kSecondsPerDay) * kSecondsPerDay); properties->SetPropertyAsInt64(NS_LITERAL_STRING("installdate"), installTime); MS_LOG(("Logged install installdate=%lld", installTime)); } // TODO: log default= based on default-browser selection properties->SetPropertyAsBool(NS_LITERAL_STRING("default"), PR_TRUE); rv = nsMetricsUtils::AddChildItem(profile, NS_LITERAL_STRING("install"), properties); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; }
nsresult nsUICommandCollector::HandleCommandEvent(nsIDOMEvent* event) { PRUint32 window; if (NS_FAILED(GetEventWindow(event, &window))) { return NS_OK; } nsString targetId, targetAnonId; if (NS_FAILED(GetEventTargets(event, targetId, targetAnonId))) { return NS_OK; } NS_ASSERTION(!targetId.IsEmpty(), "can't have an empty target id"); nsString keyId; GetEventKeyId(event, keyId); // Fill a property bag with what we want to log nsCOMPtr<nsIWritablePropertyBag2> properties; nsMetricsUtils::NewPropertyBag(getter_AddRefs(properties)); NS_ENSURE_STATE(properties); nsresult rv; rv = properties->SetPropertyAsUint32(NS_LITERAL_STRING("window"), window); NS_ENSURE_SUCCESS(rv, rv); rv = properties->SetPropertyAsAString(NS_LITERAL_STRING("action"), NS_LITERAL_STRING("command")); NS_ENSURE_SUCCESS(rv, rv); rv = SetHashedValue(properties, NS_LITERAL_STRING("targetidhash"), targetId); NS_ENSURE_SUCCESS(rv, rv); if (!targetAnonId.IsEmpty()) { rv = SetHashedValue(properties, NS_LITERAL_STRING("targetanonidhash"), targetAnonId); NS_ENSURE_SUCCESS(rv, rv); } if (!keyId.IsEmpty()) { rv = SetHashedValue(properties, NS_LITERAL_STRING("keyidhash"), keyId); NS_ENSURE_SUCCESS(rv, rv); } nsMetricsService *ms = nsMetricsService::get(); NS_ENSURE_STATE(ms); nsCOMPtr<nsIMetricsEventItem> item; ms->CreateEventItem(NS_LITERAL_STRING("uielement"), getter_AddRefs(item)); NS_ENSURE_STATE(item); item->SetProperties(properties); // Capture extra bookmark state onto the event if the target is a bookmark. rv = LogBookmarkInfo(targetId, item); NS_ENSURE_SUCCESS(rv, rv); // Actually log it rv = ms->LogEvent(item); NS_ENSURE_SUCCESS(rv, rv); MS_LOG(("Successfully logged UI Event")); return NS_OK; }
NS_IMETHODIMP nsLoadCollector::OnStateChange(nsIWebProgress *webProgress, nsIRequest *request, PRUint32 flags, nsresult status) { NS_ASSERTION(flags & STATE_IS_DOCUMENT, "incorrect state change notification"); #ifdef PR_LOGGING if (MS_LOG_ENABLED()) { nsCString name; request->GetName(name); MS_LOG(("LoadCollector: progress = %p, request = %p [%s], flags = %x, status = %x", webProgress, request, name.get(), flags, status)); } #endif nsCOMPtr<nsIChannel> channel = do_QueryInterface(request); if (!channel) { // We don't care about non-channel requests return NS_OK; } nsresult rv; if (flags & STATE_START) { RequestEntry entry; NS_ASSERTION(!mRequestMap.Get(request, &entry), "duplicate STATE_START"); nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(webProgress); nsCOMPtr<nsIDOMWindow> window = do_GetInterface(docShell); if (!window) { // We don't really care about windowless loads return NS_OK; } rv = nsMetricsUtils::NewPropertyBag(getter_AddRefs(entry.properties)); NS_ENSURE_SUCCESS(rv, rv); nsIWritablePropertyBag2 *props = entry.properties; rv = props->SetPropertyAsUint32(NS_LITERAL_STRING("window"), nsMetricsService::GetWindowID(window)); NS_ENSURE_SUCCESS(rv, rv); if (flags & STATE_RESTORING) { rv = props->SetPropertyAsBool(NS_LITERAL_STRING("bfCacheHit"), PR_TRUE); NS_ENSURE_SUCCESS(rv, rv); } nsString origin; PRUint32 loadType; docShell->GetLoadType(&loadType); switch (loadType) { case LOAD_NORMAL: case LOAD_NORMAL_REPLACE: case LOAD_BYPASS_HISTORY: origin = NS_LITERAL_STRING("typed"); break; case LOAD_NORMAL_EXTERNAL: origin = NS_LITERAL_STRING("external"); break; case LOAD_HISTORY: origin = NS_LITERAL_STRING("session-history"); break; case LOAD_RELOAD_NORMAL: case LOAD_RELOAD_BYPASS_CACHE: case LOAD_RELOAD_BYPASS_PROXY: case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE: case LOAD_RELOAD_CHARSET_CHANGE: origin = NS_LITERAL_STRING("reload"); break; case LOAD_LINK: origin = NS_LITERAL_STRING("link"); break; case LOAD_REFRESH: origin = NS_LITERAL_STRING("refresh"); break; default: break; } if (!origin.IsEmpty()) { rv = props->SetPropertyAsAString(NS_LITERAL_STRING("origin"), origin); NS_ENSURE_SUCCESS(rv, rv); } entry.startTime = PR_Now(); NS_ENSURE_TRUE(mRequestMap.Put(request, entry), NS_ERROR_OUT_OF_MEMORY); } else if (flags & STATE_STOP) { RequestEntry entry; if (mRequestMap.Get(request, &entry)) { mRequestMap.Remove(request); // Log a <document action="load"> event nsIWritablePropertyBag2 *props = entry.properties; rv = props->SetPropertyAsACString(NS_LITERAL_STRING("action"), NS_LITERAL_CSTRING("load")); NS_ENSURE_SUCCESS(rv, rv); // Compute the load time now that we have the end time. PRInt64 loadTime = (PR_Now() - entry.startTime) / PR_USEC_PER_MSEC; rv = props->SetPropertyAsUint64(NS_LITERAL_STRING("loadtime"), loadTime); NS_ENSURE_SUCCESS(rv, rv); MemUsage mu; if (GetMemUsage(&mu)) { rv = props->SetPropertyAsUint64(NS_LITERAL_STRING("memtotal"), mu.total); NS_ENSURE_SUCCESS(rv, rv); rv = props->SetPropertyAsUint64(NS_LITERAL_STRING("memresident"), mu.resident); NS_ENSURE_SUCCESS(rv, rv); } // Look up the document id, or assign a new one nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(webProgress); nsCOMPtr<nsIDOMWindow> window = do_GetInterface(docShell); if (!window) { MS_LOG(("Couldn't get window")); return NS_ERROR_UNEXPECTED; } nsCOMPtr<nsIDOMDocument> domDoc; window->GetDocument(getter_AddRefs(domDoc)); nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc); if (!doc) { MS_LOG(("Couldn't get document")); return NS_ERROR_UNEXPECTED; } nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(docShell); NS_ENSURE_STATE(item); PRBool subframe = nsMetricsUtils::IsSubframe(item); if (subframe) { rv = props->SetPropertyAsBool(NS_LITERAL_STRING("subframe"), PR_TRUE); NS_ENSURE_SUCCESS(rv, rv); } nsMetricsService *ms = nsMetricsService::get(); DocumentEntry docEntry; if (!mDocumentMap.Get(doc, &docEntry)) { docEntry.docID = mNextDocID++; docEntry.subframe = subframe; if (!ms->WindowMap().Get(window, &docEntry.windowID)) { MS_LOG(("Window not in the window map")); return NS_ERROR_UNEXPECTED; } NS_ENSURE_TRUE(mDocumentMap.Put(doc, docEntry), NS_ERROR_OUT_OF_MEMORY); } doc->AddObserver(this); // set up to log the document destroy rv = props->SetPropertyAsUint32(NS_LITERAL_STRING("docid"), docEntry.docID); NS_ENSURE_SUCCESS(rv, rv); // If this was a load of a chrome document, hash the URL of the document // so it can be identified. nsCOMPtr<nsIChannel> channel = do_QueryInterface(request); if (channel) { nsCOMPtr<nsIURI> uri; channel->GetURI(getter_AddRefs(uri)); if (uri) { PRBool isChrome = PR_FALSE; uri->SchemeIs("chrome", &isChrome); if (isChrome) { nsCString spec; uri->GetSpec(spec); nsCString hashedSpec; rv = ms->HashUTF8(spec, hashedSpec); NS_ENSURE_SUCCESS(rv, rv); rv = props->SetPropertyAsACString(NS_LITERAL_STRING("urlhash"), hashedSpec); NS_ENSURE_SUCCESS(rv, rv); } } } rv = ms->LogEvent(NS_LITERAL_STRING("document"), props); NS_ENSURE_SUCCESS(rv, rv); } else { NS_WARNING("STATE_STOP without STATE_START"); } } return NS_OK; }