-
Notifications
You must be signed in to change notification settings - Fork 134
Fix UserAgent ANR - Take 2 #14431
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
Fix UserAgent ANR - Take 2 #14431
Conversation
Generated by 🚫 Danger |
private const val APP_VERSION = "1.0" | ||
|
||
@OptIn(ExperimentalCoroutinesApi::class) | ||
@RunWith(RobolectricTestRunner::class) | ||
class UserAgentTest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The unit tests are broken now, I updated them when I implemented Option 1, but now they will fail, I will fix then when we agree on the approach.
📲 You can test the changes from this Pull Request in WooCommerce-Wear Android by scanning the QR code below to install the corresponding build.
|
📲 You can test the changes from this Pull Request in WooCommerce Android by scanning the QR code below to install the corresponding build.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the idea here is to use two UserAgent variants:
This sounds good to me 👍
I can't say I fully understood the AwDataDirLock
issue (I read the attached comment from the tracker, but still) or how moving to the background thread could increase this, but having two user agents sound to me like a completely valid approach to test.
I forgot to reply yesterday 🤦♂️. Thanks for clearly summarizing your findings @hichamboushaba! I also think testing the two-agents approach is worth a shot. |
Same as shared by Wojtek. I didn't really get the reasons why the last time moving the UserAgent initialization to the background led to the crashes. In any case, the 2 userAgents approach sounds like a good approach to test. |
Thank you all for the input, just regarding this, I'll try to explain further my theory here.
This is just a theory, and I can't prove it, but it seems to match what we had, as all the crashes happened after a The PR is now ready for review. |
We'll save the user agent to SharedPreferences, and then load it from them on subsequent launches. We'll keep the value up-to-date by lazy call to `WebSettings.getDefaultUserAgent` hoping this would avoid the race conditions leading to the `AwDataDirLock` crash.
We now have two userAgents, one used for API calls, and one for the WebView. The one used in API calls uses the `http.agent` property, to avoid ANRs caused by `WebSettings.getDefaultUserAgent`
4a3f4d6
to
87ac35a
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## trunk #14431 +/- ##
============================================
- Coverage 37.95% 37.95% -0.01%
+ Complexity 9188 9187 -1
============================================
Files 1989 1989
Lines 112311 112316 +5
Branches 14814 14815 +1
============================================
- Hits 42630 42629 -1
- Misses 65799 65804 +5
- Partials 3882 3883 +1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
} | ||
|
||
override fun toString(): String = userAgent | ||
override fun toString(): String = apiUserAgent |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any reason to keep this? Its unused.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure it's really unused? I left it because I'm not entirely sure it's not used somewhere, AS find usages
doesn't work well here, because it's an overriden function.
If we can confirm it's unused, I also prefer to have a better toString
implementation here, or to get rid of the implementation completely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work @hichamboushaba, everything works as expected and code looks good. I just left a minor suggestion but nothing blocking.
Closes WOOMOB-968
Description
This PR is a second attempt to try to fix the UserAgent ANR, as a reminder, this is an ANR that occurs when calling
WebSettings.getDefaultUserAgent
, we call this on theUserAgent#init
, which happens on app launch, and sometimes it results in a background ANR. This is a known issue for Google, as the call is heavy, and they suggest making it on a background thread to avoid blocking the main thread, something that we tried on the first attempt, but it resulted in another WebView crash (peaMlT-Tk-p2), and we had to revert our fix.My unproved theory for the crash is that the usage of the background thread in the
UserAgent#init
increased the chances for the stuck process situation that's explained here, and thus leading theAwDataDirLock
crashes.Now, we need to take a different approach for the fix, and I'll list the options we have to discuss and pick the better one:
Option 1: Use two UserAgent variants, one for API requests and one for WebView
My understanding is that for the API requests, the most important part of the UserAgent is just the app name and version, as the other parts of the UserAgent are more important when viewing HTML content where the web server might need to adapt the content depending on the WebView capabilities.
So based on the above, the idea here is to use two UserAgent variants:
http.agent
, this is the default UserAgent of the device before adding the WebView parts, and it's the default value used byHttpUrlConnection
WebSettings.getDefaultUserAgent
as then it will be called on foreground when the WebView is being initialized, and it will generally be fine.For comparison, with this change, and with an emulator running Android 15, we'll use the following values:
apiUserAgent='Dalvik/2.1.0 (Linux; U; Android 15; sdk_gphone64_arm64 Build/AE3A.240806.043) wc-android/22.9-rc-2'
webViewUserAgent='Mozilla/5.0 (Linux; Android 15; sdk_gphone64_arm64 Build/AE3A.240806.043; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/124.0.6367.219 Mobile Safari/537.36 wc-android/22.9-rc-2'
Option 2: Use SharedPreferences for caching the UserAgent.
(This was the initial approach I used in this PR; check it in commit c74f359. After further research on
AwDataDirLock
and considering the shared theory above, I believe this could cause the same crashes. Sharing for discussion only)In this approach, SharedPreferences will serve as a cache for the value. The plan is to load the initial value from SharedPreferences and then, after a set delay, update the cache (in case WebView has been updated).
The key factor in this fix is the delay before calling
WebSettings.getDefaultUserAgent
. When crashes related toAwDataDirLock
occurred, we believe they mainly happened during app startup, as there were no encrypted logs available (edit: still confused about the lack of logs, but I'm not convinced it means necessarily app startup).Option 3: Use SharedPreferences for caching the UserAgent 2
(This is a third option that's similar to Option 2, but which could be more robust, I didn't implement it just because Option 1 seemed simpler, I can implement it if we believe keeping the same UserAgent value for both API requests and the WebView is beneficial.)
In this option, we'll use the SharedPreferences as cache, but we'll make sure to call
WebSettings.getDefaultUserAgent
only when the app is going to foreground, when the app is going to foreground, there are less chances of keeping the process stuck, as the app will be given higher priority by the system. To achieve this, we can useProcessLifecycleOwner
and invoke the loading of the UserAgent when the app reaches theStarted
state.@JorgeMucientes @malinajirka @wzieba pinging you as you have more context on this issue given the discussions on Linear, please share your thoughts on the suggested approaches.
Testing information
API requests
<http.agent> wc-android/<version>
WebView
The tests that have been performed
The above.
RELEASE-NOTES.txt
if necessary. Use the "[Internal]" label for non-user-facing changes.