|
| 1 | +--- |
| 2 | +alwaysApply: false |
| 3 | +description: Android Profiling (sentry-android-core) |
| 4 | +--- |
| 5 | +# Android Profiling |
| 6 | + |
| 7 | +Android profiling lives in `sentry-android-core` and uses `Debug.startMethodTracingSampling()` for trace collection, with additional measurement collectors for frames, CPU, and memory. |
| 8 | + |
| 9 | +## Key Classes |
| 10 | + |
| 11 | +### `AndroidContinuousProfiler` |
| 12 | +- Implements `IContinuousProfiler` for continuous profiling across app lifecycle |
| 13 | +- Delegates to `AndroidProfiler` for actual trace collection |
| 14 | +- 60-second chunk duration (`MAX_CHUNK_DURATION_MILLIS`) |
| 15 | +- Platform: "android" |
| 16 | +- Maintains `rootSpanCounter` for TRACE mode, `profilerId` and `chunkId` per session/chunk |
| 17 | +- Collects measurements via `CompositePerformanceCollector` and `SentryFrameMetricsCollector` |
| 18 | +- Thread-safe with `lock` and `payloadLock` |
| 19 | + |
| 20 | +### `AndroidProfiler` |
| 21 | +- Low-level wrapper around `Debug.startMethodTracingSampling()` |
| 22 | +- Buffer size: 3MB, timeout: 30 seconds (for transaction profiling) |
| 23 | +- `start()`: Calls `Debug.startMethodTracingSampling(path, bufferSize, intervalUs)` and registers frame metrics listener |
| 24 | +- `endAndCollect()`: Stops tracing, collects measurements, returns `ProfileEndData` with trace file and measurements |
| 25 | + |
| 26 | +### `AndroidTransactionProfiler` |
| 27 | +- Implements `ITransactionProfiler` for per-transaction profiling (legacy) |
| 28 | +- `start()` / `bindTransaction()` / `onTransactionFinish()` lifecycle |
| 29 | +- Returns `ProfilingTraceData` on finish |
| 30 | + |
| 31 | +## Measurement Collectors |
| 32 | + |
| 33 | +- **`SentryFrameMetricsCollector`**: Frame metrics via `Window.OnFrameMetricsAvailableListener` |
| 34 | + - Uses `Choreographer` reflection for frame start timestamps |
| 35 | + - Tracks slow frames (> expected duration at refresh rate) and frozen frames (> 700ms) |
| 36 | +- **`AndroidMemoryCollector`**: Heap (`Runtime`) and native memory (`Debug.getNativeHeapSize()`) |
| 37 | +- **`AndroidCpuCollector`**: CPU usage from `/proc/self/stat` |
| 38 | +- **`SpanFrameMetricsCollector`**: Per-span frame metrics with interpolation |
| 39 | + |
| 40 | +## Measurements Included in Profile Chunks |
| 41 | + |
| 42 | +| Measurement | Unit | Source | |
| 43 | +|---|---|---| |
| 44 | +| Slow frame renders | nanoseconds | `SentryFrameMetricsCollector` | |
| 45 | +| Frozen frame renders | nanoseconds | `SentryFrameMetricsCollector` | |
| 46 | +| Screen frame rates | Hz | `SentryFrameMetricsCollector` | |
| 47 | +| CPU usage | percent | `AndroidCpuCollector` | |
| 48 | +| Memory footprint | bytes | `AndroidMemoryCollector` (heap) | |
| 49 | +| Native memory footprint | bytes | `AndroidMemoryCollector` (native) | |
| 50 | + |
| 51 | +## Configuration |
| 52 | + |
| 53 | +Same base options as JVM profiling (`profilesSampleRate`, `profileLifecycle`, `profilingTracesHz`), plus: |
| 54 | +- `profilingTracesDirPath` set automatically from app cache directory |
| 55 | +- Frame metrics collector initialized with Android `Context` |
| 56 | +- Setup in `AndroidOptionsInitializer.installDefaultIntegrations()` |
| 57 | + |
| 58 | +## Profiling Flow |
| 59 | + |
| 60 | +**Start**: `AndroidContinuousProfiler.start()` -> `AndroidProfiler.start()` -> `Debug.startMethodTracingSampling()` + register frame metrics listener + schedule 60s timeout |
| 61 | + |
| 62 | +**Chunk Rotation** (every 60s): Stop tracing -> collect measurements -> create `ProfileChunk.Builder` with measurements and trace file -> queue in `payloadBuilders` -> restart profiler |
| 63 | + |
| 64 | +**Sending**: `sendChunks()` builds each `ProfileChunk.Builder` and calls `scopes.captureProfileChunk()` |
| 65 | + |
| 66 | +**Lifecycle modes**: Same as JVM - MANUAL (explicit start/stop) and TRACE (`rootSpanCounter` for automatic lifecycle) |
| 67 | + |
| 68 | +## Initialization |
| 69 | + |
| 70 | +In `AndroidOptionsInitializer`: |
| 71 | +- `AndroidContinuousProfiler` created with `AndroidProfiler`, `BuildInfoProvider`, `SentryFrameMetricsCollector` |
| 72 | +- Profiler may already be running from app start profiling before SDK init |
| 73 | +- If already running at init, existing chunk ID is preserved |
| 74 | + |
| 75 | +## Code Locations |
| 76 | + |
| 77 | +- `sentry-android-core/src/main/java/io/sentry/android/core/AndroidContinuousProfiler.java` |
| 78 | +- `sentry-android-core/src/main/java/io/sentry/android/core/AndroidProfiler.java` |
| 79 | +- `sentry-android-core/src/main/java/io/sentry/android/core/AndroidTransactionProfiler.java` |
| 80 | +- `sentry-android-core/src/main/java/io/sentry/android/core/AndroidMemoryCollector.java` |
| 81 | +- `sentry-android-core/src/main/java/io/sentry/android/core/AndroidCpuCollector.java` |
| 82 | +- `sentry-android-core/src/main/java/io/sentry/android/core/SpanFrameMetricsCollector.java` |
| 83 | +- `sentry-android-core/src/main/java/io/sentry/android/core/internal/util/SentryFrameMetricsCollector.java` |
0 commit comments