diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle index 544f420ed..2fb49ff56 100644 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -23,7 +23,7 @@ ext { pluginVersion = [ checkstyle : '8.4', - gradle : '3.5.3', + gradle : '3.6.1', dependencyGraph : '0.5.0', mapboxSdkVersions: '1.0.1' ] diff --git a/libtelemetry/src/androidTestFull/java/com/mapbox/android/telemetry/crash/CrashReporterClientInstrumentationTest.java b/libtelemetry/src/androidTestFull/java/com/mapbox/android/telemetry/errors/ErrorReporterClientInstrumentationTest.java similarity index 79% rename from libtelemetry/src/androidTestFull/java/com/mapbox/android/telemetry/crash/CrashReporterClientInstrumentationTest.java rename to libtelemetry/src/androidTestFull/java/com/mapbox/android/telemetry/errors/ErrorReporterClientInstrumentationTest.java index 85e887ce2..6479760a8 100644 --- a/libtelemetry/src/androidTestFull/java/com/mapbox/android/telemetry/crash/CrashReporterClientInstrumentationTest.java +++ b/libtelemetry/src/androidTestFull/java/com/mapbox/android/telemetry/errors/ErrorReporterClientInstrumentationTest.java @@ -1,4 +1,4 @@ -package com.mapbox.android.telemetry.crash; +package com.mapbox.android.telemetry.errors; import android.content.Context; import android.content.SharedPreferences; @@ -19,14 +19,14 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -public class CrashReporterClientInstrumentationTest { +public class ErrorReporterClientInstrumentationTest { private static final String TEST_DIR_PATH = "com.mapbox.android.telemetry.test"; private static final String CRASH_FILENAME_FORMAT = "%s/%s.crash"; private static final String crashEvent = "{\"event\":\"mobile.crash\",\"created\":\"2019-02-21T21:58:43.000Z\",\"stackTraceHash\":\"%s\"}"; private File directory; - private CrashReporterClient crashReporterClient; + private ErrorReporterClient errorReporterClient; private Context context; @Before @@ -40,24 +40,24 @@ public void setUp() { for (File file: directory.listFiles()) { file.delete(); } - crashReporterClient = CrashReporterClient.create(context); + errorReporterClient = ErrorReporterClient.create(context); } @Test public void loadInvalidNullPath() { - CrashReporterClient client = crashReporterClient.loadFrom(null); + ErrorReporterClient client = errorReporterClient.loadFrom(null); assertFalse(client.hasNextEvent()); } @Test public void loadInvalidPath() { - CrashReporterClient client = crashReporterClient.loadFrom(new File("")); + ErrorReporterClient client = errorReporterClient.loadFrom(new File("")); assertFalse(client.hasNextEvent()); } @Test public void verifyEventNotLoadedFromEmptyPath() { - CrashReporterClient client = crashReporterClient.loadFrom(directory); + ErrorReporterClient client = errorReporterClient.loadFrom(directory); assertFalse(client.hasNextEvent()); } @@ -67,7 +67,7 @@ public void verifyEventLoadedWithValidHash() throws IOException { File file = FileUtils.getFile(context, String.format(CRASH_FILENAME_FORMAT, TEST_DIR_PATH, crashHash)); FileUtils.writeToFile(file, String.format(crashEvent, crashHash)); - CrashReporterClient client = crashReporterClient.loadFrom(directory); + ErrorReporterClient client = errorReporterClient.loadFrom(directory); assertTrue(client.hasNextEvent()); } @@ -77,7 +77,7 @@ public void verifyEventLoadedFirstTime() throws IOException { File file = FileUtils.getFile(context, String.format(CRASH_FILENAME_FORMAT, TEST_DIR_PATH, crashHash)); FileUtils.writeToFile(file, String.format(crashEvent, crashHash)); - CrashReporterClient client = crashReporterClient.loadFrom(directory); + ErrorReporterClient client = errorReporterClient.loadFrom(directory); assertTrue(client.hasNextEvent()); } @@ -87,10 +87,10 @@ public void verifyFileCursorReset() throws IOException { File file = FileUtils.getFile(context, String.format(CRASH_FILENAME_FORMAT, TEST_DIR_PATH, crashHash)); FileUtils.writeToFile(file, String.format(crashEvent, crashHash)); - CrashReporterClient client = crashReporterClient.loadFrom(directory); + ErrorReporterClient client = errorReporterClient.loadFrom(directory); assertTrue(client.hasNextEvent()); - client = crashReporterClient.loadFrom(new File("")); + client = errorReporterClient.loadFrom(new File("")); assertFalse(client.hasNextEvent()); } @@ -100,7 +100,7 @@ public void verifyDisabledState() { SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putBoolean(MAPBOX_PREF_ENABLE_CRASH_REPORTER, false); editor.commit(); - assertFalse(crashReporterClient.isEnabled()); + assertFalse(errorReporterClient.isEnabled()); } @Test @@ -109,7 +109,7 @@ public void verifyEnabledState() { SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putBoolean(MAPBOX_PREF_ENABLE_CRASH_REPORTER, true); editor.commit(); - assertTrue(crashReporterClient.isEnabled()); + assertTrue(errorReporterClient.isEnabled()); } @Test @@ -122,21 +122,21 @@ public void filterDupEventsBasedOnHash() throws IOException { FileUtils.writeToFile(file, String.format(crashEvent, crashHash)); // Need to toggle this flag to simulate telem success - crashReporterClient.loadFrom(directory); - CrashEvent event = crashReporterClient.nextEvent(); - assertFalse(crashReporterClient.isDuplicate(event)); + errorReporterClient.loadFrom(directory); + CrashEvent event = errorReporterClient.nextEvent(); + assertFalse(errorReporterClient.isDuplicate(event)); AtomicBoolean success = new AtomicBoolean(true); CountDownLatch latch = new CountDownLatch(1); - crashReporterClient.sendSync(event, success, latch); + errorReporterClient.sendSync(event, success, latch); - event = crashReporterClient.nextEvent(); - assertTrue(crashReporterClient.isDuplicate(event)); + event = errorReporterClient.nextEvent(); + assertTrue(errorReporterClient.isDuplicate(event)); } @Test(expected = IllegalStateException.class) public void nextCalledPriorLoadEvent() { - crashReporterClient.nextEvent(); + errorReporterClient.nextEvent(); } @Test @@ -158,19 +158,19 @@ public void verifyMappedFileDeleted() throws IOException { @Test public void deleteInvalidEvent() { - crashReporterClient.loadFrom(directory); - assertFalse(crashReporterClient.delete(new CrashEvent("mobile.crash", "2019-02-21T21:58:43.000Z"))); + errorReporterClient.loadFrom(directory); + assertFalse(errorReporterClient.delete(new CrashEvent("mobile.crash", "2019-02-21T21:58:43.000Z"))); } @Test public void attemptToDeleteAlreadyDeletedFile() throws IOException { File file = FileUtils.getFile(context, String.format(CRASH_FILENAME_FORMAT, TEST_DIR_PATH, "crash")); FileUtils.writeToFile(file, String.format(crashEvent, UUID.randomUUID().toString())); - crashReporterClient.loadFrom(directory); - CrashEvent crashEvent = crashReporterClient.nextEvent(); + errorReporterClient.loadFrom(directory); + CrashEvent crashEvent = errorReporterClient.nextEvent(); assertTrue(file.delete()); - assertFalse(crashReporterClient.delete(crashEvent)); + assertFalse(errorReporterClient.delete(crashEvent)); } private SharedPreferences getSharedPreferences() { diff --git a/libtelemetry/src/androidTestFull/java/com/mapbox/android/telemetry/crash/CrashReporterJobIntentServiceInstrumentationTest.java b/libtelemetry/src/androidTestFull/java/com/mapbox/android/telemetry/errors/ErrorReporterEngineInstrumentedTest.java similarity index 77% rename from libtelemetry/src/androidTestFull/java/com/mapbox/android/telemetry/crash/CrashReporterJobIntentServiceInstrumentationTest.java rename to libtelemetry/src/androidTestFull/java/com/mapbox/android/telemetry/errors/ErrorReporterEngineInstrumentedTest.java index 92e4dc75e..3b840c4fc 100644 --- a/libtelemetry/src/androidTestFull/java/com/mapbox/android/telemetry/crash/CrashReporterJobIntentServiceInstrumentationTest.java +++ b/libtelemetry/src/androidTestFull/java/com/mapbox/android/telemetry/errors/ErrorReporterEngineInstrumentedTest.java @@ -1,9 +1,11 @@ -package com.mapbox.android.telemetry.crash; +package com.mapbox.android.telemetry.errors; import android.content.Context; import android.content.SharedPreferences; import android.support.test.InstrumentationRegistry; + import com.mapbox.android.core.FileUtils; + import org.junit.Before; import org.junit.Test; @@ -16,7 +18,8 @@ import static com.mapbox.android.telemetry.MapboxTelemetryConstants.MAPBOX_TELEMETRY_PACKAGE; import static org.junit.Assert.assertEquals; -public class CrashReporterJobIntentServiceInstrumentationTest { +public class ErrorReporterEngineInstrumentedTest { + private static final String CRASH_FILENAME_FORMAT = "%s/%s.crash"; private static final String crashEvent = "{\"event\":\"mobile.crash\",\"created\":\"2019-02-21T21:58:43.000Z\",\"stackTraceHash\":\"%s\"}"; @@ -32,17 +35,11 @@ public void setUp() { directory.mkdir(); } - for (File file: directory.listFiles()) { + for (File file : directory.listFiles()) { file.delete(); } } - @Test - public void enqueueWork() { - CrashReporterJobIntentService.enqueueWork(InstrumentationRegistry.getTargetContext()); - // TODO: verify work is executed - } - @Test public void handleCrashReports() throws IOException { SharedPreferences sharedPreferences = @@ -54,11 +51,10 @@ public void handleCrashReports() throws IOException { File file = FileUtils.getFile(context, String.format(CRASH_FILENAME_FORMAT, MAPBOX_TELEMETRY_PACKAGE, "crash1")); FileUtils.writeToFile(file, String.format(crashEvent, UUID.randomUUID().toString())); - CrashReporterJobIntentService jobIntentService = new CrashReporterJobIntentService(); - jobIntentService.handleCrashReports(CrashReporterClient - .create(InstrumentationRegistry.getTargetContext()) + ErrorReporterEngine.handleErrorReports(ErrorReporterClient + .create(context.getApplicationContext()) .loadFrom(directory) .debug(true)); assertEquals(0, FileUtils.listAllFiles(directory).length); } -} \ No newline at end of file +} diff --git a/libtelemetry/src/androidTestFull/java/com/mapbox/android/telemetry/errors/ErrorReporterJobIntentServiceInstrumentationTest.java b/libtelemetry/src/androidTestFull/java/com/mapbox/android/telemetry/errors/ErrorReporterJobIntentServiceInstrumentationTest.java new file mode 100644 index 000000000..923875386 --- /dev/null +++ b/libtelemetry/src/androidTestFull/java/com/mapbox/android/telemetry/errors/ErrorReporterJobIntentServiceInstrumentationTest.java @@ -0,0 +1,15 @@ +package com.mapbox.android.telemetry.errors; + + +import android.support.test.InstrumentationRegistry; + +import org.junit.Test; + +public class ErrorReporterJobIntentServiceInstrumentationTest { + + @Test + public void enqueueWork() { + ErrorReporterJobIntentService.enqueueWork(InstrumentationRegistry.getInstrumentation().getTargetContext()); + // TODO: verify work is executed + } +} \ No newline at end of file diff --git a/libtelemetry/src/androidTestFull/java/com/mapbox/android/telemetry/crash/TokenChangeBroadcastReceiverInstrumentationTest.java b/libtelemetry/src/androidTestFull/java/com/mapbox/android/telemetry/errors/TokenChangeBroadcastReceiverInstrumentationTest.java similarity index 93% rename from libtelemetry/src/androidTestFull/java/com/mapbox/android/telemetry/crash/TokenChangeBroadcastReceiverInstrumentationTest.java rename to libtelemetry/src/androidTestFull/java/com/mapbox/android/telemetry/errors/TokenChangeBroadcastReceiverInstrumentationTest.java index 0310f7665..827f3df21 100644 --- a/libtelemetry/src/androidTestFull/java/com/mapbox/android/telemetry/crash/TokenChangeBroadcastReceiverInstrumentationTest.java +++ b/libtelemetry/src/androidTestFull/java/com/mapbox/android/telemetry/errors/TokenChangeBroadcastReceiverInstrumentationTest.java @@ -1,4 +1,4 @@ -package com.mapbox.android.telemetry.crash; +package com.mapbox.android.telemetry.errors; import android.content.Intent; import android.support.test.InstrumentationRegistry; diff --git a/libtelemetry/src/full/AndroidManifest.xml b/libtelemetry/src/full/AndroidManifest.xml index dc4e30e90..c72aa3b76 100644 --- a/libtelemetry/src/full/AndroidManifest.xml +++ b/libtelemetry/src/full/AndroidManifest.xml @@ -14,7 +14,7 @@ android:authorities="${applicationId}.mapboxtelemetryinitprovider" android:exported="false" android:initOrder="100"/> - diff --git a/libtelemetry/src/full/java/com/mapbox/android/telemetry/MapboxTelemetry.java b/libtelemetry/src/full/java/com/mapbox/android/telemetry/MapboxTelemetry.java index 0d63997b8..1a2318928 100644 --- a/libtelemetry/src/full/java/com/mapbox/android/telemetry/MapboxTelemetry.java +++ b/libtelemetry/src/full/java/com/mapbox/android/telemetry/MapboxTelemetry.java @@ -1,29 +1,28 @@ package com.mapbox.android.telemetry; import android.content.Context; -import android.content.Intent; import android.content.SharedPreferences; import android.net.ConnectivityManager; import android.net.NetworkInfo; +import android.util.Log; + +import com.mapbox.android.telemetry.errors.ErrorReporterEngine; import java.io.IOException; -import java.util.List; import java.util.Collections; +import java.util.List; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.ExecutorService; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.ThreadFactory; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Pattern; import android.support.annotation.NonNull; -import android.support.v4.content.LocalBroadcastManager; - -import android.util.Log; import okhttp3.Call; import okhttp3.Callback; @@ -54,7 +53,8 @@ public class MapboxTelemetry implements FullQueueCallback, ServiceTaskCallback { public MapboxTelemetry(Context context, String accessToken, String userAgent) { initializeContext(context); - setAccessToken(context, accessToken); + this.executorService = ExecutorServiceFactory.create("MapboxTelemetryExecutor", 3, 20); + setAccessToken(context, accessToken, executorService); this.userAgent = userAgent; AlarmReceiver alarmReceiver = obtainAlarmReceiver(); this.schedulerFlusher = new SchedulerFlusherFactory(applicationContext, alarmReceiver).supply(); @@ -63,8 +63,6 @@ public MapboxTelemetry(Context context, String accessToken, String userAgent) { initializeAttachmentListeners(); // Initializing callback after listeners object is instantiated this.httpCallback = getHttpCallback(telemetryListeners); - this.executorService = ExecutorServiceFactory.create("MapboxTelemetryExecutor", 3, - 20); this.queue = EventsQueue.create(this, executorService); } @@ -73,7 +71,7 @@ public MapboxTelemetry(Context context, String accessToken, String userAgent) { TelemetryClient telemetryClient, Callback httpCallback, SchedulerFlusher schedulerFlusher, Clock clock, TelemetryEnabler telemetryEnabler, ExecutorService executorService) { initializeContext(context); - setAccessToken(context, accessToken); + setAccessToken(context, accessToken, executorService); this.userAgent = userAgent; this.telemetryClient = telemetryClient; this.schedulerFlusher = schedulerFlusher; @@ -412,13 +410,15 @@ public void run() { }); } - private static synchronized void setAccessToken(@NonNull Context context, @NonNull String accessToken) { + private static synchronized void setAccessToken(@NonNull final Context context, + @NonNull String accessToken, + @NonNull ExecutorService executorService) { if (TelemetryUtils.isEmpty(accessToken)) { return; } + // Set token and check return value to see if it was previously nil and send pending error reports if (sAccessToken.getAndSet(accessToken).isEmpty()) { - LocalBroadcastManager.getInstance(context) - .sendBroadcast(new Intent(MapboxTelemetryConstants.ACTION_TOKEN_CHANGED)); + ErrorReporterEngine.sendErrorReports(context, executorService); } } diff --git a/libtelemetry/src/full/java/com/mapbox/android/telemetry/crash/CrashReporterJobIntentService.java b/libtelemetry/src/full/java/com/mapbox/android/telemetry/crash/CrashReporterJobIntentService.java deleted file mode 100644 index 0d26ef3df..000000000 --- a/libtelemetry/src/full/java/com/mapbox/android/telemetry/crash/CrashReporterJobIntentService.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.mapbox.android.telemetry.crash; - -import android.content.Context; -import android.content.Intent; -import android.support.annotation.NonNull; -import android.support.annotation.VisibleForTesting; -import android.support.v4.app.JobIntentService; -import android.util.Log; -import com.mapbox.android.core.FileUtils; -import com.mapbox.android.telemetry.CrashEvent; - -import java.io.File; - -import static com.mapbox.android.telemetry.MapboxTelemetryConstants.MAPBOX_TELEMETRY_PACKAGE; - -/** - * This is a background job that sends crash events to the telemetry endpoint - * at startup. - */ -public final class CrashReporterJobIntentService extends JobIntentService { - private static final String LOG_TAG = "CrashJobIntentService"; - private static final int JOB_ID = 666; - - static void enqueueWork(@NonNull Context context) { - enqueueWork(context, CrashReporterJobIntentService.class, JOB_ID, - new Intent(context, CrashReporterJobIntentService.class)); - } - - @Override - protected void onHandleWork(@NonNull Intent intent) { - Log.d(LOG_TAG, "onHandleWork"); - try { - File rootDirectory = FileUtils.getFile(getApplicationContext(), MAPBOX_TELEMETRY_PACKAGE); - if (!rootDirectory.exists()) { - Log.w(LOG_TAG, "Root directory doesn't exist"); - return; - } - - handleCrashReports(CrashReporterClient - .create(getApplicationContext()) - .loadFrom(rootDirectory) - ); - } catch (Throwable throwable) { - // TODO: log silent crash - Log.e(LOG_TAG, throwable.toString()); - } - } - - @VisibleForTesting - void handleCrashReports(@NonNull CrashReporterClient client) { - if (!client.isEnabled()) { - Log.w(LOG_TAG, "Crash reporter is disabled"); - return; - } - - while (client.hasNextEvent()) { - CrashEvent event = client.nextEvent(); - if (client.isDuplicate(event)) { - Log.d(LOG_TAG, "Skip duplicate crash in this batch: " + event.getHash()); - client.delete(event); - continue; - } - - if (client.send(event)) { - client.delete(event); - } else { - Log.w(LOG_TAG, "Failed to deliver crash event"); - } - } - } -} diff --git a/libtelemetry/src/full/java/com/mapbox/android/telemetry/crash/CrashReporterClient.java b/libtelemetry/src/full/java/com/mapbox/android/telemetry/errors/ErrorReporterClient.java similarity index 93% rename from libtelemetry/src/full/java/com/mapbox/android/telemetry/crash/CrashReporterClient.java rename to libtelemetry/src/full/java/com/mapbox/android/telemetry/errors/ErrorReporterClient.java index 3ebf031fb..862152c47 100644 --- a/libtelemetry/src/full/java/com/mapbox/android/telemetry/crash/CrashReporterClient.java +++ b/libtelemetry/src/full/java/com/mapbox/android/telemetry/errors/ErrorReporterClient.java @@ -1,4 +1,4 @@ -package com.mapbox.android.telemetry.crash; +package com.mapbox.android.telemetry.errors; import android.content.Context; import android.content.SharedPreferences; @@ -26,7 +26,7 @@ import static com.mapbox.android.core.crashreporter.MapboxUncaughtExceptionHanlder.MAPBOX_CRASH_REPORTER_PREFERENCES; import static com.mapbox.android.core.crashreporter.MapboxUncaughtExceptionHanlder.MAPBOX_PREF_ENABLE_CRASH_REPORTER; -final class CrashReporterClient { +final class ErrorReporterClient { private static final String LOG_TAG = "CrashReporterClient"; private static final String CRASH_REPORTER_CLIENT_USER_AGENT = "mapbox-android-crash"; private final SharedPreferences sharedPreferences; @@ -38,7 +38,7 @@ final class CrashReporterClient { private boolean isDebug; @VisibleForTesting - CrashReporterClient(@NonNull SharedPreferences sharedPreferences, + ErrorReporterClient(@NonNull SharedPreferences sharedPreferences, @NonNull MapboxTelemetry telemetry, File[] crashReports) { this.sharedPreferences = sharedPreferences; @@ -48,22 +48,22 @@ final class CrashReporterClient { this.isDebug = false; } - static CrashReporterClient create(@NonNull Context context) { + static ErrorReporterClient create(@NonNull Context context) { SharedPreferences sharedPreferences = context.getSharedPreferences(MAPBOX_CRASH_REPORTER_PREFERENCES, Context.MODE_PRIVATE); - return new CrashReporterClient(sharedPreferences, + return new ErrorReporterClient(sharedPreferences, new MapboxTelemetry(context, "", String.format("%s/%s", CRASH_REPORTER_CLIENT_USER_AGENT, BuildConfig.VERSION_NAME)), new File[0]); } - CrashReporterClient loadFrom(@NonNull File rootDir) { + ErrorReporterClient loadFrom(@NonNull File rootDir) { fileCursor = 0; crashReports = FileUtils.listAllFiles(rootDir); Arrays.sort(crashReports, new FileUtils.LastModifiedComparator()); return this; } - CrashReporterClient debug(boolean isDebug) { + ErrorReporterClient debug(boolean isDebug) { this.isDebug = isDebug; return this; } diff --git a/libtelemetry/src/full/java/com/mapbox/android/telemetry/errors/ErrorReporterEngine.java b/libtelemetry/src/full/java/com/mapbox/android/telemetry/errors/ErrorReporterEngine.java new file mode 100644 index 000000000..074b393bd --- /dev/null +++ b/libtelemetry/src/full/java/com/mapbox/android/telemetry/errors/ErrorReporterEngine.java @@ -0,0 +1,80 @@ +package com.mapbox.android.telemetry.errors; + +import android.content.Context; +import android.content.Intent; +import android.os.Build; +import android.support.annotation.NonNull; +import android.support.annotation.VisibleForTesting; +import android.support.v4.content.LocalBroadcastManager; +import android.util.Log; + +import com.mapbox.android.core.FileUtils; +import com.mapbox.android.telemetry.CrashEvent; +import com.mapbox.android.telemetry.MapboxTelemetryConstants; + +import java.io.File; +import java.util.concurrent.ExecutorService; + +import static com.mapbox.android.telemetry.MapboxTelemetryConstants.MAPBOX_TELEMETRY_PACKAGE; + +public final class ErrorReporterEngine { + private static final String LOG_TAG = "CrashReporter"; + + public static void sendErrorReports(@NonNull final Context context, + @NonNull final ExecutorService executorService) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { + LocalBroadcastManager.getInstance(context) + .sendBroadcast(new Intent(MapboxTelemetryConstants.ACTION_TOKEN_CHANGED)); + } else { + try { + executorService.execute(new Runnable() { + @Override + public void run() { + ErrorReporterEngine.sendReports(context); + } + }); + } catch (Throwable throwable) { + Log.e(LOG_TAG, throwable.toString()); + } + } + } + + static void sendReports(@NonNull Context context) { + if (context == null || context.getApplicationContext() == null) { + return; + } + + File rootDirectory = FileUtils.getFile(context.getApplicationContext(), MAPBOX_TELEMETRY_PACKAGE); + if (!rootDirectory.exists()) { + Log.w(LOG_TAG, "Root directory doesn't exist"); + return; + } + + handleErrorReports(ErrorReporterClient + .create(context.getApplicationContext()) + .loadFrom(rootDirectory)); + } + + @VisibleForTesting + static void handleErrorReports(@NonNull ErrorReporterClient client) { + if (!client.isEnabled()) { + Log.w(LOG_TAG, "Crash reporter is disabled"); + return; + } + + while (client.hasNextEvent()) { + CrashEvent event = client.nextEvent(); + if (client.isDuplicate(event)) { + Log.d(LOG_TAG, "Skip duplicate crash in this batch: " + event.getHash()); + client.delete(event); + continue; + } + + if (client.send(event)) { + client.delete(event); + } else { + Log.w(LOG_TAG, "Failed to deliver crash event"); + } + } + } +} diff --git a/libtelemetry/src/full/java/com/mapbox/android/telemetry/errors/ErrorReporterJobIntentService.java b/libtelemetry/src/full/java/com/mapbox/android/telemetry/errors/ErrorReporterJobIntentService.java new file mode 100644 index 000000000..fd0db396d --- /dev/null +++ b/libtelemetry/src/full/java/com/mapbox/android/telemetry/errors/ErrorReporterJobIntentService.java @@ -0,0 +1,33 @@ +package com.mapbox.android.telemetry.errors; + +import android.content.Context; +import android.content.Intent; +import android.support.annotation.NonNull; +import android.support.v4.app.JobIntentService; +import android.util.Log; + + +/** + * This is a background job that sends crash events to the telemetry endpoint + * at startup. + */ +public final class ErrorReporterJobIntentService extends JobIntentService { + private static final String LOG_TAG = "CrashJobIntentService"; + private static final int JOB_ID = 666; + + static void enqueueWork(@NonNull Context context) { + enqueueWork(context, ErrorReporterJobIntentService.class, JOB_ID, + new Intent(context, ErrorReporterJobIntentService.class)); + } + + @Override + protected void onHandleWork(@NonNull Intent intent) { + Log.d(LOG_TAG, "onHandleWork"); + try { + ErrorReporterEngine.sendReports(getApplicationContext()); + } catch (Throwable throwable) { + // TODO: log silent crash + Log.e(LOG_TAG, throwable.toString()); + } + } +} diff --git a/libtelemetry/src/full/java/com/mapbox/android/telemetry/crash/TokenChangeBroadcastReceiver.java b/libtelemetry/src/full/java/com/mapbox/android/telemetry/errors/TokenChangeBroadcastReceiver.java similarity index 93% rename from libtelemetry/src/full/java/com/mapbox/android/telemetry/crash/TokenChangeBroadcastReceiver.java rename to libtelemetry/src/full/java/com/mapbox/android/telemetry/errors/TokenChangeBroadcastReceiver.java index a59344e4d..67ab40bd4 100644 --- a/libtelemetry/src/full/java/com/mapbox/android/telemetry/crash/TokenChangeBroadcastReceiver.java +++ b/libtelemetry/src/full/java/com/mapbox/android/telemetry/errors/TokenChangeBroadcastReceiver.java @@ -1,4 +1,4 @@ -package com.mapbox.android.telemetry.crash; +package com.mapbox.android.telemetry.errors; import android.content.BroadcastReceiver; import android.content.Context; @@ -31,7 +31,7 @@ public static void register(@NonNull Context context) { public void onReceive(Context context, Intent intent) { try { // Start background job - CrashReporterJobIntentService.enqueueWork(context); + ErrorReporterJobIntentService.enqueueWork(context); // Unregister receiver - we need it once at startup LocalBroadcastManager.getInstance(context).unregisterReceiver(this); } catch (Throwable throwable) { diff --git a/libtelemetry/src/full/java/com/mapbox/android/telemetry/provider/MapboxTelemetryInitProvider.java b/libtelemetry/src/full/java/com/mapbox/android/telemetry/provider/MapboxTelemetryInitProvider.java index 5747a11cb..380d5da47 100644 --- a/libtelemetry/src/full/java/com/mapbox/android/telemetry/provider/MapboxTelemetryInitProvider.java +++ b/libtelemetry/src/full/java/com/mapbox/android/telemetry/provider/MapboxTelemetryInitProvider.java @@ -12,7 +12,7 @@ import android.util.Log; import com.mapbox.android.core.crashreporter.MapboxUncaughtExceptionHanlder; import com.mapbox.android.telemetry.BuildConfig; -import com.mapbox.android.telemetry.crash.TokenChangeBroadcastReceiver; +import com.mapbox.android.telemetry.errors.TokenChangeBroadcastReceiver; import com.mapbox.android.telemetry.location.LocationCollectionClient; import java.util.concurrent.TimeUnit;