Bug 1317511 - Share captive portal state with the content process r=bagder

MozReview-Commit-ID: 5FnM9DNDWwL
This commit is contained in:
Valentin Gosu 2016-11-17 17:35:24 +01:00
parent 84b8909f1f
commit 51cb7b5e93
9 changed files with 117 additions and 6 deletions

View File

@ -54,6 +54,7 @@
#include "mozilla/layers/ImageBridgeChild.h"
#include "mozilla/layout/RenderFrameChild.h"
#include "mozilla/net/NeckoChild.h"
#include "mozilla/net/CaptivePortalService.h"
#include "mozilla/plugins/PluginInstanceParent.h"
#include "mozilla/plugins/PluginModuleParent.h"
#include "mozilla/widget/WidgetMessageUtils.h"
@ -961,17 +962,19 @@ ContentChild::InitXPCOM()
bool isOffline, isLangRTL, haveBidiKeyboards;
bool isConnected;
int32_t captivePortalState;
ClipboardCapabilities clipboardCaps;
DomainPolicyClone domainPolicy;
StructuredCloneData initialData;
SendGetXPCOMProcessAttributes(&isOffline, &isConnected,
SendGetXPCOMProcessAttributes(&isOffline, &isConnected, &captivePortalState,
&isLangRTL, &haveBidiKeyboards,
&mAvailableDictionaries,
&clipboardCaps, &domainPolicy, &initialData,
&mFontFamilies);
RecvSetOffline(isOffline);
RecvSetConnectivity(isConnected);
RecvSetCaptivePortalState(captivePortalState);
RecvBidiKeyboardNotify(isLangRTL, haveBidiKeyboards);
// Create the CPOW manager as soon as possible.
@ -2066,6 +2069,21 @@ ContentChild::RecvSetConnectivity(const bool& connectivity)
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentChild::RecvSetCaptivePortalState(const int32_t& aState)
{
nsCOMPtr<nsICaptivePortalService> cps = do_GetService(NS_CAPTIVEPORTAL_CID);
if (!cps) {
return IPC_OK();
}
mozilla::net::CaptivePortalService *portal =
static_cast<mozilla::net::CaptivePortalService*>(cps.get());
portal->SetStateInChild(aState);
return IPC_OK();
}
void
ContentChild::ActorDestroy(ActorDestroyReason why)
{

View File

@ -369,6 +369,7 @@ public:
virtual mozilla::ipc::IPCResult RecvSetOffline(const bool& offline) override;
virtual mozilla::ipc::IPCResult RecvSetConnectivity(const bool& connectivity) override;
virtual mozilla::ipc::IPCResult RecvSetCaptivePortalState(const int32_t& state) override;
virtual mozilla::ipc::IPCResult RecvNotifyLayerAllocated(const dom::TabId& aTabId, const uint64_t& aLayersId) override;

View File

@ -179,6 +179,7 @@
#include "mozilla/StyleSheet.h"
#include "mozilla/StyleSheetInlines.h"
#include "nsHostObjectProtocolHandler.h"
#include "nsICaptivePortalService.h"
#include "nsIBidiKeyboard.h"
@ -517,6 +518,7 @@ static const char* sObserverTopics[] = {
"profile-before-change",
NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC,
NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC,
NS_IPC_CAPTIVE_PORTAL_SET_STATE,
"memory-pressure",
"child-gc-request",
"child-cc-request",
@ -2385,6 +2387,17 @@ ContentParent::Observe(nsISupports* aSubject,
if (!SendSetConnectivity(NS_LITERAL_STRING("true").Equals(aData))) {
return NS_ERROR_NOT_AVAILABLE;
}
} else if (!strcmp(aTopic, NS_IPC_CAPTIVE_PORTAL_SET_STATE)) {
nsCOMPtr<nsICaptivePortalService> cps = do_QueryInterface(aSubject);
MOZ_ASSERT(cps, "Should QI to a captive portal service");
if (!cps) {
return NS_ERROR_FAILURE;
}
int32_t state;
cps->GetState(&state);
if (!SendSetCaptivePortalState(state)) {
return NS_ERROR_NOT_AVAILABLE;
}
}
// listening for alert notifications
else if (!strcmp(aTopic, "alertfinished") ||
@ -2535,6 +2548,7 @@ ContentParent::RecvGetProcessAttributes(ContentParentId* aCpId,
mozilla::ipc::IPCResult
ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline,
bool* aIsConnected,
int32_t* aCaptivePortalState,
bool* aIsLangRTL,
bool* aHaveBidiKeyboards,
InfallibleTArray<nsString>* dictionaries,
@ -2551,6 +2565,12 @@ ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline,
rv = io->GetConnectivity(aIsConnected);
MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting connectivity?");
*aCaptivePortalState = nsICaptivePortalService::UNKNOWN;
nsCOMPtr<nsICaptivePortalService> cps = do_GetService(NS_CAPTIVEPORTAL_CONTRACTID);
if (cps) {
cps->GetState(aCaptivePortalState);
}
nsIBidiKeyboard* bidi = nsContentUtils::GetBidiKeyboard();
*aIsLangRTL = false;

View File

@ -693,6 +693,7 @@ private:
virtual mozilla::ipc::IPCResult
RecvGetXPCOMProcessAttributes(bool* aIsOffline,
bool* aIsConnected,
int32_t* aCaptivePortalState,
bool* aIsLangRTL,
bool* aHaveBidiKeyboards,
InfallibleTArray<nsString>* dictionaries,

View File

@ -486,6 +486,7 @@ child:
async SetOffline(bool offline);
async SetConnectivity(bool connectivity);
async SetCaptivePortalState(int32_t aState);
async NotifyVisited(URIParams uri);
@ -692,7 +693,8 @@ parent:
sync GetProcessAttributes()
returns (ContentParentId cpId, bool isForBrowser);
sync GetXPCOMProcessAttributes()
returns (bool isOffline, bool isConnected, bool isLangRTL,
returns (bool isOffline, bool isConnected, int32_t captivePortalState,
bool isLangRTL,
bool haveBidiKeyboards, nsString[] dictionaries,
ClipboardCapabilities clipboardCaps,
DomainPolicyClone domainPolicy,

View File

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CaptivePortalService.h"
#include "mozilla/net/CaptivePortalService.h"
#include "mozilla/Services.h"
#include "mozilla/Preferences.h"
#include "nsIObserverService.h"
@ -56,7 +56,7 @@ CaptivePortalService::PerformCheck()
if (mRequestInProgress || !mInitialized || !mStarted) {
return NS_OK;
}
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
nsresult rv;
if (!mCaptivePortalDetector) {
mCaptivePortalDetector =
@ -77,6 +77,7 @@ nsresult
CaptivePortalService::RearmTimer()
{
// Start a timer to recheck
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
if (mTimer) {
mTimer->Cancel();
}
@ -96,11 +97,17 @@ CaptivePortalService::RearmTimer()
nsresult
CaptivePortalService::Initialize()
{
if (mInitialized || XRE_GetProcessType() != GeckoProcessType_Default) {
if (mInitialized) {
return NS_OK;
}
mInitialized = true;
// Only the main process service should actually do anything. The service in
// the content process only mirrors the CP state in the main process.
if (XRE_GetProcessType() != GeckoProcessType_Default) {
return NS_OK;
}
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (observerService) {
@ -120,6 +127,11 @@ CaptivePortalService::Start()
return NS_ERROR_NOT_INITIALIZED;
}
if (XRE_GetProcessType() != GeckoProcessType_Default) {
// Doesn't do anything if called in the content process.
return NS_OK;
}
if (mStarted) {
return NS_OK;
}
@ -149,6 +161,11 @@ CaptivePortalService::Stop()
{
LOG(("CaptivePortalService::Stop\n"));
if (XRE_GetProcessType() != GeckoProcessType_Default) {
// Doesn't do anything when called in the content process.
return NS_OK;
}
if (!mStarted) {
return NS_OK;
}
@ -166,6 +183,17 @@ CaptivePortalService::Stop()
return NS_OK;
}
void
CaptivePortalService::SetStateInChild(int32_t aState)
{
// This should only be called in the content process, from ContentChild.cpp
// in order to mirror the captive portal state set in the chrome process.
MOZ_ASSERT(XRE_GetProcessType() != GeckoProcessType_Default);
mState = aState;
mLastChecked = TimeStamp::Now();
}
//-----------------------------------------------------------------------------
// CaptivePortalService::nsICaptivePortalService
//-----------------------------------------------------------------------------
@ -187,6 +215,11 @@ CaptivePortalService::RecheckCaptivePortal()
{
LOG(("CaptivePortalService::RecheckCaptivePortal\n"));
if (XRE_GetProcessType() != GeckoProcessType_Default) {
// Doesn't do anything if called in the content process.
return NS_OK;
}
// This is called for user activity. We need to reset the slack count,
// so the checks continue to be quite frequent.
mSlackCount = 0;
@ -215,6 +248,7 @@ CaptivePortalService::Notify(nsITimer *aTimer)
{
LOG(("CaptivePortalService::Notify\n"));
MOZ_ASSERT(aTimer == mTimer);
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
PerformCheck();
@ -243,6 +277,11 @@ CaptivePortalService::Observe(nsISupports *aSubject,
const char * aTopic,
const char16_t * aData)
{
if (XRE_GetProcessType() != GeckoProcessType_Default) {
// Doesn't do anything if called in the content process.
return NS_OK;
}
LOG(("CaptivePortalService::Observe() topic=%s\n", aTopic));
if (!strcmp(aTopic, kOpenCaptivePortalLoginEvent)) {
// A redirect or altered content has been detected.
@ -265,6 +304,15 @@ CaptivePortalService::Observe(nsISupports *aSubject,
mLastChecked = TimeStamp::Now();
mSlackCount = 0;
}
// Send notification so that the captive portal state is mirrored in the
// content process.
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
if (observerService) {
nsCOMPtr<nsICaptivePortalService> cps(this);
observerService->NotifyObservers(cps, NS_IPC_CAPTIVE_PORTAL_SET_STATE, nullptr);
}
return NS_OK;
}
@ -275,6 +323,7 @@ NS_IMETHODIMP
CaptivePortalService::Prepare()
{
LOG(("CaptivePortalService::Prepare\n"));
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
// XXX: Finish preparation shouldn't be called until dns and routing is available.
if (mCaptivePortalDetector) {
mCaptivePortalDetector->FinishPreparation(kInterfaceName);
@ -286,6 +335,7 @@ NS_IMETHODIMP
CaptivePortalService::Complete(bool success)
{
LOG(("CaptivePortalService::Complete(success=%d) mState=%d\n", success, mState));
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
mLastChecked = TimeStamp::Now();
if ((mState == UNKNOWN || mState == NOT_CAPTIVE) && success) {
mState = NOT_CAPTIVE;

View File

@ -34,6 +34,10 @@ public:
nsresult Initialize();
nsresult Start();
nsresult Stop();
// This method is only called in the content process, in order to mirror
// the captive portal state in the parent process.
void SetStateInChild(int32_t aState);
private:
virtual ~CaptivePortalService();
nsresult PerformCheck();

View File

@ -15,6 +15,9 @@ interface nsICaptivePortalServiceCallback : nsISupports
/**
* Service used for captive portal detection.
* The service is only active in the main process. It is also available in the
* content process, but only to mirror the captive portal state from the main
* process.
*/
[scriptable, uuid(bdbe0555-fc3d-4f7b-9205-c309ceb2d641)]
interface nsICaptivePortalService : nsISupports
@ -28,6 +31,7 @@ interface nsICaptivePortalService : nsISupports
* Called from XPCOM to trigger a captive portal recheck.
* A network request will only be performed if no other checks are currently
* ongoing.
* Will not do anything if called in the content process.
*/
void recheckCaptivePortal();
@ -42,3 +46,14 @@ interface nsICaptivePortalService : nsISupports
*/
readonly attribute unsigned long long lastChecked;
};
%{C++
/**
* This observer notification will be emitted when the captive portal state
* changes. After receiving it, the ContentParent will send an IPC message
* to the ContentChild, which will set the state in the captive portal service
* in the child.
*/
#define NS_IPC_CAPTIVE_PORTAL_SET_STATE "ipc:network:captive-portal-set-state"
%}

View File

@ -53,7 +53,7 @@
#include "mozilla/ipc/URIUtils.h"
#include "mozilla/net/NeckoChild.h"
#include "mozilla/dom/ContentParent.h"
#include "CaptivePortalService.h"
#include "mozilla/net/CaptivePortalService.h"
#include "ReferrerPolicy.h"
#include "nsContentSecurityManager.h"
#include "nsContentUtils.h"