Bug 1492706 - Part 2: Cover common OOM causes in the Recent tabs panel. r=nalexander, a=lizzard
authorJan Henning <jh+bugzilla@buttercookie.de>
Fri, 14 Dec 2018 21:08:32 +0000
changeset 509096 0337b9cc8e0fec27445f6ebb59c144dc6eef1b51
parent 509095 325595e085d7acfdd80ea333a9f3dba85cd3b1e6
child 509097 292715b59677a10385e02e268571930744852588
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnalexander, lizzard
bugs1492706
milestone65.0
Bug 1492706 - Part 2: Cover common OOM causes in the Recent tabs panel. r=nalexander, a=lizzard Looking at Crash Stats, the most common causes of OOMs involving the RecentTabs- Adapter happen while reading the previous session store file into memory for parsing, respectively while stringifying the parsed data back into a flat String for further storage. In the former case, we give up completely, because there's nothing we can do short of switching to a streaming JSON parser (which is out of scope for this bug), while in the latter case, we only skip the affected tab in the hope that at least some tabs might be small enough to not cause an OOM. Differential Revision: https://phabricator.services.mozilla.com/D12963
mobile/android/base/java/org/mozilla/gecko/home/RecentTabsAdapter.java
--- a/mobile/android/base/java/org/mozilla/gecko/home/RecentTabsAdapter.java
+++ b/mobile/android/base/java/org/mozilla/gecko/home/RecentTabsAdapter.java
@@ -144,17 +144,25 @@ public class RecentTabsAdapter extends R
         // If we happen to initialise before GeckoApp, waiting on either the main or the background
         // thread can lead to a deadlock, so we have to run on a separate thread instead.
         final Thread parseThread = new Thread(new Runnable() {
             @Override
             public void run() {
                 // Make sure that the start up code has had a chance to update sessionstore.old as necessary.
                 GeckoProfile.get(context).waitForOldSessionDataProcessing();
 
-                final String jsonString = GeckoProfile.get(context).readPreviousSessionFile();
+                final String jsonString;
+                try {
+                    jsonString = GeckoProfile.get(context).readPreviousSessionFile();
+                } catch (OutOfMemoryError oom) {
+                    // The file is too large, give up.
+                    // TODO: A streaming JSON parser might help by having to read only one tab at a
+                    // time.
+                    return;
+                }
                 if (jsonString == null) {
                     // No previous session data.
                     return;
                 }
 
                 final List<ClosedTab> parsedTabs = new ArrayList<>();
 
                 new SessionParser() {
@@ -162,17 +170,23 @@ public class RecentTabsAdapter extends R
                     public void onTabRead(SessionTab tab) {
                         final String url = tab.getUrl();
 
                         // Don't show last tabs for about:home
                         if (AboutPages.isAboutHome(url)) {
                             return;
                         }
 
-                        parsedTabs.add(new ClosedTab(url, tab.getTitle(), tab.getTabObject().toString()));
+                        try {
+                            parsedTabs.add(new ClosedTab(url, tab.getTitle(), tab.getTabObject().toString()));
+                        } catch (OutOfMemoryError oom) {
+                            // Stringifying may fail if the tab data is too large - let's hope that
+                            // this tab was an exception and that the next one will be smaller and
+                            // possibly succeed.
+                        }
                     }
                 }.parse(jsonString);
 
                 final ClosedTab[] closedTabs = parsedTabs.toArray(new ClosedTab[parsedTabs.size()]);
 
                 // Only modify lastSessionTabs on the UI thread.
                 ThreadUtils.postToUiThread(new Runnable() {
                     @Override