зеркало из https://github.com/mozilla/gecko-dev.git
Bug 596776 - 'IndexedDB: Prevent quota prompt from hanging on shutdown'. r=sicking.
This commit is contained in:
Родитель
84d9639d46
Коммит
e8315ce8b9
|
@ -5774,6 +5774,7 @@ var IndexedDBPromptHelper = {
|
|||
|
||||
_quotaPrompt: "indexedDB-quota-prompt",
|
||||
_quotaResponse: "indexedDB-quota-response",
|
||||
_quotaCancel: "indexedDB-quota-cancel",
|
||||
|
||||
_notificationIcon: "indexedDB-notification-icon",
|
||||
|
||||
|
@ -5781,18 +5782,21 @@ var IndexedDBPromptHelper = {
|
|||
function IndexedDBPromptHelper_init() {
|
||||
Services.obs.addObserver(this, this._permissionsPrompt, false);
|
||||
Services.obs.addObserver(this, this._quotaPrompt, false);
|
||||
Services.obs.addObserver(this, this._quotaCancel, false);
|
||||
},
|
||||
|
||||
uninit:
|
||||
function IndexedDBPromptHelper_uninit() {
|
||||
Services.obs.removeObserver(this, this._permissionsPrompt, false);
|
||||
Services.obs.removeObserver(this, this._quotaPrompt, false);
|
||||
Services.obs.removeObserver(this, this._quotaCancel, false);
|
||||
},
|
||||
|
||||
observe:
|
||||
function IndexedDBPromptHelper_observe(subject, topic, data) {
|
||||
if (topic != this._permissionsPrompt &&
|
||||
topic != this._quotaPrompt) {
|
||||
topic != this._quotaPrompt &&
|
||||
topic != this._quotaCancel) {
|
||||
throw new Error("Unexpected topic!");
|
||||
}
|
||||
|
||||
|
@ -5824,6 +5828,9 @@ var IndexedDBPromptHelper = {
|
|||
[ host, data ]);
|
||||
responseTopic = this._quotaResponse;
|
||||
}
|
||||
else if (topic == this._quotaCancel) {
|
||||
responseTopic = this._quotaResponse;
|
||||
}
|
||||
|
||||
const hiddenTimeoutDuration = 30000; // 30 seconds
|
||||
const firstTimeoutDuration = 120000; // 2 minutes
|
||||
|
@ -5861,12 +5868,16 @@ var IndexedDBPromptHelper = {
|
|||
}
|
||||
];
|
||||
|
||||
// This will be set to the result of PopupNotifications.show() below.
|
||||
// This will be set to the result of PopupNotifications.show() below, or to
|
||||
// the result of PopupNotifications.getNotification() if this is a
|
||||
// quotaCancel notification.
|
||||
var notification;
|
||||
|
||||
function timeoutNotification() {
|
||||
// Remove the notification.
|
||||
notification.remove();
|
||||
if (notification) {
|
||||
notification.remove();
|
||||
}
|
||||
|
||||
// Clear all of our timeout stuff.
|
||||
cleanup();
|
||||
|
@ -5900,6 +5911,13 @@ var IndexedDBPromptHelper = {
|
|||
}
|
||||
};
|
||||
|
||||
if (topic == this._quotaCancel) {
|
||||
notification = PopupNotifications.getNotification(this._quotaPrompt,
|
||||
browser);
|
||||
timeoutNotification();
|
||||
return;
|
||||
}
|
||||
|
||||
notification = PopupNotifications.show(browser, topic, message,
|
||||
this._notificationIcon, mainAction,
|
||||
secondaryActions, options);
|
||||
|
|
|
@ -53,6 +53,8 @@
|
|||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/Services.h"
|
||||
|
||||
#include "IndexedDatabaseManager.h"
|
||||
|
||||
#define PERMISSION_INDEXEDDB "indexedDB"
|
||||
#define PREF_INDEXEDDB_ENABLED "dom.indexedDB.enabled"
|
||||
#define TOPIC_PERMISSIONS_PROMPT "indexedDB-permissions-prompt"
|
||||
|
@ -194,5 +196,11 @@ CheckPermissionsHelper::Observe(nsISupports* aSubject,
|
|||
mPromptResult = nsDependentString(aData).ToInteger(&rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_DispatchToCurrentThread(this);
|
||||
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
|
||||
NS_ASSERTION(mgr, "This should never be null!");
|
||||
|
||||
rv = mgr->WaitForClearAndDispatch(mASCIIOrigin, this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
|
||||
#define TOPIC_QUOTA_PROMPT "indexedDB-quota-prompt"
|
||||
#define TOPIC_QUOTA_RESPONSE "indexedDB-quota-response"
|
||||
#define TOPIC_QUOTA_CANCEL "indexedDB-quota-cancel"
|
||||
|
||||
USING_INDEXEDDB_NAMESPACE
|
||||
using namespace mozilla::services;
|
||||
|
@ -132,6 +133,39 @@ CheckQuotaHelper::PromptAndReturnQuotaIsDisabled()
|
|||
return mPromptResult == nsIPermissionManager::ALLOW_ACTION;
|
||||
}
|
||||
|
||||
void
|
||||
CheckQuotaHelper::Cancel()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
mMutex.AssertCurrentThreadOwns();
|
||||
|
||||
if (mWaiting && !mHasPrompted) {
|
||||
MutexAutoUnlock unlock(mMutex);
|
||||
|
||||
// First close any prompts that are open for this window.
|
||||
nsCOMPtr<nsIObserverService> obs = GetObserverService();
|
||||
NS_WARN_IF_FALSE(obs, "Failed to get observer service!");
|
||||
if (obs && NS_FAILED(obs->NotifyObservers(static_cast<nsIRunnable*>(this),
|
||||
TOPIC_QUOTA_CANCEL, nsnull))) {
|
||||
NS_WARNING("Failed to notify observers!");
|
||||
}
|
||||
|
||||
// If that didn't trigger an Observe callback (maybe the window had already
|
||||
// died?) then go ahead and do it manually.
|
||||
if (!mHasPrompted) {
|
||||
nsAutoString response;
|
||||
response.AppendInt(nsIPermissionManager::UNKNOWN_ACTION);
|
||||
|
||||
if (NS_SUCCEEDED(Observe(nsnull, TOPIC_QUOTA_RESPONSE, response.get()))) {
|
||||
NS_ASSERTION(mHasPrompted, "Should have set this in Observe!");
|
||||
}
|
||||
else {
|
||||
NS_WARNING("Failed to notify!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS3(CheckQuotaHelper, nsIRunnable,
|
||||
nsIInterfaceRequestor,
|
||||
nsIObserver)
|
||||
|
@ -170,6 +204,13 @@ CheckQuotaHelper::Run()
|
|||
quotaString.AppendInt(quota);
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = GetObserverService();
|
||||
NS_ENSURE_STATE(obs);
|
||||
|
||||
// We have to watch to make sure that the window doesn't go away without
|
||||
// responding to us. Otherwise our database threads will hang.
|
||||
rv = obs->AddObserver(this, DOM_WINDOW_DESTROYED_TOPIC, PR_FALSE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = obs->NotifyObservers(static_cast<nsIRunnable*>(this),
|
||||
TOPIC_QUOTA_PROMPT, quotaString.get());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -214,13 +255,54 @@ CheckQuotaHelper::Observe(nsISupports* aSubject,
|
|||
const PRUnichar* aData)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(!strcmp(aTopic, TOPIC_QUOTA_RESPONSE), "Bad topic!");
|
||||
|
||||
mHasPrompted = true;
|
||||
|
||||
nsresult rv;
|
||||
mPromptResult = nsDependentString(aData).ToInteger(&rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_DispatchToCurrentThread(this);
|
||||
if (!strcmp(aTopic, TOPIC_QUOTA_RESPONSE)) {
|
||||
if (!mHasPrompted) {
|
||||
mHasPrompted = true;
|
||||
|
||||
mPromptResult = nsDependentString(aData).ToInteger(&rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = NS_DispatchToCurrentThread(this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// We no longer care about the window here.
|
||||
nsCOMPtr<nsIObserverService> obs = GetObserverService();
|
||||
NS_ENSURE_STATE(obs);
|
||||
|
||||
rv = obs->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!strcmp(aTopic, DOM_WINDOW_DESTROYED_TOPIC)) {
|
||||
NS_ASSERTION(!mHasPrompted, "Should have removed observer before now!");
|
||||
NS_ASSERTION(mWindow, "This should never be null!");
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aSubject));
|
||||
NS_ENSURE_STATE(window);
|
||||
|
||||
if (mWindow->GetSerial() == window->GetSerial()) {
|
||||
// This is our window, dying, without responding to our prompt! Fake one.
|
||||
mHasPrompted = true;
|
||||
mPromptResult = nsIPermissionManager::UNKNOWN_ACTION;
|
||||
|
||||
rv = NS_DispatchToCurrentThread(this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// We no longer care about the window here.
|
||||
nsCOMPtr<nsIObserverService> obs = GetObserverService();
|
||||
NS_ENSURE_STATE(obs);
|
||||
|
||||
rv = obs->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_NOTREACHED("Unexpected topic!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
|
|
@ -70,6 +70,8 @@ public:
|
|||
|
||||
bool PromptAndReturnQuotaIsDisabled();
|
||||
|
||||
void Cancel();
|
||||
|
||||
PRUint32 WindowSerial()
|
||||
{
|
||||
return mWindowSerial;
|
||||
|
|
|
@ -396,6 +396,24 @@ void
|
|||
IDBDatabase::Invalidate()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(gPromptHelpersMutex, "This should never be null!");
|
||||
|
||||
// Cancel any quota prompts that are currently being displayed.
|
||||
{
|
||||
MutexAutoLock lock(*gPromptHelpersMutex);
|
||||
|
||||
if (gPromptHelpers) {
|
||||
PRUint32 count = gPromptHelpers->Length();
|
||||
for (PRUint32 index = 0; index < count; index++) {
|
||||
nsRefPtr<CheckQuotaHelper>& helper = gPromptHelpers->ElementAt(index);
|
||||
if (helper->WindowSerial() == Owner()->GetSerial()) {
|
||||
helper->Cancel();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PR_AtomicSet(&mInvalidated, 1);
|
||||
CloseConnection();
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче