Line data Source code
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 : #include "ContentProcessManager.h"
8 : #include "ContentParent.h"
9 : #include "mozilla/dom/TabParent.h"
10 :
11 : #include "mozilla/StaticPtr.h"
12 : #include "mozilla/ClearOnShutdown.h"
13 :
14 : #include "nsPrintfCString.h"
15 : #include "nsIScriptSecurityManager.h"
16 :
17 : // XXX need another bug to move this to a common header.
18 : #ifdef DISABLE_ASSERTS_FOR_FUZZING
19 : #define ASSERT_UNLESS_FUZZING(...) do { } while (0)
20 : #else
21 : #define ASSERT_UNLESS_FUZZING(...) MOZ_ASSERT(false, __VA_ARGS__)
22 : #endif
23 :
24 : namespace mozilla {
25 : namespace dom {
26 :
27 : /* static */
28 : StaticAutoPtr<ContentProcessManager>
29 3 : ContentProcessManager::sSingleton;
30 :
31 : /* static */ ContentProcessManager*
32 3 : ContentProcessManager::GetSingleton()
33 : {
34 3 : MOZ_ASSERT(XRE_IsParentProcess());
35 :
36 3 : if (!sSingleton) {
37 1 : sSingleton = new ContentProcessManager();
38 1 : ClearOnShutdown(&sSingleton);
39 : }
40 3 : return sSingleton;
41 : }
42 :
43 : void
44 2 : ContentProcessManager::AddContentProcess(ContentParent* aChildCp,
45 : const ContentParentId& aParentCpId)
46 : {
47 2 : MOZ_ASSERT(NS_IsMainThread());
48 2 : MOZ_ASSERT(aChildCp);
49 :
50 2 : ContentProcessInfo& info = mContentParentMap[aChildCp->ChildID()];
51 2 : if (!info.mCp) {
52 2 : info.mCp = aChildCp;
53 : } else {
54 0 : MOZ_ASSERT(info.mCp == aChildCp);
55 0 : MOZ_ASSERT_IF(!!info.mParentCpId, info.mParentCpId == aParentCpId);
56 : }
57 2 : info.mParentCpId = aParentCpId;
58 2 : }
59 :
60 : void
61 0 : ContentProcessManager::RemoveContentProcess(const ContentParentId& aChildCpId)
62 : {
63 0 : MOZ_ASSERT(NS_IsMainThread());
64 0 : MOZ_ASSERT(mContentParentMap.find(aChildCpId) != mContentParentMap.end());
65 :
66 0 : mContentParentMap.erase(aChildCpId);
67 0 : for (auto iter = mContentParentMap.begin();
68 0 : iter != mContentParentMap.end();
69 : ++iter) {
70 0 : if (!iter->second.mChildrenCpId.empty()) {
71 0 : iter->second.mChildrenCpId.erase(aChildCpId);
72 : }
73 : }
74 0 : }
75 :
76 : bool
77 0 : ContentProcessManager::AddGrandchildProcess(const ContentParentId& aParentCpId,
78 : const ContentParentId& aChildCpId)
79 : {
80 0 : MOZ_ASSERT(NS_IsMainThread());
81 :
82 0 : auto iter = mContentParentMap.find(aParentCpId);
83 0 : if (NS_WARN_IF(iter == mContentParentMap.end())) {
84 0 : ASSERT_UNLESS_FUZZING("Parent process should be already in map!");
85 : return false;
86 : }
87 0 : iter->second.mChildrenCpId.insert(aChildCpId);
88 0 : return true;
89 : }
90 :
91 : bool
92 0 : ContentProcessManager::GetParentProcessId(const ContentParentId& aChildCpId,
93 : /*out*/ ContentParentId* aParentCpId)
94 : {
95 0 : MOZ_ASSERT(NS_IsMainThread());
96 :
97 0 : auto iter = mContentParentMap.find(aChildCpId);
98 0 : if (NS_WARN_IF(iter == mContentParentMap.end())) {
99 0 : ASSERT_UNLESS_FUZZING();
100 : return false;
101 : }
102 0 : *aParentCpId = iter->second.mParentCpId;
103 0 : return true;
104 : }
105 :
106 : ContentParent*
107 0 : ContentProcessManager::GetContentProcessById(const ContentParentId& aChildCpId)
108 : {
109 0 : MOZ_ASSERT(NS_IsMainThread());
110 :
111 0 : auto iter = mContentParentMap.find(aChildCpId);
112 0 : if (NS_WARN_IF(iter == mContentParentMap.end())) {
113 0 : ASSERT_UNLESS_FUZZING();
114 : return nullptr;
115 : }
116 0 : return iter->second.mCp;
117 : }
118 :
119 : nsTArray<ContentParentId>
120 0 : ContentProcessManager::GetAllChildProcessById(const ContentParentId& aParentCpId)
121 : {
122 0 : MOZ_ASSERT(NS_IsMainThread());
123 :
124 0 : nsTArray<ContentParentId> cpIdArray;
125 0 : auto iter = mContentParentMap.find(aParentCpId);
126 0 : if (NS_WARN_IF(iter == mContentParentMap.end())) {
127 0 : ASSERT_UNLESS_FUZZING();
128 : return Move(cpIdArray);
129 : }
130 :
131 0 : for (auto cpIter = iter->second.mChildrenCpId.begin();
132 0 : cpIter != iter->second.mChildrenCpId.end();
133 : ++cpIter) {
134 0 : cpIdArray.AppendElement(*cpIter);
135 : }
136 :
137 0 : return Move(cpIdArray);
138 : }
139 :
140 : bool
141 1 : ContentProcessManager::RegisterRemoteFrame(const TabId& aTabId,
142 : const ContentParentId& aOpenerCpId,
143 : const TabId& aOpenerTabId,
144 : const IPCTabContext& aContext,
145 : const ContentParentId& aChildCpId)
146 : {
147 1 : MOZ_ASSERT(NS_IsMainThread());
148 :
149 1 : auto iter = mContentParentMap.find(aChildCpId);
150 1 : if (NS_WARN_IF(iter == mContentParentMap.end())) {
151 0 : ASSERT_UNLESS_FUZZING();
152 : return false;
153 : }
154 :
155 2 : struct RemoteFrameInfo info;
156 :
157 : // If it's a PopupIPCTabContext, it's the case that a TabChild want to
158 : // open a new tab. aOpenerTabId has to be it's parent frame's opener id.
159 1 : if (aContext.type() == IPCTabContext::TPopupIPCTabContext) {
160 0 : auto remoteFrameIter = iter->second.mRemoteFrames.find(aOpenerTabId);
161 0 : if (remoteFrameIter == iter->second.mRemoteFrames.end()) {
162 0 : ASSERT_UNLESS_FUZZING("Failed to find parent frame's opener id.");
163 : return false;
164 : }
165 :
166 0 : info.mOpenerCpId = remoteFrameIter->second.mOpenerCpId;
167 0 : info.mOpenerTabId = remoteFrameIter->second.mOpenerTabId;
168 0 : info.mContext = remoteFrameIter->second.mContext;
169 : }
170 : else {
171 2 : MaybeInvalidTabContext tc(aContext);
172 1 : if (!tc.IsValid()) {
173 0 : NS_ERROR(nsPrintfCString("Received an invalid TabContext from "
174 : "the child process. (%s)",
175 : tc.GetInvalidReason()).get());
176 0 : return false;
177 : }
178 1 : info.mOpenerCpId = aOpenerCpId;
179 1 : info.mOpenerTabId = aOpenerTabId;
180 1 : info.mContext = tc.GetTabContext();
181 : }
182 :
183 1 : iter->second.mRemoteFrames[aTabId] = info;
184 1 : return true;
185 : }
186 :
187 : void
188 0 : ContentProcessManager::UnregisterRemoteFrame(const ContentParentId& aChildCpId,
189 : const TabId& aChildTabId)
190 : {
191 0 : MOZ_ASSERT(NS_IsMainThread());
192 :
193 0 : auto iter = mContentParentMap.find(aChildCpId);
194 0 : if (NS_WARN_IF(iter == mContentParentMap.end())) {
195 0 : ASSERT_UNLESS_FUZZING();
196 : return;
197 : }
198 :
199 0 : auto remoteFrameIter = iter->second.mRemoteFrames.find(aChildTabId);
200 0 : if (remoteFrameIter != iter->second.mRemoteFrames.end()) {
201 0 : iter->second.mRemoteFrames.erase(aChildTabId);
202 : }
203 0 : }
204 :
205 : bool
206 0 : ContentProcessManager::GetTabContextByProcessAndTabId(const ContentParentId& aChildCpId,
207 : const TabId& aChildTabId,
208 : /*out*/ TabContext* aTabContext)
209 : {
210 0 : MOZ_ASSERT(NS_IsMainThread());
211 0 : MOZ_ASSERT(aTabContext);
212 :
213 0 : auto iter = mContentParentMap.find(aChildCpId);
214 0 : if (NS_WARN_IF(iter == mContentParentMap.end())) {
215 0 : ASSERT_UNLESS_FUZZING();
216 : return false;
217 : }
218 :
219 0 : auto remoteFrameIter = iter->second.mRemoteFrames.find(aChildTabId);
220 0 : if (NS_WARN_IF(remoteFrameIter == iter->second.mRemoteFrames.end())) {
221 0 : ASSERT_UNLESS_FUZZING();
222 : return false;
223 : }
224 :
225 0 : *aTabContext = remoteFrameIter->second.mContext;
226 :
227 0 : return true;
228 : }
229 :
230 : nsTArray<TabContext>
231 0 : ContentProcessManager::GetTabContextByContentProcess(const ContentParentId& aChildCpId)
232 : {
233 0 : MOZ_ASSERT(NS_IsMainThread());
234 :
235 0 : nsTArray<TabContext> tabContextArray;
236 0 : auto iter = mContentParentMap.find(aChildCpId);
237 0 : if (NS_WARN_IF(iter == mContentParentMap.end())) {
238 0 : ASSERT_UNLESS_FUZZING();
239 : return Move(tabContextArray);
240 : }
241 :
242 0 : for (auto remoteFrameIter = iter->second.mRemoteFrames.begin();
243 0 : remoteFrameIter != iter->second.mRemoteFrames.end();
244 : ++remoteFrameIter) {
245 0 : tabContextArray.AppendElement(remoteFrameIter->second.mContext);
246 : }
247 :
248 0 : return Move(tabContextArray);
249 : }
250 :
251 : bool
252 0 : ContentProcessManager::GetRemoteFrameOpenerTabId(const ContentParentId& aChildCpId,
253 : const TabId& aChildTabId,
254 : /*out*/ContentParentId* aOpenerCpId,
255 : /*out*/TabId* aOpenerTabId)
256 : {
257 0 : MOZ_ASSERT(NS_IsMainThread());
258 0 : auto iter = mContentParentMap.find(aChildCpId);
259 0 : if (NS_WARN_IF(iter == mContentParentMap.end())) {
260 0 : ASSERT_UNLESS_FUZZING();
261 : return false;
262 : }
263 :
264 0 : auto remoteFrameIter = iter->second.mRemoteFrames.find(aChildTabId);
265 0 : if (NS_WARN_IF(remoteFrameIter == iter->second.mRemoteFrames.end())) {
266 0 : ASSERT_UNLESS_FUZZING();
267 : return false;
268 : }
269 :
270 0 : *aOpenerCpId = remoteFrameIter->second.mOpenerCpId;
271 0 : *aOpenerTabId = remoteFrameIter->second.mOpenerTabId;
272 :
273 0 : return true;
274 : }
275 :
276 : already_AddRefed<TabParent>
277 0 : ContentProcessManager::GetTabParentByProcessAndTabId(const ContentParentId& aChildCpId,
278 : const TabId& aChildTabId)
279 : {
280 0 : MOZ_ASSERT(NS_IsMainThread());
281 :
282 0 : auto iter = mContentParentMap.find(aChildCpId);
283 0 : if (NS_WARN_IF(iter == mContentParentMap.end())) {
284 0 : ASSERT_UNLESS_FUZZING();
285 : return nullptr;
286 : }
287 :
288 0 : const ManagedContainer<PBrowserParent>& browsers = iter->second.mCp->ManagedPBrowserParent();
289 0 : for (auto iter = browsers.ConstIter(); !iter.Done(); iter.Next()) {
290 0 : RefPtr<TabParent> tab = TabParent::GetFrom(iter.Get()->GetKey());
291 0 : if (tab->GetTabId() == aChildTabId) {
292 0 : return tab.forget();
293 : }
294 : }
295 :
296 0 : return nullptr;
297 : }
298 :
299 : already_AddRefed<TabParent>
300 0 : ContentProcessManager::GetTopLevelTabParentByProcessAndTabId(const ContentParentId& aChildCpId,
301 : const TabId& aChildTabId)
302 : {
303 0 : MOZ_ASSERT(NS_IsMainThread());
304 :
305 : // Used to keep the current ContentParentId and the current TabId
306 : // in the iteration(do-while loop below)
307 0 : ContentParentId currentCpId;
308 0 : TabId currentTabId;
309 :
310 : // To get the ContentParentId and the TabParentId on upper level
311 0 : ContentParentId parentCpId = aChildCpId;
312 0 : TabId openerTabId = aChildTabId;
313 :
314 : // Stop this loop when the upper ContentParentId of
315 : // the current ContentParentId is chrome(ContentParentId = 0).
316 0 : do {
317 : // Update the current ContentParentId and TabId in iteration
318 0 : currentCpId = parentCpId;
319 0 : currentTabId = openerTabId;
320 :
321 : // Get the ContentParentId and TabId on upper level
322 0 : if (!GetRemoteFrameOpenerTabId(currentCpId, currentTabId, &parentCpId, &openerTabId)) {
323 0 : return nullptr;
324 : }
325 0 : } while (parentCpId);
326 :
327 : // Get the top level TabParent by the current ContentParentId and TabId
328 0 : return GetTabParentByProcessAndTabId(currentCpId, currentTabId);
329 : }
330 :
331 : nsTArray<TabId>
332 0 : ContentProcessManager::GetTabParentsByProcessId(const ContentParentId& aChildCpId)
333 : {
334 0 : MOZ_ASSERT(NS_IsMainThread());
335 :
336 0 : nsTArray<TabId> tabIdList;
337 0 : auto iter = mContentParentMap.find(aChildCpId);
338 0 : if (NS_WARN_IF(iter == mContentParentMap.end())) {
339 0 : ASSERT_UNLESS_FUZZING();
340 : return Move(tabIdList);
341 : }
342 :
343 0 : for (auto remoteFrameIter = iter->second.mRemoteFrames.begin();
344 0 : remoteFrameIter != iter->second.mRemoteFrames.end();
345 : ++remoteFrameIter) {
346 0 : tabIdList.AppendElement(remoteFrameIter->first);
347 : }
348 :
349 0 : return Move(tabIdList);
350 : }
351 :
352 : uint32_t
353 0 : ContentProcessManager::GetTabParentCountByProcessId(const ContentParentId& aChildCpId)
354 : {
355 0 : MOZ_ASSERT(NS_IsMainThread());
356 :
357 0 : auto iter = mContentParentMap.find(aChildCpId);
358 0 : if (NS_WARN_IF(iter == mContentParentMap.end())) {
359 0 : return 0;
360 : }
361 :
362 0 : return iter->second.mRemoteFrames.size();
363 : }
364 :
365 : } // namespace dom
366 : } // namespace mozilla
|