Commit 0bfc6020 authored by Xi Han's avatar Xi Han Committed by Commit Bot

[Instant Start] Create LayoutManager before native is initialized.

The changes of the startup order in this CL are behind the feature flag
"InstantStart".

In this CL, we split setupCompositorContent() into
- setupCompositorContentPreNative() and
- setupCompositorContentPostNative().

The setupCompositorContentPreNative() creates the LayoutManager.

When Instant start is on:
1) triggerLayoutInflation() is called before loading the native library.
2) setupCompositorContentPreNative() is called in
   performPostInflationStartup() before native is initialized.

Besides, the value of field trial "tab_switcher_on_return_time_ms" of
ChromeFeatureList.TAB_SWITCHER_ON_RETURN is cached now.

In the follow up CL, we may move the creation of the LayoutManager into
doLayoutInflation().

Bug: 1041865
Change-Id: Ib1039e152cece799ffed0f636a5e55fafbf4adb2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2110529
Commit-Queue: Xi Han <hanxi@chromium.org>
Reviewed-by: default avatarYaron Friedman <yfriedman@chromium.org>
Reviewed-by: default avatarWei-Yin Chen (陳威尹) <wychen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#756652}
parent a0ca17b3
......@@ -19,6 +19,7 @@ import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.flags.DoubleCachedFieldTrialParameter;
import org.chromium.chrome.browser.flags.IntCachedFieldTrialParameter;
import org.chromium.chrome.browser.flags.StringCachedFieldTrialParameter;
import org.chromium.chrome.browser.tasks.ReturnToChromeExperimentsUtil;
import org.chromium.chrome.features.start_surface.StartSurfaceConfiguration;
import org.chromium.ui.base.DeviceFormFactor;
......@@ -44,6 +45,10 @@ public class TabUiFeatureUtilities {
new StringCachedFieldTrialParameter(ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID,
TAB_GRID_LAYOUT_ANDROID_NEW_TAB_TILE_PARAM, "");
public static final IntCachedFieldTrialParameter TAB_SWITCHER_ON_RETURN_MS =
new IntCachedFieldTrialParameter(ChromeFeatureList.TAB_SWITCHER_ON_RETURN,
ReturnToChromeExperimentsUtil.TAB_SWITCHER_ON_RETURN_MS, -1);
public static final String THUMBNAIL_ASPECT_RATIO_PARAM = "thumbnail_aspect_ratio";
public static final DoubleCachedFieldTrialParameter THUMBNAIL_ASPECT_RATIO =
new DoubleCachedFieldTrialParameter(
......
......@@ -79,6 +79,7 @@ public class ChromeCachedFlags {
TabUiFeatureUtilities.ZOOMING_MIN_SDK,
TabUiFeatureUtilities.SKIP_SLOW_ZOOMING,
TabUiFeatureUtilities.TAB_GRID_LAYOUT_ANDROID_NEW_TAB_TILE,
TabUiFeatureUtilities.TAB_SWITCHER_ON_RETURN_MS,
TabUiFeatureUtilities.THUMBNAIL_ASPECT_RATIO);
// clang-format on
CachedFeatureFlags.cacheFieldTrialParameters(fieldTrialsToCache);
......
......@@ -77,6 +77,7 @@ import org.chromium.chrome.browser.download.DownloadUtils;
import org.chromium.chrome.browser.feed.FeedProcessScopeFactory;
import org.chromium.chrome.browser.firstrun.FirstRunSignInProcessor;
import org.chromium.chrome.browser.flags.ActivityType;
import org.chromium.chrome.browser.flags.CachedFeatureFlags;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
......@@ -646,24 +647,48 @@ public class ChromeTabbedActivity
}
}
private void setupCompositorContent() {
try (TraceEvent e = TraceEvent.scoped("ChromeTabbedActivity.setupCompositorContent")) {
private void setupCompositorContentPreNativeForPhone() {
if (isTablet()) return;
try (TraceEvent e = TraceEvent.scoped(
"ChromeTabbedActivity.setupCompositorContentPreNativeForPhone")) {
CompositorViewHolder compositorViewHolder = getCompositorViewHolder();
if (isTablet()) {
mLayoutManager = new LayoutManagerChromeTablet(compositorViewHolder);
} else {
if (TabUiFeatureUtilities.isGridTabSwitcherEnabled()) {
TabManagementDelegate tabManagementDelegate =
TabManagementModuleProvider.getDelegate();
if (tabManagementDelegate != null) {
mStartSurface = tabManagementDelegate.createStartSurface(this);
assert LibraryLoader.getInstance().isInitialized();
mStartSurface.initWithNative();
}
if (TabUiFeatureUtilities.isGridTabSwitcherEnabled()) {
TabManagementDelegate tabManagementDelegate =
TabManagementModuleProvider.getDelegate();
if (tabManagementDelegate != null) {
mStartSurface = tabManagementDelegate.createStartSurface(this);
}
}
mLayoutManager = new LayoutManagerChromePhone(compositorViewHolder, mStartSurface);
}
}
private void setupCompositorContentPreNativeForTablet() {
if (!isTablet()) return;
try (TraceEvent e = TraceEvent.scoped(
"ChromeTabbedActivity.setupCompositorContentPreNativeForTablet")) {
mLayoutManager = new LayoutManagerChromeTablet(getCompositorViewHolder());
}
}
private void setupCompositorContentPostNative() {
try (TraceEvent e = TraceEvent.scoped(
"ChromeTabbedActivity.setupCompositorContentPostNative")) {
if (!isLayoutManagerCreated()) {
if (isTablet()) {
setupCompositorContentPreNativeForTablet();
} else {
setupCompositorContentPreNativeForPhone();
}
}
mLayoutManager = new LayoutManagerChromePhone(compositorViewHolder, mStartSurface);
if (mStartSurface != null) {
assert LibraryLoader.getInstance().isInitialized();
mStartSurface.initWithNative();
}
mLayoutManager.setEnableAnimations(DeviceClassManager.enableAnimations());
// TODO(yusufo): get rid of findViewById(R.id.url_bar).
......@@ -674,6 +699,10 @@ public class ChromeTabbedActivity
}
}
private boolean isLayoutManagerCreated() {
return mLayoutManager != null;
}
private void initializeToolbarManager() {
try (TraceEvent e = TraceEvent.scoped("ChromeTabbedActivity.initializeToolbarManager")) {
mUndoBarPopupController.initialize();
......@@ -780,8 +809,9 @@ public class ChromeTabbedActivity
}
}
private void addOverviewModeObserver() {
try (TraceEvent e = TraceEvent.scoped("ChromeTabbedActivity.addOverviewModeObserver")) {
private void addOverviewModeObserverPreNative() {
try (TraceEvent e = TraceEvent.scoped(
"ChromeTabbedActivity.addOverviewModeObserverPreNative")) {
mOverviewModeController.overrideOverviewModeController(mLayoutManager);
mOverviewModeObserver = new EmptyOverviewModeObserver() {
@Override
......@@ -799,6 +829,15 @@ public class ChromeTabbedActivity
}
};
mOverviewModeController.addOverviewModeObserver(mOverviewModeObserver);
}
}
private void addOverviewModeObserverPostNative() {
try (TraceEvent e = TraceEvent.scoped(
"ChromeTabbedActivity.addOverviewModeObserverPostNative")) {
if (mOverviewModeObserver == null) {
addOverviewModeObserverPreNative();
}
if (ChromeFeatureList.isEnabled(ChromeFeatureList.TAB_ENGAGEMENT_REPORTING_ANDROID)) {
// The lifecycle of this object is managed by the lifecycle dispatcher.
......@@ -837,7 +876,7 @@ public class ChromeTabbedActivity
ChromeFeatureList.DARKEN_WEBSITES_CHECKBOX_IN_THEMES_SETTING)) {
WebContentsDarkModeController.createInstance();
}
setupCompositorContent();
setupCompositorContentPostNative();
// All this initialization can be expensive so it's split into multiple tasks.
PostTask.postTask(UiThreadTaskTraits.DEFAULT, this::refreshSignIn);
......@@ -849,7 +888,7 @@ public class ChromeTabbedActivity
PostTask.postTask(UiThreadTaskTraits.DEFAULT,
this::maybeGetFeedAppLifecycleAndMaybeCreatePageViewObserver);
PostTask.postTask(UiThreadTaskTraits.DEFAULT, this::addOverviewModeObserver);
PostTask.postTask(UiThreadTaskTraits.DEFAULT, this::addOverviewModeObserverPostNative);
PostTask.postTask(UiThreadTaskTraits.DEFAULT, this::finishNativeInitialization);
AccessibilityUtil.addObserver(this);
}
......@@ -1527,6 +1566,24 @@ public class ChromeTabbedActivity
mUndoBarPopupController =
new UndoBarController(this, mTabModelSelectorImpl, this::getSnackbarManager);
// When the feature flag {@link ChromeFeatureList.INSTANT_START} turns on phones (not
// tablet), a view-only start page created on Java will be shown before native is
// initialized.
if (CachedFeatureFlags.isEnabled(ChromeFeatureList.INSTANT_START) && !isTablet()) {
prepareToShowStartPagePreNative();
}
}
/**
* Prepares to show the start page before native is initialized. For example, create
* an LayoutManagerChrome object, add overview mode observer and so on.
*/
private void prepareToShowStartPagePreNative() {
setupCompositorContentPreNativeForPhone();
getCompositorViewHolder().setLayoutManager(mLayoutManager);
mLayoutManager.setTabModelSelector(mTabModelSelectorImpl);
addOverviewModeObserverPreNative();
}
@Override
......
......@@ -38,6 +38,8 @@ import org.chromium.chrome.browser.IntentHandler;
import org.chromium.chrome.browser.LaunchIntentDispatcher;
import org.chromium.chrome.browser.WarmupManager;
import org.chromium.chrome.browser.firstrun.FirstRunFlowSequencer;
import org.chromium.chrome.browser.flags.CachedFeatureFlags;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
import org.chromium.chrome.browser.multiwindow.MultiWindowModeStateDispatcher;
import org.chromium.chrome.browser.multiwindow.MultiWindowModeStateDispatcherImpl;
......@@ -154,18 +156,27 @@ public abstract class AsyncInitializationActivity extends ChromeBaseAppCompatAct
@Override
public final void setContentViewAndLoadLibrary(Runnable onInflationCompleteCallback) {
// Start loading libraries before triggerLayoutInflation(). This "hides" library loading
// behind UI inflation and prevents stalling UI thread. See https://crbug.com/796957 for
// details. Note that for optimal performance AsyncInitTaskRunner.startBackgroundTasks()
// needs to start warmup renderer only after library is loaded.
boolean enableInstantStart = CachedFeatureFlags.isEnabled(ChromeFeatureList.INSTANT_START);
mOnInflationCompleteCallback = onInflationCompleteCallback;
if (enableInstantStart) {
triggerLayoutInflation();
}
// Start loading libraries. It happens before triggerLayoutInflation() for regular startup,
// but after triggerLayoutInflation() for instant start because we prioritize a Java UI and
// not rendering web content. This "hides" library loading behind UI inflation and prevents
// stalling UI thread. See https://crbug.com/796957 for details. Note that for optimal
// performance AsyncInitTaskRunner.startBackgroundTasks() needs to start warmup renderer
// only after library is loaded.
if (!mStartupDelayed) {
// Kick off long running IO tasks that can be done in parallel.
mNativeInitializationController.startBackgroundTasks(shouldAllocateChildConnection());
}
mOnInflationCompleteCallback = onInflationCompleteCallback;
triggerLayoutInflation();
if (!enableInstantStart) {
triggerLayoutInflation();
}
if (mLaunchBehindWorkaround != null) mLaunchBehindWorkaround.onSetContentView();
}
......
......@@ -15,12 +15,12 @@ import org.chromium.base.Log;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.metrics.RecordUserAction;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.homepage.HomepageManager;
import org.chromium.chrome.browser.locale.LocaleManager;
import org.chromium.chrome.browser.ntp.NewTabPage;
import org.chromium.chrome.browser.tab.TabLaunchType;
import org.chromium.chrome.browser.tabmodel.TabModel;
import org.chromium.chrome.browser.tasks.tab_management.TabUiFeatureUtilities;
import org.chromium.chrome.browser.util.AccessibilityUtil;
import org.chromium.chrome.features.start_surface.StartSurfaceConfiguration;
import org.chromium.content_public.browser.LoadUrlParams;
......@@ -34,7 +34,7 @@ public final class ReturnToChromeExperimentsUtil {
private static final String TAG = "TabSwitcherOnReturn";
@VisibleForTesting
static final String TAB_SWITCHER_ON_RETURN_MS = "tab_switcher_on_return_time_ms";
public static final String TAB_SWITCHER_ON_RETURN_MS = "tab_switcher_on_return_time_ms";
@VisibleForTesting
static final String UMA_TIME_TO_GTS_FIRST_MEANINGFUL_PAINT =
......@@ -57,8 +57,7 @@ public final class ReturnToChromeExperimentsUtil {
* @return true if past threshold, false if not past threshold or experiment cannot be loaded.
*/
public static boolean shouldShowTabSwitcher(final long lastBackgroundedTimeMillis) {
int tabSwitcherAfterMillis = ChromeFeatureList.getFieldTrialParamByFeatureAsInt(
ChromeFeatureList.TAB_SWITCHER_ON_RETURN, TAB_SWITCHER_ON_RETURN_MS, -1);
int tabSwitcherAfterMillis = TabUiFeatureUtilities.TAB_SWITCHER_ON_RETURN_MS.getValue();
if (lastBackgroundedTimeMillis == -1) {
// No last background timestamp set, use control behavior unless "immediate" was set.
......
......@@ -4,6 +4,8 @@
package org.chromium.chrome.browser;
import static com.google.common.truth.Truth.assertThat;
import android.content.Intent;
import android.graphics.Bitmap;
import android.support.test.filters.SmallTest;
......@@ -18,13 +20,22 @@ import org.junit.runner.RunWith;
import org.chromium.base.Callback;
import org.chromium.base.library_loader.LibraryLoader;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.Matchers;
import org.chromium.base.test.util.Restriction;
import org.chromium.chrome.browser.compositor.layouts.LayoutManagerChromePhone;
import org.chromium.chrome.browser.compositor.layouts.LayoutManagerChromeTablet;
import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
import org.chromium.chrome.browser.flags.CachedFeatureFlags;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.tasks.ReturnToChromeExperimentsUtil;
import org.chromium.chrome.features.start_surface.StartSurfaceLayout;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.chrome.test.util.browser.Features;
import org.chromium.content_public.browser.test.util.Criteria;
import org.chromium.content_public.browser.test.util.CriteriaHelper;
import org.chromium.ui.test.util.UiRestriction;
import java.io.File;
import java.io.FileNotFoundException;
......@@ -35,8 +46,14 @@ import java.io.IOException;
* Integration tests of Instant Start which requires 2-stage initialization for Clank startup.
*/
@RunWith(ChromeJUnit4ClassRunner.class)
// clang-format off
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
@Features.EnableFeatures({ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID,
ChromeFeatureList.START_SURFACE_ANDROID, ChromeFeatureList.INSTANT_START})
public class InstantStartTest {
// clang-format on
private static final String IMMEDIATE_RETURN_PARAMS = "force-fieldtrial-params=Study.Group:"
+ ReturnToChromeExperimentsUtil.TAB_SWITCHER_ON_RETURN_MS + "/0";
private Bitmap mBitmap;
private int mThumbnailFetchCount;
......@@ -48,20 +65,15 @@ public class InstantStartTest {
@Before
public void setUp() {
startMainActivityFromLauncherAndNotWaitForNative();
startMainActivityFromLauncher();
}
private void startMainActivityFromLauncherAndNotWaitForNative() {
private void startMainActivityFromLauncher() {
// Only launch Chrome.
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
mActivityTestRule.prepareUrlIntent(intent, null);
mActivityTestRule.startActivityCompletely(intent);
CriteriaHelper.pollUiThread(
()
-> mActivityTestRule.getActivity().getTabContentManager() != null,
"TabContentManager never created.");
}
private Bitmap createThumbnailBitmapAndWriteToFile(int tabId) {
......@@ -101,6 +113,12 @@ public class InstantStartTest {
mThumbnailFetchCount++;
mBitmap = bitmap;
};
CriteriaHelper.pollUiThread(Criteria.checkThat(
()
-> mActivityTestRule.getActivity().getTabContentManager(),
Matchers.notNullValue()));
TabContentManager tabContentManager =
mActivityTestRule.getActivity().getTabContentManager();
......@@ -120,4 +138,42 @@ public class InstantStartTest {
Assert.assertEquals(thumbnailBitmap.getWidth(), fetchedThumbnail.getWidth());
Assert.assertEquals(thumbnailBitmap.getHeight(), fetchedThumbnail.getHeight());
}
@Test
@SmallTest
// clang-format off
@CommandLineFlags.Add({ChromeSwitches.DISABLE_NATIVE_INITIALIZATION,
"enable-features=" + ChromeFeatureList.TAB_SWITCHER_ON_RETURN + "<Study",
"force-fieldtrials=Study/Group", IMMEDIATE_RETURN_PARAMS})
@Restriction({UiRestriction.RESTRICTION_TYPE_PHONE})
public void layoutManagerChromePhonePreNativeTest() {
// clang-format on
Assert.assertFalse(mActivityTestRule.getActivity().isTablet());
Assert.assertTrue(CachedFeatureFlags.isEnabled(ChromeFeatureList.INSTANT_START));
Assert.assertTrue(ReturnToChromeExperimentsUtil.shouldShowTabSwitcher(-1));
CriteriaHelper.pollUiThread(Criteria.checkThat(
() -> mActivityTestRule.getActivity().getLayoutManager(), Matchers.notNullValue()));
Assert.assertFalse(LibraryLoader.getInstance().isInitialized());
assertThat(mActivityTestRule.getActivity().getLayoutManager())
.isInstanceOf(LayoutManagerChromePhone.class);
assertThat(mActivityTestRule.getActivity().getLayoutManager().getOverviewLayout())
.isInstanceOf(StartSurfaceLayout.class);
}
@Test
@SmallTest
@Restriction({UiRestriction.RESTRICTION_TYPE_TABLET})
public void willInitNativeOnTabletTest() {
Assert.assertTrue(mActivityTestRule.getActivity().isTablet());
Assert.assertTrue(CachedFeatureFlags.isEnabled(ChromeFeatureList.INSTANT_START));
CriteriaHelper.pollUiThread(Criteria.checkThat(
() -> mActivityTestRule.getActivity().getLayoutManager(), Matchers.notNullValue()));
Assert.assertTrue(LibraryLoader.getInstance().isInitialized());
assertThat(mActivityTestRule.getActivity().getLayoutManager())
.isInstanceOf(LayoutManagerChromeTablet.class);
}
}
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment