Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/quota/QuotaManager.h
Line
Count
Source (jump to first uncovered line)
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_quota_quotamanager_h__
8
#define mozilla_dom_quota_quotamanager_h__
9
10
#include "QuotaCommon.h"
11
12
#include "mozilla/dom/Nullable.h"
13
#include "mozilla/dom/ipc/IdType.h"
14
#include "mozilla/Mutex.h"
15
16
#include "nsClassHashtable.h"
17
#include "nsRefPtrHashtable.h"
18
19
#include "Client.h"
20
#include "PersistenceType.h"
21
22
#include "prenv.h"
23
24
#define QUOTA_MANAGER_CONTRACTID "@mozilla.org/dom/quota/manager;1"
25
26
class mozIStorageConnection;
27
class nsIEventTarget;
28
class nsIPrincipal;
29
class nsIThread;
30
class nsITimer;
31
class nsIURI;
32
class nsPIDOMWindowOuter;
33
class nsIRunnable;
34
35
BEGIN_QUOTA_NAMESPACE
36
37
class DirectoryLockImpl;
38
class GroupInfo;
39
class GroupInfoPair;
40
class OriginInfo;
41
class OriginScope;
42
class QuotaObject;
43
44
class NS_NO_VTABLE RefCountedObject
45
{
46
public:
47
  NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
48
};
49
50
class DirectoryLock
51
  : public RefCountedObject
52
{
53
  friend class DirectoryLockImpl;
54
55
private:
56
  DirectoryLock()
57
0
  { }
58
59
  ~DirectoryLock()
60
0
  { }
61
};
62
63
class NS_NO_VTABLE OpenDirectoryListener
64
  : public RefCountedObject
65
{
66
public:
67
  virtual void
68
  DirectoryLockAcquired(DirectoryLock* aLock) = 0;
69
70
  virtual void
71
  DirectoryLockFailed() = 0;
72
73
protected:
74
  virtual ~OpenDirectoryListener()
75
  { }
76
};
77
78
struct OriginParams
79
{
80
  OriginParams(PersistenceType aPersistenceType,
81
               const nsACString& aOrigin)
82
  : mOrigin(aOrigin)
83
  , mPersistenceType(aPersistenceType)
84
0
  { }
85
86
  nsCString mOrigin;
87
  PersistenceType mPersistenceType;
88
};
89
90
class QuotaManager final
91
  : public BackgroundThreadObject
92
{
93
  friend class DirectoryLockImpl;
94
  friend class GroupInfo;
95
  friend class OriginInfo;
96
  friend class QuotaObject;
97
98
  typedef nsClassHashtable<nsCStringHashKey,
99
                           nsTArray<DirectoryLockImpl*>> DirectoryLockTable;
100
101
public:
102
  class CreateRunnable;
103
104
private:
105
  class ShutdownRunnable;
106
  class ShutdownObserver;
107
108
public:
109
  NS_INLINE_DECL_REFCOUNTING(QuotaManager)
110
111
  static bool IsRunningXPCShellTests()
112
0
  {
113
0
    static bool kRunningXPCShellTests = !!PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR");
114
0
    return kRunningXPCShellTests;
115
0
  }
116
117
  static const char kReplaceChars[];
118
119
  static void
120
  GetOrCreate(nsIRunnable* aCallback);
121
122
  // Returns a non-owning reference.
123
  static QuotaManager*
124
  Get();
125
126
  // Returns true if we've begun the shutdown process.
127
  static bool IsShuttingDown();
128
129
  bool
130
  IsOriginInitialized(const nsACString& aOrigin) const
131
0
  {
132
0
    AssertIsOnIOThread();
133
0
134
0
    return mInitializedOrigins.Contains(aOrigin);
135
0
  }
136
137
  bool
138
  IsTemporaryStorageInitialized() const
139
0
  {
140
0
    AssertIsOnIOThread();
141
0
142
0
    return mTemporaryStorageInitialized;
143
0
  }
144
145
  void
146
  InitQuotaForOrigin(PersistenceType aPersistenceType,
147
                     const nsACString& aGroup,
148
                     const nsACString& aOrigin,
149
                     uint64_t aUsageBytes,
150
                     int64_t aAccessTime,
151
                     bool aPersisted);
152
153
  void
154
  DecreaseUsageForOrigin(PersistenceType aPersistenceType,
155
                         const nsACString& aGroup,
156
                         const nsACString& aOrigin,
157
                         int64_t aSize);
158
159
  void
160
  UpdateOriginAccessTime(PersistenceType aPersistenceType,
161
                         const nsACString& aGroup,
162
                         const nsACString& aOrigin);
163
164
  void
165
  RemoveQuota();
166
167
  void
168
  RemoveQuotaForOrigin(PersistenceType aPersistenceType,
169
                       const nsACString& aGroup,
170
                       const nsACString& aOrigin)
171
0
  {
172
0
    MutexAutoLock lock(mQuotaMutex);
173
0
    LockedRemoveQuotaForOrigin(aPersistenceType, aGroup, aOrigin);
174
0
  }
175
176
  already_AddRefed<QuotaObject>
177
  GetQuotaObject(PersistenceType aPersistenceType,
178
                 const nsACString& aGroup,
179
                 const nsACString& aOrigin,
180
                 nsIFile* aFile,
181
                 int64_t* aFileSizeOut = nullptr);
182
183
  already_AddRefed<QuotaObject>
184
  GetQuotaObject(PersistenceType aPersistenceType,
185
                 const nsACString& aGroup,
186
                 const nsACString& aOrigin,
187
                 const nsAString& aPath,
188
                 int64_t* aFileSizeOut = nullptr);
189
190
  Nullable<bool>
191
  OriginPersisted(const nsACString& aGroup,
192
                  const nsACString& aOrigin);
193
194
  void
195
  PersistOrigin(const nsACString& aGroup,
196
                const nsACString& aOrigin);
197
198
  // Called when a process is being shot down. Aborts any running operations
199
  // for the given process.
200
  void
201
  AbortOperationsForProcess(ContentParentId aContentParentId);
202
203
  nsresult
204
  GetDirectoryForOrigin(PersistenceType aPersistenceType,
205
                        const nsACString& aASCIIOrigin,
206
                        nsIFile** aDirectory) const;
207
208
  nsresult
209
  RestoreDirectoryMetadata2(nsIFile* aDirectory, bool aPersistent);
210
211
  nsresult
212
  GetDirectoryMetadata2(nsIFile* aDirectory,
213
                        int64_t* aTimestamp,
214
                        bool* aPersisted,
215
                        nsACString& aSuffix,
216
                        nsACString& aGroup,
217
                        nsACString& aOrigin);
218
219
  nsresult
220
  GetDirectoryMetadata2WithRestore(nsIFile* aDirectory,
221
                                   bool aPersistent,
222
                                   int64_t* aTimestamp,
223
                                   bool* aPersisted,
224
                                   nsACString& aSuffix,
225
                                   nsACString& aGroup,
226
                                   nsACString& aOrigin);
227
228
  nsresult
229
  GetDirectoryMetadata2(nsIFile* aDirectory,
230
                        int64_t* aTimestamp,
231
                        bool* aPersisted);
232
233
  nsresult
234
  GetDirectoryMetadata2WithRestore(nsIFile* aDirectory,
235
                                   bool aPersistent,
236
                                   int64_t* aTimestamp,
237
                                   bool* aPersisted);
238
239
  // This is the main entry point into the QuotaManager API.
240
  // Any storage API implementation (quota client) that participates in
241
  // centralized quota and storage handling should call this method to get
242
  // a directory lock which will protect client's files from being deleted
243
  // while they are still in use.
244
  // After a lock is acquired, client is notified via the open listener's
245
  // method DirectoryLockAcquired. If the lock couldn't be acquired, client
246
  // gets DirectoryLockFailed notification.
247
  // A lock is a reference counted object and at the time DirectoryLockAcquired
248
  // is called, quota manager holds just one strong reference to it which is
249
  // then immediatelly cleared by quota manager. So it's up to client to add
250
  // a new reference in order to keep the lock alive.
251
  // Unlocking is simply done by dropping all references to the lock object.
252
  // In other words, protection which the lock represents dies with the lock
253
  // object itself.
254
  void
255
  OpenDirectory(PersistenceType aPersistenceType,
256
                const nsACString& aGroup,
257
                const nsACString& aOrigin,
258
                Client::Type aClientType,
259
                bool aExclusive,
260
                OpenDirectoryListener* aOpenListener);
261
262
  // XXX RemoveMe once bug 1170279 gets fixed.
263
  void
264
  OpenDirectoryInternal(const Nullable<PersistenceType>& aPersistenceType,
265
                        const OriginScope& aOriginScope,
266
                        const Nullable<Client::Type>& aClientType,
267
                        bool aExclusive,
268
                        OpenDirectoryListener* aOpenListener);
269
270
  // Collect inactive and the least recently used origins.
271
  uint64_t
272
  CollectOriginsForEviction(uint64_t aMinSizeToBeFreed,
273
                            nsTArray<RefPtr<DirectoryLockImpl>>& aLocks);
274
275
  void
276
  AssertStorageIsInitialized() const
277
#ifdef DEBUG
278
  ;
279
#else
280
0
  { }
281
#endif
282
283
  nsresult
284
  EnsureStorageIsInitialized();
285
286
  nsresult
287
  EnsureOriginIsInitialized(PersistenceType aPersistenceType,
288
                            const nsACString& aSuffix,
289
                            const nsACString& aGroup,
290
                            const nsACString& aOrigin,
291
                            nsIFile** aDirectory);
292
293
  nsresult
294
  EnsureOriginIsInitializedInternal(PersistenceType aPersistenceType,
295
                                    const nsACString& aSuffix,
296
                                    const nsACString& aGroup,
297
                                    const nsACString& aOrigin,
298
                                    nsIFile** aDirectory,
299
                                    bool* aCreated);
300
301
  nsresult
302
  EnsureTemporaryStorageIsInitialized();
303
304
  nsresult
305
  EnsureOriginDirectory(nsIFile* aDirectory,
306
                        bool* aCreated);
307
308
  void
309
  OriginClearCompleted(PersistenceType aPersistenceType,
310
                       const nsACString& aOrigin);
311
312
  void
313
  ResetOrClearCompleted();
314
315
  void
316
  StartIdleMaintenance()
317
0
  {
318
0
    AssertIsOnOwningThread();
319
0
320
0
    for (auto& client : mClients) {
321
0
      client->StartIdleMaintenance();
322
0
    }
323
0
  }
324
325
  void
326
  StopIdleMaintenance()
327
0
  {
328
0
    AssertIsOnOwningThread();
329
0
330
0
    for (auto& client : mClients) {
331
0
      client->StopIdleMaintenance();
332
0
    }
333
0
  }
334
335
  void
336
  AssertCurrentThreadOwnsQuotaMutex()
337
  {
338
    mQuotaMutex.AssertCurrentThreadOwns();
339
  }
340
341
  nsIThread*
342
  IOThread()
343
  {
344
    NS_ASSERTION(mIOThread, "This should never be null!");
345
    return mIOThread;
346
  }
347
348
  Client*
349
  GetClient(Client::Type aClientType);
350
351
  const nsString&
352
  GetBasePath() const
353
0
  {
354
0
    return mBasePath;
355
0
  }
356
357
  const nsString&
358
  GetStoragePath() const
359
0
  {
360
0
    return mStoragePath;
361
0
  }
362
363
  const nsString&
364
  GetStoragePath(PersistenceType aPersistenceType) const
365
0
  {
366
0
    if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
367
0
      return mPermanentStoragePath;
368
0
    }
369
0
370
0
    if (aPersistenceType == PERSISTENCE_TYPE_TEMPORARY) {
371
0
      return mTemporaryStoragePath;
372
0
    }
373
0
374
0
    MOZ_ASSERT(aPersistenceType == PERSISTENCE_TYPE_DEFAULT);
375
0
376
0
    return mDefaultStoragePath;
377
0
  }
378
379
  uint64_t
380
  GetGroupLimit() const;
381
382
  void
383
  GetGroupUsageAndLimit(const nsACString& aGroup,
384
                        UsageInfo* aUsageInfo);
385
386
  void
387
  NotifyStoragePressure(uint64_t aUsage);
388
389
  static void
390
  GetStorageId(PersistenceType aPersistenceType,
391
               const nsACString& aOrigin,
392
               Client::Type aClientType,
393
               nsACString& aDatabaseId);
394
395
  static nsresult
396
  GetInfoFromPrincipal(nsIPrincipal* aPrincipal,
397
                       nsACString* aSuffix,
398
                       nsACString* aGroup,
399
                       nsACString* aOrigin);
400
401
  static nsresult
402
  GetInfoFromWindow(nsPIDOMWindowOuter* aWindow,
403
                    nsACString* aSuffix,
404
                    nsACString* aGroup,
405
                    nsACString* aOrigin);
406
407
  static void
408
  GetInfoForChrome(nsACString* aSuffix,
409
                   nsACString* aGroup,
410
                   nsACString* aOrigin);
411
412
  static bool
413
  IsOriginInternal(const nsACString& aOrigin);
414
415
  static void
416
  ChromeOrigin(nsACString& aOrigin);
417
418
  static bool
419
  AreOriginsEqualOnDisk(nsACString& aOrigin1,
420
                        nsACString& aOrigin2);
421
422
private:
423
  QuotaManager();
424
425
  virtual ~QuotaManager();
426
427
  nsresult
428
  Init(const nsAString& aBaseDirPath);
429
430
  void
431
  Shutdown();
432
433
  already_AddRefed<DirectoryLockImpl>
434
  CreateDirectoryLock(const Nullable<PersistenceType>& aPersistenceType,
435
                      const nsACString& aGroup,
436
                      const OriginScope& aOriginScope,
437
                      const Nullable<Client::Type>& aClientType,
438
                      bool aExclusive,
439
                      bool aInternal,
440
                      OpenDirectoryListener* aOpenListener);
441
442
  already_AddRefed<DirectoryLockImpl>
443
  CreateDirectoryLockForEviction(PersistenceType aPersistenceType,
444
                                 const nsACString& aGroup,
445
                                 const nsACString& aOrigin);
446
447
  void
448
  RegisterDirectoryLock(DirectoryLockImpl* aLock);
449
450
  void
451
  UnregisterDirectoryLock(DirectoryLockImpl* aLock);
452
453
  void
454
  RemovePendingDirectoryLock(DirectoryLockImpl* aLock);
455
456
  uint64_t
457
  LockedCollectOriginsForEviction(
458
                                 uint64_t aMinSizeToBeFreed,
459
                                 nsTArray<RefPtr<DirectoryLockImpl>>& aLocks);
460
461
  void
462
  LockedRemoveQuotaForOrigin(PersistenceType aPersistenceType,
463
                             const nsACString& aGroup,
464
                             const nsACString& aOrigin);
465
466
  already_AddRefed<OriginInfo>
467
  LockedGetOriginInfo(PersistenceType aPersistenceType,
468
                      const nsACString& aGroup,
469
                      const nsACString& aOrigin);
470
471
  nsresult
472
  MaybeUpgradeIndexedDBDirectory();
473
474
  nsresult
475
  MaybeUpgradePersistentStorageDirectory();
476
477
  nsresult
478
  MaybeRemoveOldDirectories();
479
480
  nsresult
481
  UpgradeStorageFrom0_0To1_0(mozIStorageConnection* aConnection);
482
483
  nsresult
484
  UpgradeStorageFrom1_0To2_0(mozIStorageConnection* aConnection);
485
486
  nsresult
487
  UpgradeStorageFrom2_0To2_1(mozIStorageConnection* aConnection);
488
489
  nsresult
490
  MaybeRemoveLocalStorageData();
491
492
  nsresult
493
  MaybeRemoveLocalStorageDirectories();
494
495
  nsresult
496
  InitializeRepository(PersistenceType aPersistenceType);
497
498
  nsresult
499
  InitializeOrigin(PersistenceType aPersistenceType,
500
                   const nsACString& aGroup,
501
                   const nsACString& aOrigin,
502
                   int64_t aAccessTime,
503
                   bool aPersisted,
504
                   nsIFile* aDirectory);
505
506
  void
507
  CheckTemporaryStorageLimits();
508
509
  void
510
  DeleteFilesForOrigin(PersistenceType aPersistenceType,
511
                       const nsACString& aOrigin);
512
513
  void
514
  FinalizeOriginEviction(nsTArray<RefPtr<DirectoryLockImpl>>& aLocks);
515
516
  void
517
  ReleaseIOThreadObjects()
518
0
  {
519
0
    AssertIsOnIOThread();
520
0
521
0
    for (uint32_t index = 0; index < Client::TYPE_MAX; index++) {
522
0
      mClients[index]->ReleaseIOThreadObjects();
523
0
    }
524
0
  }
525
526
  DirectoryLockTable&
527
  GetDirectoryLockTable(PersistenceType aPersistenceType);
528
529
  bool
530
  IsSanitizedOriginValid(const nsACString& aSanitizedOrigin);
531
532
  static void
533
  ShutdownTimerCallback(nsITimer* aTimer, void* aClosure);
534
535
  mozilla::Mutex mQuotaMutex;
536
537
  nsClassHashtable<nsCStringHashKey, GroupInfoPair> mGroupInfoPairs;
538
539
  // Maintains a list of directory locks that are queued.
540
  nsTArray<RefPtr<DirectoryLockImpl>> mPendingDirectoryLocks;
541
542
  // Maintains a list of directory locks that are acquired or queued.
543
  nsTArray<DirectoryLockImpl*> mDirectoryLocks;
544
545
  // Directory lock tables that are used to update origin access time.
546
  DirectoryLockTable mTemporaryDirectoryLockTable;
547
  DirectoryLockTable mDefaultDirectoryLockTable;
548
549
  // Thread on which IO is performed.
550
  nsCOMPtr<nsIThread> mIOThread;
551
552
  // A timer that gets activated at shutdown to ensure we close all storages.
553
  nsCOMPtr<nsITimer> mShutdownTimer;
554
555
  // A list of all successfully initialized persistent origins. This list isn't
556
  // protected by any mutex but it is only ever touched on the IO thread.
557
  nsTArray<nsCString> mInitializedOrigins;
558
559
  // A hash table that is used to cache origin parser results for given
560
  // sanitized origin strings. This hash table isn't protected by any mutex but
561
  // it is only ever touched on the IO thread.
562
  nsDataHashtable<nsCStringHashKey, bool> mValidOrigins;
563
564
  // This array is populated at initialization time and then never modified, so
565
  // it can be iterated on any thread.
566
  AutoTArray<RefPtr<Client>, Client::TYPE_MAX> mClients;
567
568
  nsString mBasePath;
569
  nsString mIndexedDBPath;
570
  nsString mStoragePath;
571
  nsString mPermanentStoragePath;
572
  nsString mTemporaryStoragePath;
573
  nsString mDefaultStoragePath;
574
575
  uint64_t mTemporaryStorageLimit;
576
  uint64_t mTemporaryStorageUsage;
577
  bool mTemporaryStorageInitialized;
578
579
  bool mStorageInitialized;
580
};
581
582
END_QUOTA_NAMESPACE
583
584
#endif /* mozilla_dom_quota_quotamanager_h__ */