diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index c8c0fb79f39..6e666c8b053 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -2174,10 +2174,7 @@ bool ContentChild::RecvFlushMemory(const nsString& reason) { #ifdef MOZ_NUWA_PROCESS - if (IsNuwaProcess()) { - // Don't flush memory in the nuwa process: the GC thread could be frozen. - return true; - } + MOZ_ASSERT(!IsNuwaProcess() || !IsNuwaReady()); #endif nsCOMPtr os = mozilla::services::GetObserverService(); @@ -2416,11 +2413,7 @@ bool ContentChild::RecvMinimizeMemoryUsage() { #ifdef MOZ_NUWA_PROCESS - if (IsNuwaProcess()) { - // Don't minimize memory in the nuwa process: it will perform GC, but the - // GC thread could be frozen. - return true; - } + MOZ_ASSERT(!IsNuwaProcess() || !IsNuwaReady()); #endif nsCOMPtr mgr = do_GetService("@mozilla.org/memory-reporter-manager;1"); diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index c0c28953450..f4cc7bfdc7a 100755 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -682,6 +682,22 @@ static const char* sObserverTopics[] = { #endif }; +#ifdef MOZ_NUWA_PROCESS +// Contains the observer topics that can be sent to the Nuwa process after it +// becomes ready. The ContentParent instance will unregister sObserverTopics +// if not listed in sNuwaSafeObserverTopics. +static const char* sNuwaSafeObserverTopics[] = { + "xpcom-shutdown", + "profile-before-change", +#ifdef MOZ_WIDGET_GONK + "phone-state-changed", +#endif +#ifdef ACCESSIBILITY + "a11y-init-or-shutdown", +#endif + "nsPref:Changed" +}; +#endif /* static */ already_AddRefed ContentParent::RunNuwaProcess() { @@ -2923,6 +2939,41 @@ ContentParent::ForkNewProcess(bool aBlocking) #endif } +#ifdef MOZ_NUWA_PROCESS +// Keep only observer topics listed in sNuwaSafeObserverTopics and unregister +// all the other registered topics. +static void +KeepNuwaSafeObserverTopics(ContentParent* aNuwaContentParent) +{ + MOZ_ASSERT(aNuwaContentParent && aNuwaContentParent->IsNuwaProcess()); + + nsCOMPtr obs = mozilla::services::GetObserverService(); + if (!obs) { + return; + } + + size_t topicLength = ArrayLength(sObserverTopics); + for (size_t i = 0; i < topicLength; ++i) { + bool nuwaSafe = false; + size_t safeTopicLength = ArrayLength(sNuwaSafeObserverTopics); + + for (size_t j = 0; j < safeTopicLength; j++) { + if (!nsCRT::strcmp(sObserverTopics[i], + sNuwaSafeObserverTopics[j])) { + // In the whitelist: don't need to unregister. + nuwaSafe = true; + break; + } + } + + if (!nuwaSafe) { + obs->RemoveObserver(aNuwaContentParent, sObserverTopics[i]); + } + } + +} +#endif + void ContentParent::OnNuwaReady() { @@ -2932,6 +2983,8 @@ ContentParent::OnNuwaReady() MOZ_ASSERT(IsNuwaProcess()); sNuwaReady = true; + KeepNuwaSafeObserverTopics(this); + PreallocatedProcessManager::OnNuwaReady(); return; #else @@ -3025,6 +3078,16 @@ ContentParent::Observe(nsISupports* aSubject, if (!mIsAlive || !mSubprocess) return NS_OK; + // The Nuwa process unregisters the topics after it becomes ready except for + // the ones listed in sNuwaSafeObserverTopics. If the topic needs to be + // observed by the Nuwa process, either for: + // 1. The topic is safe for the Nuwa process, either: + // 1.1 The state can safely happen (only run on the main thread) in the Nuwa + // process (e.g. "a11y-init-or-shutdown"), or + // 1.2 The topic doesn't send an IPC message (e.g. "xpcom-shutdown"). + // 2. The topic needs special handling (e.g. nsPref:Changed), + // add the topic to sNuwaSafeObserverTopics and then handle it if necessary. + // listening for memory pressure event if (!strcmp(aTopic, "memory-pressure") && !StringEndsWith(nsDependentString(aData), @@ -3039,7 +3102,7 @@ ContentParent::Observe(nsISupports* aSubject, PrefSetting pref(strData, null_t(), null_t()); Preferences::GetPreference(&pref); #ifdef MOZ_NUWA_PROCESS - if (IsNuwaProcess() && PreallocatedProcessManager::IsNuwaReady()) { + if (IsReadyNuwaProcess()) { // Don't send the pref update to the Nuwa process. Save the update // to send to the forked child. if (!sNuwaPrefUpdates) { @@ -3056,28 +3119,16 @@ ContentParent::Observe(nsISupports* aSubject, #endif } else if (!strcmp(aTopic, NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC)) { - NS_ConvertUTF16toUTF8 dataStr(aData); - const char *offline = dataStr.get(); -#ifdef MOZ_NUWA_PROCESS - if (!(IsNuwaReady() && IsNuwaProcess())) { -#endif - if (!SendSetOffline(!strcmp(offline, "true") ? true : false)) { - return NS_ERROR_NOT_AVAILABLE; - } -#ifdef MOZ_NUWA_PROCESS - } -#endif + NS_ConvertUTF16toUTF8 dataStr(aData); + const char *offline = dataStr.get(); + if (!SendSetOffline(!strcmp(offline, "true") ? true : false)) { + return NS_ERROR_NOT_AVAILABLE; + } } else if (!strcmp(aTopic, NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC)) { -#ifdef MOZ_NUWA_PROCESS - if (!(IsNuwaReady() && IsNuwaProcess())) { -#endif - if (!SendSetConnectivity(NS_LITERAL_STRING("true").Equals(aData))) { - return NS_ERROR_NOT_AVAILABLE; - } -#ifdef MOZ_NUWA_PROCESS + if (!SendSetConnectivity(NS_LITERAL_STRING("true").Equals(aData))) { + return NS_ERROR_NOT_AVAILABLE; } -#endif } // listening for alert notifications else if (!strcmp(aTopic, "alertfinished") || @@ -3103,13 +3154,7 @@ ContentParent::Observe(nsISupports* aSubject, nsCString creason; CopyUTF16toUTF8(aData, creason); DeviceStorageFile* file = static_cast(aSubject); - -#ifdef MOZ_NUWA_PROCESS - if (!(IsNuwaReady() && IsNuwaProcess())) -#endif - { - unused << SendFilePathUpdate(file->mStorageType, file->mStorageName, file->mPath, creason); - } + unused << SendFilePathUpdate(file->mStorageType, file->mStorageName, file->mPath, creason); } #ifdef MOZ_WIDGET_GONK else if(!strcmp(aTopic, NS_VOLUME_STATE_CHANGED)) { @@ -3142,27 +3187,17 @@ ContentParent::Observe(nsISupports* aSubject, vol->GetIsRemovable(&isRemovable); vol->GetIsHotSwappable(&isHotSwappable); -#ifdef MOZ_NUWA_PROCESS - if (!(IsNuwaReady() && IsNuwaProcess())) -#endif - { - unused << SendFileSystemUpdate(volName, mountPoint, state, - mountGeneration, isMediaPresent, - isSharing, isFormatting, isFake, - isUnmounting, isRemovable, isHotSwappable); - } + unused << SendFileSystemUpdate(volName, mountPoint, state, + mountGeneration, isMediaPresent, + isSharing, isFormatting, isFake, + isUnmounting, isRemovable, isHotSwappable); } else if (!strcmp(aTopic, "phone-state-changed")) { nsString state(aData); unused << SendNotifyPhoneStateChange(state); } else if(!strcmp(aTopic, NS_VOLUME_REMOVED)) { -#ifdef MOZ_NUWA_PROCESS - if (!(IsNuwaReady() && IsNuwaProcess())) -#endif - { - nsString volName(aData); - unused << SendVolumeRemoved(volName); - } + nsString volName(aData); + unused << SendVolumeRemoved(volName); } #endif #ifdef ACCESSIBILITY @@ -4468,12 +4503,10 @@ ContentParent::DoSendAsyncMessage(JSContext* aCx, if (aCpows && (!mgr || !mgr->Wrap(aCx, aCpows, &cpows))) { return false; } -#ifdef MOZ_NUWA_PROCESS - if (IsNuwaProcess() && IsNuwaReady()) { + if (IsReadyNuwaProcess()) { // Nuwa won't receive frame messages after it is frozen. return true; } -#endif return SendAsyncMessage(nsString(aMessage), data, cpows, Principal(aPrincipal)); } diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index 4021b0608ab..3011fa40ddb 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -260,6 +260,15 @@ public: bool IsNuwaProcess(); #endif + // A shorthand for checking if the Nuwa process is ready. + bool IsReadyNuwaProcess() { +#ifdef MOZ_NUWA_PROCESS + return IsNuwaProcess() && IsNuwaReady(); +#else + return false; +#endif + } + GeckoChildProcessHost* Process() { return mSubprocess; } diff --git a/ipc/glue/MessageLink.cpp b/ipc/glue/MessageLink.cpp index 219c2281140..7b302219126 100644 --- a/ipc/glue/MessageLink.cpp +++ b/ipc/glue/MessageLink.cpp @@ -187,6 +187,7 @@ ProcessLink::SendMessage(Message *msg) case mozilla::dom::PNuwa::Msg_Fork__ID: case mozilla::dom::PNuwa::Reply_AddNewProcess__ID: case mozilla::dom::PContent::Msg_NotifyPhoneStateChange__ID: + case mozilla::dom::PContent::Msg_ActivateA11y__ID: case mozilla::hal_sandbox::PHal::Msg_NotifyNetworkChange__ID: case GOODBYE_MESSAGE_TYPE: break;