From 4939f3c0988bced525dc76c033aa6e46ecbc25e5 Mon Sep 17 00:00:00 2001 From: Serg Date: Mon, 23 Feb 2026 17:05:42 -0500 Subject: [PATCH] [Android] Fix NPE in HomeSurfaceTracker on activity resume (#34114) Pass a temporary no-op HomeSurfaceTracker when mHomeSurfaceTracker is null during warm startup to prevent the NPE in upstream's setInitialOverviewStateOnResumeWithNtp. This can happen on activity recreate (rotation, process death, foldable transitions) where onResumeWithNative fires before the tracker is initialized. Resolves: https://github.com/brave/brave-browser/issues/53071 --- android/java/apk_for_test.flags | 2 +- .../tasks/BraveReturnToChromeUtil.java | 39 +++++++++++++++---- .../chromium/chrome/browser/BytecodeTest.java | 11 ++++-- .../BraveReturnToChromeUtilClassAdapter.java | 2 +- 4 files changed, 41 insertions(+), 13 deletions(-) diff --git a/android/java/apk_for_test.flags b/android/java/apk_for_test.flags index 8ff675c3d02..71268116454 100644 --- a/android/java/apk_for_test.flags +++ b/android/java/apk_for_test.flags @@ -653,7 +653,7 @@ -keep class org.chromium.chrome.browser.tasks.ReturnToChromeUtil { *** shouldShowNtpAsHomeSurfaceAtStartup(...); *** createNewTabAndShowHomeSurfaceUi(...); - *** showHomeSurfaceUiOnNtp(...); + *** setInitialOverviewStateOnResumeWithNtp(...); } -keep class org.chromium.chrome.browser.IntentHandler { diff --git a/android/java/org/chromium/chrome/browser/tasks/BraveReturnToChromeUtil.java b/android/java/org/chromium/chrome/browser/tasks/BraveReturnToChromeUtil.java index 597080b8253..84105c49798 100644 --- a/android/java/org/chromium/chrome/browser/tasks/BraveReturnToChromeUtil.java +++ b/android/java/org/chromium/chrome/browser/tasks/BraveReturnToChromeUtil.java @@ -17,6 +17,7 @@ import org.chromium.chrome.browser.ntp.BraveFreshNtpHelper; import org.chromium.chrome.browser.preferences.ChromeSharedPreferences; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.TabCreator; +import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.url.GURL; @@ -149,15 +150,39 @@ public final class BraveReturnToChromeUtil { } /** - * Shows the home surface UI on the given NTP. This is a wrapper around the upstream method that - * adds a null check for homeSurfaceTracker to prevent crashes when the tracker is not - * initialized. + * Sets the initial overview state on resume with NTP. Wraps the upstream method to handle the + * case where homeSurfaceTracker is null (not yet initialized during warm startup). When null, + * we pass a temporary no-op HomeSurfaceTracker to avoid the NPE in upstream's + * homeSurfaceTracker.isHomeSurfaceTab() call. This is safe because the temporary tracker's + * isHomeSurfaceTab() always returns false (no home surface tab set), which causes upstream to + * call updateHomeSurfaceAndTrackingTabs() on the throwaway instance — effectively a no-op that + * doesn't interfere with the real tracker created later in ChromeTabbedActivity initialization. + * The no-op tracker is also safe when passed through to upstream's showHomeSurfaceUiOnNtp() and + * createNewTabAndShowHomeSurfaceUi() in the else branch — those methods only call + * updateHomeSurfaceAndTrackingTabs() on it, which again just sets fields on the throwaway. The + * real tracker (ChromeTabbedActivity.mHomeSurfaceTracker) is created independently and flows + * into NewTabPage via NativePageFactory, so subsequent reads are unaffected. + * + *

Note: unlike upstream's shouldShowNtpAsHomeSurfaceAtStartup which bails out on activity + * recreate (isFromRecreate check), we intentionally allow the NTP to show in recreate scenarios + * (e.g., rotation, process death restore, foldable transitions). This is because our + * inactivity-based NTP logic should still apply — if the user was away for 1+ hours, we want + * the NTP shown regardless of whether the activity was recreated on return. */ - static void showHomeSurfaceUiOnNtp( - Tab ntpTab, Tab lastActiveTab, @Nullable HomeSurfaceTracker homeSurfaceTracker) { + public static boolean setInitialOverviewStateOnResumeWithNtp( + boolean isIncognito, + boolean shouldShowNtpHomeSurfaceOnStartup, + TabModel currentTabModel, + TabCreator tabCreator, + @Nullable HomeSurfaceTracker homeSurfaceTracker) { if (homeSurfaceTracker == null) { - return; + homeSurfaceTracker = new HomeSurfaceTracker(); } - ReturnToChromeUtil.showHomeSurfaceUiOnNtp(ntpTab, lastActiveTab, homeSurfaceTracker); + return ReturnToChromeUtil.setInitialOverviewStateOnResumeWithNtp( + isIncognito, + shouldShowNtpHomeSurfaceOnStartup, + currentTabModel, + tabCreator, + homeSurfaceTracker); } } diff --git a/android/javatests/org/chromium/chrome/browser/BytecodeTest.java b/android/javatests/org/chromium/chrome/browser/BytecodeTest.java index 8f2771bbb05..92f23838e92 100644 --- a/android/javatests/org/chromium/chrome/browser/BytecodeTest.java +++ b/android/javatests/org/chromium/chrome/browser/BytecodeTest.java @@ -131,6 +131,7 @@ import org.chromium.chrome.browser.tabmodel.AsyncTabParamsManager; import org.chromium.chrome.browser.tabmodel.IncognitoStateProvider; import org.chromium.chrome.browser.tabmodel.TabCreator; import org.chromium.chrome.browser.tabmodel.TabCreatorManager; +import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tasks.HomeSurfaceTracker; import org.chromium.chrome.browser.tasks.tab_management.TabGroupCreationUiDelegate; @@ -751,11 +752,13 @@ public class BytecodeTest { Assert.assertTrue( methodExists( "org/chromium/chrome/browser/tasks/ReturnToChromeUtil", - "showHomeSurfaceUiOnNtp", + "setInitialOverviewStateOnResumeWithNtp", MethodModifier.STATIC, - void.class, - Tab.class, - Tab.class, + boolean.class, + boolean.class, + boolean.class, + TabModel.class, + TabCreator.class, HomeSurfaceTracker.class)); Assert.assertTrue( methodExists( diff --git a/build/android/bytecode/java/org/brave/bytecode/BraveReturnToChromeUtilClassAdapter.java b/build/android/bytecode/java/org/brave/bytecode/BraveReturnToChromeUtilClassAdapter.java index 574792de619..6e850028319 100644 --- a/build/android/bytecode/java/org/brave/bytecode/BraveReturnToChromeUtilClassAdapter.java +++ b/build/android/bytecode/java/org/brave/bytecode/BraveReturnToChromeUtilClassAdapter.java @@ -28,7 +28,7 @@ public class BraveReturnToChromeUtilClassAdapter extends BraveClassVisitor { changeMethodOwner( sReturnToChromeUtilClassName, - "showHomeSurfaceUiOnNtp", + "setInitialOverviewStateOnResumeWithNtp", sBraveReturnToChromeUtilClassName); } }