Bug 587288: 0. Compartmentalize regexp allocator, remove ExecutablePool atomic refcou...
[mozilla-central.git] / dom / ipc / ContentChild.cpp
blob3714510363bc67439db725caa9e4df595d5a0e4a
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim: set sw=4 ts=8 et tw=80 : */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is Mozilla Content App.
18 * The Initial Developer of the Original Code is
19 * The Mozilla Foundation.
20 * Portions created by the Initial Developer are Copyright (C) 2009
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Frederic Plourde <frederic.plourde@collabora.co.uk>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #ifdef MOZ_WIDGET_GTK2
41 #include <gtk/gtk.h>
42 #endif
44 #ifdef MOZ_WIDGET_QT
45 #include "nsQAppInstance.h"
46 #endif
48 #include "ContentChild.h"
49 #include "CrashReporterChild.h"
50 #include "TabChild.h"
51 #include "AudioChild.h"
53 #include "mozilla/ipc/TestShellChild.h"
54 #include "mozilla/net/NeckoChild.h"
55 #include "mozilla/ipc/XPCShellEnvironment.h"
56 #include "mozilla/jsipc/PContextWrapperChild.h"
57 #include "mozilla/dom/ExternalHelperAppChild.h"
58 #include "mozilla/dom/StorageChild.h"
59 #include "mozilla/dom/PCrashReporterChild.h"
61 #include "nsAudioStream.h"
63 #include "nsIObserverService.h"
64 #include "nsTObserverArray.h"
65 #include "nsIObserver.h"
66 #include "nsIPrefService.h"
67 #include "nsServiceManagerUtils.h"
68 #include "nsXULAppAPI.h"
69 #include "nsWeakReference.h"
70 #include "nsIScriptError.h"
71 #include "nsIConsoleService.h"
73 #include "History.h"
74 #include "nsDocShellCID.h"
75 #include "nsNetUtil.h"
77 #include "base/message_loop.h"
78 #include "base/task.h"
80 #include "nsChromeRegistryContent.h"
81 #include "mozilla/chrome/RegistryMessageUtils.h"
82 #include "nsFrameMessageManager.h"
84 #include "nsIGeolocationProvider.h"
86 #ifdef MOZ_PERMISSIONS
87 #include "nsPermission.h"
88 #include "nsPermissionManager.h"
89 #endif
91 #if defined(ANDROID) || defined(LINUX)
92 #include <sys/time.h>
93 #include <sys/resource.h>
94 // TODO: For other platforms that support setpriority, figure out
95 // appropriate values of niceness
96 static const int kRelativeNiceness = 10;
97 #endif
99 #include "nsAccelerometer.h"
101 #if defined(ANDROID)
102 #include "APKOpen.h"
103 #endif
105 using namespace mozilla::ipc;
106 using namespace mozilla::net;
107 using namespace mozilla::places;
108 using namespace mozilla::docshell;
110 namespace mozilla {
111 namespace dom {
112 class AlertObserver
114 public:
116 AlertObserver(nsIObserver *aObserver, const nsString& aData)
117 : mObserver(aObserver)
118 , mData(aData)
122 ~AlertObserver() {}
124 bool ShouldRemoveFrom(nsIObserver* aObserver,
125 const nsString& aData) const
127 return (mObserver == aObserver &&
128 mData == aData);
131 bool Observes(const nsString& aData) const
133 return mData.Equals(aData);
136 bool Notify(const nsCString& aType) const
138 mObserver->Observe(nsnull, aType.get(), mData.get());
139 return true;
142 private:
143 nsCOMPtr<nsIObserver> mObserver;
144 nsString mData;
147 class ConsoleListener : public nsIConsoleListener
149 public:
150 ConsoleListener(ContentChild* aChild)
151 : mChild(aChild) {}
153 NS_DECL_ISUPPORTS
154 NS_DECL_NSICONSOLELISTENER
156 private:
157 ContentChild* mChild;
158 friend class ContentChild;
161 NS_IMPL_ISUPPORTS1(ConsoleListener, nsIConsoleListener)
163 NS_IMETHODIMP
164 ConsoleListener::Observe(nsIConsoleMessage* aMessage)
166 if (!mChild)
167 return NS_OK;
169 nsCOMPtr<nsIScriptError> scriptError = do_QueryInterface(aMessage);
170 if (scriptError) {
171 nsString msg, sourceName, sourceLine;
172 nsXPIDLCString category;
173 PRUint32 lineNum, colNum, flags;
175 nsresult rv = scriptError->GetErrorMessage(msg);
176 NS_ENSURE_SUCCESS(rv, rv);
177 rv = scriptError->GetSourceName(sourceName);
178 NS_ENSURE_SUCCESS(rv, rv);
179 rv = scriptError->GetSourceLine(sourceLine);
180 NS_ENSURE_SUCCESS(rv, rv);
181 rv = scriptError->GetCategory(getter_Copies(category));
182 NS_ENSURE_SUCCESS(rv, rv);
183 rv = scriptError->GetLineNumber(&lineNum);
184 NS_ENSURE_SUCCESS(rv, rv);
185 rv = scriptError->GetColumnNumber(&colNum);
186 NS_ENSURE_SUCCESS(rv, rv);
187 rv = scriptError->GetFlags(&flags);
188 NS_ENSURE_SUCCESS(rv, rv);
189 mChild->SendScriptError(msg, sourceName, sourceLine,
190 lineNum, colNum, flags, category);
191 return NS_OK;
194 nsXPIDLString msg;
195 nsresult rv = aMessage->GetMessageMoz(getter_Copies(msg));
196 NS_ENSURE_SUCCESS(rv, rv);
197 mChild->SendConsoleMessage(msg);
198 return NS_OK;
201 ContentChild* ContentChild::sSingleton;
203 ContentChild::ContentChild()
204 #ifdef ANDROID
205 : mScreenSize(0, 0)
206 #endif
210 ContentChild::~ContentChild()
214 bool
215 ContentChild::Init(MessageLoop* aIOLoop,
216 base::ProcessHandle aParentHandle,
217 IPC::Channel* aChannel)
219 #ifdef MOZ_WIDGET_GTK2
220 // sigh
221 gtk_init(NULL, NULL);
222 #endif
224 #ifdef MOZ_WIDGET_QT
225 // sigh, seriously
226 nsQAppInstance::AddRef();
227 #endif
229 #ifdef MOZ_X11
230 // Do this after initializing GDK, or GDK will install its own handler.
231 XRE_InstallX11ErrorHandler();
232 #endif
234 NS_ASSERTION(!sSingleton, "only one ContentChild per child");
236 #if defined(ANDROID) || defined(LINUX)
237 // XXX We change the behavior of Linux child processes here. That
238 // means that, not just in Fennec, but also in Firefox, once it has
239 // child processes, those will be niced. IOW, Firefox with child processes
240 // will have different performance profiles on Linux than other
241 // platforms. This may alter Talos results and so forth.
242 char* relativeNicenessStr = getenv("MOZ_CHILD_PROCESS_RELATIVE_NICENESS");
243 setpriority(PRIO_PROCESS, 0, getpriority(PRIO_PROCESS, 0) +
244 (relativeNicenessStr ? atoi(relativeNicenessStr) :
245 kRelativeNiceness));
246 #endif
248 Open(aChannel, aParentHandle, aIOLoop);
249 sSingleton = this;
251 #if defined(ANDROID)
252 PCrashReporterChild* crashreporter = SendPCrashReporterConstructor();
253 InfallibleTArray<Mapping> mappings;
254 const struct mapping_info *info = getLibraryMapping();
255 while (info->name) {
256 mappings.AppendElement(Mapping(nsDependentCString(info->name),
257 nsDependentCString(info->file_id),
258 info->base,
259 info->len,
260 info->offset));
261 info++;
263 crashreporter->SendAddLibraryMappings(mappings);
264 #endif
266 return true;
269 void
270 ContentChild::InitXPCOM()
272 nsCOMPtr<nsIConsoleService> svc(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
273 if (!svc) {
274 NS_WARNING("Couldn't acquire console service");
275 return;
278 mConsoleListener = new ConsoleListener(this);
279 if (NS_FAILED(svc->RegisterListener(mConsoleListener)))
280 NS_WARNING("Couldn't register console listener for child process");
283 PBrowserChild*
284 ContentChild::AllocPBrowser(const PRUint32& aChromeFlags)
286 nsRefPtr<TabChild> iframe = new TabChild(aChromeFlags);
287 return NS_SUCCEEDED(iframe->Init()) ? iframe.forget().get() : NULL;
290 bool
291 ContentChild::DeallocPBrowser(PBrowserChild* iframe)
293 TabChild* child = static_cast<TabChild*>(iframe);
294 NS_RELEASE(child);
295 return true;
298 PCrashReporterChild*
299 ContentChild::AllocPCrashReporter()
301 return new CrashReporterChild();
304 bool
305 ContentChild::DeallocPCrashReporter(PCrashReporterChild* crashreporter)
307 delete crashreporter;
308 return true;
311 PTestShellChild*
312 ContentChild::AllocPTestShell()
314 return new TestShellChild();
317 bool
318 ContentChild::DeallocPTestShell(PTestShellChild* shell)
320 delete shell;
321 return true;
324 bool
325 ContentChild::RecvPTestShellConstructor(PTestShellChild* actor)
327 actor->SendPContextWrapperConstructor()->SendPObjectWrapperConstructor(true);
328 return true;
331 PAudioChild*
332 ContentChild::AllocPAudio(const PRInt32& numChannels,
333 const PRInt32& rate,
334 const PRInt32& format)
336 AudioChild *child = new AudioChild();
337 NS_ADDREF(child);
338 return child;
341 bool
342 ContentChild::DeallocPAudio(PAudioChild* doomed)
344 AudioChild *child = static_cast<AudioChild*>(doomed);
345 NS_RELEASE(child);
346 return true;
349 PNeckoChild*
350 ContentChild::AllocPNecko()
352 return new NeckoChild();
355 bool
356 ContentChild::DeallocPNecko(PNeckoChild* necko)
358 delete necko;
359 return true;
362 PExternalHelperAppChild*
363 ContentChild::AllocPExternalHelperApp(const IPC::URI& uri,
364 const nsCString& aMimeContentType,
365 const nsCString& aContentDisposition,
366 const bool& aForceSave,
367 const PRInt64& aContentLength,
368 const IPC::URI& aReferrer)
370 ExternalHelperAppChild *child = new ExternalHelperAppChild();
371 child->AddRef();
372 return child;
375 bool
376 ContentChild::DeallocPExternalHelperApp(PExternalHelperAppChild* aService)
378 ExternalHelperAppChild *child = static_cast<ExternalHelperAppChild*>(aService);
379 child->Release();
380 return true;
383 PStorageChild*
384 ContentChild::AllocPStorage(const StorageConstructData& aData)
386 NS_NOTREACHED("We should never be manually allocating PStorageChild actors");
387 return nsnull;
390 bool
391 ContentChild::DeallocPStorage(PStorageChild* aActor)
393 StorageChild* child = static_cast<StorageChild*>(aActor);
394 child->ReleaseIPDLReference();
395 return true;
398 bool
399 ContentChild::RecvRegisterChrome(const InfallibleTArray<ChromePackage>& packages,
400 const InfallibleTArray<ResourceMapping>& resources,
401 const InfallibleTArray<OverrideMapping>& overrides)
403 nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
404 nsChromeRegistryContent* chromeRegistry =
405 static_cast<nsChromeRegistryContent*>(registrySvc.get());
406 chromeRegistry->RegisterRemoteChrome(packages, resources, overrides);
407 return true;
410 bool
411 ContentChild::RecvSetOffline(const PRBool& offline)
413 nsCOMPtr<nsIIOService> io (do_GetIOService());
414 NS_ASSERTION(io, "IO Service can not be null");
416 io->SetOffline(offline);
418 return true;
421 void
422 ContentChild::ActorDestroy(ActorDestroyReason why)
424 if (AbnormalShutdown == why) {
425 NS_WARNING("shutting down early because of crash!");
426 QuickExit();
429 #ifndef DEBUG
430 // In release builds, there's no point in the content process
431 // going through the full XPCOM shutdown path, because it doesn't
432 // keep persistent state.
433 QuickExit();
434 #endif
436 mAlertObservers.Clear();
438 nsCOMPtr<nsIConsoleService> svc(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
439 if (svc) {
440 svc->UnregisterListener(mConsoleListener);
441 mConsoleListener->mChild = nsnull;
444 XRE_ShutdownChildProcess();
447 void
448 ContentChild::ProcessingError(Result what)
450 switch (what) {
451 case MsgDropped:
452 QuickExit();
454 case MsgNotKnown:
455 case MsgNotAllowed:
456 case MsgPayloadError:
457 case MsgProcessingError:
458 case MsgRouteError:
459 case MsgValueError:
460 NS_RUNTIMEABORT("aborting because of fatal error");
462 default:
463 NS_RUNTIMEABORT("not reached");
467 void
468 ContentChild::QuickExit()
470 NS_WARNING("content process _exit()ing");
471 _exit(0);
474 nsresult
475 ContentChild::AddRemoteAlertObserver(const nsString& aData,
476 nsIObserver* aObserver)
478 NS_ASSERTION(aObserver, "Adding a null observer?");
479 mAlertObservers.AppendElement(new AlertObserver(aObserver, aData));
480 return NS_OK;
483 bool
484 ContentChild::RecvPreferenceUpdate(const PrefTuple& aPref)
486 nsCOMPtr<nsIPrefServiceInternal> prefs = do_GetService("@mozilla.org/preferences-service;1");
487 if (!prefs)
488 return false;
490 prefs->SetPreference(&aPref);
492 return true;
495 bool
496 ContentChild::RecvNotifyAlertsObserver(const nsCString& aType, const nsString& aData)
498 for (PRUint32 i = 0; i < mAlertObservers.Length();
499 /*we mutate the array during the loop; ++i iff no mutation*/) {
500 AlertObserver* observer = mAlertObservers[i];
501 if (observer->Observes(aData) && observer->Notify(aType)) {
502 // if aType == alertfinished, this alert is done. we can
503 // remove the observer.
504 if (aType.Equals(nsDependentCString("alertfinished"))) {
505 mAlertObservers.RemoveElementAt(i);
506 continue;
509 ++i;
511 return true;
514 bool
515 ContentChild::RecvNotifyVisited(const IPC::URI& aURI)
517 nsCOMPtr<nsIURI> newURI(aURI);
518 History::GetService()->NotifyVisited(newURI);
519 return true;
523 bool
524 ContentChild::RecvAsyncMessage(const nsString& aMsg, const nsString& aJSON)
526 nsRefPtr<nsFrameMessageManager> cpm = nsFrameMessageManager::sChildProcessManager;
527 if (cpm) {
528 cpm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(cpm.get()),
529 aMsg, PR_FALSE, aJSON, nsnull, nsnull);
531 return true;
534 bool
535 ContentChild::RecvGeolocationUpdate(const GeoPosition& somewhere)
537 nsCOMPtr<nsIGeolocationUpdate> gs = do_GetService("@mozilla.org/geolocation/service;1");
538 if (!gs) {
539 return true;
541 nsCOMPtr<nsIDOMGeoPosition> position = somewhere;
542 gs->Update(position);
543 return true;
546 bool
547 ContentChild::RecvAddPermission(const IPC::Permission& permission)
549 #if MOZ_PERMISSIONS
550 nsRefPtr<nsPermissionManager> permissionManager =
551 nsPermissionManager::GetSingleton();
552 NS_ABORT_IF_FALSE(permissionManager,
553 "We have no permissionManager in the Content process !");
555 permissionManager->AddInternal(nsCString(permission.host),
556 nsCString(permission.type),
557 permission.capability,
559 permission.expireType,
560 permission.expireTime,
561 nsPermissionManager::eNotify,
562 nsPermissionManager::eNoDBOperation);
563 #endif
565 return true;
567 bool
568 ContentChild::RecvAccelerationChanged(const double& x, const double& y,
569 const double& z)
571 nsCOMPtr<nsIAccelerometerUpdate> acu =
572 do_GetService(NS_ACCELEROMETER_CONTRACTID);
573 if (acu)
574 acu->AccelerationChanged(x, y, z);
575 return true;
578 bool
579 ContentChild::RecvScreenSizeChanged(const gfxIntSize& size)
581 #ifdef ANDROID
582 mScreenSize = size;
583 #else
584 NS_RUNTIMEABORT("Message currently only expected on android");
585 #endif
586 return true;
589 bool
590 ContentChild::RecvFlushMemory(const nsString& reason)
592 nsCOMPtr<nsIObserverService> os =
593 mozilla::services::GetObserverService();
594 if (os)
595 os->NotifyObservers(nsnull, "memory-pressure", reason.get());
596 return true;
599 } // namespace dom
600 } // namespace mozilla