-
-
Notifications
You must be signed in to change notification settings - Fork 356
fix(session-replay): Fixes orientation change misalignment for session replay on Android #5321
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
Conversation
|
@romtsn I took the liberty of adding you as a reviewer too since you have more context on the internals of SR on Android 🙇 |
packages/core/android/src/main/java/io/sentry/react/RNSentryReactFragmentLifecycleTracer.java
Outdated
Show resolved
Hide resolved
Android (legacy) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| c94a927+dirty | 366.16 ms | 375.68 ms | 9.52 ms |
| 77061ed+dirty | 369.55 ms | 408.35 ms | 38.80 ms |
| 3bd3f0d+dirty | 447.21 ms | 472.31 ms | 25.10 ms |
| 93137d1+dirty | 400.15 ms | 424.74 ms | 24.59 ms |
| bc9680d | 375.15 ms | 401.12 ms | 25.97 ms |
| 7be1f99 | 454.83 ms | 461.36 ms | 6.53 ms |
| bfe454a+dirty | 573.44 ms | 579.46 ms | 6.02 ms |
| 955f2eb+dirty | 422.74 ms | 410.19 ms | -12.55 ms |
| 6a70a7e+dirty | 381.72 ms | 413.94 ms | 32.22 ms |
| 95aaf8a | 437.89 ms | 419.45 ms | -18.44 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| c94a927+dirty | 17.75 MiB | 19.70 MiB | 1.95 MiB |
| 77061ed+dirty | 17.75 MiB | 19.68 MiB | 1.94 MiB |
| 3bd3f0d+dirty | 17.75 MiB | 19.70 MiB | 1.95 MiB |
| 93137d1+dirty | 17.75 MiB | 19.70 MiB | 1.95 MiB |
| bc9680d | 17.75 MiB | 20.15 MiB | 2.41 MiB |
| 7be1f99 | 17.75 MiB | 20.15 MiB | 2.41 MiB |
| bfe454a+dirty | 17.75 MiB | 19.69 MiB | 1.94 MiB |
| 955f2eb+dirty | 17.75 MiB | 19.70 MiB | 1.95 MiB |
| 6a70a7e+dirty | 17.75 MiB | 19.69 MiB | 1.94 MiB |
| 95aaf8a | 17.75 MiB | 19.68 MiB | 1.93 MiB |
Previous results on branch: antonis/replay-orientation
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| de62b18+dirty | 346.52 ms | 372.72 ms | 26.20 ms |
| d1e5478+dirty | 406.67 ms | 428.49 ms | 21.81 ms |
| 4c0adf8+dirty | 364.89 ms | 395.48 ms | 30.59 ms |
| c7e9027+dirty | 496.56 ms | 533.29 ms | 36.72 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| de62b18+dirty | 17.75 MiB | 19.75 MiB | 2.00 MiB |
| d1e5478+dirty | 43.75 MiB | 47.99 MiB | 4.23 MiB |
| 4c0adf8+dirty | 17.75 MiB | 19.75 MiB | 2.00 MiB |
| c7e9027+dirty | 43.75 MiB | 47.99 MiB | 4.23 MiB |
Android (new) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| d1fd647+dirty | 374.46 ms | 409.51 ms | 35.05 ms |
| 170d5ea+dirty | 348.79 ms | 406.94 ms | 58.15 ms |
| 6479fd5+dirty | 393.06 ms | 434.04 ms | 40.98 ms |
| 3e0a5f9+dirty | 379.92 ms | 450.96 ms | 71.04 ms |
| 1226664+dirty | 377.65 ms | 453.94 ms | 76.29 ms |
| 95aaf8a+dirty | 342.82 ms | 393.75 ms | 50.93 ms |
| 46da307+dirty | 356.62 ms | 415.02 ms | 58.40 ms |
| 5ee3314+dirty | 358.69 ms | 394.00 ms | 35.31 ms |
| 2adbd1e+dirty | 366.13 ms | 419.49 ms | 53.36 ms |
| 1853710+dirty | 360.67 ms | 396.28 ms | 35.61 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| d1fd647+dirty | 7.15 MiB | 8.43 MiB | 1.28 MiB |
| 170d5ea+dirty | 7.15 MiB | 8.42 MiB | 1.27 MiB |
| 6479fd5+dirty | 7.15 MiB | 8.41 MiB | 1.26 MiB |
| 3e0a5f9+dirty | 7.15 MiB | 8.42 MiB | 1.27 MiB |
| 1226664+dirty | 7.15 MiB | 8.46 MiB | 1.30 MiB |
| 95aaf8a+dirty | 7.15 MiB | 8.41 MiB | 1.26 MiB |
| 46da307+dirty | 7.15 MiB | 8.41 MiB | 1.26 MiB |
| 5ee3314+dirty | 7.15 MiB | 8.43 MiB | 1.28 MiB |
| 2adbd1e+dirty | 7.15 MiB | 8.43 MiB | 1.28 MiB |
| 1853710+dirty | 7.15 MiB | 8.41 MiB | 1.26 MiB |
Previous results on branch: antonis/replay-orientation
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| de62b18+dirty | 293.96 ms | 339.25 ms | 45.29 ms |
| d1e5478+dirty | 374.04 ms | 395.37 ms | 21.32 ms |
| 4c0adf8+dirty | 312.60 ms | 365.30 ms | 52.70 ms |
| c7e9027+dirty | 371.88 ms | 388.36 ms | 16.48 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| de62b18+dirty | 7.15 MiB | 8.46 MiB | 1.31 MiB |
| d1e5478+dirty | 43.94 MiB | 48.81 MiB | 4.88 MiB |
| 4c0adf8+dirty | 7.15 MiB | 8.46 MiB | 1.31 MiB |
| c7e9027+dirty | 43.94 MiB | 48.81 MiB | 4.88 MiB |
iOS (legacy) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 9f211e3+dirty | 1218.80 ms | 1233.88 ms | 15.08 ms |
| 785ffb1+dirty | 1237.63 ms | 1240.50 ms | 2.87 ms |
| ec14be7+dirty | 1234.64 ms | 1245.54 ms | 10.90 ms |
| 955f2eb+dirty | 1235.06 ms | 1253.88 ms | 18.81 ms |
| 1226664+dirty | 1220.59 ms | 1221.61 ms | 1.02 ms |
| 2adbd1e+dirty | 1207.51 ms | 1218.98 ms | 11.47 ms |
| 4167e15+dirty | 1213.39 ms | 1222.50 ms | 9.11 ms |
| 6a70a7e+dirty | 1225.82 ms | 1230.79 ms | 4.98 ms |
| d1fd647+dirty | 1219.35 ms | 1233.18 ms | 13.83 ms |
| 05bef0e+dirty | 1221.02 ms | 1237.04 ms | 16.02 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 9f211e3+dirty | 2.63 MiB | 3.91 MiB | 1.28 MiB |
| 785ffb1+dirty | 2.63 MiB | 3.81 MiB | 1.18 MiB |
| ec14be7+dirty | 2.63 MiB | 3.98 MiB | 1.34 MiB |
| 955f2eb+dirty | 2.63 MiB | 3.98 MiB | 1.35 MiB |
| 1226664+dirty | 2.63 MiB | 4.00 MiB | 1.37 MiB |
| 2adbd1e+dirty | 2.63 MiB | 4.00 MiB | 1.36 MiB |
| 4167e15+dirty | 2.63 MiB | 4.00 MiB | 1.37 MiB |
| 6a70a7e+dirty | 2.63 MiB | 3.98 MiB | 1.34 MiB |
| d1fd647+dirty | 2.63 MiB | 3.99 MiB | 1.36 MiB |
| 05bef0e+dirty | 2.63 MiB | 3.99 MiB | 1.36 MiB |
Previous results on branch: antonis/replay-orientation
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| de62b18+dirty | 1213.62 ms | 1226.20 ms | 12.58 ms |
| c7e9027+dirty | 1229.94 ms | 1225.36 ms | -4.57 ms |
| d1e5478+dirty | 1215.80 ms | 1211.24 ms | -4.57 ms |
| 4c0adf8+dirty | 1218.67 ms | 1226.43 ms | 7.76 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| de62b18+dirty | 2.63 MiB | 4.01 MiB | 1.38 MiB |
| c7e9027+dirty | 3.41 MiB | 4.57 MiB | 1.16 MiB |
| d1e5478+dirty | 3.41 MiB | 4.57 MiB | 1.16 MiB |
| 4c0adf8+dirty | 2.63 MiB | 4.01 MiB | 1.38 MiB |
iOS (new) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 9f211e3+dirty | 1215.38 ms | 1218.15 ms | 2.77 ms |
| 785ffb1+dirty | 1213.71 ms | 1213.37 ms | -0.35 ms |
| ec14be7+dirty | 1229.62 ms | 1230.53 ms | 0.91 ms |
| 955f2eb+dirty | 1225.78 ms | 1239.27 ms | 13.49 ms |
| 1226664+dirty | 1237.10 ms | 1245.27 ms | 8.16 ms |
| 2adbd1e+dirty | 1220.65 ms | 1230.20 ms | 9.56 ms |
| 4167e15+dirty | 1228.96 ms | 1242.15 ms | 13.19 ms |
| 6a70a7e+dirty | 1231.40 ms | 1239.49 ms | 8.09 ms |
| d1fd647+dirty | 1218.16 ms | 1225.82 ms | 7.65 ms |
| 05bef0e+dirty | 1223.31 ms | 1225.55 ms | 2.24 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 9f211e3+dirty | 3.19 MiB | 4.48 MiB | 1.29 MiB |
| 785ffb1+dirty | 3.19 MiB | 4.38 MiB | 1.19 MiB |
| ec14be7+dirty | 3.19 MiB | 4.54 MiB | 1.36 MiB |
| 955f2eb+dirty | 3.19 MiB | 4.55 MiB | 1.36 MiB |
| 1226664+dirty | 3.19 MiB | 4.57 MiB | 1.38 MiB |
| 2adbd1e+dirty | 3.19 MiB | 4.56 MiB | 1.38 MiB |
| 4167e15+dirty | 3.19 MiB | 4.57 MiB | 1.38 MiB |
| 6a70a7e+dirty | 3.19 MiB | 4.54 MiB | 1.36 MiB |
| d1fd647+dirty | 3.19 MiB | 4.56 MiB | 1.37 MiB |
| 05bef0e+dirty | 3.19 MiB | 4.56 MiB | 1.37 MiB |
Previous results on branch: antonis/replay-orientation
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| de62b18+dirty | 1218.02 ms | 1216.85 ms | -1.17 ms |
| c7e9027+dirty | 1221.62 ms | 1214.66 ms | -6.96 ms |
| d1e5478+dirty | 1209.60 ms | 1215.76 ms | 6.16 ms |
| 4c0adf8+dirty | 1218.00 ms | 1228.30 ms | 10.30 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| de62b18+dirty | 3.19 MiB | 4.58 MiB | 1.39 MiB |
| c7e9027+dirty | 3.41 MiB | 4.57 MiB | 1.16 MiB |
| d1e5478+dirty | 3.41 MiB | 4.57 MiB | 1.16 MiB |
| 4c0adf8+dirty | 3.19 MiB | 4.58 MiB | 1.39 MiB |
|
important fix for pixel copy since it avoid leaks! |
|
@sentry review |
packages/core/android/src/main/java/io/sentry/react/RNSentryReactFragmentLifecycleTracer.java
Outdated
Show resolved
Hide resolved
# Conflicts: # CHANGELOG.md
|
@sentry review |
packages/core/android/src/main/java/io/sentry/react/RNSentryReactFragmentLifecycleTracer.java
Outdated
Show resolved
Hide resolved
packages/core/android/src/main/java/io/sentry/react/RNSentryReactFragmentLifecycleTracer.java
Outdated
Show resolved
Hide resolved
packages/core/android/src/main/java/io/sentry/react/RNSentryReactFragmentLifecycleTracer.java
Outdated
Show resolved
Hide resolved
packages/core/android/src/main/java/io/sentry/react/RNSentryReactFragmentLifecycleTracer.java
Outdated
Show resolved
Hide resolved
packages/core/android/src/main/java/io/sentry/react/RNSentryReactFragmentLifecycleTracer.java
Outdated
Show resolved
Hide resolved
packages/core/android/src/main/java/io/sentry/react/RNSentryReactFragmentLifecycleTracer.java
Outdated
Show resolved
Hide resolved
packages/core/android/src/main/java/io/sentry/react/RNSentryReactFragmentLifecycleTracer.java
Outdated
Show resolved
Hide resolved
|
Overall looks good! lets get the approval of @romtsn before merging. |
| } | ||
| } | ||
|
|
||
| private @Nullable ReplayIntegration getReplayIntegration() { |
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.
nit: I think you could simplify this method by calling ScopesAdapter.getInstance().getOptions().getReplayController() and then checking if it's instanceof ReplayIntegration. This would spare a few cycles.
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.
Alternatively, we could even expose the onWindowSizeChanged method in the ReplayController interface, but would require a new Android SDK release, so I'll leave it up to you to decide :)
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 idea @romtsn 🙇
Updated with dbee1d4 and verified that everything works as before.
Alternatively, we could even expose the onWindowSizeChanged method in the ReplayController interface, but would require a new Android SDK release, so I'll leave it up to you to decide :)
I'll add a note to iterate on this as an improvement. It would be nice to ship the fix soon since this is also a PII.
| } | ||
| }); | ||
|
|
||
| // Add layout listener to detect configuration changes after detaching any previous one |
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.
so, as I understood this logic only applies when ReactNavigationIntegration is used and ttid-tracking is enabled. I was wondering if we should actually make it independent from the both above, and just introduce a replay-specific FragmentLifecycleCallbacks? Also, is this only a problem when fragments are used (i.e. reactNavigation), or also applies to activity-based apps?
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.
Good catch @romtsn 🙇
make it independent from the both above, and just introduce a replay-specific FragmentLifecycleCallbacks?
Makes sense 👍 Updated with bbddc27
Also, is this only a problem when fragments are used (i.e. reactNavigation), or also applies to activity-based apps?
I was able to still reproduce the issue on a bare app that seems to have only Activities. I think for most real world scenarios the fragment implementation would be used and I would opt for handling this case separately.
Example Activity only app
import React from 'react';
import { Button, View, Text, StyleSheet } from 'react-native';
import * as Sentry from '@sentry/react-native';
Sentry.init({
dsn: 'DSN',
// Adds more context data to events (IP address, cookies, user, etc.)
// For more information, visit: https://docs.sentry.io/platforms/react-native/data-management/data-collected/
sendDefaultPii: true,
// Enable Logs
enableLogs: true,
// Configure Session Replay
replaysSessionSampleRate: 0.1,
replaysOnErrorSampleRate: 1,
integrations: [Sentry.mobileReplayIntegration(), Sentry.feedbackIntegration()],
// uncomment the line below to enable Spotlight (https://spotlightjs.com)
// spotlight: __DEV__,
});
export default function App() {
return (
<View style={styles.container}>
<Text style={styles.text}>Hello, Minimal App!</Text>
<Button title='Try!' onPress={ () => { Sentry.captureException(new Error('First error')) }}/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#fff',
},
text: {
fontSize: 20,
},
});
export default Sentry.wrap(App);
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.
I agree, let's not care about it for now. If we get reports we can do that later 👍 Let me review the updated logic
romtsn
left a comment
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.
One nit comment and one question - going to approve once we figure those out. But this looks great already, thanks for investigating!
|
There seems to be a CI issue at this point irrelevant from this PR that causes failures like: |
| final RNSentryReplayFragmentLifecycleTracer fragmentLifecycleTracer = | ||
| new RNSentryReplayFragmentLifecycleTracer(logger); | ||
|
|
||
| final @Nullable FragmentActivity fragmentActivity = (FragmentActivity) getCurrentActivity(); |
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.
I assume it should be always a FragmentActivity but maybe worth to have an instanceof check just in case?
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.
I used the pattern from above but I think it's a good idea to add the check 👍 Updated with a8ad163
| private @NotNull final ILogger logger; | ||
|
|
||
| @SuppressWarnings("PMD.AvoidUsingVolatile") | ||
| private @Nullable volatile ReplayIntegration replayIntegration; |
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.
I assume volatile is not really needed here since everything is being accessed from the main thread (OnGlobalLayoutListener is likely called on the main thread too). But it's also fine as it is
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.
Updated with f963590
| private int lastWidth = -1; | ||
| private int lastHeight = -1; | ||
|
|
||
| private @Nullable View currentView; |
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.
theoretically this shouldn't leak since we nullify it in onFragmentViewDestroyed but maybe worth to have it as a WeakRef just in case?
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.
Good idea 👍 Updated with f56e75c
romtsn
left a comment
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.
LGTM, thanks for addressing the feedback!
📢 Type of change
📜 Description
Fixes orientation change misalignment for session replay on Android by manually triggering the onWindowSizeChanged when the screen size changes. This should cover orientation changes or other screen size changes (e.g. foldables).
💡 Motivation and Context
Fixes #4982
💚 How did you test it?
Tested with the latest SDK and the
screenshotStrategymakes a difference on how the bug is manifested📝 Checklist
sendDefaultPIIis enabled🔮 Next steps