Skip to content
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

Move optional synchronous user agent fetch out of start up #1181

Merged
merged 6 commits into from
Mar 27, 2024

Conversation

gdeluna-branch
Copy link
Contributor

@gdeluna-branch gdeluna-branch commented Mar 25, 2024

Reference

SDK-XXX -- <TITLE>.

Description

Due to an external bug, an alternative to the original user agent string method was introduced to mitigate these crashes. However, the alternative method had some impact on app start up due to the limitation that it needed the main thread in order to access webview instance's settings.

To mitigate the performance impact of the workaround, the fetch routines have been refactored into coroutines to be invoked at more opportune times.

  • getUserAgentAsync executes immediately after the session initialization in the background.
    • If a v2 event were immediately enqueued, the event will have a lock awaiting its completion
  • getUserAgentSync executes immediately before a v2 event is enqueued only if the public boolean Branch.setIsUserAgentSync(true); has been set

Thereafter, the result of either operation is cached in memory as was before.

Because of the queueing mechanism, regardless of the thread, the request object must still be alerted when an operation completes. This is done in the continuation from the coroutines. Regardless of the result of the fetch, either a valid string or null, the lock is removed to not dead lock the SDK.

Testing Instructions

Integrate in both main thread and backgrounded implementations. The SDK should never lock up.

Refer to logs for the following cases:

1. Sync True, Main thread

02:08:26.237 V Queue is: io.branch.referral.ServerRequestRegisterOpen@92ddee5 with locks []
02:08:26.237 V onRequestSucceeded io.branch.referral.ServerRequestRegisterOpen@92ddee5 io.branch.referral.ServerResponse@b7afecc on callback io.branch.referral.BranchUniversalReferralInitWrapper@283f6b0
02:08:26.239 D branch init complete!
02:08:26.240 V Deferring userAgent string call for sync retrieval
02:08:26.240 V onInitSessionCompleted on thread main

{send event}

02:08:43.589 V Start invoking getUserAgentSync from thread main
02:08:43.597 V Preparing V2 event, user agent is
02:08:43.597 V handleNewRequest adding process wait lock USER_AGENT_STRING_LOCK
02:08:43.598 D handleNewRequest io.branch.referral.util.BranchEvent$1@6ca2d85
02:08:43.603 V processNextQueueItem handleNewRequest
02:08:43.604 V Queue is: io.branch.referral.util.BranchEvent$1@6ca2d85 with locks [USER_AGENT_STRING_LOCK]
02:08:43.604 D processNextQueueItem, req io.branch.referral.util.BranchEvent$1@6ca2d85
02:08:43.606 V Begin getUserAgentSync Thread[main,5,main]
02:08:43.979 V End getUserAgentSync Thread[main,5,main] Mozilla/5.0 (Linux; Android 14; sdk_gphone64_x86_64 Build/UE1A.230829.036.A1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/122.0.6261.120 Mobile Safari/537.36
02:08:43.979 V onUserAgentStringFetchFinished, releasing lock
02:08:43.979 V processNextQueueItem onUserAgentStringFetchFinished

2. Sync false, Main Thread

02:20:38.631 V onRequestSucceeded io.branch.referral.ServerRequestRegisterOpen@9f3ebc8 io.branch.referral.ServerResponse@1b41e1b on callback io.branch.referral.BranchUniversalReferralInitWrapper@b6ad24f
02:20:38.635 D branch init complete!
02:20:38.638 V onInitSessionCompleted on thread main
02:20:38.638 V Begin getUserAgentAsync Thread[DefaultDispatcher-worker-1,5,main]
02:20:38.638 V processNextQueueItem onPostExecuteInner
02:20:38.640 V Queue is:
02:20:39.009 V End getUserAgentAsync Thread[DefaultDispatcher-worker-1,5,main] Mozilla/5.0 (Linux; Android 14; sdk_gphone64_x86_64 Build/UE1A.230829.036.A1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/122.0.6261.120 Mobile Safari/537.36
02:20:39.009 V onInitSessionCompleted resumeWith userAgent Mozilla/5.0 (Linux; Android 14; sdk_gphone64_x86_64 Build/UE1A.230829.036.A1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/122.0.6261.120 Mobile Safari/537.36 on thread DefaultDispatcher-worker-1
02:20:39.009 V processNextQueueItem getUserAgentAsync resumeWith
02:20:39.009 V Queue is:

{send event}

02:21:13.581 V userAgent was cached: Mozilla/5.0 (Linux; Android 14; sdk_gphone64_x86_64 Build/UE1A.230829.036.A1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/122.0.6261.120 Mobile Safari/537.36
02:21:13.581 V processNextQueueItem setPostUserAgent
02:21:13.581 V Queue is:
02:21:13.585 V Preparing V2 event, user agent is Mozilla/5.0 (Linux; Android 14; sdk_gphone64_x86_64 Build/UE1A.230829.036.A1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/122.0.6261.120 Mobile Safari/537.36
02:21:13.586 D handleNewRequest io.branch.referral.util.BranchEvent$1@25278e

3. Sync true, Background thread

02:23:14.740 V Deferring userAgent string call for sync retrieval
02:23:14.743 V onInitSessionCompleted on thread main
02:23:14.745 V processNextQueueItem onPostExecuteInner
02:23:14.746 V Queue is:

{send event}

02:23:35.130 V Start invoking getUserAgentSync from thread RxNewThreadScheduler-2
02:23:35.138 V Preparing V2 event, user agent is
02:23:35.138 V handleNewRequest adding process wait lock USER_AGENT_STRING_LOCK
02:23:35.139 D handleNewRequest io.branch.referral.util.BranchEvent$1@e38e414
02:23:35.140 V Begin getUserAgentSync Thread[main,5,main]
02:23:35.141 V processNextQueueItem handleNewRequest
02:23:35.142 V Queue is: io.branch.referral.util.BranchEvent$1@e38e414 with locks [USER_AGENT_STRING_LOCK]
02:23:35.142 D processNextQueueItem, req io.branch.referral.util.BranchEvent$1@e38e414
02:23:35.601 V End getUserAgentSync Thread[main,5,main] Mozilla/5.0 (Linux; Android 14; sdk_gphone64_x86_64 Build/UE1A.230829.036.A1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/122.0.6261.120 Mobile Safari/537.36
02:23:35.602 V onUserAgentStringFetchFinished, releasing lock

{send event 2}

02:27:03.399 V userAgent was cached: Mozilla/5.0 (Linux; Android 14; sdk_gphone64_x86_64 Build/UE1A.230829.036.A1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/122.0.6261.120 Mobile Safari/537.36
02:27:03.401 V processNextQueueItem setPostUserAgent
02:27:03.402 V Queue is:
02:27:03.409 V Preparing V2 event, user agent is Mozilla/5.0 (Linux; Android 14; sdk_gphone64_x86_64 Build/UE1A.230829.036.A1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/122.0.6261.120 Mobile Safari/537.36
02:27:03.409 D handleNewRequest io.branch.referral.util.BranchEvent$1@8e0cc59
02:27:03.414 V processNextQueueItem handleNewRequest
02:27:03.415 V Queue is: io.branch.referral.util.BranchEvent$1@8e0cc59 with locks []

4. Sync false, Background thread

02:35:39.574 V onInitSessionCompleted on thread main
02:35:39.574 V Begin getUserAgentAsync Thread[DefaultDispatcher-worker-1,5,main]
02:35:39.608 V processNextQueueItem onPostExecuteInner
02:35:39.609 V Queue is:
02:35:40.041 V End getUserAgentAsync Thread[DefaultDispatcher-worker-1,5,main] Mozilla/5.0 (Linux; Android 14; sdk_gphone64_x86_64 Build/UE1A.230829.036.A1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/122.0.6261.120 Mobile Safari/537.36
02:35:40.042 V onInitSessionCompleted resumeWith userAgent Mozilla/5.0 (Linux; Android 14; sdk_gphone64_x86_64 Build/UE1A.230829.036.A1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/122.0.6261.120 Mobile Safari/537.36 on thread DefaultDispatcher-worker-1

{send event}

02:36:06.028 V userAgent was cached: Mozilla/5.0 (Linux; Android 14; sdk_gphone64_x86_64 Build/UE1A.230829.036.A1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/122.0.6261.120 Mobile Safari/537.36
02:36:06.028 V processNextQueueItem setPostUserAgent
02:36:06.029 V Queue is:
02:36:06.039 V Preparing V2 event, user agent is Mozilla/5.0 (Linux; Android 14; sdk_gphone64_x86_64 Build/UE1A.230829.036.A1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/122.0.6261.120 Mobile Safari/537.36
02:36:06.040 D handleNewRequest io.branch.referral.util.BranchEvent$1@b68c11a
02:36:06.042 V processNextQueueItem handleNewRequest
02:36:06.043 V Queue is: io.branch.referral.util.BranchEvent$1@b68c11a with locks []

Risk Assessment [LOW]

  • I, the PR creator, have tested — integration, unit, or otherwise — this code.

Reviewer Checklist (To be checked off by the reviewer only)

  • JIRA Ticket is referenced in PR title.
  • Correctness & Style
    • Conforms to AOSP Style Guides
    • Mission critical pieces are documented in code and out of code as needed.
  • Unit Tests reviewed and test issue sufficiently.
  • Functionality was reviewed in QA independently by another engineer on the team.

cc @BranchMetrics/saas-sdk-devs for visibility.

Copy link

codecov bot commented Mar 26, 2024

Codecov Report

Attention: Patch coverage is 55.22388% with 30 lines in your changes are missing coverage. Please review.

Project coverage is 38.24%. Comparing base (1b6bb47) to head (103722e).

Files Patch % Lines
...K/src/main/java/io/branch/referral/DeviceInfo.java 48.64% 17 Missing and 2 partials ⚠️
...main/java/io/branch/referral/util/BranchEvent.java 53.33% 6 Missing and 1 partial ⚠️
...a/io/branch/referral/ServerRequestInitSession.java 72.72% 1 Missing and 2 partials ⚠️
...h-SDK/src/main/java/io/branch/referral/Branch.java 50.00% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master    #1181      +/-   ##
============================================
+ Coverage     38.11%   38.24%   +0.13%     
+ Complexity      689      687       -2     
============================================
  Files            59       59              
  Lines          6279     6309      +30     
  Branches        939      944       +5     
============================================
+ Hits           2393     2413      +20     
- Misses         3443     3448       +5     
- Partials        443      448       +5     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@gdeluna-branch gdeluna-branch changed the title WIP: Move optional synchronous user agent fetch out of start up Move optional synchronous user agent fetch out of start up Mar 26, 2024
@echo-branch
Copy link
Contributor

Can we also add a performance test as well. Just to stress test the API.

Copy link
Contributor

@NidhiDixit09 NidhiDixit09 left a comment

Choose a reason for hiding this comment

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

Code Looks Good to me.
I have validated all four cases Sync True/False, Main thread / Background Thread. Output in logs is macthing with the logs mentioned here.
Note: I have called Branch.setIsUserAgentSync(true); before creating Branch Instance.

@gdeluna-branch
Copy link
Contributor Author

gdeluna-branch commented Mar 26, 2024

Can we also add a performance test as well. Just to stress test the API.

Thanks for the suggestion, adding tests preemptively enqueuing several events, I see the dispatcher had already enqueued each coroutine and executed them all one by one. I'll make an optimization.

(Although subsequent executions were much much faster. It's still redundant and on dispatcher main)

@echo-branch echo-branch self-requested a review March 27, 2024 21:37
@gdeluna-branch gdeluna-branch merged commit 72e3d1d into master Mar 27, 2024
7 of 8 checks passed
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.

4 participants