Skip to content

Conversation

@CDRussell
Copy link
Member

@CDRussell CDRussell commented Jul 23, 2018

Task/Issue URL: https://app.asana.com/0/488551667048375/533891143524678
Tech Design URL:
CC:

Description:
Attempting to save the WebView's state using the usual Android state saving mechanism can fail with a TransactionTooLargeException. This will happen when the underlying Bundle exceeds a certain size. The size isn't well documented but can be anecdotally anywhere between 500KB and 1MB. This type of exception is dominating our crash reports.

This PR stops using the normal Android state saving mechanism, and reverts to an in-memory LRU cache instead. We have chosen 10MiB max cache size (after which WebView history for least recently used tabs will start becoming inaccessible).

Steps to test this PR:

Testing - happy path

  1. Browse to a page,
  2. Browse to another.
  3. Hit the HOME button once loaded
  4. Return to the app. Ensure the previous page is reloaded and the rough scroll position is restored.
  5. Hit the BACK button. Verify the previous page is loaded (and that you don't just land on the new tab screen)
  6. Add in multiple tabs and repeat the above - ensuring things work as expected while there is enough room in the cache.

Testing - less happy path

  1. You might want to manually lower the cache size to test this PR out. See WebViewSessionInMemoryStorage.CACHE_SIZE for this value. Recommend setting it to around 5KB for testing (empirically, each visited site might add around 1KB to the size)
  2. Additionally, you might want to get Android to throw out all Activities as soon you leave them from developer settings to force the state saving to kick in.
  3. Monitor logcat for output given by WebViewSessionInMemoryStorage class - this will tell you what the size of the cache is and let you see how close you are to exhausting it.
  4. Repeat the steps from the happy path, above. This time however, deliberately exhaust the cache.
  5. When you bring the app to the foreground, verify that the previous page is loaded
  6. This time, you should notice that you can't return to your previous pages in history. They are gone; we ran out of room in the cache to store the history. So we'll reload their previous page but they'll lose their browsing history.

Internal references:

Software Engineering Expectations
Technical Design Template

@CDRussell CDRussell requested review from brindy and subsymbolic July 23, 2018 15:38
@subsymbolic subsymbolic self-assigned this Jul 24, 2018
Copy link
Contributor

@subsymbolic subsymbolic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work


class WebViewSessionInMemoryStorage : WebViewSessionStorage {

private val map = object: LruCache<String, Bundle>(CACHE_SIZE) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we rename map to cache?


/**
* We can calculate this however we choose, but it should match up with the value we use for cache size.
* i.e., if we specify max cache size in bytes, we should calculate an approximate size of the cache entry in bytes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't really know what you meant by this comment so I looked up the documentation. Is it worth updating? I have something like this in mind:
Size of a single entry. Refer to the documentation for details on the relationship between size and the max size set in the constructor

}

companion object {
private const val CACHE_SIZE = 10 * 1024 * 1024 // 10 MB
Copy link
Contributor

@subsymbolic subsymbolic Jul 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we change the comment to \\ 10 MiB?

Copy link
Contributor

@subsymbolic subsymbolic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great. Do you want to hold off merging until @brindy has given it a test too?

* We can calculate this however we choose, but it should match up with the value we use for cache size.
* i.e., we specify the max cache size in bytes, so we need to calculate an approximate size of the cache entry in bytes.
* Size (in bytes) of a single entry in the cache for the given key.
* We specify the max cache size in bytes, so we need to calculate an approximate size of the cache entry in bytes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@CDRussell
Copy link
Member Author

CDRussell commented Jul 24, 2018

Do you want to hold off merging until @brindy has given it a test too?

Yup, sounds good.

Copy link
Contributor

@brindy brindy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

I also tested with "don't keep activities" turned on

@CDRussell CDRussell merged commit f44b192 into develop Jul 25, 2018
@CDRussell CDRussell deleted the feature/bug_fix_webview_state_too_large branch July 25, 2018 10:29
subsymbolic pushed a commit that referenced this pull request Jul 26, 2018
* Store last seen global state; likely a small bug that we weren't already

* Wire tab activity and FireDialog to delete web view sessions

* Formatting

* Update cache size comment to indicate 10 MiB instead of 10 MB

* Change variable name from map to cache

* Improve comment on sizeOf function
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants