Back to index

lightning-sunbird  0.9+nobinonly
nsWindowCollector.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* vim:set ts=2 sw=2 sts=2 et cindent: */
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is the Metrics extension.
00017  *
00018  * The Initial Developer of the Original Code is Google Inc.
00019  * Portions created by the Initial Developer are Copyright (C) 2006
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *  Brian Ryner <bryner@brianryner.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsWindowCollector.h"
00040 #include "nsMetricsService.h"
00041 #include "nsIObserverService.h"
00042 #include "nsIServiceManager.h"
00043 #include "nsPIDOMWindow.h"
00044 #include "nsIDocShell.h"
00045 #include "nsIDocShellTreeItem.h"
00046 #include "nsIInterfaceRequestorUtils.h"
00047 #include "nsServiceManagerUtils.h"
00048 #include "nsDocShellCID.h"
00049 #include "nsAutoPtr.h"
00050 #include "nsITimer.h"
00051 #include "nsComponentManagerUtils.h"
00052 
00053 nsWindowCollector::nsWindowCollector()
00054 {
00055 }
00056 
00057 nsWindowCollector::~nsWindowCollector()
00058 {
00059 }
00060 
00061 NS_IMPL_ISUPPORTS2(nsWindowCollector, nsIMetricsCollector, nsIObserver)
00062 
00063 NS_IMETHODIMP
00064 nsWindowCollector::OnAttach()
00065 {
00066   nsCOMPtr<nsIObserverService> obsSvc =
00067     do_GetService("@mozilla.org/observer-service;1");
00068   NS_ENSURE_STATE(obsSvc);
00069 
00070   nsresult rv = obsSvc->AddObserver(this, NS_WEBNAVIGATION_CREATE, PR_FALSE);
00071   NS_ENSURE_SUCCESS(rv, rv);
00072   rv = obsSvc->AddObserver(this, NS_CHROME_WEBNAVIGATION_CREATE, PR_FALSE);
00073   NS_ENSURE_SUCCESS(rv, rv);
00074   rv = obsSvc->AddObserver(this, "domwindowopened", PR_FALSE);
00075   NS_ENSURE_SUCCESS(rv, rv);
00076   rv = obsSvc->AddObserver(this, "domwindowclosed", PR_FALSE);
00077   NS_ENSURE_SUCCESS(rv, rv);
00078   rv = obsSvc->AddObserver(this, NS_METRICS_WEBNAVIGATION_DESTROY, PR_FALSE);
00079   NS_ENSURE_SUCCESS(rv, rv);
00080   rv = obsSvc->AddObserver(this,
00081                            NS_METRICS_CHROME_WEBNAVIGATION_DESTROY, PR_FALSE);
00082   NS_ENSURE_SUCCESS(rv, rv);
00083 
00084   return NS_OK;
00085 }
00086 
00087 NS_IMETHODIMP
00088 nsWindowCollector::OnDetach()
00089 {
00090   nsCOMPtr<nsIObserverService> obsSvc =
00091     do_GetService("@mozilla.org/observer-service;1");
00092   NS_ENSURE_STATE(obsSvc);
00093 
00094   nsresult rv = obsSvc->RemoveObserver(this, NS_WEBNAVIGATION_CREATE);
00095   NS_ENSURE_SUCCESS(rv, rv);
00096   rv = obsSvc->RemoveObserver(this, NS_CHROME_WEBNAVIGATION_CREATE);
00097   NS_ENSURE_SUCCESS(rv, rv);
00098   rv = obsSvc->RemoveObserver(this, "domwindowopened");
00099   NS_ENSURE_SUCCESS(rv, rv);
00100   rv = obsSvc->RemoveObserver(this, "domwindowclosed");
00101   NS_ENSURE_SUCCESS(rv, rv);
00102   rv = obsSvc->RemoveObserver(this, NS_METRICS_WEBNAVIGATION_DESTROY);
00103   NS_ENSURE_SUCCESS(rv, rv);
00104   rv = obsSvc->RemoveObserver(this, NS_METRICS_CHROME_WEBNAVIGATION_DESTROY);
00105   NS_ENSURE_SUCCESS(rv, rv);
00106 
00107   return NS_OK;
00108 }
00109 
00110 NS_IMETHODIMP
00111 nsWindowCollector::OnNewLog()
00112 {
00113   return NS_OK;
00114 }
00115 
00116 struct WindowOpenClosure
00117 {
00118   WindowOpenClosure(nsISupports *subj, nsWindowCollector *coll)
00119       : subject(subj), collector(coll) { }
00120 
00121   nsCOMPtr<nsISupports> subject;
00122   nsRefPtr<nsWindowCollector> collector;
00123 };
00124 
00125 /* static */ void
00126 nsWindowCollector::WindowOpenCallback(nsITimer *timer, void *closure)
00127 {
00128   WindowOpenClosure *wc = NS_STATIC_CAST(WindowOpenClosure *, closure);
00129   wc->collector->LogWindowOpen(timer, wc->subject);
00130 
00131   delete wc;
00132 }
00133 
00134 void
00135 nsWindowCollector::LogWindowOpen(nsITimer *timer, nsISupports *subject)
00136 {
00137   mWindowOpenTimers.RemoveElement(timer);
00138   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(subject);
00139 
00140   if (!window) {
00141     return;
00142   }
00143 
00144   nsCOMPtr<nsIDOMWindowInternal> opener;
00145   window->GetOpener(getter_AddRefs(opener));
00146 
00147   nsCOMPtr<nsIWritablePropertyBag2> properties;
00148   nsMetricsUtils::NewPropertyBag(getter_AddRefs(properties));
00149   if (!properties) {
00150     return;
00151   }
00152 
00153   if (opener) {
00154     properties->SetPropertyAsUint32(NS_LITERAL_STRING("opener"),
00155                                     nsMetricsService::GetWindowID(opener));
00156   }
00157 
00158   properties->SetPropertyAsUint32(NS_LITERAL_STRING("windowid"),
00159                                   nsMetricsService::GetWindowID(window));
00160 
00161   properties->SetPropertyAsACString(NS_LITERAL_STRING("action"),
00162                                     NS_LITERAL_CSTRING("open"));
00163 
00164   nsMetricsService *ms = nsMetricsService::get();
00165   if (ms) {
00166     ms->LogEvent(NS_LITERAL_STRING("window"), properties);
00167   }
00168 }
00169 
00170 NS_IMETHODIMP
00171 nsWindowCollector::Observe(nsISupports *subject,
00172                            const char *topic,
00173                            const PRUnichar *data)
00174 {
00175   nsCOMPtr<nsIWritablePropertyBag2> properties;
00176   nsresult rv = nsMetricsUtils::NewPropertyBag(getter_AddRefs(properties));
00177   NS_ENSURE_SUCCESS(rv, rv);
00178 
00179   nsCOMPtr<nsPIDOMWindow> window;
00180   nsCString action;
00181 
00182   if (strcmp(topic, NS_WEBNAVIGATION_CREATE) == 0 ||
00183       strcmp(topic, NS_CHROME_WEBNAVIGATION_CREATE) == 0) {
00184     // Log a window creation event.
00185     action.Assign("create");
00186 
00187     nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(subject);
00188     NS_ENSURE_STATE(item);
00189 
00190     window = do_GetInterface(subject);
00191     NS_ENSURE_STATE(window);
00192 
00193     // We want the window's real parent, even if it crosses a chrome/content
00194     // boundary.  This requires going up the docshell tree.
00195     nsCOMPtr<nsIDocShellTreeItem> parentItem;
00196     item->GetParent(getter_AddRefs(parentItem));
00197     nsCOMPtr<nsPIDOMWindow> parentWindow = do_GetInterface(parentItem);
00198     if (parentWindow) {
00199       PRUint32 id = nsMetricsService::GetWindowID(parentWindow);
00200       rv = properties->SetPropertyAsUint32(NS_LITERAL_STRING("parent"), id);
00201       NS_ENSURE_SUCCESS(rv, rv);
00202     }
00203 
00204     if (strcmp(topic, NS_CHROME_WEBNAVIGATION_CREATE) == 0) {
00205       rv = properties->SetPropertyAsBool(NS_LITERAL_STRING("chrome"), PR_TRUE);
00206       NS_ENSURE_SUCCESS(rv, rv);
00207     }
00208     if (nsMetricsUtils::IsSubframe(item)) {
00209       rv = properties->SetPropertyAsBool(NS_LITERAL_STRING("subframe"),
00210                                          PR_TRUE);
00211       NS_ENSURE_SUCCESS(rv, rv);
00212     }
00213   } else if (strcmp(topic, "domwindowopened") == 0) {
00214     // We'd like to log a window open event now, but the window opener
00215     // has not yet been set when we receive the domwindowopened notification.
00216 
00217     nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
00218     NS_ENSURE_STATE(timer);
00219 
00220     WindowOpenClosure *wc = new WindowOpenClosure(subject, this);
00221     NS_ENSURE_TRUE(wc, NS_ERROR_OUT_OF_MEMORY);
00222 
00223     rv = timer->InitWithFuncCallback(nsWindowCollector::WindowOpenCallback,
00224                                      wc, 0, nsITimer::TYPE_ONE_SHOT);
00225     NS_ENSURE_SUCCESS(rv, rv);
00226 
00227     mWindowOpenTimers.AppendElement(timer);
00228   } else if (strcmp(topic, "domwindowclosed") == 0) {
00229     // Log a window close event.
00230     action.Assign("close");
00231     window = do_QueryInterface(subject);
00232   } else if (strcmp(topic, NS_METRICS_WEBNAVIGATION_DESTROY) == 0 ||
00233              strcmp(topic, NS_METRICS_CHROME_WEBNAVIGATION_DESTROY) == 0) {
00234     // Log a window destroy event.
00235     action.Assign("destroy");
00236     window = do_GetInterface(subject);
00237 
00238     nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(subject);
00239     NS_ENSURE_STATE(item);
00240     if (nsMetricsUtils::IsSubframe(item)) {
00241       rv = properties->SetPropertyAsBool(NS_LITERAL_STRING("subframe"),
00242                                          PR_TRUE);
00243       NS_ENSURE_SUCCESS(rv, rv);
00244     }
00245   }
00246 
00247   if (window) {
00248     rv = properties->SetPropertyAsUint32(NS_LITERAL_STRING("windowid"),
00249                                          nsMetricsService::GetWindowID(window));
00250     NS_ENSURE_SUCCESS(rv, rv);
00251 
00252     rv = properties->SetPropertyAsACString(NS_LITERAL_STRING("action"),
00253                                            action);
00254     NS_ENSURE_SUCCESS(rv, rv);
00255 
00256     nsMetricsService *ms = nsMetricsService::get();
00257     NS_ENSURE_STATE(ms);
00258     rv = ms->LogEvent(NS_LITERAL_STRING("window"), properties);
00259   }
00260 
00261   return rv;
00262 }