Bug 1134596 - Separate nsIOService's network detection from offlineMode r=honzab

This commit is contained in:
Valentin Gosu 2015-05-02 00:14:39 +03:00
parent c63887599f
commit 5882106bb7
10 changed files with 171 additions and 56 deletions

View File

@ -610,7 +610,7 @@ pref("mousewheel.with_win.action", 1);
pref("browser.xul.error_pages.enabled", true);
pref("browser.xul.error_pages.expert_bad_cert", false);
// Work Offline is best manually managed by the user.
// If true, network link events will change the value of navigator.onLine
pref("network.manage-offline-status", false);
// We want to make sure mail URLs are handled externally...

View File

@ -806,12 +806,15 @@ ContentChild::InitXPCOM()
NS_WARNING("Couldn't register console listener for child process");
bool isOffline, isLangRTL;
bool isConnected;
ClipboardCapabilities clipboardCaps;
DomainPolicyClone domainPolicy;
SendGetXPCOMProcessAttributes(&isOffline, &isLangRTL, &mAvailableDictionaries,
SendGetXPCOMProcessAttributes(&isOffline, &isConnected,
&isLangRTL, &mAvailableDictionaries,
&clipboardCaps, &domainPolicy);
RecvSetOffline(isOffline);
RecvSetConnectivity(isConnected);
RecvBidiKeyboardNotify(isLangRTL);
// Create the CPOW manager as soon as possible.
@ -1883,6 +1886,18 @@ ContentChild::RecvSetOffline(const bool& offline)
return true;
}
bool
ContentChild::RecvSetConnectivity(const bool& connectivity)
{
nsCOMPtr<nsIIOService> io(do_GetIOService());
nsCOMPtr<nsIIOServiceInternal> ioInternal(do_QueryInterface(io));
NS_ASSERTION(ioInternal, "IO Service can not be null");
ioInternal->SetConnectivity(connectivity);
return true;
}
void
ContentChild::ActorDestroy(ActorDestroyReason why)
{

View File

@ -294,6 +294,7 @@ public:
virtual bool DeallocPRemoteSpellcheckEngineChild(PRemoteSpellcheckEngineChild*) override;
virtual bool RecvSetOffline(const bool& offline) override;
virtual bool RecvSetConnectivity(const bool& connectivity) override;
virtual bool RecvSpeakerManagerNotify() override;

View File

@ -405,6 +405,7 @@ bool ContentParent::sNuwaReady = false;
#endif
#define NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC "ipc:network:set-offline"
#define NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC "ipc:network:set-connectivity"
class MemoryReportRequestParent : public PMemoryReportRequestParent
{
@ -643,6 +644,7 @@ static const char* sObserverTopics[] = {
"xpcom-shutdown",
"profile-before-change",
NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC,
NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC,
"child-memory-reporter-request",
"memory-pressure",
"child-gc-request",
@ -2935,13 +2937,16 @@ ContentParent::RecvAddNewProcess(const uint32_t& aPid,
// Update offline settings.
bool isOffline, isLangRTL;
bool isConnected;
InfallibleTArray<nsString> unusedDictionaries;
ClipboardCapabilities clipboardCaps;
DomainPolicyClone domainPolicy;
RecvGetXPCOMProcessAttributes(&isOffline, &isLangRTL, &unusedDictionaries,
RecvGetXPCOMProcessAttributes(&isOffline, &isConnected,
&isLangRTL, &unusedDictionaries,
&clipboardCaps, &domainPolicy);
mozilla::unused << content->SendSetOffline(isOffline);
mozilla::unused << content->SendSetConnectivity(isConnected);
MOZ_ASSERT(!clipboardCaps.supportsSelectionClipboard() &&
!clipboardCaps.supportsFindClipboard(),
"Unexpected values");
@ -3032,6 +3037,17 @@ ContentParent::Observe(nsISupports* aSubject,
}
#ifdef MOZ_NUWA_PROCESS
}
#endif
}
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
}
#endif
}
// listening for alert notifications
@ -3282,6 +3298,7 @@ ContentParent::RecvGetProcessAttributes(ContentParentId* aCpId,
bool
ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline,
bool* aIsConnected,
bool* aIsLangRTL,
InfallibleTArray<nsString>* dictionaries,
ClipboardCapabilities* clipboardCaps,
@ -3292,6 +3309,9 @@ ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline,
DebugOnly<nsresult> rv = io->GetOffline(aIsOffline);
MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting offline?");
rv = io->GetConnectivity(aIsConnected);
MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting connectivity?");
nsIBidiKeyboard* bidi = nsContentUtils::GetBidiKeyboard();
*aIsLangRTL = false;

View File

@ -546,6 +546,7 @@ private:
bool* aIsForApp,
bool* aIsForBrowser) override;
virtual bool RecvGetXPCOMProcessAttributes(bool* aIsOffline,
bool* aIsConnected,
bool* aIsLangRTL,
InfallibleTArray<nsString>* dictionaries,
ClipboardCapabilities* clipboardCaps,

View File

@ -525,6 +525,7 @@ child:
RegisterChromeItem(ChromeRegistryItem item);
async SetOffline(bool offline);
async SetConnectivity(bool connectivity);
async NotifyVisited(URIParams uri);
@ -669,7 +670,7 @@ parent:
sync GetProcessAttributes()
returns (ContentParentId cpId, bool isForApp, bool isForBrowser);
sync GetXPCOMProcessAttributes()
returns (bool isOffline, bool isLangRTL, nsString[] dictionaries,
returns (bool isOffline, bool isConnected, bool isLangRTL, nsString[] dictionaries,
ClipboardCapabilities clipboardCaps,
DomainPolicyClone domainPolicy);

View File

@ -22,7 +22,7 @@ interface nsILoadInfo;
* as a convenience to the programmer and in some cases to improve performance
* by eliminating intermediate data structures and interfaces.
*/
[scriptable, uuid(b1c3c61d-2df9-4240-ae16-0355b51a2770)]
[scriptable, uuid(4286de5a-b2ea-446f-8f70-e2a461f42694)]
interface nsIIOService : nsISupports
{
/**
@ -178,6 +178,11 @@ interface nsIIOService : nsISupports
*/
attribute boolean offline;
/**
* Returns false if there are no interfaces for a network request
*/
readonly attribute boolean connectivity;
/**
* Set whether network appears to be offline for network connections from
* a given appID.
@ -269,3 +274,14 @@ interface nsIAppOfflineInfo : nsISupports
*/
#define NS_IOSERVICE_APP_OFFLINE_STATUS_TOPIC "network:app-offline-status-changed"
%}
[builtinclass, uuid(cd66ffef-3bc3-40de-841a-e2dcbea213a2)]
interface nsIIOServiceInternal : nsISupports
{
/**
* This is an internal method that should only be called from ContentChild
* in order to pass the connectivity state from the chrome process to the
* content process. It throws if called outside the content process.
*/
void SetConnectivity(in boolean connectivity);
};

View File

@ -158,7 +158,8 @@ NS_IMPL_ISUPPORTS(nsAppOfflineInfo, nsIAppOfflineInfo)
nsIOService::nsIOService()
: mOffline(true)
, mOfflineForProfileChange(false)
, mManageOfflineStatus(false)
, mManageLinkStatus(false)
, mConnectivity(true)
, mSettingOffline(false)
, mSetOfflineValue(false)
, mShutdown(false)
@ -284,17 +285,10 @@ nsIOService::InitializeNetworkLinkService()
if (mNetworkLinkService) {
mNetworkLinkServiceInitialized = true;
}
else {
// We can't really determine if the machine has a usable network connection,
// so let's cross our fingers!
mManageOfflineStatus = false;
}
if (mManageOfflineStatus)
OnNetworkLinkEvent(NS_NETWORK_LINK_DATA_UNKNOWN);
else
SetOffline(false);
// After initializing the networkLinkService, query the connectivity state
OnNetworkLinkEvent(NS_NETWORK_LINK_DATA_UNKNOWN);
return rv;
}
@ -323,6 +317,7 @@ NS_IMPL_ISUPPORTS(nsIOService,
nsINetUtil,
nsISpeculativeConnect,
nsIObserver,
nsIIOServiceInternal,
nsISupportsWeakReference)
////////////////////////////////////////////////////////////////////////////////
@ -955,7 +950,8 @@ nsIOService::SetOffline(bool offline)
mProxyService->ReloadPAC();
// don't care if notification fails
if (observerService)
// Only send the ONLINE notification if there is connectivity
if (observerService && mConnectivity)
observerService->NotifyObservers(subject,
NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
NS_LITERAL_STRING(NS_IOSERVICE_ONLINE).get());
@ -981,6 +977,72 @@ nsIOService::SetOffline(bool offline)
return NS_OK;
}
NS_IMETHODIMP
nsIOService::GetConnectivity(bool *aConnectivity)
{
*aConnectivity = mConnectivity;
return NS_OK;
}
NS_IMETHODIMP
nsIOService::SetConnectivity(bool aConnectivity)
{
// This should only be called from ContentChild to pass the connectivity
// value from the chrome process to the content process.
if (XRE_GetProcessType() == GeckoProcessType_Default) {
return NS_ERROR_NOT_AVAILABLE;
}
return SetConnectivityInternal(aConnectivity);
}
nsresult
nsIOService::SetConnectivityInternal(bool aConnectivity)
{
if (mConnectivity == aConnectivity) {
// Nothing to do here.
return NS_OK;
}
mConnectivity = aConnectivity;
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (!observerService) {
return NS_OK;
}
// This notification sends the connectivity to the child processes
if (XRE_GetProcessType() == GeckoProcessType_Default) {
observerService->NotifyObservers(nullptr,
NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC, aConnectivity ?
MOZ_UTF16("true") :
MOZ_UTF16("false"));
}
if (mOffline) {
// We don't need to send any notifications if we're offline
return NS_OK;
}
if (aConnectivity) {
// If we were previously offline due to connectivity=false,
// send the ONLINE notification
observerService->NotifyObservers(
static_cast<nsIIOService *>(this),
NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
NS_LITERAL_STRING(NS_IOSERVICE_ONLINE).get());
} else {
// If we were previously online and lost connectivity
// send the OFFLINE notification
const nsLiteralString offlineString(MOZ_UTF16(NS_IOSERVICE_OFFLINE));
observerService->NotifyObservers(static_cast<nsIIOService *>(this),
NS_IOSERVICE_GOING_OFFLINE_TOPIC,
offlineString.get());
observerService->NotifyObservers(static_cast<nsIIOService *>(this),
NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
offlineString.get());
}
return NS_OK;
}
NS_IMETHODIMP
nsIOService::AllowPort(int32_t inPort, const char *scheme, bool *_retval)
@ -1209,11 +1271,8 @@ nsIOService::Observe(nsISupports *subject,
} else if (!strcmp(topic, kProfileChangeNetRestoreTopic)) {
if (mOfflineForProfileChange) {
mOfflineForProfileChange = false;
if (!mManageOfflineStatus ||
NS_FAILED(OnNetworkLinkEvent(NS_NETWORK_LINK_DATA_UNKNOWN))) {
SetOffline(false);
}
}
SetOffline(false);
}
} else if (!strcmp(topic, kProfileDoChange)) {
if (data && NS_LITERAL_STRING("startup").Equals(data)) {
// Lazy initialization of network link service (see bug 620472)
@ -1221,6 +1280,10 @@ nsIOService::Observe(nsISupports *subject,
// Set up the initilization flag regardless the actuall result.
// If we fail here, we will fail always on.
mNetworkLinkServiceInitialized = true;
// The browser starts off as offline. We go into online mode after this.
SetOffline(false);
// And now reflect the preference setting
nsCOMPtr<nsIPrefBranch> prefBranch;
GetPrefBranch(getter_AddRefs(prefBranch));
@ -1237,9 +1300,7 @@ nsIOService::Observe(nsISupports *subject,
// Break circular reference.
mProxyService = nullptr;
} else if (!strcmp(topic, NS_NETWORK_LINK_TOPIC)) {
if (!mOfflineForProfileChange && mManageOfflineStatus) {
OnNetworkLinkEvent(NS_ConvertUTF16toUTF8(data).get());
}
OnNetworkLinkEvent(NS_ConvertUTF16toUTF8(data).get());
} else if (!strcmp(topic, NS_WIDGET_WAKE_OBSERVER_TOPIC)) {
// coming back alive from sleep
nsCOMPtr<nsIObserverService> observerService =
@ -1383,32 +1444,26 @@ nsIOService::NewSimpleNestedURI(nsIURI* aURI, nsIURI** aResult)
NS_IMETHODIMP
nsIOService::SetManageOfflineStatus(bool aManage)
{
nsresult rv = NS_OK;
mManageLinkStatus = aManage;
// SetManageOfflineStatus must throw when we fail to go from non-managed
// to managed. Usually because there is no link monitoring service
// available. Failure to do this switch is detected by a failure of
// OnNetworkLinkEvent(). When there is no network link available during
// call to InitializeNetworkLinkService(), application is put to offline
// mode. And when we change mMangeOfflineStatus to false on the next line
// we get stuck on being offline even though the link becomes later
// available.
bool wasManaged = mManageOfflineStatus;
mManageOfflineStatus = aManage;
// When detection is not activated, the default connectivity state is true.
if (!mManageLinkStatus) {
SetConnectivityInternal(true);
return NS_OK;
}
InitializeNetworkLinkService();
if (mManageOfflineStatus && !wasManaged) {
rv = OnNetworkLinkEvent(NS_NETWORK_LINK_DATA_UNKNOWN);
if (NS_FAILED(rv))
mManageOfflineStatus = false;
}
return rv;
// If the NetworkLinkService is already initialized, it does not call
// OnNetworkLinkEvent. This is needed, when mManageLinkStatus goes from
// false to true.
OnNetworkLinkEvent(NS_NETWORK_LINK_DATA_UNKNOWN);
return NS_OK;
}
NS_IMETHODIMP
nsIOService::GetManageOfflineStatus(bool* aManage) {
*aManage = mManageOfflineStatus;
nsIOService::GetManageOfflineStatus(bool* aManage)
{
*aManage = mManageLinkStatus;
return NS_OK;
}
@ -1422,7 +1477,7 @@ nsIOService::OnNetworkLinkEvent(const char *data)
if (mShutdown)
return NS_ERROR_NOT_AVAILABLE;
if (!mManageOfflineStatus) {
if (!mManageLinkStatus) {
return NS_OK;
}
@ -1435,21 +1490,19 @@ nsIOService::OnNetworkLinkEvent(const char *data)
// dial option is set to always autodial. If so, then we are
// always up for the purposes of offline management.
if (autodialEnabled) {
bool isUp = true;
#if defined(XP_WIN)
// On Windows, we should first check with the OS to see if
// autodial is enabled. If it is enabled then we are allowed
// to manage the offline state.
if (nsNativeConnectionHelper::IsAutodialEnabled()) {
return SetOffline(false);
}
#else
return SetOffline(false);
isUp = nsNativeConnectionHelper::IsAutodialEnabled();
#endif
return SetConnectivityInternal(isUp);
}
}
}
bool isUp;
bool isUp = true;
if (!strcmp(data, NS_NETWORK_LINK_DATA_CHANGED)) {
// CHANGED means UP/DOWN didn't change
return NS_OK;
@ -1465,7 +1518,7 @@ nsIOService::OnNetworkLinkEvent(const char *data)
return NS_OK;
}
return SetOffline(!isUp);
return SetConnectivityInternal(isUp);
}
NS_IMETHODIMP

View File

@ -26,6 +26,7 @@
// Intended internal use only for remoting offline/inline events.
// See Bug 552829
#define NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC "ipc:network:set-offline"
#define NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC "ipc:network:set-connectivity"
static const char gScheme[][sizeof("resource")] =
{"chrome", "file", "http", "https", "jar", "data", "resource"};
@ -49,6 +50,7 @@ class nsIOService final : public nsIIOService2
, public nsINetUtil
, public nsISpeculativeConnect
, public nsSupportsWeakReference
, public nsIIOServiceInternal
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
@ -57,6 +59,7 @@ public:
NS_DECL_NSIOBSERVER
NS_DECL_NSINETUTIL
NS_DECL_NSISPECULATIVECONNECT
NS_DECL_NSIIOSERVICEINTERNAL
// Gets the singleton instance of the IO Service, creating it as needed
// Returns nullptr on out of memory or failure to initialize.
@ -86,6 +89,7 @@ private:
// - destroy using Release
nsIOService();
~nsIOService();
nsresult SetConnectivityInternal(bool aConnectivity);
nsresult OnNetworkLinkEvent(const char *data);
@ -121,7 +125,8 @@ private:
private:
bool mOffline;
bool mOfflineForProfileChange;
bool mManageOfflineStatus;
bool mManageLinkStatus;
bool mConnectivity;
// Used to handle SetOffline() reentrancy. See the comment in
// SetOffline() for more details.

View File

@ -1963,10 +1963,13 @@ inline bool
NS_IsOffline()
{
bool offline = true;
bool connectivity = true;
nsCOMPtr<nsIIOService> ios = do_GetIOService();
if (ios)
if (ios) {
ios->GetOffline(&offline);
return offline;
ios->GetConnectivity(&connectivity);
}
return offline || !connectivity;
}
inline bool