Skip to content

Commit dde05b5

Browse files
Marc O'Morainmarcomorain
authored andcommitted
Use fixed resources for sending
Introduce 2 limits on the resources used. Use an Executor with a thread pool of max size 1 for sending HTTP requests to Sentry. This thread pool will use 0 threads at idle, and reduce the number of threads in use down to 0 after a minute of no exceptions. Use a fixed queue for events. A queue of up to 50 events will be queued for sending to Sentry. If more than 50 events are queued, the new events will be discarded. These two changes will add a fixed ceiling to the amount of resources the Sentry client will use on the device.
1 parent c1e3845 commit dde05b5

File tree

1 file changed

+34
-30
lines changed
  • sentry-android/src/main/java/com/joshdholtz/sentry

1 file changed

+34
-30
lines changed

sentry-android/src/main/java/com/joshdholtz/sentry/Sentry.java

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@
3939
import java.util.Map;
4040
import java.util.TimeZone;
4141
import java.util.UUID;
42+
import java.util.concurrent.ArrayBlockingQueue;
43+
import java.util.concurrent.Executor;
44+
import java.util.concurrent.ThreadFactory;
45+
import java.util.concurrent.ThreadPoolExecutor;
46+
import java.util.concurrent.TimeUnit;
47+
import java.util.concurrent.atomic.AtomicLong;
4248

4349
import javax.net.ssl.SSLContext;
4450
import javax.net.ssl.TrustManager;
@@ -72,11 +78,7 @@
7278
import android.net.ConnectivityManager;
7379
import android.net.NetworkInfo;
7480
import android.net.Uri;
75-
import android.os.AsyncTask;
7681
import android.os.Build;
77-
import android.os.Handler;
78-
import android.os.HandlerThread;
79-
import android.os.Looper;
8082
import android.util.DisplayMetrics;
8183
import android.util.Log;
8284
import android.view.WindowManager;
@@ -96,8 +98,10 @@ public class Sentry {
9698
private int verifySsl;
9799
private SentryEventCaptureListener captureListener;
98100
private JSONObject contexts = new JSONObject();
101+
private Executor executor;
99102

100103
private static final String TAG = "Sentry";
104+
private static final int MAX_QUEUE_LENGTH = 50;
101105

102106
private Sentry() {
103107
}
@@ -134,11 +138,31 @@ public static void init(Context context, String dsn, boolean setupUncaughtExcept
134138
Sentry.getInstance().packageInfo = findPackage(Sentry.getInstance().context);
135139
Sentry.getInstance().verifySsl = getVerifySsl(dsn);
136140
Sentry.getInstance().contexts = readContexts(Sentry.getInstance().context, Sentry.getInstance().packageInfo);
141+
Sentry.getInstance().executor = fixedQueueDiscardingExecutor(MAX_QUEUE_LENGTH);
137142

138143
if (setupUncaughtExceptionHandler) {
139144
Sentry.getInstance().setupUncaughtExceptionHandler();
140145
}
141146
}
147+
148+
private static Executor fixedQueueDiscardingExecutor(int queueSize) {
149+
// Name our threads so that it is easy for app developers to see who is creating threads.
150+
final ThreadFactory threadFactory = new ThreadFactory() {
151+
private final AtomicLong count = new AtomicLong();
152+
@Override
153+
public Thread newThread(Runnable runnable) {
154+
final Thread thread = new Thread(runnable);
155+
thread.setName(String.format(Locale.US, "Sentry HTTP Thread %d", count.incrementAndGet()));
156+
return thread;
157+
}
158+
};
159+
160+
return new ThreadPoolExecutor(
161+
0, 1, // Keep 0 threads alive. Max pool size is 1.
162+
60, TimeUnit.SECONDS, // Kill unused threads after this length.
163+
new ArrayBlockingQueue<Runnable>(queueSize),
164+
threadFactory, new ThreadPoolExecutor.DiscardPolicy()); // Discard exceptions
165+
}
142166

143167
private static int getVerifySsl(String dsn) {
144168
int verifySsl = 1;
@@ -319,24 +343,7 @@ public static void captureEvent(SentryEventBuilder builder) {
319343

320344
log("Request - " + request.getRequestData());
321345

322-
// Check if on main thread - if not, run on main thread
323-
if (Looper.myLooper() == Looper.getMainLooper()) {
324-
doCaptureEventPost(request);
325-
} else if (Sentry.getInstance().context != null) {
326-
327-
HandlerThread thread = new HandlerThread("SentryThread") {};
328-
thread.start();
329-
Runnable runnable = new Runnable() {
330-
@Override
331-
public void run() {
332-
doCaptureEventPost(request);
333-
}
334-
};
335-
Handler h = new Handler(thread.getLooper());
336-
h.post(runnable);
337-
338-
}
339-
346+
doCaptureEventPost(request);
340347
}
341348

342349
private static boolean shouldAttemptPost() {
@@ -425,11 +432,10 @@ private static void doCaptureEventPost(final SentryEventRequest request) {
425432
InternalStorage.getInstance().addRequest(request);
426433
return;
427434
}
428-
429-
new AsyncTask<Void, Void, Void>(){
430-
@Override
431-
protected Void doInBackground(Void... params) {
432435

436+
getInstance().executor.execute(new Runnable() {
437+
@Override
438+
public void run() {
433439
int projectId = Integer.parseInt(getProjectId());
434440
String url = Sentry.getInstance().baseUrl + "/api/" + projectId + "/store/";
435441

@@ -501,11 +507,9 @@ protected Void doInBackground(Void... params) {
501507
} else {
502508
InternalStorage.getInstance().addRequest(request);
503509
}
504-
505-
return null;
506510
}
507511

508-
private byte[] readBytes(InputStream inputStream) throws IOException {
512+
private byte[] readBytes(InputStream inputStream) throws IOException {
509513
// this dynamically extends to take the bytes you read
510514
ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
511515

@@ -523,7 +527,7 @@ private byte[] readBytes(InputStream inputStream) throws IOException {
523527
return byteBuffer.toByteArray();
524528
}
525529

526-
}.execute();
530+
});
527531

528532
}
529533

0 commit comments

Comments
 (0)