BranchMetrics / android-branch-deep-linking-attribution

The Branch Android SDK for deep linking and attribution. Branch helps mobile apps grow with deep links / deeplinks that power paid acquisition and re-engagement campaigns, referral programs, content sharing, deep linked emails, smart banners, custom user onboarding, and more.
https://docs.branch.io/pages/apps/android/
MIT License
395 stars 155 forks source link

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

Closed gdeluna-branch closed 3 months ago

gdeluna-branch commented 3 months ago

Reference

SDK-XXX -- .</p> <h2>Description</h2> <p>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.</p> <p>To mitigate the performance impact of the workaround, the fetch routines have been refactored into coroutines to be invoked at more opportune times. </p> <ul> <li><code>getUserAgentAsync</code> executes immediately <strong>after</strong> the session initialization in the background. <ul> <li>If a v2 event were immediately enqueued, the event will have a lock awaiting its completion</li> </ul></li> <li><code>getUserAgentSync</code> executes immediately <strong>before</strong> a v2 event is enqueued only if the public boolean <code>Branch.setIsUserAgentSync(true);</code> has been set </li> </ul> <p>Thereafter, the result of either operation is cached in memory as was before.</p> <p>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.</p> <h2>Testing Instructions</h2> <p>Integrate in both main thread and backgrounded implementations. The SDK should never lock up.</p> <p>Refer to logs for the following cases:</p> <h3>1. Sync True, Main thread</h3> <p>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! <strong>02:08:26.240 V Deferring userAgent string call for sync retrieval</strong> 02:08:26.240 V onInitSessionCompleted on thread main</p> <p>{send event}</p> <p>02:08:43.589 V Start invoking <strong>getUserAgentSync</strong> 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 <strong>Begin getUserAgentSync Thread[main,5,main]</strong> 02:08:43.979 V <strong>End getUserAgentSync Thread[main,5,main]</strong> 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 <strong>onUserAgentStringFetchFinished, releasing lock</strong> 02:08:43.979 V <strong>processNextQueueItem onUserAgentStringFetchFinished</strong></p> <h3>2. Sync false, Main Thread</h3> <p>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 <strong>Begin getUserAgentAsync Thread[DefaultDispatcher-worker-1,5,main]</strong> 02:20:38.638 V processNextQueueItem onPostExecuteInner 02:20:38.640 V Queue is: 02:20:39.009 V <strong>End getUserAgentAsync Thread[DefaultDispatcher-worker-1,5,main]</strong> 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 <strong>onInitSessionCompleted resumeWith userAgent</strong> 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: </p> <p>{send event}</p> <p>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 <strong>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</strong> 02:21:13.586 D handleNewRequest io.branch.referral.util.BranchEvent$1@25278e</p> <h3>3. Sync true, Background thread</h3> <p>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: </p> <p>{send event}</p> <p>02:23:35.130 V Start invoking getUserAgentSync from thread <strong>RxNewThreadScheduler-2</strong> 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 <strong>Begin getUserAgentSync Thread[main,5,main]</strong> 02:23:35.141 V processNextQueueItem handleNewRequest 02:23:35.142 V Queue is: io.branch.referral.util.BranchEvent$1@e38e414 with <strong>locks [USER_AGENT_STRING_LOCK]</strong> 02:23:35.142 D processNextQueueItem, req io.branch.referral.util.BranchEvent$1@e38e414 02:23:35.601 V <strong>End getUserAgentSync Thread[main,5,main]</strong> 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 <strong>onUserAgentStringFetchFinished, releasing lock</strong></p> <p>{send event 2}</p> <p>02:27:03.399 V <strong>userAgent was cached</strong>: 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 <strong>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</strong> 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 <strong>with locks []</strong></p> <h3>4. Sync false, Background thread</h3> <p>02:35:39.574 V onInitSessionCompleted on thread main 02:35:39.574 V <strong>Begin getUserAgentAsync Thread[DefaultDispatcher-worker-1,5,main]</strong> 02:35:39.608 V processNextQueueItem onPostExecuteInner 02:35:39.609 V Queue is: 02:35:40.041 V <strong>End getUserAgentAsync Thread[DefaultDispatcher-worker-1,5,main]</strong> 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 <strong>thread DefaultDispatcher-worker-1</strong></p> <p>{send event}</p> <p>02:36:06.028 V <strong>userAgent was cached</strong>: 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 <strong>Preparing V2 event, user agent is</strong> 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 <strong>locks []</strong></p> <h2>Risk Assessment [<code>LOW</code>]</h2> <!-- CHOOSE ONE OF THE THREE ASSESSMENTS ABOVE --> <!-- FOR MEDIUM OR HIGH ASSESSMENTS, ADD ADDITIONAL NOTES HERE --> <ul> <li>[x] I, the PR creator, have tested — integration, unit, or otherwise — this code.</li> </ul> <h2>Reviewer Checklist (To be checked off by the reviewer only)</h2> <ul> <li>[ ] JIRA Ticket is referenced in PR title.</li> <li>Correctness & Style <ul> <li>[ ] Conforms to <a rel="noreferrer nofollow" target="_blank" href="https://source.android.com/setup/contribute/code-style">AOSP Style Guides</a></li> <li>[ ] Mission critical pieces are documented in code and out of code as needed.</li> </ul></li> <li>[ ] Unit Tests reviewed and test issue sufficiently.</li> <li>[ ] Functionality was reviewed in QA independently by another engineer on the team.</li> </ul> <p>cc @BranchMetrics/saas-sdk-devs for visibility.</p> </div> </div> <div class="comment"> <div class="user"> <a rel="noreferrer nofollow" target="_blank" href="https://github.com/codecov[bot]"><img src="https://avatars.githubusercontent.com/in/254?v=4" />codecov[bot]</a> commented <strong> 3 months ago</strong> </div> <div class="markdown-body"> <h2><a href="https://app.codecov.io/gh/BranchMetrics/android-branch-deep-linking-attribution/pull/1181?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=BranchMetrics">Codecov</a> Report</h2> <p>Attention: Patch coverage is <code>55.22388%</code> with <code>30 lines</code> in your changes are missing coverage. Please review.</p> <blockquote> <p>Project coverage is 38.24%. Comparing base <a href="https://app.codecov.io/gh/BranchMetrics/android-branch-deep-linking-attribution/commit/1b6bb47562123ef98f295501d616fac988f63443?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=BranchMetrics">(<code>1b6bb47</code>)</a> to head <a href="https://app.codecov.io/gh/BranchMetrics/android-branch-deep-linking-attribution/pull/1181?dropdown=coverage&src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=BranchMetrics">(<code>103722e</code>)</a>.</p> </blockquote> <table> <thead> <tr> <th><a href="https://app.codecov.io/gh/BranchMetrics/android-branch-deep-linking-attribution/pull/1181?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=BranchMetrics">Files</a></th> <th>Patch %</th> <th>Lines</th> </tr> </thead> <tbody> <tr> <td><a href="https://app.codecov.io/gh/BranchMetrics/android-branch-deep-linking-attribution/pull/1181?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=BranchMetrics#diff-QnJhbmNoLVNESy9zcmMvbWFpbi9qYXZhL2lvL2JyYW5jaC9yZWZlcnJhbC9EZXZpY2VJbmZvLmphdmE=">...K/src/main/java/io/branch/referral/DeviceInfo.java</a></td> <td>48.64%</td> <td><a href="https://app.codecov.io/gh/BranchMetrics/android-branch-deep-linking-attribution/pull/1181?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=BranchMetrics">17 Missing and 2 partials :warning: </a></td> </tr> <tr> <td><a href="https://app.codecov.io/gh/BranchMetrics/android-branch-deep-linking-attribution/pull/1181?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=BranchMetrics#diff-QnJhbmNoLVNESy9zcmMvbWFpbi9qYXZhL2lvL2JyYW5jaC9yZWZlcnJhbC91dGlsL0JyYW5jaEV2ZW50LmphdmE=">...main/java/io/branch/referral/util/BranchEvent.java</a></td> <td>53.33%</td> <td><a href="https://app.codecov.io/gh/BranchMetrics/android-branch-deep-linking-attribution/pull/1181?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=BranchMetrics">6 Missing and 1 partial :warning: </a></td> </tr> <tr> <td><a href="https://app.codecov.io/gh/BranchMetrics/android-branch-deep-linking-attribution/pull/1181?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=BranchMetrics#diff-QnJhbmNoLVNESy9zcmMvbWFpbi9qYXZhL2lvL2JyYW5jaC9yZWZlcnJhbC9TZXJ2ZXJSZXF1ZXN0SW5pdFNlc3Npb24uamF2YQ==">...a/io/branch/referral/ServerRequestInitSession.java</a></td> <td>72.72%</td> <td><a href="https://app.codecov.io/gh/BranchMetrics/android-branch-deep-linking-attribution/pull/1181?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=BranchMetrics">1 Missing and 2 partials :warning: </a></td> </tr> <tr> <td><a href="https://app.codecov.io/gh/BranchMetrics/android-branch-deep-linking-attribution/pull/1181?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=BranchMetrics#diff-QnJhbmNoLVNESy9zcmMvbWFpbi9qYXZhL2lvL2JyYW5jaC9yZWZlcnJhbC9CcmFuY2guamF2YQ==">...h-SDK/src/main/java/io/branch/referral/Branch.java</a></td> <td>50.00%</td> <td><a href="https://app.codecov.io/gh/BranchMetrics/android-branch-deep-linking-attribution/pull/1181?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=BranchMetrics">1 Missing :warning: </a></td> </tr> </tbody> </table> <details><summary>Additional details and impacted files</summary> ```diff @@ 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 ``` </details> <p><a href="https://app.codecov.io/gh/BranchMetrics/android-branch-deep-linking-attribution/pull/1181?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=BranchMetrics">:umbrella: View full report in Codecov by Sentry</a>.<br /> :loudspeaker: Have feedback on the report? <a href="https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=BranchMetrics">Share it here</a>.</p> </div> </div> <div class="comment"> <div class="user"> <a rel="noreferrer nofollow" target="_blank" href="https://github.com/echo-branch"><img src="https://avatars.githubusercontent.com/u/43450805?v=4" />echo-branch</a> commented <strong> 3 months ago</strong> </div> <div class="markdown-body"> <p>Can we also add a performance test as well. Just to stress test the API.</p> </div> </div> <div class="comment"> <div class="user"> <a rel="noreferrer nofollow" target="_blank" href="https://github.com/gdeluna-branch"><img src="https://avatars.githubusercontent.com/u/94577415?v=4" />gdeluna-branch</a> commented <strong> 3 months ago</strong> </div> <div class="markdown-body"> <blockquote> <p>Can we also add a performance test as well. Just to stress test the API.</p> </blockquote> <p>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. </p> <p>(Although subsequent executions were much much faster. It's still redundant and on dispatcher main)</p> </div> </div> <div class="page-bar-simple"> </div> <div class="footer"> <ul class="body"> <li>© <script> document.write(new Date().getFullYear()) </script> Githubissues.</li> <li>Githubissues is a development platform for aggregating issues.</li> </ul> </div> <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.min.js"></script> <script src="/githubissues/assets/js.js"></script> <script src="/githubissues/assets/markdown.js"></script> <script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.4.0/build/highlight.min.js"></script> <script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.4.0/build/languages/go.min.js"></script> <script> hljs.highlightAll(); </script> </body> </html>