Arena pool macros don't want to die.
[mozilla-central.git] / dom / ipc / ContentProcessParent.cpp
blob5f293aae2715047b7b9e8f11fbb413cb5330ddcc
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 #include "ContentProcessParent.h"
42 #include "TabParent.h"
43 #include "mozilla/ipc/TestShellParent.h"
44 #include "mozilla/net/NeckoParent.h"
45 #include "nsIPrefBranch.h"
46 #include "nsIPrefBranch2.h"
47 #include "nsIPrefLocalizedString.h"
48 #include "nsIObserverService.h"
50 #include "nsAutoPtr.h"
51 #include "nsCOMPtr.h"
52 #include "nsServiceManagerUtils.h"
53 #include "nsThreadUtils.h"
54 #include "nsChromeRegistryChrome.h"
56 using namespace mozilla::ipc;
57 using namespace mozilla::net;
58 using mozilla::MonitorAutoEnter;
60 namespace mozilla {
61 namespace dom {
63 #define NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC "ipc:network:set-offline"
65 ContentProcessParent* ContentProcessParent::gSingleton;
67 ContentProcessParent*
68 ContentProcessParent::GetSingleton(PRBool aForceNew)
70 if (gSingleton && !gSingleton->IsAlive())
71 gSingleton = nsnull;
73 if (!gSingleton && aForceNew) {
74 nsRefPtr<ContentProcessParent> parent = new ContentProcessParent();
75 if (parent) {
76 nsCOMPtr<nsIObserverService> obs =
77 do_GetService("@mozilla.org/observer-service;1");
78 if (obs) {
79 if (NS_SUCCEEDED(obs->AddObserver(parent, "xpcom-shutdown",
80 PR_FALSE))) {
81 gSingleton = parent;
82 nsCOMPtr<nsIPrefBranch2> prefs
83 (do_GetService(NS_PREFSERVICE_CONTRACTID));
84 if (prefs) {
85 prefs->AddObserver("", parent, PR_FALSE);
88 obs->AddObserver(
89 parent, NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC, PR_FALSE);
91 nsCOMPtr<nsIThreadInternal>
92 threadInt(do_QueryInterface(NS_GetCurrentThread()));
93 if (threadInt) {
94 threadInt->GetObserver(getter_AddRefs(parent->mOldObserver));
95 threadInt->SetObserver(parent);
99 return gSingleton;
102 void
103 ContentProcessParent::ActorDestroy(ActorDestroyReason why)
105 nsCOMPtr<nsIThreadObserver>
106 kungFuDeathGrip(static_cast<nsIThreadObserver*>(this));
107 nsCOMPtr<nsIObserverService>
108 obs(do_GetService("@mozilla.org/observer-service;1"));
109 if (obs)
110 obs->RemoveObserver(static_cast<nsIObserver*>(this), "xpcom-shutdown");
111 nsCOMPtr<nsIThreadInternal>
112 threadInt(do_QueryInterface(NS_GetCurrentThread()));
113 if (threadInt)
114 threadInt->SetObserver(mOldObserver);
115 if (mRunToCompletionDepth)
116 mRunToCompletionDepth = 0;
118 mIsAlive = false;
121 TabParent*
122 ContentProcessParent::CreateTab()
124 return static_cast<TabParent*>(SendPIFrameEmbeddingConstructor());
127 TestShellParent*
128 ContentProcessParent::CreateTestShell()
130 return static_cast<TestShellParent*>(SendPTestShellConstructor());
133 bool
134 ContentProcessParent::DestroyTestShell(TestShellParent* aTestShell)
136 return PTestShellParent::Send__delete__(aTestShell);
139 ContentProcessParent::ContentProcessParent()
140 : mMonitor("ContentProcessParent::mMonitor")
141 , mRunToCompletionDepth(0)
142 , mShouldCallUnblockChild(false)
143 , mIsAlive(true)
145 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
146 mSubprocess = new GeckoChildProcessHost(GeckoProcessType_Content);
147 mSubprocess->AsyncLaunch();
148 Open(mSubprocess->GetChannel(), mSubprocess->GetChildProcessHandle());
150 nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
151 nsChromeRegistryChrome* chromeRegistry =
152 static_cast<nsChromeRegistryChrome*>(registrySvc.get());
153 chromeRegistry->SendRegisteredChrome(this);
156 ContentProcessParent::~ContentProcessParent()
158 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
159 //If the previous content process has died, a new one could have
160 //been started since.
161 if (gSingleton == this)
162 gSingleton = nsnull;
165 bool
166 ContentProcessParent::IsAlive()
168 return mIsAlive;
171 bool
172 ContentProcessParent::RecvGetPrefType(const nsCString& prefName,
173 PRInt32* retValue, nsresult* rv)
175 *retValue = 0;
177 EnsurePrefService();
178 *rv = mPrefService->GetPrefType(prefName.get(), retValue);
179 return true;
182 bool
183 ContentProcessParent::RecvGetBoolPref(const nsCString& prefName,
184 PRBool* retValue, nsresult* rv)
186 *retValue = PR_FALSE;
188 EnsurePrefService();
189 *rv = mPrefService->GetBoolPref(prefName.get(), retValue);
190 return true;
193 bool
194 ContentProcessParent::RecvGetIntPref(const nsCString& prefName,
195 PRInt32* retValue, nsresult* rv)
197 *retValue = 0;
199 EnsurePrefService();
200 *rv = mPrefService->GetIntPref(prefName.get(), retValue);
201 return true;
204 bool
205 ContentProcessParent::RecvGetCharPref(const nsCString& prefName,
206 nsCString* retValue, nsresult* rv)
208 EnsurePrefService();
209 *rv = mPrefService->GetCharPref(prefName.get(), getter_Copies(*retValue));
210 return true;
213 bool
214 ContentProcessParent::RecvGetPrefLocalizedString(const nsCString& prefName,
215 nsString* retValue, nsresult* rv)
217 EnsurePrefService();
218 nsCOMPtr<nsIPrefLocalizedString> string;
219 *rv = mPrefService->GetComplexValue(prefName.get(),
220 NS_GET_IID(nsIPrefLocalizedString), getter_AddRefs(string));
222 if (NS_SUCCEEDED(*rv))
223 string->GetData(getter_Copies(*retValue));
225 return true;
228 bool
229 ContentProcessParent::RecvPrefHasUserValue(const nsCString& prefName,
230 PRBool* retValue, nsresult* rv)
232 *retValue = PR_FALSE;
234 EnsurePrefService();
235 *rv = mPrefService->PrefHasUserValue(prefName.get(), retValue);
236 return true;
239 bool
240 ContentProcessParent::RecvPrefIsLocked(const nsCString& prefName,
241 PRBool* retValue, nsresult* rv)
243 *retValue = PR_FALSE;
245 EnsurePrefService();
246 *rv = mPrefService->PrefIsLocked(prefName.get(), retValue);
248 return true;
251 bool
252 ContentProcessParent::RecvGetChildList(const nsCString& domain,
253 nsTArray<nsCString>* list, nsresult* rv)
255 EnsurePrefService();
257 PRUint32 count;
258 char **childArray;
259 *rv = mPrefService->GetChildList(domain.get(), &count, &childArray);
261 if (NS_SUCCEEDED(*rv)) {
262 list->SetCapacity(count);
263 for (PRUint32 i = 0; i < count; ++i)
264 *(list->AppendElement()) = childArray[i];
267 return true;
270 void
271 ContentProcessParent::EnsurePrefService()
273 nsresult rv;
274 if (!mPrefService) {
275 mPrefService = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
276 NS_ASSERTION(NS_SUCCEEDED(rv),
277 "We lost prefService in the Chrome process !");
281 NS_IMPL_THREADSAFE_ISUPPORTS2(ContentProcessParent,
282 nsIObserver,
283 nsIThreadObserver)
285 namespace {
286 void
287 DeleteSubprocess(GeckoChildProcessHost* aSubprocess)
289 delete aSubprocess;
293 NS_IMETHODIMP
294 ContentProcessParent::Observe(nsISupports* aSubject,
295 const char* aTopic,
296 const PRUnichar* aData)
298 if (!strcmp(aTopic, "xpcom-shutdown") && mSubprocess) {
299 // remove the global remote preferences observers
300 nsCOMPtr<nsIPrefBranch2> prefs
301 (do_GetService(NS_PREFSERVICE_CONTRACTID));
302 if (prefs) {
303 if (gSingleton) {
304 prefs->RemoveObserver("", this);
308 Close();
309 XRE_GetIOMessageLoop()->PostTask(
310 FROM_HERE,
311 NewRunnableFunction(DeleteSubprocess, mSubprocess));
312 mSubprocess = nsnull;
315 // listening for remotePrefs...
316 if (!strcmp(aTopic, "nsPref:changed")) {
317 // We know prefs are ASCII here.
318 NS_LossyConvertUTF16toASCII strData(aData);
319 if (mIsAlive)
320 SendNotifyRemotePrefObserver(strData);
323 if (!strcmp(aTopic, NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC) && mSubprocess) {
324 NS_ConvertUTF16toUTF8 dataStr(aData);
325 const char *offline = dataStr.get();
326 if (mIsAlive)
327 SendSetOffline(!strcmp(offline, "true") ? true : false);
329 return NS_OK;
332 PIFrameEmbeddingParent*
333 ContentProcessParent::AllocPIFrameEmbedding()
335 TabParent* parent = new TabParent();
336 if (parent){
337 NS_ADDREF(parent);
339 return parent;
342 bool
343 ContentProcessParent::DeallocPIFrameEmbedding(PIFrameEmbeddingParent* frame)
345 TabParent* parent = static_cast<TabParent*>(frame);
346 NS_RELEASE(parent);
347 return true;
350 PTestShellParent*
351 ContentProcessParent::AllocPTestShell()
353 return new TestShellParent();
356 bool
357 ContentProcessParent::DeallocPTestShell(PTestShellParent* shell)
359 delete shell;
360 return true;
363 PNeckoParent*
364 ContentProcessParent::AllocPNecko()
366 return new NeckoParent();
369 bool
370 ContentProcessParent::DeallocPNecko(PNeckoParent* necko)
372 delete necko;
373 return true;
376 void
377 ContentProcessParent::ReportChildAlreadyBlocked()
379 if (!mRunToCompletionDepth) {
380 #ifdef DEBUG
381 printf("Running to completion...\n");
382 #endif
383 mRunToCompletionDepth = 1;
384 mShouldCallUnblockChild = false;
388 bool
389 ContentProcessParent::RequestRunToCompletion()
391 if (!mRunToCompletionDepth &&
392 BlockChild()) {
393 #ifdef DEBUG
394 printf("Running to completion...\n");
395 #endif
396 mRunToCompletionDepth = 1;
397 mShouldCallUnblockChild = true;
399 return !!mRunToCompletionDepth;
402 /* void onDispatchedEvent (in nsIThreadInternal thread); */
403 NS_IMETHODIMP
404 ContentProcessParent::OnDispatchedEvent(nsIThreadInternal *thread)
406 if (mOldObserver)
407 return mOldObserver->OnDispatchedEvent(thread);
409 return NS_OK;
412 /* void onProcessNextEvent (in nsIThreadInternal thread, in boolean mayWait, in unsigned long recursionDepth); */
413 NS_IMETHODIMP
414 ContentProcessParent::OnProcessNextEvent(nsIThreadInternal *thread,
415 PRBool mayWait,
416 PRUint32 recursionDepth)
418 if (mRunToCompletionDepth)
419 ++mRunToCompletionDepth;
421 if (mOldObserver)
422 return mOldObserver->OnProcessNextEvent(thread, mayWait, recursionDepth);
424 return NS_OK;
427 /* void afterProcessNextEvent (in nsIThreadInternal thread, in unsigned long recursionDepth); */
428 NS_IMETHODIMP
429 ContentProcessParent::AfterProcessNextEvent(nsIThreadInternal *thread,
430 PRUint32 recursionDepth)
432 if (mRunToCompletionDepth &&
433 !--mRunToCompletionDepth) {
434 #ifdef DEBUG
435 printf("... ran to completion.\n");
436 #endif
437 if (mShouldCallUnblockChild) {
438 mShouldCallUnblockChild = false;
439 UnblockChild();
443 if (mOldObserver)
444 return mOldObserver->AfterProcessNextEvent(thread, recursionDepth);
446 return NS_OK;
449 } // namespace dom
450 } // namespace mozilla