Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/docshell/base/BrowsingContext.cpp
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
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "BrowsingContext.h"
8
9
#include "mozilla/dom/ChromeBrowsingContext.h"
10
#include "mozilla/dom/BrowsingContextBinding.h"
11
#include "mozilla/dom/ContentChild.h"
12
#include "mozilla/Assertions.h"
13
#include "mozilla/ClearOnShutdown.h"
14
#include "mozilla/Logging.h"
15
#include "mozilla/StaticPtr.h"
16
17
#include "nsDataHashtable.h"
18
#include "nsRefPtrHashtable.h"
19
#include "nsIDocShell.h"
20
#include "nsContentUtils.h"
21
#include "nsThreadUtils.h"
22
23
namespace mozilla {
24
namespace dom {
25
26
static LazyLogModule gBrowsingContextLog("BrowsingContext");
27
28
static StaticAutoPtr<BrowsingContext::Children> sRootBrowsingContexts;
29
30
static StaticAutoPtr<nsDataHashtable<nsUint64HashKey, BrowsingContext*>>
31
  sBrowsingContexts;
32
33
// TODO(farre): This duplicates some of the work performed by the
34
// bfcache. This should be unified. [Bug 1471601]
35
static StaticAutoPtr<nsRefPtrHashtable<nsUint64HashKey, BrowsingContext>>
36
  sCachedBrowsingContexts;
37
38
/* static */ void
39
BrowsingContext::Init()
40
3
{
41
3
  if (!sRootBrowsingContexts) {
42
3
    sRootBrowsingContexts = new BrowsingContext::Children();
43
3
    ClearOnShutdown(&sRootBrowsingContexts);
44
3
  }
45
3
46
3
  if (!sBrowsingContexts) {
47
3
    sBrowsingContexts =
48
3
      new nsDataHashtable<nsUint64HashKey, BrowsingContext*>();
49
3
    ClearOnShutdown(&sBrowsingContexts);
50
3
  }
51
3
52
3
  if (!sCachedBrowsingContexts) {
53
3
    sCachedBrowsingContexts =
54
3
      new nsRefPtrHashtable<nsUint64HashKey, BrowsingContext>();
55
3
    ClearOnShutdown(&sCachedBrowsingContexts);
56
3
  }
57
3
}
58
59
/* static */ LogModule*
60
BrowsingContext::GetLog()
61
0
{
62
0
  return gBrowsingContextLog;
63
0
}
64
65
/* static */ already_AddRefed<BrowsingContext>
66
BrowsingContext::Get(uint64_t aId)
67
0
{
68
0
  RefPtr<BrowsingContext> abc = sBrowsingContexts->Get(aId);
69
0
  return abc.forget();
70
0
}
71
72
/* static */ already_AddRefed<BrowsingContext>
73
BrowsingContext::Create(nsIDocShell* aDocShell)
74
0
{
75
0
  RefPtr<BrowsingContext> context;
76
0
  if (XRE_IsParentProcess()) {
77
0
    context = new ChromeBrowsingContext(aDocShell);
78
0
  } else {
79
0
    // TODO(farre): will we ever create BrowsingContexts on processes
80
0
    // other than content and parent?
81
0
    MOZ_ASSERT(XRE_IsContentProcess());
82
0
    context = new BrowsingContext(aDocShell);
83
0
  }
84
0
85
0
  return context.forget();
86
0
}
87
88
BrowsingContext::BrowsingContext(nsIDocShell* aDocShell)
89
  : mBrowsingContextId(nsContentUtils::GenerateBrowsingContextId())
90
  , mDocShell(aDocShell)
91
0
{
92
0
  sBrowsingContexts->Put(mBrowsingContextId, this);
93
0
}
94
95
BrowsingContext::BrowsingContext(uint64_t aBrowsingContextId,
96
                const nsAString& aName)
97
  : mBrowsingContextId(aBrowsingContextId)
98
  , mName(aName)
99
0
{
100
0
  sBrowsingContexts->Put(mBrowsingContextId, this);
101
0
}
102
103
void
104
BrowsingContext::Attach(BrowsingContext* aParent)
105
0
{
106
0
  if (isInList()) {
107
0
    MOZ_LOG(GetLog(),
108
0
            LogLevel::Debug,
109
0
            ("%s: Connecting already existing 0x%08" PRIx64 " to 0x%08" PRIx64,
110
0
             XRE_IsParentProcess() ? "Parent" : "Child",
111
0
             Id(),
112
0
             aParent ? aParent->Id() : 0));
113
0
    MOZ_DIAGNOSTIC_ASSERT(sBrowsingContexts->Contains(Id()));
114
0
    MOZ_DIAGNOSTIC_ASSERT(!IsCached());
115
0
    return;
116
0
  }
117
0
118
0
  bool wasCached = sCachedBrowsingContexts->Remove(Id());
119
0
120
0
  MOZ_LOG(GetLog(),
121
0
          LogLevel::Debug,
122
0
          ("%s: %s 0x%08" PRIx64 " to 0x%08" PRIx64,
123
0
           XRE_IsParentProcess() ? "Parent" : "Child",
124
0
           wasCached ? "Re-connecting" : "Connecting",
125
0
           Id(),
126
0
           aParent ? aParent->Id() : 0));
127
0
128
0
  auto* children = aParent ? &aParent->mChildren : sRootBrowsingContexts.get();
129
0
  children->insertBack(this);
130
0
  mParent = aParent;
131
0
132
0
  if (!XRE_IsContentProcess()) {
133
0
    return;
134
0
  }
135
0
136
0
  auto cc = ContentChild::GetSingleton();
137
0
  MOZ_DIAGNOSTIC_ASSERT(cc);
138
0
  cc->SendAttachBrowsingContext(
139
0
    BrowsingContextId(mParent ? mParent->Id() : 0),
140
0
    BrowsingContextId(Id()),
141
0
    mName);
142
0
}
143
144
void
145
BrowsingContext::Detach()
146
0
{
147
0
  RefPtr<BrowsingContext> kungFuDeathGrip(this);
148
0
149
0
  if (sCachedBrowsingContexts) {
150
0
    sCachedBrowsingContexts->Remove(Id());
151
0
  }
152
0
153
0
  if (!isInList()) {
154
0
    MOZ_LOG(GetLog(),
155
0
            LogLevel::Debug,
156
0
            ("%s: Detaching already detached 0x%08" PRIx64,
157
0
             XRE_IsParentProcess() ? "Parent" : "Child",
158
0
             Id()));
159
0
    return;
160
0
  }
161
0
162
0
  MOZ_LOG(GetLog(),
163
0
          LogLevel::Debug,
164
0
          ("%s: Detaching 0x%08" PRIx64 " from 0x%08" PRIx64,
165
0
           XRE_IsParentProcess() ? "Parent" : "Child",
166
0
           Id(),
167
0
           mParent ? mParent->Id() : 0));
168
0
169
0
  remove();
170
0
171
0
  if (!XRE_IsContentProcess()) {
172
0
    return;
173
0
  }
174
0
175
0
  auto cc = ContentChild::GetSingleton();
176
0
  MOZ_DIAGNOSTIC_ASSERT(cc);
177
0
  cc->SendDetachBrowsingContext(BrowsingContextId(Id()),
178
0
                                false /* aMoveToBFCache */);
179
0
}
180
181
void
182
BrowsingContext::CacheChildren()
183
0
{
184
0
  if (mChildren.isEmpty()) {
185
0
    return;
186
0
  }
187
0
188
0
  MOZ_LOG(GetLog(),
189
0
          LogLevel::Debug,
190
0
          ("%s: Caching children of 0x%08" PRIx64 "",
191
0
           XRE_IsParentProcess() ? "Parent" : "Child",
192
0
           Id()));
193
0
194
0
  while (!mChildren.isEmpty()) {
195
0
    RefPtr<BrowsingContext> child = mChildren.popFirst();
196
0
    sCachedBrowsingContexts->Put(child->Id(), child);
197
0
  }
198
0
199
0
  if (!XRE_IsContentProcess()) {
200
0
    return;
201
0
  }
202
0
203
0
  auto cc = ContentChild::GetSingleton();
204
0
  MOZ_DIAGNOSTIC_ASSERT(cc);
205
0
  cc->SendDetachBrowsingContext(BrowsingContextId(Id()),
206
0
                                true /* aMoveToBFCache */);
207
0
}
208
209
bool
210
BrowsingContext::IsCached()
211
0
{
212
0
  return sCachedBrowsingContexts->Contains(Id());
213
0
}
214
215
void
216
BrowsingContext::GetChildren(nsTArray<RefPtr<BrowsingContext>>& aChildren)
217
0
{
218
0
  for (BrowsingContext* context : mChildren) {
219
0
    aChildren.AppendElement(context);
220
0
  }
221
0
}
222
223
/* static */ void
224
BrowsingContext::GetRootBrowsingContexts(nsTArray<RefPtr<BrowsingContext>>& aBrowsingContexts)
225
0
{
226
0
  for (BrowsingContext* context : *sRootBrowsingContexts) {
227
0
    aBrowsingContexts.AppendElement(context);
228
0
  }
229
0
}
230
231
BrowsingContext::~BrowsingContext()
232
0
{
233
0
  MOZ_DIAGNOSTIC_ASSERT(!isInList());
234
0
235
0
  if (sBrowsingContexts) {
236
0
    sBrowsingContexts->Remove(mBrowsingContextId);
237
0
  }
238
0
}
239
240
nsISupports*
241
BrowsingContext::GetParentObject() const
242
0
{
243
0
  return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
244
0
}
245
246
JSObject*
247
BrowsingContext::WrapObject(JSContext* aCx,
248
                            JS::Handle<JSObject*> aGivenProto)
249
0
{
250
0
  return BrowsingContext_Binding::Wrap(aCx, this, aGivenProto);
251
0
}
252
253
static void
254
ImplCycleCollectionUnlink(BrowsingContext::Children& aField)
255
0
{
256
0
  aField.clear();
257
0
}
258
259
static void
260
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
261
                            BrowsingContext::Children& aField,
262
                            const char* aName,
263
                            uint32_t aFlags = 0)
264
0
{
265
0
  for (BrowsingContext* aContext : aField) {
266
0
    aCallback.NoteNativeChild(aContext,
267
0
                              NS_CYCLE_COLLECTION_PARTICIPANT(BrowsingContext));
268
0
  }
269
0
}
270
271
NS_IMPL_CYCLE_COLLECTION_CLASS(BrowsingContext)
272
273
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(BrowsingContext)
274
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell, mChildren)
275
0
  if (XRE_IsParentProcess()) {
276
0
    ChromeBrowsingContext::Cast(tmp)->Unlink();
277
0
  }
278
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
279
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
280
281
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(BrowsingContext)
282
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocShell, mChildren)
283
0
  if (XRE_IsParentProcess()) {
284
0
    ChromeBrowsingContext::Cast(tmp)->Traverse(cb);
285
0
  }
286
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
287
288
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(BrowsingContext)
289
290
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(BrowsingContext, AddRef)
291
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(BrowsingContext, Release)
292
293
} // namespace dom
294
} // namespace mozilla