Skip to content

Commit

Permalink
Merge 3428305 into c9d0787
Browse files Browse the repository at this point in the history
  • Loading branch information
adinauer committed Apr 19, 2023
2 parents c9d0787 + 3428305 commit a874a2b
Show file tree
Hide file tree
Showing 11 changed files with 237 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -279,11 +279,60 @@ private static void readDefaultOptionValues(
}
}

if (options.getProguardUuid() == null) {
options.setProguardUuid(getProguardUUID(context, options.getLogger()));
// TODO when to parse, when not?
// TODO parse bundle IDs as well; extract proguard parsing to parser; also parse bundleIds;
// return data class containing both properties
// TODO on SAGP side, add bundleIds to sentry-debug-meta.properties file
final @Nullable Properties debugMetaProperties =
loadDebugMetaProperties(context, options.getLogger());

if (debugMetaProperties != null) {
if (options.getProguardUuid() == null) {
final @Nullable String proguardUuid =
debugMetaProperties.getProperty("io.sentry.ProguardUuids");
options.getLogger().log(SentryLevel.DEBUG, "Proguard UUID found: %s", proguardUuid);
options.setProguardUuid(proguardUuid);
}

if (options.getBundleIds().isEmpty()) {
final @Nullable String bundleIdStrings =
debugMetaProperties.getProperty("io.sentry.bundle-ids");
options.getLogger().log(SentryLevel.DEBUG, "Bundle IDs found: %s", bundleIdStrings);
if (bundleIdStrings != null) {
// TODO really nullable?
final @Nullable String[] bundleIds = bundleIdStrings.split(",", -1);
if (bundleIds != null) {
for (final String bundleId : bundleIds) {
options.addBundleId(bundleId);
}
}
}
}
}
}

private static @Nullable Properties loadDebugMetaProperties(
final @NotNull Context context, final @NotNull ILogger logger) {
final AssetManager assets = context.getAssets();
// one may have thousands of asset files and looking up this list might slow down the SDK init.
// quite a bit, for this reason, we try to open the file directly and take care of errors
// like FileNotFoundException
try (final InputStream is =
new BufferedInputStream(assets.open("sentry-debug-meta.properties"))) {
final Properties properties = new Properties();
properties.load(is);
return properties;
} catch (FileNotFoundException e) {
logger.log(SentryLevel.INFO, "sentry-debug-meta.properties file was not found.");
} catch (IOException e) {
logger.log(SentryLevel.ERROR, "Error getting Proguard UUIDs.", e);
} catch (RuntimeException e) {
logger.log(SentryLevel.ERROR, "sentry-debug-meta.properties file is malformed.", e);
}

return null;
}

private static @Nullable String getProguardUUID(
final @NotNull Context context, final @NotNull ILogger logger) {
final AssetManager assets = context.getAssets();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ final class ManifestMetadataReader {

static final String ATTACH_THREADS = "io.sentry.attach-threads";
static final String PROGUARD_UUID = "io.sentry.proguard-uuid";

static final String SOURCE_BUNDLE_IDS = "io.sentry.bundle-ids";
static final String IDLE_TIMEOUT = "io.sentry.traces.idle-timeout";

static final String ATTACH_SCREENSHOT = "io.sentry.attach-screenshot";
Expand Down Expand Up @@ -341,6 +343,13 @@ static void applyMetadata(
SentryIntegrationPackageStorage.getInstance().addIntegration(integration);
}
}

List<String> sourceBundleIds = readList(metadata, logger, SOURCE_BUNDLE_IDS);
if (sourceBundleIds != null) {
for (String bundleId : sourceBundleIds) {
options.addBundleId(bundleId);
}
}
}

options
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,19 @@ class AndroidOptionsInitializerTest {
assertEquals("proguard-uuid", fixture.sentryOptions.proguardUuid)
}

@Test
fun `init should set bundle IDs id on start`() {
fixture.initSut(
Bundle().apply {
putString(ManifestMetadataReader.SOURCE_BUNDLE_IDS, "12ea7a02-46ac-44c0-a5bb-6d1fd9586411, faa3ab42-b1bd-4659-af8e-1682324aa744")
},
hasAppContext = false
)

assertTrue(fixture.sentryOptions.bundleIds.size == 2)
assertTrue(fixture.sentryOptions.bundleIds.containsAll(listOf("12ea7a02-46ac-44c0-a5bb-6d1fd9586411", "faa3ab42-b1bd-4659-af8e-1682324aa744")))
}

@Test
fun `init should set Android transport gate`() {
fixture.initSut()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1243,4 +1243,64 @@ class ManifestMetadataReaderTest {
assertNotNull(resultingSet)
assert(resultingSet.containsAll(listOf("Database Instrumentation", "OkHttp Instrumentation")))
}

@Test
fun `applyMetadata reads single bundle ID`() {
// Arrange
val bundle = bundleOf(ManifestMetadataReader.SOURCE_BUNDLE_IDS to "12ea7a02-46ac-44c0-a5bb-6d1fd9586411")
val context = fixture.getContext(metaData = bundle)

// Act
ManifestMetadataReader.applyMetadata(context, fixture.options, fixture.buildInfoProvider)

// Assert
val bundleIds = fixture.options.bundleIds
assertNotNull(bundleIds)
assert(bundleIds.containsAll(listOf("12ea7a02-46ac-44c0-a5bb-6d1fd9586411")))
}

@Test
fun `applyMetadata reads multiple bundle IDs`() {
// Arrange
val bundle = bundleOf(ManifestMetadataReader.SOURCE_BUNDLE_IDS to "12ea7a02-46ac-44c0-a5bb-6d1fd9586411, faa3ab42-b1bd-4659-af8e-1682324aa744")
val context = fixture.getContext(metaData = bundle)

// Act
ManifestMetadataReader.applyMetadata(context, fixture.options, fixture.buildInfoProvider)

// Assert
val bundleIds = fixture.options.bundleIds
assertNotNull(bundleIds)
assert(bundleIds.containsAll(listOf("12ea7a02-46ac-44c0-a5bb-6d1fd9586411", "faa3ab42-b1bd-4659-af8e-1682324aa744")))
}

@Test
fun `applyMetadata reads empty bundle IDs`() {
// Arrange
val bundle = bundleOf(ManifestMetadataReader.SOURCE_BUNDLE_IDS to "")
val context = fixture.getContext(metaData = bundle)

// Act
ManifestMetadataReader.applyMetadata(context, fixture.options, fixture.buildInfoProvider)

// Assert
val bundleIds = fixture.options.bundleIds
assertNotNull(bundleIds)
assert(bundleIds.isEmpty())
}

@Test
fun `applyMetadata reads missing bundle IDs`() {
// Arrange
val bundle = bundleOf()
val context = fixture.getContext(metaData = bundle)

// Act
ManifestMetadataReader.applyMetadata(context, fixture.options, fixture.buildInfoProvider)

// Assert
val bundleIds = fixture.options.bundleIds
assertNotNull(bundleIds)
assert(bundleIds.isEmpty())
}
}
5 changes: 5 additions & 0 deletions sentry/api/sentry.api
Original file line number Diff line number Diff line change
Expand Up @@ -229,13 +229,15 @@ public abstract interface class io/sentry/EventProcessor {

public final class io/sentry/ExternalOptions {
public fun <init> ()V
public fun addBundleId (Ljava/lang/String;)V
public fun addContextTag (Ljava/lang/String;)V
public fun addIgnoredExceptionForType (Ljava/lang/Class;)V
public fun addInAppExclude (Ljava/lang/String;)V
public fun addInAppInclude (Ljava/lang/String;)V
public fun addTracePropagationTarget (Ljava/lang/String;)V
public fun addTracingOrigin (Ljava/lang/String;)V
public static fun from (Lio/sentry/config/PropertiesProvider;Lio/sentry/ILogger;)Lio/sentry/ExternalOptions;
public fun getBundleIds ()Ljava/util/List;
public fun getContextTags ()Ljava/util/List;
public fun getDebug ()Ljava/lang/Boolean;
public fun getDist ()Ljava/lang/String;
Expand Down Expand Up @@ -1541,6 +1543,7 @@ public final class io/sentry/SentryNanotimeDateProvider : io/sentry/SentryDatePr

public class io/sentry/SentryOptions {
public fun <init> ()V
public fun addBundleId (Ljava/lang/String;)V
public fun addCollector (Lio/sentry/ICollector;)V
public fun addContextTag (Ljava/lang/String;)V
public fun addEventProcessor (Lio/sentry/EventProcessor;)V
Expand All @@ -1553,6 +1556,7 @@ public class io/sentry/SentryOptions {
public fun getBeforeBreadcrumb ()Lio/sentry/SentryOptions$BeforeBreadcrumbCallback;
public fun getBeforeSend ()Lio/sentry/SentryOptions$BeforeSendCallback;
public fun getBeforeSendTransaction ()Lio/sentry/SentryOptions$BeforeSendTransactionCallback;
public fun getBundleIds ()Ljava/util/List;
public fun getCacheDirPath ()Ljava/lang/String;
public fun getClientReportRecorder ()Lio/sentry/clientreport/IClientReportRecorder;
public fun getCollectors ()Ljava/util/List;
Expand Down Expand Up @@ -2688,6 +2692,7 @@ public final class io/sentry/protocol/Contexts$Deserializer : io/sentry/JsonDese
}

public final class io/sentry/protocol/DebugImage : io/sentry/JsonSerializable, io/sentry/JsonUnknown {
public static final field JVM Ljava/lang/String;
public static final field PROGUARD Ljava/lang/String;
public fun <init> ()V
public fun getArch ()Ljava/lang/String;
Expand Down
12 changes: 12 additions & 0 deletions sentry/src/main/java/io/sentry/ExternalOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public final class ExternalOptions {
new CopyOnWriteArraySet<>();
private @Nullable Boolean printUncaughtStackTrace;
private @Nullable Boolean sendClientReports;
private @NotNull List<String> bundleIds = new CopyOnWriteArrayList<>();

@SuppressWarnings("unchecked")
public static @NotNull ExternalOptions from(
Expand Down Expand Up @@ -109,6 +110,9 @@ public final class ExternalOptions {
options.addContextTag(contextTag);
}
options.setProguardUuid(propertiesProvider.getProperty("proguard-uuid"));
for (final String bundleId : propertiesProvider.getList("bundle-ids")) {
options.addBundleId(bundleId);
}
options.setIdleTimeout(propertiesProvider.getLongProperty("idle-timeout"));

for (final String ignoredExceptionType :
Expand Down Expand Up @@ -335,4 +339,12 @@ public void setIdleTimeout(final @Nullable Long idleTimeout) {
public void setSendClientReports(final @Nullable Boolean sendClientReports) {
this.sendClientReports = sendClientReports;
}

public @NotNull List<String> getBundleIds() {
return bundleIds;
}

public void addBundleId(final @NotNull String bundleId) {
bundleIds.add(bundleId);
}
}
31 changes: 22 additions & 9 deletions sentry/src/main/java/io/sentry/MainEventProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand Down Expand Up @@ -66,23 +67,35 @@ public MainEventProcessor(final @NotNull SentryOptions options) {
}

private void setDebugMeta(final @NotNull SentryBaseEvent event) {
final @NotNull List<DebugImage> debugImages = new CopyOnWriteArrayList<>();

if (options.getProguardUuid() != null) {
final DebugImage proguardMappingImage = new DebugImage();
proguardMappingImage.setType(DebugImage.PROGUARD);
proguardMappingImage.setUuid(options.getProguardUuid());
debugImages.add(proguardMappingImage);
}

for (final @NotNull String bundleId : options.getBundleIds()) {
final DebugImage sourceBundleImage = new DebugImage();
sourceBundleImage.setType(DebugImage.JVM);
sourceBundleImage.setDebugId(bundleId);
debugImages.add(sourceBundleImage);
}

if (!debugImages.isEmpty()) {
DebugMeta debugMeta = event.getDebugMeta();

if (debugMeta == null) {
debugMeta = new DebugMeta();
}
if (debugMeta.getImages() == null) {
debugMeta.setImages(new ArrayList<>());
}
List<DebugImage> images = debugMeta.getImages();
if (images != null) {
final DebugImage debugImage = new DebugImage();
debugImage.setType(DebugImage.PROGUARD);
debugImage.setUuid(options.getProguardUuid());
images.add(debugImage);
event.setDebugMeta(debugMeta);
debugMeta.setImages(debugImages);
} else {
debugMeta.getImages().addAll(debugImages);
}

event.setDebugMeta(debugMeta);
}
}

Expand Down
31 changes: 31 additions & 0 deletions sentry/src/main/java/io/sentry/SentryOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ public class SentryOptions {
*/
private final @NotNull List<Integration> integrations = new CopyOnWriteArrayList<>();

/** List of bundle IDs representing source bundles. */
private final @NotNull Set<String> bundleIds = new CopyOnWriteArraySet<>();

/**
* The DSN tells the SDK where to send the events to. If this value is not provided, the SDK will
* just not send any events.
Expand Down Expand Up @@ -1776,6 +1779,31 @@ public void setProguardUuid(final @Nullable String proguardUuid) {
this.proguardUuid = proguardUuid;
}

/**
* Adds a bundle ID (also known as debugId) representing a source bundle that contains sources for
* this application. These sources will be used to source code for frames of an exceptions stack
* trace.
*
* @param bundleId Bundle ID generated by sentry-cli or the sentry-android-gradle-plugin
*/
public void addBundleId(final @Nullable String bundleId) {
if (bundleId != null) {
final @NotNull String trimmedBundleId = bundleId.trim();
if (!trimmedBundleId.isEmpty()) {
this.bundleIds.add(trimmedBundleId);
}
}
}

/**
* Returns all configured bundle IDs referencing source code bundles.
*
* @return list of bundle IDs
*/
public @NotNull Set<String> getBundleIds() {
return bundleIds;
}

/**
* Returns Context tags names applied to Sentry events as Sentry tags.
*
Expand Down Expand Up @@ -2229,6 +2257,9 @@ public void merge(final @NotNull ExternalOptions options) {
if (options.getIdleTimeout() != null) {
setIdleTimeout(options.getIdleTimeout());
}
for (String bundleId : options.getBundleIds()) {
addBundleId(bundleId);
}
}

private @NotNull SdkVersion createSdkVersion() {
Expand Down
1 change: 1 addition & 0 deletions sentry/src/main/java/io/sentry/protocol/DebugImage.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
*/
public final class DebugImage implements JsonUnknown, JsonSerializable {
public static final String PROGUARD = "proguard";
public static final String JVM = "jvm";

/**
* The unique UUID of the image.
Expand Down
31 changes: 31 additions & 0 deletions sentry/src/test/java/io/sentry/ExternalOptionsTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,37 @@ class ExternalOptionsTest {
}
}

@Test
fun `creates options with single bundle ID using external properties`() {
withPropertiesFile("bundle-ids=12ea7a02-46ac-44c0-a5bb-6d1fd9586411") { options ->
assertTrue(options.bundleIds.containsAll(listOf("12ea7a02-46ac-44c0-a5bb-6d1fd9586411")))
}
}

@Test
fun `creates options with multiple bundle IDs using external properties`() {
withPropertiesFile("bundle-ids=12ea7a02-46ac-44c0-a5bb-6d1fd9586411,faa3ab42-b1bd-4659-af8e-1682324aa744") { options ->
assertTrue(options.bundleIds.containsAll(listOf("12ea7a02-46ac-44c0-a5bb-6d1fd9586411", "faa3ab42-b1bd-4659-af8e-1682324aa744")))
}
}

@Test
fun `creates options with empty bundle IDs using external properties`() {
withPropertiesFile("bundle-ids=") { options ->
assertTrue(options.bundleIds.size == 1)
// trimming is tested in SentryOptionsTest so even though there's an empty string here
// it will be filtered when being merged with SentryOptions
assertTrue(options.bundleIds.containsAll(listOf("")))
}
}

@Test
fun `creates options with missing bundle IDs using external properties`() {
withPropertiesFile("") { options ->
assertTrue(options.bundleIds.isEmpty())
}
}

private fun withPropertiesFile(textLines: List<String> = emptyList(), logger: ILogger = mock(), fn: (ExternalOptions) -> Unit) {
// create a sentry.properties file in temporary folder
val temporaryFolder = TemporaryFolder()
Expand Down

0 comments on commit a874a2b

Please sign in to comment.