--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -677,16 +677,32 @@ static const char* sObserverTopics[] = {
"profiler-stopped",
"profiler-paused",
"profiler-resumed",
"profiler-subprocess-gather",
"profiler-subprocess",
#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>
ContentParent::RunNuwaProcess()
{
MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<ContentParent> nuwaProcess =
new ContentParent(/* aApp = */ nullptr,
/* aOpener = */ nullptr,
/* aIsForBrowser = */ false,
@@ -2918,25 +2934,62 @@ ContentParent::ForkNewProcess(bool aBloc
if (mNuwaParent->ForkNewProcess(pid, mozilla::Move(fds), aBlocking)) {
OnNewProcessCreated(pid, mozilla::Move(fds));
}
#else
NS_ERROR("ContentParent::ForkNewProcess() not implemented!");
#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<nsIObserverService> 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()
{
#ifdef MOZ_NUWA_PROCESS
// Protection from unauthorized IPC message is done in PNuwa protocol.
// Just assert that this actor is really for the Nuwa process.
MOZ_ASSERT(IsNuwaProcess());
sNuwaReady = true;
+ KeepNuwaSafeObserverTopics(this);
+
PreallocatedProcessManager::OnNuwaReady();
return;
#else
NS_ERROR("ContentParent::OnNuwaReady() not implemented!");
return;
#endif
}
@@ -3020,69 +3073,67 @@ ContentParent::Observe(nsISupports* aSub
NS_ProcessNextEvent(nullptr, true);
}
NS_ASSERTION(!mSubprocess, "Close should have nulled mSubprocess");
}
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),
NS_LITERAL_STRING("-no-forward"))) {
unused << SendFlushMemory(nsDependentString(aData));
}
// listening for remotePrefs...
else if (!strcmp(aTopic, "nsPref:changed")) {
// We know prefs are ASCII here.
NS_LossyConvertUTF16toASCII strData(aData);
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) {
sNuwaPrefUpdates = new nsTArray<PrefSetting>();
}
sNuwaPrefUpdates->AppendElement(pref);
} else if (!SendPreferenceUpdate(pref)) {
return NS_ERROR_NOT_AVAILABLE;
}
#else
if (!SendPreferenceUpdate(pref)) {
return NS_ERROR_NOT_AVAILABLE;
}
#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") ||
!strcmp(aTopic, "alertclickcallback") ||
!strcmp(aTopic, "alertshow") ) {
if (!SendNotifyAlertsObserver(nsDependentCString(aTopic),
nsDependentString(aData)))
return NS_ERROR_NOT_AVAILABLE;
@@ -3098,23 +3149,17 @@ ContentParent::Observe(nsISupports* aSub
}
else if (!strcmp(aTopic, "last-pb-context-exited")) {
unused << SendLastPrivateDocShellDestroyed();
}
else if (!strcmp(aTopic, "file-watcher-update")) {
nsCString creason;
CopyUTF16toUTF8(aData, creason);
DeviceStorageFile* file = static_cast<DeviceStorageFile*>(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)) {
nsCOMPtr<nsIVolume> vol = do_QueryInterface(aSubject);
if (!vol) {
return NS_ERROR_NOT_AVAILABLE;
}
@@ -3137,37 +3182,27 @@ ContentParent::Observe(nsISupports* aSub
vol->GetIsMediaPresent(&isMediaPresent);
vol->GetIsSharing(&isSharing);
vol->GetIsFormatting(&isFormatting);
vol->GetIsFake(&isFake);
vol->GetIsUnmounting(&isUnmounting);
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
// Make sure accessibility is running in content process when accessibility
// gets initiated in chrome process.
else if (aData && (*aData == '1') &&
!strcmp(aTopic, "a11y-init-or-shutdown")) {
unused << SendActivateA11y();
@@ -4463,22 +4498,20 @@ ContentParent::DoSendAsyncMessage(JSCont
if (!BuildClonedMessageDataForParent(this, aData, data)) {
return false;
}
InfallibleTArray<CpowEntry> cpows;
jsipc::CPOWManager* mgr = GetCPOWManager();
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));
}
bool
ContentParent::CheckPermission(const nsAString& aPermission)
{
return AssertAppProcessPermission(this, NS_ConvertUTF16toUTF8(aPermission).get());
}