Attachment #8832158: Part 7: Storage for bug #1217544

View | Details | Raw Unified | Return to bug 1217544
Collapse All | Expand All

(-)a/dom/backgroundsync/BackgroundSync.cpp (-26 / +266 lines)
Line     Link Here 
 Lines 4-20    Link Here 
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
6
7
#include "BackgroundSync.h"
7
#include "BackgroundSync.h"
8
#include "BackgroundSyncChild.h"
8
#include "BackgroundSyncChild.h"
9
9
10
#include "mozilla/dom/Promise.h"
10
#include "mozilla/dom/Promise.h"
11
#include "mozilla/dom/PromiseWorkerProxy.h"
11
#include "mozilla/dom/PromiseWorkerProxy.h"
12
#include "mozilla/dom/BackgroundSyncIPCTypes.h"
13
#include "mozilla/dom/BackgroundSyncBinding.h"
12
#include "mozilla/dom/BackgroundSyncBinding.h"
14
#include "mozilla/ipc/BackgroundChild.h"
13
#include "mozilla/ipc/BackgroundChild.h"
15
#include "mozilla/ipc/BackgroundUtils.h"
14
#include "mozilla/ipc/BackgroundUtils.h"
16
#include "mozilla/ipc/PBackgroundChild.h"
15
#include "mozilla/ipc/PBackgroundChild.h"
17
#include "mozilla/Unused.h"
16
#include "mozilla/Unused.h"
18
#include "mozilla/Preferences.h"
17
#include "mozilla/Preferences.h"
19
#include "nsISupportsPrimitives.h"
18
#include "nsISupportsPrimitives.h"
20
#include "nsIGlobalObject.h"
19
#include "nsIGlobalObject.h"
 Lines 66-91   public: Link Here 
66
  nsresult Cancel() override
65
  nsresult Cancel() override
67
  {
66
  {
68
    mActor = nullptr;
67
    mActor = nullptr;
69
    mPromise = nullptr;
68
    mPromise = nullptr;
70
    mOp = nullptr;
69
    mOp = nullptr;
71
    return NS_OK;
70
    return NS_OK;
72
  }
71
  }
73
72
73
  void
74
  MaybeReject(nsresult aRv)
75
  {
76
    MOZ_ASSERT(mPromise);
77
78
    mPromise->MaybeReject(aRv);
79
  }
80
74
private:
81
private:
75
  ~SyncOpRunnable() {}
82
  ~SyncOpRunnable() {}
76
83
77
  RefPtr<Promise> mPromise;
84
  RefPtr<Promise> mPromise;
78
  nsAutoPtr<SyncOp> mOp;
85
  nsAutoPtr<SyncOp> mOp;
79
  RefPtr<BackgroundSyncChild> mActor;
86
  RefPtr<BackgroundSyncChild> mActor;
80
};
87
};
81
88
82
NS_IMPL_ISUPPORTS(SyncOpRunnable, nsICancelableRunnable, nsIRunnable)
89
NS_IMPL_ISUPPORTS(SyncOpRunnable, nsICancelableRunnable, nsIRunnable)
83
90
91
class RegisterResultRunnable final : public WorkerRunnable
92
{
93
public:
94
  RegisterResultRunnable(WorkerPrivate* aWorkerPrivate,
95
                         PromiseWorkerProxy* aProxy,
96
                         nsresult aStatus,
97
                         ErrorResult& aRv)
98
    : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
99
    , mProxy(aProxy)
100
    , mStatus(aStatus)
101
    , mRv(aRv)
102
  {}
103
104
  bool
105
  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
106
  {
107
    RefPtr<Promise> promise = mProxy->WorkerPromise();
108
    if (NS_SUCCEEDED(mStatus)) {
109
      promise->MaybeResolve(JS::NullHandleValue);
110
    } else {
111
      mRv.Throw(mStatus);
112
      promise->MaybeReject(mStatus);
113
    }
114
    return true;
115
  }
116
117
private:
118
  ~RegisterResultRunnable() {}
119
120
  RefPtr<PromiseWorkerProxy> mProxy;
121
  nsresult mStatus;
122
  ErrorResult& mRv;
123
};
124
125
class RegisterHelper final : public nsIRunnable,
126
                             public nsICancelableRunnable
127
{
128
public:
129
  NS_DECL_THREADSAFE_ISUPPORTS
130
131
  // Worker thread constructor.
132
  RegisterHelper(BackgroundSync* aTarget,
133
                 PromiseWorkerProxy* aPromiseProxy,
134
                 const PrincipalInfo& aPrincipalInfo,
135
                 const nsAString& aScope,
136
                 const nsAString& aTag,
137
                 ErrorResult& aRv)
138
    : mTarget(aTarget)
139
    , mPromiseProxy(aPromiseProxy)
140
    , mPromise(nullptr)
141
    , mPrincipalInfo(aPrincipalInfo)
142
    , mScope(aScope)
143
    , mTag(aTag)
144
    , mRv(aRv)
145
  {
146
    MOZ_ASSERT(!NS_IsMainThread());
147
    MOZ_ASSERT(mTarget);
148
    MOZ_ASSERT(mPromiseProxy);
149
  }
150
151
  // Main thread constructor.
152
  RegisterHelper(BackgroundSync* aTarget,
153
                 Promise* aPromise,
154
                 const PrincipalInfo& aPrincipalInfo,
155
                 const nsAString& aScope,
156
                 const nsAString& aTag,
157
                 ErrorResult& aRv)
158
    : mTarget(aTarget)
159
    , mPromiseProxy(nullptr)
160
    , mPromise(aPromise)
161
    , mPrincipalInfo(aPrincipalInfo)
162
    , mScope(aScope)
163
    , mTag(aTag)
164
    , mRv(aRv)
165
  {
166
    MOZ_ASSERT(NS_IsMainThread());
167
    MOZ_ASSERT(mTarget);
168
    MOZ_ASSERT(mPromise);
169
  }
170
171
  void
172
  Execute()
173
  {
174
    if (NS_IsMainThread()) {
175
      nsresult rv;
176
      nsCOMPtr<nsIPrincipal> principal =
177
        PrincipalInfoToPrincipal(mPrincipalInfo, &rv);
178
      if (NS_WARN_IF(NS_FAILED(rv))) {
179
        MaybeReject(rv);
180
        return;
181
      }
182
183
      rv = principal->GetOrigin(mOrigin);
184
      if (NS_WARN_IF(NS_FAILED(rv))) {
185
        MaybeReject(rv);
186
        return;
187
      }
188
189
      if (mPromise) {
190
        const SyncRegisterArgs args(NS_ConvertUTF8toUTF16(mOrigin),
191
                                    mScope, (nsString(mTag)));
192
        mTarget->ExecuteOp(SyncOpArgs(args), mPromise, mRv);
193
      } else {
194
        MOZ_ASSERT(mPromiseProxy);
195
        MOZ_ASSERT(mWorkerThread);
196
        mWorkerThread->Dispatch(this, nsIThread::DISPATCH_NORMAL);
197
      }
198
    } else {
199
      MOZ_ASSERT(mPromiseProxy);
200
201
      mWorkerThread = do_GetCurrentThread();
202
203
      nsresult rv = NS_DispatchToMainThread(this);
204
      if (NS_WARN_IF(NS_FAILED(rv))) {
205
        MaybeReject(rv);
206
      }
207
    }
208
  }
209
210
  /**
211
   * This method is called only when the RegisterHelper is created on a worker
212
   * thread. And in that case it is called twice. The first time in the main
213
   * thread, to get the origin value from the principal info and the second time
214
   * back on the worker thread to continue with the execution of the sync
215
   * operation.
216
   */
217
  NS_IMETHOD Run() override
218
  {
219
    if (NS_IsMainThread()) {
220
      Execute();
221
    } else {
222
      RefPtr<Promise> promise = mPromiseProxy->WorkerPromise();
223
      MOZ_ASSERT(promise);
224
      const SyncRegisterArgs args(NS_ConvertUTF8toUTF16(mOrigin),
225
                                  mScope, (nsString(mTag)));
226
      mTarget->ExecuteOp(SyncOpArgs(args), promise, mRv);
227
    }
228
229
    return NS_OK;
230
  }
231
232
  nsresult Cancel() override
233
  {
234
    return NS_OK;
235
  }
236
237
private:
238
  ~RegisterHelper() {}
239
240
  void
241
  MaybeReject(nsresult aRv)
242
  {
243
    MOZ_ASSERT(NS_IsMainThread());
244
245
    if (mPromise) {
246
      mRv.Throw(aRv);
247
      return mPromise->MaybeReject(aRv);
248
    }
249
250
    MOZ_ASSERT(mPromiseProxy);
251
252
    MutexAutoLock lock(mPromiseProxy->Lock());
253
    if (mPromiseProxy->CleanedUp()) {
254
      // Worker has already shut down, can't access worker private;
255
      return;
256
    }
257
    RefPtr<RegisterResultRunnable> runnable =
258
      new RegisterResultRunnable(mPromiseProxy->GetWorkerPrivate(),
259
                                 mPromiseProxy, aRv, mRv);
260
    MOZ_ALWAYS_TRUE(runnable->Dispatch());
261
  }
262
263
  RefPtr<BackgroundSync> mTarget;
264
  RefPtr<PromiseWorkerProxy> mPromiseProxy;
265
  RefPtr<Promise> mPromise;
266
  PrincipalInfo mPrincipalInfo;
267
  nsString mScope;
268
  nsString mTag;
269
  nsAutoCString mOrigin;
270
  ErrorResult& mRv;
271
  nsCOMPtr<nsIThread> mWorkerThread;
272
};
273
274
NS_IMPL_ISUPPORTS(RegisterHelper, nsICancelableRunnable, nsIRunnable)
275
84
class TeardownRunnable final : public nsIRunnable,
276
class TeardownRunnable final : public nsIRunnable,
85
                               public nsICancelableRunnable
277
                               public nsICancelableRunnable
86
{
278
{
87
public:
279
public:
88
  NS_DECL_ISUPPORTS
280
  NS_DECL_ISUPPORTS
89
281
90
  explicit TeardownRunnable(BackgroundSyncChild* aActor)
282
  explicit TeardownRunnable(BackgroundSyncChild* aActor)
91
    : mActor(aActor)
283
    : mActor(aActor)
 Lines 335-351   BackgroundSync::ActorCreated(PBackground Link Here 
335
  MOZ_ASSERT(IsBackgroundSyncThread());
527
  MOZ_ASSERT(IsBackgroundSyncThread());
336
  MOZ_ASSERT(aActor);
528
  MOZ_ASSERT(aActor);
337
  MOZ_ASSERT(!mActor);
529
  MOZ_ASSERT(!mActor);
338
530
339
  if (mShuttingDown) {
531
  if (mShuttingDown) {
340
    return;
532
    return;
341
  }
533
  }
342
534
343
  PBackgroundSyncChild* actor = aActor->SendPBackgroundSyncConstructor();
535
  PBackgroundSyncChild* actor =
536
    aActor->SendPBackgroundSyncConstructor(*mPrincipalInfo);
344
  mActor = static_cast<BackgroundSyncChild*>(actor);
537
  mActor = static_cast<BackgroundSyncChild*>(actor);
345
  MOZ_ASSERT(mActor);
538
  MOZ_ASSERT(mActor);
346
539
347
  // Flush pending requests.
540
  // Flush pending requests.
348
  for (uint32_t i = 0, len = mPendingOperations.Length(); i < len; ++i) {
541
  for (uint32_t i = 0, len = mPendingOperations.Length(); i < len; ++i) {
349
    RefPtr<SyncOpRunnable> runnable = mPendingOperations[i];
542
    RefPtr<SyncOpRunnable> runnable = mPendingOperations[i];
350
    MOZ_ASSERT(runnable);
543
    MOZ_ASSERT(runnable);
351
    runnable->SetActor(mActor);
544
    runnable->SetActor(mActor);
 Lines 383-447   BackgroundSync::Observe(nsISupports* aSu Link Here 
383
    }
576
    }
384
  }
577
  }
385
578
386
  Shutdown();
579
  Shutdown();
387
580
388
  return NS_OK;
581
  return NS_OK;
389
}
582
}
390
583
584
void
585
BackgroundSync::ExecuteOp(SyncOpRunnable* aRunnable,
586
                          ErrorResult& aRv)
587
{
588
  MOZ_ASSERT(IsBackgroundSyncThread());
589
590
  if (mShuttingDown) {
591
    aRunnable->MaybeReject(NS_ERROR_NOT_AVAILABLE);
592
    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
593
  }
594
595
  if (!mActor) {
596
    mPendingOperations.AppendElement(aRunnable);
597
    return;
598
  }
599
600
  MOZ_ASSERT(mPendingOperations.IsEmpty());
601
602
  aRunnable->SetActor(mActor);
603
  nsresult rv = NS_DispatchToCurrentThread(aRunnable);
604
  if (NS_WARN_IF(NS_FAILED(rv))) {
605
    aRunnable->MaybeReject(rv);
606
  }
607
}
608
609
void
610
BackgroundSync::ExecuteOp(const SyncOpArgs& aArgs,
611
                          Promise* aPromise,
612
                          ErrorResult& aRv)
613
{
614
  MOZ_ASSERT(IsBackgroundSyncThread());
615
616
  nsAutoPtr<SyncOp> op(new SyncOp(*mPrincipalInfo, aArgs));
617
  RefPtr<SyncOpRunnable> runnable = new SyncOpRunnable(aPromise, op);
618
619
  ExecuteOp(runnable, aRv);
620
}
621
622
// WebIDL interface methods.
623
391
already_AddRefed<Promise>
624
already_AddRefed<Promise>
392
BackgroundSync::ExecuteOp(const SyncOpArgs& aArgs, ErrorResult& aRv)
625
BackgroundSync::Register(const nsAString& aTag, ErrorResult& aRv)
393
{
626
{
394
  MOZ_ASSERT(IsBackgroundSyncThread());
627
  MOZ_ASSERT(IsBackgroundSyncThread());
395
628
396
  if (mShuttingDown) {
629
  if (mShuttingDown) {
397
    return nullptr;
630
    return nullptr;
398
  }
631
  }
399
632
400
  RefPtr<Promise> p = Promise::Create(mGlobal, aRv);
633
  RefPtr<Promise> p = Promise::Create(mGlobal, aRv);
401
  if (NS_WARN_IF(aRv.Failed())) {
634
  if (NS_WARN_IF(aRv.Failed())) {
402
    return nullptr;
635
    return nullptr;
403
  }
636
  }
404
637
405
  nsAutoPtr<SyncOp> op(new SyncOp(*mPrincipalInfo, aArgs));
638
  RefPtr<RegisterHelper> helper;
406
  RefPtr<SyncOpRunnable> runnable = new SyncOpRunnable(p, op);
407
639
408
  if (!mActor) {
640
  if (NS_IsMainThread()) {
409
    mPendingOperations.AppendElement(runnable);
641
    helper = new RegisterHelper(this, p, *mPrincipalInfo, mScope, aTag, aRv);
410
    return p.forget();
642
  } else {
643
    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
644
    MOZ_ASSERT(workerPrivate);
645
    workerPrivate->AssertIsOnWorkerThread();
646
647
    RefPtr<PromiseWorkerProxy> promiseProxy =
648
      PromiseWorkerProxy::Create(workerPrivate, p);
649
    if (!promiseProxy) {
650
      p->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
651
      return p.forget();
652
    }
653
654
    helper = new RegisterHelper(this, promiseProxy, *mPrincipalInfo, mScope,
655
                                aTag, aRv);
411
  }
656
  }
412
657
413
  runnable->SetActor(mActor);
658
  helper->Execute();
414
  nsresult rv = NS_DispatchToCurrentThread(runnable);
415
  if (NS_WARN_IF(NS_FAILED(rv))) {
416
    p->MaybeReject(rv);
417
  }
418
419
  return p.forget();
659
  return p.forget();
420
}
660
}
421
661
422
// WebIDL interface methods.
423
424
already_AddRefed<Promise>
425
BackgroundSync::Register(const nsAString& aTag, ErrorResult& aRv)
426
{
427
  MOZ_ASSERT(IsBackgroundSyncThread());
428
429
  const SyncRegisterArgs args(mScope, (nsString(aTag)));
430
  return ExecuteOp(SyncOpArgs(args), aRv);
431
}
432
433
already_AddRefed<Promise>
662
already_AddRefed<Promise>
434
BackgroundSync::GetTags(ErrorResult& aRv)
663
BackgroundSync::GetTags(ErrorResult& aRv)
435
{
664
{
436
  MOZ_ASSERT(IsBackgroundSyncThread());
665
  MOZ_ASSERT(IsBackgroundSyncThread());
437
666
667
  if (mShuttingDown) {
668
    return nullptr;
669
  }
670
671
  RefPtr<Promise> p = Promise::Create(mGlobal, aRv);
672
  if (NS_WARN_IF(aRv.Failed())) {
673
    return nullptr;
674
  }
675
438
  const SyncGetTagsArgs args;
676
  const SyncGetTagsArgs args;
439
  return ExecuteOp(SyncOpArgs(args), aRv);
677
  ExecuteOp(SyncOpArgs(args), p, aRv);
678
679
  return p.forget();
440
}
680
}
441
681
442
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(BackgroundSync, mGlobal)
682
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(BackgroundSync, mGlobal)
443
NS_IMPL_CYCLE_COLLECTING_ADDREF(BackgroundSync)
683
NS_IMPL_CYCLE_COLLECTING_ADDREF(BackgroundSync)
444
NS_IMPL_CYCLE_COLLECTING_RELEASE(BackgroundSync)
684
NS_IMPL_CYCLE_COLLECTING_RELEASE(BackgroundSync)
445
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BackgroundSync)
685
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BackgroundSync)
446
  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
686
  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
447
  NS_INTERFACE_MAP_ENTRY(nsIIPCBackgroundChildCreateCallback)
687
  NS_INTERFACE_MAP_ENTRY(nsIIPCBackgroundChildCreateCallback)
(-)a/dom/backgroundsync/BackgroundSync.h (-3 / +8 lines)
Line     Link Here 
 Lines 5-21    Link Here 
5
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
6
7
#ifndef mozilla_dom_BackgroundSync_h
7
#ifndef mozilla_dom_BackgroundSync_h
8
#define mozilla_dom_BackgroundSync_h
8
#define mozilla_dom_BackgroundSync_h
9
9
10
#include "jsapi.h"
10
#include "jsapi.h"
11
#include "mozilla/AlreadyAddRefed.h"
11
#include "mozilla/AlreadyAddRefed.h"
12
#include "mozilla/ErrorResult.h"
12
#include "mozilla/ErrorResult.h"
13
#include "mozilla/dom/BackgroundSyncIPCTypes.h"
13
#include "mozilla/dom/backgroundsync/BackgroundSyncIPCTypes.h"
14
#include "mozilla/dom/BindingDeclarations.h"
14
#include "mozilla/dom/BindingDeclarations.h"
15
#include "nsCOMPtr.h"
15
#include "nsCOMPtr.h"
16
#include "nsIIPCBackgroundChildCreateCallback.h"
16
#include "nsIIPCBackgroundChildCreateCallback.h"
17
#include "nsIObserver.h"
17
#include "nsIObserver.h"
18
#include "nsWrapperCache.h"
18
#include "nsWrapperCache.h"
19
19
20
class nsIGlobalObject;
20
class nsIGlobalObject;
21
class nsIPrincipal;
21
class nsIPrincipal;
 Lines 39-54   namespace backgroundsync { Link Here 
39
39
40
class BackgroundSyncChild;
40
class BackgroundSyncChild;
41
class SyncOpRunnable;
41
class SyncOpRunnable;
42
42
43
class BackgroundSync final : public nsIIPCBackgroundChildCreateCallback
43
class BackgroundSync final : public nsIIPCBackgroundChildCreateCallback
44
                           , public nsIObserver
44
                           , public nsIObserver
45
                           , public nsWrapperCache
45
                           , public nsWrapperCache
46
{
46
{
47
  friend class RegisterHelper;
48
47
  NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK
49
  NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK
48
  NS_DECL_NSIOBSERVER
50
  NS_DECL_NSIOBSERVER
49
51
50
public:
52
public:
51
  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
53
  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
52
  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(
54
  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(
53
      BackgroundSync, nsIIPCBackgroundChildCreateCallback)
55
      BackgroundSync, nsIIPCBackgroundChildCreateCallback)
54
56
 Lines 87-104   public: Link Here 
87
  void Shutdown();
89
  void Shutdown();
88
private:
90
private:
89
  BackgroundSync(nsIGlobalObject* aGlobal,
91
  BackgroundSync(nsIGlobalObject* aGlobal,
90
                 const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
92
                 const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
91
                 const nsAString& aScope);
93
                 const nsAString& aScope);
92
94
93
  ~BackgroundSync();
95
  ~BackgroundSync();
94
96
95
  already_AddRefed<Promise>
97
  void
96
  ExecuteOp(const SyncOpArgs& aArgs, ErrorResult& aRv);
98
  ExecuteOp(SyncOpRunnable* aRunnable,ErrorResult& aRv);
99
  void
100
  ExecuteOp(const SyncOpArgs& aArgs, Promise* aPromise,
101
            ErrorResult& aRv);
97
102
98
  uint64_t mInnerID;
103
  uint64_t mInnerID;
99
104
100
  nsCOMPtr<nsIGlobalObject> mGlobal;
105
  nsCOMPtr<nsIGlobalObject> mGlobal;
101
106
102
  nsAutoPtr<workers::WorkerHolder> mWorkerHolder;
107
  nsAutoPtr<workers::WorkerHolder> mWorkerHolder;
103
108
104
  RefPtr<BackgroundSyncChild> mActor;
109
  RefPtr<BackgroundSyncChild> mActor;
(-)a/dom/backgroundsync/BackgroundSyncChild.h (-2 / +2 lines)
Line     Link Here 
 Lines 4-28    Link Here 
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
6
7
#ifndef mozilla_dom_BackgroundSyncChild_h
7
#ifndef mozilla_dom_BackgroundSyncChild_h
8
#define mozilla_dom_BackgroundSyncChild_h
8
#define mozilla_dom_BackgroundSyncChild_h
9
9
10
#include "BackgroundSync.h"
10
#include "BackgroundSync.h"
11
11
12
#include "mozilla/dom/PBackgroundSyncChild.h"
12
#include "mozilla/dom/backgroundsync/PBackgroundSyncChild.h"
13
13
14
#include "nsID.h"
14
#include "nsID.h"
15
#include "nsClassHashtable.h"
15
#include "nsClassHashtable.h"
16
16
17
namespace mozilla {
17
namespace mozilla {
18
18
19
namespace ipc {
19
namespace ipc {
20
class BackgroundChildImpl;
20
  class BackgroundChildImpl;
21
} // namespace ipc
21
} // namespace ipc
22
22
23
namespace dom {
23
namespace dom {
24
namespace backgroundsync {
24
namespace backgroundsync {
25
25
26
class BackgroundSync;
26
class BackgroundSync;
27
27
28
class BackgroundSyncChild final : public PBackgroundSyncChild
28
class BackgroundSyncChild final : public PBackgroundSyncChild
(-)a/dom/backgroundsync/BackgroundSyncIPCTypes.ipdlh (-1 / +82 lines)
Line     Link Here 
 Lines 1-55    Link Here 
1
/* This Source Code Form is subject to the terms of the Mozilla Public
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
4
5
include PBackgroundSharedTypes;
5
include PBackgroundSharedTypes;
6
6
7
using RegistrationState from "mozilla/dom/backgroundsync/BackgroundSyncTypes.h";
8
using mozilla::void_t from "ipc/IPCMessageUtils.h";
9
7
namespace mozilla {
10
namespace mozilla {
8
namespace dom {
11
namespace dom {
12
namespace backgroundsync {
9
13
10
struct SyncRegisterArgs
14
struct SyncRegisterArgs
11
{
15
{
16
  nsString mOrigin;
12
  nsString mScope;
17
  nsString mScope;
13
  nsString mTag;
18
  nsString mTag;
14
};
19
};
15
20
16
struct SyncGetTagsArgs
21
struct SyncGetTagsArgs
17
{
22
{
23
  nsString mScope;
18
};
24
};
19
25
20
union SyncOpArgs
26
union SyncOpArgs
21
{
27
{
22
  SyncRegisterArgs;
28
  SyncRegisterArgs;
23
  SyncGetTagsArgs;
29
  SyncGetTagsArgs;
24
};
30
};
25
31
26
struct SyncOp
32
struct SyncOp
27
{
33
{
28
  PrincipalInfo mPrincipal;
34
  PrincipalInfo mPrincipal;
29
  SyncOpArgs mArgs;
35
  SyncOpArgs mArgs;
30
};
36
};
31
37
38
struct Registration
39
{
40
  nsString mId;
41
  nsString mOrigin;
42
  nsString mScope;
43
  nsString mTag;
44
  RegistrationState mState;
45
  bool mLastChance;
46
};
47
32
struct SyncRegisterResponse
48
struct SyncRegisterResponse
33
{
49
{
34
  bool mSuccess;
50
  Registration mRegistration;
51
  bool mFirstRegistration;
35
};
52
};
36
53
37
struct SyncGetTagsResponse
54
struct SyncGetTagsResponse
38
{
55
{
39
  nsString[] mTags;
56
  nsString[] mTags;
40
};
57
};
41
58
59
struct SyncGetAllResponse
60
{
61
  Registration[] mRegistrations;
62
};
63
64
struct SyncRemoveResponse
65
{
66
  nsString mOrigin;
67
};
68
69
struct SyncChangeStateResponse
70
{
71
  Registration mRegistration;
72
};
73
74
struct SyncRegisterOriginResponse
75
{
76
  Registration mRegistration;
77
};
78
79
struct SyncUnregisterOriginResponse
80
{
81
};
82
83
struct SyncGetAllOriginsResponse
84
{
85
  nsString[] mOrigins;
86
};
87
42
struct SyncOpError
88
struct SyncOpError
43
{
89
{
44
  uint32_t mCode;
90
  uint32_t mCode;
45
};
91
};
46
92
47
union SyncOpResponse
93
union SyncOpResponse
48
{
94
{
95
  void_t;
49
  SyncRegisterResponse;
96
  SyncRegisterResponse;
50
  SyncGetTagsResponse;
97
  SyncGetTagsResponse;
98
  SyncGetAllResponse;
99
  SyncRemoveResponse;
100
  SyncChangeStateResponse;
101
  SyncRegisterOriginResponse;
102
  SyncUnregisterOriginResponse;
103
  SyncGetAllOriginsResponse;
51
  SyncOpError;
104
  SyncOpError;
52
};
105
};
53
106
107
struct SyncGetAllArgs
108
{};
109
110
struct SyncChangeStateArgs
111
{
112
  nsString mId;
113
  uint16_t mState;
114
};
115
116
struct SyncRemoveArgs
117
{
118
  nsString mId;
119
};
120
121
union SyncInternalOpArgs
122
{
123
  void_t;
124
  SyncGetAllArgs;
125
  SyncChangeStateArgs;
126
  SyncRemoveArgs;
127
};
128
129
struct SyncInternalOp
130
{
131
  SyncInternalOpArgs mArgs;
132
};
133
134
} // namespace backgroundsync
54
} // namespace dom
135
} // namespace dom
55
} // namespace mozilla
136
} // namespace mozilla
(-)a/dom/backgroundsync/BackgroundSyncParent.cpp (-23 / +70 lines)
Line     Link Here 
 Lines 11-83    Link Here 
11
11
12
namespace mozilla {
12
namespace mozilla {
13
13
14
using namespace ipc;
14
using namespace ipc;
15
15
16
namespace dom {
16
namespace dom {
17
namespace backgroundsync {
17
namespace backgroundsync {
18
18
19
BackgroundSyncParent::BackgroundSyncParent()
19
class BackgroundSyncParent::PendingRequest final
20
{
21
public:
22
  NS_INLINE_DECL_REFCOUNTING(PendingRequest)
23
24
  explicit PendingRequest(const nsID& aRequestId,
25
                          const SyncOp& aOp)
26
    : mRequestId(aRequestId)
27
    , mOp(aOp)
28
  {}
29
30
  nsID RequestId() const
31
  {
32
    return mRequestId;
33
  }
34
35
  SyncOp Op() const
36
  {
37
    return mOp;
38
  }
39
private:
40
  ~PendingRequest() {}
41
42
  const nsID mRequestId;
43
  const SyncOp mOp;
44
};
45
46
BackgroundSyncParent::BackgroundSyncParent(const PrincipalInfo& aPrincipalInfo)
47
20
{
48
{
21
  AssertIsOnBackgroundThread();
49
  AssertIsOnBackgroundThread();
50
51
  mStorageManagerIdFactory =
52
    StorageManagerIdFactory::Create(this, aPrincipalInfo);
22
}
53
}
23
54
24
BackgroundSyncParent::~BackgroundSyncParent()
55
BackgroundSyncParent::~BackgroundSyncParent()
25
{
56
{
26
  AssertIsOnBackgroundThread();
57
  AssertIsOnBackgroundThread();
27
}
58
}
28
59
29
void BackgroundSyncParent::ActorDestroy(ActorDestroyReason aWhy)
60
void
61
BackgroundSyncParent::ActorDestroy(ActorDestroyReason aWhy)
30
{
62
{
31
  AssertIsOnBackgroundThread();
63
  AssertIsOnBackgroundThread();
32
}
64
}
33
65
66
void
67
BackgroundSyncParent::ExecuteRequest(const nsID& aRequestId,
68
                                     const SyncOp& aOp)
69
{
70
  AssertIsOnBackgroundThread();
71
  // XXX Progress request to BackgroundSyncService.
72
}
73
34
mozilla::ipc::IPCResult
74
mozilla::ipc::IPCResult
35
BackgroundSyncParent::RecvRequest(const nsID& aRequestId,
75
BackgroundSyncParent::RecvRequest(const nsID& aRequestId,
36
                                  const SyncOp& aOp)
76
                                  const SyncOp& aOp)
37
{
77
{
38
  AssertIsOnBackgroundThread();
78
  AssertIsOnBackgroundThread();
39
79
40
  switch(aOp.mArgs().type()) {
80
  // If we haven't created a StorageManagerId for this parent yet, we
41
    case SyncOpArgs::TSyncRegisterArgs:
81
  // queue the request.
42
    {
82
  if (!mStorageManagerId) {
43
      // XXX Do registration.
83
    RefPtr<PendingRequest> pendingRequest = new PendingRequest(aRequestId, aOp);
44
      const SyncRegisterResponse response(true);
84
    mPendingRequests.AppendElement(pendingRequest);
45
      //const SyncOpError response(static_cast<uint32_t>(NS_ERROR_FAILURE));
85
    return IPC_OK();
46
      Unused << SendResponse(aRequestId, response);
47
      break;
48
    }
49
    case SyncOpArgs::TSyncGetTagsArgs:
50
    {
51
      //XXX Do GetTags.
52
      nsTArray<nsString> tags;
53
      const SyncGetTagsResponse response(tags);
54
      Unused << SendResponse(aRequestId, response);
55
      break;
56
    }
57
    default:
58
    {
59
      MOZ_CRASH("Unknown BackgroundSync request");
60
    }
61
  }
86
  }
87
88
  ExecuteRequest(aRequestId, aOp);
62
  return IPC_OK();
89
  return IPC_OK();
63
}
90
}
64
91
65
mozilla::ipc::IPCResult
92
mozilla::ipc::IPCResult
66
BackgroundSyncParent::RecvShutdown()
93
BackgroundSyncParent::RecvShutdown()
67
{
94
{
68
  AssertIsOnBackgroundThread();
95
  AssertIsOnBackgroundThread();
69
96
70
  Unused << Send__delete__(this);
97
  Unused << Send__delete__(this);
71
98
72
  return IPC_OK();
99
  return IPC_OK();
73
}
100
}
74
101
75
void
102
void
103
BackgroundSyncParent::OnStorageManagerIdCreated(
104
    StorageManagerId* aManagerId)
105
{
106
  MOZ_ASSERT(mStorageManagerIdFactory);
107
  MOZ_ASSERT(!mStorageManagerId);
108
109
  mStorageManagerId = aManagerId;
110
  mStorageManagerIdFactory->RemoveListener(this);
111
  mStorageManagerIdFactory = nullptr;
112
113
  // Flush pending requests.
114
  for (uint32_t i = 0, len = mPendingRequests.Length(); i < len; i++) {
115
    MOZ_ASSERT(mPendingRequests[i]);
116
    ExecuteRequest(mPendingRequests[i]->RequestId(),
117
                   mPendingRequests[i]->Op());
118
  }
119
  mPendingRequests.Clear();
120
}
121
122
void
76
BackgroundSyncParent::NotifyResponse(const nsID& aRequestId,
123
BackgroundSyncParent::NotifyResponse(const nsID& aRequestId,
77
                                     const SyncOpResponse& aResponse)
124
                                     const SyncOpResponse& aResponse)
78
{
125
{
79
  AssertIsOnBackgroundThread();
126
  AssertIsOnBackgroundThread();
80
127
81
  Unused << SendResponse(aRequestId, aResponse);
128
  Unused << SendResponse(aRequestId, aResponse);
82
}
129
}
83
130
(-)a/dom/backgroundsync/BackgroundSyncParent.h (-3 / +24 lines)
Line     Link Here 
 Lines 2-49    Link Here 
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
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 file,
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
6
7
#ifndef mozilla_dom_BackgroundSyncParent_h
7
#ifndef mozilla_dom_BackgroundSyncParent_h
8
#define mozilla_dom_BackgroundSyncParent_h
8
#define mozilla_dom_BackgroundSyncParent_h
9
9
10
#include "mozilla/dom/PBackgroundSyncParent.h"
10
#include "mozilla/dom/backgroundsync/PBackgroundSyncParent.h"
11
#include "mozilla/dom/BackgroundSyncIPCTypes.h"
11
#include "mozilla/dom/backgroundsync/BackgroundSyncIPCTypes.h"
12
13
#include "StorageManagerId.h"
12
14
13
#include "nsID.h"
15
#include "nsID.h"
14
16
15
namespace mozilla {
17
namespace mozilla {
16
18
17
namespace ipc {
19
namespace ipc {
18
  class BackgroundParentImpl;
20
  class BackgroundParentImpl;
21
  class PrincipalInfo;
19
} // namespace ipc
22
} // namespace ipc
20
23
21
namespace dom {
24
namespace dom {
22
namespace backgroundsync {
25
namespace backgroundsync {
23
26
24
class BackgroundSyncParent final : public PBackgroundSyncParent
27
class BackgroundSyncParent final : public PBackgroundSyncParent
28
                                 , StorageManagerIdFactory::Listener
25
{
29
{
26
  friend class mozilla::ipc::BackgroundParentImpl;
30
  friend class mozilla::ipc::BackgroundParentImpl;
31
  friend class CreateManagerIdRunnable;
27
32
28
public:
33
public:
34
  NS_INLINE_DECL_REFCOUNTING(BackgroundSyncParent)
35
29
  virtual mozilla::ipc::IPCResult
36
  virtual mozilla::ipc::IPCResult
30
  RecvRequest(const nsID& aRequestId, const SyncOp& aOp) override;
37
  RecvRequest(const nsID& aRequestId, const SyncOp& aOp) override;
31
38
32
  virtual mozilla::ipc::IPCResult
39
  virtual mozilla::ipc::IPCResult
33
  RecvShutdown() override;
40
  RecvShutdown() override;
34
41
35
  void NotifyResponse(const nsID& aRequestId,
42
  void NotifyResponse(const nsID& aRequestId,
36
                      const SyncOpResponse& aResponse);
43
                      const SyncOpResponse& aResponse);
37
44
38
private:
45
private:
39
  BackgroundSyncParent();
46
  explicit BackgroundSyncParent(const PrincipalInfo& aPrincipalInfo);
40
  ~BackgroundSyncParent();
47
  ~BackgroundSyncParent();
41
48
42
  virtual void ActorDestroy(ActorDestroyReason aWhy) override;
49
  virtual void ActorDestroy(ActorDestroyReason aWhy) override;
50
51
  void ExecuteRequest(const nsID& aRequestId, const SyncOp& aOp);
52
53
  // StorageManagerId method
54
  virtual void
55
  OnStorageManagerIdCreated(StorageManagerId* aManagerId) override;
56
57
  RefPtr<StorageManagerIdFactory> mStorageManagerIdFactory;
58
  // We use this Id to ensure that we have a single StorageManager
59
  // per principal.
60
  RefPtr<StorageManagerId> mStorageManagerId;
61
62
  class PendingRequest;
63
  nsTArray<RefPtr<PendingRequest>> mPendingRequests;
43
};
64
};
44
65
45
} // namespace backgroundsync
66
} // namespace backgroundsync
46
} // namespace dom
67
} // namespace dom
47
} // namespace mozilla
68
} // namespace mozilla
48
69
49
#endif // mozilla_dom_BackgroundSyncParent_h
70
#endif // mozilla_dom_BackgroundSyncParent_h
(-)a/dom/backgroundsync/BackgroundSyncTypes.h (+39 lines)
Line     Link Here 
Line 0    Link Here 
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=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/. */
6
7
#ifndef mozilla_dom_BackgroundSyncTypes_h
8
#define mozilla_dom_BackgroundSyncTypes_h
9
10
namespace mozilla {
11
namespace dom {
12
namespace backgroundsync {
13
14
enum RegistrationState
15
{
16
  ePending = 1,
17
  eWaiting,
18
  eFiring,
19
  eReregisteringWhileFiring,
20
  eNumberOfRegistrationStates
21
};
22
23
} // namespace backgroundsync
24
} // namespace dom
25
} // namespace mozilla
26
27
namespace IPC {
28
29
using mozilla::dom::backgroundsync::RegistrationState;
30
31
template <>
32
struct ParamTraits<RegistrationState>
33
  : public ContiguousEnumSerializer<RegistrationState,
34
                                    RegistrationState::ePending,
35
                                    RegistrationState::eNumberOfRegistrationStates>
36
{ };
37
38
} // namespace IPC
39
#endif // mozilla_dom_BackgroundSyncTypes_h
(-)a/dom/backgroundsync/ChromeDBSchema.cpp (+154 lines)
Line     Link Here 
Line 0    Link Here 
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=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/. */
6
7
#include "ChromeDBSchema.h"
8
#include "DBCommon.h"
9
10
#include "ipc/IPCMessageUtils.h"
11
#include "mozilla/storage.h"
12
#include "mozIStorageConnection.h"
13
#include "mozIStorageStatement.h"
14
#include "mozStorageHelper.h"
15
16
namespace mozilla {
17
namespace dom {
18
namespace backgroundsync {
19
namespace chromedb {
20
21
using namespace mozilla::dom::backgroundsync::dbcommon;
22
23
using storage::utils::Expect;
24
using storage::utils::Migration;
25
26
namespace {
27
28
// Update this whenever the DB schema is changed.
29
const int32_t kLatestSchemaVersion = 1;
30
31
// We will wipe out databases with schema versions less than this. Newer
32
// versions will be migrated on open to the latest schema version.
33
const int32_t kFirstShippedSchemaVersion = 1;
34
35
// ---------
36
const char* const kTableOrigins =
37
  "CREATE TABLE origins ("
38
    "origin TEXT NOT NULL PRIMARY KEY"
39
  ")";
40
// ---------
41
// End schema definition
42
// ---------
43
44
} // namespace
45
46
nsresult
47
CreateOrMigrateSchema(mozIStorageConnection* aConn)
48
{
49
  nsTArray<nsCString> tablesSql;
50
  tablesSql.AppendElement(nsCString(kTableOrigins));
51
52
  nsTArray<Expect> expect;
53
  expect.AppendElement(Expect("origins", "table", kTableOrigins));
54
  expect.AppendElement(Expect("sqlite_autoindex_origins_1", "index"));
55
56
  return storage::utils::CreateOrMigrateSchema(aConn,
57
                                               kFirstShippedSchemaVersion,
58
                                               kLatestSchemaVersion, tablesSql,
59
                                               expect, nsTArray<Migration>());
60
}
61
62
nsresult
63
InitializeConnection(mozIStorageConnection* aConn)
64
{
65
  return storage::utils::InitializeConnection(aConn, kPageSize, kGrowthSize,
66
                                              kWalAutoCheckpointPages,
67
                                              kWalAutoCheckpointSize);
68
}
69
70
nsresult
71
IncrementalVacuum(mozIStorageConnection* aConn)
72
{
73
  return storage::utils::IncrementalVacuum(aConn, kMaxFreePages);
74
}
75
76
nsresult
77
Register(mozIStorageConnection* aConn,
78
         const nsAString& aOrigin)
79
{
80
  MOZ_ASSERT(!NS_IsMainThread());
81
  MOZ_ASSERT(aConn);
82
83
  nsCOMPtr<mozIStorageStatement> state;
84
  nsresult rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
85
    "INSERT INTO origins ("
86
      "origin "
87
    ") VALUES ("
88
      ":origin "
89
    ");"
90
  ), getter_AddRefs(state));
91
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
92
93
  nsString origin;
94
  rv = state->BindStringByName(NS_LITERAL_CSTRING("origin"), aOrigin);
95
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
96
97
  rv = state->Execute();
98
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
99
100
  return rv;
101
}
102
103
nsresult
104
Unregister(mozIStorageConnection* aConn,
105
           const nsAString& aOrigin)
106
{
107
  MOZ_ASSERT(!NS_IsMainThread());
108
  MOZ_ASSERT(aConn);
109
110
  nsCOMPtr<mozIStorageStatement> state;
111
  nsresult rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
112
    "DELETE FROM origins WHERE origin=:origin;"
113
  ), getter_AddRefs(state));
114
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
115
116
  nsString origin;
117
  rv = state->BindStringByName(NS_LITERAL_CSTRING("origin"), aOrigin);
118
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
119
120
  rv = state->Execute();
121
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
122
123
  return rv;
124
}
125
126
nsresult
127
GetAll(mozIStorageConnection* aConn,
128
       nsTArray<nsString>& aOrigins)
129
{
130
  MOZ_ASSERT(!NS_IsMainThread());
131
  MOZ_ASSERT(aConn);
132
133
  nsCOMPtr<mozIStorageStatement> state;
134
  nsresult rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
135
    "SELECT * FROM origins;"
136
  ), getter_AddRefs(state));
137
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
138
139
  bool hasMoreData = false;
140
  while (NS_SUCCEEDED(state->ExecuteStep(&hasMoreData)) && hasMoreData) {
141
    nsString origin;
142
    rv = state->GetString(0, origin);
143
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
144
145
    aOrigins.AppendElement(origin);
146
  }
147
148
  return rv;
149
}
150
151
} // namespace chromedb
152
} // namespace backgroundsync
153
} // namespace dom
154
} // namespace mozilla
(-)a/dom/backgroundsync/ChromeDBSchema.h (+47 lines)
Line     Link Here 
Line 0    Link Here 
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=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/. */
6
7
#ifndef mozilla_dom_ChromeDBSchema_h
8
#define mozilla_dom_ChromeDBSchema_h
9
10
class mozIStorageConnection;
11
struct nsID;
12
13
namespace mozilla {
14
namespace dom {
15
namespace backgroundsync {
16
namespace chromedb {
17
18
// Note, this cannot be executed within a transaction.
19
nsresult
20
CreateOrMigrateSchema(mozIStorageConnection* aConn);
21
22
// Note, this cannot be executed within a transaction.
23
nsresult
24
InitializeConnection(mozIStorageConnection* aConn);
25
26
nsresult
27
Register(mozIStorageConnection* aConn,
28
         const nsAString& aOrigin);
29
30
nsresult
31
Unregister(mozIStorageConnection* aConn,
32
           const nsAString& aOrigin);
33
34
nsresult
35
GetAll(mozIStorageConnection* aConn,
36
       nsTArray<nsString>& aOrigins);
37
38
// Note, this works best when its NOT executed within a transaction.
39
nsresult
40
IncrementalVacuum(mozIStorageConnection* aConn);
41
42
} // namespace chromedb
43
} // namespace backgroundsync
44
} // namespace dom
45
} // namespace mozilla
46
47
#endif // mozilla_dom_ChromeDBSchema_h
(-)a/dom/backgroundsync/ChromeStorageManager.cpp (+593 lines)
Line     Link Here 
Line 0    Link Here 
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=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/. */
6
7
#include "ChromeDBSchema.h"
8
#include "ChromeStorageManager.h"
9
#include "mozilla/dom/backgroundsync/BackgroundSyncIPCTypes.h"
10
11
#include "nsAppDirectoryServiceDefs.h"
12
#include "nsIThread.h"
13
#include "nsThreadUtils.h"
14
15
namespace mozilla {
16
namespace dom {
17
namespace backgroundsync {
18
19
using mozilla::ipc::AssertIsOnBackgroundThread;
20
21
namespace {
22
  ChromeStorageManager* csmInstance = nullptr;
23
} // namespace
24
25
//-----------------------------------------------------------------------------
26
27
class ChromeStorageAction
28
{
29
public:
30
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ChromeStorageAction)
31
32
  enum Type {
33
    eRegister = 0,
34
    eUnregister,
35
    eGetAll
36
  };
37
38
  ChromeStorageAction(Type aType,
39
                      const nsID& aRequestId)
40
    : mType(aType)
41
    , mRequestId(aRequestId)
42
  {}
43
44
  ChromeStorageAction(Type aType,
45
                      const nsID& aRequestId,
46
                      const nsAString& aOrigin)
47
    : mType(aType)
48
    , mRequestId(aRequestId)
49
    , mOrigin(aOrigin)
50
  {}
51
52
  ChromeStorageAction(Type aType,
53
                      const nsID& aRequestId,
54
                      const Registration& aRegistration)
55
    : mType(aType)
56
    , mRequestId(aRequestId)
57
    , mRegistration(aRegistration)
58
  {}
59
60
  Type GetType()
61
  {
62
    return mType;
63
  }
64
65
  nsString& GetOrigin()
66
  {
67
    return mOrigin;
68
  }
69
70
  nsID& GetRequestId()
71
  {
72
    return mRequestId;
73
  }
74
75
  Registration& GetRegistration()
76
  {
77
    return mRegistration;
78
  }
79
80
private:
81
  ~ChromeStorageAction() {}
82
83
  enum Type mType;
84
  nsID mRequestId;
85
  nsString mOrigin;
86
  Registration mRegistration;
87
};
88
89
//-----------------------------------------------------------------------------
90
// IO thread
91
92
class ContinueInitRunnable final : public nsIRunnable
93
                                 , public nsICancelableRunnable
94
{
95
public:
96
  NS_DECL_THREADSAFE_ISUPPORTS
97
98
  ContinueInitRunnable(ChromeStorageManager* aManager,
99
                       nsIThread* aBackgroundThread,
100
                       nsIFile* aDBDir)
101
    : mManager(aManager)
102
    , mBackgroundThread(aBackgroundThread)
103
    , mDBDir(aDBDir)
104
  {
105
  }
106
107
  NS_IMETHODIMP
108
  Run() override
109
  {
110
    if (mBackgroundThread == nsCOMPtr<nsIThread>(do_GetCurrentThread())) {
111
      MOZ_ASSERT(mDBConn);
112
      mManager->OnInitialized(mDBConn);
113
      return NS_OK;
114
    }
115
116
    nsCOMPtr<nsIFile> dbFile;
117
    nsresult rv = mDBDir->Clone(getter_AddRefs(dbFile));
118
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
119
120
    rv = dbFile->AppendNative(NS_LITERAL_CSTRING("backgroundsync_chrome.sqlite"));
121
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
122
123
    nsCOMPtr<mozIStorageService> storage =
124
      do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
125
    if (NS_WARN_IF(!storage)) { return rv; }
126
127
    rv = storage->OpenDatabase(dbFile, getter_AddRefs(mDBConn));
128
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
129
130
    MOZ_ASSERT(mDBConn);
131
132
    chromedb::CreateOrMigrateSchema(mDBConn);
133
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
134
135
    rv = mBackgroundThread->Dispatch(this, nsIThread::DISPATCH_NORMAL);
136
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
137
138
    return rv;
139
  }
140
141
  nsresult
142
  Cancel() override
143
  {
144
    return NS_OK;
145
  }
146
147
private:
148
  ~ContinueInitRunnable() {};
149
150
  nsCOMPtr<mozIStorageConnection> mDBConn;
151
  RefPtr<ChromeStorageManager> mManager;
152
  nsCOMPtr<nsIThread> mBackgroundThread;
153
  nsCOMPtr<nsIFile> mDBDir;
154
};
155
156
NS_IMPL_ISUPPORTS(ContinueInitRunnable, nsICancelableRunnable, nsIRunnable)
157
158
//-----------------------------------------------------------------------------
159
// Main thread
160
161
class XPCOMShutdownObserver final : public nsIRunnable
162
                                  , public nsIObserver
163
{
164
public:
165
  NS_DECL_THREADSAFE_ISUPPORTS
166
167
  XPCOMShutdownObserver(ChromeStorageManager* aManager, nsIThread* aIOThread)
168
    : mManager(aManager)
169
    , mIOThread(aIOThread)
170
    , mBackgroundThread(do_GetCurrentThread())
171
  {
172
    AssertIsOnBackgroundThread();
173
  }
174
175
  NS_IMETHODIMP
176
  Run() override
177
  {
178
    if (mBackgroundThread == nsCOMPtr<nsIThread>(do_GetCurrentThread())) {
179
      MOZ_ASSERT(mManager);
180
      mManager->Shutdown();
181
      return NS_OK;
182
    }
183
184
    AssertIsOnMainThread();
185
186
    nsCOMPtr<nsIObserverService> os = services::GetObserverService();
187
    if (NS_WARN_IF(!os)) {
188
      return NS_ERROR_FAILURE;
189
    }
190
191
    nsresult rv = os->AddObserver(this, "xpcom-shutdown",
192
                                  /* holdsWeak */ false);
193
    NS_ENSURE_SUCCESS(rv, rv);
194
195
    nsCOMPtr<nsIFile> dbFile;
196
    rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
197
                                getter_AddRefs(dbFile));
198
    NS_ENSURE_SUCCESS(rv, rv);
199
200
    RefPtr<ContinueInitRunnable> runnable =
201
      new ContinueInitRunnable(mManager, mBackgroundThread, dbFile);
202
    rv = mIOThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL);
203
    NS_ENSURE_SUCCESS(rv, rv);
204
205
    return NS_OK;
206
  }
207
208
  NS_IMETHODIMP
209
  Observe(nsISupports* aSubject,
210
          const char* aTopic, const char16_t* aData) override
211
  {
212
    AssertIsOnMainThread();
213
214
    MOZ_ASSERT(!strcmp(aTopic, "xpcom-shutdown"));
215
216
    nsresult rv = mBackgroundThread->Dispatch(this, nsIThread::DISPATCH_NORMAL);
217
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
218
219
    return rv;
220
  }
221
222
private:
223
  ~XPCOMShutdownObserver() {};
224
225
  RefPtr<ChromeStorageManager> mManager;
226
  nsCOMPtr<nsIThread> mIOThread;
227
  nsCOMPtr<nsIThread> mBackgroundThread;
228
};
229
230
NS_IMPL_ISUPPORTS(XPCOMShutdownObserver, nsIRunnable, nsIObserver)
231
232
class ContinueShutdownRunnable final : public nsIRunnable
233
                                     , public nsICancelableRunnable
234
{
235
public:
236
  NS_DECL_THREADSAFE_ISUPPORTS
237
238
  ContinueShutdownRunnable(ChromeStorageManager* aManager,
239
                           XPCOMShutdownObserver* aObserver,
240
                           nsIThread* aBackgroundThread)
241
    : mManager(aManager)
242
    , mObserver(aObserver)
243
    , mBackgroundThread(aBackgroundThread)
244
  {
245
  }
246
247
  NS_IMETHODIMP
248
  Run() override
249
  {
250
    if (mBackgroundThread == nsCOMPtr<nsIThread>(do_GetCurrentThread())) {
251
      mManager->FinishShutdown();
252
      return NS_OK;
253
    }
254
255
    AssertIsOnMainThread();
256
257
    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
258
    if (obs) {
259
      obs->RemoveObserver(mObserver, "xpcom-shutdown");
260
    }
261
262
    nsresult rv =
263
      mBackgroundThread->Dispatch(this, nsIThread::DISPATCH_NORMAL);
264
    NS_ENSURE_SUCCESS(rv, rv);
265
266
    return NS_OK;
267
  }
268
269
  nsresult
270
  Cancel() override
271
  {
272
    return NS_OK;
273
  }
274
275
private:
276
  ~ContinueShutdownRunnable() {};
277
278
  RefPtr<ChromeStorageManager> mManager;
279
  RefPtr<XPCOMShutdownObserver> mObserver;
280
  nsCOMPtr<nsIThread> mBackgroundThread;
281
};
282
283
NS_IMPL_ISUPPORTS(ContinueShutdownRunnable, nsICancelableRunnable, nsIRunnable)
284
285
//-----------------------------------------------------------------------------
286
// IO thread
287
288
class ShutdownRunnable : public nsIRunnable,
289
                         public nsICancelableRunnable
290
{
291
public:
292
  NS_DECL_THREADSAFE_ISUPPORTS
293
294
  explicit ShutdownRunnable(ChromeStorageManager* aManager,
295
                            mozIStorageConnection* aConn,
296
                            XPCOMShutdownObserver* aObserver)
297
    : mManager(aManager)
298
    , mDBConn(aConn)
299
    , mObserver(aObserver)
300
    , mBackgroundThread(do_GetCurrentThread())
301
  {
302
    AssertIsOnBackgroundThread();
303
  }
304
305
  NS_IMETHODIMP
306
  Run() override
307
  {
308
    nsresult rv;
309
    if (mDBConn) {
310
      rv = mDBConn->Close();
311
      NS_ENSURE_SUCCESS(rv, rv);
312
    }
313
314
    RefPtr<ContinueShutdownRunnable> runnable =
315
      new ContinueShutdownRunnable(mManager, mObserver, mBackgroundThread);
316
    rv = NS_DispatchToMainThread(runnable, nsIThread::DISPATCH_NORMAL);
317
    NS_ENSURE_SUCCESS(rv, rv);
318
319
    return NS_OK;
320
  }
321
322
  nsresult
323
  Cancel() override
324
  {
325
    return NS_OK;
326
  }
327
328
private:
329
  ~ShutdownRunnable() {};
330
331
  RefPtr<ChromeStorageManager> mManager;
332
  nsCOMPtr<mozIStorageConnection> mDBConn;
333
  RefPtr<XPCOMShutdownObserver> mObserver;
334
  nsCOMPtr<nsIThread> mBackgroundThread;
335
};
336
337
NS_IMPL_ISUPPORTS(ShutdownRunnable, nsICancelableRunnable, nsIRunnable)
338
339
class StorageActionRunnable : public nsIRunnable,
340
                              public nsICancelableRunnable
341
{
342
public:
343
  NS_DECL_THREADSAFE_ISUPPORTS
344
345
  StorageActionRunnable(ChromeStorageManager* aManager,
346
                        mozIStorageConnection* aConn,
347
                        ChromeStorageAction* aAction)
348
    : mManager(aManager)
349
    , mInitiatingThread(do_GetCurrentThread())
350
    , mConn(aConn)
351
    , mAction(aAction)
352
  {
353
    MOZ_ASSERT(aManager);
354
    MOZ_ASSERT(mInitiatingThread);
355
    MOZ_ASSERT(aConn);
356
    MOZ_ASSERT(aAction);
357
  }
358
359
  NS_IMETHODIMP
360
  Run() override
361
  {
362
    nsresult rv = NS_OK;
363
    if (mInitiatingThread == nsCOMPtr<nsIThread>(do_GetCurrentThread())) {
364
      mManager->OnRequestComplete(mAction->GetRequestId(), mResponse);
365
      return rv;
366
    }
367
368
    switch (mAction->GetType()) {
369
      case ChromeStorageAction::Type::eRegister:
370
        {
371
          Registration registration = mAction->GetRegistration();
372
          rv = chromedb::Register(mConn, registration.mOrigin());
373
          if (NS_WARN_IF(NS_FAILED(rv))) {
374
            mResponse = SyncOpError(static_cast<uint32_t>(rv));
375
          } else {
376
            mResponse = SyncRegisterOriginResponse(registration);
377
          }
378
        }
379
        break;
380
      case ChromeStorageAction::Type::eUnregister:
381
        rv = chromedb::Unregister(mConn, mAction->GetOrigin());
382
        if (NS_WARN_IF(NS_FAILED(rv))) {
383
          mResponse = SyncOpError(static_cast<uint32_t>(rv));
384
        } else {
385
          mResponse = SyncUnregisterOriginResponse();
386
        }
387
        break;
388
      case ChromeStorageAction::Type::eGetAll:
389
        {
390
          nsTArray<nsString> origins;
391
          rv = chromedb::GetAll(mConn, origins);
392
          if (NS_WARN_IF(NS_FAILED(rv))) {
393
            mResponse = SyncOpError(static_cast<uint32_t>(rv));
394
          } else {
395
            mResponse = SyncGetAllOriginsResponse(origins);
396
          }
397
          break;
398
        }
399
      default:
400
        MOZ_CRASH("BackgroundSync: Unexpected ChromeStorageAction");
401
    }
402
403
    rv = mInitiatingThread->Dispatch(this, nsIThread::DISPATCH_NORMAL);
404
405
    return rv;
406
  }
407
408
  nsresult
409
  Cancel() override
410
  {
411
    return NS_OK;
412
  }
413
414
private:
415
  ~StorageActionRunnable() {}
416
417
  RefPtr<ChromeStorageManager> mManager;
418
  nsCOMPtr<nsIThread> mInitiatingThread;
419
  nsCOMPtr<mozIStorageConnection> mConn;
420
  RefPtr<ChromeStorageAction> mAction;
421
  SyncOpResponse mResponse;
422
};
423
424
NS_IMPL_ISUPPORTS(StorageActionRunnable, nsICancelableRunnable, nsIRunnable)
425
426
//-----------------------------------------------------------------------------
427
// PBackground thread
428
429
// static
430
already_AddRefed<ChromeStorageManager>
431
ChromeStorageManager::GetOrCreate()
432
{
433
  AssertIsOnBackgroundThread();
434
435
  RefPtr<ChromeStorageManager> instance = csmInstance;
436
  if (!instance) {
437
    instance = new ChromeStorageManager();
438
  }
439
  return instance.forget();
440
}
441
442
ChromeStorageManager::ChromeStorageManager()
443
  : mShuttingDown(false)
444
{
445
  AssertIsOnBackgroundThread();
446
447
  Init();
448
}
449
450
ChromeStorageManager::~ChromeStorageManager()
451
{
452
  MOZ_ASSERT(!mShutdownObserver);
453
  MOZ_ASSERT(!mDBConn);
454
  MOZ_ASSERT(mPendingActions.IsEmpty());
455
456
  csmInstance = nullptr;
457
}
458
459
void
460
ChromeStorageManager::Init()
461
{
462
  AssertIsOnBackgroundThread();
463
464
  // During the initialization process we create the IO thread and jump to
465
  // the main thread to observe for xpcom-shutdown. Then we jump to the IO
466
  // thread to open the DB and jump back to the PBackground thread with the
467
  // DB connection reference.
468
469
  nsresult rv = NS_NewNamedThread("BSyncChIOThread", getter_AddRefs(mIOThread));
470
  if (NS_WARN_IF(NS_FAILED(rv))) { return; }
471
472
  mShutdownObserver = new XPCOMShutdownObserver(this, mIOThread);
473
  rv = NS_DispatchToMainThread(mShutdownObserver);
474
  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed dispatching to main thread");
475
}
476
477
void
478
ChromeStorageManager::OnInitialized(mozIStorageConnection* aConn)
479
{
480
  AssertIsOnBackgroundThread();
481
  MOZ_ASSERT(aConn);
482
483
  mDBConn = aConn;
484
485
  for (uint32_t i = 0; i < mPendingActions.Length(); ++i) {
486
    ExecuteStorageAction(mPendingActions[i]);
487
  }
488
  mPendingActions.Clear();
489
}
490
491
void
492
ChromeStorageManager::Shutdown()
493
{
494
  AssertIsOnBackgroundThread();
495
496
  // During the shutdown process we jump to the IO thread to close the DB.
497
  // Then jump to the main thread to stop observing for xpcom-shutdown and
498
  // to shutdown the IO thread. After that we jump back to the PBackground
499
  // thread to clean up the rest of resources and close the door.
500
501
  if (mShuttingDown) {
502
    return;
503
  }
504
505
  mShuttingDown = true;
506
507
  RefPtr<ShutdownRunnable> runnable =
508
    new ShutdownRunnable(this, mDBConn, mShutdownObserver);
509
  mIOThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL);
510
  mDBConn = nullptr;
511
}
512
513
void
514
ChromeStorageManager::FinishShutdown()
515
{
516
  AssertIsOnBackgroundThread();
517
518
  mPendingActions.Clear();
519
520
  nsCOMPtr<nsIThread> ioThread;
521
  mIOThread.swap(ioThread);
522
  MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(
523
        NewRunnableMethod(ioThread, &nsIThread::Shutdown)));
524
525
  mShutdownObserver = nullptr;
526
}
527
528
void
529
ChromeStorageManager::ExecuteStorageAction(ChromeStorageAction* aAction)
530
{
531
  AssertIsOnBackgroundThread();
532
533
  if (mShuttingDown) {
534
    return;
535
  }
536
537
  if (!mDBConn) {
538
    mPendingActions.AppendElement(aAction);
539
    return;
540
  }
541
542
  RefPtr<StorageActionRunnable> runnable = new StorageActionRunnable(this,
543
                                                                     mDBConn,
544
                                                                     aAction);
545
  mIOThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL);
546
}
547
548
void
549
ChromeStorageManager::Register(const nsID& aRequestId,
550
                               const Registration& aRegistration)
551
{
552
  AssertIsOnBackgroundThread();
553
554
  RefPtr<ChromeStorageAction> action =
555
    new ChromeStorageAction(ChromeStorageAction::Type::eRegister, aRequestId,
556
                            aRegistration);
557
  ExecuteStorageAction(action);
558
}
559
560
void
561
ChromeStorageManager::Unregister(const nsID& aRequestId,
562
                                 const nsAString& aOrigin)
563
{
564
  AssertIsOnBackgroundThread();
565
566
  RefPtr<ChromeStorageAction> action =
567
    new ChromeStorageAction(ChromeStorageAction::Type::eUnregister, aRequestId,
568
                            aOrigin);
569
  ExecuteStorageAction(action);
570
}
571
572
void
573
ChromeStorageManager::GetAll(const nsID& aRequestId)
574
{
575
  AssertIsOnBackgroundThread();
576
577
  RefPtr<ChromeStorageAction> action =
578
    new ChromeStorageAction(ChromeStorageAction::Type::eGetAll, aRequestId);
579
  ExecuteStorageAction(action);
580
}
581
582
void
583
ChromeStorageManager::OnRequestComplete(const nsID& aRequestId,
584
                                        const SyncOpResponse& aResponse)
585
{
586
  AssertIsOnBackgroundThread();
587
588
  // XXX Notify listener.
589
}
590
591
} // namespace backgroundsync
592
} // namespace dom
593
} // namespace mozilla
(-)a/dom/backgroundsync/ChromeStorageManager.h (+78 lines)
Line     Link Here 
Line 0    Link Here 
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=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 file,
5
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#ifndef mozilla_dom_ChromeStorageManager_h
8
#define mozilla_dom_ChromeStorageManager_h
9
10
/**
11
 * This singleton object is kept alive by the BackgroundSyncService. While a
12
 * content related storage request is on going, this object should be kept
13
 * alive. If no pending storage requests are in place, this object can be
14
 * released.
15
 **
16
 * It manages the chrome database that stores the origins that have pending
17
 * sync registrations.
18
 */
19
20
#include "mozilla/ipc/BackgroundParent.h"
21
#include "mozilla/storage.h"
22
#include "nsISupportsImpl.h"
23
24
namespace mozilla {
25
namespace dom {
26
namespace backgroundsync {
27
28
class ChromeStorageAction;
29
class Registration;
30
class XPCOMShutdownObserver;
31
32
class ChromeStorageManager final
33
{
34
  friend class ContinueInitRunnable;
35
  friend class ContinueShutdownRunnable;
36
  friend class StorageActionRunnable;
37
  friend class XPCOMShutdownObserver;
38
39
public:
40
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ChromeStorageManager)
41
42
  static already_AddRefed<ChromeStorageManager>
43
  GetOrCreate();
44
45
  void Register(const nsID& aRequestId, const Registration& aRegistration);
46
  void Unregister(const nsID& aRequestId, const nsAString& aOrigin);
47
  void GetAll(const nsID& aRequestId);
48
49
private:
50
  ChromeStorageManager();
51
  ~ChromeStorageManager();
52
53
  void Init();
54
  void OnInitialized(mozIStorageConnection* aConn);
55
56
  void Shutdown();
57
  void FinishShutdown();
58
59
  void ExecuteStorageAction(ChromeStorageAction* aAction);
60
61
  void OnRequestComplete(const nsID& aRequestId,
62
                         const SyncOpResponse& aResponse);
63
64
  RefPtr<XPCOMShutdownObserver> mShutdownObserver;
65
66
  nsCOMPtr<nsIThread> mIOThread;
67
  nsCOMPtr<mozIStorageConnection> mDBConn;
68
69
  nsTArray<RefPtr<ChromeStorageAction>> mPendingActions;
70
71
  bool mShuttingDown;
72
};
73
74
} // namespace backgroundsync
75
} // namespace dom
76
} // namespace mozilla
77
78
#endif // mozilla_dom_ChromeStorageManager_h
(-)a/dom/backgroundsync/DBAction.cpp (+228 lines)
Line     Link Here 
Line 0    Link Here 
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=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/. */
6
7
#include "DBAction.h"
8
#include "DBSchema.h"
9
10
#include "mozilla/dom/quota/PersistenceType.h"
11
#include "mozilla/net/nsFileProtocolHandler.h"
12
#include "mozilla/storage.h"
13
#include "mozIStorageConnection.h"
14
#include "mozIStorageService.h"
15
#include "mozStorageCID.h"
16
#include "nsIFile.h"
17
#include "nsIURI.h"
18
#include "nsIFileURL.h"
19
#include "nsThreadUtils.h"
20
21
namespace mozilla {
22
namespace dom {
23
namespace backgroundsync {
24
25
using mozilla::dom::quota::PERSISTENCE_TYPE_DEFAULT;
26
using mozilla::dom::quota::PersistenceType;
27
28
DBAction::DBAction(Mode aMode)
29
  : mMode(aMode)
30
{
31
}
32
33
DBAction::~DBAction()
34
{
35
}
36
37
void
38
DBAction::RunOnTarget(Resolver* aResolver, const QuotaInfo& aQuotaInfo,
39
                      Data* aOptionalData)
40
{
41
  MOZ_ASSERT(!NS_IsMainThread());
42
  MOZ_ASSERT(aResolver);
43
  MOZ_ASSERT(aQuotaInfo.mDir);
44
45
  if (IsCanceled()) {
46
    aResolver->Resolve(NS_ERROR_ABORT);
47
    return;
48
  }
49
50
  nsCOMPtr<nsIFile> dbDir;
51
  nsresult rv = aQuotaInfo.mDir->Clone(getter_AddRefs(dbDir));
52
  if (NS_WARN_IF(NS_FAILED(rv))) {
53
    aResolver->Resolve(rv);
54
    return;
55
  }
56
57
  rv = dbDir->Append(NS_LITERAL_STRING("backgroundsync"));
58
  if (NS_WARN_IF(NS_FAILED(rv))) {
59
    aResolver->Resolve(rv);
60
    return;
61
  }
62
63
  nsCOMPtr<mozIStorageConnection> conn;
64
65
  // Attempt to reuse the connection opened by a previous Action.
66
  if (aOptionalData) {
67
    conn = aOptionalData->GetConnection();
68
  }
69
70
  // If there is no previous ClientAction, then we must open one.
71
  if (!conn) {
72
    rv = OpenConnection(aQuotaInfo, dbDir, getter_AddRefs(conn));
73
    if (NS_WARN_IF(NS_FAILED(rv))) {
74
      aResolver->Resolve(rv);
75
      return;
76
    }
77
    MOZ_ASSERT(conn);
78
79
    // Save this connection in the shared Data object so later ClientActions
80
    // can use it.  This avoids opening a new connection for every
81
    // ClientAction.
82
    if (aOptionalData) {
83
      // Since we know this connection will be around for as long as the
84
      // storage is open, use our special wrapped connection class.  This
85
      // will let us perform certain operations once the storage origin
86
      // is closed.
87
      nsCOMPtr<mozIStorageConnection> wrapped =
88
        new storage::IncrementalVacuumConnection(conn, dbcommon::kMaxFreePages);
89
      aOptionalData->SetConnection(wrapped);
90
    }
91
  }
92
93
  RunWithDBOnTarget(aResolver, aQuotaInfo, dbDir, conn);
94
}
95
96
nsresult
97
DBAction::OpenConnection(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
98
                         mozIStorageConnection** aConnOut)
99
{
100
  MOZ_ASSERT(!NS_IsMainThread());
101
  MOZ_ASSERT(aDBDir);
102
  MOZ_ASSERT(aConnOut);
103
104
  nsCOMPtr<mozIStorageConnection> conn;
105
106
  bool exists;
107
  nsresult rv = aDBDir->Exists(&exists);
108
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
109
110
  if (!exists) {
111
    if (NS_WARN_IF(mMode != Create)) {  return NS_ERROR_FILE_NOT_FOUND; }
112
    rv = aDBDir->Create(nsIFile::DIRECTORY_TYPE, 0755);
113
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
114
  }
115
116
  nsCOMPtr<nsIFile> dbFile;
117
  rv = aDBDir->Clone(getter_AddRefs(dbFile));
118
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
119
120
  rv = dbFile->Append(NS_LITERAL_STRING("backgroundsync.sqlite"));
121
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
122
123
  rv = dbFile->Exists(&exists);
124
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
125
126
  // Use our default file:// protocol handler directly to construct the database
127
  // URL. This avoids any problems if a plugin registers a custom file://
128
  // handler. If such a custom handler used javascript, then we would have a
129
  // bad time running off the main thread here.
130
  RefPtr<nsFileProtocolHandler> handler = new nsFileProtocolHandler();
131
  rv = handler->Init();
132
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
133
134
  nsCOMPtr<nsIURI> uri;
135
  rv = handler->NewFileURI(dbFile, getter_AddRefs(uri));
136
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
137
138
  nsCOMPtr<nsIFileURL> dbFileUrl = do_QueryInterface(uri);
139
  if (NS_WARN_IF(!dbFileUrl)) { return NS_ERROR_UNEXPECTED; }
140
141
  nsAutoCString type;
142
  PersistenceTypeToText(PERSISTENCE_TYPE_DEFAULT, type);
143
144
  rv = dbFileUrl->SetQuery(
145
    NS_LITERAL_CSTRING("persistenceType=") + type +
146
    NS_LITERAL_CSTRING("&group=") + aQuotaInfo.mGroup +
147
    NS_LITERAL_CSTRING("&origin=") + aQuotaInfo.mOrigin +
148
    NS_LITERAL_CSTRING("&cache=private"));
149
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
150
151
  nsCOMPtr<mozIStorageService> ss =
152
    do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
153
  if (NS_WARN_IF(!ss)) { return NS_ERROR_UNEXPECTED; }
154
155
  rv = ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(conn));
156
  if (rv == NS_ERROR_FILE_CORRUPTED) {
157
    NS_WARNING("BackgroundSync database corrupted. Recreating empty database.");
158
159
    conn = nullptr;
160
161
    // There is nothing else we can do to recover.  Also, this data can
162
    // be deleted by QuotaManager at any time anyways.
163
    rv = WipeDatabase(dbFile, aDBDir);
164
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
165
166
    rv = ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(conn));
167
  }
168
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
169
170
  // Check the schema to make sure it is not too old.
171
  int32_t schemaVersion = 0;
172
  rv = conn->GetSchemaVersion(&schemaVersion);
173
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
174
  if (schemaVersion > 0 && schemaVersion < db::kFirstShippedSchemaVersion) {
175
    conn = nullptr;
176
    rv = WipeDatabase(dbFile, aDBDir);
177
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
178
179
    rv = ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(conn));
180
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
181
  }
182
183
  rv = db::InitializeConnection(conn);
184
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
185
186
  conn.forget(aConnOut);
187
188
  return rv;
189
}
190
191
nsresult
192
DBAction::WipeDatabase(nsIFile* aDBFile, nsIFile* aDBDir)
193
{
194
  nsresult rv = aDBFile->Remove(false);
195
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
196
197
  // Note, the -wal journal file will be automatically deleted by sqlite when
198
  // the new database is created.  No need to explicitly delete it here.
199
200
  return rv;
201
}
202
203
SyncDBAction::SyncDBAction(Mode aMode)
204
  : DBAction(aMode)
205
{
206
}
207
208
SyncDBAction::~SyncDBAction()
209
{
210
}
211
212
void
213
SyncDBAction::RunWithDBOnTarget(Resolver* aResolver,
214
                                const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
215
                                mozIStorageConnection* aConn)
216
{
217
  MOZ_ASSERT(!NS_IsMainThread());
218
  MOZ_ASSERT(aResolver);
219
  MOZ_ASSERT(aDBDir);
220
  MOZ_ASSERT(aConn);
221
222
  nsresult rv = RunSyncOnTarget(aQuotaInfo, aConn);
223
  aResolver->Resolve(rv);
224
}
225
226
} // namespace backgroundsync
227
} // namespace dom
228
} // namespace mozilla
(-)a/dom/backgroundsync/DBAction.h (+83 lines)
Line     Link Here 
Line 0    Link Here 
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=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/. */
6
7
#ifndef mozilla_dom_DBAction_h
8
#define mozilla_dom_DBAction_h
9
10
#include "mozilla/dom/quota/shared/ClientAction.h"
11
#include "mozilla/dom/quota/shared/QuotaInfo.h"
12
#include "mozilla/RefPtr.h"
13
#include "nsString.h"
14
15
class mozIStorageConnection;
16
class nsIFile;
17
18
namespace mozilla {
19
namespace dom {
20
namespace backgroundsync {
21
22
using quota::shared::ClientAction;
23
using quota::shared::QuotaInfo;
24
25
class DBAction : public ClientAction
26
{
27
protected:
28
  // The mode specifies whether the database should already exist or if its
29
  // ok to create a new database.
30
  enum Mode
31
  {
32
    Existing,
33
    Create
34
  };
35
36
  explicit DBAction(Mode aMode);
37
38
  // ClientAction objects are deleted through their base pointer
39
  virtual ~DBAction();
40
41
  // Just as the resolver must be ref'd until resolve, you may also
42
  // ref the DB connection. The connection can only be referenced from the
43
  // target thread and must be released upon resolve.
44
  virtual void
45
  RunWithDBOnTarget(Resolver* aResolver, const QuotaInfo& aQuotaInfo,
46
                    nsIFile* aDBDir, mozIStorageConnection* aConn) = 0;
47
48
private:
49
  virtual void
50
  RunOnTarget(Resolver* aResolver, const QuotaInfo& aQuotaInfo,
51
              Data* aOptionalData) override;
52
53
  nsresult OpenConnection(const QuotaInfo& aQuotaInfo, nsIFile* aQuotaDir,
54
                          mozIStorageConnection** aConnOut);
55
56
  nsresult WipeDatabase(nsIFile* aDBFile, nsIFile* aDBDir);
57
58
  const Mode mMode;
59
};
60
61
class SyncDBAction : public DBAction
62
{
63
protected:
64
  explicit SyncDBAction(Mode aMode);
65
66
  // Action objects are deleted through their base pointer
67
  virtual ~SyncDBAction();
68
69
  virtual nsresult
70
  RunSyncOnTarget(const QuotaInfo& aQuotaInfo,
71
                  mozIStorageConnection* aConn) = 0;
72
73
private:
74
  virtual void
75
  RunWithDBOnTarget(Resolver* aResolver, const QuotaInfo& aQuotaInfo,
76
                    nsIFile* aDBDir, mozIStorageConnection* aConn) override;
77
};
78
79
} // namespace backgroundsync
80
} // namespace dom
81
} // namespace mozilla
82
83
#endif // mozilla_dom_DBAction_h
(-)a/dom/backgroundsync/DBCommon.h (+36 lines)
Line     Link Here 
Line 0    Link Here 
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=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/. */
6
7
#ifndef mozilla_dom_BackgroundSync_DBCommon_h
8
#define mozilla_dom_BackgroundSync_DBCommon_h
9
10
namespace mozilla {
11
namespace dom {
12
namespace backgroundsync {
13
namespace dbcommon {
14
15
const uint32_t kPageSize = 4 * 1024;
16
17
// Grow the database in chunks to reduce fragmentation
18
const uint32_t kGrowthSize = 32 * 1024;
19
const uint32_t kGrowthPages = kGrowthSize / kPageSize;
20
static_assert(kGrowthSize % kPageSize == 0,
21
              "Growth size must be multiple of page size");
22
23
// Only release free pages when we have more than this limit
24
const int32_t kMaxFreePages = kGrowthPages;
25
26
const uint32_t kWalAutoCheckpointSize = 512 * 1024;
27
const uint32_t kWalAutoCheckpointPages = kWalAutoCheckpointSize / kPageSize;
28
static_assert(kWalAutoCheckpointSize % kPageSize == 0,
29
              "WAL checkpoint size must be multiple of page size");
30
31
} // namespace dbcommon
32
} // namespace backgroundsync
33
} // namespace dom
34
} // namespace mozilla
35
36
#endif // mozilla_dom_BackgroundSync_DBCommon_h
(-)a/dom/backgroundsync/DBSchema.cpp (+404 lines)
Line     Link Here 
Line 0    Link Here 
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=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/. */
6
7
#include "DBSchema.h"
8
#include "DBCommon.h"
9
#include "mozilla/dom/backgroundsync/BackgroundSyncIPCTypes.h"
10
11
#include "ipc/IPCMessageUtils.h"
12
#include "mozIStorageConnection.h"
13
#include "mozIStorageStatement.h"
14
#include "mozStorageHelper.h"
15
#include "nsICryptoHash.h"
16
#include "nsNetCID.h"
17
18
namespace mozilla {
19
namespace dom {
20
namespace backgroundsync {
21
namespace db {
22
23
using namespace mozilla::dom::backgroundsync::dbcommon;
24
25
using mozilla::dom::backgroundsync::Registration;
26
using storage::utils::Migration;
27
28
const int32_t kFirstShippedSchemaVersion = 1;
29
30
namespace {
31
32
// Update this whenever the DB schema is changed.
33
const int32_t kLatestSchemaVersion = 1;
34
35
// ---------
36
// We want to use the concatenation of scope and tag as the primary key, but
37
// since scope is a URL, it can be quite long and so quite expensive to index,
38
// so we create a hash of this concatenation taking the first 8 bytes of its
39
// SHA1.
40
//
41
// tag allows NULL below since that is how "" is represented in a
42
// BLOB column. We use BLOB to avoid encoding issues with storing
43
// DOMStrings.
44
const char* const kTableRegistrations =
45
  "CREATE TABLE registrations ("
46
    "id TEXT NOT NULL PRIMARY KEY, "
47
    "origin TEXT NOT NULL, "
48
    "scope TEXT NOT NULL, "
49
    "tag BLOB NULL, "
50
    "state INTEGER NOT NULL, "
51
    "lastChance INTEGER NOT NULL"
52
  ")";
53
// ---------
54
// End schema definition
55
// ---------
56
57
} // namespace
58
59
60
nsresult
61
CreateOrMigrateSchema(mozIStorageConnection* aConn)
62
{
63
  nsTArray<nsCString> tablesSql;
64
  tablesSql.AppendElement(nsCString(kTableRegistrations));
65
66
  nsTArray<Expect> expect;
67
  expect.AppendElement(Expect("registrations", "table", kTableRegistrations));
68
  expect.AppendElement(Expect("sqlite_autoindex_registrations_1", "index"));
69
70
  return storage::utils::CreateOrMigrateSchema(aConn,
71
                                               kFirstShippedSchemaVersion,
72
                                               kLatestSchemaVersion, tablesSql,
73
                                               expect, nsTArray<Migration>());
74
}
75
76
nsresult
77
InitializeConnection(mozIStorageConnection* aConn)
78
{
79
  return storage::utils::InitializeConnection(aConn, kPageSize, kGrowthSize,
80
                                              kWalAutoCheckpointPages,
81
                                              kWalAutoCheckpointSize);
82
}
83
84
nsresult
85
IncrementalVacuum(mozIStorageConnection* aConn)
86
{
87
  return storage::utils::IncrementalVacuum(aConn, kMaxFreePages);
88
}
89
90
nsresult
91
GetId(const nsAString& aScope, const nsAString& aTag, nsAString& aId)
92
{
93
  nsresult rv;
94
95
  nsCOMPtr<nsICryptoHash> crypto =
96
    do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
97
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
98
99
  rv = crypto->Init(nsICryptoHash::SHA1);
100
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
101
102
  nsAString concat(aScope + NS_LITERAL_STRING("@") + aTag);
103
  rv = crypto->Update(reinterpret_cast<const uint8_t*>(concat.BeginReading()),
104
                      concat.Length());
105
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
106
107
  nsAutoCString fullHash;
108
  rv = crypto->Finish(true /* based64 result */, fullHash);
109
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
110
111
  aId = NS_ConvertUTF8toUTF16(Substring(fullHash, 0, 8));
112
  return rv;
113
}
114
115
nsresult
116
Register(mozIStorageConnection* aConn,
117
         const SyncRegisterArgs& aArgs,
118
         bool& firstRegistrationForOrigin,
119
         Registration& aRegistration)
120
{
121
  MOZ_ASSERT(!NS_IsMainThread());
122
  MOZ_ASSERT(aConn);
123
124
  nsresult rv = NS_OK;
125
126
  {
127
    nsCOMPtr<mozIStorageStatement> state;
128
    rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
129
      "INSERT INTO registrations ("
130
        "id, "
131
        "origin, "
132
        "scope, "
133
        "tag, "
134
        "state, "
135
        "lastChance "
136
      ") VALUES ("
137
        ":id, "
138
        ":origin, "
139
        ":scope, "
140
        ":tag, "
141
        ":state, "
142
        ":lastChance "
143
      ");"
144
    ), getter_AddRefs(state));
145
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
146
147
    nsString id;
148
    GetId(aArgs.mScope(), aArgs.mTag(), id);
149
150
    Registration registration(id, aArgs.mOrigin(),
151
                              aArgs.mScope(),
152
                              aArgs.mTag(),
153
                              RegistrationState::ePending,
154
                              false);
155
    aRegistration = registration;
156
157
    rv = state->BindStringByName(NS_LITERAL_CSTRING("id"),
158
                                 registration.mId());
159
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
160
161
    rv = state->BindStringByName(NS_LITERAL_CSTRING("origin"),
162
                                 registration.mOrigin());
163
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
164
165
    rv = state->BindStringByName(NS_LITERAL_CSTRING("scope"),
166
                                 registration.mScope());
167
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
168
169
    rv = state->BindUTF8StringAsBlobByName(NS_LITERAL_CSTRING("tag"),
170
                                           NS_ConvertUTF16toUTF8(registration.mTag()));
171
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
172
173
    rv = state->BindInt32ByName(NS_LITERAL_CSTRING("state"),
174
                                RegistrationState::ePending);
175
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
176
177
    // By default new registrations are not flagged as last chance.
178
    rv = state->BindInt32ByName(NS_LITERAL_CSTRING("lastChance"), 0);
179
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
180
181
    rv = state->Execute();
182
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
183
  }
184
185
  // After inserting the new registration we check if this is the first
186
  // registration for this origin. In that case, we need to register the
187
  // origin in the 'origins' DB.
188
  nsCOMPtr<mozIStorageStatement> state;
189
  rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
190
    "SELECT COUNT(*) FROM (SELECT id FROM registrations WHERE origin=:origin);"
191
  ), getter_AddRefs(state));
192
193
  rv = state->BindStringByName(NS_LITERAL_CSTRING("origin"), aArgs.mOrigin());
194
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
195
196
  bool hasMoreData = false;
197
  NS_SUCCEEDED(state->ExecuteStep(&hasMoreData));
198
199
  int32_t count;
200
  rv = state->GetInt32(0, &count);
201
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
202
  firstRegistrationForOrigin = (count == 1);
203
204
  return rv;
205
}
206
207
nsresult
208
GetTags(mozIStorageConnection* aConn,
209
        const SyncGetTagsArgs& aArgs,
210
        nsTArray<nsString>& aTags)
211
{
212
  MOZ_ASSERT(!NS_IsMainThread());
213
  MOZ_ASSERT(aConn);
214
215
  nsCOMPtr<mozIStorageStatement> state;
216
  nsresult rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
217
    "SELECT tag FROM registrations;"
218
  ), getter_AddRefs(state));
219
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
220
221
  bool hasMoreData = false;
222
  while (NS_SUCCEEDED(state->ExecuteStep(&hasMoreData)) && hasMoreData) {
223
    nsAutoCString tag;
224
    rv = state->GetBlobAsUTF8String(0, tag);
225
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
226
    aTags.AppendElement(NS_ConvertUTF8toUTF16(tag));
227
  }
228
229
  return rv;
230
}
231
232
nsresult
233
GetAll(mozIStorageConnection* aConn,
234
       nsTArray<Registration>& aRegistrations)
235
{
236
  MOZ_ASSERT(!NS_IsMainThread());
237
  MOZ_ASSERT(aConn);
238
239
  nsCOMPtr<mozIStorageStatement> state;
240
  nsresult rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
241
    "SELECT "
242
    "id, "
243
    "origin, "
244
    "scope, "
245
    "tag, "
246
    "state, "
247
    "lastChance FROM registrations;"
248
  ), getter_AddRefs(state));
249
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
250
251
  bool hasMoreData = false;
252
  while (NS_SUCCEEDED(state->ExecuteStep(&hasMoreData)) && hasMoreData) {
253
    nsString id;
254
    rv = state->GetString(0, id);
255
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
256
257
    nsString origin;
258
    rv = state->GetString(1, origin);
259
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
260
261
    nsString scope;
262
    rv = state->GetString(2, scope);
263
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
264
265
    nsAutoCString tag;
266
    rv = state->GetBlobAsUTF8String(3, tag);
267
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
268
269
    int32_t registrationState;
270
    rv = state->GetInt32(4, &registrationState);
271
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
272
273
    int32_t lastChance;
274
    rv = state->GetInt32(5, &lastChance);
275
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
276
277
    Registration registration(id, origin, scope, NS_ConvertUTF8toUTF16(tag),
278
      RegistrationState(registrationState), bool(lastChance));
279
    aRegistrations.AppendElement(registration);
280
  }
281
282
  return rv;
283
}
284
285
nsresult
286
Remove(mozIStorageConnection* aConn,
287
       const SyncRemoveArgs& aArgs,
288
       nsString& aOrigin)
289
{
290
  MOZ_ASSERT(!NS_IsMainThread());
291
  MOZ_ASSERT(aConn);
292
293
  // Get the origin value before removing the entry from the 'registrations'
294
  // DB so we can remove the entry from the 'origins' DB in case that there are
295
  // no more sync registrations for that origin.
296
  nsCOMPtr<mozIStorageStatement> getOriginState;
297
  nsresult rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
298
    "SELECT origin FROM registrations WHERE id=:id;"
299
  ), getter_AddRefs(getOriginState));
300
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
301
302
  rv = getOriginState->BindStringByName(NS_LITERAL_CSTRING("id"), aArgs.mId());
303
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
304
305
  int32_t count = 0;
306
  bool hasMoreData = false;
307
  while (NS_SUCCEEDED(getOriginState->ExecuteStep(&hasMoreData))
308
         && hasMoreData) {
309
    // We only set the origin on the first registration.
310
    if (count == 0) {
311
      rv = getOriginState->GetString(0, aOrigin);
312
      if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
313
    } else if (!aOrigin.IsEmpty() && hasMoreData){
314
      aOrigin = EmptyString();
315
    }
316
    hasMoreData = false;
317
    count++;
318
  }
319
320
  nsCOMPtr<mozIStorageStatement> state;
321
  rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
322
    "DELETE FROM registrations WHERE id=:id;"
323
  ), getter_AddRefs(state));
324
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
325
326
  rv = state->BindStringByName(NS_LITERAL_CSTRING("id"), aArgs.mId());
327
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
328
329
  rv = state->Execute();
330
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
331
332
  return rv;
333
}
334
335
nsresult
336
ChangeState(mozIStorageConnection* aConn,
337
            const SyncChangeStateArgs& aArgs,
338
            Registration& aRegistrationOut)
339
{
340
  MOZ_ASSERT(!NS_IsMainThread());
341
  MOZ_ASSERT(aConn);
342
343
  nsCOMPtr<mozIStorageStatement> state;
344
  nsresult rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
345
    "UPDATE registrations SET state=:regstate WHERE id=:id;"
346
  ), getter_AddRefs(state));
347
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
348
349
  rv = state->BindInt32ByName(NS_LITERAL_CSTRING("regstate"),
350
                              static_cast<int32_t>(aArgs.mState()));
351
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
352
353
  rv = state->BindStringByName(NS_LITERAL_CSTRING("id"), aArgs.mId());
354
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
355
356
  rv = state->Execute();
357
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
358
359
  {
360
    // Get the origin value after changing its state.
361
    nsCOMPtr<mozIStorageStatement> state;
362
    nsresult rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
363
      "SELECT * FROM registrations WHERE id=:id;"
364
    ), getter_AddRefs(state));
365
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
366
367
    rv = state->BindStringByName(NS_LITERAL_CSTRING("id"), aArgs.mId());
368
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
369
370
    bool ignored = false;
371
    rv = state->ExecuteStep(&ignored);
372
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
373
374
    rv = state->GetString(0, aRegistrationOut.mId());
375
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
376
377
    rv = state->GetString(1, aRegistrationOut.mOrigin());
378
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
379
380
    rv = state->GetString(2, aRegistrationOut.mScope());
381
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
382
383
    rv = state->GetString(3, aRegistrationOut.mTag());
384
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
385
386
    int32_t registrationState;
387
    rv = state->GetInt32(4, &registrationState);
388
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
389
    aRegistrationOut.mState() =
390
      RegistrationState(registrationState);
391
392
    int32_t lastChance;
393
    rv = state->GetInt32(5, &lastChance);
394
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
395
    aRegistrationOut.mLastChance() = bool(lastChance);
396
  }
397
398
  return rv;
399
}
400
401
} // namespace db
402
} // namespace backgroundsync
403
} // namespace dom
404
} // namespace mozilla
(-)a/dom/backgroundsync/DBSchema.h (+69 lines)
Line     Link Here 
Line 0    Link Here 
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=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/. */
6
7
#ifndef mozilla_dom_DBSchema_h
8
#define mozilla_dom_DBSchema_h
9
10
class mozIStorageConnection;
11
struct nsID;
12
13
namespace mozilla {
14
namespace dom {
15
namespace backgroundsync {
16
17
class Registration;
18
19
namespace db {
20
21
using storage::utils::Expect;
22
23
// Note, this cannot be executed within a transaction.
24
nsresult
25
CreateOrMigrateSchema(mozIStorageConnection* aConn);
26
27
// Note, this cannot be executed within a transaction.
28
nsresult
29
InitializeConnection(mozIStorageConnection* aConn);
30
31
nsresult
32
Register(mozIStorageConnection* aConn,
33
         const SyncRegisterArgs& aArgs,
34
         bool& firstRegistrationForOrigin,
35
         Registration& aRegistration);
36
37
nsresult
38
GetTags(mozIStorageConnection* aConn,
39
        const SyncGetTagsArgs& aArgs,
40
        nsTArray<nsString>& aTags);
41
42
nsresult
43
GetAll(mozIStorageConnection* aConn,
44
       nsTArray<Registration>& aRegistrations);
45
46
nsresult
47
Remove(mozIStorageConnection* aConn,
48
       const SyncRemoveArgs& aArgs,
49
       nsString& aOrigin);
50
51
nsresult
52
ChangeState(mozIStorageConnection* aConn,
53
            const SyncChangeStateArgs& aArgs,
54
            Registration& aRegistration);
55
56
// Note, this works best when its NOT executed within a transaction.
57
nsresult
58
IncrementalVacuum(mozIStorageConnection* aConn);
59
60
// We will wipe out databases with schema versions less than this. Newer
61
// versions will be migrated on open to the latest schema version.
62
extern const int32_t kFirstShippedSchemaVersion;
63
64
} // namespace db
65
} // namespace backgroundsync
66
} // namespace dom
67
} // namespace mozilla
68
69
#endif // mozilla_dom_DBSchema_h
(-)a/dom/backgroundsync/PBackgroundSync.ipdl (+2 lines)
Line     Link Here 
 Lines 5-28    Link Here 
5
include protocol PBackground;
5
include protocol PBackground;
6
6
7
include BackgroundSyncIPCTypes;
7
include BackgroundSyncIPCTypes;
8
8
9
using struct nsID from "nsID.h";
9
using struct nsID from "nsID.h";
10
10
11
namespace mozilla {
11
namespace mozilla {
12
namespace dom {
12
namespace dom {
13
namespace backgroundsync {
13
14
14
protocol PBackgroundSync
15
protocol PBackgroundSync
15
{
16
{
16
  manager PBackground;
17
  manager PBackground;
17
18
18
parent: // child -> parent messages
19
parent: // child -> parent messages
19
  async Request(nsID aRequestId, SyncOp aOp);
20
  async Request(nsID aRequestId, SyncOp aOp);
20
  async Shutdown();
21
  async Shutdown();
21
22
22
child: // parent -> child messages
23
child: // parent -> child messages
23
  async Response(nsID requestId, SyncOpResponse aResponse);
24
  async Response(nsID requestId, SyncOpResponse aResponse);
24
  async __delete__();
25
  async __delete__();
25
};
26
};
26
27
28
} // namespace backgroundsync
27
} // namespace dom
29
} // namespace dom
28
} // namespace mozilla
30
} // namespace mozilla
(-)a/dom/backgroundsync/QuotaClient.cpp (+185 lines)
Line     Link Here 
Line 0    Link Here 
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=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/. */
6
7
#include "QuotaClient.h"
8
#include "StorageManager.h"
9
10
#include "mozilla/DebugOnly.h"
11
#include "mozilla/dom/quota/QuotaManager.h"
12
#include "mozilla/dom/quota/UsageInfo.h"
13
#include "mozilla/ipc/BackgroundParent.h"
14
#include "nsIFile.h"
15
#include "nsISimpleEnumerator.h"
16
#include "nsThreadUtils.h"
17
18
namespace {
19
20
using mozilla::DebugOnly;
21
using mozilla::dom::ContentParentId;
22
using mozilla::dom::backgroundsync::StorageManager;
23
using mozilla::dom::quota::Client;
24
using mozilla::dom::quota::PersistenceType;
25
using mozilla::dom::quota::QuotaManager;
26
using mozilla::dom::quota::UsageInfo;
27
using mozilla::ipc::AssertIsOnBackgroundThread;
28
29
class BackgroundSyncQuotaClient final : public Client
30
{
31
public:
32
  virtual Type
33
  GetType() override
34
  {
35
    return BACKGROUNDSYNC;
36
  }
37
38
  virtual nsresult
39
  InitOrigin(PersistenceType aPersistenceType, const nsACString& aGroup,
40
             const nsACString& aOrigin, UsageInfo* aUsageInfo) override
41
  {
42
    // The QuotaManager passes a nullptr UsageInfo if there is no quota being
43
    // enforced against the origin.
44
    if (!aUsageInfo) {
45
      return NS_OK;
46
    }
47
48
    return GetUsageForOrigin(aPersistenceType, aGroup, aOrigin, aUsageInfo);
49
  }
50
51
  virtual nsresult
52
  GetUsageForOrigin(PersistenceType aPersistenceType, const nsACString& aGroup,
53
                    const nsACString& aOrigin, UsageInfo* aUsageInfo) override
54
  {
55
    MOZ_ASSERT(aUsageInfo);
56
57
    QuotaManager* qm = QuotaManager::Get();
58
    MOZ_ASSERT(qm);
59
60
    nsCOMPtr<nsIFile> dir;
61
    nsresult rv = qm->GetDirectoryForOrigin(aPersistenceType, aOrigin,
62
                                            getter_AddRefs(dir));
63
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
64
65
    rv = dir->Append(NS_LITERAL_STRING(BACKGROUNDSYNC_DIRECTORY_NAME));
66
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
67
68
    nsCOMPtr<nsISimpleEnumerator> entries;
69
    rv = dir->GetDirectoryEntries(getter_AddRefs(entries));
70
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
71
72
    bool hasMore;
73
    while (NS_SUCCEEDED(rv = entries->HasMoreElements(&hasMore)) && hasMore &&
74
           !aUsageInfo->Canceled()) {
75
      nsCOMPtr<nsISupports> entry;
76
      rv = entries->GetNext(getter_AddRefs(entry));
77
      if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
78
79
      nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
80
81
      nsAutoString leafName;
82
      rv = file->GetLeafName(leafName);
83
      if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
84
85
      bool isDir;
86
      rv = file->IsDirectory(&isDir);
87
      if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
88
89
      if (isDir) {
90
        NS_WARNING("Unknown BackgroundSync directory found!");
91
        continue;
92
      }
93
94
      // Ignore transient sqlite files and marker files
95
      if (leafName.EqualsLiteral("backgroundsync.sqlite-journal") ||
96
          leafName.EqualsLiteral("backgroundsync.sqlite-shm") ||
97
          leafName.Find(NS_LITERAL_CSTRING("backgroundsync.sqlite-mj"), false, 0, 0) == 0 ||
98
          leafName.EqualsLiteral("context_open.marker")) {
99
        continue;
100
      }
101
102
      if (leafName.EqualsLiteral("backgroundsync.sqlite") ||
103
          leafName.EqualsLiteral("backgroundsync.sqlite-wal")) {
104
        int64_t fileSize;
105
        rv = file->GetFileSize(&fileSize);
106
        if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
107
        MOZ_ASSERT(fileSize >= 0);
108
109
        aUsageInfo->AppendToDatabaseUsage(fileSize);
110
        continue;
111
      }
112
113
      NS_WARNING("Unknown BackgroundSync file found!");
114
    }
115
116
    return NS_OK;
117
  }
118
119
  virtual void
120
  OnOriginClearCompleted(PersistenceType aPersistenceType,
121
                         const nsACString& aOrigin) override
122
  { }
123
124
  virtual void
125
  ReleaseIOThreadObjects() override
126
  {
127
    // Nothing to do here as the ClientContext handles cleaning everything up
128
    // automatically.
129
  }
130
131
  virtual void
132
  AbortOperations(const nsACString& aOrigin) override
133
  {
134
    AssertIsOnBackgroundThread();
135
136
    StorageManager::Abort(aOrigin);
137
  }
138
139
  virtual void
140
  AbortOperationsForProcess(ContentParentId aContentParentId) override
141
  { }
142
143
  virtual void
144
  StartIdleMaintenance() override
145
  { }
146
147
  virtual void
148
  StopIdleMaintenance() override
149
  { }
150
151
  virtual void
152
  ShutdownWorkThreads() override
153
  {
154
    AssertIsOnBackgroundThread();
155
156
    // spins the event loop and synchronously shuts down all StorageManagers.
157
    StorageManager::ShutdownAll();
158
  }
159
160
private:
161
  ~BackgroundSyncQuotaClient()
162
  {
163
    AssertIsOnBackgroundThread();
164
  }
165
166
  NS_INLINE_DECL_REFCOUNTING(BackgroundSyncQuotaClient, override)
167
};
168
169
} // namespace
170
171
namespace mozilla {
172
namespace dom {
173
namespace backgroundsync {
174
175
already_AddRefed<mozilla::dom::quota::Client> CreateQuotaClient()
176
{
177
  AssertIsOnBackgroundThread();
178
179
  RefPtr<BackgroundSyncQuotaClient> ref = new BackgroundSyncQuotaClient();
180
  return ref.forget();
181
}
182
183
} // namespace backgroundsync
184
} // namespace dom
185
} // namespace mozilla
(-)a/dom/backgroundsync/QuotaClient.h (+24 lines)
Line     Link Here 
Line 0    Link Here 
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=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/. */
6
7
#ifndef mozilla_dom_backgroundsync_QuotaClient_h
8
#define mozilla_dom_backgroundsync_QuotaClient_h
9
10
#include "mozilla/Attributes.h"
11
#include "mozilla/dom/quota/Client.h"
12
13
namespace mozilla {
14
namespace dom {
15
namespace backgroundsync {
16
17
already_AddRefed<mozilla::dom::quota::Client>
18
CreateQuotaClient();
19
20
} // namespace backgroundsync
21
} // namespace dom
22
} // namespace mozilla
23
24
#endif // mozilla_dom_backgroundsync_QuotaClient_h
(-)a/dom/backgroundsync/StorageManager.cpp (+780 lines)
Line     Link Here 
Line 0    Link Here 
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=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/. */
6
7
#include "DBAction.h"
8
#include "StorageManager.h"
9
10
#include "mozilla/AutoRestore.h"
11
#include "mozilla/StaticMutex.h"
12
#include "nsIThread.h"
13
#include "nsThreadUtils.h"
14
15
namespace mozilla {
16
namespace dom {
17
namespace backgroundsync {
18
19
namespace {
20
21
// ClientActions that are executed when a ClientContext is first created.
22
// It ensures that the database is setup properly.
23
// This lets other actions not worry about these details.
24
class SetupAction final : public SyncDBAction
25
{
26
public:
27
  SetupAction()
28
    : SyncDBAction(DBAction::Create)
29
  { }
30
31
  virtual nsresult
32
  RunSyncOnTarget(const QuotaInfo& aQuotaInfo,
33
                  mozIStorageConnection* aConn) override
34
  {
35
    // Executes in its own transaction.
36
    nsresult rv = db::CreateOrMigrateSchema(aConn);
37
    if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
38
39
    return rv;
40
  }
41
};
42
43
} // anonymous namespace
44
45
// ---------------------------------------------------------------------------
46
47
// Singleton class to track StorageManager instances and ensure there is only
48
// one for each unique StorageManagerId.
49
class StorageManager::Factory
50
{
51
public:
52
  friend class StaticAutoPtr<StorageManager::Factory>;
53
54
  static nsresult
55
  GetOrCreate(StorageManagerId* aManagerId,
56
              StorageManager** aManagerOut)
57
  {
58
    AssertIsOnBackgroundThread();
59
60
    // Ensure there is a factory instance. This forces the Get() call
61
    // below to use the same factory.
62
    nsresult rv = MaybeCreateInstance();
63
    if (NS_WARN_IF(NS_FAILED(rv))) {
64
      return rv;
65
    }
66
67
    RefPtr<StorageManager> ref = Get(aManagerId);
68
    if (!ref) {
69
      nsCOMPtr<nsIThread> ioThread;
70
      rv = NS_NewNamedThread("BSyncIOThread", getter_AddRefs(ioThread));
71
      if (NS_WARN_IF(NS_FAILED(rv))) {
72
        return rv;
73
      }
74
75
      ref = new StorageManager(aManagerId, ioThread);
76
77
      // There may be an old manager for this origin in the process of
78
      // cleaning up.  We need to tell the new manager about this so
79
      // that it won't actually start until the old manager is done.
80
      RefPtr<StorageManager> oldManager = Get(aManagerId, Closing);
81
      ref->Init(oldManager);
82
83
      MOZ_ASSERT(!sFactory->mManagerList.Contains(ref));
84
      sFactory->mManagerList.AppendElement(ref);
85
    }
86
87
    ref.forget(aManagerOut);
88
89
    return NS_OK;
90
  }
91
92
  static already_AddRefed<StorageManager>
93
  Get(StorageManagerId* aManagerId, State aState = Open)
94
  {
95
    AssertIsOnBackgroundThread();
96
97
    nsresult rv = MaybeCreateInstance();
98
    if (NS_WARN_IF(NS_FAILED(rv))) {
99
      return nullptr;
100
    }
101
102
    // Iterate in reverse to find the most recent, matching Manager. This
103
    // is important when looking for a Closing Manager.  If a new Manager
104
    // chains to an old Manager we want it to be the most recent one.
105
    ManagerList::BackwardIterator iter(sFactory->mManagerList);
106
    while (iter.HasMore()) {
107
      RefPtr<StorageManager> manager = iter.GetNext();
108
      if (aState == manager->GetState() && *manager->mManagerId == *aManagerId) {
109
        return manager.forget();
110
      }
111
    }
112
113
    return nullptr;
114
  }
115
116
  static void
117
  Remove(StorageManager* aManager)
118
  {
119
    AssertIsOnBackgroundThread();
120
    MOZ_ASSERT(aManager);
121
    MOZ_ASSERT(sFactory);
122
123
    MOZ_ALWAYS_TRUE(sFactory->mManagerList.RemoveElement(aManager));
124
125
    // Clean up the factory singleton if there are no more managers.
126
    MaybeDestroyInstance();
127
  }
128
129
  static void
130
  Abort(const nsACString& aOrigin)
131
  {
132
    AssertIsOnBackgroundThread();
133
134
    if (!sFactory) {
135
      return;
136
    }
137
138
    MOZ_ASSERT(!sFactory->mManagerList.IsEmpty());
139
140
    {
141
      ManagerList::ForwardIterator iter(sFactory->mManagerList);
142
      while (iter.HasMore()) {
143
        RefPtr<StorageManager> manager = iter.GetNext();
144
        if (aOrigin.IsVoid() ||
145
            manager->mManagerId->QuotaOrigin() == aOrigin) {
146
          manager->Abort();
147
        }
148
      }
149
    }
150
  }
151
152
  static void
153
  ShutdownAll()
154
  {
155
    AssertIsOnBackgroundThread();
156
157
    if (!sFactory) {
158
      return;
159
    }
160
161
    MOZ_ASSERT(!sFactory->mManagerList.IsEmpty());
162
163
    {
164
      // Note that we are synchronously calling shutdown code here. If any
165
      // of the shutdown code synchronously decides to delete the Factory
166
      // we need to delay that delete until the end of this method.
167
      AutoRestore<bool> restore(sFactory->mInSyncShutdown);
168
      sFactory->mInSyncShutdown = true;
169
170
      ManagerList::ForwardIterator iter(sFactory->mManagerList);
171
      while (iter.HasMore()) {
172
        RefPtr<StorageManager> manager = iter.GetNext();
173
        manager->Shutdown();
174
      }
175
    }
176
177
    MaybeDestroyInstance();
178
  }
179
180
  static bool
181
  IsShutdownAllComplete()
182
  {
183
    AssertIsOnBackgroundThread();
184
    return !sFactory;
185
  }
186
187
private:
188
  Factory()
189
    : mInSyncShutdown(false)
190
  {
191
    MOZ_COUNT_CTOR(StorageManager::Factory);
192
  }
193
194
  ~Factory()
195
  {
196
    MOZ_COUNT_DTOR(StorageManager::Factory);
197
    MOZ_ASSERT(mManagerList.IsEmpty());
198
    MOZ_ASSERT(!mInSyncShutdown);
199
  }
200
201
  static nsresult
202
  MaybeCreateInstance()
203
  {
204
    AssertIsOnBackgroundThread();
205
206
    if (!sFactory) {
207
      // Be clear about what we are locking. sFactory is bg thread only, so
208
      // we don't need to lock it here. Just protect sFactoryShutdown and
209
      // sBackgroundThread.
210
      {
211
        StaticMutexAutoLock lock(sMutex);
212
213
        if (sFactoryShutdown) {
214
          return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
215
        }
216
      }
217
218
      // We cannot use ClearOnShutdown() here because we're not on the main
219
      // thread. Instead, we delete sFactory in Factory::Remove() after the
220
      // last manager is removed.  ShutdownObserver ensures this happens
221
      // before shutdown.
222
      sFactory = new Factory();
223
    }
224
225
    // Never return sFactory to code outside Factory.  We need to delete it
226
    // out from under ourselves just before we return from Remove().  This
227
    // would be (even more) dangerous if other code had a pointer to the
228
    // factory itself.
229
230
    return NS_OK;
231
  }
232
233
  static void
234
  MaybeDestroyInstance()
235
  {
236
    AssertIsOnBackgroundThread();
237
    MOZ_ASSERT(sFactory);
238
239
    // If the factory is still in use then we cannot delete yet. This
240
    // could be due to managers still existing or because we are in the
241
    // middle of shutting down. We need to be careful not to delete ourself
242
    // synchronously during shutdown.
243
    if (!sFactory->mManagerList.IsEmpty() || sFactory->mInSyncShutdown) {
244
      return;
245
    }
246
247
    sFactory = nullptr;
248
  }
249
250
  // Singleton created on demand and deleted when last Manager is cleared
251
  // in Remove(). PBackground thread only.
252
  static StaticAutoPtr<Factory> sFactory;
253
254
  // Protects following static attribute.
255
  static StaticMutex sMutex;
256
257
  // Indicate if shutdown has occurred to block re-creation of sFactory.
258
  // Must hold sMutex to access.
259
  static bool sFactoryShutdown;
260
261
  // Weak references as we don't want to keep StorageManager objects alive
262
  // forever.
263
  // When a Manager is destroyed it calls Factory::Remove() to clear itself.
264
  // PBackground thread only.
265
  typedef nsTObserverArray<StorageManager*> ManagerList;
266
  ManagerList mManagerList;
267
268
  // This flag is set when we are looping through the list and calling
269
  // Shutdown() on each Manager.  We need to be careful not to synchronously
270
  // trigger the deletion of the factory while still executing this loop.
271
  bool mInSyncShutdown;
272
};
273
274
// static
275
StaticAutoPtr<StorageManager::Factory> StorageManager::Factory::sFactory;
276
277
// static
278
StaticMutex StorageManager::Factory::sMutex;
279
280
// static
281
bool StorageManager::Factory::sFactoryShutdown = false;
282
283
// ---------------------------------------------------------------------------
284
285
// Abstract class to help implement the varios ClientActions.
286
class StorageManager::BaseAction : public SyncDBAction
287
{
288
protected:
289
  BaseAction(const nsID& aRequestId, StorageManager* aManager)
290
    : SyncDBAction(DBAction::Existing)
291
    , mRequestId(aRequestId)
292
    , mManager(aManager)
293
  {}
294
295
  virtual void
296
  Complete(nsresult aRv) = 0;
297
298
  virtual void
299
  CompleteOnInitiatingThread(nsresult aRv) override
300
  {
301
    NS_ASSERT_OWNINGTHREAD(StorageManager::BaseAction);
302
303
    Complete(aRv);
304
305
    // Ensure we release the manager on the initiating thread.
306
    mManager = nullptr;
307
  }
308
309
  const nsID mRequestId;
310
  RefPtr<StorageManager> mManager;
311
};
312
313
// ---------------------------------------------------------------------------
314
315
class StorageManager::RegisterAction final : public StorageManager::BaseAction
316
{
317
public:
318
  RegisterAction(const nsID& aRequestId,
319
                 StorageManager* aManager,
320
                 const SyncRegisterArgs& aRegisterArgs)
321
    : BaseAction(aRequestId, aManager)
322
    , mArgs(aRegisterArgs)
323
    , mFirstRegistration(true)
324
  {}
325
326
  virtual nsresult
327
  RunSyncOnTarget(const QuotaInfo& aQuotaInfo,
328
                  mozIStorageConnection* aConn) override
329
  {
330
    nsresult rv = db::Register(aConn, mArgs, mFirstRegistration,
331
                               mRegistration);
332
    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "db::Register failed");
333
    return rv;
334
  }
335
336
  virtual void
337
  Complete(nsresult aRv) override
338
  {
339
    if (NS_FAILED(aRv)) {
340
      mManager->OnRequestComplete(mRequestId,
341
        SyncOpError(static_cast<uint32_t>(aRv)));
342
    } else {
343
      mManager->OnRequestComplete(mRequestId,
344
          SyncRegisterResponse(mRegistration, mFirstRegistration));
345
    }
346
  }
347
348
private:
349
  SyncRegisterArgs mArgs;
350
  bool mFirstRegistration;
351
  Registration mRegistration;
352
};
353
354
// ---------------------------------------------------------------------------
355
356
class StorageManager::GetTagsAction final : public StorageManager::BaseAction
357
{
358
public:
359
  GetTagsAction(const nsID& aRequestId,
360
                StorageManager* aManager,
361
                const SyncGetTagsArgs& aGetTagsArgs)
362
    : BaseAction(aRequestId, aManager)
363
    , mArgs(aGetTagsArgs)
364
  {}
365
366
  virtual nsresult
367
  RunSyncOnTarget(const QuotaInfo& aQuotaInfo,
368
                  mozIStorageConnection* aConn) override
369
  {
370
    nsresult rv = db::GetTags(aConn, mArgs, mTags);
371
    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "GetTags failed");
372
    return rv;
373
  }
374
375
  virtual void
376
  Complete(nsresult aRv) override
377
  {
378
    if (NS_FAILED(aRv)) {
379
      mManager->OnRequestComplete(mRequestId,
380
        SyncOpError(static_cast<uint32_t>(aRv)));
381
    } else {
382
      mManager->OnRequestComplete(mRequestId,
383
        SyncGetTagsResponse(mTags));
384
    }
385
  }
386
387
private:
388
  SyncGetTagsArgs mArgs;
389
  nsTArray<nsString> mTags;
390
};
391
392
// ---------------------------------------------------------------------------
393
394
class StorageManager::GetAllAction final : public StorageManager::BaseAction
395
{
396
public:
397
  GetAllAction(const nsID& aRequestId,
398
               StorageManager* aManager)
399
    : BaseAction(aRequestId, aManager)
400
  {}
401
402
  virtual nsresult
403
  RunSyncOnTarget(const QuotaInfo& aQuotaInfo,
404
                  mozIStorageConnection* aConn) override
405
  {
406
    nsresult rv = db::GetAll(aConn, mRegistrations);
407
    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "GetAll failed");
408
    return rv;
409
  }
410
411
  virtual void
412
  Complete(nsresult aRv) override
413
  {
414
    NS_WARNING_ASSERTION(NS_SUCCEEDED(aRv), "GetAll failed");
415
    // We need to remove the reference to the request independently of
416
    // its result so we can close the context.
417
    mManager->OnRequestComplete(mRequestId,
418
      SyncGetAllResponse(mRegistrations));
419
  }
420
421
private:
422
  nsTArray<Registration> mRegistrations;
423
};
424
425
// ---------------------------------------------------------------------------
426
427
class StorageManager::RemoveAction final : public StorageManager::BaseAction
428
{
429
public:
430
  RemoveAction(const nsID& aRequestId,
431
               StorageManager* aManager,
432
               const SyncRemoveArgs& aRemoveArgs)
433
    : BaseAction(aRequestId, aManager)
434
    , mArgs(aRemoveArgs)
435
  {}
436
437
  virtual nsresult
438
  RunSyncOnTarget(const QuotaInfo& aQuotaInfo,
439
                  mozIStorageConnection* aConn) override
440
  {
441
    nsresult rv = db::Remove(aConn, mArgs, mOrigin);
442
    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Remove failed");
443
    return rv;
444
  }
445
446
  virtual void
447
  Complete(nsresult aRv) override
448
  {
449
    NS_WARNING_ASSERTION(NS_SUCCEEDED(aRv), "Remove failed");
450
    // We need to remove the reference to the request independently of
451
    // its result so we can close the context.
452
    mManager->OnRequestComplete(mRequestId,
453
      SyncRemoveResponse(mOrigin));
454
  }
455
456
private:
457
  SyncRemoveArgs mArgs;
458
  nsString mOrigin;
459
};
460
461
// ---------------------------------------------------------------------------
462
463
class StorageManager::ChangeStateAction final : public StorageManager::BaseAction
464
{
465
public:
466
  ChangeStateAction(const nsID& aRequestId,
467
                   StorageManager* aManager,
468
                   const SyncChangeStateArgs& aChangeStateArgs)
469
    : BaseAction(aRequestId, aManager)
470
    , mArgs(aChangeStateArgs)
471
  {}
472
473
  virtual nsresult
474
  RunSyncOnTarget(const QuotaInfo& aQuotaInfo,
475
                  mozIStorageConnection* aConn) override
476
  {
477
    nsresult rv = db::ChangeState(aConn, mArgs, mRegistration);
478
    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "ChangeState failed");
479
    return rv;
480
  }
481
482
  virtual void
483
  Complete(nsresult aRv) override
484
  {
485
    NS_WARNING_ASSERTION(NS_SUCCEEDED(aRv), "ChangeState failed");
486
    // We need to remove the reference to the request independently of
487
    // its result so we can close the context.
488
    mManager->OnRequestComplete(mRequestId,
489
      SyncChangeStateResponse(mRegistration));
490
  }
491
492
private:
493
  SyncChangeStateArgs mArgs;
494
  Registration mRegistration;
495
};
496
497
// ---------------------------------------------------------------------------
498
499
// static
500
nsresult
501
StorageManager::GetOrCreate(StorageManagerId* aManagerId,
502
                            StorageManager** aManagerOut)
503
{
504
  AssertIsOnBackgroundThread();
505
  return Factory::GetOrCreate(aManagerId, aManagerOut);
506
}
507
508
// static
509
void
510
StorageManager::ShutdownAll()
511
{
512
  mozilla::ipc::AssertIsOnBackgroundThread();
513
514
  Factory::ShutdownAll();
515
  while (!Factory::IsShutdownAllComplete()) {
516
    if (!NS_ProcessNextEvent()) {
517
      NS_WARNING("Something bad happened!");
518
      break;
519
    }
520
  }
521
}
522
523
// static
524
void
525
StorageManager::Abort(const nsACString& aOrigin)
526
{
527
 mozilla::ipc::AssertIsOnBackgroundThread();
528
529
 Factory::Abort(aOrigin);
530
}
531
532
StorageManager::StorageManager(StorageManagerId* aManagerId,
533
                               nsIThread* aIOThread)
534
  : mManagerId(aManagerId)
535
  , mIOThread(aIOThread)
536
  , mContext(nullptr)
537
  , mShuttingDown(false)
538
  , mState(Open)
539
{
540
  MOZ_ASSERT(mManagerId);
541
  MOZ_ASSERT(mIOThread);
542
}
543
544
StorageManager::~StorageManager()
545
{
546
  NS_ASSERT_OWNINGTHREAD(StorageManager);
547
  MOZ_ASSERT(mState == Closing);
548
  MOZ_ASSERT(!mContext);
549
550
  nsCOMPtr<nsIThread> ioThread;
551
  mIOThread.swap(ioThread);
552
  MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(
553
        NewRunnableMethod(ioThread, &nsIThread::Shutdown)));
554
}
555
556
void
557
StorageManager::Init(StorageManager* aOldManager)
558
{
559
  NS_ASSERT_OWNINGTHREAD(StorageManager);
560
561
  RefPtr<ClientContext> oldContext;
562
  if (aOldManager) {
563
    oldContext = aOldManager->mContext;
564
  }
565
566
  // Create the context immediately. Since there can at most be one
567
  // ClientContext per StorageManager, this lets us cleanly call
568
  // Factory::Remove() once the ClientContext goes away.
569
  RefPtr<ClientAction> setupAction = new SetupAction();
570
  RefPtr<ClientContext> ref =
571
    ClientContext::Create(this, quota::Client::BACKGROUNDSYNC,
572
                          NS_LITERAL_STRING("backgroundsync"),
573
                          mIOThread, setupAction, oldContext);
574
  mContext = ref;
575
}
576
577
void
578
StorageManager::Abort()
579
{
580
  NS_ASSERT_OWNINGTHREAD(StorageManager);
581
  MOZ_ASSERT(mContext);
582
583
  // Note that we are closing to prevent any new requests from coming in and
584
  // creating a new ClientContext. We must ensure all Contexts and IO
585
  // operations are complete before shutdown proceeds.
586
  NoteClosing();
587
588
  // Cancel and only note that we are done after the context is cleaned up.
589
  RefPtr<ClientContext> context = mContext;
590
  context->CancelAll();
591
}
592
593
void
594
StorageManager::Shutdown()
595
{
596
  NS_ASSERT_OWNINGTHREAD(StorageManager);
597
598
  // Ignore duplicate attempts to shutdown. This can occur when we start a
599
  // browser initiated shutdown and then run ~StorageManager() which also
600
  // calls Shutdown().
601
  if (mShuttingDown) {
602
    return;
603
  }
604
605
  mShuttingDown = true;
606
607
  // Note that we are closing to prevent any new requests from coming in and
608
  // creating a new ClientContext. We must ensure all Contexts and IO
609
  // operations are complete before shutdown proceeds.
610
  NoteClosing();
611
612
  // If there is a context, then cancel and only note that we are done after
613
  // its cleaned up.
614
  if (mContext) {
615
    RefPtr<ClientContext> context = mContext;
616
    context->CancelAll();
617
  }
618
}
619
620
void
621
StorageManager::NoteClosing()
622
{
623
  NS_ASSERT_OWNINGTHREAD(StorageManager);
624
625
  // This can be called more than once legitimately through different paths.
626
  mState = Closing;
627
}
628
629
void
630
StorageManager::RemoveClientContext(ClientContext* aContext)
631
{
632
  NS_ASSERT_OWNINGTHREAD(StorageManager);
633
  MOZ_ASSERT(mContext);
634
  MOZ_ASSERT(mContext == aContext);
635
636
  // Wether the ClientContext destruction was triggered from the StorageManager
637
  // going idle or the underlying storage being invalidated, we should know we
638
  // are closing before the ClientContext is destroyed.
639
  MOZ_ASSERT(mState == Closing);
640
641
  mContext = nullptr;
642
643
  // Once the context is gone, we can immediately remove ourself from the
644
  // Factory list. We don't need to block shutdown by stayin in the list
645
  // any more.
646
  Factory::Remove(this);
647
}
648
649
already_AddRefed<nsIPrincipal>
650
StorageManager::GetPrincipal() const
651
{
652
  MOZ_ASSERT(NS_IsMainThread());
653
654
  nsCOMPtr<nsIPrincipal> ref = mManagerId->Principal();
655
  return ref.forget();
656
}
657
658
void
659
StorageManager::MaybeAllowContextToClose()
660
{
661
  NS_ASSERT_OWNINGTHREAD(StorageManager);
662
  // If we have an active context, but we have no more pending requests,
663
  // then let it shut itself down. We must wait for all possible users
664
  // of state information to complete before doing this.
665
  RefPtr<ClientContext> context = mContext;
666
  if (context && mPendingRequests.IsEmpty()) {
667
    // Mark the StorageManager as invalid so that it won't get used again.
668
    NoteClosing();
669
670
    context->AllowToClose();
671
  }
672
}
673
674
// Common to DOM and internal requests.
675
void
676
StorageManager::ExecuteRequest(const nsID& aRequestId, ClientAction* aAction)
677
{
678
  NS_ASSERT_OWNINGTHREAD(StorageManager);
679
  MOZ_ASSERT(mContext);
680
  MOZ_ASSERT(aAction);
681
682
  mPendingRequests.AppendElement(aRequestId);
683
684
  if (NS_WARN_IF(mState == Closing)) {
685
    OnRequestComplete(aRequestId,
686
                      SyncOpError(static_cast<uint32_t>(NS_ERROR_ABORT)));
687
    return;
688
  }
689
690
  RefPtr<ClientContext> context = mContext;
691
  MOZ_ASSERT(!context->IsCanceled());
692
693
  context->Dispatch(aAction);
694
}
695
696
// DOM request.
697
void
698
StorageManager::ExecuteRequest(const nsID& aRequestId, const SyncOp& aOp)
699
{
700
  RefPtr<ClientAction> action;
701
702
  switch(aOp.mArgs().type()) {
703
    case SyncOpArgs::TSyncRegisterArgs:
704
    {
705
      action = new RegisterAction(aRequestId, this,
706
                                  aOp.mArgs().get_SyncRegisterArgs());
707
      break;
708
    }
709
    case SyncOpArgs::TSyncGetTagsArgs:
710
    {
711
      action = new GetTagsAction(aRequestId, this,
712
                                 aOp.mArgs().get_SyncGetTagsArgs());
713
      break;
714
    }
715
    default:
716
    {
717
      MOZ_CRASH("Unknown BackgroundSync request");
718
    }
719
  }
720
721
  ExecuteRequest(aRequestId, action);
722
}
723
724
// Internal request.
725
void
726
StorageManager::ExecuteRequest(const nsID& aRequestId, const SyncInternalOp& aOp)
727
{
728
  RefPtr<ClientAction> action;
729
730
  switch(aOp.mArgs().type()) {
731
    case SyncInternalOpArgs::TSyncGetAllArgs:
732
    {
733
      action = new GetAllAction(aRequestId, this);
734
      break;
735
    }
736
    case SyncInternalOpArgs::TSyncChangeStateArgs:
737
    {
738
      action = new ChangeStateAction(aRequestId, this,
739
                                     aOp.mArgs().get_SyncChangeStateArgs());
740
      break;
741
    }
742
    case SyncInternalOpArgs::TSyncRemoveArgs:
743
    {
744
      action = new RemoveAction(aRequestId, this,
745
                                aOp.mArgs().get_SyncRemoveArgs());
746
      break;
747
    }
748
    default:
749
    {
750
      MOZ_CRASH("Unknown BackgroundSync internal request");
751
    }
752
  }
753
754
  ExecuteRequest(aRequestId, action);
755
}
756
757
// Common to DOM and internal responses.
758
void
759
StorageManager::OnRequestComplete(const nsID& aRequestId)
760
{
761
  NS_ASSERT_OWNINGTHREAD(StorageManager);
762
  MOZ_ASSERT(mPendingRequests.Contains(aRequestId));
763
764
  mPendingRequests.RemoveElement(aRequestId);
765
766
  MaybeAllowContextToClose();
767
}
768
769
template<typename T>
770
void
771
StorageManager::OnRequestComplete(const nsID& aRequestId, const T& aResponse)
772
{
773
  // XXX Notify listener
774
775
  OnRequestComplete(aRequestId);
776
}
777
778
} // namespace backgroundsync
779
} // namespace dom
780
} // namespace mozilla
(-)a/dom/backgroundsync/StorageManager.h (+116 lines)
Line     Link Here 
Line 0    Link Here 
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=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 file,
5
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#ifndef mozilla_dom_StorageManager_h
8
#define mozilla_dom_StorageManager_h
9
10
#include "mozilla/dom/quota/shared/ClientContext.h"
11
12
namespace mozilla {
13
namespace dom {
14
namespace backgroundsync {
15
16
using quota::shared::ClientContext;
17
18
/**
19
 * The StorageManager class is responsible for managing the storage of sync
20
 * requests. The DOM objects and IPC actors are basically just plumbing to
21
 * get the request to the right StorageManager object running in the parent
22
 * process.
23
 *
24
 * There should be exactly one StorageManager object for each origin or app
25
 * using the BackgroundSync API. This uniqueness is defined by the
26
 * StorageManagerId equality operator. The uniqueness is enforced by the
27
 * Manager GetOrCreate() factory method.
28
 *
29
 * The StorageManager instances are kept alive by the BackgroundSyncService,
30
 * which keeps a reference to the StorageManager dealing with a storage request
31
 * until that request is completed or the actor requesting it is destroyed.
32
 */
33
34
class StorageManager final : public ClientContext::Listener
35
{
36
public:
37
  NS_INLINE_DECL_REFCOUNTING(StorageManager, override)
38
39
  static nsresult GetOrCreate(StorageManagerId* aManagerId,
40
                              StorageManager** aManagerOut);
41
42
  enum State
43
  {
44
    Open,
45
    Closing
46
  };
47
48
  State GetState() const
49
  {
50
    return mState;
51
  }
52
53
  already_AddRefed<StorageManagerId> GetManagerId() const
54
  {
55
    RefPtr<StorageManagerId> ref = mManagerId;
56
    return ref.forget();
57
  }
58
59
  // Synchronously shutdown.  This spins the event loop.
60
  static void ShutdownAll();
61
62
  // Cancel actions for given origin or all actions if passed string is null.
63
  static void Abort(const nsACString& aOrigin);
64
65
  void ExecuteRequest(const nsID& aRequestId, const SyncOp& aOp);
66
67
  // quota::ClientContext::Listener
68
  virtual void NoteClosing() override;
69
  virtual void RemoveClientContext(ClientContext* aContext) override;
70
  virtual already_AddRefed<nsIPrincipal> GetPrincipal() const override;
71
72
private:
73
  class BaseAction;
74
  class ChangeStateAction;
75
  class Factory;
76
  class GetAllAction;
77
  class GetTagsAction;
78
  class RegisterAction;
79
  class RemoveAction;
80
81
  StorageManager(StorageManagerId* aManagerId,
82
                 nsIThread* aIOThread);
83
  ~StorageManager();
84
85
  void Init(StorageManager* aOldManager);
86
  void Abort();
87
  void Shutdown();
88
89
  void MaybeAllowContextToClose();
90
91
  void OnRequestComplete(const nsID& aRequestId);
92
  template<typename T>
93
  void OnRequestComplete(const nsID& aRequestId, const T& aResponse);
94
95
  void ExecuteRequest(const nsID& aRequestId, ClientAction* aAction);
96
  void ExecuteRequest(const nsID& aRequestId, const SyncInternalOp& aOp);
97
98
  RefPtr<StorageManagerId> mManagerId;
99
  nsCOMPtr<nsIThread> mIOThread;
100
101
  // Weak reference cleared by RemoveClientContext() in ClientContext
102
  // destructor.
103
  ClientContext* MOZ_NON_OWNING_REF mContext;
104
105
  bool mShuttingDown;
106
  State mState;
107
108
  // Keep a list of the request IDs coming from BackgroundSyncService.
109
  nsTArray<nsID> mPendingRequests;
110
};
111
112
} // namespace backgroundsync
113
} // namespace dom
114
} // namespace mozilla
115
116
#endif // mozilla_dom_StorageManager_h
(-)a/dom/backgroundsync/StorageManagerId.cpp (+167 lines)
Line     Link Here 
Line 0    Link Here 
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=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/. */
6
7
#include "StorageManagerId.h"
8
9
#include "mozilla/ipc/BackgroundParent.h"
10
#include "mozilla/dom/quota/QuotaManager.h"
11
12
namespace mozilla {
13
namespace dom {
14
namespace backgroundsync {
15
16
/**
17
 * StorageManagerIdFactory
18
 */
19
20
// static
21
already_AddRefed<StorageManagerIdFactory>
22
StorageManagerIdFactory::Create(Listener* aListener,
23
                                const PrincipalInfo& aPrincipalInfo)
24
{
25
  AssertIsOnBackgroundThread();
26
27
  RefPtr<StorageManagerIdFactory> factory =
28
    new StorageManagerIdFactory(aListener, aPrincipalInfo);
29
30
  MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(NewRunnableMethod(factory,
31
                                              &StorageManagerIdFactory::Run)));
32
33
  return factory.forget();
34
}
35
36
StorageManagerIdFactory::StorageManagerIdFactory(
37
    Listener* aListener, const PrincipalInfo& aPrincipalInfo)
38
  : mPrincipalInfo(aPrincipalInfo)
39
  , mInitiatingThread(NS_GetCurrentThread())
40
{
41
  AssertIsOnBackgroundThread();
42
  MOZ_ASSERT(mInitiatingThread);
43
  MOZ_ASSERT(aListener);
44
45
  mListenerList.AppendElement(aListener);
46
}
47
48
StorageManagerIdFactory::~StorageManagerIdFactory()
49
{
50
  // Since this is a Runnable that executes on multiple threads, its a race
51
  // to see which thread de-refs us last. Therefore we cannot guarantee which
52
  // thread we destruct on.
53
54
  MOZ_ASSERT(mListenerList.IsEmpty());
55
}
56
57
void
58
StorageManagerIdFactory::Run()
59
{
60
  // Execute twice. First on the main thread and then back on the originating
61
  // thread.
62
63
  if (mManagerId) {
64
    AssertIsOnBackgroundThread();
65
66
    ListenerList::ForwardIterator iter(mListenerList);
67
    while (iter.HasMore()) {
68
      iter.GetNext()->OnStorageManagerIdCreated(mManagerId);
69
    }
70
71
    // The listener must clear its reference in
72
    // OnStorageManagerIdCreated().
73
    MOZ_ASSERT(mListenerList.IsEmpty());
74
75
    return;
76
  }
77
78
  AssertIsOnMainThread();
79
80
  nsresult rv;
81
  RefPtr<nsIPrincipal> principal =
82
    PrincipalInfoToPrincipal(mPrincipalInfo, &rv);
83
  if (NS_WARN_IF(NS_FAILED(rv))) {
84
    return;
85
  }
86
87
  rv = StorageManagerId::Create(principal, getter_AddRefs(mManagerId));
88
  if (NS_WARN_IF(NS_FAILED(rv))) {
89
    return;
90
  }
91
92
  MOZ_ALWAYS_SUCCEEDS(mInitiatingThread->Dispatch(
93
        NewRunnableMethod(this, &StorageManagerIdFactory::Run),
94
        NS_DISPATCH_NORMAL));
95
}
96
97
void
98
StorageManagerIdFactory::RemoveListener(Listener* aListener)
99
{
100
  AssertIsOnBackgroundThread();
101
  MOZ_ASSERT(aListener);
102
103
  MOZ_ALWAYS_TRUE(mListenerList.RemoveElement(aListener));
104
}
105
106
/**
107
 * StorageManagerId
108
 */
109
110
// static
111
nsresult
112
StorageManagerId::Create(nsIPrincipal* aPrincipal,
113
                         StorageManagerId** aManagerIdOut)
114
{
115
  MOZ_ASSERT(NS_IsMainThread());
116
117
  // The QuotaManager::GetInfoFromPrincipal() has special logic for system
118
  // and about: principals.  We need to use the same modified origin in
119
  // order to interpret calls from QM correctly.
120
  nsCString quotaOrigin;
121
  nsresult rv = quota::QuotaManager::GetInfoFromPrincipal(aPrincipal,
122
                                                          nullptr,   // suffix
123
                                                          nullptr,   //group
124
                                                          &quotaOrigin,
125
                                                          nullptr);  // is app
126
  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
127
128
  RefPtr<StorageManagerId> ref =
129
    new StorageManagerId(aPrincipal, quotaOrigin);
130
  ref.forget(aManagerIdOut);
131
132
  return NS_OK;
133
}
134
135
already_AddRefed<nsIPrincipal>
136
StorageManagerId::Principal() const
137
{
138
  MOZ_ASSERT(NS_IsMainThread());
139
  nsCOMPtr<nsIPrincipal> ref = mPrincipal;
140
  return ref.forget();
141
}
142
143
StorageManagerId::StorageManagerId(nsIPrincipal* aPrincipal,
144
                                   const nsACString& aQuotaOrigin)
145
    : mPrincipal(aPrincipal)
146
    , mQuotaOrigin(aQuotaOrigin)
147
{
148
  MOZ_ASSERT(mPrincipal);
149
}
150
151
StorageManagerId::~StorageManagerId()
152
{
153
  // If we're already on the main thread, then default destruction is fine
154
  if (NS_IsMainThread()) {
155
    return;
156
  }
157
158
  // Otherwise we need to proxy to main thread to do the release
159
160
  // The PBackground worker thread shouldn't be running after the main thread
161
  // is stopped.  So main thread is guaranteed to exist here.
162
  NS_ReleaseOnMainThread(mPrincipal.forget());
163
}
164
165
} // namespace backgroundsync
166
} // namespace dom
167
} // namespace mozilla
(-)a/dom/backgroundsync/StorageManagerId.h (+95 lines)
Line     Link Here 
Line 0    Link Here 
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=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 file,
5
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#ifndef mozilla_dom_StorageManagerId_h
8
#define mozilla_dom_StorageManagerId_h
9
10
namespace mozilla {
11
namespace dom {
12
namespace backgroundsync {
13
14
using mozilla::ipc::PrincipalInfo;
15
16
class StorageManagerId final
17
{
18
public:
19
  // Main thread only.
20
  static nsresult Create(nsIPrincipal* aPrincipal,
21
                         StorageManagerId** aManagerIdOut);
22
23
  // Main thread only.
24
  already_AddRefed<nsIPrincipal> Principal() const;
25
26
  const nsACString& QuotaOrigin() const { return mQuotaOrigin; }
27
28
  bool operator==(const StorageManagerId& aOther) const
29
  {
30
    return mQuotaOrigin == aOther.mQuotaOrigin;
31
  }
32
33
private:
34
  StorageManagerId(nsIPrincipal* aPrincipal, const nsACString& aOrigin);
35
  ~StorageManagerId();
36
37
  StorageManagerId(const StorageManagerId&) = delete;
38
  StorageManagerId& operator=(const StorageManagerId&) = delete;
39
40
  // Only accessible on main thread.
41
  nsCOMPtr<nsIPrincipal> mPrincipal;
42
43
  // Immutable to allow threadsafe access.
44
  const nsCString mQuotaOrigin;
45
46
public:
47
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(StorageManagerId)
48
};
49
50
class StorageManagerIdFactory
51
{
52
public:
53
  // An interface to be implemented by code wishing to use the
54
  // StorageManagerIdFactory.
55
  // Note, the Listener implementation is responsible for calling
56
  // RemoveListener() on the StorageManagerIdFactory to clear the weak
57
  // reference.
58
  class Listener
59
  {
60
  public:
61
    virtual void OnStorageManagerIdCreated(StorageManagerId* aManagerId) = 0;
62
  };
63
64
  static already_AddRefed<StorageManagerIdFactory>
65
  Create(Listener* aListener, const PrincipalInfo& aPrincipalInfo);
66
67
  // The Listener must call RemoveListener() when
68
  // OnStorageManagerIdCreated is called or when
69
  // the Listener is destroyed.
70
  void RemoveListener(Listener* aListener);
71
72
  void Run();
73
74
private:
75
  StorageManagerIdFactory(Listener* aListener,
76
                          const PrincipalInfo& aPrincipalInfo);
77
  virtual ~StorageManagerIdFactory();
78
79
  // Weak reference cleared by RemoveListener().
80
  typedef nsTObserverArray<Listener*> ListenerList;
81
  ListenerList mListenerList;
82
83
  const PrincipalInfo mPrincipalInfo;
84
  RefPtr<nsIThread> mInitiatingThread;
85
  RefPtr<StorageManagerId> mManagerId;
86
87
public:
88
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(StorageManagerIdFactory)
89
};
90
91
} // namespace backgroundsync
92
} // namespace dom
93
} // namespace mozilla
94
95
#endif // mozilla_dom_StorageManagerId_h
(-)a/dom/backgroundsync/moz.build (-2 / +11 lines)
Line     Link Here 
 Lines 1-21    Link Here 
1
# vim: set filetype=python:
1
# vim: set filetype=python:
2
# This Source Code Form is subject to the terms of the Mozilla Public
2
# This Source Code Form is subject to the terms of the Mozilla Public
3
# License, v. 2.0. If a copy of the MPL was not distributed with this
3
# License, v. 2.0. If a copy of the MPL was not distributed with this
4
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
5
6
EXPORTS.mozilla.dom.backgroundsync += [
6
EXPORTS.mozilla.dom.backgroundsync += [
7
    'BackgroundSync.h'
7
    'BackgroundSync.h',
8
    'BackgroundSyncTypes.h',
9
    'QuotaClient.h'
8
]
10
]
9
11
10
UNIFIED_SOURCES += [
12
UNIFIED_SOURCES += [
11
    'BackgroundSync.cpp',
13
    'BackgroundSync.cpp',
12
    'BackgroundSyncChild.cpp',
14
    'BackgroundSyncChild.cpp',
13
    'BackgroundSyncParent.cpp'
15
    'BackgroundSyncParent.cpp',
16
    'ChromeDBSchema.cpp',
17
    'ChromeStorageManager.cpp',
18
    'DBAction.cpp',
19
    'DBSchema.cpp',
20
    'QuotaClient.cpp',
21
    'StorageManager.cpp',
22
    'StorageManagerId.cpp'
14
]
23
]
15
24
16
IPDL_SOURCES += [
25
IPDL_SOURCES += [
17
    'BackgroundSyncIPCTypes.ipdlh',
26
    'BackgroundSyncIPCTypes.ipdlh',
18
    'PBackgroundSync.ipdl'
27
    'PBackgroundSync.ipdl'
19
]
28
]
20
29
21
LOCAL_INCLUDES += [
30
LOCAL_INCLUDES += [
(-)a/dom/quota/ActorsParent.cpp (-1 / +4 lines)
Line     Link Here 
 Lines 25-40    Link Here 
25
25
26
#include <algorithm>
26
#include <algorithm>
27
#include "GeckoProfiler.h"
27
#include "GeckoProfiler.h"
28
#include "mozilla/Atomics.h"
28
#include "mozilla/Atomics.h"
29
#include "mozilla/BasePrincipal.h"
29
#include "mozilla/BasePrincipal.h"
30
#include "mozilla/CondVar.h"
30
#include "mozilla/CondVar.h"
31
#include "mozilla/dom/PContent.h"
31
#include "mozilla/dom/PContent.h"
32
#include "mozilla/dom/asmjscache/AsmJSCache.h"
32
#include "mozilla/dom/asmjscache/AsmJSCache.h"
33
#include "mozilla/dom/backgroundsync/QuotaClient.h"
33
#include "mozilla/dom/cache/QuotaClient.h"
34
#include "mozilla/dom/cache/QuotaClient.h"
34
#include "mozilla/dom/indexedDB/ActorsParent.h"
35
#include "mozilla/dom/indexedDB/ActorsParent.h"
35
#include "mozilla/dom/quota/PQuotaParent.h"
36
#include "mozilla/dom/quota/PQuotaParent.h"
36
#include "mozilla/dom/quota/PQuotaRequestParent.h"
37
#include "mozilla/dom/quota/PQuotaRequestParent.h"
37
#include "mozilla/dom/quota/PQuotaUsageRequestParent.h"
38
#include "mozilla/dom/quota/PQuotaUsageRequestParent.h"
38
#include "mozilla/ipc/BackgroundParent.h"
39
#include "mozilla/ipc/BackgroundParent.h"
39
#include "mozilla/ipc/BackgroundUtils.h"
40
#include "mozilla/ipc/BackgroundUtils.h"
40
#include "mozilla/IntegerRange.h"
41
#include "mozilla/IntegerRange.h"
 Lines 3173-3197   QuotaManager::Init(const nsAString& aBas Link Here 
3173
  // Make a timer here to avoid potential failures later. We don't actually
3174
  // Make a timer here to avoid potential failures later. We don't actually
3174
  // initialize the timer until shutdown.
3175
  // initialize the timer until shutdown.
3175
  mShutdownTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
3176
  mShutdownTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
3176
  if (NS_WARN_IF(!mShutdownTimer)) {
3177
  if (NS_WARN_IF(!mShutdownTimer)) {
3177
    return NS_ERROR_FAILURE;
3178
    return NS_ERROR_FAILURE;
3178
  }
3179
  }
3179
3180
3180
  static_assert(Client::IDB == 0 && Client::ASMJS == 1 && Client::DOMCACHE == 2 &&
3181
  static_assert(Client::IDB == 0 && Client::ASMJS == 1 && Client::DOMCACHE == 2 &&
3181
                Client::TYPE_MAX == 3, "Fix the registration!");
3182
                Client::BACKGROUNDSYNC == 3 && Client::TYPE_MAX == 4,
3183
                "Fix the registration!");
3182
3184
3183
  MOZ_ASSERT(mClients.Capacity() == Client::TYPE_MAX,
3185
  MOZ_ASSERT(mClients.Capacity() == Client::TYPE_MAX,
3184
             "Should be using an auto array with correct capacity!");
3186
             "Should be using an auto array with correct capacity!");
3185
3187
3186
  // Register clients.
3188
  // Register clients.
3187
  mClients.AppendElement(indexedDB::CreateQuotaClient());
3189
  mClients.AppendElement(indexedDB::CreateQuotaClient());
3188
  mClients.AppendElement(asmjscache::CreateClient());
3190
  mClients.AppendElement(asmjscache::CreateClient());
3189
  mClients.AppendElement(cache::CreateQuotaClient());
3191
  mClients.AppendElement(cache::CreateQuotaClient());
3192
  mClients.AppendElement(backgroundsync::CreateQuotaClient());
3190
3193
3191
  return NS_OK;
3194
  return NS_OK;
3192
}
3195
}
3193
3196
3194
void
3197
void
3195
QuotaManager::Shutdown()
3198
QuotaManager::Shutdown()
3196
{
3199
{
3197
  AssertIsOnOwningThread();
3200
  AssertIsOnOwningThread();
(-)a/dom/quota/Client.h (+9 lines)
Line     Link Here 
 Lines 13-28    Link Here 
13
13
14
#include "PersistenceType.h"
14
#include "PersistenceType.h"
15
15
16
class nsIRunnable;
16
class nsIRunnable;
17
17
18
#define IDB_DIRECTORY_NAME "idb"
18
#define IDB_DIRECTORY_NAME "idb"
19
#define ASMJSCACHE_DIRECTORY_NAME "asmjs"
19
#define ASMJSCACHE_DIRECTORY_NAME "asmjs"
20
#define DOMCACHE_DIRECTORY_NAME "cache"
20
#define DOMCACHE_DIRECTORY_NAME "cache"
21
#define BACKGROUNDSYNC_DIRECTORY_NAME "backgroundsync"
21
22
22
BEGIN_QUOTA_NAMESPACE
23
BEGIN_QUOTA_NAMESPACE
23
24
24
class QuotaManager;
25
class QuotaManager;
25
class UsageInfo;
26
class UsageInfo;
26
27
27
// An abstract interface for quota manager clients.
28
// An abstract interface for quota manager clients.
28
// Each storage API must provide an implementation of this interface in order
29
// Each storage API must provide an implementation of this interface in order
 Lines 37-52   public: Link Here 
37
  Release() = 0;
38
  Release() = 0;
38
39
39
  enum Type {
40
  enum Type {
40
    IDB = 0,
41
    IDB = 0,
41
    //LS,
42
    //LS,
42
    //APPCACHE,
43
    //APPCACHE,
43
    ASMJS,
44
    ASMJS,
44
    DOMCACHE,
45
    DOMCACHE,
46
    BACKGROUNDSYNC,
45
    TYPE_MAX
47
    TYPE_MAX
46
  };
48
  };
47
49
48
  virtual Type
50
  virtual Type
49
  GetType() = 0;
51
  GetType() = 0;
50
52
51
  static nsresult
53
  static nsresult
52
  TypeToText(Type aType, nsAString& aText)
54
  TypeToText(Type aType, nsAString& aText)
 Lines 59-74   public: Link Here 
59
      case ASMJS:
61
      case ASMJS:
60
        aText.AssignLiteral(ASMJSCACHE_DIRECTORY_NAME);
62
        aText.AssignLiteral(ASMJSCACHE_DIRECTORY_NAME);
61
        break;
63
        break;
62
64
63
      case DOMCACHE:
65
      case DOMCACHE:
64
        aText.AssignLiteral(DOMCACHE_DIRECTORY_NAME);
66
        aText.AssignLiteral(DOMCACHE_DIRECTORY_NAME);
65
        break;
67
        break;
66
68
69
      case BACKGROUNDSYNC:
70
        aText.AssignLiteral(BACKGROUNDSYNC_DIRECTORY_NAME);
71
        break;
72
67
      case TYPE_MAX:
73
      case TYPE_MAX:
68
      default:
74
      default:
69
        NS_NOTREACHED("Bad id value!");
75
        NS_NOTREACHED("Bad id value!");
70
        return NS_ERROR_UNEXPECTED;
76
        return NS_ERROR_UNEXPECTED;
71
    }
77
    }
72
78
73
    return NS_OK;
79
    return NS_OK;
74
  }
80
  }
 Lines 80-95   public: Link Here 
80
      aType = IDB;
86
      aType = IDB;
81
    }
87
    }
82
    else if (aText.EqualsLiteral(ASMJSCACHE_DIRECTORY_NAME)) {
88
    else if (aText.EqualsLiteral(ASMJSCACHE_DIRECTORY_NAME)) {
83
      aType = ASMJS;
89
      aType = ASMJS;
84
    }
90
    }
85
    else if (aText.EqualsLiteral(DOMCACHE_DIRECTORY_NAME)) {
91
    else if (aText.EqualsLiteral(DOMCACHE_DIRECTORY_NAME)) {
86
      aType = DOMCACHE;
92
      aType = DOMCACHE;
87
    }
93
    }
94
    else if (aText.EqualsLiteral(BACKGROUNDSYNC_DIRECTORY_NAME)) {
95
      aType = BACKGROUNDSYNC;
96
    }
88
    else {
97
    else {
89
      return NS_ERROR_FAILURE;
98
      return NS_ERROR_FAILURE;
90
    }
99
    }
91
100
92
    return NS_OK;
101
    return NS_OK;
93
  }
102
  }
94
103
95
  // Methods which are called on the IO thred.
104
  // Methods which are called on the IO thred.
(-)a/ipc/glue/BackgroundChildImpl.cpp (-2 / +2 lines)
Line     Link Here 
 Lines 500-517   BackgroundChildImpl::DeallocPGamepadTest Link Here 
500
  delete static_cast<dom::GamepadTestChannelChild*>(aActor);
500
  delete static_cast<dom::GamepadTestChannelChild*>(aActor);
501
  return true;
501
  return true;
502
}
502
}
503
503
504
// -----------------------------------------------------------------------------
504
// -----------------------------------------------------------------------------
505
// Background Sync API
505
// Background Sync API
506
// -----------------------------------------------------------------------------
506
// -----------------------------------------------------------------------------
507
507
508
dom::PBackgroundSyncChild*
508
dom::backgroundsync::PBackgroundSyncChild*
509
BackgroundChildImpl::AllocPBackgroundSyncChild()
509
BackgroundChildImpl::AllocPBackgroundSyncChild(const PrincipalInfo&)
510
{
510
{
511
  RefPtr<BackgroundSyncChild> agent = new BackgroundSyncChild();
511
  RefPtr<BackgroundSyncChild> agent = new BackgroundSyncChild();
512
  return agent.forget().take();
512
  return agent.forget().take();
513
}
513
}
514
514
515
bool
515
bool
516
BackgroundChildImpl::DeallocPBackgroundSyncChild(PBackgroundSyncChild* aActor)
516
BackgroundChildImpl::DeallocPBackgroundSyncChild(PBackgroundSyncChild* aActor)
517
{
517
{
(-)a/ipc/glue/BackgroundChildImpl.h (-1 / +1 lines)
Line     Link Here 
 Lines 175-191   protected: Link Here 
175
175
176
  virtual PGamepadTestChannelChild*
176
  virtual PGamepadTestChannelChild*
177
  AllocPGamepadTestChannelChild() override;
177
  AllocPGamepadTestChannelChild() override;
178
178
179
  virtual bool
179
  virtual bool
180
  DeallocPGamepadTestChannelChild(PGamepadTestChannelChild* aActor) override;
180
  DeallocPGamepadTestChannelChild(PGamepadTestChannelChild* aActor) override;
181
181
182
  virtual PBackgroundSyncChild*
182
  virtual PBackgroundSyncChild*
183
  AllocPBackgroundSyncChild() override;
183
  AllocPBackgroundSyncChild(const PrincipalInfo& aPrincipalInfo) override;
184
184
185
  virtual bool
185
  virtual bool
186
  DeallocPBackgroundSyncChild(PBackgroundSyncChild* aActor) override;
186
  DeallocPBackgroundSyncChild(PBackgroundSyncChild* aActor) override;
187
};
187
};
188
188
189
class BackgroundChildImpl::ThreadLocal final
189
class BackgroundChildImpl::ThreadLocal final
190
{
190
{
191
  friend class nsAutoPtr<ThreadLocal>;
191
  friend class nsAutoPtr<ThreadLocal>;
(-)a/ipc/glue/BackgroundParentImpl.cpp (-4 / +10 lines)
Line     Link Here 
 Lines 935-967   bool Link Here 
935
BackgroundParentImpl::DeallocPGamepadTestChannelParent(dom::PGamepadTestChannelParent *aActor)
935
BackgroundParentImpl::DeallocPGamepadTestChannelParent(dom::PGamepadTestChannelParent *aActor)
936
{
936
{
937
  MOZ_ASSERT(aActor);
937
  MOZ_ASSERT(aActor);
938
  RefPtr<dom::GamepadTestChannelParent> parent =
938
  RefPtr<dom::GamepadTestChannelParent> parent =
939
    dont_AddRef(static_cast<dom::GamepadTestChannelParent*>(aActor));
939
    dont_AddRef(static_cast<dom::GamepadTestChannelParent*>(aActor));
940
  return true;
940
  return true;
941
}
941
}
942
942
943
mozilla::dom::PBackgroundSyncParent*
943
mozilla::dom::backgroundsync::PBackgroundSyncParent*
944
BackgroundParentImpl::AllocPBackgroundSyncParent()
944
BackgroundParentImpl::AllocPBackgroundSyncParent(
945
    const PrincipalInfo& aPrincipalInfo)
945
{
946
{
946
  AssertIsInMainProcess();
947
  AssertIsInMainProcess();
947
  AssertIsOnBackgroundThread();
948
  AssertIsOnBackgroundThread();
948
949
949
  return new BackgroundSyncParent();
950
  RefPtr<BackgroundSyncParent> agent =
951
    new BackgroundSyncParent(aPrincipalInfo);
952
  return agent.forget().take();
950
}
953
}
951
954
952
bool
955
bool
953
BackgroundParentImpl::DeallocPBackgroundSyncParent(PBackgroundSyncParent* aActor)
956
BackgroundParentImpl::DeallocPBackgroundSyncParent(PBackgroundSyncParent* aActor)
954
{
957
{
955
  AssertIsInMainProcess();
958
  AssertIsInMainProcess();
956
  AssertIsOnBackgroundThread();
959
  AssertIsOnBackgroundThread();
957
  MOZ_ASSERT(aActor);
960
  MOZ_ASSERT(aActor);
958
961
959
  delete static_cast<BackgroundSyncParent*>(aActor);
962
  RefPtr<BackgroundSyncParent> parent =
963
    dont_AddRef(static_cast<BackgroundSyncParent*>(aActor));
964
  MOZ_ASSERT(parent);
965
960
  return true;
966
  return true;
961
}
967
}
962
968
963
} // namespace ipc
969
} // namespace ipc
964
} // namespace mozilla
970
} // namespace mozilla
965
971
966
void
972
void
967
TestParent::ActorDestroy(ActorDestroyReason aWhy)
973
TestParent::ActorDestroy(ActorDestroyReason aWhy)
(-)a/ipc/glue/BackgroundParentImpl.h (-1 / +1 lines)
Line     Link Here 
 Lines 203-219   protected: Link Here 
203
203
204
  virtual PGamepadTestChannelParent*
204
  virtual PGamepadTestChannelParent*
205
  AllocPGamepadTestChannelParent() override;
205
  AllocPGamepadTestChannelParent() override;
206
206
207
  virtual bool
207
  virtual bool
208
  DeallocPGamepadTestChannelParent(PGamepadTestChannelParent* aActor) override;
208
  DeallocPGamepadTestChannelParent(PGamepadTestChannelParent* aActor) override;
209
209
210
  virtual PBackgroundSyncParent*
210
  virtual PBackgroundSyncParent*
211
  AllocPBackgroundSyncParent() override;
211
  AllocPBackgroundSyncParent(const PrincipalInfo& aPrincipalInfo) override;
212
212
213
  virtual bool
213
  virtual bool
214
  DeallocPBackgroundSyncParent(PBackgroundSyncParent* aActor) override;
214
  DeallocPBackgroundSyncParent(PBackgroundSyncParent* aActor) override;
215
};
215
};
216
216
217
} // namespace ipc
217
} // namespace ipc
218
} // namespace mozilla
218
} // namespace mozilla
219
219
(-)a/ipc/glue/PBackground.ipdl (-1 / +1 lines)
Line     Link Here 
 Lines 105-121   parent: Link Here 
105
  async PQuota();
105
  async PQuota();
106
106
107
  async PFileSystemRequest(FileSystemParams params);
107
  async PFileSystemRequest(FileSystemParams params);
108
108
109
  async PGamepadEventChannel();
109
  async PGamepadEventChannel();
110
110
111
  async PGamepadTestChannel();
111
  async PGamepadTestChannel();
112
112
113
  async PBackgroundSync();
113
  async PBackgroundSync(PrincipalInfo aPrincipalInfo);
114
114
115
child:
115
child:
116
  async PCache();
116
  async PCache();
117
  async PCacheStreamControl();
117
  async PCacheStreamControl();
118
118
119
both:
119
both:
120
  async PBlob(BlobConstructorParams params);
120
  async PBlob(BlobConstructorParams params);
121
121

Return to bug 1217544