Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(292)

Side by Side Diff: chrome/android/javatests/src/org/chromium/chrome/browser/BindingManagerIntegrationTest.java

Issue 1141283003: Upstream oodles of Chrome for Android code into Chromium. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: final patch? Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.chrome.browser;
6
7 import android.test.FlakyTest;
8 import android.test.suitebuilder.annotation.LargeTest;
9 import android.util.SparseArray;
10
11 import org.chromium.base.ThreadUtils;
12 import org.chromium.base.test.util.CommandLineFlags;
13 import org.chromium.base.test.util.Feature;
14 import org.chromium.chrome.browser.compositor.layouts.Layout;
15 import org.chromium.chrome.browser.tabmodel.ChromeTabCreator;
16 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
17 import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType;
18 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
19 import org.chromium.chrome.test.ChromeActivityTestCaseBase;
20 import org.chromium.chrome.test.util.ChromeTabUtils;
21 import org.chromium.chrome.test.util.TestHttpServerClient;
22 import org.chromium.content.browser.BindingManager;
23 import org.chromium.content.browser.ChildProcessConnection;
24 import org.chromium.content.browser.ChildProcessLauncher;
25 import org.chromium.content.browser.test.util.Criteria;
26 import org.chromium.content.browser.test.util.CriteriaHelper;
27 import org.chromium.content_public.browser.LoadUrlParams;
28 import org.chromium.ui.base.DeviceFormFactor;
29
30 import java.util.concurrent.Callable;
31
32 /**
33 * Integration tests for the BindingManager API. This test plants a mock Binding Manager
34 * implementation and verifies that the signals it relies on are correctly deliv ered.
35 */
36 @CommandLineFlags.Add(ChromeSwitches.DISABLE_DOCUMENT_MODE) // crbug.com/414719
37 public class BindingManagerIntegrationTest extends ChromeActivityTestCaseBase<Ch romeActivity> {
38
39 private static class MockBindingManager implements BindingManager {
40 // Maps pid to the last received visibility state of the renderer.
41 private final SparseArray<Boolean> mProcessInForegroundMap = new SparseA rray<Boolean>();
42 // Maps pid to a string recording calls to setInForeground() and visibil ityDetermined().
43 private final SparseArray<String> mVisibilityCallsMap = new SparseArray< String>();
44
45 boolean isInForeground(int pid) {
46 return mProcessInForegroundMap.get(pid);
47 }
48
49 boolean isInBackground(int pid) {
50 return !mProcessInForegroundMap.get(pid);
51 }
52
53 boolean setInForegroundWasCalled(int pid) {
54 return mProcessInForegroundMap.get(pid) != null;
55 }
56
57 String getVisibilityCalls(int pid) {
58 return mVisibilityCallsMap.get(pid);
59 }
60
61 @Override
62 public void addNewConnection(int pid, ChildProcessConnection connection) {
63 mVisibilityCallsMap.put(pid, "");
64 }
65
66 @Override
67 public void setInForeground(int pid, boolean inForeground) {
68 mProcessInForegroundMap.put(pid, inForeground);
69
70 if (inForeground) {
71 mVisibilityCallsMap.put(pid, mVisibilityCallsMap.get(pid) + "FG; ");
72 } else {
73 mVisibilityCallsMap.put(pid, mVisibilityCallsMap.get(pid) + "BG; ");
74 }
75 }
76
77 @Override
78 public void determinedVisibility(int pid) {
79 mVisibilityCallsMap.put(pid, mVisibilityCallsMap.get(pid) + "DETERMI NED;");
80 }
81
82 @Override
83 public void onSentToBackground() {}
84
85 @Override
86 public void onBroughtToForeground() {}
87
88 @Override
89 public boolean isOomProtected(int pid) {
90 return false;
91 }
92
93 @Override
94 public void clearConnection(int pid) {}
95 }
96
97 private MockBindingManager mBindingManager;
98
99 private static final String FILE_PATH = "chrome/test/data/android/test.html" ;
100 // about:version will always be handled by a different renderer than a local file.
101 private static final String ABOUT_VERSION_PATH = "chrome://version/";
102
103 public BindingManagerIntegrationTest() {
104 super(ChromeActivity.class);
105 }
106
107 /**
108 * Verifies that the .setProcessInForeground() signal is called correctly as the tabs are
109 * created and switched.
110 */
111 @LargeTest
112 @Feature({"ProcessManagement"})
113 public void testTabSwitching() throws InterruptedException {
114 // Create two tabs and wait until they are loaded, so that their rendere rs are around.
115 final Tab[] tabs = new Tab[2];
116 getInstrumentation().runOnMainSync(new Runnable() {
117 @Override
118 public void run() {
119 // Foreground tab.
120 ChromeTabCreator tabCreator = getActivity().getCurrentTabCreator ();
121 tabs[0] = tabCreator.createNewTab(
122 new LoadUrlParams(TestHttpServerClient.getUrl(FILE_PATH) ),
123 TabLaunchType.FROM_KEYBOARD, null);
124 // Background tab.
125 tabs[1] = tabCreator.createNewTab(
126 new LoadUrlParams(TestHttpServerClient.getUrl(FILE_PATH) ),
127 TabLaunchType.FROM_LONGPRESS_BACKGROUND, null);
128 // On Svelte devices the background tab would not be loaded auto matically, so
129 // trigger the load manually.
130 tabs[1].show(TabSelectionType.FROM_USER);
131 tabs[1].hide();
132 }
133 });
134 ChromeTabUtils.waitForTabPageLoaded(tabs[0], TestHttpServerClient.getUrl (FILE_PATH));
135 ChromeTabUtils.waitForTabPageLoaded(tabs[1], TestHttpServerClient.getUrl (FILE_PATH));
136
137 // Wait for the new tab animations on phones to finish.
138 if (!DeviceFormFactor.isTablet(getActivity())
139 && getActivity() instanceof CompositorChromeActivity) {
140 final CompositorChromeActivity activity = (CompositorChromeActivity) getActivity();
141 assertTrue("Did not finish animation",
142 CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
143 @Override
144 public boolean isSatisfied() {
145 Layout layout = activity.getCompositorViewHolder()
146 .getLayoutManager().getActiveLayout();
147 return !layout.isLayoutAnimating();
148 }
149 }));
150 }
151 getInstrumentation().waitForIdleSync();
152
153 getInstrumentation().runOnMainSync(new Runnable() {
154 @Override
155 public void run() {
156 // Make sure that the renderers were spawned.
157 assertTrue(tabs[0].getContentViewCore().getCurrentRenderProcessI d() > 0);
158 assertTrue(tabs[1].getContentViewCore().getCurrentRenderProcessI d() > 0);
159
160 // Verify that the renderer of the foreground tab was signalled as visible.
161 assertTrue(mBindingManager.isInForeground(
162 tabs[0].getContentViewCore().getCurrentRenderProcessId() ));
163 // Verify that the renderer of the tab loaded in background was signalled as not
164 // visible.
165 assertTrue(mBindingManager.isInBackground(
166 tabs[1].getContentViewCore().getCurrentRenderProcessId() ));
167
168 // Select tabs[1] and verify that the renderer visibility was fl ipped.
169 TabModelUtils.setIndex(getActivity().getCurrentTabModel(), index Of(tabs[1]));
170 assertTrue(mBindingManager.isInBackground(
171 tabs[0].getContentViewCore().getCurrentRenderProcessId() ));
172 assertTrue(mBindingManager.isInForeground(
173 tabs[1].getContentViewCore().getCurrentRenderProcessId() ));
174 }
175 });
176 }
177
178 /**
179 * Verifies that the .setProcessInForeground() signal is called correctly wh en a tab that
180 * crashed in background is restored in foreground. This is a regression tes t for
181 * http://crbug.com/399521.
182 */
183 @LargeTest
184 @Feature({"ProcessManagement"})
185 public void testCrashInBackground() throws InterruptedException {
186 // Create two tabs and wait until they are loaded, so that their rendere rs are around.
187 final Tab[] tabs = new Tab[2];
188 getInstrumentation().runOnMainSync(new Runnable() {
189 @Override
190 public void run() {
191 // Foreground tab.
192 ChromeTabCreator tabCreator = getActivity().getCurrentTabCreator ();
193 tabs[0] = tabCreator.createNewTab(
194 new LoadUrlParams(TestHttpServerClient.getUrl(FILE_PATH) ),
195 TabLaunchType.FROM_KEYBOARD, null);
196 // Background tab.
197 tabs[1] = tabCreator.createNewTab(
198 new LoadUrlParams(TestHttpServerClient.getUrl(FILE_PATH) ),
199 TabLaunchType.FROM_LONGPRESS_BACKGROUND, null);
200 // On Svelte devices the background tab would not be loaded auto matically, so
201 // trigger the load manually.
202 tabs[1].show(TabSelectionType.FROM_USER);
203 tabs[1].hide();
204 }
205 });
206 ChromeTabUtils.waitForTabPageLoaded(tabs[0], TestHttpServerClient.getUrl (FILE_PATH));
207 ChromeTabUtils.waitForTabPageLoaded(tabs[1], TestHttpServerClient.getUrl (FILE_PATH));
208
209 // Wait for the new tab animations on phones to finish.
210 if (!DeviceFormFactor.isTablet(getActivity())
211 && getActivity() instanceof CompositorChromeActivity) {
212 final CompositorChromeActivity activity = (CompositorChromeActivity) getActivity();
213 assertTrue("Did not finish animation",
214 CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
215 @Override
216 public boolean isSatisfied() {
217 Layout layout = activity.getCompositorViewHolder()
218 .getLayoutManager().getActiveLayout();
219 return !layout.isLayoutAnimating();
220 }
221 }));
222 }
223 getInstrumentation().waitForIdleSync();
224
225 getInstrumentation().runOnMainSync(new Runnable() {
226 @Override
227 public void run() {
228 // Make sure that the renderers were spawned.
229 assertTrue(tabs[0].getContentViewCore().getCurrentRenderProcessI d() > 0);
230 assertTrue(tabs[1].getContentViewCore().getCurrentRenderProcessI d() > 0);
231
232 // Verify that the renderer of the foreground tab was signalled as visible.
233 assertTrue(mBindingManager.isInForeground(
234 tabs[0].getContentViewCore().getCurrentRenderProcessId() ));
235 // Verify that the renderer of the tab loaded in background was signalled as not
236 // visible.
237 assertTrue(mBindingManager.isInBackground(
238 tabs[1].getContentViewCore().getCurrentRenderProcessId() ));
239 }
240 });
241
242 // Kill the renderer and wait for the crash to be noted by the browser p rocess.
243 assertTrue(ChildProcessLauncher.crashProcessForTesting(
244 tabs[1].getContentViewCore().getCurrentRenderProcessId()));
245
246 assertTrue("Renderer crash wasn't noticed by the browser.",
247 CriteriaHelper.pollForCriteria(new Criteria() {
248 @Override
249 public boolean isSatisfied() {
250 return tabs[1].getContentViewCore().getCurrentRenderProc essId() == 0;
251 }
252 }));
253
254 // Switch to the tab that crashed in background.
255 getInstrumentation().runOnMainSync(new Runnable() {
256 @Override
257 public void run() {
258 TabModelUtils.setIndex(getActivity().getCurrentTabModel(), index Of(tabs[1]));
259 }
260 });
261
262 // Wait until the process is spawned and its visibility is determined.
263 assertTrue("Process for the crashed tab was not respawned.",
264 CriteriaHelper.pollForCriteria(new Criteria() {
265 @Override
266 public boolean isSatisfied() {
267 return tabs[1].getContentViewCore().getCurrentRenderProc essId() != 0;
268 }
269 }));
270
271 assertTrue("isInForeground() was not called for the process.",
272 CriteriaHelper.pollForCriteria(new Criteria() {
273 @Override
274 public boolean isSatisfied() {
275 return mBindingManager.setInForegroundWasCalled(
276 tabs[1].getContentViewCore().getCurrentRenderPro cessId());
277 }
278 }));
279
280 getInstrumentation().runOnMainSync(new Runnable() {
281 @Override
282 public void run() {
283 // Verify the visibility of the renderers.
284 assertTrue(mBindingManager.isInBackground(
285 tabs[0].getContentViewCore().getCurrentRenderProcessId() ));
286 assertTrue(mBindingManager.isInForeground(
287 tabs[1].getContentViewCore().getCurrentRenderProcessId() ));
288 }
289 });
290 }
291
292 /**
293 * Verifies that a renderer that crashes in foreground has the correct visib ility when
294 * recreated.
295 */
296 @LargeTest
297 @Feature({"ProcessManagement"})
298 public void testCrashInForeground() throws InterruptedException {
299 // Create a tab in foreground and wait until it is loaded.
300 final Tab tab = ThreadUtils.runOnUiThreadBlockingNoException(
301 new Callable<Tab>() {
302 @Override
303 public Tab call() throws Exception {
304 ChromeTabCreator tabCreator = getActivity().getCurrentTa bCreator();
305 return tabCreator.createNewTab(
306 new LoadUrlParams(TestHttpServerClient.getUrl(FI LE_PATH)),
307 TabLaunchType.FROM_KEYBOARD, null);
308 }
309 });
310 ChromeTabUtils.waitForTabPageLoaded(tab, TestHttpServerClient.getUrl(FIL E_PATH));
311 getInstrumentation().waitForIdleSync();
312
313 // Kill the renderer and wait for the crash to be noted by the browser p rocess.
314 assertTrue(ChildProcessLauncher.crashProcessForTesting(
315 tab.getContentViewCore().getCurrentRenderProcessId()));
316
317 assertTrue("Renderer crash wasn't noticed by the browser.",
318 CriteriaHelper.pollForCriteria(new Criteria() {
319 @Override
320 public boolean isSatisfied() {
321 return tab.getContentViewCore().getCurrentRenderProcessI d() == 0;
322 }
323 }));
324
325 // Reload the tab, respawning the renderer.
326 getInstrumentation().runOnMainSync(new Runnable() {
327 @Override
328 public void run() {
329 tab.reload();
330 }
331 });
332
333 // Wait until the process is spawned and its visibility is determined.
334 assertTrue("Process for the crashed tab was not respawned.",
335 CriteriaHelper.pollForCriteria(new Criteria() {
336 @Override
337 public boolean isSatisfied() {
338 return tab.getContentViewCore().getCurrentRenderProcessI d() != 0;
339 }
340 }));
341
342 assertTrue("isInForeground() was not called for the process.",
343 CriteriaHelper.pollForCriteria(new Criteria() {
344 @Override
345 public boolean isSatisfied() {
346 return mBindingManager.setInForegroundWasCalled(
347 tab.getContentViewCore().getCurrentRenderProcess Id());
348 }
349 }));
350
351 getInstrumentation().runOnMainSync(new Runnable() {
352 @Override
353 public void run() {
354 // Verify the visibility of the renderer.
355 assertTrue(mBindingManager.isInForeground(
356 tab.getContentViewCore().getCurrentRenderProcessId()));
357 }
358 });
359 }
360
361 /**
362 * Ensures correctness of the visibilityDetermined() calls, that should be a lways preceded by
363 * setInForeground().
364 *
365 * Bug: https://crbug.com/474543
366 * @LargeTest
367 * @Feature({"ProcessManagement"})
368 */
369 @FlakyTest
370 public void testVisibilityDetermined() throws InterruptedException {
371 // Create a tab in foreground and wait until it is loaded.
372 final Tab fgTab = ThreadUtils.runOnUiThreadBlockingNoException(
373 new Callable<Tab>() {
374 @Override
375 public Tab call() {
376 ChromeTabCreator tabCreator = getActivity().getCurrentTa bCreator();
377 return tabCreator.createNewTab(
378 new LoadUrlParams(TestHttpServerClient.getUrl(FI LE_PATH)),
379 TabLaunchType.FROM_KEYBOARD, null);
380 }});
381 ChromeTabUtils.waitForTabPageLoaded(fgTab, TestHttpServerClient.getUrl(F ILE_PATH));
382 int initialNavigationPid = fgTab.getContentViewCore().getCurrentRenderPr ocessId();
383 // Ensure the following calls happened:
384 // - FG - setInForeground(true) - when the tab is created in the foregr ound
385 // - DETERMINED - visibilityDetermined() - after the initial navigation is committed
386 assertEquals("FG;DETERMINED;", mBindingManager.getVisibilityCalls(initia lNavigationPid));
387
388 // Navigate to about:version which requires a different renderer.
389 getInstrumentation().runOnMainSync(new Runnable() {
390 @Override
391 public void run() {
392 fgTab.loadUrl(new LoadUrlParams(ABOUT_VERSION_PATH));
393 }
394 });
395 ChromeTabUtils.waitForTabPageLoaded(fgTab, ABOUT_VERSION_PATH);
396 int secondNavigationPid = fgTab.getContentViewCore().getCurrentRenderPro cessId();
397 assertTrue(secondNavigationPid != initialNavigationPid);
398 // Ensure the following calls happened:
399 // - BG - setInForeground(false) - when the renderer is created for unc ommited frame
400 // - FG - setInForeground(true) - when the frame is swapped in on commi t
401 // - DETERMINED - visibilityDetermined() - after the navigation is comm itted
402 assertEquals("BG;FG;DETERMINED;", mBindingManager.getVisibilityCalls(sec ondNavigationPid));
403
404 // Open a tab in the background and load it.
405 final Tab bgTab = ThreadUtils.runOnUiThreadBlockingNoException(
406 new Callable<Tab>() {
407 @Override
408 public Tab call() {
409 ChromeTabCreator tabCreator = getActivity().getCurrentTa bCreator();
410 Tab tab = tabCreator.createNewTab(
411 new LoadUrlParams(TestHttpServerClient.getUrl(FI LE_PATH)),
412 TabLaunchType.FROM_LONGPRESS_BACKGROUND, null);
413 // On Svelte devices the background tab would not be loa ded automatically,
414 // so trigger the load manually.
415 tab.show(TabSelectionType.FROM_USER);
416 tab.hide();
417 return tab;
418 }});
419 ChromeTabUtils.waitForTabPageLoaded(bgTab, TestHttpServerClient.getUrl(F ILE_PATH));
420 int bgNavigationPid = bgTab.getContentViewCore().getCurrentRenderProcess Id();
421 // Ensure the following calls happened:
422 // - BG - setInForeground(false) - when tab is created in the backgroun d
423 // - DETERMINED - visibilityDetermined() - after the navigation is comm itted
424 assertEquals("BG;DETERMINED;", mBindingManager.getVisibilityCalls(bgNavi gationPid));
425 }
426
427 @Override
428 public void startMainActivity() throws InterruptedException {
429 startMainActivityOnBlankPage();
430 }
431
432 @Override
433 protected void setUp() throws Exception {
434 super.setUp();
435
436 // Hook in the test binding manager.
437 mBindingManager = new MockBindingManager();
438 ChildProcessLauncher.setBindingManagerForTesting(mBindingManager);
439 }
440
441 /**
442 * @return the index of the given tab in the current tab model
443 */
444 private int indexOf(Tab tab) {
445 return getActivity().getCurrentTabModel().indexOf(tab);
446 }
447 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698