Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
michael@0 | 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
michael@0 | 2 | /* vim: set sw=4 ts=8 et tw=80 : */ |
michael@0 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | #include "mozilla/DebugOnly.h" |
michael@0 | 8 | |
michael@0 | 9 | #include "base/basictypes.h" |
michael@0 | 10 | |
michael@0 | 11 | #include "ContentParent.h" |
michael@0 | 12 | |
michael@0 | 13 | #if defined(ANDROID) || defined(LINUX) |
michael@0 | 14 | # include <sys/time.h> |
michael@0 | 15 | # include <sys/resource.h> |
michael@0 | 16 | #endif |
michael@0 | 17 | |
michael@0 | 18 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 19 | #include <sys/types.h> |
michael@0 | 20 | #include <sys/wait.h> |
michael@0 | 21 | #endif |
michael@0 | 22 | |
michael@0 | 23 | #include "chrome/common/process_watcher.h" |
michael@0 | 24 | |
michael@0 | 25 | #include "AppProcessChecker.h" |
michael@0 | 26 | #include "AudioChannelService.h" |
michael@0 | 27 | #include "CrashReporterParent.h" |
michael@0 | 28 | #include "IHistory.h" |
michael@0 | 29 | #include "IDBFactory.h" |
michael@0 | 30 | #include "IndexedDBParent.h" |
michael@0 | 31 | #include "IndexedDatabaseManager.h" |
michael@0 | 32 | #include "mozIApplication.h" |
michael@0 | 33 | #include "mozilla/ClearOnShutdown.h" |
michael@0 | 34 | #include "mozilla/dom/asmjscache/AsmJSCache.h" |
michael@0 | 35 | #include "mozilla/dom/Element.h" |
michael@0 | 36 | #include "mozilla/dom/ExternalHelperAppParent.h" |
michael@0 | 37 | #include "mozilla/dom/PFileDescriptorSetParent.h" |
michael@0 | 38 | #include "mozilla/dom/PMemoryReportRequestParent.h" |
michael@0 | 39 | #include "mozilla/dom/power/PowerManagerService.h" |
michael@0 | 40 | #include "mozilla/dom/DOMStorageIPC.h" |
michael@0 | 41 | #include "mozilla/dom/bluetooth/PBluetoothParent.h" |
michael@0 | 42 | #include "mozilla/dom/PFMRadioParent.h" |
michael@0 | 43 | #include "mozilla/dom/devicestorage/DeviceStorageRequestParent.h" |
michael@0 | 44 | #include "mozilla/dom/FileSystemRequestParent.h" |
michael@0 | 45 | #include "mozilla/dom/GeolocationBinding.h" |
michael@0 | 46 | #include "mozilla/dom/FileDescriptorSetParent.h" |
michael@0 | 47 | #include "mozilla/dom/telephony/TelephonyParent.h" |
michael@0 | 48 | #include "mozilla/dom/time/DateCacheCleaner.h" |
michael@0 | 49 | #include "SmsParent.h" |
michael@0 | 50 | #include "mozilla/hal_sandbox/PHalParent.h" |
michael@0 | 51 | #include "mozilla/ipc/BackgroundChild.h" |
michael@0 | 52 | #include "mozilla/ipc/BackgroundParent.h" |
michael@0 | 53 | #include "mozilla/ipc/TestShellParent.h" |
michael@0 | 54 | #include "mozilla/ipc/InputStreamUtils.h" |
michael@0 | 55 | #include "mozilla/layers/CompositorParent.h" |
michael@0 | 56 | #include "mozilla/layers/ImageBridgeParent.h" |
michael@0 | 57 | #include "mozilla/net/NeckoParent.h" |
michael@0 | 58 | #include "mozilla/Preferences.h" |
michael@0 | 59 | #include "mozilla/Services.h" |
michael@0 | 60 | #include "mozilla/StaticPtr.h" |
michael@0 | 61 | #include "mozilla/unused.h" |
michael@0 | 62 | #include "nsAppRunner.h" |
michael@0 | 63 | #include "nsAutoPtr.h" |
michael@0 | 64 | #include "nsCDefaultURIFixup.h" |
michael@0 | 65 | #include "nsCExternalHandlerService.h" |
michael@0 | 66 | #include "nsCOMPtr.h" |
michael@0 | 67 | #include "nsChromeRegistryChrome.h" |
michael@0 | 68 | #include "nsConsoleMessage.h" |
michael@0 | 69 | #include "nsConsoleService.h" |
michael@0 | 70 | #include "nsDebugImpl.h" |
michael@0 | 71 | #include "nsDOMFile.h" |
michael@0 | 72 | #include "nsFrameMessageManager.h" |
michael@0 | 73 | #include "nsHashPropertyBag.h" |
michael@0 | 74 | #include "nsIAlertsService.h" |
michael@0 | 75 | #include "nsIAppsService.h" |
michael@0 | 76 | #include "nsIClipboard.h" |
michael@0 | 77 | #include "nsIDOMGeoGeolocation.h" |
michael@0 | 78 | #include "mozilla/dom/WakeLock.h" |
michael@0 | 79 | #include "nsIDOMWindow.h" |
michael@0 | 80 | #include "nsIExternalProtocolService.h" |
michael@0 | 81 | #include "nsIGfxInfo.h" |
michael@0 | 82 | #include "nsIIdleService.h" |
michael@0 | 83 | #include "nsIMemoryReporter.h" |
michael@0 | 84 | #include "nsIMozBrowserFrame.h" |
michael@0 | 85 | #include "nsIMutable.h" |
michael@0 | 86 | #include "nsIObserverService.h" |
michael@0 | 87 | #include "nsIPresShell.h" |
michael@0 | 88 | #include "nsIRemoteBlob.h" |
michael@0 | 89 | #include "nsIScriptError.h" |
michael@0 | 90 | #include "nsIStyleSheet.h" |
michael@0 | 91 | #include "nsISupportsPrimitives.h" |
michael@0 | 92 | #include "nsIURIFixup.h" |
michael@0 | 93 | #include "nsIWindowWatcher.h" |
michael@0 | 94 | #include "nsIXULRuntime.h" |
michael@0 | 95 | #include "nsMemoryReporterManager.h" |
michael@0 | 96 | #include "nsServiceManagerUtils.h" |
michael@0 | 97 | #include "nsStyleSheetService.h" |
michael@0 | 98 | #include "nsThreadUtils.h" |
michael@0 | 99 | #include "nsToolkitCompsCID.h" |
michael@0 | 100 | #include "nsWidgetsCID.h" |
michael@0 | 101 | #include "PreallocatedProcessManager.h" |
michael@0 | 102 | #include "ProcessPriorityManager.h" |
michael@0 | 103 | #include "SandboxHal.h" |
michael@0 | 104 | #include "StructuredCloneUtils.h" |
michael@0 | 105 | #include "TabParent.h" |
michael@0 | 106 | #include "URIUtils.h" |
michael@0 | 107 | #include "nsIWebBrowserChrome.h" |
michael@0 | 108 | #include "nsIDocShell.h" |
michael@0 | 109 | #include "mozilla/net/NeckoMessageUtils.h" |
michael@0 | 110 | #include "gfxPrefs.h" |
michael@0 | 111 | |
michael@0 | 112 | #if defined(ANDROID) || defined(LINUX) |
michael@0 | 113 | #include "nsSystemInfo.h" |
michael@0 | 114 | #endif |
michael@0 | 115 | |
michael@0 | 116 | #ifdef ANDROID |
michael@0 | 117 | # include "gfxAndroidPlatform.h" |
michael@0 | 118 | #endif |
michael@0 | 119 | |
michael@0 | 120 | #ifdef MOZ_PERMISSIONS |
michael@0 | 121 | # include "nsPermissionManager.h" |
michael@0 | 122 | #endif |
michael@0 | 123 | |
michael@0 | 124 | #ifdef MOZ_WIDGET_ANDROID |
michael@0 | 125 | # include "AndroidBridge.h" |
michael@0 | 126 | #endif |
michael@0 | 127 | |
michael@0 | 128 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 129 | #include "nsIVolume.h" |
michael@0 | 130 | #include "nsIVolumeService.h" |
michael@0 | 131 | #include "SpeakerManagerService.h" |
michael@0 | 132 | using namespace mozilla::system; |
michael@0 | 133 | #endif |
michael@0 | 134 | |
michael@0 | 135 | #ifdef MOZ_B2G_BT |
michael@0 | 136 | #include "BluetoothParent.h" |
michael@0 | 137 | #include "BluetoothService.h" |
michael@0 | 138 | #endif |
michael@0 | 139 | |
michael@0 | 140 | #include "JavaScriptParent.h" |
michael@0 | 141 | |
michael@0 | 142 | #ifdef MOZ_B2G_FM |
michael@0 | 143 | #include "mozilla/dom/FMRadioParent.h" |
michael@0 | 144 | #endif |
michael@0 | 145 | |
michael@0 | 146 | #include "Crypto.h" |
michael@0 | 147 | |
michael@0 | 148 | #ifdef MOZ_WEBSPEECH |
michael@0 | 149 | #include "mozilla/dom/SpeechSynthesisParent.h" |
michael@0 | 150 | #endif |
michael@0 | 151 | |
michael@0 | 152 | #ifdef ENABLE_TESTS |
michael@0 | 153 | #include "BackgroundChildImpl.h" |
michael@0 | 154 | #include "mozilla/ipc/PBackgroundChild.h" |
michael@0 | 155 | #include "nsIIPCBackgroundChildCreateCallback.h" |
michael@0 | 156 | #endif |
michael@0 | 157 | |
michael@0 | 158 | static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID); |
michael@0 | 159 | static const char* sClipboardTextFlavors[] = { kUnicodeMime }; |
michael@0 | 160 | |
michael@0 | 161 | using base::ChildPrivileges; |
michael@0 | 162 | using base::KillProcess; |
michael@0 | 163 | using namespace mozilla::dom::bluetooth; |
michael@0 | 164 | using namespace mozilla::dom::devicestorage; |
michael@0 | 165 | using namespace mozilla::dom::indexedDB; |
michael@0 | 166 | using namespace mozilla::dom::power; |
michael@0 | 167 | using namespace mozilla::dom::mobilemessage; |
michael@0 | 168 | using namespace mozilla::dom::telephony; |
michael@0 | 169 | using namespace mozilla::hal; |
michael@0 | 170 | using namespace mozilla::ipc; |
michael@0 | 171 | using namespace mozilla::layers; |
michael@0 | 172 | using namespace mozilla::net; |
michael@0 | 173 | using namespace mozilla::jsipc; |
michael@0 | 174 | |
michael@0 | 175 | #ifdef ENABLE_TESTS |
michael@0 | 176 | |
michael@0 | 177 | class BackgroundTester MOZ_FINAL : public nsIIPCBackgroundChildCreateCallback, |
michael@0 | 178 | public nsIObserver |
michael@0 | 179 | { |
michael@0 | 180 | static uint32_t sCallbackCount; |
michael@0 | 181 | |
michael@0 | 182 | private: |
michael@0 | 183 | ~BackgroundTester() |
michael@0 | 184 | { } |
michael@0 | 185 | |
michael@0 | 186 | virtual void |
michael@0 | 187 | ActorCreated(PBackgroundChild* aActor) MOZ_OVERRIDE |
michael@0 | 188 | { |
michael@0 | 189 | MOZ_RELEASE_ASSERT(aActor, |
michael@0 | 190 | "Failed to create a PBackgroundChild actor!"); |
michael@0 | 191 | |
michael@0 | 192 | NS_NAMED_LITERAL_CSTRING(testStr, "0123456789"); |
michael@0 | 193 | |
michael@0 | 194 | PBackgroundTestChild* testActor = |
michael@0 | 195 | aActor->SendPBackgroundTestConstructor(testStr); |
michael@0 | 196 | MOZ_RELEASE_ASSERT(testActor); |
michael@0 | 197 | |
michael@0 | 198 | if (!sCallbackCount) { |
michael@0 | 199 | PBackgroundChild* existingBackgroundChild = |
michael@0 | 200 | BackgroundChild::GetForCurrentThread(); |
michael@0 | 201 | |
michael@0 | 202 | MOZ_RELEASE_ASSERT(existingBackgroundChild); |
michael@0 | 203 | MOZ_RELEASE_ASSERT(existingBackgroundChild == aActor); |
michael@0 | 204 | |
michael@0 | 205 | bool ok = |
michael@0 | 206 | existingBackgroundChild-> |
michael@0 | 207 | SendPBackgroundTestConstructor(testStr); |
michael@0 | 208 | MOZ_RELEASE_ASSERT(ok); |
michael@0 | 209 | |
michael@0 | 210 | // Callback 3. |
michael@0 | 211 | ok = BackgroundChild::GetOrCreateForCurrentThread(this); |
michael@0 | 212 | MOZ_RELEASE_ASSERT(ok); |
michael@0 | 213 | } |
michael@0 | 214 | |
michael@0 | 215 | sCallbackCount++; |
michael@0 | 216 | } |
michael@0 | 217 | |
michael@0 | 218 | virtual void |
michael@0 | 219 | ActorFailed() MOZ_OVERRIDE |
michael@0 | 220 | { |
michael@0 | 221 | MOZ_CRASH("Failed to create a PBackgroundChild actor!"); |
michael@0 | 222 | } |
michael@0 | 223 | |
michael@0 | 224 | NS_IMETHOD |
michael@0 | 225 | Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) |
michael@0 | 226 | MOZ_OVERRIDE |
michael@0 | 227 | { |
michael@0 | 228 | nsCOMPtr<nsIObserverService> observerService = |
michael@0 | 229 | mozilla::services::GetObserverService(); |
michael@0 | 230 | MOZ_RELEASE_ASSERT(observerService); |
michael@0 | 231 | |
michael@0 | 232 | nsresult rv = observerService->RemoveObserver(this, aTopic); |
michael@0 | 233 | MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); |
michael@0 | 234 | |
michael@0 | 235 | if (!strcmp(aTopic, "profile-after-change")) { |
michael@0 | 236 | if (mozilla::Preferences::GetBool("pbackground.testing", false)) { |
michael@0 | 237 | rv = observerService->AddObserver(this, "xpcom-shutdown", |
michael@0 | 238 | false); |
michael@0 | 239 | MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); |
michael@0 | 240 | |
michael@0 | 241 | // Callback 1. |
michael@0 | 242 | bool ok = BackgroundChild::GetOrCreateForCurrentThread(this); |
michael@0 | 243 | MOZ_RELEASE_ASSERT(ok); |
michael@0 | 244 | |
michael@0 | 245 | BackgroundChildImpl::ThreadLocal* threadLocal = |
michael@0 | 246 | BackgroundChildImpl::GetThreadLocalForCurrentThread(); |
michael@0 | 247 | MOZ_RELEASE_ASSERT(threadLocal); |
michael@0 | 248 | |
michael@0 | 249 | // Callback 2. |
michael@0 | 250 | ok = BackgroundChild::GetOrCreateForCurrentThread(this); |
michael@0 | 251 | MOZ_RELEASE_ASSERT(ok); |
michael@0 | 252 | } |
michael@0 | 253 | |
michael@0 | 254 | return NS_OK; |
michael@0 | 255 | } |
michael@0 | 256 | |
michael@0 | 257 | if (!strcmp(aTopic, "xpcom-shutdown")) { |
michael@0 | 258 | MOZ_RELEASE_ASSERT(sCallbackCount == 3); |
michael@0 | 259 | |
michael@0 | 260 | return NS_OK; |
michael@0 | 261 | } |
michael@0 | 262 | |
michael@0 | 263 | MOZ_CRASH("Unknown observer topic!"); |
michael@0 | 264 | } |
michael@0 | 265 | |
michael@0 | 266 | public: |
michael@0 | 267 | NS_DECL_ISUPPORTS |
michael@0 | 268 | }; |
michael@0 | 269 | |
michael@0 | 270 | uint32_t BackgroundTester::sCallbackCount = 0; |
michael@0 | 271 | |
michael@0 | 272 | NS_IMPL_ISUPPORTS(BackgroundTester, nsIIPCBackgroundChildCreateCallback, |
michael@0 | 273 | nsIObserver) |
michael@0 | 274 | |
michael@0 | 275 | #endif // ENABLE_TESTS |
michael@0 | 276 | |
michael@0 | 277 | void |
michael@0 | 278 | MaybeTestPBackground() |
michael@0 | 279 | { |
michael@0 | 280 | #ifdef ENABLE_TESTS |
michael@0 | 281 | // This test relies on running the event loop and XPCShell does not always |
michael@0 | 282 | // do so. Bail out here if we detect that we're running in XPCShell. |
michael@0 | 283 | if (PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR")) { |
michael@0 | 284 | return; |
michael@0 | 285 | } |
michael@0 | 286 | |
michael@0 | 287 | // This is called too early at startup to test preferences directly. We have |
michael@0 | 288 | // to install an observer to be notified when preferences are available. |
michael@0 | 289 | nsCOMPtr<nsIObserverService> observerService = |
michael@0 | 290 | mozilla::services::GetObserverService(); |
michael@0 | 291 | MOZ_RELEASE_ASSERT(observerService); |
michael@0 | 292 | |
michael@0 | 293 | nsCOMPtr<nsIObserver> observer = new BackgroundTester(); |
michael@0 | 294 | nsresult rv = observerService->AddObserver(observer, "profile-after-change", |
michael@0 | 295 | false); |
michael@0 | 296 | MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); |
michael@0 | 297 | #endif |
michael@0 | 298 | } |
michael@0 | 299 | |
michael@0 | 300 | namespace mozilla { |
michael@0 | 301 | namespace dom { |
michael@0 | 302 | |
michael@0 | 303 | #define NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC "ipc:network:set-offline" |
michael@0 | 304 | |
michael@0 | 305 | class MemoryReportRequestParent : public PMemoryReportRequestParent |
michael@0 | 306 | { |
michael@0 | 307 | public: |
michael@0 | 308 | MemoryReportRequestParent(); |
michael@0 | 309 | virtual ~MemoryReportRequestParent(); |
michael@0 | 310 | |
michael@0 | 311 | virtual bool Recv__delete__(const uint32_t& generation, const InfallibleTArray<MemoryReport>& report); |
michael@0 | 312 | private: |
michael@0 | 313 | ContentParent* Owner() |
michael@0 | 314 | { |
michael@0 | 315 | return static_cast<ContentParent*>(Manager()); |
michael@0 | 316 | } |
michael@0 | 317 | }; |
michael@0 | 318 | |
michael@0 | 319 | MemoryReportRequestParent::MemoryReportRequestParent() |
michael@0 | 320 | { |
michael@0 | 321 | MOZ_COUNT_CTOR(MemoryReportRequestParent); |
michael@0 | 322 | } |
michael@0 | 323 | |
michael@0 | 324 | bool |
michael@0 | 325 | MemoryReportRequestParent::Recv__delete__(const uint32_t& generation, const InfallibleTArray<MemoryReport>& childReports) |
michael@0 | 326 | { |
michael@0 | 327 | nsRefPtr<nsMemoryReporterManager> mgr = |
michael@0 | 328 | nsMemoryReporterManager::GetOrCreate(); |
michael@0 | 329 | if (mgr) { |
michael@0 | 330 | mgr->HandleChildReports(generation, childReports); |
michael@0 | 331 | } |
michael@0 | 332 | return true; |
michael@0 | 333 | } |
michael@0 | 334 | |
michael@0 | 335 | MemoryReportRequestParent::~MemoryReportRequestParent() |
michael@0 | 336 | { |
michael@0 | 337 | MOZ_COUNT_DTOR(MemoryReportRequestParent); |
michael@0 | 338 | } |
michael@0 | 339 | |
michael@0 | 340 | // A memory reporter for ContentParent objects themselves. |
michael@0 | 341 | class ContentParentsMemoryReporter MOZ_FINAL : public nsIMemoryReporter |
michael@0 | 342 | { |
michael@0 | 343 | public: |
michael@0 | 344 | NS_DECL_ISUPPORTS |
michael@0 | 345 | NS_DECL_NSIMEMORYREPORTER |
michael@0 | 346 | }; |
michael@0 | 347 | |
michael@0 | 348 | NS_IMPL_ISUPPORTS(ContentParentsMemoryReporter, nsIMemoryReporter) |
michael@0 | 349 | |
michael@0 | 350 | NS_IMETHODIMP |
michael@0 | 351 | ContentParentsMemoryReporter::CollectReports(nsIMemoryReporterCallback* cb, |
michael@0 | 352 | nsISupports* aClosure) |
michael@0 | 353 | { |
michael@0 | 354 | nsAutoTArray<ContentParent*, 16> cps; |
michael@0 | 355 | ContentParent::GetAllEvenIfDead(cps); |
michael@0 | 356 | |
michael@0 | 357 | for (uint32_t i = 0; i < cps.Length(); i++) { |
michael@0 | 358 | ContentParent* cp = cps[i]; |
michael@0 | 359 | MessageChannel* channel = cp->GetIPCChannel(); |
michael@0 | 360 | |
michael@0 | 361 | nsString friendlyName; |
michael@0 | 362 | cp->FriendlyName(friendlyName); |
michael@0 | 363 | |
michael@0 | 364 | cp->AddRef(); |
michael@0 | 365 | nsrefcnt refcnt = cp->Release(); |
michael@0 | 366 | |
michael@0 | 367 | const char* channelStr = "no channel"; |
michael@0 | 368 | uint32_t numQueuedMessages = 0; |
michael@0 | 369 | if (channel) { |
michael@0 | 370 | if (channel->Unsound_IsClosed()) { |
michael@0 | 371 | channelStr = "closed channel"; |
michael@0 | 372 | } else { |
michael@0 | 373 | channelStr = "open channel"; |
michael@0 | 374 | } |
michael@0 | 375 | numQueuedMessages = channel->Unsound_NumQueuedMessages(); |
michael@0 | 376 | } |
michael@0 | 377 | |
michael@0 | 378 | nsPrintfCString path("queued-ipc-messages/content-parent" |
michael@0 | 379 | "(%s, pid=%d, %s, 0x%p, refcnt=%d)", |
michael@0 | 380 | NS_ConvertUTF16toUTF8(friendlyName).get(), |
michael@0 | 381 | cp->Pid(), channelStr, cp, refcnt); |
michael@0 | 382 | |
michael@0 | 383 | NS_NAMED_LITERAL_CSTRING(desc, |
michael@0 | 384 | "The number of unset IPC messages held in this ContentParent's " |
michael@0 | 385 | "channel. A large value here might indicate that we're leaking " |
michael@0 | 386 | "messages. Similarly, a ContentParent object for a process that's no " |
michael@0 | 387 | "longer running could indicate that we're leaking ContentParents."); |
michael@0 | 388 | |
michael@0 | 389 | nsresult rv = cb->Callback(/* process */ EmptyCString(), |
michael@0 | 390 | path, |
michael@0 | 391 | KIND_OTHER, |
michael@0 | 392 | UNITS_COUNT, |
michael@0 | 393 | numQueuedMessages, |
michael@0 | 394 | desc, |
michael@0 | 395 | aClosure); |
michael@0 | 396 | |
michael@0 | 397 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 398 | } |
michael@0 | 399 | |
michael@0 | 400 | return NS_OK; |
michael@0 | 401 | } |
michael@0 | 402 | |
michael@0 | 403 | nsDataHashtable<nsStringHashKey, ContentParent*>* ContentParent::sAppContentParents; |
michael@0 | 404 | nsTArray<ContentParent*>* ContentParent::sNonAppContentParents; |
michael@0 | 405 | nsTArray<ContentParent*>* ContentParent::sPrivateContent; |
michael@0 | 406 | StaticAutoPtr<LinkedList<ContentParent> > ContentParent::sContentParents; |
michael@0 | 407 | |
michael@0 | 408 | // This is true when subprocess launching is enabled. This is the |
michael@0 | 409 | // case between StartUp() and ShutDown() or JoinAllSubprocesses(). |
michael@0 | 410 | static bool sCanLaunchSubprocesses; |
michael@0 | 411 | |
michael@0 | 412 | // The first content child has ID 1, so the chrome process can have ID 0. |
michael@0 | 413 | static uint64_t gContentChildID = 1; |
michael@0 | 414 | |
michael@0 | 415 | // We want the prelaunched process to know that it's for apps, but not |
michael@0 | 416 | // actually for any app in particular. Use a magic manifest URL. |
michael@0 | 417 | // Can't be a static constant. |
michael@0 | 418 | #define MAGIC_PREALLOCATED_APP_MANIFEST_URL NS_LITERAL_STRING("{{template}}") |
michael@0 | 419 | |
michael@0 | 420 | static const char* sObserverTopics[] = { |
michael@0 | 421 | "xpcom-shutdown", |
michael@0 | 422 | NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC, |
michael@0 | 423 | "child-memory-reporter-request", |
michael@0 | 424 | "memory-pressure", |
michael@0 | 425 | "child-gc-request", |
michael@0 | 426 | "child-cc-request", |
michael@0 | 427 | "child-mmu-request", |
michael@0 | 428 | "last-pb-context-exited", |
michael@0 | 429 | "file-watcher-update", |
michael@0 | 430 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 431 | NS_VOLUME_STATE_CHANGED, |
michael@0 | 432 | "phone-state-changed", |
michael@0 | 433 | #endif |
michael@0 | 434 | #ifdef ACCESSIBILITY |
michael@0 | 435 | "a11y-init-or-shutdown", |
michael@0 | 436 | #endif |
michael@0 | 437 | }; |
michael@0 | 438 | |
michael@0 | 439 | /* static */ already_AddRefed<ContentParent> |
michael@0 | 440 | ContentParent::RunNuwaProcess() |
michael@0 | 441 | { |
michael@0 | 442 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 443 | nsRefPtr<ContentParent> nuwaProcess = |
michael@0 | 444 | new ContentParent(/* aApp = */ nullptr, |
michael@0 | 445 | /* aIsForBrowser = */ false, |
michael@0 | 446 | /* aIsForPreallocated = */ true, |
michael@0 | 447 | PROCESS_PRIORITY_BACKGROUND, |
michael@0 | 448 | /* aIsNuwaProcess = */ true); |
michael@0 | 449 | nuwaProcess->Init(); |
michael@0 | 450 | return nuwaProcess.forget(); |
michael@0 | 451 | } |
michael@0 | 452 | |
michael@0 | 453 | // PreallocateAppProcess is called by the PreallocatedProcessManager. |
michael@0 | 454 | // ContentParent then takes this process back within |
michael@0 | 455 | // MaybeTakePreallocatedAppProcess. |
michael@0 | 456 | /*static*/ already_AddRefed<ContentParent> |
michael@0 | 457 | ContentParent::PreallocateAppProcess() |
michael@0 | 458 | { |
michael@0 | 459 | nsRefPtr<ContentParent> process = |
michael@0 | 460 | new ContentParent(/* app = */ nullptr, |
michael@0 | 461 | /* isForBrowserElement = */ false, |
michael@0 | 462 | /* isForPreallocated = */ true, |
michael@0 | 463 | PROCESS_PRIORITY_PREALLOC); |
michael@0 | 464 | process->Init(); |
michael@0 | 465 | return process.forget(); |
michael@0 | 466 | } |
michael@0 | 467 | |
michael@0 | 468 | /*static*/ already_AddRefed<ContentParent> |
michael@0 | 469 | ContentParent::MaybeTakePreallocatedAppProcess(const nsAString& aAppManifestURL, |
michael@0 | 470 | ProcessPriority aInitialPriority) |
michael@0 | 471 | { |
michael@0 | 472 | nsRefPtr<ContentParent> process = PreallocatedProcessManager::Take(); |
michael@0 | 473 | if (!process) { |
michael@0 | 474 | return nullptr; |
michael@0 | 475 | } |
michael@0 | 476 | |
michael@0 | 477 | if (!process->SetPriorityAndCheckIsAlive(aInitialPriority)) { |
michael@0 | 478 | // Kill the process just in case it's not actually dead; we don't want |
michael@0 | 479 | // to "leak" this process! |
michael@0 | 480 | process->KillHard(); |
michael@0 | 481 | return nullptr; |
michael@0 | 482 | } |
michael@0 | 483 | process->TransformPreallocatedIntoApp(aAppManifestURL); |
michael@0 | 484 | |
michael@0 | 485 | return process.forget(); |
michael@0 | 486 | } |
michael@0 | 487 | |
michael@0 | 488 | /*static*/ void |
michael@0 | 489 | ContentParent::StartUp() |
michael@0 | 490 | { |
michael@0 | 491 | if (XRE_GetProcessType() != GeckoProcessType_Default) { |
michael@0 | 492 | return; |
michael@0 | 493 | } |
michael@0 | 494 | |
michael@0 | 495 | // Note: This reporter measures all ContentParents. |
michael@0 | 496 | RegisterStrongMemoryReporter(new ContentParentsMemoryReporter()); |
michael@0 | 497 | |
michael@0 | 498 | mozilla::dom::time::InitializeDateCacheCleaner(); |
michael@0 | 499 | |
michael@0 | 500 | BackgroundChild::Startup(); |
michael@0 | 501 | |
michael@0 | 502 | sCanLaunchSubprocesses = true; |
michael@0 | 503 | |
michael@0 | 504 | // Try to preallocate a process that we can transform into an app later. |
michael@0 | 505 | PreallocatedProcessManager::AllocateAfterDelay(); |
michael@0 | 506 | |
michael@0 | 507 | // Test the PBackground infrastructure on ENABLE_TESTS builds when a special |
michael@0 | 508 | // testing preference is set. |
michael@0 | 509 | MaybeTestPBackground(); |
michael@0 | 510 | } |
michael@0 | 511 | |
michael@0 | 512 | /*static*/ void |
michael@0 | 513 | ContentParent::ShutDown() |
michael@0 | 514 | { |
michael@0 | 515 | // No-op for now. We rely on normal process shutdown and |
michael@0 | 516 | // ClearOnShutdown() to clean up our state. |
michael@0 | 517 | sCanLaunchSubprocesses = false; |
michael@0 | 518 | } |
michael@0 | 519 | |
michael@0 | 520 | /*static*/ void |
michael@0 | 521 | ContentParent::JoinProcessesIOThread(const nsTArray<ContentParent*>* aProcesses, |
michael@0 | 522 | Monitor* aMonitor, bool* aDone) |
michael@0 | 523 | { |
michael@0 | 524 | const nsTArray<ContentParent*>& processes = *aProcesses; |
michael@0 | 525 | for (uint32_t i = 0; i < processes.Length(); ++i) { |
michael@0 | 526 | if (GeckoChildProcessHost* process = processes[i]->mSubprocess) { |
michael@0 | 527 | process->Join(); |
michael@0 | 528 | } |
michael@0 | 529 | } |
michael@0 | 530 | { |
michael@0 | 531 | MonitorAutoLock lock(*aMonitor); |
michael@0 | 532 | *aDone = true; |
michael@0 | 533 | lock.Notify(); |
michael@0 | 534 | } |
michael@0 | 535 | // Don't touch any arguments to this function from now on. |
michael@0 | 536 | } |
michael@0 | 537 | |
michael@0 | 538 | /*static*/ void |
michael@0 | 539 | ContentParent::JoinAllSubprocesses() |
michael@0 | 540 | { |
michael@0 | 541 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 542 | |
michael@0 | 543 | nsAutoTArray<ContentParent*, 8> processes; |
michael@0 | 544 | GetAll(processes); |
michael@0 | 545 | if (processes.IsEmpty()) { |
michael@0 | 546 | printf_stderr("There are no live subprocesses."); |
michael@0 | 547 | return; |
michael@0 | 548 | } |
michael@0 | 549 | |
michael@0 | 550 | printf_stderr("Subprocesses are still alive. Doing emergency join.\n"); |
michael@0 | 551 | |
michael@0 | 552 | bool done = false; |
michael@0 | 553 | Monitor monitor("mozilla.dom.ContentParent.JoinAllSubprocesses"); |
michael@0 | 554 | XRE_GetIOMessageLoop()->PostTask(FROM_HERE, |
michael@0 | 555 | NewRunnableFunction( |
michael@0 | 556 | &ContentParent::JoinProcessesIOThread, |
michael@0 | 557 | &processes, &monitor, &done)); |
michael@0 | 558 | { |
michael@0 | 559 | MonitorAutoLock lock(monitor); |
michael@0 | 560 | while (!done) { |
michael@0 | 561 | lock.Wait(); |
michael@0 | 562 | } |
michael@0 | 563 | } |
michael@0 | 564 | |
michael@0 | 565 | sCanLaunchSubprocesses = false; |
michael@0 | 566 | } |
michael@0 | 567 | |
michael@0 | 568 | /*static*/ already_AddRefed<ContentParent> |
michael@0 | 569 | ContentParent::GetNewOrUsed(bool aForBrowserElement) |
michael@0 | 570 | { |
michael@0 | 571 | if (!sNonAppContentParents) |
michael@0 | 572 | sNonAppContentParents = new nsTArray<ContentParent*>(); |
michael@0 | 573 | |
michael@0 | 574 | int32_t maxContentProcesses = Preferences::GetInt("dom.ipc.processCount", 1); |
michael@0 | 575 | if (maxContentProcesses < 1) |
michael@0 | 576 | maxContentProcesses = 1; |
michael@0 | 577 | |
michael@0 | 578 | if (sNonAppContentParents->Length() >= uint32_t(maxContentProcesses)) { |
michael@0 | 579 | uint32_t idx = rand() % sNonAppContentParents->Length(); |
michael@0 | 580 | nsRefPtr<ContentParent> p = (*sNonAppContentParents)[idx]; |
michael@0 | 581 | NS_ASSERTION(p->IsAlive(), "Non-alive contentparent in sNonAppContentParents?"); |
michael@0 | 582 | return p.forget(); |
michael@0 | 583 | } |
michael@0 | 584 | |
michael@0 | 585 | // Try to take and transform the preallocated process into browser. |
michael@0 | 586 | nsRefPtr<ContentParent> p = PreallocatedProcessManager::Take(); |
michael@0 | 587 | if (p) { |
michael@0 | 588 | p->TransformPreallocatedIntoBrowser(); |
michael@0 | 589 | } else { |
michael@0 | 590 | // Failed in using the preallocated process: fork from the chrome process. |
michael@0 | 591 | #ifdef MOZ_NUWA_PROCESS |
michael@0 | 592 | if (Preferences::GetBool("dom.ipc.processPrelaunch.enabled", false)) { |
michael@0 | 593 | // Wait until the Nuwa process forks a new process. |
michael@0 | 594 | return nullptr; |
michael@0 | 595 | } |
michael@0 | 596 | #endif |
michael@0 | 597 | p = new ContentParent(/* app = */ nullptr, |
michael@0 | 598 | aForBrowserElement, |
michael@0 | 599 | /* isForPreallocated = */ false, |
michael@0 | 600 | PROCESS_PRIORITY_FOREGROUND); |
michael@0 | 601 | } |
michael@0 | 602 | |
michael@0 | 603 | p->Init(); |
michael@0 | 604 | sNonAppContentParents->AppendElement(p); |
michael@0 | 605 | return p.forget(); |
michael@0 | 606 | } |
michael@0 | 607 | |
michael@0 | 608 | /*static*/ ProcessPriority |
michael@0 | 609 | ContentParent::GetInitialProcessPriority(Element* aFrameElement) |
michael@0 | 610 | { |
michael@0 | 611 | // Frames with mozapptype == critical which are expecting a system message |
michael@0 | 612 | // get FOREGROUND_HIGH priority. |
michael@0 | 613 | |
michael@0 | 614 | if (!aFrameElement) { |
michael@0 | 615 | return PROCESS_PRIORITY_FOREGROUND; |
michael@0 | 616 | } |
michael@0 | 617 | |
michael@0 | 618 | if (aFrameElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::mozapptype, |
michael@0 | 619 | NS_LITERAL_STRING("keyboard"), eCaseMatters)) { |
michael@0 | 620 | return PROCESS_PRIORITY_FOREGROUND_KEYBOARD; |
michael@0 | 621 | } else if (!aFrameElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::mozapptype, |
michael@0 | 622 | NS_LITERAL_STRING("critical"), eCaseMatters)) { |
michael@0 | 623 | return PROCESS_PRIORITY_FOREGROUND; |
michael@0 | 624 | } |
michael@0 | 625 | |
michael@0 | 626 | nsCOMPtr<nsIMozBrowserFrame> browserFrame = |
michael@0 | 627 | do_QueryInterface(aFrameElement); |
michael@0 | 628 | if (!browserFrame) { |
michael@0 | 629 | return PROCESS_PRIORITY_FOREGROUND; |
michael@0 | 630 | } |
michael@0 | 631 | |
michael@0 | 632 | return browserFrame->GetIsExpectingSystemMessage() ? |
michael@0 | 633 | PROCESS_PRIORITY_FOREGROUND_HIGH : |
michael@0 | 634 | PROCESS_PRIORITY_FOREGROUND; |
michael@0 | 635 | } |
michael@0 | 636 | |
michael@0 | 637 | bool |
michael@0 | 638 | ContentParent::PreallocatedProcessReady() |
michael@0 | 639 | { |
michael@0 | 640 | #ifdef MOZ_NUWA_PROCESS |
michael@0 | 641 | return PreallocatedProcessManager::PreallocatedProcessReady(); |
michael@0 | 642 | #else |
michael@0 | 643 | return true; |
michael@0 | 644 | #endif |
michael@0 | 645 | } |
michael@0 | 646 | |
michael@0 | 647 | void |
michael@0 | 648 | ContentParent::RunAfterPreallocatedProcessReady(nsIRunnable* aRequest) |
michael@0 | 649 | { |
michael@0 | 650 | #ifdef MOZ_NUWA_PROCESS |
michael@0 | 651 | PreallocatedProcessManager::RunAfterPreallocatedProcessReady(aRequest); |
michael@0 | 652 | #endif |
michael@0 | 653 | } |
michael@0 | 654 | |
michael@0 | 655 | /*static*/ TabParent* |
michael@0 | 656 | ContentParent::CreateBrowserOrApp(const TabContext& aContext, |
michael@0 | 657 | Element* aFrameElement) |
michael@0 | 658 | { |
michael@0 | 659 | if (!sCanLaunchSubprocesses) { |
michael@0 | 660 | return nullptr; |
michael@0 | 661 | } |
michael@0 | 662 | |
michael@0 | 663 | if (aContext.IsBrowserElement() || !aContext.HasOwnApp()) { |
michael@0 | 664 | if (nsRefPtr<ContentParent> cp = GetNewOrUsed(aContext.IsBrowserElement())) { |
michael@0 | 665 | uint32_t chromeFlags = 0; |
michael@0 | 666 | |
michael@0 | 667 | // Propagate the private-browsing status of the element's parent |
michael@0 | 668 | // docshell to the remote docshell, via the chrome flags. |
michael@0 | 669 | nsCOMPtr<Element> frameElement = do_QueryInterface(aFrameElement); |
michael@0 | 670 | MOZ_ASSERT(frameElement); |
michael@0 | 671 | nsIDocShell* docShell = |
michael@0 | 672 | frameElement->OwnerDoc()->GetWindow()->GetDocShell(); |
michael@0 | 673 | MOZ_ASSERT(docShell); |
michael@0 | 674 | nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell); |
michael@0 | 675 | if (loadContext && loadContext->UsePrivateBrowsing()) { |
michael@0 | 676 | chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW; |
michael@0 | 677 | } |
michael@0 | 678 | bool affectLifetime; |
michael@0 | 679 | docShell->GetAffectPrivateSessionLifetime(&affectLifetime); |
michael@0 | 680 | if (affectLifetime) { |
michael@0 | 681 | chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME; |
michael@0 | 682 | } |
michael@0 | 683 | |
michael@0 | 684 | nsRefPtr<TabParent> tp(new TabParent(cp, aContext, chromeFlags)); |
michael@0 | 685 | tp->SetOwnerElement(aFrameElement); |
michael@0 | 686 | |
michael@0 | 687 | PBrowserParent* browser = cp->SendPBrowserConstructor( |
michael@0 | 688 | // DeallocPBrowserParent() releases this ref. |
michael@0 | 689 | tp.forget().take(), |
michael@0 | 690 | aContext.AsIPCTabContext(), |
michael@0 | 691 | chromeFlags); |
michael@0 | 692 | return static_cast<TabParent*>(browser); |
michael@0 | 693 | } |
michael@0 | 694 | return nullptr; |
michael@0 | 695 | } |
michael@0 | 696 | |
michael@0 | 697 | // If we got here, we have an app and we're not a browser element. ownApp |
michael@0 | 698 | // shouldn't be null, because we otherwise would have gone into the |
michael@0 | 699 | // !HasOwnApp() branch above. |
michael@0 | 700 | nsCOMPtr<mozIApplication> ownApp = aContext.GetOwnApp(); |
michael@0 | 701 | |
michael@0 | 702 | if (!sAppContentParents) { |
michael@0 | 703 | sAppContentParents = |
michael@0 | 704 | new nsDataHashtable<nsStringHashKey, ContentParent*>(); |
michael@0 | 705 | } |
michael@0 | 706 | |
michael@0 | 707 | // Each app gets its own ContentParent instance unless it shares it with |
michael@0 | 708 | // a parent app. |
michael@0 | 709 | nsAutoString manifestURL; |
michael@0 | 710 | if (NS_FAILED(ownApp->GetManifestURL(manifestURL))) { |
michael@0 | 711 | NS_ERROR("Failed to get manifest URL"); |
michael@0 | 712 | return nullptr; |
michael@0 | 713 | } |
michael@0 | 714 | |
michael@0 | 715 | ProcessPriority initialPriority = GetInitialProcessPriority(aFrameElement); |
michael@0 | 716 | nsRefPtr<ContentParent> p = sAppContentParents->Get(manifestURL); |
michael@0 | 717 | |
michael@0 | 718 | if (!p && Preferences::GetBool("dom.ipc.reuse_parent_app")) { |
michael@0 | 719 | nsAutoString parentAppURL; |
michael@0 | 720 | aFrameElement->GetAttr(kNameSpaceID_None, |
michael@0 | 721 | nsGkAtoms::parentapp, parentAppURL); |
michael@0 | 722 | nsAdoptingString systemAppURL = |
michael@0 | 723 | Preferences::GetString("browser.homescreenURL"); |
michael@0 | 724 | nsCOMPtr<nsIAppsService> appsService = |
michael@0 | 725 | do_GetService(APPS_SERVICE_CONTRACTID); |
michael@0 | 726 | if (!parentAppURL.IsEmpty() && |
michael@0 | 727 | !parentAppURL.Equals(systemAppURL) && |
michael@0 | 728 | appsService) { |
michael@0 | 729 | nsCOMPtr<mozIApplication> parentApp; |
michael@0 | 730 | nsCOMPtr<mozIApplication> app; |
michael@0 | 731 | appsService->GetAppByManifestURL(parentAppURL, |
michael@0 | 732 | getter_AddRefs(parentApp)); |
michael@0 | 733 | appsService->GetAppByManifestURL(manifestURL, |
michael@0 | 734 | getter_AddRefs(app)); |
michael@0 | 735 | |
michael@0 | 736 | // Only let certified apps re-use the same process. |
michael@0 | 737 | unsigned short parentAppStatus = 0; |
michael@0 | 738 | unsigned short appStatus = 0; |
michael@0 | 739 | if (app && |
michael@0 | 740 | NS_SUCCEEDED(app->GetAppStatus(&appStatus)) && |
michael@0 | 741 | appStatus == nsIPrincipal::APP_STATUS_CERTIFIED && |
michael@0 | 742 | parentApp && |
michael@0 | 743 | NS_SUCCEEDED(parentApp->GetAppStatus(&parentAppStatus)) && |
michael@0 | 744 | parentAppStatus == nsIPrincipal::APP_STATUS_CERTIFIED) { |
michael@0 | 745 | // Check if we can re-use the process of the parent app. |
michael@0 | 746 | p = sAppContentParents->Get(parentAppURL); |
michael@0 | 747 | } |
michael@0 | 748 | } |
michael@0 | 749 | } |
michael@0 | 750 | |
michael@0 | 751 | if (p) { |
michael@0 | 752 | // Check that the process is still alive and set its priority. |
michael@0 | 753 | // Hopefully the process won't die after this point, if this call |
michael@0 | 754 | // succeeds. |
michael@0 | 755 | if (!p->SetPriorityAndCheckIsAlive(initialPriority)) { |
michael@0 | 756 | p = nullptr; |
michael@0 | 757 | } |
michael@0 | 758 | } |
michael@0 | 759 | |
michael@0 | 760 | if (!p) { |
michael@0 | 761 | p = MaybeTakePreallocatedAppProcess(manifestURL, |
michael@0 | 762 | initialPriority); |
michael@0 | 763 | if (!p) { |
michael@0 | 764 | #ifdef MOZ_NUWA_PROCESS |
michael@0 | 765 | if (Preferences::GetBool("dom.ipc.processPrelaunch.enabled", |
michael@0 | 766 | false)) { |
michael@0 | 767 | // Returning nullptr from here so the frame loader will retry |
michael@0 | 768 | // later when we have a spare process. |
michael@0 | 769 | return nullptr; |
michael@0 | 770 | } |
michael@0 | 771 | #endif |
michael@0 | 772 | NS_WARNING("Unable to use pre-allocated app process"); |
michael@0 | 773 | p = new ContentParent(ownApp, |
michael@0 | 774 | /* isForBrowserElement = */ false, |
michael@0 | 775 | /* isForPreallocated = */ false, |
michael@0 | 776 | initialPriority); |
michael@0 | 777 | p->Init(); |
michael@0 | 778 | } |
michael@0 | 779 | sAppContentParents->Put(manifestURL, p); |
michael@0 | 780 | } |
michael@0 | 781 | |
michael@0 | 782 | uint32_t chromeFlags = 0; |
michael@0 | 783 | |
michael@0 | 784 | nsRefPtr<TabParent> tp = new TabParent(p, aContext, chromeFlags); |
michael@0 | 785 | tp->SetOwnerElement(aFrameElement); |
michael@0 | 786 | PBrowserParent* browser = p->SendPBrowserConstructor( |
michael@0 | 787 | // DeallocPBrowserParent() releases this ref. |
michael@0 | 788 | nsRefPtr<TabParent>(tp).forget().take(), |
michael@0 | 789 | aContext.AsIPCTabContext(), |
michael@0 | 790 | chromeFlags); |
michael@0 | 791 | |
michael@0 | 792 | p->MaybeTakeCPUWakeLock(aFrameElement); |
michael@0 | 793 | |
michael@0 | 794 | return static_cast<TabParent*>(browser); |
michael@0 | 795 | } |
michael@0 | 796 | |
michael@0 | 797 | void |
michael@0 | 798 | ContentParent::GetAll(nsTArray<ContentParent*>& aArray) |
michael@0 | 799 | { |
michael@0 | 800 | aArray.Clear(); |
michael@0 | 801 | |
michael@0 | 802 | if (!sContentParents) { |
michael@0 | 803 | return; |
michael@0 | 804 | } |
michael@0 | 805 | |
michael@0 | 806 | for (ContentParent* cp = sContentParents->getFirst(); cp; |
michael@0 | 807 | cp = cp->LinkedListElement<ContentParent>::getNext()) { |
michael@0 | 808 | if (cp->mIsAlive) { |
michael@0 | 809 | aArray.AppendElement(cp); |
michael@0 | 810 | } |
michael@0 | 811 | } |
michael@0 | 812 | } |
michael@0 | 813 | |
michael@0 | 814 | void |
michael@0 | 815 | ContentParent::GetAllEvenIfDead(nsTArray<ContentParent*>& aArray) |
michael@0 | 816 | { |
michael@0 | 817 | aArray.Clear(); |
michael@0 | 818 | |
michael@0 | 819 | if (!sContentParents) { |
michael@0 | 820 | return; |
michael@0 | 821 | } |
michael@0 | 822 | |
michael@0 | 823 | for (ContentParent* cp = sContentParents->getFirst(); cp; |
michael@0 | 824 | cp = cp->LinkedListElement<ContentParent>::getNext()) { |
michael@0 | 825 | aArray.AppendElement(cp); |
michael@0 | 826 | } |
michael@0 | 827 | } |
michael@0 | 828 | |
michael@0 | 829 | void |
michael@0 | 830 | ContentParent::Init() |
michael@0 | 831 | { |
michael@0 | 832 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
michael@0 | 833 | if (obs) { |
michael@0 | 834 | size_t length = ArrayLength(sObserverTopics); |
michael@0 | 835 | for (size_t i = 0; i < length; ++i) { |
michael@0 | 836 | obs->AddObserver(this, sObserverTopics[i], false); |
michael@0 | 837 | } |
michael@0 | 838 | } |
michael@0 | 839 | Preferences::AddStrongObserver(this, ""); |
michael@0 | 840 | if (obs) { |
michael@0 | 841 | obs->NotifyObservers(static_cast<nsIObserver*>(this), "ipc:content-created", nullptr); |
michael@0 | 842 | } |
michael@0 | 843 | |
michael@0 | 844 | #ifdef ACCESSIBILITY |
michael@0 | 845 | // If accessibility is running in chrome process then start it in content |
michael@0 | 846 | // process. |
michael@0 | 847 | if (nsIPresShell::IsAccessibilityActive()) { |
michael@0 | 848 | unused << SendActivateA11y(); |
michael@0 | 849 | } |
michael@0 | 850 | #endif |
michael@0 | 851 | |
michael@0 | 852 | DebugOnly<FileUpdateDispatcher*> observer = FileUpdateDispatcher::GetSingleton(); |
michael@0 | 853 | NS_ASSERTION(observer, "FileUpdateDispatcher is null"); |
michael@0 | 854 | } |
michael@0 | 855 | |
michael@0 | 856 | namespace { |
michael@0 | 857 | |
michael@0 | 858 | class SystemMessageHandledListener MOZ_FINAL |
michael@0 | 859 | : public nsITimerCallback |
michael@0 | 860 | , public LinkedListElement<SystemMessageHandledListener> |
michael@0 | 861 | { |
michael@0 | 862 | public: |
michael@0 | 863 | NS_DECL_ISUPPORTS |
michael@0 | 864 | |
michael@0 | 865 | SystemMessageHandledListener() {} |
michael@0 | 866 | |
michael@0 | 867 | static void OnSystemMessageHandled() |
michael@0 | 868 | { |
michael@0 | 869 | if (!sListeners) { |
michael@0 | 870 | return; |
michael@0 | 871 | } |
michael@0 | 872 | |
michael@0 | 873 | SystemMessageHandledListener* listener = sListeners->popFirst(); |
michael@0 | 874 | if (!listener) { |
michael@0 | 875 | return; |
michael@0 | 876 | } |
michael@0 | 877 | |
michael@0 | 878 | // Careful: ShutDown() may delete |this|. |
michael@0 | 879 | listener->ShutDown(); |
michael@0 | 880 | } |
michael@0 | 881 | |
michael@0 | 882 | void Init(WakeLock* aWakeLock) |
michael@0 | 883 | { |
michael@0 | 884 | MOZ_ASSERT(!mWakeLock); |
michael@0 | 885 | MOZ_ASSERT(!mTimer); |
michael@0 | 886 | |
michael@0 | 887 | // mTimer keeps a strong reference to |this|. When this object's |
michael@0 | 888 | // destructor runs, it will remove itself from the LinkedList. |
michael@0 | 889 | |
michael@0 | 890 | if (!sListeners) { |
michael@0 | 891 | sListeners = new LinkedList<SystemMessageHandledListener>(); |
michael@0 | 892 | ClearOnShutdown(&sListeners); |
michael@0 | 893 | } |
michael@0 | 894 | sListeners->insertBack(this); |
michael@0 | 895 | |
michael@0 | 896 | mWakeLock = aWakeLock; |
michael@0 | 897 | |
michael@0 | 898 | mTimer = do_CreateInstance("@mozilla.org/timer;1"); |
michael@0 | 899 | |
michael@0 | 900 | uint32_t timeoutSec = |
michael@0 | 901 | Preferences::GetInt("dom.ipc.systemMessageCPULockTimeoutSec", 30); |
michael@0 | 902 | mTimer->InitWithCallback(this, timeoutSec * 1000, |
michael@0 | 903 | nsITimer::TYPE_ONE_SHOT); |
michael@0 | 904 | } |
michael@0 | 905 | |
michael@0 | 906 | NS_IMETHOD Notify(nsITimer* aTimer) |
michael@0 | 907 | { |
michael@0 | 908 | // Careful: ShutDown() may delete |this|. |
michael@0 | 909 | ShutDown(); |
michael@0 | 910 | return NS_OK; |
michael@0 | 911 | } |
michael@0 | 912 | |
michael@0 | 913 | private: |
michael@0 | 914 | static StaticAutoPtr<LinkedList<SystemMessageHandledListener> > sListeners; |
michael@0 | 915 | |
michael@0 | 916 | void ShutDown() |
michael@0 | 917 | { |
michael@0 | 918 | nsRefPtr<SystemMessageHandledListener> kungFuDeathGrip = this; |
michael@0 | 919 | |
michael@0 | 920 | ErrorResult rv; |
michael@0 | 921 | mWakeLock->Unlock(rv); |
michael@0 | 922 | |
michael@0 | 923 | if (mTimer) { |
michael@0 | 924 | mTimer->Cancel(); |
michael@0 | 925 | mTimer = nullptr; |
michael@0 | 926 | } |
michael@0 | 927 | } |
michael@0 | 928 | |
michael@0 | 929 | nsRefPtr<WakeLock> mWakeLock; |
michael@0 | 930 | nsCOMPtr<nsITimer> mTimer; |
michael@0 | 931 | }; |
michael@0 | 932 | |
michael@0 | 933 | StaticAutoPtr<LinkedList<SystemMessageHandledListener> > |
michael@0 | 934 | SystemMessageHandledListener::sListeners; |
michael@0 | 935 | |
michael@0 | 936 | NS_IMPL_ISUPPORTS(SystemMessageHandledListener, |
michael@0 | 937 | nsITimerCallback) |
michael@0 | 938 | |
michael@0 | 939 | } // anonymous namespace |
michael@0 | 940 | |
michael@0 | 941 | void |
michael@0 | 942 | ContentParent::MaybeTakeCPUWakeLock(Element* aFrameElement) |
michael@0 | 943 | { |
michael@0 | 944 | // Take the CPU wake lock on behalf of this processs if it's expecting a |
michael@0 | 945 | // system message. We'll release the CPU lock once the message is |
michael@0 | 946 | // delivered, or after some period of time, which ever comes first. |
michael@0 | 947 | |
michael@0 | 948 | nsCOMPtr<nsIMozBrowserFrame> browserFrame = |
michael@0 | 949 | do_QueryInterface(aFrameElement); |
michael@0 | 950 | if (!browserFrame || |
michael@0 | 951 | !browserFrame->GetIsExpectingSystemMessage()) { |
michael@0 | 952 | return; |
michael@0 | 953 | } |
michael@0 | 954 | |
michael@0 | 955 | nsRefPtr<PowerManagerService> pms = PowerManagerService::GetInstance(); |
michael@0 | 956 | nsRefPtr<WakeLock> lock = |
michael@0 | 957 | pms->NewWakeLockOnBehalfOfProcess(NS_LITERAL_STRING("cpu"), this); |
michael@0 | 958 | |
michael@0 | 959 | // This object's Init() function keeps it alive. |
michael@0 | 960 | nsRefPtr<SystemMessageHandledListener> listener = |
michael@0 | 961 | new SystemMessageHandledListener(); |
michael@0 | 962 | listener->Init(lock); |
michael@0 | 963 | } |
michael@0 | 964 | |
michael@0 | 965 | bool |
michael@0 | 966 | ContentParent::SetPriorityAndCheckIsAlive(ProcessPriority aPriority) |
michael@0 | 967 | { |
michael@0 | 968 | ProcessPriorityManager::SetProcessPriority(this, aPriority); |
michael@0 | 969 | |
michael@0 | 970 | // Now that we've set this process's priority, check whether the process is |
michael@0 | 971 | // still alive. Hopefully we've set the priority to FOREGROUND*, so the |
michael@0 | 972 | // process won't unexpectedly crash after this point! |
michael@0 | 973 | // |
michael@0 | 974 | // Bug 943174: use waitid() with WNOWAIT so that, if the process |
michael@0 | 975 | // did exit, we won't consume its zombie and confuse the |
michael@0 | 976 | // GeckoChildProcessHost dtor. Also, if the process isn't a |
michael@0 | 977 | // direct child because of Nuwa this will fail with ECHILD, and we |
michael@0 | 978 | // need to assume the child is alive in that case rather than |
michael@0 | 979 | // assuming it's dead (as is otherwise a reasonable fallback). |
michael@0 | 980 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 981 | siginfo_t info; |
michael@0 | 982 | info.si_pid = 0; |
michael@0 | 983 | if (waitid(P_PID, Pid(), &info, WNOWAIT | WNOHANG | WEXITED) == 0 |
michael@0 | 984 | && info.si_pid != 0) { |
michael@0 | 985 | return false; |
michael@0 | 986 | } |
michael@0 | 987 | #endif |
michael@0 | 988 | |
michael@0 | 989 | return true; |
michael@0 | 990 | } |
michael@0 | 991 | |
michael@0 | 992 | // Helper for ContentParent::TransformPreallocatedIntoApp. |
michael@0 | 993 | static void |
michael@0 | 994 | TryGetNameFromManifestURL(const nsAString& aManifestURL, |
michael@0 | 995 | nsAString& aName) |
michael@0 | 996 | { |
michael@0 | 997 | aName.Truncate(); |
michael@0 | 998 | if (aManifestURL.IsEmpty() || |
michael@0 | 999 | aManifestURL == MAGIC_PREALLOCATED_APP_MANIFEST_URL) { |
michael@0 | 1000 | return; |
michael@0 | 1001 | } |
michael@0 | 1002 | |
michael@0 | 1003 | nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID); |
michael@0 | 1004 | NS_ENSURE_TRUE_VOID(appsService); |
michael@0 | 1005 | |
michael@0 | 1006 | nsCOMPtr<mozIApplication> app; |
michael@0 | 1007 | appsService->GetAppByManifestURL(aManifestURL, getter_AddRefs(app)); |
michael@0 | 1008 | |
michael@0 | 1009 | if (!app) { |
michael@0 | 1010 | return; |
michael@0 | 1011 | } |
michael@0 | 1012 | |
michael@0 | 1013 | app->GetName(aName); |
michael@0 | 1014 | } |
michael@0 | 1015 | |
michael@0 | 1016 | void |
michael@0 | 1017 | ContentParent::TransformPreallocatedIntoApp(const nsAString& aAppManifestURL) |
michael@0 | 1018 | { |
michael@0 | 1019 | MOZ_ASSERT(IsPreallocated()); |
michael@0 | 1020 | mAppManifestURL = aAppManifestURL; |
michael@0 | 1021 | TryGetNameFromManifestURL(aAppManifestURL, mAppName); |
michael@0 | 1022 | } |
michael@0 | 1023 | |
michael@0 | 1024 | void |
michael@0 | 1025 | ContentParent::TransformPreallocatedIntoBrowser() |
michael@0 | 1026 | { |
michael@0 | 1027 | // Reset mAppManifestURL, mIsForBrowser and mOSPrivileges for browser. |
michael@0 | 1028 | mAppManifestURL.Truncate(); |
michael@0 | 1029 | mIsForBrowser = true; |
michael@0 | 1030 | } |
michael@0 | 1031 | |
michael@0 | 1032 | void |
michael@0 | 1033 | ContentParent::ShutDownProcess(bool aCloseWithError) |
michael@0 | 1034 | { |
michael@0 | 1035 | const InfallibleTArray<PIndexedDBParent*>& idbParents = |
michael@0 | 1036 | ManagedPIndexedDBParent(); |
michael@0 | 1037 | for (uint32_t i = 0; i < idbParents.Length(); ++i) { |
michael@0 | 1038 | static_cast<IndexedDBParent*>(idbParents[i])->Disconnect(); |
michael@0 | 1039 | } |
michael@0 | 1040 | |
michael@0 | 1041 | // If Close() fails with an error, we'll end up back in this function, but |
michael@0 | 1042 | // with aCloseWithError = true. It's important that we call |
michael@0 | 1043 | // CloseWithError() in this case; see bug 895204. |
michael@0 | 1044 | |
michael@0 | 1045 | if (!aCloseWithError && !mCalledClose) { |
michael@0 | 1046 | // Close() can only be called once: It kicks off the destruction |
michael@0 | 1047 | // sequence. |
michael@0 | 1048 | mCalledClose = true; |
michael@0 | 1049 | Close(); |
michael@0 | 1050 | } |
michael@0 | 1051 | |
michael@0 | 1052 | if (aCloseWithError && !mCalledCloseWithError) { |
michael@0 | 1053 | MessageChannel* channel = GetIPCChannel(); |
michael@0 | 1054 | if (channel) { |
michael@0 | 1055 | mCalledCloseWithError = true; |
michael@0 | 1056 | channel->CloseWithError(); |
michael@0 | 1057 | } |
michael@0 | 1058 | } |
michael@0 | 1059 | |
michael@0 | 1060 | // NB: must MarkAsDead() here so that this isn't accidentally |
michael@0 | 1061 | // returned from Get*() while in the midst of shutdown. |
michael@0 | 1062 | MarkAsDead(); |
michael@0 | 1063 | |
michael@0 | 1064 | // A ContentParent object might not get freed until after XPCOM shutdown has |
michael@0 | 1065 | // shut down the cycle collector. But by then it's too late to release any |
michael@0 | 1066 | // CC'ed objects, so we need to null them out here, while we still can. See |
michael@0 | 1067 | // bug 899761. |
michael@0 | 1068 | if (mMessageManager) { |
michael@0 | 1069 | mMessageManager->Disconnect(); |
michael@0 | 1070 | mMessageManager = nullptr; |
michael@0 | 1071 | } |
michael@0 | 1072 | } |
michael@0 | 1073 | |
michael@0 | 1074 | void |
michael@0 | 1075 | ContentParent::MarkAsDead() |
michael@0 | 1076 | { |
michael@0 | 1077 | if (!mAppManifestURL.IsEmpty()) { |
michael@0 | 1078 | if (sAppContentParents) { |
michael@0 | 1079 | sAppContentParents->Remove(mAppManifestURL); |
michael@0 | 1080 | if (!sAppContentParents->Count()) { |
michael@0 | 1081 | delete sAppContentParents; |
michael@0 | 1082 | sAppContentParents = nullptr; |
michael@0 | 1083 | } |
michael@0 | 1084 | } |
michael@0 | 1085 | } else if (sNonAppContentParents) { |
michael@0 | 1086 | sNonAppContentParents->RemoveElement(this); |
michael@0 | 1087 | if (!sNonAppContentParents->Length()) { |
michael@0 | 1088 | delete sNonAppContentParents; |
michael@0 | 1089 | sNonAppContentParents = nullptr; |
michael@0 | 1090 | } |
michael@0 | 1091 | } |
michael@0 | 1092 | |
michael@0 | 1093 | if (sPrivateContent) { |
michael@0 | 1094 | sPrivateContent->RemoveElement(this); |
michael@0 | 1095 | if (!sPrivateContent->Length()) { |
michael@0 | 1096 | delete sPrivateContent; |
michael@0 | 1097 | sPrivateContent = nullptr; |
michael@0 | 1098 | } |
michael@0 | 1099 | } |
michael@0 | 1100 | |
michael@0 | 1101 | mIsAlive = false; |
michael@0 | 1102 | } |
michael@0 | 1103 | |
michael@0 | 1104 | void |
michael@0 | 1105 | ContentParent::OnChannelError() |
michael@0 | 1106 | { |
michael@0 | 1107 | nsRefPtr<ContentParent> content(this); |
michael@0 | 1108 | #ifdef MOZ_NUWA_PROCESS |
michael@0 | 1109 | // Handle app or Nuwa process exit before normal channel error handling. |
michael@0 | 1110 | PreallocatedProcessManager::MaybeForgetSpare(this); |
michael@0 | 1111 | #endif |
michael@0 | 1112 | PContentParent::OnChannelError(); |
michael@0 | 1113 | } |
michael@0 | 1114 | |
michael@0 | 1115 | void |
michael@0 | 1116 | ContentParent::OnChannelConnected(int32_t pid) |
michael@0 | 1117 | { |
michael@0 | 1118 | ProcessHandle handle; |
michael@0 | 1119 | if (!base::OpenPrivilegedProcessHandle(pid, &handle)) { |
michael@0 | 1120 | NS_WARNING("Can't open handle to child process."); |
michael@0 | 1121 | } |
michael@0 | 1122 | else { |
michael@0 | 1123 | // we need to close the existing handle before setting a new one. |
michael@0 | 1124 | base::CloseProcessHandle(OtherProcess()); |
michael@0 | 1125 | SetOtherProcess(handle); |
michael@0 | 1126 | |
michael@0 | 1127 | #if defined(ANDROID) || defined(LINUX) |
michael@0 | 1128 | // Check nice preference |
michael@0 | 1129 | int32_t nice = Preferences::GetInt("dom.ipc.content.nice", 0); |
michael@0 | 1130 | |
michael@0 | 1131 | // Environment variable overrides preference |
michael@0 | 1132 | char* relativeNicenessStr = getenv("MOZ_CHILD_PROCESS_RELATIVE_NICENESS"); |
michael@0 | 1133 | if (relativeNicenessStr) { |
michael@0 | 1134 | nice = atoi(relativeNicenessStr); |
michael@0 | 1135 | } |
michael@0 | 1136 | |
michael@0 | 1137 | /* make the GUI thread have higher priority on single-cpu devices */ |
michael@0 | 1138 | nsCOMPtr<nsIPropertyBag2> infoService = do_GetService(NS_SYSTEMINFO_CONTRACTID); |
michael@0 | 1139 | if (infoService) { |
michael@0 | 1140 | int32_t cpus; |
michael@0 | 1141 | nsresult rv = infoService->GetPropertyAsInt32(NS_LITERAL_STRING("cpucount"), &cpus); |
michael@0 | 1142 | if (NS_FAILED(rv)) { |
michael@0 | 1143 | cpus = 1; |
michael@0 | 1144 | } |
michael@0 | 1145 | if (nice != 0 && cpus == 1) { |
michael@0 | 1146 | setpriority(PRIO_PROCESS, pid, getpriority(PRIO_PROCESS, pid) + nice); |
michael@0 | 1147 | } |
michael@0 | 1148 | } |
michael@0 | 1149 | #endif |
michael@0 | 1150 | } |
michael@0 | 1151 | |
michael@0 | 1152 | // Set a reply timeout. The only time the parent process will actually |
michael@0 | 1153 | // timeout is through urgent messages (which are used by CPOWs). |
michael@0 | 1154 | SetReplyTimeoutMs(Preferences::GetInt("dom.ipc.cpow.timeout", 3000)); |
michael@0 | 1155 | } |
michael@0 | 1156 | |
michael@0 | 1157 | void |
michael@0 | 1158 | ContentParent::ProcessingError(Result what) |
michael@0 | 1159 | { |
michael@0 | 1160 | if (MsgDropped == what) { |
michael@0 | 1161 | // Messages sent after crashes etc. are not a big deal. |
michael@0 | 1162 | return; |
michael@0 | 1163 | } |
michael@0 | 1164 | // Other errors are big deals. |
michael@0 | 1165 | KillHard(); |
michael@0 | 1166 | } |
michael@0 | 1167 | |
michael@0 | 1168 | namespace { |
michael@0 | 1169 | |
michael@0 | 1170 | void |
michael@0 | 1171 | DelayedDeleteSubprocess(GeckoChildProcessHost* aSubprocess) |
michael@0 | 1172 | { |
michael@0 | 1173 | XRE_GetIOMessageLoop() |
michael@0 | 1174 | ->PostTask(FROM_HERE, |
michael@0 | 1175 | new DeleteTask<GeckoChildProcessHost>(aSubprocess)); |
michael@0 | 1176 | } |
michael@0 | 1177 | |
michael@0 | 1178 | // This runnable only exists to delegate ownership of the |
michael@0 | 1179 | // ContentParent to this runnable, until it's deleted by the event |
michael@0 | 1180 | // system. |
michael@0 | 1181 | struct DelayedDeleteContentParentTask : public nsRunnable |
michael@0 | 1182 | { |
michael@0 | 1183 | DelayedDeleteContentParentTask(ContentParent* aObj) : mObj(aObj) { } |
michael@0 | 1184 | |
michael@0 | 1185 | // No-op |
michael@0 | 1186 | NS_IMETHODIMP Run() { return NS_OK; } |
michael@0 | 1187 | |
michael@0 | 1188 | nsRefPtr<ContentParent> mObj; |
michael@0 | 1189 | }; |
michael@0 | 1190 | |
michael@0 | 1191 | } |
michael@0 | 1192 | |
michael@0 | 1193 | void |
michael@0 | 1194 | ContentParent::ActorDestroy(ActorDestroyReason why) |
michael@0 | 1195 | { |
michael@0 | 1196 | if (mForceKillTask) { |
michael@0 | 1197 | mForceKillTask->Cancel(); |
michael@0 | 1198 | mForceKillTask = nullptr; |
michael@0 | 1199 | } |
michael@0 | 1200 | |
michael@0 | 1201 | nsRefPtr<nsFrameMessageManager> ppm = mMessageManager; |
michael@0 | 1202 | if (ppm) { |
michael@0 | 1203 | ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), |
michael@0 | 1204 | CHILD_PROCESS_SHUTDOWN_MESSAGE, false, |
michael@0 | 1205 | nullptr, nullptr, nullptr, nullptr); |
michael@0 | 1206 | } |
michael@0 | 1207 | nsRefPtr<ContentParent> kungFuDeathGrip(this); |
michael@0 | 1208 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
michael@0 | 1209 | if (obs) { |
michael@0 | 1210 | size_t length = ArrayLength(sObserverTopics); |
michael@0 | 1211 | for (size_t i = 0; i < length; ++i) { |
michael@0 | 1212 | obs->RemoveObserver(static_cast<nsIObserver*>(this), |
michael@0 | 1213 | sObserverTopics[i]); |
michael@0 | 1214 | } |
michael@0 | 1215 | } |
michael@0 | 1216 | |
michael@0 | 1217 | if (ppm) { |
michael@0 | 1218 | ppm->Disconnect(); |
michael@0 | 1219 | } |
michael@0 | 1220 | |
michael@0 | 1221 | // Tell the memory reporter manager that this ContentParent is going away. |
michael@0 | 1222 | nsRefPtr<nsMemoryReporterManager> mgr = |
michael@0 | 1223 | nsMemoryReporterManager::GetOrCreate(); |
michael@0 | 1224 | #ifdef MOZ_NUWA_PROCESS |
michael@0 | 1225 | bool isMemoryChild = !IsNuwaProcess(); |
michael@0 | 1226 | #else |
michael@0 | 1227 | bool isMemoryChild = true; |
michael@0 | 1228 | #endif |
michael@0 | 1229 | if (mgr && isMemoryChild) { |
michael@0 | 1230 | mgr->DecrementNumChildProcesses(); |
michael@0 | 1231 | } |
michael@0 | 1232 | |
michael@0 | 1233 | // remove the global remote preferences observers |
michael@0 | 1234 | Preferences::RemoveObserver(this, ""); |
michael@0 | 1235 | |
michael@0 | 1236 | RecvRemoveGeolocationListener(); |
michael@0 | 1237 | |
michael@0 | 1238 | mConsoleService = nullptr; |
michael@0 | 1239 | |
michael@0 | 1240 | MarkAsDead(); |
michael@0 | 1241 | |
michael@0 | 1242 | if (obs) { |
michael@0 | 1243 | nsRefPtr<nsHashPropertyBag> props = new nsHashPropertyBag(); |
michael@0 | 1244 | |
michael@0 | 1245 | props->SetPropertyAsUint64(NS_LITERAL_STRING("childID"), mChildID); |
michael@0 | 1246 | |
michael@0 | 1247 | if (AbnormalShutdown == why) { |
michael@0 | 1248 | props->SetPropertyAsBool(NS_LITERAL_STRING("abnormal"), true); |
michael@0 | 1249 | |
michael@0 | 1250 | #ifdef MOZ_CRASHREPORTER |
michael@0 | 1251 | // There's a window in which child processes can crash |
michael@0 | 1252 | // after IPC is established, but before a crash reporter |
michael@0 | 1253 | // is created. |
michael@0 | 1254 | if (ManagedPCrashReporterParent().Length() > 0) { |
michael@0 | 1255 | CrashReporterParent* crashReporter = |
michael@0 | 1256 | static_cast<CrashReporterParent*>(ManagedPCrashReporterParent()[0]); |
michael@0 | 1257 | |
michael@0 | 1258 | // If we're an app process, always stomp the latest URI |
michael@0 | 1259 | // loaded in the child process with our manifest URL. We |
michael@0 | 1260 | // would rather associate the crashes with apps than |
michael@0 | 1261 | // random child windows loaded in them. |
michael@0 | 1262 | // |
michael@0 | 1263 | // XXX would be nice if we could get both ... |
michael@0 | 1264 | if (!mAppManifestURL.IsEmpty()) { |
michael@0 | 1265 | crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("URL"), |
michael@0 | 1266 | NS_ConvertUTF16toUTF8(mAppManifestURL)); |
michael@0 | 1267 | } |
michael@0 | 1268 | |
michael@0 | 1269 | crashReporter->GenerateCrashReport(this, nullptr); |
michael@0 | 1270 | |
michael@0 | 1271 | nsAutoString dumpID(crashReporter->ChildDumpID()); |
michael@0 | 1272 | props->SetPropertyAsAString(NS_LITERAL_STRING("dumpID"), dumpID); |
michael@0 | 1273 | } |
michael@0 | 1274 | #endif |
michael@0 | 1275 | } |
michael@0 | 1276 | obs->NotifyObservers((nsIPropertyBag2*) props, "ipc:content-shutdown", nullptr); |
michael@0 | 1277 | } |
michael@0 | 1278 | |
michael@0 | 1279 | mIdleListeners.Clear(); |
michael@0 | 1280 | |
michael@0 | 1281 | // If the child process was terminated due to a SIGKIL, ShutDownProcess |
michael@0 | 1282 | // might not have been called yet. We must call it to ensure that our |
michael@0 | 1283 | // channel is closed, etc. |
michael@0 | 1284 | ShutDownProcess(/* closeWithError */ true); |
michael@0 | 1285 | |
michael@0 | 1286 | MessageLoop::current()-> |
michael@0 | 1287 | PostTask(FROM_HERE, |
michael@0 | 1288 | NewRunnableFunction(DelayedDeleteSubprocess, mSubprocess)); |
michael@0 | 1289 | mSubprocess = nullptr; |
michael@0 | 1290 | |
michael@0 | 1291 | // IPDL rules require actors to live on past ActorDestroy, but it |
michael@0 | 1292 | // may be that the kungFuDeathGrip above is the last reference to |
michael@0 | 1293 | // |this|. If so, when we go out of scope here, we're deleted and |
michael@0 | 1294 | // all hell breaks loose. |
michael@0 | 1295 | // |
michael@0 | 1296 | // This runnable ensures that a reference to |this| lives on at |
michael@0 | 1297 | // least until after the current task finishes running. |
michael@0 | 1298 | NS_DispatchToCurrentThread(new DelayedDeleteContentParentTask(this)); |
michael@0 | 1299 | } |
michael@0 | 1300 | |
michael@0 | 1301 | void |
michael@0 | 1302 | ContentParent::NotifyTabDestroying(PBrowserParent* aTab) |
michael@0 | 1303 | { |
michael@0 | 1304 | // There can be more than one PBrowser for a given app process |
michael@0 | 1305 | // because of popup windows. PBrowsers can also destroy |
michael@0 | 1306 | // concurrently. When all the PBrowsers are destroying, kick off |
michael@0 | 1307 | // another task to ensure the child process *really* shuts down, |
michael@0 | 1308 | // even if the PBrowsers themselves never finish destroying. |
michael@0 | 1309 | int32_t numLiveTabs = ManagedPBrowserParent().Length(); |
michael@0 | 1310 | ++mNumDestroyingTabs; |
michael@0 | 1311 | if (mNumDestroyingTabs != numLiveTabs) { |
michael@0 | 1312 | return; |
michael@0 | 1313 | } |
michael@0 | 1314 | |
michael@0 | 1315 | // We're dying now, so prevent this content process from being |
michael@0 | 1316 | // recycled during its shutdown procedure. |
michael@0 | 1317 | MarkAsDead(); |
michael@0 | 1318 | |
michael@0 | 1319 | MOZ_ASSERT(!mForceKillTask); |
michael@0 | 1320 | int32_t timeoutSecs = |
michael@0 | 1321 | Preferences::GetInt("dom.ipc.tabs.shutdownTimeoutSecs", 5); |
michael@0 | 1322 | if (timeoutSecs > 0) { |
michael@0 | 1323 | MessageLoop::current()->PostDelayedTask( |
michael@0 | 1324 | FROM_HERE, |
michael@0 | 1325 | mForceKillTask = NewRunnableMethod(this, &ContentParent::KillHard), |
michael@0 | 1326 | timeoutSecs * 1000); |
michael@0 | 1327 | } |
michael@0 | 1328 | } |
michael@0 | 1329 | |
michael@0 | 1330 | void |
michael@0 | 1331 | ContentParent::NotifyTabDestroyed(PBrowserParent* aTab, |
michael@0 | 1332 | bool aNotifiedDestroying) |
michael@0 | 1333 | { |
michael@0 | 1334 | if (aNotifiedDestroying) { |
michael@0 | 1335 | --mNumDestroyingTabs; |
michael@0 | 1336 | } |
michael@0 | 1337 | |
michael@0 | 1338 | // There can be more than one PBrowser for a given app process |
michael@0 | 1339 | // because of popup windows. When the last one closes, shut |
michael@0 | 1340 | // us down. |
michael@0 | 1341 | if (ManagedPBrowserParent().Length() == 1) { |
michael@0 | 1342 | MessageLoop::current()->PostTask( |
michael@0 | 1343 | FROM_HERE, |
michael@0 | 1344 | NewRunnableMethod(this, &ContentParent::ShutDownProcess, |
michael@0 | 1345 | /* force */ false)); |
michael@0 | 1346 | } |
michael@0 | 1347 | } |
michael@0 | 1348 | |
michael@0 | 1349 | jsipc::JavaScriptParent* |
michael@0 | 1350 | ContentParent::GetCPOWManager() |
michael@0 | 1351 | { |
michael@0 | 1352 | if (ManagedPJavaScriptParent().Length()) { |
michael@0 | 1353 | return static_cast<JavaScriptParent*>(ManagedPJavaScriptParent()[0]); |
michael@0 | 1354 | } |
michael@0 | 1355 | JavaScriptParent* actor = static_cast<JavaScriptParent*>(SendPJavaScriptConstructor()); |
michael@0 | 1356 | return actor; |
michael@0 | 1357 | } |
michael@0 | 1358 | |
michael@0 | 1359 | TestShellParent* |
michael@0 | 1360 | ContentParent::CreateTestShell() |
michael@0 | 1361 | { |
michael@0 | 1362 | return static_cast<TestShellParent*>(SendPTestShellConstructor()); |
michael@0 | 1363 | } |
michael@0 | 1364 | |
michael@0 | 1365 | bool |
michael@0 | 1366 | ContentParent::DestroyTestShell(TestShellParent* aTestShell) |
michael@0 | 1367 | { |
michael@0 | 1368 | return PTestShellParent::Send__delete__(aTestShell); |
michael@0 | 1369 | } |
michael@0 | 1370 | |
michael@0 | 1371 | TestShellParent* |
michael@0 | 1372 | ContentParent::GetTestShellSingleton() |
michael@0 | 1373 | { |
michael@0 | 1374 | if (!ManagedPTestShellParent().Length()) |
michael@0 | 1375 | return nullptr; |
michael@0 | 1376 | return static_cast<TestShellParent*>(ManagedPTestShellParent()[0]); |
michael@0 | 1377 | } |
michael@0 | 1378 | |
michael@0 | 1379 | void |
michael@0 | 1380 | ContentParent::InitializeMembers() |
michael@0 | 1381 | { |
michael@0 | 1382 | mSubprocess = nullptr; |
michael@0 | 1383 | mChildID = gContentChildID++; |
michael@0 | 1384 | mGeolocationWatchID = -1; |
michael@0 | 1385 | mForceKillTask = nullptr; |
michael@0 | 1386 | mNumDestroyingTabs = 0; |
michael@0 | 1387 | mIsAlive = true; |
michael@0 | 1388 | mSendPermissionUpdates = false; |
michael@0 | 1389 | mCalledClose = false; |
michael@0 | 1390 | mCalledCloseWithError = false; |
michael@0 | 1391 | mCalledKillHard = false; |
michael@0 | 1392 | } |
michael@0 | 1393 | |
michael@0 | 1394 | ContentParent::ContentParent(mozIApplication* aApp, |
michael@0 | 1395 | bool aIsForBrowser, |
michael@0 | 1396 | bool aIsForPreallocated, |
michael@0 | 1397 | ProcessPriority aInitialPriority /* = PROCESS_PRIORITY_FOREGROUND */, |
michael@0 | 1398 | bool aIsNuwaProcess /* = false */) |
michael@0 | 1399 | : mIsForBrowser(aIsForBrowser) |
michael@0 | 1400 | , mIsNuwaProcess(aIsNuwaProcess) |
michael@0 | 1401 | { |
michael@0 | 1402 | InitializeMembers(); // Perform common initialization. |
michael@0 | 1403 | |
michael@0 | 1404 | // No more than one of !!aApp, aIsForBrowser, aIsForPreallocated should be |
michael@0 | 1405 | // true. |
michael@0 | 1406 | MOZ_ASSERT(!!aApp + aIsForBrowser + aIsForPreallocated <= 1); |
michael@0 | 1407 | |
michael@0 | 1408 | // Only the preallocated process uses Nuwa. |
michael@0 | 1409 | MOZ_ASSERT_IF(aIsNuwaProcess, aIsForPreallocated); |
michael@0 | 1410 | |
michael@0 | 1411 | // Insert ourselves into the global linked list of ContentParent objects. |
michael@0 | 1412 | if (!sContentParents) { |
michael@0 | 1413 | sContentParents = new LinkedList<ContentParent>(); |
michael@0 | 1414 | } |
michael@0 | 1415 | if (!aIsNuwaProcess) { |
michael@0 | 1416 | sContentParents->insertBack(this); |
michael@0 | 1417 | } |
michael@0 | 1418 | |
michael@0 | 1419 | if (aApp) { |
michael@0 | 1420 | aApp->GetManifestURL(mAppManifestURL); |
michael@0 | 1421 | aApp->GetName(mAppName); |
michael@0 | 1422 | } else if (aIsForPreallocated) { |
michael@0 | 1423 | mAppManifestURL = MAGIC_PREALLOCATED_APP_MANIFEST_URL; |
michael@0 | 1424 | } |
michael@0 | 1425 | |
michael@0 | 1426 | // From this point on, NS_WARNING, NS_ASSERTION, etc. should print out the |
michael@0 | 1427 | // PID along with the warning. |
michael@0 | 1428 | nsDebugImpl::SetMultiprocessMode("Parent"); |
michael@0 | 1429 | |
michael@0 | 1430 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 1431 | ChildPrivileges privs = aIsNuwaProcess |
michael@0 | 1432 | ? base::PRIVILEGES_INHERIT |
michael@0 | 1433 | : base::PRIVILEGES_DEFAULT; |
michael@0 | 1434 | mSubprocess = new GeckoChildProcessHost(GeckoProcessType_Content, privs); |
michael@0 | 1435 | mSubprocess->SetSandboxEnabled(ShouldSandboxContentProcesses()); |
michael@0 | 1436 | |
michael@0 | 1437 | IToplevelProtocol::SetTransport(mSubprocess->GetChannel()); |
michael@0 | 1438 | |
michael@0 | 1439 | if (!aIsNuwaProcess) { |
michael@0 | 1440 | // Tell the memory reporter manager that this ContentParent exists. |
michael@0 | 1441 | nsRefPtr<nsMemoryReporterManager> mgr = |
michael@0 | 1442 | nsMemoryReporterManager::GetOrCreate(); |
michael@0 | 1443 | if (mgr) { |
michael@0 | 1444 | mgr->IncrementNumChildProcesses(); |
michael@0 | 1445 | } |
michael@0 | 1446 | } |
michael@0 | 1447 | |
michael@0 | 1448 | std::vector<std::string> extraArgs; |
michael@0 | 1449 | if (aIsNuwaProcess) { |
michael@0 | 1450 | extraArgs.push_back("-nuwa"); |
michael@0 | 1451 | } |
michael@0 | 1452 | mSubprocess->LaunchAndWaitForProcessHandle(extraArgs); |
michael@0 | 1453 | |
michael@0 | 1454 | Open(mSubprocess->GetChannel(), mSubprocess->GetOwnedChildProcessHandle()); |
michael@0 | 1455 | |
michael@0 | 1456 | InitInternal(aInitialPriority, |
michael@0 | 1457 | true, /* Setup off-main thread compositing */ |
michael@0 | 1458 | true /* Send registered chrome */); |
michael@0 | 1459 | } |
michael@0 | 1460 | |
michael@0 | 1461 | #ifdef MOZ_NUWA_PROCESS |
michael@0 | 1462 | static const mozilla::ipc::FileDescriptor* |
michael@0 | 1463 | FindFdProtocolFdMapping(const nsTArray<ProtocolFdMapping>& aFds, |
michael@0 | 1464 | ProtocolId aProtoId) |
michael@0 | 1465 | { |
michael@0 | 1466 | for (unsigned int i = 0; i < aFds.Length(); i++) { |
michael@0 | 1467 | if (aFds[i].protocolId() == aProtoId) { |
michael@0 | 1468 | return &aFds[i].fd(); |
michael@0 | 1469 | } |
michael@0 | 1470 | } |
michael@0 | 1471 | return nullptr; |
michael@0 | 1472 | } |
michael@0 | 1473 | |
michael@0 | 1474 | /** |
michael@0 | 1475 | * This constructor is used for new content process cloned from a template. |
michael@0 | 1476 | * |
michael@0 | 1477 | * For Nuwa. |
michael@0 | 1478 | */ |
michael@0 | 1479 | ContentParent::ContentParent(ContentParent* aTemplate, |
michael@0 | 1480 | const nsAString& aAppManifestURL, |
michael@0 | 1481 | base::ProcessHandle aPid, |
michael@0 | 1482 | const nsTArray<ProtocolFdMapping>& aFds) |
michael@0 | 1483 | : mAppManifestURL(aAppManifestURL) |
michael@0 | 1484 | , mIsForBrowser(false) |
michael@0 | 1485 | , mIsNuwaProcess(false) |
michael@0 | 1486 | { |
michael@0 | 1487 | InitializeMembers(); // Perform common initialization. |
michael@0 | 1488 | |
michael@0 | 1489 | sContentParents->insertBack(this); |
michael@0 | 1490 | |
michael@0 | 1491 | // From this point on, NS_WARNING, NS_ASSERTION, etc. should print out the |
michael@0 | 1492 | // PID along with the warning. |
michael@0 | 1493 | nsDebugImpl::SetMultiprocessMode("Parent"); |
michael@0 | 1494 | |
michael@0 | 1495 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 1496 | |
michael@0 | 1497 | const FileDescriptor* fd = FindFdProtocolFdMapping(aFds, GetProtocolId()); |
michael@0 | 1498 | |
michael@0 | 1499 | NS_ASSERTION(fd != nullptr, "IPC Channel for PContent is necessary!"); |
michael@0 | 1500 | mSubprocess = new GeckoExistingProcessHost(GeckoProcessType_Content, |
michael@0 | 1501 | aPid, |
michael@0 | 1502 | *fd); |
michael@0 | 1503 | |
michael@0 | 1504 | // Tell the memory reporter manager that this ContentParent exists. |
michael@0 | 1505 | nsRefPtr<nsMemoryReporterManager> mgr = |
michael@0 | 1506 | nsMemoryReporterManager::GetOrCreate(); |
michael@0 | 1507 | if (mgr) { |
michael@0 | 1508 | mgr->IncrementNumChildProcesses(); |
michael@0 | 1509 | } |
michael@0 | 1510 | |
michael@0 | 1511 | mSubprocess->LaunchAndWaitForProcessHandle(); |
michael@0 | 1512 | |
michael@0 | 1513 | // Clone actors routed by aTemplate for this instance. |
michael@0 | 1514 | IToplevelProtocol::SetTransport(mSubprocess->GetChannel()); |
michael@0 | 1515 | ProtocolCloneContext cloneContext; |
michael@0 | 1516 | cloneContext.SetContentParent(this); |
michael@0 | 1517 | CloneManagees(aTemplate, &cloneContext); |
michael@0 | 1518 | CloneOpenedToplevels(aTemplate, aFds, aPid, &cloneContext); |
michael@0 | 1519 | |
michael@0 | 1520 | Open(mSubprocess->GetChannel(), |
michael@0 | 1521 | mSubprocess->GetChildProcessHandle()); |
michael@0 | 1522 | |
michael@0 | 1523 | // Set the subprocess's priority (bg if we're a preallocated process, fg |
michael@0 | 1524 | // otherwise). We do this first because we're likely /lowering/ its CPU and |
michael@0 | 1525 | // memory priority, which it has inherited from this process. |
michael@0 | 1526 | ProcessPriority priority; |
michael@0 | 1527 | if (IsPreallocated()) { |
michael@0 | 1528 | priority = PROCESS_PRIORITY_PREALLOC; |
michael@0 | 1529 | } else { |
michael@0 | 1530 | priority = PROCESS_PRIORITY_FOREGROUND; |
michael@0 | 1531 | } |
michael@0 | 1532 | |
michael@0 | 1533 | InitInternal(priority, |
michael@0 | 1534 | false, /* Setup Off-main thread compositing */ |
michael@0 | 1535 | false /* Send registered chrome */); |
michael@0 | 1536 | } |
michael@0 | 1537 | #endif // MOZ_NUWA_PROCESS |
michael@0 | 1538 | |
michael@0 | 1539 | ContentParent::~ContentParent() |
michael@0 | 1540 | { |
michael@0 | 1541 | if (mForceKillTask) { |
michael@0 | 1542 | mForceKillTask->Cancel(); |
michael@0 | 1543 | } |
michael@0 | 1544 | |
michael@0 | 1545 | if (OtherProcess()) |
michael@0 | 1546 | base::CloseProcessHandle(OtherProcess()); |
michael@0 | 1547 | |
michael@0 | 1548 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 1549 | |
michael@0 | 1550 | // We should be removed from all these lists in ActorDestroy. |
michael@0 | 1551 | MOZ_ASSERT(!sPrivateContent || !sPrivateContent->Contains(this)); |
michael@0 | 1552 | if (mAppManifestURL.IsEmpty()) { |
michael@0 | 1553 | MOZ_ASSERT(!sNonAppContentParents || |
michael@0 | 1554 | !sNonAppContentParents->Contains(this)); |
michael@0 | 1555 | } else { |
michael@0 | 1556 | // In general, we expect sAppContentParents->Get(mAppManifestURL) to be |
michael@0 | 1557 | // nullptr. But it could be that we created another ContentParent for |
michael@0 | 1558 | // this app after we did this->ActorDestroy(), so the right check is |
michael@0 | 1559 | // that sAppContentParents->Get(mAppManifestURL) != this. |
michael@0 | 1560 | MOZ_ASSERT(!sAppContentParents || |
michael@0 | 1561 | sAppContentParents->Get(mAppManifestURL) != this); |
michael@0 | 1562 | } |
michael@0 | 1563 | } |
michael@0 | 1564 | |
michael@0 | 1565 | void |
michael@0 | 1566 | ContentParent::InitInternal(ProcessPriority aInitialPriority, |
michael@0 | 1567 | bool aSetupOffMainThreadCompositing, |
michael@0 | 1568 | bool aSendRegisteredChrome) |
michael@0 | 1569 | { |
michael@0 | 1570 | // Set the subprocess's priority. We do this early on because we're likely |
michael@0 | 1571 | // /lowering/ the process's CPU and memory priority, which it has inherited |
michael@0 | 1572 | // from this process. |
michael@0 | 1573 | // |
michael@0 | 1574 | // This call can cause us to send IPC messages to the child process, so it |
michael@0 | 1575 | // must come after the Open() call above. |
michael@0 | 1576 | ProcessPriorityManager::SetProcessPriority(this, aInitialPriority); |
michael@0 | 1577 | |
michael@0 | 1578 | if (aSetupOffMainThreadCompositing) { |
michael@0 | 1579 | // NB: internally, this will send an IPC message to the child |
michael@0 | 1580 | // process to get it to create the CompositorChild. This |
michael@0 | 1581 | // message goes through the regular IPC queue for this |
michael@0 | 1582 | // channel, so delivery will happen-before any other messages |
michael@0 | 1583 | // we send. The CompositorChild must be created before any |
michael@0 | 1584 | // PBrowsers are created, because they rely on the Compositor |
michael@0 | 1585 | // already being around. (Creation is async, so can't happen |
michael@0 | 1586 | // on demand.) |
michael@0 | 1587 | bool useOffMainThreadCompositing = !!CompositorParent::CompositorLoop(); |
michael@0 | 1588 | if (useOffMainThreadCompositing) { |
michael@0 | 1589 | DebugOnly<bool> opened = PCompositor::Open(this); |
michael@0 | 1590 | MOZ_ASSERT(opened); |
michael@0 | 1591 | |
michael@0 | 1592 | if (gfxPrefs::AsyncVideoEnabled()) { |
michael@0 | 1593 | opened = PImageBridge::Open(this); |
michael@0 | 1594 | MOZ_ASSERT(opened); |
michael@0 | 1595 | } |
michael@0 | 1596 | } |
michael@0 | 1597 | } |
michael@0 | 1598 | |
michael@0 | 1599 | if (aSendRegisteredChrome) { |
michael@0 | 1600 | nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService(); |
michael@0 | 1601 | nsChromeRegistryChrome* chromeRegistry = |
michael@0 | 1602 | static_cast<nsChromeRegistryChrome*>(registrySvc.get()); |
michael@0 | 1603 | chromeRegistry->SendRegisteredChrome(this); |
michael@0 | 1604 | } |
michael@0 | 1605 | |
michael@0 | 1606 | mMessageManager = nsFrameMessageManager::NewProcessMessageManager(this); |
michael@0 | 1607 | |
michael@0 | 1608 | if (gAppData) { |
michael@0 | 1609 | nsCString version(gAppData->version); |
michael@0 | 1610 | nsCString buildID(gAppData->buildID); |
michael@0 | 1611 | nsCString name(gAppData->name); |
michael@0 | 1612 | nsCString UAName(gAppData->UAName); |
michael@0 | 1613 | |
michael@0 | 1614 | // Sending all information to content process. |
michael@0 | 1615 | unused << SendAppInfo(version, buildID, name, UAName); |
michael@0 | 1616 | } |
michael@0 | 1617 | |
michael@0 | 1618 | nsStyleSheetService *sheetService = nsStyleSheetService::GetInstance(); |
michael@0 | 1619 | if (sheetService) { |
michael@0 | 1620 | // This looks like a lot of work, but in a normal browser session we just |
michael@0 | 1621 | // send two loads. |
michael@0 | 1622 | |
michael@0 | 1623 | nsCOMArray<nsIStyleSheet>& agentSheets = *sheetService->AgentStyleSheets(); |
michael@0 | 1624 | for (uint32_t i = 0; i < agentSheets.Length(); i++) { |
michael@0 | 1625 | URIParams uri; |
michael@0 | 1626 | SerializeURI(agentSheets[i]->GetSheetURI(), uri); |
michael@0 | 1627 | unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::AGENT_SHEET); |
michael@0 | 1628 | } |
michael@0 | 1629 | |
michael@0 | 1630 | nsCOMArray<nsIStyleSheet>& userSheets = *sheetService->UserStyleSheets(); |
michael@0 | 1631 | for (uint32_t i = 0; i < userSheets.Length(); i++) { |
michael@0 | 1632 | URIParams uri; |
michael@0 | 1633 | SerializeURI(userSheets[i]->GetSheetURI(), uri); |
michael@0 | 1634 | unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::USER_SHEET); |
michael@0 | 1635 | } |
michael@0 | 1636 | |
michael@0 | 1637 | nsCOMArray<nsIStyleSheet>& authorSheets = *sheetService->AuthorStyleSheets(); |
michael@0 | 1638 | for (uint32_t i = 0; i < authorSheets.Length(); i++) { |
michael@0 | 1639 | URIParams uri; |
michael@0 | 1640 | SerializeURI(authorSheets[i]->GetSheetURI(), uri); |
michael@0 | 1641 | unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::AUTHOR_SHEET); |
michael@0 | 1642 | } |
michael@0 | 1643 | } |
michael@0 | 1644 | |
michael@0 | 1645 | #ifdef MOZ_CONTENT_SANDBOX |
michael@0 | 1646 | bool shouldSandbox = true; |
michael@0 | 1647 | #ifdef MOZ_NUWA_PROCESS |
michael@0 | 1648 | if (IsNuwaProcess()) { |
michael@0 | 1649 | shouldSandbox = false; |
michael@0 | 1650 | } |
michael@0 | 1651 | #endif |
michael@0 | 1652 | if (shouldSandbox && !SendSetProcessSandbox()) { |
michael@0 | 1653 | KillHard(); |
michael@0 | 1654 | } |
michael@0 | 1655 | #endif |
michael@0 | 1656 | } |
michael@0 | 1657 | |
michael@0 | 1658 | bool |
michael@0 | 1659 | ContentParent::IsAlive() |
michael@0 | 1660 | { |
michael@0 | 1661 | return mIsAlive; |
michael@0 | 1662 | } |
michael@0 | 1663 | |
michael@0 | 1664 | bool |
michael@0 | 1665 | ContentParent::IsForApp() |
michael@0 | 1666 | { |
michael@0 | 1667 | return !mAppManifestURL.IsEmpty(); |
michael@0 | 1668 | } |
michael@0 | 1669 | |
michael@0 | 1670 | #ifdef MOZ_NUWA_PROCESS |
michael@0 | 1671 | bool |
michael@0 | 1672 | ContentParent::IsNuwaProcess() |
michael@0 | 1673 | { |
michael@0 | 1674 | return mIsNuwaProcess; |
michael@0 | 1675 | } |
michael@0 | 1676 | #endif |
michael@0 | 1677 | |
michael@0 | 1678 | int32_t |
michael@0 | 1679 | ContentParent::Pid() |
michael@0 | 1680 | { |
michael@0 | 1681 | if (!mSubprocess || !mSubprocess->GetChildProcessHandle()) { |
michael@0 | 1682 | return -1; |
michael@0 | 1683 | } |
michael@0 | 1684 | return base::GetProcId(mSubprocess->GetChildProcessHandle()); |
michael@0 | 1685 | } |
michael@0 | 1686 | |
michael@0 | 1687 | bool |
michael@0 | 1688 | ContentParent::RecvReadPrefsArray(InfallibleTArray<PrefSetting>* aPrefs) |
michael@0 | 1689 | { |
michael@0 | 1690 | Preferences::GetPreferences(aPrefs); |
michael@0 | 1691 | return true; |
michael@0 | 1692 | } |
michael@0 | 1693 | |
michael@0 | 1694 | bool |
michael@0 | 1695 | ContentParent::RecvReadFontList(InfallibleTArray<FontListEntry>* retValue) |
michael@0 | 1696 | { |
michael@0 | 1697 | #ifdef ANDROID |
michael@0 | 1698 | gfxAndroidPlatform::GetPlatform()->GetFontList(retValue); |
michael@0 | 1699 | #endif |
michael@0 | 1700 | return true; |
michael@0 | 1701 | } |
michael@0 | 1702 | |
michael@0 | 1703 | bool |
michael@0 | 1704 | ContentParent::RecvReadPermissions(InfallibleTArray<IPC::Permission>* aPermissions) |
michael@0 | 1705 | { |
michael@0 | 1706 | #ifdef MOZ_PERMISSIONS |
michael@0 | 1707 | nsCOMPtr<nsIPermissionManager> permissionManagerIface = |
michael@0 | 1708 | do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); |
michael@0 | 1709 | nsPermissionManager* permissionManager = |
michael@0 | 1710 | static_cast<nsPermissionManager*>(permissionManagerIface.get()); |
michael@0 | 1711 | NS_ABORT_IF_FALSE(permissionManager, |
michael@0 | 1712 | "We have no permissionManager in the Chrome process !"); |
michael@0 | 1713 | |
michael@0 | 1714 | nsCOMPtr<nsISimpleEnumerator> enumerator; |
michael@0 | 1715 | DebugOnly<nsresult> rv = permissionManager->GetEnumerator(getter_AddRefs(enumerator)); |
michael@0 | 1716 | NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "Could not get enumerator!"); |
michael@0 | 1717 | while(1) { |
michael@0 | 1718 | bool hasMore; |
michael@0 | 1719 | enumerator->HasMoreElements(&hasMore); |
michael@0 | 1720 | if (!hasMore) |
michael@0 | 1721 | break; |
michael@0 | 1722 | |
michael@0 | 1723 | nsCOMPtr<nsISupports> supp; |
michael@0 | 1724 | enumerator->GetNext(getter_AddRefs(supp)); |
michael@0 | 1725 | nsCOMPtr<nsIPermission> perm = do_QueryInterface(supp); |
michael@0 | 1726 | |
michael@0 | 1727 | nsCString host; |
michael@0 | 1728 | perm->GetHost(host); |
michael@0 | 1729 | uint32_t appId; |
michael@0 | 1730 | perm->GetAppId(&appId); |
michael@0 | 1731 | bool isInBrowserElement; |
michael@0 | 1732 | perm->GetIsInBrowserElement(&isInBrowserElement); |
michael@0 | 1733 | nsCString type; |
michael@0 | 1734 | perm->GetType(type); |
michael@0 | 1735 | uint32_t capability; |
michael@0 | 1736 | perm->GetCapability(&capability); |
michael@0 | 1737 | uint32_t expireType; |
michael@0 | 1738 | perm->GetExpireType(&expireType); |
michael@0 | 1739 | int64_t expireTime; |
michael@0 | 1740 | perm->GetExpireTime(&expireTime); |
michael@0 | 1741 | |
michael@0 | 1742 | aPermissions->AppendElement(IPC::Permission(host, appId, |
michael@0 | 1743 | isInBrowserElement, type, |
michael@0 | 1744 | capability, expireType, |
michael@0 | 1745 | expireTime)); |
michael@0 | 1746 | } |
michael@0 | 1747 | |
michael@0 | 1748 | // Ask for future changes |
michael@0 | 1749 | mSendPermissionUpdates = true; |
michael@0 | 1750 | #endif |
michael@0 | 1751 | |
michael@0 | 1752 | return true; |
michael@0 | 1753 | } |
michael@0 | 1754 | |
michael@0 | 1755 | bool |
michael@0 | 1756 | ContentParent::RecvSetClipboardText(const nsString& text, |
michael@0 | 1757 | const bool& isPrivateData, |
michael@0 | 1758 | const int32_t& whichClipboard) |
michael@0 | 1759 | { |
michael@0 | 1760 | nsresult rv; |
michael@0 | 1761 | nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv)); |
michael@0 | 1762 | NS_ENSURE_SUCCESS(rv, true); |
michael@0 | 1763 | |
michael@0 | 1764 | nsCOMPtr<nsISupportsString> dataWrapper = |
michael@0 | 1765 | do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv); |
michael@0 | 1766 | NS_ENSURE_SUCCESS(rv, true); |
michael@0 | 1767 | |
michael@0 | 1768 | rv = dataWrapper->SetData(text); |
michael@0 | 1769 | NS_ENSURE_SUCCESS(rv, true); |
michael@0 | 1770 | |
michael@0 | 1771 | nsCOMPtr<nsITransferable> trans = do_CreateInstance("@mozilla.org/widget/transferable;1", &rv); |
michael@0 | 1772 | NS_ENSURE_SUCCESS(rv, true); |
michael@0 | 1773 | trans->Init(nullptr); |
michael@0 | 1774 | |
michael@0 | 1775 | // If our data flavor has already been added, this will fail. But we don't care |
michael@0 | 1776 | trans->AddDataFlavor(kUnicodeMime); |
michael@0 | 1777 | trans->SetIsPrivateData(isPrivateData); |
michael@0 | 1778 | |
michael@0 | 1779 | nsCOMPtr<nsISupports> nsisupportsDataWrapper = |
michael@0 | 1780 | do_QueryInterface(dataWrapper); |
michael@0 | 1781 | |
michael@0 | 1782 | rv = trans->SetTransferData(kUnicodeMime, nsisupportsDataWrapper, |
michael@0 | 1783 | text.Length() * sizeof(char16_t)); |
michael@0 | 1784 | NS_ENSURE_SUCCESS(rv, true); |
michael@0 | 1785 | |
michael@0 | 1786 | clipboard->SetData(trans, nullptr, whichClipboard); |
michael@0 | 1787 | return true; |
michael@0 | 1788 | } |
michael@0 | 1789 | |
michael@0 | 1790 | bool |
michael@0 | 1791 | ContentParent::RecvGetClipboardText(const int32_t& whichClipboard, nsString* text) |
michael@0 | 1792 | { |
michael@0 | 1793 | nsresult rv; |
michael@0 | 1794 | nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv)); |
michael@0 | 1795 | NS_ENSURE_SUCCESS(rv, true); |
michael@0 | 1796 | |
michael@0 | 1797 | nsCOMPtr<nsITransferable> trans = do_CreateInstance("@mozilla.org/widget/transferable;1", &rv); |
michael@0 | 1798 | NS_ENSURE_SUCCESS(rv, true); |
michael@0 | 1799 | trans->Init(nullptr); |
michael@0 | 1800 | trans->AddDataFlavor(kUnicodeMime); |
michael@0 | 1801 | |
michael@0 | 1802 | clipboard->GetData(trans, whichClipboard); |
michael@0 | 1803 | nsCOMPtr<nsISupports> tmp; |
michael@0 | 1804 | uint32_t len; |
michael@0 | 1805 | rv = trans->GetTransferData(kUnicodeMime, getter_AddRefs(tmp), &len); |
michael@0 | 1806 | if (NS_FAILED(rv)) |
michael@0 | 1807 | return true; |
michael@0 | 1808 | |
michael@0 | 1809 | nsCOMPtr<nsISupportsString> supportsString = do_QueryInterface(tmp); |
michael@0 | 1810 | // No support for non-text data |
michael@0 | 1811 | if (!supportsString) |
michael@0 | 1812 | return true; |
michael@0 | 1813 | supportsString->GetData(*text); |
michael@0 | 1814 | return true; |
michael@0 | 1815 | } |
michael@0 | 1816 | |
michael@0 | 1817 | bool |
michael@0 | 1818 | ContentParent::RecvEmptyClipboard(const int32_t& whichClipboard) |
michael@0 | 1819 | { |
michael@0 | 1820 | nsresult rv; |
michael@0 | 1821 | nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv)); |
michael@0 | 1822 | NS_ENSURE_SUCCESS(rv, true); |
michael@0 | 1823 | |
michael@0 | 1824 | clipboard->EmptyClipboard(whichClipboard); |
michael@0 | 1825 | |
michael@0 | 1826 | return true; |
michael@0 | 1827 | } |
michael@0 | 1828 | |
michael@0 | 1829 | bool |
michael@0 | 1830 | ContentParent::RecvClipboardHasText(const int32_t& whichClipboard, bool* hasText) |
michael@0 | 1831 | { |
michael@0 | 1832 | nsresult rv; |
michael@0 | 1833 | nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv)); |
michael@0 | 1834 | NS_ENSURE_SUCCESS(rv, true); |
michael@0 | 1835 | |
michael@0 | 1836 | clipboard->HasDataMatchingFlavors(sClipboardTextFlavors, 1, |
michael@0 | 1837 | whichClipboard, hasText); |
michael@0 | 1838 | return true; |
michael@0 | 1839 | } |
michael@0 | 1840 | |
michael@0 | 1841 | bool |
michael@0 | 1842 | ContentParent::RecvGetSystemColors(const uint32_t& colorsCount, InfallibleTArray<uint32_t>* colors) |
michael@0 | 1843 | { |
michael@0 | 1844 | #ifdef MOZ_WIDGET_ANDROID |
michael@0 | 1845 | NS_ASSERTION(AndroidBridge::Bridge() != nullptr, "AndroidBridge is not available"); |
michael@0 | 1846 | if (AndroidBridge::Bridge() == nullptr) { |
michael@0 | 1847 | // Do not fail - the colors won't be right, but it's not critical |
michael@0 | 1848 | return true; |
michael@0 | 1849 | } |
michael@0 | 1850 | |
michael@0 | 1851 | colors->AppendElements(colorsCount); |
michael@0 | 1852 | |
michael@0 | 1853 | // The array elements correspond to the members of AndroidSystemColors structure, |
michael@0 | 1854 | // so just pass the pointer to the elements buffer |
michael@0 | 1855 | AndroidBridge::Bridge()->GetSystemColors((AndroidSystemColors*)colors->Elements()); |
michael@0 | 1856 | #endif |
michael@0 | 1857 | return true; |
michael@0 | 1858 | } |
michael@0 | 1859 | |
michael@0 | 1860 | bool |
michael@0 | 1861 | ContentParent::RecvGetIconForExtension(const nsCString& aFileExt, const uint32_t& aIconSize, InfallibleTArray<uint8_t>* bits) |
michael@0 | 1862 | { |
michael@0 | 1863 | #ifdef MOZ_WIDGET_ANDROID |
michael@0 | 1864 | NS_ASSERTION(AndroidBridge::Bridge() != nullptr, "AndroidBridge is not available"); |
michael@0 | 1865 | if (AndroidBridge::Bridge() == nullptr) { |
michael@0 | 1866 | // Do not fail - just no icon will be shown |
michael@0 | 1867 | return true; |
michael@0 | 1868 | } |
michael@0 | 1869 | |
michael@0 | 1870 | bits->AppendElements(aIconSize * aIconSize * 4); |
michael@0 | 1871 | |
michael@0 | 1872 | AndroidBridge::Bridge()->GetIconForExtension(aFileExt, aIconSize, bits->Elements()); |
michael@0 | 1873 | #endif |
michael@0 | 1874 | return true; |
michael@0 | 1875 | } |
michael@0 | 1876 | |
michael@0 | 1877 | bool |
michael@0 | 1878 | ContentParent::RecvGetShowPasswordSetting(bool* showPassword) |
michael@0 | 1879 | { |
michael@0 | 1880 | // default behavior is to show the last password character |
michael@0 | 1881 | *showPassword = true; |
michael@0 | 1882 | #ifdef MOZ_WIDGET_ANDROID |
michael@0 | 1883 | NS_ASSERTION(AndroidBridge::Bridge() != nullptr, "AndroidBridge is not available"); |
michael@0 | 1884 | |
michael@0 | 1885 | *showPassword = mozilla::widget::android::GeckoAppShell::GetShowPasswordSetting(); |
michael@0 | 1886 | #endif |
michael@0 | 1887 | return true; |
michael@0 | 1888 | } |
michael@0 | 1889 | |
michael@0 | 1890 | bool |
michael@0 | 1891 | ContentParent::RecvFirstIdle() |
michael@0 | 1892 | { |
michael@0 | 1893 | // When the ContentChild goes idle, it sends us a FirstIdle message |
michael@0 | 1894 | // which we use as a good time to prelaunch another process. If we |
michael@0 | 1895 | // prelaunch any sooner than this, then we'll be competing with the |
michael@0 | 1896 | // child process and slowing it down. |
michael@0 | 1897 | PreallocatedProcessManager::AllocateAfterDelay(); |
michael@0 | 1898 | return true; |
michael@0 | 1899 | } |
michael@0 | 1900 | |
michael@0 | 1901 | bool |
michael@0 | 1902 | ContentParent::RecvAudioChannelGetState(const AudioChannel& aChannel, |
michael@0 | 1903 | const bool& aElementHidden, |
michael@0 | 1904 | const bool& aElementWasHidden, |
michael@0 | 1905 | AudioChannelState* aState) |
michael@0 | 1906 | { |
michael@0 | 1907 | nsRefPtr<AudioChannelService> service = |
michael@0 | 1908 | AudioChannelService::GetAudioChannelService(); |
michael@0 | 1909 | *aState = AUDIO_CHANNEL_STATE_NORMAL; |
michael@0 | 1910 | if (service) { |
michael@0 | 1911 | *aState = service->GetStateInternal(aChannel, mChildID, |
michael@0 | 1912 | aElementHidden, aElementWasHidden); |
michael@0 | 1913 | } |
michael@0 | 1914 | return true; |
michael@0 | 1915 | } |
michael@0 | 1916 | |
michael@0 | 1917 | bool |
michael@0 | 1918 | ContentParent::RecvAudioChannelRegisterType(const AudioChannel& aChannel, |
michael@0 | 1919 | const bool& aWithVideo) |
michael@0 | 1920 | { |
michael@0 | 1921 | nsRefPtr<AudioChannelService> service = |
michael@0 | 1922 | AudioChannelService::GetAudioChannelService(); |
michael@0 | 1923 | if (service) { |
michael@0 | 1924 | service->RegisterType(aChannel, mChildID, aWithVideo); |
michael@0 | 1925 | } |
michael@0 | 1926 | return true; |
michael@0 | 1927 | } |
michael@0 | 1928 | |
michael@0 | 1929 | bool |
michael@0 | 1930 | ContentParent::RecvAudioChannelUnregisterType(const AudioChannel& aChannel, |
michael@0 | 1931 | const bool& aElementHidden, |
michael@0 | 1932 | const bool& aWithVideo) |
michael@0 | 1933 | { |
michael@0 | 1934 | nsRefPtr<AudioChannelService> service = |
michael@0 | 1935 | AudioChannelService::GetAudioChannelService(); |
michael@0 | 1936 | if (service) { |
michael@0 | 1937 | service->UnregisterType(aChannel, aElementHidden, mChildID, aWithVideo); |
michael@0 | 1938 | } |
michael@0 | 1939 | return true; |
michael@0 | 1940 | } |
michael@0 | 1941 | |
michael@0 | 1942 | bool |
michael@0 | 1943 | ContentParent::RecvAudioChannelChangedNotification() |
michael@0 | 1944 | { |
michael@0 | 1945 | nsRefPtr<AudioChannelService> service = |
michael@0 | 1946 | AudioChannelService::GetAudioChannelService(); |
michael@0 | 1947 | if (service) { |
michael@0 | 1948 | service->SendAudioChannelChangedNotification(ChildID()); |
michael@0 | 1949 | } |
michael@0 | 1950 | return true; |
michael@0 | 1951 | } |
michael@0 | 1952 | |
michael@0 | 1953 | bool |
michael@0 | 1954 | ContentParent::RecvAudioChannelChangeDefVolChannel(const int32_t& aChannel, |
michael@0 | 1955 | const bool& aHidden) |
michael@0 | 1956 | { |
michael@0 | 1957 | nsRefPtr<AudioChannelService> service = |
michael@0 | 1958 | AudioChannelService::GetAudioChannelService(); |
michael@0 | 1959 | if (service) { |
michael@0 | 1960 | service->SetDefaultVolumeControlChannelInternal(aChannel, |
michael@0 | 1961 | aHidden, mChildID); |
michael@0 | 1962 | } |
michael@0 | 1963 | return true; |
michael@0 | 1964 | } |
michael@0 | 1965 | |
michael@0 | 1966 | bool |
michael@0 | 1967 | ContentParent::RecvBroadcastVolume(const nsString& aVolumeName) |
michael@0 | 1968 | { |
michael@0 | 1969 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 1970 | nsresult rv; |
michael@0 | 1971 | nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID, &rv); |
michael@0 | 1972 | if (vs) { |
michael@0 | 1973 | vs->BroadcastVolume(aVolumeName); |
michael@0 | 1974 | } |
michael@0 | 1975 | return true; |
michael@0 | 1976 | #else |
michael@0 | 1977 | NS_WARNING("ContentParent::RecvBroadcastVolume shouldn't be called when MOZ_WIDGET_GONK is not defined"); |
michael@0 | 1978 | return false; |
michael@0 | 1979 | #endif |
michael@0 | 1980 | } |
michael@0 | 1981 | |
michael@0 | 1982 | bool |
michael@0 | 1983 | ContentParent::RecvNuwaReady() |
michael@0 | 1984 | { |
michael@0 | 1985 | #ifdef MOZ_NUWA_PROCESS |
michael@0 | 1986 | if (!IsNuwaProcess()) { |
michael@0 | 1987 | NS_ERROR( |
michael@0 | 1988 | nsPrintfCString( |
michael@0 | 1989 | "Terminating child process %d for unauthorized IPC message: NuwaReady", |
michael@0 | 1990 | Pid()).get()); |
michael@0 | 1991 | |
michael@0 | 1992 | KillHard(); |
michael@0 | 1993 | return false; |
michael@0 | 1994 | } |
michael@0 | 1995 | PreallocatedProcessManager::OnNuwaReady(); |
michael@0 | 1996 | return true; |
michael@0 | 1997 | #else |
michael@0 | 1998 | NS_ERROR("ContentParent::RecvNuwaReady() not implemented!"); |
michael@0 | 1999 | return false; |
michael@0 | 2000 | #endif |
michael@0 | 2001 | } |
michael@0 | 2002 | |
michael@0 | 2003 | bool |
michael@0 | 2004 | ContentParent::RecvAddNewProcess(const uint32_t& aPid, |
michael@0 | 2005 | const InfallibleTArray<ProtocolFdMapping>& aFds) |
michael@0 | 2006 | { |
michael@0 | 2007 | #ifdef MOZ_NUWA_PROCESS |
michael@0 | 2008 | if (!IsNuwaProcess()) { |
michael@0 | 2009 | NS_ERROR( |
michael@0 | 2010 | nsPrintfCString( |
michael@0 | 2011 | "Terminating child process %d for unauthorized IPC message: " |
michael@0 | 2012 | "AddNewProcess(%d)", Pid(), aPid).get()); |
michael@0 | 2013 | |
michael@0 | 2014 | KillHard(); |
michael@0 | 2015 | return false; |
michael@0 | 2016 | } |
michael@0 | 2017 | nsRefPtr<ContentParent> content; |
michael@0 | 2018 | content = new ContentParent(this, |
michael@0 | 2019 | MAGIC_PREALLOCATED_APP_MANIFEST_URL, |
michael@0 | 2020 | aPid, |
michael@0 | 2021 | aFds); |
michael@0 | 2022 | content->Init(); |
michael@0 | 2023 | PreallocatedProcessManager::PublishSpareProcess(content); |
michael@0 | 2024 | return true; |
michael@0 | 2025 | #else |
michael@0 | 2026 | NS_ERROR("ContentParent::RecvAddNewProcess() not implemented!"); |
michael@0 | 2027 | return false; |
michael@0 | 2028 | #endif |
michael@0 | 2029 | } |
michael@0 | 2030 | |
michael@0 | 2031 | // We want ContentParent to show up in CC logs for debugging purposes, but we |
michael@0 | 2032 | // don't actually cycle collect it. |
michael@0 | 2033 | NS_IMPL_CYCLE_COLLECTION_0(ContentParent) |
michael@0 | 2034 | |
michael@0 | 2035 | NS_IMPL_CYCLE_COLLECTING_ADDREF(ContentParent) |
michael@0 | 2036 | NS_IMPL_CYCLE_COLLECTING_RELEASE(ContentParent) |
michael@0 | 2037 | |
michael@0 | 2038 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ContentParent) |
michael@0 | 2039 | NS_INTERFACE_MAP_ENTRY(nsIObserver) |
michael@0 | 2040 | NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionCallback) |
michael@0 | 2041 | NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver) |
michael@0 | 2042 | NS_INTERFACE_MAP_END |
michael@0 | 2043 | |
michael@0 | 2044 | NS_IMETHODIMP |
michael@0 | 2045 | ContentParent::Observe(nsISupports* aSubject, |
michael@0 | 2046 | const char* aTopic, |
michael@0 | 2047 | const char16_t* aData) |
michael@0 | 2048 | { |
michael@0 | 2049 | if (!strcmp(aTopic, "xpcom-shutdown") && mSubprocess) { |
michael@0 | 2050 | ShutDownProcess(/* closeWithError */ false); |
michael@0 | 2051 | NS_ASSERTION(!mSubprocess, "Close should have nulled mSubprocess"); |
michael@0 | 2052 | } |
michael@0 | 2053 | |
michael@0 | 2054 | if (!mIsAlive || !mSubprocess) |
michael@0 | 2055 | return NS_OK; |
michael@0 | 2056 | |
michael@0 | 2057 | // listening for memory pressure event |
michael@0 | 2058 | if (!strcmp(aTopic, "memory-pressure") && |
michael@0 | 2059 | !StringEndsWith(nsDependentString(aData), |
michael@0 | 2060 | NS_LITERAL_STRING("-no-forward"))) { |
michael@0 | 2061 | unused << SendFlushMemory(nsDependentString(aData)); |
michael@0 | 2062 | } |
michael@0 | 2063 | // listening for remotePrefs... |
michael@0 | 2064 | else if (!strcmp(aTopic, "nsPref:changed")) { |
michael@0 | 2065 | // We know prefs are ASCII here. |
michael@0 | 2066 | NS_LossyConvertUTF16toASCII strData(aData); |
michael@0 | 2067 | |
michael@0 | 2068 | PrefSetting pref(strData, null_t(), null_t()); |
michael@0 | 2069 | Preferences::GetPreference(&pref); |
michael@0 | 2070 | if (!SendPreferenceUpdate(pref)) { |
michael@0 | 2071 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 2072 | } |
michael@0 | 2073 | } |
michael@0 | 2074 | else if (!strcmp(aTopic, NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC)) { |
michael@0 | 2075 | NS_ConvertUTF16toUTF8 dataStr(aData); |
michael@0 | 2076 | const char *offline = dataStr.get(); |
michael@0 | 2077 | if (!SendSetOffline(!strcmp(offline, "true") ? true : false)) |
michael@0 | 2078 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 2079 | } |
michael@0 | 2080 | // listening for alert notifications |
michael@0 | 2081 | else if (!strcmp(aTopic, "alertfinished") || |
michael@0 | 2082 | !strcmp(aTopic, "alertclickcallback") || |
michael@0 | 2083 | !strcmp(aTopic, "alertshow") ) { |
michael@0 | 2084 | if (!SendNotifyAlertsObserver(nsDependentCString(aTopic), |
michael@0 | 2085 | nsDependentString(aData))) |
michael@0 | 2086 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 2087 | } |
michael@0 | 2088 | else if (!strcmp(aTopic, "child-memory-reporter-request")) { |
michael@0 | 2089 | bool isNuwa = false; |
michael@0 | 2090 | #ifdef MOZ_NUWA_PROCESS |
michael@0 | 2091 | isNuwa = IsNuwaProcess(); |
michael@0 | 2092 | #endif |
michael@0 | 2093 | if (!isNuwa) { |
michael@0 | 2094 | unsigned generation; |
michael@0 | 2095 | int minimize, identOffset = -1; |
michael@0 | 2096 | nsDependentString msg(aData); |
michael@0 | 2097 | NS_ConvertUTF16toUTF8 cmsg(msg); |
michael@0 | 2098 | |
michael@0 | 2099 | if (sscanf(cmsg.get(), |
michael@0 | 2100 | "generation=%x minimize=%d DMDident=%n", |
michael@0 | 2101 | &generation, &minimize, &identOffset) < 2 |
michael@0 | 2102 | || identOffset < 0) { |
michael@0 | 2103 | return NS_ERROR_INVALID_ARG; |
michael@0 | 2104 | } |
michael@0 | 2105 | // The pre-%n part of the string should be all ASCII, so the byte |
michael@0 | 2106 | // offset in identOffset should be correct as a char offset. |
michael@0 | 2107 | MOZ_ASSERT(cmsg[identOffset - 1] == '='); |
michael@0 | 2108 | unused << SendPMemoryReportRequestConstructor( |
michael@0 | 2109 | generation, minimize, nsString(Substring(msg, identOffset))); |
michael@0 | 2110 | } |
michael@0 | 2111 | } |
michael@0 | 2112 | else if (!strcmp(aTopic, "child-gc-request")){ |
michael@0 | 2113 | unused << SendGarbageCollect(); |
michael@0 | 2114 | } |
michael@0 | 2115 | else if (!strcmp(aTopic, "child-cc-request")){ |
michael@0 | 2116 | unused << SendCycleCollect(); |
michael@0 | 2117 | } |
michael@0 | 2118 | else if (!strcmp(aTopic, "child-mmu-request")){ |
michael@0 | 2119 | unused << SendMinimizeMemoryUsage(); |
michael@0 | 2120 | } |
michael@0 | 2121 | else if (!strcmp(aTopic, "last-pb-context-exited")) { |
michael@0 | 2122 | unused << SendLastPrivateDocShellDestroyed(); |
michael@0 | 2123 | } |
michael@0 | 2124 | else if (!strcmp(aTopic, "file-watcher-update")) { |
michael@0 | 2125 | nsCString creason; |
michael@0 | 2126 | CopyUTF16toUTF8(aData, creason); |
michael@0 | 2127 | DeviceStorageFile* file = static_cast<DeviceStorageFile*>(aSubject); |
michael@0 | 2128 | |
michael@0 | 2129 | unused << SendFilePathUpdate(file->mStorageType, file->mStorageName, file->mPath, creason); |
michael@0 | 2130 | } |
michael@0 | 2131 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 2132 | else if(!strcmp(aTopic, NS_VOLUME_STATE_CHANGED)) { |
michael@0 | 2133 | nsCOMPtr<nsIVolume> vol = do_QueryInterface(aSubject); |
michael@0 | 2134 | if (!vol) { |
michael@0 | 2135 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 2136 | } |
michael@0 | 2137 | |
michael@0 | 2138 | nsString volName; |
michael@0 | 2139 | nsString mountPoint; |
michael@0 | 2140 | int32_t state; |
michael@0 | 2141 | int32_t mountGeneration; |
michael@0 | 2142 | bool isMediaPresent; |
michael@0 | 2143 | bool isSharing; |
michael@0 | 2144 | bool isFormatting; |
michael@0 | 2145 | |
michael@0 | 2146 | vol->GetName(volName); |
michael@0 | 2147 | vol->GetMountPoint(mountPoint); |
michael@0 | 2148 | vol->GetState(&state); |
michael@0 | 2149 | vol->GetMountGeneration(&mountGeneration); |
michael@0 | 2150 | vol->GetIsMediaPresent(&isMediaPresent); |
michael@0 | 2151 | vol->GetIsSharing(&isSharing); |
michael@0 | 2152 | vol->GetIsFormatting(&isFormatting); |
michael@0 | 2153 | |
michael@0 | 2154 | unused << SendFileSystemUpdate(volName, mountPoint, state, |
michael@0 | 2155 | mountGeneration, isMediaPresent, |
michael@0 | 2156 | isSharing, isFormatting); |
michael@0 | 2157 | } else if (!strcmp(aTopic, "phone-state-changed")) { |
michael@0 | 2158 | nsString state(aData); |
michael@0 | 2159 | unused << SendNotifyPhoneStateChange(state); |
michael@0 | 2160 | } |
michael@0 | 2161 | #endif |
michael@0 | 2162 | #ifdef ACCESSIBILITY |
michael@0 | 2163 | // Make sure accessibility is running in content process when accessibility |
michael@0 | 2164 | // gets initiated in chrome process. |
michael@0 | 2165 | else if (aData && (*aData == '1') && |
michael@0 | 2166 | !strcmp(aTopic, "a11y-init-or-shutdown")) { |
michael@0 | 2167 | unused << SendActivateA11y(); |
michael@0 | 2168 | } |
michael@0 | 2169 | #endif |
michael@0 | 2170 | |
michael@0 | 2171 | return NS_OK; |
michael@0 | 2172 | } |
michael@0 | 2173 | |
michael@0 | 2174 | PCompositorParent* |
michael@0 | 2175 | ContentParent::AllocPCompositorParent(mozilla::ipc::Transport* aTransport, |
michael@0 | 2176 | base::ProcessId aOtherProcess) |
michael@0 | 2177 | { |
michael@0 | 2178 | return CompositorParent::Create(aTransport, aOtherProcess); |
michael@0 | 2179 | } |
michael@0 | 2180 | |
michael@0 | 2181 | PImageBridgeParent* |
michael@0 | 2182 | ContentParent::AllocPImageBridgeParent(mozilla::ipc::Transport* aTransport, |
michael@0 | 2183 | base::ProcessId aOtherProcess) |
michael@0 | 2184 | { |
michael@0 | 2185 | return ImageBridgeParent::Create(aTransport, aOtherProcess); |
michael@0 | 2186 | } |
michael@0 | 2187 | |
michael@0 | 2188 | PBackgroundParent* |
michael@0 | 2189 | ContentParent::AllocPBackgroundParent(Transport* aTransport, |
michael@0 | 2190 | ProcessId aOtherProcess) |
michael@0 | 2191 | { |
michael@0 | 2192 | return BackgroundParent::Alloc(this, aTransport, aOtherProcess); |
michael@0 | 2193 | } |
michael@0 | 2194 | |
michael@0 | 2195 | bool |
michael@0 | 2196 | ContentParent::RecvGetProcessAttributes(uint64_t* aId, |
michael@0 | 2197 | bool* aIsForApp, bool* aIsForBrowser) |
michael@0 | 2198 | { |
michael@0 | 2199 | *aId = mChildID; |
michael@0 | 2200 | *aIsForApp = IsForApp(); |
michael@0 | 2201 | *aIsForBrowser = mIsForBrowser; |
michael@0 | 2202 | |
michael@0 | 2203 | return true; |
michael@0 | 2204 | } |
michael@0 | 2205 | |
michael@0 | 2206 | bool |
michael@0 | 2207 | ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline) |
michael@0 | 2208 | { |
michael@0 | 2209 | nsCOMPtr<nsIIOService> io(do_GetIOService()); |
michael@0 | 2210 | NS_ASSERTION(io, "No IO service?"); |
michael@0 | 2211 | DebugOnly<nsresult> rv = io->GetOffline(aIsOffline); |
michael@0 | 2212 | NS_ASSERTION(NS_SUCCEEDED(rv), "Failed getting offline?"); |
michael@0 | 2213 | |
michael@0 | 2214 | return true; |
michael@0 | 2215 | } |
michael@0 | 2216 | |
michael@0 | 2217 | mozilla::jsipc::PJavaScriptParent * |
michael@0 | 2218 | ContentParent::AllocPJavaScriptParent() |
michael@0 | 2219 | { |
michael@0 | 2220 | mozilla::jsipc::JavaScriptParent *parent = new mozilla::jsipc::JavaScriptParent(); |
michael@0 | 2221 | if (!parent->init()) { |
michael@0 | 2222 | delete parent; |
michael@0 | 2223 | return nullptr; |
michael@0 | 2224 | } |
michael@0 | 2225 | return parent; |
michael@0 | 2226 | } |
michael@0 | 2227 | |
michael@0 | 2228 | bool |
michael@0 | 2229 | ContentParent::DeallocPJavaScriptParent(PJavaScriptParent *parent) |
michael@0 | 2230 | { |
michael@0 | 2231 | static_cast<mozilla::jsipc::JavaScriptParent *>(parent)->decref(); |
michael@0 | 2232 | return true; |
michael@0 | 2233 | } |
michael@0 | 2234 | |
michael@0 | 2235 | PBrowserParent* |
michael@0 | 2236 | ContentParent::AllocPBrowserParent(const IPCTabContext& aContext, |
michael@0 | 2237 | const uint32_t &aChromeFlags) |
michael@0 | 2238 | { |
michael@0 | 2239 | unused << aChromeFlags; |
michael@0 | 2240 | |
michael@0 | 2241 | const IPCTabAppBrowserContext& appBrowser = aContext.appBrowserContext(); |
michael@0 | 2242 | |
michael@0 | 2243 | // We don't trust the IPCTabContext we receive from the child, so we'll bail |
michael@0 | 2244 | // if we receive an IPCTabContext that's not a PopupIPCTabContext. |
michael@0 | 2245 | // (PopupIPCTabContext lets the child process prove that it has access to |
michael@0 | 2246 | // the app it's trying to open.) |
michael@0 | 2247 | if (appBrowser.type() != IPCTabAppBrowserContext::TPopupIPCTabContext) { |
michael@0 | 2248 | NS_ERROR("Unexpected IPCTabContext type. Aborting AllocPBrowserParent."); |
michael@0 | 2249 | return nullptr; |
michael@0 | 2250 | } |
michael@0 | 2251 | |
michael@0 | 2252 | const PopupIPCTabContext& popupContext = appBrowser.get_PopupIPCTabContext(); |
michael@0 | 2253 | TabParent* opener = static_cast<TabParent*>(popupContext.openerParent()); |
michael@0 | 2254 | if (!opener) { |
michael@0 | 2255 | NS_ERROR("Got null opener from child; aborting AllocPBrowserParent."); |
michael@0 | 2256 | return nullptr; |
michael@0 | 2257 | } |
michael@0 | 2258 | |
michael@0 | 2259 | // Popup windows of isBrowser frames must be isBrowser if the parent |
michael@0 | 2260 | // isBrowser. Allocating a !isBrowser frame with same app ID would allow |
michael@0 | 2261 | // the content to access data it's not supposed to. |
michael@0 | 2262 | if (!popupContext.isBrowserElement() && opener->IsBrowserElement()) { |
michael@0 | 2263 | NS_ERROR("Child trying to escalate privileges! Aborting AllocPBrowserParent."); |
michael@0 | 2264 | return nullptr; |
michael@0 | 2265 | } |
michael@0 | 2266 | |
michael@0 | 2267 | MaybeInvalidTabContext tc(aContext); |
michael@0 | 2268 | if (!tc.IsValid()) { |
michael@0 | 2269 | NS_ERROR(nsPrintfCString("Child passed us an invalid TabContext. (%s) " |
michael@0 | 2270 | "Aborting AllocPBrowserParent.", |
michael@0 | 2271 | tc.GetInvalidReason()).get()); |
michael@0 | 2272 | return nullptr; |
michael@0 | 2273 | } |
michael@0 | 2274 | |
michael@0 | 2275 | TabParent* parent = new TabParent(this, tc.GetTabContext(), aChromeFlags); |
michael@0 | 2276 | |
michael@0 | 2277 | // We release this ref in DeallocPBrowserParent() |
michael@0 | 2278 | NS_ADDREF(parent); |
michael@0 | 2279 | return parent; |
michael@0 | 2280 | } |
michael@0 | 2281 | |
michael@0 | 2282 | bool |
michael@0 | 2283 | ContentParent::DeallocPBrowserParent(PBrowserParent* frame) |
michael@0 | 2284 | { |
michael@0 | 2285 | TabParent* parent = static_cast<TabParent*>(frame); |
michael@0 | 2286 | NS_RELEASE(parent); |
michael@0 | 2287 | return true; |
michael@0 | 2288 | } |
michael@0 | 2289 | |
michael@0 | 2290 | PDeviceStorageRequestParent* |
michael@0 | 2291 | ContentParent::AllocPDeviceStorageRequestParent(const DeviceStorageParams& aParams) |
michael@0 | 2292 | { |
michael@0 | 2293 | nsRefPtr<DeviceStorageRequestParent> result = new DeviceStorageRequestParent(aParams); |
michael@0 | 2294 | if (!result->EnsureRequiredPermissions(this)) { |
michael@0 | 2295 | return nullptr; |
michael@0 | 2296 | } |
michael@0 | 2297 | result->Dispatch(); |
michael@0 | 2298 | return result.forget().take(); |
michael@0 | 2299 | } |
michael@0 | 2300 | |
michael@0 | 2301 | bool |
michael@0 | 2302 | ContentParent::DeallocPDeviceStorageRequestParent(PDeviceStorageRequestParent* doomed) |
michael@0 | 2303 | { |
michael@0 | 2304 | DeviceStorageRequestParent *parent = static_cast<DeviceStorageRequestParent*>(doomed); |
michael@0 | 2305 | NS_RELEASE(parent); |
michael@0 | 2306 | return true; |
michael@0 | 2307 | } |
michael@0 | 2308 | |
michael@0 | 2309 | PFileSystemRequestParent* |
michael@0 | 2310 | ContentParent::AllocPFileSystemRequestParent(const FileSystemParams& aParams) |
michael@0 | 2311 | { |
michael@0 | 2312 | nsRefPtr<FileSystemRequestParent> result = new FileSystemRequestParent(); |
michael@0 | 2313 | if (!result->Dispatch(this, aParams)) { |
michael@0 | 2314 | return nullptr; |
michael@0 | 2315 | } |
michael@0 | 2316 | return result.forget().take(); |
michael@0 | 2317 | } |
michael@0 | 2318 | |
michael@0 | 2319 | bool |
michael@0 | 2320 | ContentParent::DeallocPFileSystemRequestParent(PFileSystemRequestParent* doomed) |
michael@0 | 2321 | { |
michael@0 | 2322 | FileSystemRequestParent* parent = static_cast<FileSystemRequestParent*>(doomed); |
michael@0 | 2323 | NS_RELEASE(parent); |
michael@0 | 2324 | return true; |
michael@0 | 2325 | } |
michael@0 | 2326 | |
michael@0 | 2327 | PBlobParent* |
michael@0 | 2328 | ContentParent::AllocPBlobParent(const BlobConstructorParams& aParams) |
michael@0 | 2329 | { |
michael@0 | 2330 | return BlobParent::Create(this, aParams); |
michael@0 | 2331 | } |
michael@0 | 2332 | |
michael@0 | 2333 | bool |
michael@0 | 2334 | ContentParent::DeallocPBlobParent(PBlobParent* aActor) |
michael@0 | 2335 | { |
michael@0 | 2336 | delete aActor; |
michael@0 | 2337 | return true; |
michael@0 | 2338 | } |
michael@0 | 2339 | |
michael@0 | 2340 | BlobParent* |
michael@0 | 2341 | ContentParent::GetOrCreateActorForBlob(nsIDOMBlob* aBlob) |
michael@0 | 2342 | { |
michael@0 | 2343 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 2344 | MOZ_ASSERT(aBlob); |
michael@0 | 2345 | |
michael@0 | 2346 | // If the blob represents a remote blob for this ContentParent then we can |
michael@0 | 2347 | // simply pass its actor back here. |
michael@0 | 2348 | if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob)) { |
michael@0 | 2349 | if (BlobParent* actor = static_cast<BlobParent*>( |
michael@0 | 2350 | static_cast<PBlobParent*>(remoteBlob->GetPBlob()))) { |
michael@0 | 2351 | if (static_cast<ContentParent*>(actor->Manager()) == this) { |
michael@0 | 2352 | return actor; |
michael@0 | 2353 | } |
michael@0 | 2354 | } |
michael@0 | 2355 | } |
michael@0 | 2356 | |
michael@0 | 2357 | // XXX This is only safe so long as all blob implementations in our tree |
michael@0 | 2358 | // inherit nsDOMFileBase. If that ever changes then this will need to grow |
michael@0 | 2359 | // a real interface or something. |
michael@0 | 2360 | const nsDOMFileBase* blob = static_cast<nsDOMFileBase*>(aBlob); |
michael@0 | 2361 | |
michael@0 | 2362 | // We often pass blobs that are multipart but that only contain one sub-blob |
michael@0 | 2363 | // (WebActivities does this a bunch). Unwrap to reduce the number of actors |
michael@0 | 2364 | // that we have to maintain. |
michael@0 | 2365 | const nsTArray<nsCOMPtr<nsIDOMBlob> >* subBlobs = blob->GetSubBlobs(); |
michael@0 | 2366 | if (subBlobs && subBlobs->Length() == 1) { |
michael@0 | 2367 | const nsCOMPtr<nsIDOMBlob>& subBlob = subBlobs->ElementAt(0); |
michael@0 | 2368 | MOZ_ASSERT(subBlob); |
michael@0 | 2369 | |
michael@0 | 2370 | // We can only take this shortcut if the multipart and the sub-blob are both |
michael@0 | 2371 | // Blob objects or both File objects. |
michael@0 | 2372 | nsCOMPtr<nsIDOMFile> multipartBlobAsFile = do_QueryInterface(aBlob); |
michael@0 | 2373 | nsCOMPtr<nsIDOMFile> subBlobAsFile = do_QueryInterface(subBlob); |
michael@0 | 2374 | if (!multipartBlobAsFile == !subBlobAsFile) { |
michael@0 | 2375 | // The wrapping might have been unnecessary, see if we can simply pass an |
michael@0 | 2376 | // existing remote blob for this ContentParent. |
michael@0 | 2377 | if (nsCOMPtr<nsIRemoteBlob> remoteSubBlob = do_QueryInterface(subBlob)) { |
michael@0 | 2378 | BlobParent* actor = |
michael@0 | 2379 | static_cast<BlobParent*>( |
michael@0 | 2380 | static_cast<PBlobParent*>(remoteSubBlob->GetPBlob())); |
michael@0 | 2381 | MOZ_ASSERT(actor); |
michael@0 | 2382 | |
michael@0 | 2383 | if (static_cast<ContentParent*>(actor->Manager()) == this) { |
michael@0 | 2384 | return actor; |
michael@0 | 2385 | } |
michael@0 | 2386 | } |
michael@0 | 2387 | |
michael@0 | 2388 | // No need to add a reference here since the original blob must have a |
michael@0 | 2389 | // strong reference in the caller and it must also have a strong reference |
michael@0 | 2390 | // to this sub-blob. |
michael@0 | 2391 | aBlob = subBlob; |
michael@0 | 2392 | blob = static_cast<nsDOMFileBase*>(aBlob); |
michael@0 | 2393 | subBlobs = blob->GetSubBlobs(); |
michael@0 | 2394 | } |
michael@0 | 2395 | } |
michael@0 | 2396 | |
michael@0 | 2397 | // All blobs shared between processes must be immutable. |
michael@0 | 2398 | nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(aBlob); |
michael@0 | 2399 | if (!mutableBlob || NS_FAILED(mutableBlob->SetMutable(false))) { |
michael@0 | 2400 | NS_WARNING("Failed to make blob immutable!"); |
michael@0 | 2401 | return nullptr; |
michael@0 | 2402 | } |
michael@0 | 2403 | |
michael@0 | 2404 | ChildBlobConstructorParams params; |
michael@0 | 2405 | |
michael@0 | 2406 | if (blob->IsSizeUnknown() || blob->IsDateUnknown()) { |
michael@0 | 2407 | // We don't want to call GetSize or GetLastModifiedDate |
michael@0 | 2408 | // yet since that may stat a file on the main thread |
michael@0 | 2409 | // here. Instead we'll learn the size lazily from the |
michael@0 | 2410 | // other process. |
michael@0 | 2411 | params = MysteryBlobConstructorParams(); |
michael@0 | 2412 | } |
michael@0 | 2413 | else { |
michael@0 | 2414 | nsString contentType; |
michael@0 | 2415 | nsresult rv = aBlob->GetType(contentType); |
michael@0 | 2416 | NS_ENSURE_SUCCESS(rv, nullptr); |
michael@0 | 2417 | |
michael@0 | 2418 | uint64_t length; |
michael@0 | 2419 | rv = aBlob->GetSize(&length); |
michael@0 | 2420 | NS_ENSURE_SUCCESS(rv, nullptr); |
michael@0 | 2421 | |
michael@0 | 2422 | nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob); |
michael@0 | 2423 | if (file) { |
michael@0 | 2424 | FileBlobConstructorParams fileParams; |
michael@0 | 2425 | |
michael@0 | 2426 | rv = file->GetMozLastModifiedDate(&fileParams.modDate()); |
michael@0 | 2427 | NS_ENSURE_SUCCESS(rv, nullptr); |
michael@0 | 2428 | |
michael@0 | 2429 | rv = file->GetName(fileParams.name()); |
michael@0 | 2430 | NS_ENSURE_SUCCESS(rv, nullptr); |
michael@0 | 2431 | |
michael@0 | 2432 | fileParams.contentType() = contentType; |
michael@0 | 2433 | fileParams.length() = length; |
michael@0 | 2434 | |
michael@0 | 2435 | params = fileParams; |
michael@0 | 2436 | } else { |
michael@0 | 2437 | NormalBlobConstructorParams blobParams; |
michael@0 | 2438 | blobParams.contentType() = contentType; |
michael@0 | 2439 | blobParams.length() = length; |
michael@0 | 2440 | params = blobParams; |
michael@0 | 2441 | } |
michael@0 | 2442 | } |
michael@0 | 2443 | |
michael@0 | 2444 | BlobParent* actor = BlobParent::Create(this, aBlob); |
michael@0 | 2445 | NS_ENSURE_TRUE(actor, nullptr); |
michael@0 | 2446 | |
michael@0 | 2447 | return SendPBlobConstructor(actor, params) ? actor : nullptr; |
michael@0 | 2448 | } |
michael@0 | 2449 | |
michael@0 | 2450 | void |
michael@0 | 2451 | ContentParent::KillHard() |
michael@0 | 2452 | { |
michael@0 | 2453 | // On Windows, calling KillHard multiple times causes problems - the |
michael@0 | 2454 | // process handle becomes invalid on the first call, causing a second call |
michael@0 | 2455 | // to crash our process - more details in bug 890840. |
michael@0 | 2456 | if (mCalledKillHard) { |
michael@0 | 2457 | return; |
michael@0 | 2458 | } |
michael@0 | 2459 | mCalledKillHard = true; |
michael@0 | 2460 | mForceKillTask = nullptr; |
michael@0 | 2461 | // This ensures the process is eventually killed, but doesn't |
michael@0 | 2462 | // immediately KILLITWITHFIRE because we want to get a minidump if |
michael@0 | 2463 | // possible. After a timeout though, the process is forceably |
michael@0 | 2464 | // killed. |
michael@0 | 2465 | if (!KillProcess(OtherProcess(), 1, false)) { |
michael@0 | 2466 | NS_WARNING("failed to kill subprocess!"); |
michael@0 | 2467 | } |
michael@0 | 2468 | mSubprocess->SetAlreadyDead(); |
michael@0 | 2469 | XRE_GetIOMessageLoop()->PostTask( |
michael@0 | 2470 | FROM_HERE, |
michael@0 | 2471 | NewRunnableFunction(&ProcessWatcher::EnsureProcessTerminated, |
michael@0 | 2472 | OtherProcess(), /*force=*/true)); |
michael@0 | 2473 | //We do clean-up here |
michael@0 | 2474 | MessageLoop::current()->PostDelayedTask( |
michael@0 | 2475 | FROM_HERE, |
michael@0 | 2476 | NewRunnableMethod(this, &ContentParent::ShutDownProcess, |
michael@0 | 2477 | /* closeWithError */ true), |
michael@0 | 2478 | 3000); |
michael@0 | 2479 | // We've now closed the OtherProcess() handle, so must set it to null to |
michael@0 | 2480 | // prevent our dtor closing it twice. |
michael@0 | 2481 | SetOtherProcess(0); |
michael@0 | 2482 | } |
michael@0 | 2483 | |
michael@0 | 2484 | bool |
michael@0 | 2485 | ContentParent::IsPreallocated() |
michael@0 | 2486 | { |
michael@0 | 2487 | return mAppManifestURL == MAGIC_PREALLOCATED_APP_MANIFEST_URL; |
michael@0 | 2488 | } |
michael@0 | 2489 | |
michael@0 | 2490 | void |
michael@0 | 2491 | ContentParent::FriendlyName(nsAString& aName) |
michael@0 | 2492 | { |
michael@0 | 2493 | aName.Truncate(); |
michael@0 | 2494 | #ifdef MOZ_NUWA_PROCESS |
michael@0 | 2495 | if (IsNuwaProcess()) { |
michael@0 | 2496 | aName.AssignLiteral("(Nuwa)"); |
michael@0 | 2497 | } else |
michael@0 | 2498 | #endif |
michael@0 | 2499 | if (IsPreallocated()) { |
michael@0 | 2500 | aName.AssignLiteral("(Preallocated)"); |
michael@0 | 2501 | } else if (mIsForBrowser) { |
michael@0 | 2502 | aName.AssignLiteral("Browser"); |
michael@0 | 2503 | } else if (!mAppName.IsEmpty()) { |
michael@0 | 2504 | aName = mAppName; |
michael@0 | 2505 | } else if (!mAppManifestURL.IsEmpty()) { |
michael@0 | 2506 | aName.AssignLiteral("Unknown app: "); |
michael@0 | 2507 | aName.Append(mAppManifestURL); |
michael@0 | 2508 | } else { |
michael@0 | 2509 | aName.AssignLiteral("???"); |
michael@0 | 2510 | } |
michael@0 | 2511 | } |
michael@0 | 2512 | |
michael@0 | 2513 | PCrashReporterParent* |
michael@0 | 2514 | ContentParent::AllocPCrashReporterParent(const NativeThreadId& tid, |
michael@0 | 2515 | const uint32_t& processType) |
michael@0 | 2516 | { |
michael@0 | 2517 | #ifdef MOZ_CRASHREPORTER |
michael@0 | 2518 | return new CrashReporterParent(); |
michael@0 | 2519 | #else |
michael@0 | 2520 | return nullptr; |
michael@0 | 2521 | #endif |
michael@0 | 2522 | } |
michael@0 | 2523 | |
michael@0 | 2524 | bool |
michael@0 | 2525 | ContentParent::RecvPCrashReporterConstructor(PCrashReporterParent* actor, |
michael@0 | 2526 | const NativeThreadId& tid, |
michael@0 | 2527 | const uint32_t& processType) |
michael@0 | 2528 | { |
michael@0 | 2529 | static_cast<CrashReporterParent*>(actor)->SetChildData(tid, processType); |
michael@0 | 2530 | return true; |
michael@0 | 2531 | } |
michael@0 | 2532 | |
michael@0 | 2533 | bool |
michael@0 | 2534 | ContentParent::DeallocPCrashReporterParent(PCrashReporterParent* crashreporter) |
michael@0 | 2535 | { |
michael@0 | 2536 | delete crashreporter; |
michael@0 | 2537 | return true; |
michael@0 | 2538 | } |
michael@0 | 2539 | |
michael@0 | 2540 | hal_sandbox::PHalParent* |
michael@0 | 2541 | ContentParent::AllocPHalParent() |
michael@0 | 2542 | { |
michael@0 | 2543 | return hal_sandbox::CreateHalParent(); |
michael@0 | 2544 | } |
michael@0 | 2545 | |
michael@0 | 2546 | bool |
michael@0 | 2547 | ContentParent::DeallocPHalParent(hal_sandbox::PHalParent* aHal) |
michael@0 | 2548 | { |
michael@0 | 2549 | delete aHal; |
michael@0 | 2550 | return true; |
michael@0 | 2551 | } |
michael@0 | 2552 | |
michael@0 | 2553 | PIndexedDBParent* |
michael@0 | 2554 | ContentParent::AllocPIndexedDBParent() |
michael@0 | 2555 | { |
michael@0 | 2556 | return new IndexedDBParent(this); |
michael@0 | 2557 | } |
michael@0 | 2558 | |
michael@0 | 2559 | bool |
michael@0 | 2560 | ContentParent::DeallocPIndexedDBParent(PIndexedDBParent* aActor) |
michael@0 | 2561 | { |
michael@0 | 2562 | delete aActor; |
michael@0 | 2563 | return true; |
michael@0 | 2564 | } |
michael@0 | 2565 | |
michael@0 | 2566 | bool |
michael@0 | 2567 | ContentParent::RecvPIndexedDBConstructor(PIndexedDBParent* aActor) |
michael@0 | 2568 | { |
michael@0 | 2569 | nsRefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::GetOrCreate(); |
michael@0 | 2570 | NS_ENSURE_TRUE(mgr, false); |
michael@0 | 2571 | |
michael@0 | 2572 | if (!IndexedDatabaseManager::IsMainProcess()) { |
michael@0 | 2573 | NS_RUNTIMEABORT("Not supported yet!"); |
michael@0 | 2574 | } |
michael@0 | 2575 | |
michael@0 | 2576 | nsRefPtr<IDBFactory> factory; |
michael@0 | 2577 | nsresult rv = IDBFactory::Create(this, getter_AddRefs(factory)); |
michael@0 | 2578 | NS_ENSURE_SUCCESS(rv, false); |
michael@0 | 2579 | |
michael@0 | 2580 | NS_ASSERTION(factory, "This should never be null!"); |
michael@0 | 2581 | |
michael@0 | 2582 | IndexedDBParent* actor = static_cast<IndexedDBParent*>(aActor); |
michael@0 | 2583 | actor->mFactory = factory; |
michael@0 | 2584 | actor->mASCIIOrigin = factory->GetASCIIOrigin(); |
michael@0 | 2585 | |
michael@0 | 2586 | return true; |
michael@0 | 2587 | } |
michael@0 | 2588 | |
michael@0 | 2589 | PMemoryReportRequestParent* |
michael@0 | 2590 | ContentParent::AllocPMemoryReportRequestParent(const uint32_t& generation, |
michael@0 | 2591 | const bool &minimizeMemoryUsage, |
michael@0 | 2592 | const nsString &aDMDDumpIdent) |
michael@0 | 2593 | { |
michael@0 | 2594 | MemoryReportRequestParent* parent = new MemoryReportRequestParent(); |
michael@0 | 2595 | return parent; |
michael@0 | 2596 | } |
michael@0 | 2597 | |
michael@0 | 2598 | bool |
michael@0 | 2599 | ContentParent::DeallocPMemoryReportRequestParent(PMemoryReportRequestParent* actor) |
michael@0 | 2600 | { |
michael@0 | 2601 | delete actor; |
michael@0 | 2602 | return true; |
michael@0 | 2603 | } |
michael@0 | 2604 | |
michael@0 | 2605 | PTestShellParent* |
michael@0 | 2606 | ContentParent::AllocPTestShellParent() |
michael@0 | 2607 | { |
michael@0 | 2608 | return new TestShellParent(); |
michael@0 | 2609 | } |
michael@0 | 2610 | |
michael@0 | 2611 | bool |
michael@0 | 2612 | ContentParent::DeallocPTestShellParent(PTestShellParent* shell) |
michael@0 | 2613 | { |
michael@0 | 2614 | delete shell; |
michael@0 | 2615 | return true; |
michael@0 | 2616 | } |
michael@0 | 2617 | |
michael@0 | 2618 | PNeckoParent* |
michael@0 | 2619 | ContentParent::AllocPNeckoParent() |
michael@0 | 2620 | { |
michael@0 | 2621 | return new NeckoParent(); |
michael@0 | 2622 | } |
michael@0 | 2623 | |
michael@0 | 2624 | bool |
michael@0 | 2625 | ContentParent::DeallocPNeckoParent(PNeckoParent* necko) |
michael@0 | 2626 | { |
michael@0 | 2627 | delete necko; |
michael@0 | 2628 | return true; |
michael@0 | 2629 | } |
michael@0 | 2630 | |
michael@0 | 2631 | PExternalHelperAppParent* |
michael@0 | 2632 | ContentParent::AllocPExternalHelperAppParent(const OptionalURIParams& uri, |
michael@0 | 2633 | const nsCString& aMimeContentType, |
michael@0 | 2634 | const nsCString& aContentDisposition, |
michael@0 | 2635 | const uint32_t& aContentDispositionHint, |
michael@0 | 2636 | const nsString& aContentDispositionFilename, |
michael@0 | 2637 | const bool& aForceSave, |
michael@0 | 2638 | const int64_t& aContentLength, |
michael@0 | 2639 | const OptionalURIParams& aReferrer, |
michael@0 | 2640 | PBrowserParent* aBrowser) |
michael@0 | 2641 | { |
michael@0 | 2642 | ExternalHelperAppParent *parent = new ExternalHelperAppParent(uri, aContentLength); |
michael@0 | 2643 | parent->AddRef(); |
michael@0 | 2644 | parent->Init(this, |
michael@0 | 2645 | aMimeContentType, |
michael@0 | 2646 | aContentDisposition, |
michael@0 | 2647 | aContentDispositionHint, |
michael@0 | 2648 | aContentDispositionFilename, |
michael@0 | 2649 | aForceSave, |
michael@0 | 2650 | aReferrer, |
michael@0 | 2651 | aBrowser); |
michael@0 | 2652 | return parent; |
michael@0 | 2653 | } |
michael@0 | 2654 | |
michael@0 | 2655 | bool |
michael@0 | 2656 | ContentParent::DeallocPExternalHelperAppParent(PExternalHelperAppParent* aService) |
michael@0 | 2657 | { |
michael@0 | 2658 | ExternalHelperAppParent *parent = static_cast<ExternalHelperAppParent *>(aService); |
michael@0 | 2659 | parent->Release(); |
michael@0 | 2660 | return true; |
michael@0 | 2661 | } |
michael@0 | 2662 | |
michael@0 | 2663 | PSmsParent* |
michael@0 | 2664 | ContentParent::AllocPSmsParent() |
michael@0 | 2665 | { |
michael@0 | 2666 | if (!AssertAppProcessPermission(this, "sms")) { |
michael@0 | 2667 | return nullptr; |
michael@0 | 2668 | } |
michael@0 | 2669 | |
michael@0 | 2670 | SmsParent* parent = new SmsParent(); |
michael@0 | 2671 | parent->AddRef(); |
michael@0 | 2672 | return parent; |
michael@0 | 2673 | } |
michael@0 | 2674 | |
michael@0 | 2675 | bool |
michael@0 | 2676 | ContentParent::DeallocPSmsParent(PSmsParent* aSms) |
michael@0 | 2677 | { |
michael@0 | 2678 | static_cast<SmsParent*>(aSms)->Release(); |
michael@0 | 2679 | return true; |
michael@0 | 2680 | } |
michael@0 | 2681 | |
michael@0 | 2682 | PTelephonyParent* |
michael@0 | 2683 | ContentParent::AllocPTelephonyParent() |
michael@0 | 2684 | { |
michael@0 | 2685 | if (!AssertAppProcessPermission(this, "telephony")) { |
michael@0 | 2686 | return nullptr; |
michael@0 | 2687 | } |
michael@0 | 2688 | |
michael@0 | 2689 | TelephonyParent* actor = new TelephonyParent(); |
michael@0 | 2690 | NS_ADDREF(actor); |
michael@0 | 2691 | return actor; |
michael@0 | 2692 | } |
michael@0 | 2693 | |
michael@0 | 2694 | bool |
michael@0 | 2695 | ContentParent::DeallocPTelephonyParent(PTelephonyParent* aActor) |
michael@0 | 2696 | { |
michael@0 | 2697 | static_cast<TelephonyParent*>(aActor)->Release(); |
michael@0 | 2698 | return true; |
michael@0 | 2699 | } |
michael@0 | 2700 | |
michael@0 | 2701 | PStorageParent* |
michael@0 | 2702 | ContentParent::AllocPStorageParent() |
michael@0 | 2703 | { |
michael@0 | 2704 | return new DOMStorageDBParent(); |
michael@0 | 2705 | } |
michael@0 | 2706 | |
michael@0 | 2707 | bool |
michael@0 | 2708 | ContentParent::DeallocPStorageParent(PStorageParent* aActor) |
michael@0 | 2709 | { |
michael@0 | 2710 | DOMStorageDBParent* child = static_cast<DOMStorageDBParent*>(aActor); |
michael@0 | 2711 | child->ReleaseIPDLReference(); |
michael@0 | 2712 | return true; |
michael@0 | 2713 | } |
michael@0 | 2714 | |
michael@0 | 2715 | PBluetoothParent* |
michael@0 | 2716 | ContentParent::AllocPBluetoothParent() |
michael@0 | 2717 | { |
michael@0 | 2718 | #ifdef MOZ_B2G_BT |
michael@0 | 2719 | if (!AssertAppProcessPermission(this, "bluetooth")) { |
michael@0 | 2720 | return nullptr; |
michael@0 | 2721 | } |
michael@0 | 2722 | return new mozilla::dom::bluetooth::BluetoothParent(); |
michael@0 | 2723 | #else |
michael@0 | 2724 | MOZ_CRASH("No support for bluetooth on this platform!"); |
michael@0 | 2725 | #endif |
michael@0 | 2726 | } |
michael@0 | 2727 | |
michael@0 | 2728 | bool |
michael@0 | 2729 | ContentParent::DeallocPBluetoothParent(PBluetoothParent* aActor) |
michael@0 | 2730 | { |
michael@0 | 2731 | #ifdef MOZ_B2G_BT |
michael@0 | 2732 | delete aActor; |
michael@0 | 2733 | return true; |
michael@0 | 2734 | #else |
michael@0 | 2735 | MOZ_CRASH("No support for bluetooth on this platform!"); |
michael@0 | 2736 | #endif |
michael@0 | 2737 | } |
michael@0 | 2738 | |
michael@0 | 2739 | bool |
michael@0 | 2740 | ContentParent::RecvPBluetoothConstructor(PBluetoothParent* aActor) |
michael@0 | 2741 | { |
michael@0 | 2742 | #ifdef MOZ_B2G_BT |
michael@0 | 2743 | nsRefPtr<BluetoothService> btService = BluetoothService::Get(); |
michael@0 | 2744 | NS_ENSURE_TRUE(btService, false); |
michael@0 | 2745 | |
michael@0 | 2746 | return static_cast<BluetoothParent*>(aActor)->InitWithService(btService); |
michael@0 | 2747 | #else |
michael@0 | 2748 | MOZ_CRASH("No support for bluetooth on this platform!"); |
michael@0 | 2749 | #endif |
michael@0 | 2750 | } |
michael@0 | 2751 | |
michael@0 | 2752 | PFMRadioParent* |
michael@0 | 2753 | ContentParent::AllocPFMRadioParent() |
michael@0 | 2754 | { |
michael@0 | 2755 | #ifdef MOZ_B2G_FM |
michael@0 | 2756 | if (!AssertAppProcessPermission(this, "fmradio")) { |
michael@0 | 2757 | return nullptr; |
michael@0 | 2758 | } |
michael@0 | 2759 | return new FMRadioParent(); |
michael@0 | 2760 | #else |
michael@0 | 2761 | NS_WARNING("No support for FMRadio on this platform!"); |
michael@0 | 2762 | return nullptr; |
michael@0 | 2763 | #endif |
michael@0 | 2764 | } |
michael@0 | 2765 | |
michael@0 | 2766 | bool |
michael@0 | 2767 | ContentParent::DeallocPFMRadioParent(PFMRadioParent* aActor) |
michael@0 | 2768 | { |
michael@0 | 2769 | #ifdef MOZ_B2G_FM |
michael@0 | 2770 | delete aActor; |
michael@0 | 2771 | return true; |
michael@0 | 2772 | #else |
michael@0 | 2773 | NS_WARNING("No support for FMRadio on this platform!"); |
michael@0 | 2774 | return false; |
michael@0 | 2775 | #endif |
michael@0 | 2776 | } |
michael@0 | 2777 | |
michael@0 | 2778 | asmjscache::PAsmJSCacheEntryParent* |
michael@0 | 2779 | ContentParent::AllocPAsmJSCacheEntryParent( |
michael@0 | 2780 | const asmjscache::OpenMode& aOpenMode, |
michael@0 | 2781 | const asmjscache::WriteParams& aWriteParams, |
michael@0 | 2782 | const IPC::Principal& aPrincipal) |
michael@0 | 2783 | { |
michael@0 | 2784 | return asmjscache::AllocEntryParent(aOpenMode, aWriteParams, aPrincipal); |
michael@0 | 2785 | } |
michael@0 | 2786 | |
michael@0 | 2787 | bool |
michael@0 | 2788 | ContentParent::DeallocPAsmJSCacheEntryParent(PAsmJSCacheEntryParent* aActor) |
michael@0 | 2789 | { |
michael@0 | 2790 | asmjscache::DeallocEntryParent(aActor); |
michael@0 | 2791 | return true; |
michael@0 | 2792 | } |
michael@0 | 2793 | |
michael@0 | 2794 | PSpeechSynthesisParent* |
michael@0 | 2795 | ContentParent::AllocPSpeechSynthesisParent() |
michael@0 | 2796 | { |
michael@0 | 2797 | #ifdef MOZ_WEBSPEECH |
michael@0 | 2798 | return new mozilla::dom::SpeechSynthesisParent(); |
michael@0 | 2799 | #else |
michael@0 | 2800 | return nullptr; |
michael@0 | 2801 | #endif |
michael@0 | 2802 | } |
michael@0 | 2803 | |
michael@0 | 2804 | bool |
michael@0 | 2805 | ContentParent::DeallocPSpeechSynthesisParent(PSpeechSynthesisParent* aActor) |
michael@0 | 2806 | { |
michael@0 | 2807 | #ifdef MOZ_WEBSPEECH |
michael@0 | 2808 | delete aActor; |
michael@0 | 2809 | return true; |
michael@0 | 2810 | #else |
michael@0 | 2811 | return false; |
michael@0 | 2812 | #endif |
michael@0 | 2813 | } |
michael@0 | 2814 | |
michael@0 | 2815 | bool |
michael@0 | 2816 | ContentParent::RecvPSpeechSynthesisConstructor(PSpeechSynthesisParent* aActor) |
michael@0 | 2817 | { |
michael@0 | 2818 | #ifdef MOZ_WEBSPEECH |
michael@0 | 2819 | return true; |
michael@0 | 2820 | #else |
michael@0 | 2821 | return false; |
michael@0 | 2822 | #endif |
michael@0 | 2823 | } |
michael@0 | 2824 | |
michael@0 | 2825 | bool |
michael@0 | 2826 | ContentParent::RecvSpeakerManagerGetSpeakerStatus(bool* aValue) |
michael@0 | 2827 | { |
michael@0 | 2828 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 2829 | *aValue = false; |
michael@0 | 2830 | nsRefPtr<SpeakerManagerService> service = |
michael@0 | 2831 | SpeakerManagerService::GetSpeakerManagerService(); |
michael@0 | 2832 | if (service) { |
michael@0 | 2833 | *aValue = service->GetSpeakerStatus(); |
michael@0 | 2834 | } |
michael@0 | 2835 | return true; |
michael@0 | 2836 | #endif |
michael@0 | 2837 | return false; |
michael@0 | 2838 | } |
michael@0 | 2839 | |
michael@0 | 2840 | bool |
michael@0 | 2841 | ContentParent::RecvSpeakerManagerForceSpeaker(const bool& aEnable) |
michael@0 | 2842 | { |
michael@0 | 2843 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 2844 | nsRefPtr<SpeakerManagerService> service = |
michael@0 | 2845 | SpeakerManagerService::GetSpeakerManagerService(); |
michael@0 | 2846 | if (service) { |
michael@0 | 2847 | service->ForceSpeaker(aEnable, mChildID); |
michael@0 | 2848 | } |
michael@0 | 2849 | return true; |
michael@0 | 2850 | #endif |
michael@0 | 2851 | return false; |
michael@0 | 2852 | } |
michael@0 | 2853 | |
michael@0 | 2854 | bool |
michael@0 | 2855 | ContentParent::RecvStartVisitedQuery(const URIParams& aURI) |
michael@0 | 2856 | { |
michael@0 | 2857 | nsCOMPtr<nsIURI> newURI = DeserializeURI(aURI); |
michael@0 | 2858 | if (!newURI) { |
michael@0 | 2859 | return false; |
michael@0 | 2860 | } |
michael@0 | 2861 | nsCOMPtr<IHistory> history = services::GetHistoryService(); |
michael@0 | 2862 | if (history) { |
michael@0 | 2863 | history->RegisterVisitedCallback(newURI, nullptr); |
michael@0 | 2864 | } |
michael@0 | 2865 | return true; |
michael@0 | 2866 | } |
michael@0 | 2867 | |
michael@0 | 2868 | |
michael@0 | 2869 | bool |
michael@0 | 2870 | ContentParent::RecvVisitURI(const URIParams& uri, |
michael@0 | 2871 | const OptionalURIParams& referrer, |
michael@0 | 2872 | const uint32_t& flags) |
michael@0 | 2873 | { |
michael@0 | 2874 | nsCOMPtr<nsIURI> ourURI = DeserializeURI(uri); |
michael@0 | 2875 | if (!ourURI) { |
michael@0 | 2876 | return false; |
michael@0 | 2877 | } |
michael@0 | 2878 | nsCOMPtr<nsIURI> ourReferrer = DeserializeURI(referrer); |
michael@0 | 2879 | nsCOMPtr<IHistory> history = services::GetHistoryService(); |
michael@0 | 2880 | if (history) { |
michael@0 | 2881 | history->VisitURI(ourURI, ourReferrer, flags); |
michael@0 | 2882 | } |
michael@0 | 2883 | return true; |
michael@0 | 2884 | } |
michael@0 | 2885 | |
michael@0 | 2886 | |
michael@0 | 2887 | bool |
michael@0 | 2888 | ContentParent::RecvSetURITitle(const URIParams& uri, |
michael@0 | 2889 | const nsString& title) |
michael@0 | 2890 | { |
michael@0 | 2891 | nsCOMPtr<nsIURI> ourURI = DeserializeURI(uri); |
michael@0 | 2892 | if (!ourURI) { |
michael@0 | 2893 | return false; |
michael@0 | 2894 | } |
michael@0 | 2895 | nsCOMPtr<IHistory> history = services::GetHistoryService(); |
michael@0 | 2896 | if (history) { |
michael@0 | 2897 | history->SetURITitle(ourURI, title); |
michael@0 | 2898 | } |
michael@0 | 2899 | return true; |
michael@0 | 2900 | } |
michael@0 | 2901 | |
michael@0 | 2902 | bool |
michael@0 | 2903 | ContentParent::RecvGetRandomValues(const uint32_t& length, |
michael@0 | 2904 | InfallibleTArray<uint8_t>* randomValues) |
michael@0 | 2905 | { |
michael@0 | 2906 | uint8_t* buf = Crypto::GetRandomValues(length); |
michael@0 | 2907 | if (!buf) { |
michael@0 | 2908 | return true; |
michael@0 | 2909 | } |
michael@0 | 2910 | |
michael@0 | 2911 | randomValues->SetCapacity(length); |
michael@0 | 2912 | randomValues->SetLength(length); |
michael@0 | 2913 | |
michael@0 | 2914 | memcpy(randomValues->Elements(), buf, length); |
michael@0 | 2915 | |
michael@0 | 2916 | NS_Free(buf); |
michael@0 | 2917 | |
michael@0 | 2918 | return true; |
michael@0 | 2919 | } |
michael@0 | 2920 | |
michael@0 | 2921 | bool |
michael@0 | 2922 | ContentParent::RecvLoadURIExternal(const URIParams& uri) |
michael@0 | 2923 | { |
michael@0 | 2924 | nsCOMPtr<nsIExternalProtocolService> extProtService(do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID)); |
michael@0 | 2925 | if (!extProtService) { |
michael@0 | 2926 | return true; |
michael@0 | 2927 | } |
michael@0 | 2928 | nsCOMPtr<nsIURI> ourURI = DeserializeURI(uri); |
michael@0 | 2929 | if (!ourURI) { |
michael@0 | 2930 | return false; |
michael@0 | 2931 | } |
michael@0 | 2932 | extProtService->LoadURI(ourURI, nullptr); |
michael@0 | 2933 | return true; |
michael@0 | 2934 | } |
michael@0 | 2935 | |
michael@0 | 2936 | bool |
michael@0 | 2937 | ContentParent::RecvShowAlertNotification(const nsString& aImageUrl, const nsString& aTitle, |
michael@0 | 2938 | const nsString& aText, const bool& aTextClickable, |
michael@0 | 2939 | const nsString& aCookie, const nsString& aName, |
michael@0 | 2940 | const nsString& aBidi, const nsString& aLang, |
michael@0 | 2941 | const IPC::Principal& aPrincipal) |
michael@0 | 2942 | { |
michael@0 | 2943 | #ifdef MOZ_CHILD_PERMISSIONS |
michael@0 | 2944 | uint32_t permission = mozilla::CheckPermission(this, aPrincipal, |
michael@0 | 2945 | "desktop-notification"); |
michael@0 | 2946 | if (permission != nsIPermissionManager::ALLOW_ACTION) { |
michael@0 | 2947 | return true; |
michael@0 | 2948 | } |
michael@0 | 2949 | #endif /* MOZ_CHILD_PERMISSIONS */ |
michael@0 | 2950 | |
michael@0 | 2951 | nsCOMPtr<nsIAlertsService> sysAlerts(do_GetService(NS_ALERTSERVICE_CONTRACTID)); |
michael@0 | 2952 | if (sysAlerts) { |
michael@0 | 2953 | sysAlerts->ShowAlertNotification(aImageUrl, aTitle, aText, aTextClickable, |
michael@0 | 2954 | aCookie, this, aName, aBidi, aLang, aPrincipal); |
michael@0 | 2955 | } |
michael@0 | 2956 | return true; |
michael@0 | 2957 | } |
michael@0 | 2958 | |
michael@0 | 2959 | bool |
michael@0 | 2960 | ContentParent::RecvCloseAlert(const nsString& aName, |
michael@0 | 2961 | const IPC::Principal& aPrincipal) |
michael@0 | 2962 | { |
michael@0 | 2963 | #ifdef MOZ_CHILD_PERMISSIONS |
michael@0 | 2964 | uint32_t permission = mozilla::CheckPermission(this, aPrincipal, |
michael@0 | 2965 | "desktop-notification"); |
michael@0 | 2966 | if (permission != nsIPermissionManager::ALLOW_ACTION) { |
michael@0 | 2967 | return true; |
michael@0 | 2968 | } |
michael@0 | 2969 | #endif |
michael@0 | 2970 | |
michael@0 | 2971 | nsCOMPtr<nsIAlertsService> sysAlerts(do_GetService(NS_ALERTSERVICE_CONTRACTID)); |
michael@0 | 2972 | if (sysAlerts) { |
michael@0 | 2973 | sysAlerts->CloseAlert(aName, aPrincipal); |
michael@0 | 2974 | } |
michael@0 | 2975 | |
michael@0 | 2976 | return true; |
michael@0 | 2977 | } |
michael@0 | 2978 | |
michael@0 | 2979 | bool |
michael@0 | 2980 | ContentParent::RecvSyncMessage(const nsString& aMsg, |
michael@0 | 2981 | const ClonedMessageData& aData, |
michael@0 | 2982 | const InfallibleTArray<CpowEntry>& aCpows, |
michael@0 | 2983 | const IPC::Principal& aPrincipal, |
michael@0 | 2984 | InfallibleTArray<nsString>* aRetvals) |
michael@0 | 2985 | { |
michael@0 | 2986 | nsIPrincipal* principal = aPrincipal; |
michael@0 | 2987 | if (!Preferences::GetBool("dom.testing.ignore_ipc_principal", false) && |
michael@0 | 2988 | principal && !AssertAppPrincipal(this, principal)) { |
michael@0 | 2989 | return false; |
michael@0 | 2990 | } |
michael@0 | 2991 | |
michael@0 | 2992 | nsRefPtr<nsFrameMessageManager> ppm = mMessageManager; |
michael@0 | 2993 | if (ppm) { |
michael@0 | 2994 | StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData); |
michael@0 | 2995 | CpowIdHolder cpows(GetCPOWManager(), aCpows); |
michael@0 | 2996 | |
michael@0 | 2997 | ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), |
michael@0 | 2998 | aMsg, true, &cloneData, &cpows, aPrincipal, aRetvals); |
michael@0 | 2999 | } |
michael@0 | 3000 | return true; |
michael@0 | 3001 | } |
michael@0 | 3002 | |
michael@0 | 3003 | bool |
michael@0 | 3004 | ContentParent::AnswerRpcMessage(const nsString& aMsg, |
michael@0 | 3005 | const ClonedMessageData& aData, |
michael@0 | 3006 | const InfallibleTArray<CpowEntry>& aCpows, |
michael@0 | 3007 | const IPC::Principal& aPrincipal, |
michael@0 | 3008 | InfallibleTArray<nsString>* aRetvals) |
michael@0 | 3009 | { |
michael@0 | 3010 | nsIPrincipal* principal = aPrincipal; |
michael@0 | 3011 | if (!Preferences::GetBool("dom.testing.ignore_ipc_principal", false) && |
michael@0 | 3012 | principal && !AssertAppPrincipal(this, principal)) { |
michael@0 | 3013 | return false; |
michael@0 | 3014 | } |
michael@0 | 3015 | |
michael@0 | 3016 | nsRefPtr<nsFrameMessageManager> ppm = mMessageManager; |
michael@0 | 3017 | if (ppm) { |
michael@0 | 3018 | StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData); |
michael@0 | 3019 | CpowIdHolder cpows(GetCPOWManager(), aCpows); |
michael@0 | 3020 | ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), |
michael@0 | 3021 | aMsg, true, &cloneData, &cpows, aPrincipal, aRetvals); |
michael@0 | 3022 | } |
michael@0 | 3023 | return true; |
michael@0 | 3024 | } |
michael@0 | 3025 | |
michael@0 | 3026 | bool |
michael@0 | 3027 | ContentParent::RecvAsyncMessage(const nsString& aMsg, |
michael@0 | 3028 | const ClonedMessageData& aData, |
michael@0 | 3029 | const InfallibleTArray<CpowEntry>& aCpows, |
michael@0 | 3030 | const IPC::Principal& aPrincipal) |
michael@0 | 3031 | { |
michael@0 | 3032 | nsIPrincipal* principal = aPrincipal; |
michael@0 | 3033 | if (!Preferences::GetBool("dom.testing.ignore_ipc_principal", false) && |
michael@0 | 3034 | principal && !AssertAppPrincipal(this, principal)) { |
michael@0 | 3035 | return false; |
michael@0 | 3036 | } |
michael@0 | 3037 | |
michael@0 | 3038 | nsRefPtr<nsFrameMessageManager> ppm = mMessageManager; |
michael@0 | 3039 | if (ppm) { |
michael@0 | 3040 | StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData); |
michael@0 | 3041 | CpowIdHolder cpows(GetCPOWManager(), aCpows); |
michael@0 | 3042 | ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), |
michael@0 | 3043 | aMsg, false, &cloneData, &cpows, aPrincipal, nullptr); |
michael@0 | 3044 | } |
michael@0 | 3045 | return true; |
michael@0 | 3046 | } |
michael@0 | 3047 | |
michael@0 | 3048 | bool |
michael@0 | 3049 | ContentParent::RecvFilePathUpdateNotify(const nsString& aType, |
michael@0 | 3050 | const nsString& aStorageName, |
michael@0 | 3051 | const nsString& aFilePath, |
michael@0 | 3052 | const nsCString& aReason) |
michael@0 | 3053 | { |
michael@0 | 3054 | nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(aType, |
michael@0 | 3055 | aStorageName, |
michael@0 | 3056 | aFilePath); |
michael@0 | 3057 | |
michael@0 | 3058 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
michael@0 | 3059 | if (!obs) { |
michael@0 | 3060 | return false; |
michael@0 | 3061 | } |
michael@0 | 3062 | obs->NotifyObservers(dsf, "file-watcher-update", |
michael@0 | 3063 | NS_ConvertASCIItoUTF16(aReason).get()); |
michael@0 | 3064 | return true; |
michael@0 | 3065 | } |
michael@0 | 3066 | |
michael@0 | 3067 | static int32_t |
michael@0 | 3068 | AddGeolocationListener(nsIDOMGeoPositionCallback* watcher, bool highAccuracy) |
michael@0 | 3069 | { |
michael@0 | 3070 | nsCOMPtr<nsIDOMGeoGeolocation> geo = do_GetService("@mozilla.org/geolocation;1"); |
michael@0 | 3071 | if (!geo) { |
michael@0 | 3072 | return -1; |
michael@0 | 3073 | } |
michael@0 | 3074 | |
michael@0 | 3075 | PositionOptions* options = new PositionOptions(); |
michael@0 | 3076 | options->mTimeout = 0; |
michael@0 | 3077 | options->mMaximumAge = 0; |
michael@0 | 3078 | options->mEnableHighAccuracy = highAccuracy; |
michael@0 | 3079 | int32_t retval = 1; |
michael@0 | 3080 | geo->WatchPosition(watcher, nullptr, options, &retval); |
michael@0 | 3081 | return retval; |
michael@0 | 3082 | } |
michael@0 | 3083 | |
michael@0 | 3084 | bool |
michael@0 | 3085 | ContentParent::RecvAddGeolocationListener(const IPC::Principal& aPrincipal, |
michael@0 | 3086 | const bool& aHighAccuracy) |
michael@0 | 3087 | { |
michael@0 | 3088 | #ifdef MOZ_CHILD_PERMISSIONS |
michael@0 | 3089 | if (!Preferences::GetBool("dom.testing.ignore_ipc_principal", false)) { |
michael@0 | 3090 | uint32_t permission = mozilla::CheckPermission(this, aPrincipal, |
michael@0 | 3091 | "geolocation"); |
michael@0 | 3092 | if (permission != nsIPermissionManager::ALLOW_ACTION) { |
michael@0 | 3093 | return true; |
michael@0 | 3094 | } |
michael@0 | 3095 | } |
michael@0 | 3096 | #endif /* MOZ_CHILD_PERMISSIONS */ |
michael@0 | 3097 | |
michael@0 | 3098 | // To ensure no geolocation updates are skipped, we always force the |
michael@0 | 3099 | // creation of a new listener. |
michael@0 | 3100 | RecvRemoveGeolocationListener(); |
michael@0 | 3101 | mGeolocationWatchID = AddGeolocationListener(this, aHighAccuracy); |
michael@0 | 3102 | return true; |
michael@0 | 3103 | } |
michael@0 | 3104 | |
michael@0 | 3105 | bool |
michael@0 | 3106 | ContentParent::RecvRemoveGeolocationListener() |
michael@0 | 3107 | { |
michael@0 | 3108 | if (mGeolocationWatchID != -1) { |
michael@0 | 3109 | nsCOMPtr<nsIDOMGeoGeolocation> geo = do_GetService("@mozilla.org/geolocation;1"); |
michael@0 | 3110 | if (!geo) { |
michael@0 | 3111 | return true; |
michael@0 | 3112 | } |
michael@0 | 3113 | geo->ClearWatch(mGeolocationWatchID); |
michael@0 | 3114 | mGeolocationWatchID = -1; |
michael@0 | 3115 | } |
michael@0 | 3116 | return true; |
michael@0 | 3117 | } |
michael@0 | 3118 | |
michael@0 | 3119 | bool |
michael@0 | 3120 | ContentParent::RecvSetGeolocationHigherAccuracy(const bool& aEnable) |
michael@0 | 3121 | { |
michael@0 | 3122 | // This should never be called without a listener already present, |
michael@0 | 3123 | // so this check allows us to forgo securing privileges. |
michael@0 | 3124 | if (mGeolocationWatchID != -1) { |
michael@0 | 3125 | RecvRemoveGeolocationListener(); |
michael@0 | 3126 | mGeolocationWatchID = AddGeolocationListener(this, aEnable); |
michael@0 | 3127 | } |
michael@0 | 3128 | return true; |
michael@0 | 3129 | } |
michael@0 | 3130 | |
michael@0 | 3131 | NS_IMETHODIMP |
michael@0 | 3132 | ContentParent::HandleEvent(nsIDOMGeoPosition* postion) |
michael@0 | 3133 | { |
michael@0 | 3134 | unused << SendGeolocationUpdate(GeoPosition(postion)); |
michael@0 | 3135 | return NS_OK; |
michael@0 | 3136 | } |
michael@0 | 3137 | |
michael@0 | 3138 | nsConsoleService * |
michael@0 | 3139 | ContentParent::GetConsoleService() |
michael@0 | 3140 | { |
michael@0 | 3141 | if (mConsoleService) { |
michael@0 | 3142 | return mConsoleService.get(); |
michael@0 | 3143 | } |
michael@0 | 3144 | |
michael@0 | 3145 | // Get the ConsoleService by CID rather than ContractID, so that we |
michael@0 | 3146 | // can cast the returned pointer to an nsConsoleService (rather than |
michael@0 | 3147 | // just an nsIConsoleService). This allows us to call the non-idl function |
michael@0 | 3148 | // nsConsoleService::LogMessageWithMode. |
michael@0 | 3149 | NS_DEFINE_CID(consoleServiceCID, NS_CONSOLESERVICE_CID); |
michael@0 | 3150 | nsCOMPtr<nsConsoleService> consoleService(do_GetService(consoleServiceCID)); |
michael@0 | 3151 | mConsoleService = consoleService; |
michael@0 | 3152 | return mConsoleService.get(); |
michael@0 | 3153 | } |
michael@0 | 3154 | |
michael@0 | 3155 | bool |
michael@0 | 3156 | ContentParent::RecvConsoleMessage(const nsString& aMessage) |
michael@0 | 3157 | { |
michael@0 | 3158 | nsRefPtr<nsConsoleService> consoleService = GetConsoleService(); |
michael@0 | 3159 | if (!consoleService) { |
michael@0 | 3160 | return true; |
michael@0 | 3161 | } |
michael@0 | 3162 | |
michael@0 | 3163 | nsRefPtr<nsConsoleMessage> msg(new nsConsoleMessage(aMessage.get())); |
michael@0 | 3164 | consoleService->LogMessageWithMode(msg, nsConsoleService::SuppressLog); |
michael@0 | 3165 | return true; |
michael@0 | 3166 | } |
michael@0 | 3167 | |
michael@0 | 3168 | bool |
michael@0 | 3169 | ContentParent::RecvScriptError(const nsString& aMessage, |
michael@0 | 3170 | const nsString& aSourceName, |
michael@0 | 3171 | const nsString& aSourceLine, |
michael@0 | 3172 | const uint32_t& aLineNumber, |
michael@0 | 3173 | const uint32_t& aColNumber, |
michael@0 | 3174 | const uint32_t& aFlags, |
michael@0 | 3175 | const nsCString& aCategory) |
michael@0 | 3176 | { |
michael@0 | 3177 | nsRefPtr<nsConsoleService> consoleService = GetConsoleService(); |
michael@0 | 3178 | if (!consoleService) { |
michael@0 | 3179 | return true; |
michael@0 | 3180 | } |
michael@0 | 3181 | |
michael@0 | 3182 | nsCOMPtr<nsIScriptError> msg(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID)); |
michael@0 | 3183 | nsresult rv = msg->Init(aMessage, aSourceName, aSourceLine, |
michael@0 | 3184 | aLineNumber, aColNumber, aFlags, aCategory.get()); |
michael@0 | 3185 | if (NS_FAILED(rv)) |
michael@0 | 3186 | return true; |
michael@0 | 3187 | |
michael@0 | 3188 | consoleService->LogMessageWithMode(msg, nsConsoleService::SuppressLog); |
michael@0 | 3189 | return true; |
michael@0 | 3190 | } |
michael@0 | 3191 | |
michael@0 | 3192 | bool |
michael@0 | 3193 | ContentParent::RecvPrivateDocShellsExist(const bool& aExist) |
michael@0 | 3194 | { |
michael@0 | 3195 | if (!sPrivateContent) |
michael@0 | 3196 | sPrivateContent = new nsTArray<ContentParent*>(); |
michael@0 | 3197 | if (aExist) { |
michael@0 | 3198 | sPrivateContent->AppendElement(this); |
michael@0 | 3199 | } else { |
michael@0 | 3200 | sPrivateContent->RemoveElement(this); |
michael@0 | 3201 | if (!sPrivateContent->Length()) { |
michael@0 | 3202 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
michael@0 | 3203 | obs->NotifyObservers(nullptr, "last-pb-context-exited", nullptr); |
michael@0 | 3204 | delete sPrivateContent; |
michael@0 | 3205 | sPrivateContent = nullptr; |
michael@0 | 3206 | } |
michael@0 | 3207 | } |
michael@0 | 3208 | return true; |
michael@0 | 3209 | } |
michael@0 | 3210 | |
michael@0 | 3211 | bool |
michael@0 | 3212 | ContentParent::DoSendAsyncMessage(JSContext* aCx, |
michael@0 | 3213 | const nsAString& aMessage, |
michael@0 | 3214 | const mozilla::dom::StructuredCloneData& aData, |
michael@0 | 3215 | JS::Handle<JSObject *> aCpows, |
michael@0 | 3216 | nsIPrincipal* aPrincipal) |
michael@0 | 3217 | { |
michael@0 | 3218 | ClonedMessageData data; |
michael@0 | 3219 | if (!BuildClonedMessageDataForParent(this, aData, data)) { |
michael@0 | 3220 | return false; |
michael@0 | 3221 | } |
michael@0 | 3222 | InfallibleTArray<CpowEntry> cpows; |
michael@0 | 3223 | if (!GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) { |
michael@0 | 3224 | return false; |
michael@0 | 3225 | } |
michael@0 | 3226 | return SendAsyncMessage(nsString(aMessage), data, cpows, aPrincipal); |
michael@0 | 3227 | } |
michael@0 | 3228 | |
michael@0 | 3229 | bool |
michael@0 | 3230 | ContentParent::CheckPermission(const nsAString& aPermission) |
michael@0 | 3231 | { |
michael@0 | 3232 | return AssertAppProcessPermission(this, NS_ConvertUTF16toUTF8(aPermission).get()); |
michael@0 | 3233 | } |
michael@0 | 3234 | |
michael@0 | 3235 | bool |
michael@0 | 3236 | ContentParent::CheckManifestURL(const nsAString& aManifestURL) |
michael@0 | 3237 | { |
michael@0 | 3238 | return AssertAppProcessManifestURL(this, NS_ConvertUTF16toUTF8(aManifestURL).get()); |
michael@0 | 3239 | } |
michael@0 | 3240 | |
michael@0 | 3241 | bool |
michael@0 | 3242 | ContentParent::CheckAppHasPermission(const nsAString& aPermission) |
michael@0 | 3243 | { |
michael@0 | 3244 | return AssertAppHasPermission(this, NS_ConvertUTF16toUTF8(aPermission).get()); |
michael@0 | 3245 | } |
michael@0 | 3246 | |
michael@0 | 3247 | bool |
michael@0 | 3248 | ContentParent::CheckAppHasStatus(unsigned short aStatus) |
michael@0 | 3249 | { |
michael@0 | 3250 | return AssertAppHasStatus(this, aStatus); |
michael@0 | 3251 | } |
michael@0 | 3252 | |
michael@0 | 3253 | bool |
michael@0 | 3254 | ContentParent::RecvSystemMessageHandled() |
michael@0 | 3255 | { |
michael@0 | 3256 | SystemMessageHandledListener::OnSystemMessageHandled(); |
michael@0 | 3257 | return true; |
michael@0 | 3258 | } |
michael@0 | 3259 | |
michael@0 | 3260 | bool |
michael@0 | 3261 | ContentParent::RecvCreateFakeVolume(const nsString& fsName, const nsString& mountPoint) |
michael@0 | 3262 | { |
michael@0 | 3263 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 3264 | nsresult rv; |
michael@0 | 3265 | nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID, &rv); |
michael@0 | 3266 | if (vs) { |
michael@0 | 3267 | vs->CreateFakeVolume(fsName, mountPoint); |
michael@0 | 3268 | } |
michael@0 | 3269 | return true; |
michael@0 | 3270 | #else |
michael@0 | 3271 | NS_WARNING("ContentParent::RecvCreateFakeVolume shouldn't be called when MOZ_WIDGET_GONK is not defined"); |
michael@0 | 3272 | return false; |
michael@0 | 3273 | #endif |
michael@0 | 3274 | } |
michael@0 | 3275 | |
michael@0 | 3276 | bool |
michael@0 | 3277 | ContentParent::RecvSetFakeVolumeState(const nsString& fsName, const int32_t& fsState) |
michael@0 | 3278 | { |
michael@0 | 3279 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 3280 | nsresult rv; |
michael@0 | 3281 | nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID, &rv); |
michael@0 | 3282 | if (vs) { |
michael@0 | 3283 | vs->SetFakeVolumeState(fsName, fsState); |
michael@0 | 3284 | } |
michael@0 | 3285 | return true; |
michael@0 | 3286 | #else |
michael@0 | 3287 | NS_WARNING("ContentParent::RecvSetFakeVolumeState shouldn't be called when MOZ_WIDGET_GONK is not defined"); |
michael@0 | 3288 | return false; |
michael@0 | 3289 | #endif |
michael@0 | 3290 | } |
michael@0 | 3291 | |
michael@0 | 3292 | bool |
michael@0 | 3293 | ContentParent::RecvKeywordToURI(const nsCString& aKeyword, OptionalInputStreamParams* aPostData, |
michael@0 | 3294 | OptionalURIParams* aURI) |
michael@0 | 3295 | { |
michael@0 | 3296 | nsCOMPtr<nsIURIFixup> fixup = do_GetService(NS_URIFIXUP_CONTRACTID); |
michael@0 | 3297 | if (!fixup) { |
michael@0 | 3298 | return true; |
michael@0 | 3299 | } |
michael@0 | 3300 | |
michael@0 | 3301 | nsCOMPtr<nsIInputStream> postData; |
michael@0 | 3302 | nsCOMPtr<nsIURI> uri; |
michael@0 | 3303 | if (NS_FAILED(fixup->KeywordToURI(aKeyword, getter_AddRefs(postData), |
michael@0 | 3304 | getter_AddRefs(uri)))) { |
michael@0 | 3305 | return true; |
michael@0 | 3306 | } |
michael@0 | 3307 | |
michael@0 | 3308 | nsTArray<mozilla::ipc::FileDescriptor> fds; |
michael@0 | 3309 | SerializeInputStream(postData, *aPostData, fds); |
michael@0 | 3310 | MOZ_ASSERT(fds.IsEmpty()); |
michael@0 | 3311 | |
michael@0 | 3312 | SerializeURI(uri, *aURI); |
michael@0 | 3313 | return true; |
michael@0 | 3314 | } |
michael@0 | 3315 | |
michael@0 | 3316 | bool |
michael@0 | 3317 | ContentParent::ShouldContinueFromReplyTimeout() |
michael@0 | 3318 | { |
michael@0 | 3319 | // The only time ContentParent sends blocking messages is for CPOWs, so |
michael@0 | 3320 | // timeouts should only ever occur in electrolysis-enabled sessions. |
michael@0 | 3321 | MOZ_ASSERT(BrowserTabsRemote()); |
michael@0 | 3322 | return false; |
michael@0 | 3323 | } |
michael@0 | 3324 | |
michael@0 | 3325 | bool |
michael@0 | 3326 | ContentParent::ShouldSandboxContentProcesses() |
michael@0 | 3327 | { |
michael@0 | 3328 | #ifdef MOZ_CONTENT_SANDBOX |
michael@0 | 3329 | return !PR_GetEnv("MOZ_DISABLE_CONTENT_SANDBOX"); |
michael@0 | 3330 | #else |
michael@0 | 3331 | return true; |
michael@0 | 3332 | #endif |
michael@0 | 3333 | } |
michael@0 | 3334 | |
michael@0 | 3335 | bool |
michael@0 | 3336 | ContentParent::RecvRecordingDeviceEvents(const nsString& aRecordingStatus, |
michael@0 | 3337 | const nsString& aPageURL, |
michael@0 | 3338 | const bool& aIsAudio, |
michael@0 | 3339 | const bool& aIsVideo) |
michael@0 | 3340 | { |
michael@0 | 3341 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
michael@0 | 3342 | if (obs) { |
michael@0 | 3343 | // recording-device-ipc-events needs to gather more information from content process |
michael@0 | 3344 | nsRefPtr<nsHashPropertyBag> props = new nsHashPropertyBag(); |
michael@0 | 3345 | props->SetPropertyAsUint64(NS_LITERAL_STRING("childID"), ChildID()); |
michael@0 | 3346 | props->SetPropertyAsBool(NS_LITERAL_STRING("isApp"), IsForApp()); |
michael@0 | 3347 | props->SetPropertyAsBool(NS_LITERAL_STRING("isAudio"), aIsAudio); |
michael@0 | 3348 | props->SetPropertyAsBool(NS_LITERAL_STRING("isVideo"), aIsVideo); |
michael@0 | 3349 | |
michael@0 | 3350 | nsString requestURL = IsForApp() ? AppManifestURL() : aPageURL; |
michael@0 | 3351 | props->SetPropertyAsAString(NS_LITERAL_STRING("requestURL"), requestURL); |
michael@0 | 3352 | |
michael@0 | 3353 | obs->NotifyObservers((nsIPropertyBag2*) props, |
michael@0 | 3354 | "recording-device-ipc-events", |
michael@0 | 3355 | aRecordingStatus.get()); |
michael@0 | 3356 | } else { |
michael@0 | 3357 | NS_WARNING("Could not get the Observer service for ContentParent::RecvRecordingDeviceEvents."); |
michael@0 | 3358 | } |
michael@0 | 3359 | return true; |
michael@0 | 3360 | } |
michael@0 | 3361 | |
michael@0 | 3362 | bool |
michael@0 | 3363 | ContentParent::RecvGetGraphicsFeatureStatus(const int32_t& aFeature, |
michael@0 | 3364 | int32_t* aStatus, |
michael@0 | 3365 | bool* aSuccess) |
michael@0 | 3366 | { |
michael@0 | 3367 | nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1"); |
michael@0 | 3368 | if (!gfxInfo) { |
michael@0 | 3369 | *aSuccess = false; |
michael@0 | 3370 | return true; |
michael@0 | 3371 | } |
michael@0 | 3372 | |
michael@0 | 3373 | *aSuccess = NS_SUCCEEDED(gfxInfo->GetFeatureStatus(aFeature, aStatus)); |
michael@0 | 3374 | return true; |
michael@0 | 3375 | } |
michael@0 | 3376 | |
michael@0 | 3377 | bool |
michael@0 | 3378 | ContentParent::RecvAddIdleObserver(const uint64_t& aObserver, const uint32_t& aIdleTimeInS) |
michael@0 | 3379 | { |
michael@0 | 3380 | nsresult rv; |
michael@0 | 3381 | nsCOMPtr<nsIIdleService> idleService = |
michael@0 | 3382 | do_GetService("@mozilla.org/widget/idleservice;1", &rv); |
michael@0 | 3383 | NS_ENSURE_SUCCESS(rv, false); |
michael@0 | 3384 | |
michael@0 | 3385 | nsRefPtr<ParentIdleListener> listener = new ParentIdleListener(this, aObserver); |
michael@0 | 3386 | mIdleListeners.Put(aObserver, listener); |
michael@0 | 3387 | idleService->AddIdleObserver(listener, aIdleTimeInS); |
michael@0 | 3388 | return true; |
michael@0 | 3389 | } |
michael@0 | 3390 | |
michael@0 | 3391 | bool |
michael@0 | 3392 | ContentParent::RecvRemoveIdleObserver(const uint64_t& aObserver, const uint32_t& aIdleTimeInS) |
michael@0 | 3393 | { |
michael@0 | 3394 | nsresult rv; |
michael@0 | 3395 | nsCOMPtr<nsIIdleService> idleService = |
michael@0 | 3396 | do_GetService("@mozilla.org/widget/idleservice;1", &rv); |
michael@0 | 3397 | NS_ENSURE_SUCCESS(rv, false); |
michael@0 | 3398 | |
michael@0 | 3399 | nsRefPtr<ParentIdleListener> listener; |
michael@0 | 3400 | bool found = mIdleListeners.Get(aObserver, &listener); |
michael@0 | 3401 | if (found) { |
michael@0 | 3402 | mIdleListeners.Remove(aObserver); |
michael@0 | 3403 | idleService->RemoveIdleObserver(listener, aIdleTimeInS); |
michael@0 | 3404 | } |
michael@0 | 3405 | |
michael@0 | 3406 | return true; |
michael@0 | 3407 | } |
michael@0 | 3408 | |
michael@0 | 3409 | bool |
michael@0 | 3410 | ContentParent::RecvBackUpXResources(const FileDescriptor& aXSocketFd) |
michael@0 | 3411 | { |
michael@0 | 3412 | #ifndef MOZ_X11 |
michael@0 | 3413 | NS_RUNTIMEABORT("This message only makes sense on X11 platforms"); |
michael@0 | 3414 | #else |
michael@0 | 3415 | NS_ABORT_IF_FALSE(0 > mChildXSocketFdDup.get(), |
michael@0 | 3416 | "Already backed up X resources??"); |
michael@0 | 3417 | mChildXSocketFdDup.forget(); |
michael@0 | 3418 | if (aXSocketFd.IsValid()) { |
michael@0 | 3419 | mChildXSocketFdDup.reset(aXSocketFd.PlatformHandle()); |
michael@0 | 3420 | } |
michael@0 | 3421 | #endif |
michael@0 | 3422 | return true; |
michael@0 | 3423 | } |
michael@0 | 3424 | |
michael@0 | 3425 | PFileDescriptorSetParent* |
michael@0 | 3426 | ContentParent::AllocPFileDescriptorSetParent(const FileDescriptor& aFD) |
michael@0 | 3427 | { |
michael@0 | 3428 | return new FileDescriptorSetParent(aFD); |
michael@0 | 3429 | } |
michael@0 | 3430 | |
michael@0 | 3431 | bool |
michael@0 | 3432 | ContentParent::DeallocPFileDescriptorSetParent(PFileDescriptorSetParent* aActor) |
michael@0 | 3433 | { |
michael@0 | 3434 | delete static_cast<FileDescriptorSetParent*>(aActor); |
michael@0 | 3435 | return true; |
michael@0 | 3436 | } |
michael@0 | 3437 | |
michael@0 | 3438 | } // namespace dom |
michael@0 | 3439 | } // namespace mozilla |
michael@0 | 3440 | |
michael@0 | 3441 | NS_IMPL_ISUPPORTS(ParentIdleListener, nsIObserver) |
michael@0 | 3442 | |
michael@0 | 3443 | NS_IMETHODIMP |
michael@0 | 3444 | ParentIdleListener::Observe(nsISupports*, const char* aTopic, const char16_t* aData) { |
michael@0 | 3445 | mozilla::unused << mParent->SendNotifyIdleObserver(mObserver, |
michael@0 | 3446 | nsDependentCString(aTopic), |
michael@0 | 3447 | nsDependentString(aData)); |
michael@0 | 3448 | return NS_OK; |
michael@0 | 3449 | } |