Skip to content

Commit

Permalink
Merge branch 'main' into feat/remove-sensitive-data-from-urls
Browse files Browse the repository at this point in the history
  • Loading branch information
adinauer committed Jan 27, 2023
2 parents 349930e + 0a390a6 commit 46cff12
Show file tree
Hide file tree
Showing 48 changed files with 1,153 additions and 295 deletions.
1 change: 1 addition & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<!--- Put an `x` in the boxes that apply -->
- [ ] I reviewed the submitted code
- [ ] I added tests to verify the changes
- [ ] No new PII added or SDK only sends newly added PII if `sendDefaultPII` is enabled
- [ ] I updated the docs if needed
- [ ] No breaking changes

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ jobs:
${{ runner.os }}-gradle-
- name: Initialize CodeQL
uses: github/codeql-action/init@515828d97454b8354517688ddc5b48402b723750 # pin@v2
uses: github/codeql-action/init@a34ca99b4610d924e04c68db79e503e1f79f9f02 # pin@v2
with:
languages: ${{ matrix.language }}

- run: |
./gradlew assemble
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@515828d97454b8354517688ddc5b48402b723750 # pin@v2
uses: github/codeql-action/analyze@a34ca99b4610d924e04c68db79e503e1f79f9f02 # pin@v2
18 changes: 17 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,23 @@

## Unreleased

### Fixes

- Remove authority from URLs sent to Sentry ([#2366](https://github.com/getsentry/sentry-java/pull/2366))

### Dependencies

- Bump Native SDK from v0.5.3 to v0.5.4 ([#2500](https://github.com/getsentry/sentry-java/pull/2500))
- [changelog](https://github.com/getsentry/sentry-native/blob/master/CHANGELOG.md#054)
- [diff](https://github.com/getsentry/sentry-native/compare/0.5.3...0.5.4)

## 6.13.0

### Features

- Send cpu usage percentage in profile payload ([#2469](https://github.com/getsentry/sentry-java/pull/2469))
- Send transaction memory stats in profile payload ([#2447](https://github.com/getsentry/sentry-java/pull/2447))
- Add cpu usage collection ([#2462](https://github.com/getsentry/sentry-java/pull/2462))
- Improve ANR implementation: ([#2475](https://github.com/getsentry/sentry-java/pull/2475))
- Add `abnormal_mechanism` to sessions for ANR rate calculation
- Always attach thread dump to ANR events
Expand All @@ -12,8 +27,9 @@

### Fixes

- Fix performance collector setup called in main thread ([#2499](https://github.com/getsentry/sentry-java/pull/2499))
- Expand guard against CVE-2018-9492 "Privilege Escalation via Content Provider" ([#2482](https://github.com/getsentry/sentry-java/pull/2482))
- Remove authority from URLs sent to Sentry ([#2366](https://github.com/getsentry/sentry-java/pull/2366))
- Prevent OOM by disabling TransactionPerformanceCollector for now ([#2498](https://github.com/getsentry/sentry-java/pull/2498))

## 6.12.1

Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ android.useAndroidX=true
android.defaults.buildfeatures.buildconfig=true

# Release information
versionName=6.12.1
versionName=6.13.0

# Override the SDK name on native crashes on Android
sentryAndroidSdkName=sentry.native.android
Expand Down
12 changes: 10 additions & 2 deletions sentry-android-core/api/sentry-android-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ public final class io/sentry/android/core/ActivityLifecycleIntegration : android
public fun register (Lio/sentry/IHub;Lio/sentry/SentryOptions;)V
}

public final class io/sentry/android/core/AndroidCpuCollector : io/sentry/ICollector {
public fun <init> (Lio/sentry/ILogger;Lio/sentry/android/core/BuildInfoProvider;)V
public fun collect (Ljava/lang/Iterable;)V
public fun setup ()V
}

public final class io/sentry/android/core/AndroidDateUtils {
public fun <init> ()V
public static fun getCurrentSentryDateTime ()Lio/sentry/SentryDate;
Expand All @@ -37,9 +43,10 @@ public final class io/sentry/android/core/AndroidLogger : io/sentry/ILogger {
public fun log (Lio/sentry/SentryLevel;Ljava/lang/Throwable;Ljava/lang/String;[Ljava/lang/Object;)V
}

public class io/sentry/android/core/AndroidMemoryCollector : io/sentry/IMemoryCollector {
public class io/sentry/android/core/AndroidMemoryCollector : io/sentry/ICollector {
public fun <init> ()V
public fun collect ()Lio/sentry/MemoryCollectionData;
public fun collect (Ljava/lang/Iterable;)V
public fun setup ()V
}

public final class io/sentry/android/core/AnrIntegration : io/sentry/Integration, java/io/Closeable {
Expand Down Expand Up @@ -257,6 +264,7 @@ public final class io/sentry/android/core/UserInteractionIntegration : android/a
public final class io/sentry/android/core/ViewHierarchyEventProcessor : io/sentry/EventProcessor {
public fun <init> (Lio/sentry/android/core/SentryAndroidOptions;)V
public fun process (Lio/sentry/SentryEvent;Lio/sentry/Hint;)Lio/sentry/SentryEvent;
public static fun snapshotViewHierarchy (Landroid/app/Activity;Lio/sentry/ILogger;)Lio/sentry/protocol/ViewHierarchy;
public static fun snapshotViewHierarchy (Landroid/view/View;)Lio/sentry/protocol/ViewHierarchy;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package io.sentry.android.core;

import android.annotation.SuppressLint;
import android.os.Build;
import android.os.SystemClock;
import android.system.Os;
import android.system.OsConstants;
import io.sentry.CpuCollectionData;
import io.sentry.ICollector;
import io.sentry.ILogger;
import io.sentry.PerformanceCollectionData;
import io.sentry.SentryLevel;
import io.sentry.util.FileUtils;
import io.sentry.util.Objects;
import java.io.File;
import java.io.IOException;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;

// The approach to get the cpu usage info was taken from
// https://eng.lyft.com/monitoring-cpu-performance-of-lyfts-android-applications-4e36fafffe12
// The content of the /proc/self/stat file is specified in
// https://man7.org/linux/man-pages/man5/proc.5.html
@ApiStatus.Internal
public final class AndroidCpuCollector implements ICollector {

private long lastRealtimeNanos = 0;
private long lastCpuNanos = 0;

/** Number of clock ticks per second. */
private long clockSpeedHz = 1;

private long numCores = 1;
private final long NANOSECOND_PER_SECOND = 1_000_000_000;

/** Number of nanoseconds per clock tick. */
private double nanosecondsPerClockTick = NANOSECOND_PER_SECOND / (double) clockSpeedHz;

/** File containing stats about this process. */
private final @NotNull File selfStat = new File("/proc/self/stat");

private final @NotNull ILogger logger;
private final @NotNull BuildInfoProvider buildInfoProvider;
private boolean isEnabled = false;

public AndroidCpuCollector(
final @NotNull ILogger logger, final @NotNull BuildInfoProvider buildInfoProvider) {
this.logger = Objects.requireNonNull(logger, "Logger is required.");
this.buildInfoProvider =
Objects.requireNonNull(buildInfoProvider, "BuildInfoProvider is required.");
}

@SuppressLint("NewApi")
@Override
public void setup() {
if (buildInfoProvider.getSdkInfoVersion() < Build.VERSION_CODES.LOLLIPOP) {
isEnabled = false;
return;
}
isEnabled = true;
clockSpeedHz = Os.sysconf(OsConstants._SC_CLK_TCK);
numCores = Os.sysconf(OsConstants._SC_NPROCESSORS_CONF);
nanosecondsPerClockTick = NANOSECOND_PER_SECOND / (double) clockSpeedHz;
lastCpuNanos = readTotalCpuNanos();
}

@SuppressLint("NewApi")
@Override
public void collect(
@NotNull final Iterable<PerformanceCollectionData> performanceCollectionData) {
if (buildInfoProvider.getSdkInfoVersion() < Build.VERSION_CODES.LOLLIPOP || !isEnabled) {
return;
}
final long nowNanos = SystemClock.elapsedRealtimeNanos();
final long realTimeNanosDiff = nowNanos - lastRealtimeNanos;
lastRealtimeNanos = nowNanos;
final long cpuNanos = readTotalCpuNanos();
final long cpuNanosDiff = cpuNanos - lastCpuNanos;
lastCpuNanos = cpuNanos;
// Later we need to divide the percentage by the number of cores, otherwise we could
// get a percentage value higher than 1. We also want to send the percentage as a
// number from 0 to 100, so we are going to multiply it by 100
final double cpuUsagePercentage = cpuNanosDiff / (double) realTimeNanosDiff;

CpuCollectionData cpuData =
new CpuCollectionData(
System.currentTimeMillis(), (cpuUsagePercentage / (double) numCores) * 100.0);

for (PerformanceCollectionData data : performanceCollectionData) {
data.addCpuData(cpuData);
}
}

/** Read the /proc/self/stat file and parses the result. */
private long readTotalCpuNanos() {
String stat = null;
try {
stat = FileUtils.readText(selfStat);
} catch (IOException e) {
// If an error occurs when reading the file, we avoid reading it again until the setup method
// is called again
isEnabled = false;
logger.log(
SentryLevel.WARNING, "Unable to read /proc/self/stat file. Disabling cpu collection.", e);
}
if (stat != null) {
stat = stat.trim();
String[] stats = stat.split("[\n\t\r ]");
try {
// Amount of clock ticks this process has been scheduled in user mode
long uTime = Long.parseLong(stats[13]);
// Amount of clock ticks this process has been scheduled in kernel mode
long sTime = Long.parseLong(stats[14]);
// Amount of clock ticks this process' waited-for children has been scheduled in user mode
long cuTime = Long.parseLong(stats[15]);
// Amount of clock ticks this process' waited-for children has been scheduled in kernel mode
long csTime = Long.parseLong(stats[16]);
return (long) ((uTime + sTime + cuTime + csTime) * nanosecondsPerClockTick);
} catch (NumberFormatException e) {
logger.log(SentryLevel.ERROR, "Error parsing /proc/self/stat file.", e);
return 0;
}
}
return 0;
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
package io.sentry.android.core;

import android.os.Debug;
import io.sentry.IMemoryCollector;
import io.sentry.ICollector;
import io.sentry.MemoryCollectionData;
import io.sentry.PerformanceCollectionData;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;

@ApiStatus.Internal
public class AndroidMemoryCollector implements IMemoryCollector {
public class AndroidMemoryCollector implements ICollector {

@Override
public void setup() {}

@Override
public MemoryCollectionData collect() {
public void collect(@NotNull Iterable<PerformanceCollectionData> performanceCollectionData) {
long now = System.currentTimeMillis();
long usedMemory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
long usedNativeMemory = Debug.getNativeHeapSize() - Debug.getNativeHeapFreeSize();
return new MemoryCollectionData(now, usedMemory, usedNativeMemory);
MemoryCollectionData memoryData = new MemoryCollectionData(now, usedMemory, usedNativeMemory);
for (PerformanceCollectionData data : performanceCollectionData) {
data.addMemoryData(memoryData);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,10 @@ static void initializeIntegrationsAndProcessors(
options.setGestureTargetLocators(gestureTargetLocators);
}
options.setMainThreadChecker(AndroidMainThreadChecker.getInstance());
options.setMemoryCollector(new AndroidMemoryCollector());
if (options.getCollectors().isEmpty()) {
options.addCollector(new AndroidMemoryCollector());
options.addCollector(new AndroidCpuCollector(options.getLogger(), buildInfoProvider));
}
}

private static void installDefaultIntegrations(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@
import android.os.Process;
import android.os.SystemClock;
import android.view.FrameMetrics;
import io.sentry.CpuCollectionData;
import io.sentry.HubAdapter;
import io.sentry.IHub;
import io.sentry.ITransaction;
import io.sentry.ITransactionProfiler;
import io.sentry.MemoryCollectionData;
import io.sentry.PerformanceCollectionData;
import io.sentry.ProfilingTraceData;
import io.sentry.ProfilingTransactionData;
import io.sentry.SentryLevel;
Expand Down Expand Up @@ -233,7 +236,7 @@ public void onFrameMetricCollected(
options
.getExecutorService()
.schedule(
() -> timedOutProfilingData = onTransactionFinish(transaction, true),
() -> timedOutProfilingData = onTransactionFinish(transaction, true, null),
PROFILING_TIMEOUT_MILLIS);

transactionStartNanos = SystemClock.elapsedRealtimeNanos();
Expand All @@ -247,11 +250,12 @@ public void onFrameMetricCollected(

@Override
public @Nullable synchronized ProfilingTraceData onTransactionFinish(
final @NotNull ITransaction transaction) {
final @NotNull ITransaction transaction,
final @Nullable PerformanceCollectionData performanceCollectionData) {
try {
return options
.getExecutorService()
.submit(() -> onTransactionFinish(transaction, false))
.submit(() -> onTransactionFinish(transaction, false, performanceCollectionData))
.get();
} catch (ExecutionException e) {
options.getLogger().log(SentryLevel.ERROR, "Error finishing profiling: ", e);
Expand All @@ -263,7 +267,9 @@ public void onFrameMetricCollected(

@SuppressLint("NewApi")
private @Nullable ProfilingTraceData onTransactionFinish(
final @NotNull ITransaction transaction, final boolean isTimeout) {
final @NotNull ITransaction transaction,
final boolean isTimeout,
final @Nullable PerformanceCollectionData performanceCollectionData) {

// onTransactionStart() is only available since Lollipop
// and SystemClock.elapsedRealtimeNanos() since Jelly Bean
Expand Down Expand Up @@ -383,6 +389,7 @@ public void onFrameMetricCollected(
ProfileMeasurement.ID_SCREEN_FRAME_RATES,
new ProfileMeasurement(ProfileMeasurement.UNIT_HZ, screenFrameRateMeasurements));
}
putPerformanceCollectionDataInMeasurements(performanceCollectionData);

// cpu max frequencies are read with a lambda because reading files is involved, so it will be
// done in the background when the trace file is read
Expand All @@ -408,6 +415,54 @@ public void onFrameMetricCollected(
measurementsMap);
}

private void putPerformanceCollectionDataInMeasurements(
final @Nullable PerformanceCollectionData performanceCollectionData) {
if (performanceCollectionData != null) {
final @NotNull ArrayDeque<ProfileMeasurementValue> memoryUsageMeasurements =
new ArrayDeque<>();
final @NotNull ArrayDeque<ProfileMeasurementValue> nativeMemoryUsageMeasurements =
new ArrayDeque<>();
final @NotNull ArrayDeque<ProfileMeasurementValue> cpuUsageMeasurements = new ArrayDeque<>();
for (CpuCollectionData cpuData : performanceCollectionData.getCpuData()) {
cpuUsageMeasurements.add(
new ProfileMeasurementValue(
TimeUnit.MILLISECONDS.toNanos(cpuData.getTimestampMillis()) - transactionStartNanos,
cpuData.getCpuUsagePercentage()));
}
for (MemoryCollectionData memoryData : performanceCollectionData.getMemoryData()) {
if (memoryData.getUsedHeapMemory() > -1) {
memoryUsageMeasurements.add(
new ProfileMeasurementValue(
TimeUnit.MILLISECONDS.toNanos(memoryData.getTimestampMillis())
- transactionStartNanos,
memoryData.getUsedHeapMemory()));
}
if (memoryData.getUsedNativeMemory() > -1) {
nativeMemoryUsageMeasurements.add(
new ProfileMeasurementValue(
TimeUnit.MILLISECONDS.toNanos(memoryData.getTimestampMillis())
- transactionStartNanos,
memoryData.getUsedNativeMemory()));
}
}
if (!cpuUsageMeasurements.isEmpty()) {
measurementsMap.put(
ProfileMeasurement.ID_CPU_USAGE,
new ProfileMeasurement(ProfileMeasurement.UNIT_PERCENT, cpuUsageMeasurements));
}
if (!memoryUsageMeasurements.isEmpty()) {
measurementsMap.put(
ProfileMeasurement.ID_MEMORY_FOOTPRINT,
new ProfileMeasurement(ProfileMeasurement.UNIT_BYTES, memoryUsageMeasurements));
}
if (!nativeMemoryUsageMeasurements.isEmpty()) {
measurementsMap.put(
ProfileMeasurement.ID_MEMORY_NATIVE_FOOTPRINT,
new ProfileMeasurement(ProfileMeasurement.UNIT_BYTES, nativeMemoryUsageMeasurements));
}
}
}

/**
* Get MemoryInfo object representing the memory state of the application.
*
Expand Down
Loading

0 comments on commit 46cff12

Please sign in to comment.