Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "base/basictypes.h"
9 #include "AsyncConnectionHelper.h"
11 #include "mozilla/dom/quota/QuotaManager.h"
12 #include "mozilla/storage.h"
13 #include "nsComponentManagerUtils.h"
14 #include "nsContentUtils.h"
15 #include "nsProxyRelease.h"
16 #include "nsThreadUtils.h"
17 #include "nsWrapperCacheInlines.h"
19 #include "IDBEvents.h"
20 #include "IDBTransaction.h"
21 #include "IndexedDatabaseManager.h"
22 #include "ProfilerHelpers.h"
23 #include "ReportInternalError.h"
24 #include "TransactionThreadPool.h"
26 #include "ipc/IndexedDBChild.h"
27 #include "ipc/IndexedDBParent.h"
29 using namespace mozilla;
30 USING_INDEXEDDB_NAMESPACE
31 using mozilla::dom::quota::QuotaManager;
33 namespace {
35 IDBTransaction* gCurrentTransaction = nullptr;
37 const uint32_t kProgressHandlerGranularity = 1000;
39 class MOZ_STACK_CLASS TransactionPoolEventTarget : public StackBasedEventTarget
40 {
41 public:
42 NS_DECL_NSIEVENTTARGET
44 TransactionPoolEventTarget(IDBTransaction* aTransaction)
45 : mTransaction(aTransaction)
46 { }
48 private:
49 IDBTransaction* mTransaction;
50 };
52 // This inline is just so that we always clear aBuffers appropriately even if
53 // something fails.
54 inline
55 nsresult
56 ConvertCloneReadInfosToArrayInternal(
57 JSContext* aCx,
58 nsTArray<StructuredCloneReadInfo>& aReadInfos,
59 JS::MutableHandle<JS::Value> aResult)
60 {
61 JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, 0));
62 if (!array) {
63 IDB_WARNING("Failed to make array!");
64 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
65 }
67 if (!aReadInfos.IsEmpty()) {
68 if (!JS_SetArrayLength(aCx, array, uint32_t(aReadInfos.Length()))) {
69 IDB_WARNING("Failed to set array length!");
70 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
71 }
73 for (uint32_t index = 0, count = aReadInfos.Length(); index < count;
74 index++) {
75 StructuredCloneReadInfo& readInfo = aReadInfos[index];
77 JS::Rooted<JS::Value> val(aCx);
78 if (!IDBObjectStore::DeserializeValue(aCx, readInfo, &val)) {
79 NS_WARNING("Failed to decode!");
80 return NS_ERROR_DOM_DATA_CLONE_ERR;
81 }
83 if (!JS_SetElement(aCx, array, index, val)) {
84 IDB_WARNING("Failed to set array element!");
85 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
86 }
87 }
88 }
90 aResult.setObject(*array);
91 return NS_OK;
92 }
94 } // anonymous namespace
96 HelperBase::~HelperBase()
97 {
98 if (!NS_IsMainThread()) {
99 IDBRequest* request;
100 mRequest.forget(&request);
102 if (request) {
103 nsCOMPtr<nsIThread> mainThread;
104 NS_GetMainThread(getter_AddRefs(mainThread));
105 NS_WARN_IF_FALSE(mainThread, "Couldn't get the main thread!");
107 if (mainThread) {
108 NS_ProxyRelease(mainThread, static_cast<EventTarget*>(request));
109 }
110 }
111 }
112 }
114 nsresult
115 HelperBase::WrapNative(JSContext* aCx,
116 nsISupports* aNative,
117 JS::MutableHandle<JS::Value> aResult)
118 {
119 NS_ASSERTION(aCx, "Null context!");
120 NS_ASSERTION(aNative, "Null pointer!");
121 NS_ASSERTION(aResult.address(), "Null pointer!");
122 NS_ASSERTION(mRequest, "Null request!");
124 nsresult rv = nsContentUtils::WrapNative(aCx, aNative, aResult);
125 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
127 return NS_OK;
128 }
130 void
131 HelperBase::ReleaseMainThreadObjects()
132 {
133 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
135 mRequest = nullptr;
136 }
138 AsyncConnectionHelper::AsyncConnectionHelper(IDBDatabase* aDatabase,
139 IDBRequest* aRequest)
140 : HelperBase(aRequest),
141 mDatabase(aDatabase),
142 mResultCode(NS_OK),
143 mDispatched(false)
144 {
145 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
146 }
148 AsyncConnectionHelper::AsyncConnectionHelper(IDBTransaction* aTransaction,
149 IDBRequest* aRequest)
150 : HelperBase(aRequest),
151 mDatabase(aTransaction->mDatabase),
152 mTransaction(aTransaction),
153 mResultCode(NS_OK),
154 mDispatched(false)
155 {
156 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
157 }
159 AsyncConnectionHelper::~AsyncConnectionHelper()
160 {
161 if (!NS_IsMainThread()) {
162 IDBDatabase* database;
163 mDatabase.forget(&database);
165 IDBTransaction* transaction;
166 mTransaction.forget(&transaction);
168 nsCOMPtr<nsIThread> mainThread;
169 NS_GetMainThread(getter_AddRefs(mainThread));
170 NS_WARN_IF_FALSE(mainThread, "Couldn't get the main thread!");
172 if (mainThread) {
173 if (database) {
174 NS_ProxyRelease(mainThread, static_cast<IDBWrapperCache*>(database));
175 }
176 if (transaction) {
177 NS_ProxyRelease(mainThread, static_cast<IDBWrapperCache*>(transaction));
178 }
179 }
180 }
182 NS_ASSERTION(!mOldProgressHandler, "Should not have anything here!");
183 }
185 NS_IMPL_ISUPPORTS(AsyncConnectionHelper, nsIRunnable,
186 mozIStorageProgressHandler)
188 NS_IMETHODIMP
189 AsyncConnectionHelper::Run()
190 {
191 if (NS_IsMainThread()) {
192 PROFILER_MAIN_THREAD_LABEL("IndexedDB", "AsyncConnectionHelper::Run");
194 if (mTransaction &&
195 mTransaction->IsAborted()) {
196 // Always fire a "error" event with ABORT_ERR if the transaction was
197 // aborted, even if the request succeeded or failed with another error.
198 mResultCode = NS_ERROR_DOM_INDEXEDDB_ABORT_ERR;
199 }
201 IDBTransaction* oldTransaction = gCurrentTransaction;
202 gCurrentTransaction = mTransaction;
204 ChildProcessSendResult sendResult =
205 IndexedDatabaseManager::IsMainProcess() ?
206 MaybeSendResponseToChildProcess(mResultCode) :
207 Success_NotSent;
209 switch (sendResult) {
210 case Success_Sent: {
211 if (mRequest) {
212 mRequest->NotifyHelperSentResultsToChildProcess(NS_OK);
213 }
214 break;
215 }
217 case Success_NotSent: {
218 if (mRequest) {
219 nsresult rv = mRequest->NotifyHelperCompleted(this);
220 if (NS_SUCCEEDED(mResultCode) && NS_FAILED(rv)) {
221 mResultCode = rv;
222 }
224 IDB_PROFILER_MARK("IndexedDB Request %llu: Running main thread "
225 "response (rv = %lu)",
226 "IDBRequest[%llu] MT Done",
227 mRequest->GetSerialNumber(), mResultCode);
228 }
230 // Call OnError if the database had an error or if the OnSuccess
231 // handler has an error.
232 if (NS_FAILED(mResultCode) ||
233 NS_FAILED((mResultCode = OnSuccess()))) {
234 OnError();
235 }
236 break;
237 }
239 case Success_ActorDisconnected: {
240 // Nothing needs to be done here.
241 break;
242 }
244 case Error: {
245 IDB_WARNING("MaybeSendResultsToChildProcess failed!");
246 mResultCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
247 if (mRequest) {
248 mRequest->NotifyHelperSentResultsToChildProcess(mResultCode);
249 }
250 break;
251 }
253 default:
254 MOZ_CRASH("Unknown value for ChildProcessSendResult!");
255 }
257 NS_ASSERTION(gCurrentTransaction == mTransaction, "Should be unchanged!");
258 gCurrentTransaction = oldTransaction;
260 if (mDispatched && mTransaction) {
261 mTransaction->OnRequestFinished();
262 }
264 ReleaseMainThreadObjects();
266 NS_ASSERTION(!(mDatabase || mTransaction || mRequest), "Subclass didn't "
267 "call AsyncConnectionHelper::ReleaseMainThreadObjects!");
269 return NS_OK;
270 }
272 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
274 PROFILER_LABEL("IndexedDB", "AsyncConnectionHelper::Run");
276 IDB_PROFILER_MARK_IF(mRequest,
277 "IndexedDB Request %llu: Beginning database work",
278 "IDBRequest[%llu] DT Start",
279 mRequest->GetSerialNumber());
281 nsresult rv = NS_OK;
282 nsCOMPtr<mozIStorageConnection> connection;
284 if (mTransaction) {
285 rv = mTransaction->GetOrCreateConnection(getter_AddRefs(connection));
286 if (NS_SUCCEEDED(rv)) {
287 NS_ASSERTION(connection, "This should never be null!");
288 }
289 }
291 bool setProgressHandler = false;
292 if (connection) {
293 rv = connection->SetProgressHandler(kProgressHandlerGranularity, this,
294 getter_AddRefs(mOldProgressHandler));
295 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "SetProgressHandler failed!");
296 if (NS_SUCCEEDED(rv)) {
297 setProgressHandler = true;
298 }
299 }
301 if (NS_SUCCEEDED(rv)) {
302 bool hasSavepoint = false;
303 if (mDatabase) {
304 QuotaManager::SetCurrentWindow(mDatabase->GetOwner());
306 // Make the first savepoint.
307 if (mTransaction) {
308 if (!(hasSavepoint = mTransaction->StartSavepoint())) {
309 NS_WARNING("Failed to make savepoint!");
310 }
311 }
312 }
314 mResultCode = DoDatabaseWork(connection);
316 if (mDatabase) {
317 // Release or roll back the savepoint depending on the error code.
318 if (hasSavepoint) {
319 NS_ASSERTION(mTransaction, "Huh?!");
320 if (NS_SUCCEEDED(mResultCode)) {
321 mTransaction->ReleaseSavepoint();
322 }
323 else {
324 mTransaction->RollbackSavepoint();
325 }
326 }
328 // Don't unset this until we're sure that all SQLite activity has
329 // completed!
330 QuotaManager::SetCurrentWindow(nullptr);
331 }
332 }
333 else {
334 // NS_ERROR_NOT_AVAILABLE is our special code for "database is invalidated"
335 // and we should fail with RECOVERABLE_ERR.
336 if (rv == NS_ERROR_NOT_AVAILABLE) {
337 mResultCode = NS_ERROR_DOM_INDEXEDDB_RECOVERABLE_ERR;
338 }
339 else {
340 IDB_REPORT_INTERNAL_ERR();
341 mResultCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
342 }
343 }
345 if (setProgressHandler) {
346 nsCOMPtr<mozIStorageProgressHandler> handler;
347 rv = connection->RemoveProgressHandler(getter_AddRefs(handler));
348 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "RemoveProgressHandler failed!");
349 #ifdef DEBUG
350 if (NS_SUCCEEDED(rv)) {
351 NS_ASSERTION(SameCOMIdentity(handler, static_cast<nsIRunnable*>(this)),
352 "Mismatch!");
353 }
354 #endif
355 }
357 IDB_PROFILER_MARK_IF(mRequest,
358 "IndexedDB Request %llu: Finished database work "
359 "(rv = %lu)",
360 "IDBRequest[%llu] DT Done", mRequest->GetSerialNumber(),
361 mResultCode);
363 return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
364 }
366 NS_IMETHODIMP
367 AsyncConnectionHelper::OnProgress(mozIStorageConnection* aConnection,
368 bool* _retval)
369 {
370 if (mDatabase && mDatabase->IsInvalidated()) {
371 // Someone is trying to delete the database file. Exit lightningfast!
372 *_retval = true;
373 return NS_OK;
374 }
376 if (mOldProgressHandler) {
377 return mOldProgressHandler->OnProgress(aConnection, _retval);
378 }
380 *_retval = false;
381 return NS_OK;
382 }
384 nsresult
385 AsyncConnectionHelper::Dispatch(nsIEventTarget* aTarget)
386 {
387 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
389 nsresult rv = Init();
390 if (NS_FAILED(rv)) {
391 return rv;
392 }
394 rv = aTarget->Dispatch(this, NS_DISPATCH_NORMAL);
395 NS_ENSURE_SUCCESS(rv, rv);
397 if (mTransaction) {
398 mTransaction->OnNewRequest();
399 }
401 mDispatched = true;
403 return NS_OK;
404 }
406 nsresult
407 AsyncConnectionHelper::DispatchToTransactionPool()
408 {
409 NS_ASSERTION(mTransaction, "Only ok to call this with a transaction!");
410 TransactionPoolEventTarget target(mTransaction);
411 return Dispatch(&target);
412 }
414 // static
415 void
416 AsyncConnectionHelper::SetCurrentTransaction(IDBTransaction* aTransaction)
417 {
418 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
419 NS_ASSERTION(!aTransaction || !gCurrentTransaction,
420 "Stepping on another transaction!");
422 gCurrentTransaction = aTransaction;
423 }
425 // static
426 IDBTransaction*
427 AsyncConnectionHelper::GetCurrentTransaction()
428 {
429 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
431 return gCurrentTransaction;
432 }
434 nsresult
435 AsyncConnectionHelper::Init()
436 {
437 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
439 return NS_OK;
440 }
442 already_AddRefed<nsIDOMEvent>
443 AsyncConnectionHelper::CreateSuccessEvent(mozilla::dom::EventTarget* aOwner)
444 {
445 return CreateGenericEvent(mRequest, NS_LITERAL_STRING(SUCCESS_EVT_STR),
446 eDoesNotBubble, eNotCancelable);
447 }
449 nsresult
450 AsyncConnectionHelper::OnSuccess()
451 {
452 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
453 NS_ASSERTION(mRequest, "Null request!");
455 PROFILER_MAIN_THREAD_LABEL("IndexedDB", "AsyncConnectionHelper::OnSuccess");
457 nsRefPtr<nsIDOMEvent> event = CreateSuccessEvent(mRequest);
458 if (!event) {
459 IDB_WARNING("Failed to create event!");
460 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
461 }
463 bool dummy;
464 nsresult rv = mRequest->DispatchEvent(event, &dummy);
465 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
467 WidgetEvent* internalEvent = event->GetInternalNSEvent();
468 NS_ASSERTION(internalEvent, "This should never be null!");
470 NS_ASSERTION(!mTransaction ||
471 mTransaction->IsOpen() ||
472 mTransaction->IsAborted(),
473 "How else can this be closed?!");
475 if (internalEvent->mFlags.mExceptionHasBeenRisen &&
476 mTransaction &&
477 mTransaction->IsOpen()) {
478 rv = mTransaction->Abort(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR);
479 NS_ENSURE_SUCCESS(rv, rv);
480 }
482 return NS_OK;
483 }
485 void
486 AsyncConnectionHelper::OnError()
487 {
488 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
489 NS_ASSERTION(mRequest, "Null request!");
491 PROFILER_MAIN_THREAD_LABEL("IndexedDB", "AsyncConnectionHelper::OnError");
493 // Make an error event and fire it at the target.
494 nsRefPtr<nsIDOMEvent> event =
495 CreateGenericEvent(mRequest, NS_LITERAL_STRING(ERROR_EVT_STR), eDoesBubble,
496 eCancelable);
497 if (!event) {
498 NS_ERROR("Failed to create event!");
499 return;
500 }
502 bool doDefault;
503 nsresult rv = mRequest->DispatchEvent(event, &doDefault);
504 if (NS_SUCCEEDED(rv)) {
505 NS_ASSERTION(!mTransaction ||
506 mTransaction->IsOpen() ||
507 mTransaction->IsAborted(),
508 "How else can this be closed?!");
510 WidgetEvent* internalEvent = event->GetInternalNSEvent();
511 NS_ASSERTION(internalEvent, "This should never be null!");
513 if (internalEvent->mFlags.mExceptionHasBeenRisen &&
514 mTransaction &&
515 mTransaction->IsOpen() &&
516 NS_FAILED(mTransaction->Abort(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR))) {
517 NS_WARNING("Failed to abort transaction!");
518 }
520 if (doDefault &&
521 mTransaction &&
522 mTransaction->IsOpen() &&
523 NS_FAILED(mTransaction->Abort(mRequest))) {
524 NS_WARNING("Failed to abort transaction!");
525 }
526 }
527 else {
528 NS_WARNING("DispatchEvent failed!");
529 }
530 }
532 nsresult
533 AsyncConnectionHelper::GetSuccessResult(JSContext* aCx,
534 JS::MutableHandle<JS::Value> aVal)
535 {
536 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
538 aVal.setUndefined();
539 return NS_OK;
540 }
542 void
543 AsyncConnectionHelper::ReleaseMainThreadObjects()
544 {
545 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
547 mDatabase = nullptr;
548 mTransaction = nullptr;
550 HelperBase::ReleaseMainThreadObjects();
551 }
553 AsyncConnectionHelper::ChildProcessSendResult
554 AsyncConnectionHelper::MaybeSendResponseToChildProcess(nsresult aResultCode)
555 {
556 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
557 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
559 // If there's no request, there could never have been an actor, and so there
560 // is nothing to do.
561 if (!mRequest) {
562 return Success_NotSent;
563 }
565 IDBTransaction* trans = GetCurrentTransaction();
566 // We may not have a transaction, e.g. for deleteDatabase
567 if (!trans) {
568 return Success_NotSent;
569 }
571 // Are we shutting down the child?
572 IndexedDBDatabaseParent* dbActor = trans->Database()->GetActorParent();
573 if (dbActor && dbActor->IsDisconnected()) {
574 return Success_ActorDisconnected;
575 }
577 IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
578 if (!actor) {
579 return Success_NotSent;
580 }
582 IDB_PROFILER_MARK("IndexedDB Request %llu: Sending response to child "
583 "process (rv = %lu)",
584 "IDBRequest[%llu] MT Done",
585 mRequest->GetSerialNumber(), aResultCode);
587 return SendResponseToChildProcess(aResultCode);
588 }
590 nsresult
591 AsyncConnectionHelper::OnParentProcessRequestComplete(
592 const ResponseValue& aResponseValue)
593 {
594 NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
596 if (aResponseValue.type() == ResponseValue::Tnsresult) {
597 NS_ASSERTION(NS_FAILED(aResponseValue.get_nsresult()), "Huh?");
598 SetError(aResponseValue.get_nsresult());
599 }
600 else {
601 nsresult rv = UnpackResponseFromParentProcess(aResponseValue);
602 NS_ENSURE_SUCCESS(rv, rv);
603 }
605 return Run();
606 }
608 // static
609 nsresult
610 AsyncConnectionHelper::ConvertToArrayAndCleanup(
611 JSContext* aCx,
612 nsTArray<StructuredCloneReadInfo>& aReadInfos,
613 JS::MutableHandle<JS::Value> aResult)
614 {
615 NS_ASSERTION(aCx, "Null context!");
616 NS_ASSERTION(aResult.address(), "Null pointer!");
618 nsresult rv = ConvertCloneReadInfosToArrayInternal(aCx, aReadInfos, aResult);
620 for (uint32_t index = 0; index < aReadInfos.Length(); index++) {
621 aReadInfos[index].mCloneBuffer.clear();
622 }
623 aReadInfos.Clear();
625 return rv;
626 }
628 NS_IMETHODIMP_(MozExternalRefCountType)
629 StackBasedEventTarget::AddRef()
630 {
631 NS_NOTREACHED("Don't call me!");
632 return 2;
633 }
635 NS_IMETHODIMP_(MozExternalRefCountType)
636 StackBasedEventTarget::Release()
637 {
638 NS_NOTREACHED("Don't call me!");
639 return 1;
640 }
642 NS_IMETHODIMP
643 StackBasedEventTarget::QueryInterface(REFNSIID aIID,
644 void** aInstancePtr)
645 {
646 NS_NOTREACHED("Don't call me!");
647 return NS_NOINTERFACE;
648 }
650 NS_IMETHODIMP
651 ImmediateRunEventTarget::Dispatch(nsIRunnable* aRunnable,
652 uint32_t aFlags)
653 {
654 NS_ASSERTION(aRunnable, "Null pointer!");
656 nsCOMPtr<nsIRunnable> runnable(aRunnable);
657 DebugOnly<nsresult> rv =
658 runnable->Run();
659 MOZ_ASSERT(NS_SUCCEEDED(rv));
660 return NS_OK;
661 }
663 NS_IMETHODIMP
664 ImmediateRunEventTarget::IsOnCurrentThread(bool* aIsOnCurrentThread)
665 {
666 *aIsOnCurrentThread = true;
667 return NS_OK;
668 }
670 NS_IMETHODIMP
671 TransactionPoolEventTarget::Dispatch(nsIRunnable* aRunnable,
672 uint32_t aFlags)
673 {
674 NS_ASSERTION(aRunnable, "Null pointer!");
675 NS_ASSERTION(aFlags == NS_DISPATCH_NORMAL, "Unsupported!");
677 TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
678 NS_ENSURE_TRUE(pool, NS_ERROR_UNEXPECTED);
680 nsresult rv = pool->Dispatch(mTransaction, aRunnable, false, nullptr);
681 NS_ENSURE_SUCCESS(rv, rv);
683 return NS_OK;
684 }
686 NS_IMETHODIMP
687 TransactionPoolEventTarget::IsOnCurrentThread(bool* aIsOnCurrentThread)
688 {
689 *aIsOnCurrentThread = false;
690 return NS_OK;
691 }
693 NS_IMETHODIMP
694 NoDispatchEventTarget::Dispatch(nsIRunnable* aRunnable,
695 uint32_t aFlags)
696 {
697 nsCOMPtr<nsIRunnable> runnable = aRunnable;
698 return NS_OK;
699 }
701 NS_IMETHODIMP
702 NoDispatchEventTarget::IsOnCurrentThread(bool* aIsOnCurrentThread)
703 {
704 *aIsOnCurrentThread = true;
705 return NS_OK;
706 }