@@ -48,6 +48,8 @@ public class AnrProfilingIntegration
4848 private volatile @ Nullable SentryAndroidOptions options ;
4949 private volatile @ Nullable Thread thread = null ;
5050 private volatile boolean inForeground = false ;
51+ private volatile @ Nullable Handler mainHandler ;
52+ private volatile @ Nullable Thread mainThread ;
5153
5254 @ Override
5355 public void register (final @ NotNull IScopes scopes , final @ NotNull SentryOptions options ) {
@@ -63,17 +65,35 @@ public void register(final @NotNull IScopes scopes, final @NotNull SentryOptions
6365 return ;
6466 }
6567
68+ final Looper mainLooper = Looper .getMainLooper ();
69+ this .mainThread = mainLooper .getThread ();
70+ this .mainHandler = new Handler (mainLooper );
71+
6672 addIntegrationToSdkVersion ("AnrProfiling" );
6773 AppState .getInstance ().addAppStateListener (this );
6874 }
6975 }
7076
7177 @ Override
7278 public void close () throws IOException {
73- onBackground ();
7479 enabled .set (false );
7580 AppState .getInstance ().removeAppStateListener (this );
7681
82+ // Remove any pending updater callbacks from the main handler
83+ final @ Nullable Handler handler = mainHandler ;
84+ if (handler != null ) {
85+ handler .removeCallbacks (updater );
86+ }
87+
88+ // Wake and interrupt the thread so it exits
89+ final @ Nullable Thread t = thread ;
90+ if (t != null ) {
91+ synchronized (this ) {
92+ notifyAll ();
93+ }
94+ t .interrupt ();
95+ }
96+
7797 final @ Nullable SentryAndroidOptions opts = options ;
7898 if (opts != null ) {
7999 try {
@@ -95,7 +115,7 @@ public void run() {
95115 }
96116 }
97117 });
98- } catch (Throwable t ) {
118+ } catch (Throwable e ) {
99119 logger .log (SentryLevel .WARNING , "Failed to submit AnrProfileManager close" );
100120 }
101121 }
@@ -113,15 +133,19 @@ public void onForeground() {
113133 inForeground = true ;
114134 updater .run ();
115135
116- final @ Nullable Thread oldThread = thread ;
117- if (oldThread != null ) {
118- oldThread .interrupt ();
136+ final @ Nullable Thread existingThread = thread ;
137+ if (existingThread != null && existingThread .isAlive ()) {
138+ // Wake the existing thread
139+ synchronized (this ) {
140+ notifyAll ();
141+ }
142+ }
143+ if (existingThread == null || !existingThread .isAlive ()) {
144+ final @ NotNull Thread profilingThread = new Thread (this , "AnrProfilingIntegration" );
145+ profilingThread .setDaemon (true );
146+ profilingThread .start ();
147+ thread = profilingThread ;
119148 }
120-
121- final @ NotNull Thread profilingThread = new Thread (this , "AnrProfilingIntegration" );
122- profilingThread .setDaemon (true );
123- profilingThread .start ();
124- thread = profilingThread ;
125149 }
126150 }
127151
@@ -131,32 +155,37 @@ public void onBackground() {
131155 return ;
132156 }
133157 try (final @ NotNull ISentryLifecycleToken ignored = lifecycleLock .acquire ()) {
134- if (!inForeground ) {
135- return ;
136- }
137-
138158 inForeground = false ;
139- final @ Nullable Thread oldThread = thread ;
140- if (oldThread != null ) {
141- oldThread .interrupt ();
142- }
143159 }
144160 }
145161
146162 @ Override
147163 public void run () {
148- // get main thread Handler so we can post messages
149- final Looper mainLooper = Looper .getMainLooper ();
150- final Thread mainThread = mainLooper .getThread ();
151- final Handler mainHandler = new Handler (mainLooper );
164+ final @ Nullable Handler handler = mainHandler ;
165+ final @ Nullable Thread mt = mainThread ;
166+ if (handler == null || mt == null ) {
167+ return ;
168+ }
152169
153170 try {
154171 while (enabled .get () && !Thread .currentThread ().isInterrupted ()) {
155172 try {
156- checkMainThread (mainThread );
173+ if (!inForeground ) {
174+ // Wait until we're back in the foreground or disabled
175+ synchronized (this ) {
176+ while (!inForeground && enabled .get ()) {
177+ wait ();
178+ }
179+ }
180+ // Reset the updater timestamp after waking to avoid false suspicion
181+ updater .run ();
182+ continue ;
183+ }
184+
185+ checkMainThread (mt );
157186
158- mainHandler .removeCallbacks (updater );
159- mainHandler .post (updater );
187+ handler .removeCallbacks (updater );
188+ handler .post (updater );
160189
161190 // noinspection BusyWait
162191 Thread .sleep (POLLING_INTERVAL_MS );
0 commit comments