mirror of
git://f0xx.org/android_cast
synced 2026-07-29 07:39:15 +03:00
snap, 20260522_late_night
This commit is contained in:
@@ -26,6 +26,30 @@
|
|||||||
client_max_body_size 4m;
|
client_max_body_size 4m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location = /app/androidcast_project/crashes/api/diag.php {
|
||||||
|
include fastcgi_params;
|
||||||
|
fastcgi_pass unix:/run/php-fpm.socket;
|
||||||
|
fastcgi_param SCRIPT_FILENAME /var/www/localhost/htdocs/apps/app/androidcast_project/android_cast/examples/crash_reporter/backend/public/api/diag.php;
|
||||||
|
fastcgi_param SCRIPT_NAME /app/androidcast_project/crashes/api/diag.php;
|
||||||
|
fastcgi_param REQUEST_URI $request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /app/androidcast_project/crashes/api/reports.php {
|
||||||
|
include fastcgi_params;
|
||||||
|
fastcgi_pass unix:/run/php-fpm.socket;
|
||||||
|
fastcgi_param SCRIPT_FILENAME /var/www/localhost/htdocs/apps/app/androidcast_project/android_cast/examples/crash_reporter/backend/public/api/reports.php;
|
||||||
|
fastcgi_param SCRIPT_NAME /app/androidcast_project/crashes/api/reports.php;
|
||||||
|
fastcgi_param REQUEST_URI $request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /app/androidcast_project/crashes/api/report_viewed.php {
|
||||||
|
include fastcgi_params;
|
||||||
|
fastcgi_pass unix:/run/php-fpm.socket;
|
||||||
|
fastcgi_param SCRIPT_FILENAME /var/www/localhost/htdocs/apps/app/androidcast_project/android_cast/examples/crash_reporter/backend/public/api/report_viewed.php;
|
||||||
|
fastcgi_param SCRIPT_NAME /app/androidcast_project/crashes/api/report_viewed.php;
|
||||||
|
fastcgi_param REQUEST_URI $request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
location ^~ /app/androidcast_project/crashes/ {
|
location ^~ /app/androidcast_project/crashes/ {
|
||||||
include fastcgi_params;
|
include fastcgi_params;
|
||||||
fastcgi_pass unix:/run/php-fpm.socket;
|
fastcgi_pass unix:/run/php-fpm.socket;
|
||||||
|
|||||||
47
examples/crash_reporter/backend/public/api/diag.php
Normal file
47
examples/crash_reporter/backend/public/api/diag.php
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
require_once __DIR__ . '/../../src/bootstrap.php';
|
||||||
|
|
||||||
|
if (!cfg('debug')) {
|
||||||
|
json_out(['ok' => false, 'error' => 'diag disabled'], 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = cfg('db.sqlite_path');
|
||||||
|
$out = [
|
||||||
|
'ok' => true,
|
||||||
|
'php_user' => get_current_user(),
|
||||||
|
'sqlite_path' => $path,
|
||||||
|
'sqlite_realpath' => is_string($path) ? realpath($path) : null,
|
||||||
|
'sqlite_exists' => is_string($path) && is_file($path),
|
||||||
|
'sqlite_writable' => is_string($path) && is_writable($path),
|
||||||
|
'data_dir_writable' => is_string($path) && is_writable(dirname($path)),
|
||||||
|
'storage_writable' => is_writable(dirname(__DIR__) . '/../storage'),
|
||||||
|
'tables' => [],
|
||||||
|
'reports_columns' => [],
|
||||||
|
'test_insert' => null,
|
||||||
|
];
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = Database::pdo();
|
||||||
|
$tables = $pdo->query(
|
||||||
|
"SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name"
|
||||||
|
)->fetchAll(PDO::FETCH_COLUMN);
|
||||||
|
$out['tables'] = $tables;
|
||||||
|
if (in_array('reports', $tables, true)) {
|
||||||
|
$out['reports_columns'] = $pdo->query('PRAGMA table_info(reports)')->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
}
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
$stmt = $pdo->prepare(
|
||||||
|
'INSERT INTO reports (report_id, fingerprint, crash_type, generated_at_ms, received_at_ms, device_model, app_version, payload_json)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)'
|
||||||
|
);
|
||||||
|
$rid = 'diag-' . time();
|
||||||
|
$stmt->execute([$rid, 'diag', 'java', 1, 1, null, null, '{}']);
|
||||||
|
$pdo->rollBack();
|
||||||
|
$out['test_insert'] = 'ok (rolled back)';
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
$out['ok'] = false;
|
||||||
|
$out['test_insert'] = $e->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
json_out($out);
|
||||||
25
examples/crash_reporter/backend/public/api/report_viewed.php
Normal file
25
examples/crash_reporter/backend/public/api/report_viewed.php
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
require_once __DIR__ . '/../../src/bootstrap.php';
|
||||||
|
|
||||||
|
if (!Auth::user()) {
|
||||||
|
json_out(['ok' => false, 'error' => 'unauthorized'], 401);
|
||||||
|
}
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||||
|
json_out(['ok' => false, 'error' => 'POST required'], 405);
|
||||||
|
}
|
||||||
|
|
||||||
|
$raw = file_get_contents('php://input');
|
||||||
|
$data = is_string($raw) && $raw !== '' ? json_decode($raw, true) : $_POST;
|
||||||
|
$id = (int) ($data['id'] ?? 0);
|
||||||
|
if ($id <= 0) {
|
||||||
|
json_out(['ok' => false, 'error' => 'invalid id'], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ReportRepository::markViewed($id, (int) Auth::user()['id']);
|
||||||
|
json_out(['ok' => true, 'id' => $id]);
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
error_log('report_viewed: ' . $e->getMessage());
|
||||||
|
json_out(['ok' => false, 'error' => 'failed'], 500);
|
||||||
|
}
|
||||||
26
examples/crash_reporter/backend/public/api/reports.php
Normal file
26
examples/crash_reporter/backend/public/api/reports.php
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
require_once __DIR__ . '/../../src/bootstrap.php';
|
||||||
|
|
||||||
|
if (!Auth::user()) {
|
||||||
|
json_out(['ok' => false, 'error' => 'unauthorized'], 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
$grouped = isset($_GET['group']) && $_GET['group'] === '1';
|
||||||
|
$page = max(1, (int) ($_GET['page'] ?? 1));
|
||||||
|
$perPage = (int) ($_GET['per_page'] ?? 50);
|
||||||
|
$allowedPerPage = [25, 50, 75, 100, 200];
|
||||||
|
if (!in_array($perPage, $allowedPerPage, true)) {
|
||||||
|
$perPage = 50;
|
||||||
|
}
|
||||||
|
$sort = (string) ($_GET['sort'] ?? ($grouped ? 'cnt' : 'generated_at_ms'));
|
||||||
|
$dir = (string) ($_GET['dir'] ?? 'desc');
|
||||||
|
$sinceMs = max(0, (int) ($_GET['since_ms'] ?? 0));
|
||||||
|
|
||||||
|
try {
|
||||||
|
$data = ReportRepository::listPage($grouped, $page, $perPage, $sort, $dir, $sinceMs);
|
||||||
|
json_out(['ok' => true] + $data);
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
error_log('reports api: ' . $e->getMessage());
|
||||||
|
json_out(['ok' => false, 'error' => 'list failed'], 500);
|
||||||
|
}
|
||||||
@@ -33,6 +33,7 @@ try {
|
|||||||
json_out(['ok' => false, 'error' => 'duplicate report_id'], 409);
|
json_out(['ok' => false, 'error' => 'duplicate report_id'], 409);
|
||||||
}
|
}
|
||||||
error_log('crash upload PDO: ' . $msg);
|
error_log('crash upload PDO: ' . $msg);
|
||||||
|
log_crash_event('upload', 'PDO: ' . $msg);
|
||||||
$out = ['ok' => false, 'error' => 'store failed'];
|
$out = ['ok' => false, 'error' => 'store failed'];
|
||||||
if (cfg('debug')) {
|
if (cfg('debug')) {
|
||||||
$out['hint'] = $msg;
|
$out['hint'] = $msg;
|
||||||
@@ -40,6 +41,7 @@ try {
|
|||||||
json_out($out, 500);
|
json_out($out, 500);
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
error_log('crash upload: ' . $e->getMessage());
|
error_log('crash upload: ' . $e->getMessage());
|
||||||
|
log_crash_event('upload', $e->getMessage());
|
||||||
$out = ['ok' => false, 'error' => 'store failed'];
|
$out = ['ok' => false, 'error' => 'store failed'];
|
||||||
if (cfg('debug')) {
|
if (cfg('debug')) {
|
||||||
$out['hint'] = $e->getMessage();
|
$out['hint'] = $e->getMessage();
|
||||||
|
|||||||
@@ -1,12 +1,30 @@
|
|||||||
:root {
|
:root,
|
||||||
|
[data-theme="dark"] {
|
||||||
--bg: #0f1419;
|
--bg: #0f1419;
|
||||||
--surface: #1a2332;
|
--surface: #1a2332;
|
||||||
|
--surface2: #0a0e14;
|
||||||
--border: #2d3a4f;
|
--border: #2d3a4f;
|
||||||
--text: #e7ecf3;
|
--text: #e7ecf3;
|
||||||
--muted: #8b9cb3;
|
--muted: #8b9cb3;
|
||||||
--accent: #3d8bfd;
|
--accent: #3d8bfd;
|
||||||
--accent2: #5eead4;
|
--accent2: #5eead4;
|
||||||
--danger: #f87171;
|
--danger: #f87171;
|
||||||
|
--row-hover: rgba(61, 139, 253, .12);
|
||||||
|
--row-open: rgba(61, 139, 253, .08);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="light"] {
|
||||||
|
--bg: #f0f2f6;
|
||||||
|
--surface: #ffffff;
|
||||||
|
--surface2: #e8ecf2;
|
||||||
|
--border: #c5d0e0;
|
||||||
|
--text: #1a2332;
|
||||||
|
--muted: #5a6b82;
|
||||||
|
--accent: #2563eb;
|
||||||
|
--accent2: #0d9488;
|
||||||
|
--danger: #dc2626;
|
||||||
|
--row-hover: rgba(37, 99, 235, .1);
|
||||||
|
--row-open: rgba(37, 99, 235, .06);
|
||||||
}
|
}
|
||||||
* { box-sizing: border-box; }
|
* { box-sizing: border-box; }
|
||||||
body {
|
body {
|
||||||
@@ -331,10 +349,232 @@ a:hover { text-decoration: underline; }
|
|||||||
.btn.active { background: var(--accent); border-color: var(--accent); color: #fff; }
|
.btn.active { background: var(--accent); border-color: var(--accent); color: #fff; }
|
||||||
.data-table { width: 100%; border-collapse: collapse; margin-top: 16px; font-size: 14px; }
|
.data-table { width: 100%; border-collapse: collapse; margin-top: 16px; font-size: 14px; }
|
||||||
.data-table th, .data-table td { border-bottom: 1px solid var(--border); padding: 10px 8px; text-align: left; }
|
.data-table th, .data-table td { border-bottom: 1px solid var(--border); padding: 10px 8px; text-align: left; }
|
||||||
|
.reports-tree .report-tree-head { width: 2.5rem; padding: 0; }
|
||||||
|
.reports-tree .report-tree-cell {
|
||||||
|
width: 2.5rem;
|
||||||
|
padding: 6px 4px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.report-tree-toggle {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 2rem;
|
||||||
|
height: 2rem;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--muted);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background .12s ease, color .12s ease;
|
||||||
|
}
|
||||||
|
.report-tree-toggle:hover,
|
||||||
|
.report-tree-toggle:focus-visible {
|
||||||
|
background: rgba(61, 139, 253, .18);
|
||||||
|
color: var(--accent);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
.report-tree-arrow {
|
||||||
|
display: block;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-top: 5px solid transparent;
|
||||||
|
border-bottom: 5px solid transparent;
|
||||||
|
border-left: 7px solid currentColor;
|
||||||
|
transition: transform .18s ease;
|
||||||
|
}
|
||||||
|
.report-tree-toggle[aria-expanded="true"] .report-tree-arrow {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
.report-row {
|
||||||
|
transition: background .12s ease;
|
||||||
|
}
|
||||||
|
.report-row--nav { cursor: pointer; }
|
||||||
|
.report-row:hover,
|
||||||
|
.report-row:focus-within,
|
||||||
|
.report-brief-panel--nav:hover,
|
||||||
|
.report-brief-panel--nav:focus-within {
|
||||||
|
background: var(--row-hover);
|
||||||
|
}
|
||||||
|
.report-row.report-row--open {
|
||||||
|
background: var(--row-open);
|
||||||
|
}
|
||||||
|
.report-brief-panel--nav {
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 0 8px 8px 0;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.report-brief-panel--nav:focus {
|
||||||
|
outline: 2px solid var(--accent);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
.report-brief-row[hidden] { display: none; }
|
||||||
|
.report-brief-cell {
|
||||||
|
padding: 0 12px 12px 2.75rem !important;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
background: var(--surface2);
|
||||||
|
}
|
||||||
|
.report-brief {
|
||||||
|
margin: 0;
|
||||||
|
padding: 10px 14px;
|
||||||
|
border-left: 3px solid var(--accent);
|
||||||
|
border-radius: 0 8px 8px 0;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.45;
|
||||||
|
}
|
||||||
|
.report-brief p { margin: 0 0 6px; }
|
||||||
|
.report-brief p:last-child { margin-bottom: 0; }
|
||||||
|
.report-brief-hint { font-size: 12px; margin-top: 8px !important; }
|
||||||
.badge { background: var(--accent2); color: #042; padding: 2px 8px; border-radius: 999px; font-weight: 700; }
|
.badge { background: var(--accent2); color: #042; padding: 2px 8px; border-radius: 999px; font-weight: 700; }
|
||||||
.stack { background: #0a0e14; padding: 16px; border-radius: 8px; overflow-x: auto; font-size: 13px; line-height: 1.5; }
|
.stack { background: var(--surface2); padding: 16px; border-radius: 8px; overflow-x: auto; font-size: 13px; line-height: 1.5; }
|
||||||
|
.reports-toolbar .toolbar-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
|
||||||
|
.toolbar-select { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--muted); }
|
||||||
|
.toolbar-select select {
|
||||||
|
padding: 6px 8px;
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
background: var(--bg);
|
||||||
|
color: var(--text);
|
||||||
|
}
|
||||||
|
.reports-mode-btn { margin-left: 0; }
|
||||||
|
.reports-mode-btn.active { background: var(--accent); border-color: var(--accent); color: #fff; }
|
||||||
|
.reports-status { margin: 8px 0 0; min-height: 1.2em; }
|
||||||
|
.reports-table-wrap { overflow-x: auto; }
|
||||||
|
.reports-pagination { margin-top: 16px; }
|
||||||
|
.pagination-inner {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
.page-btn:disabled { opacity: .45; cursor: not-allowed; }
|
||||||
|
.page-info { font-size: 13px; color: var(--muted); }
|
||||||
|
.data-table th.sortable {
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.data-table th.sortable:hover { color: var(--accent); }
|
||||||
|
.data-table th.sortable--active { color: var(--accent); }
|
||||||
|
.sort-ind { display: inline-block; min-width: 1em; font-size: 11px; opacity: .85; }
|
||||||
|
.sort-idle { opacity: .35; }
|
||||||
|
.col-tags {
|
||||||
|
min-width: 6rem;
|
||||||
|
max-width: 11rem;
|
||||||
|
text-align: right;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.col-tags .report-tags {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 4px;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
.data-table th.col-tags { text-align: right; }
|
||||||
|
.report-tag {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 999px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.4;
|
||||||
|
color: #fff;
|
||||||
|
background: var(--tag-bg, #5c6b82);
|
||||||
|
}
|
||||||
.exc { color: var(--danger); font-weight: 600; }
|
.exc { color: var(--danger); font-weight: 600; }
|
||||||
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; margin: 20px 0; }
|
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; margin: 20px 0; }
|
||||||
.card { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 16px; }
|
.card { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 16px; }
|
||||||
|
.cards--lift .card--lift {
|
||||||
|
transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
|
||||||
|
}
|
||||||
|
.cards--lift .card--lift:hover {
|
||||||
|
transform: translateY(-4px);
|
||||||
|
box-shadow: 0 10px 24px rgba(0, 0, 0, .22);
|
||||||
|
border-color: var(--accent);
|
||||||
|
}
|
||||||
|
[data-theme="light"] .cards--lift .card--lift:hover {
|
||||||
|
box-shadow: 0 10px 22px rgba(26, 35, 50, .14);
|
||||||
|
}
|
||||||
|
.detail-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 14px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
.back-link {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 2.5rem;
|
||||||
|
height: 2.5rem;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
color: var(--text);
|
||||||
|
text-decoration: none;
|
||||||
|
flex-shrink: 0;
|
||||||
|
transition: background .15s ease, border-color .15s ease, color .15s ease;
|
||||||
|
}
|
||||||
|
.back-link:hover {
|
||||||
|
background: var(--row-hover);
|
||||||
|
border-color: var(--accent);
|
||||||
|
color: var(--accent);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.back-icon {
|
||||||
|
display: block;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
margin-left: 3px;
|
||||||
|
border-left: 2px solid currentColor;
|
||||||
|
border-bottom: 2px solid currentColor;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
.detail-tree {
|
||||||
|
margin-top: 20px;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.detail-tree-item + .detail-tree-item {
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
.detail-tree-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: stretch;
|
||||||
|
width: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background .12s ease;
|
||||||
|
}
|
||||||
|
.detail-tree-row:hover,
|
||||||
|
.detail-tree-row:focus-within,
|
||||||
|
.detail-tree-row.report-row--open {
|
||||||
|
background: var(--row-hover);
|
||||||
|
}
|
||||||
|
.detail-tree-caption {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.detail-tree-body {
|
||||||
|
padding: 0 14px 14px 2.75rem;
|
||||||
|
background: var(--surface2);
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
.detail-tree-body[hidden] { display: none; }
|
||||||
|
.star-rating { display: inline-flex; gap: 2px; line-height: 1; }
|
||||||
|
.star {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);
|
||||||
|
background: var(--border);
|
||||||
|
}
|
||||||
|
.star--on { background: #f59e0b; }
|
||||||
|
[data-theme="light"] .star--on { background: #d97706; }
|
||||||
.muted { color: var(--muted); }
|
.muted { color: var(--muted); }
|
||||||
.alert { background: rgba(248,113,113,.15); color: var(--danger); padding: 10px; border-radius: 8px; }
|
.alert { background: rgba(248,113,113,.15); color: var(--danger); padding: 10px; border-radius: 8px; }
|
||||||
|
|||||||
@@ -1,4 +1,103 @@
|
|||||||
document.addEventListener('DOMContentLoaded', () => {
|
(function () {
|
||||||
|
const STORAGE = {
|
||||||
|
theme: 'crash_console_theme',
|
||||||
|
perPage: 'crash_console_per_page',
|
||||||
|
lastVisit: 'crash_console_last_visit_ms',
|
||||||
|
viewed: 'crash_console_viewed_ids',
|
||||||
|
sort: 'crash_console_sort',
|
||||||
|
skipStamp: 'crash_skip_visit_stamp',
|
||||||
|
};
|
||||||
|
|
||||||
|
const TAG_NEW = { label: 'new', bg: '#3d8bfd' };
|
||||||
|
const CRASH_KIND_TAGS = {
|
||||||
|
native: { label: 'NDK', bg: '#b45309' },
|
||||||
|
java: { label: 'Java', bg: '#6d28d9' },
|
||||||
|
android: { label: 'Android', bg: '#047857' },
|
||||||
|
};
|
||||||
|
|
||||||
|
const LIST_COLUMNS = [
|
||||||
|
{ key: 'device_model', label: 'Device' },
|
||||||
|
{ key: 'app_version', label: 'App' },
|
||||||
|
{ key: 'os_name', label: 'OS' },
|
||||||
|
{ key: 'os_version', label: 'OS ver' },
|
||||||
|
{ key: 'received_at_ms', label: 'Received', fmt: 'time' },
|
||||||
|
{ key: 'rating', label: 'Rating', fmt: 'stars', noSort: true },
|
||||||
|
];
|
||||||
|
|
||||||
|
const SORT_API_MAP = {
|
||||||
|
os_name: 'device_model',
|
||||||
|
os_version: 'app_version',
|
||||||
|
rating: 'fingerprint_cnt',
|
||||||
|
};
|
||||||
|
|
||||||
|
const GROUP_COLUMNS = [
|
||||||
|
{ key: 'cnt', label: 'Count' },
|
||||||
|
{ key: 'fingerprint', label: 'Fingerprint', fmt: 'fp' },
|
||||||
|
{ key: 'crash_type', label: 'Type' },
|
||||||
|
{ key: 'last_generated_ms', label: 'Last generated', fmt: 'time' },
|
||||||
|
{ key: 'last_received_ms', label: 'Last received', fmt: 'time' },
|
||||||
|
];
|
||||||
|
|
||||||
|
function basePath() {
|
||||||
|
return document.body.getAttribute('data-base-path') || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function lsGet(key, fallback) {
|
||||||
|
try {
|
||||||
|
const v = localStorage.getItem(key);
|
||||||
|
return v === null ? fallback : v;
|
||||||
|
} catch {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function lsSet(key, value) {
|
||||||
|
try {
|
||||||
|
localStorage.setItem(key, value);
|
||||||
|
} catch { /* ignore */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
function getViewedIds() {
|
||||||
|
try {
|
||||||
|
const raw = lsGet(STORAGE.viewed, '[]');
|
||||||
|
const arr = JSON.parse(raw);
|
||||||
|
return new Set(Array.isArray(arr) ? arr.map(Number).filter(Boolean) : []);
|
||||||
|
} catch {
|
||||||
|
return new Set();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addViewedId(id) {
|
||||||
|
const set = getViewedIds();
|
||||||
|
set.add(Number(id));
|
||||||
|
lsSet(STORAGE.viewed, JSON.stringify([...set]));
|
||||||
|
}
|
||||||
|
|
||||||
|
function lastVisitMs() {
|
||||||
|
return Number(lsGet(STORAGE.lastVisit, '0')) || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function stampLastVisit() {
|
||||||
|
lsSet(STORAGE.lastVisit, String(Date.now()));
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyTheme(theme) {
|
||||||
|
const t = theme === 'light' ? 'light' : 'dark';
|
||||||
|
document.documentElement.setAttribute('data-theme', t);
|
||||||
|
lsSet(STORAGE.theme, t);
|
||||||
|
const sel = document.getElementById('theme-select');
|
||||||
|
if (sel) sel.value = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
function initTheme() {
|
||||||
|
applyTheme(lsGet(STORAGE.theme, 'dark'));
|
||||||
|
const sel = document.getElementById('theme-select');
|
||||||
|
if (sel) {
|
||||||
|
sel.addEventListener('change', () => applyTheme(sel.value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function initNav() {
|
||||||
const nav = document.getElementById('nav-pane');
|
const nav = document.getElementById('nav-pane');
|
||||||
const handle = document.getElementById('nav-handle');
|
const handle = document.getElementById('nav-handle');
|
||||||
if (!nav || !handle) return;
|
if (!nav || !handle) return;
|
||||||
@@ -7,4 +106,446 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
handle.setAttribute('aria-expanded', open ? 'true' : 'false');
|
handle.setAttribute('aria-expanded', open ? 'true' : 'false');
|
||||||
});
|
});
|
||||||
handle.setAttribute('aria-expanded', nav.classList.contains('open') ? 'true' : 'false');
|
handle.setAttribute('aria-expanded', nav.classList.contains('open') ? 'true' : 'false');
|
||||||
});
|
}
|
||||||
|
|
||||||
|
function markReportViewed(id) {
|
||||||
|
if (!id) return;
|
||||||
|
addViewedId(id);
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
xhr.open('POST', basePath() + '/api/report_viewed.php', true);
|
||||||
|
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||||
|
xhr.send(JSON.stringify({ id: Number(id) }));
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindDetailTree(root) {
|
||||||
|
root.querySelectorAll('[data-tree-toggle]').forEach((row) => {
|
||||||
|
const panelId = row.getAttribute('data-controls');
|
||||||
|
const panel = panelId ? document.getElementById(panelId) : null;
|
||||||
|
const btn = row.querySelector('.report-tree-toggle');
|
||||||
|
if (!panel) return;
|
||||||
|
const toggle = (e) => {
|
||||||
|
if (e && e.target.closest('.report-tree-toggle') && e.type === 'click') {
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
const open = panel.hidden;
|
||||||
|
panel.hidden = !open;
|
||||||
|
if (btn) btn.setAttribute('aria-expanded', open ? 'true' : 'false');
|
||||||
|
row.classList.toggle('report-row--open', open);
|
||||||
|
};
|
||||||
|
if (btn) {
|
||||||
|
btn.addEventListener('click', (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
toggle(e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
row.addEventListener('click', () => toggle());
|
||||||
|
row.addEventListener('keydown', (e) => {
|
||||||
|
if (e.key === 'Enter' || e.key === ' ') {
|
||||||
|
e.preventDefault();
|
||||||
|
toggle();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function initReportDetail() {
|
||||||
|
const id = document.body.getAttribute('data-report-id');
|
||||||
|
if (!id) return;
|
||||||
|
markReportViewed(id);
|
||||||
|
const tree = document.getElementById('detail-tree');
|
||||||
|
if (tree) bindDetailTree(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeHtml(s) {
|
||||||
|
return String(s)
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/"/g, '"');
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatTime(ms) {
|
||||||
|
if (!ms) return '—';
|
||||||
|
const d = new Date(Number(ms));
|
||||||
|
return d.toISOString().replace('T', ' ').slice(0, 19);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatCell(col, row) {
|
||||||
|
const v = row[col.key];
|
||||||
|
if (col.fmt === 'time') return formatTime(v);
|
||||||
|
if (col.fmt === 'stars') return formatStars(Number(row.rating ?? 0));
|
||||||
|
if (col.fmt === 'fp') {
|
||||||
|
const s = String(v || '');
|
||||||
|
return '<code class="fp">' + escapeHtml(s.slice(0, 12)) + (s.length > 12 ? '…' : '') + '</code>';
|
||||||
|
}
|
||||||
|
return escapeHtml(v ?? '') || '<span class="muted">—</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatStars(n) {
|
||||||
|
const score = Math.max(0, Math.min(5, Number(n) || 0));
|
||||||
|
let html =
|
||||||
|
'<span class="star-rating" role="img" aria-label="' + score + ' out of 5 priority">';
|
||||||
|
for (let i = 1; i <= 5; i++) {
|
||||||
|
html += '<span class="star' + (i <= score ? ' star--on' : '') + '" aria-hidden="true"></span>';
|
||||||
|
}
|
||||||
|
return html + '</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function crashKindTag(crashType) {
|
||||||
|
const t = String(crashType || '').toLowerCase();
|
||||||
|
return CRASH_KIND_TAGS[t] || { label: t || '?', bg: '#5c6b82' };
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTagPills(tags) {
|
||||||
|
if (!tags.length) return '<span class="muted">—</span>';
|
||||||
|
return tags
|
||||||
|
.map(
|
||||||
|
(t) =>
|
||||||
|
'<span class="report-tag" style="--tag-bg:' +
|
||||||
|
escapeHtml(t.bg) +
|
||||||
|
'">' +
|
||||||
|
escapeHtml(t.label) +
|
||||||
|
'</span>'
|
||||||
|
)
|
||||||
|
.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildTags(row, grouped) {
|
||||||
|
const tags = [];
|
||||||
|
const kind = crashKindTag(row.crash_type);
|
||||||
|
tags.push(kind);
|
||||||
|
if (!grouped && row.id) {
|
||||||
|
const viewed = row.viewed || getViewedIds().has(Number(row.id));
|
||||||
|
const sinceVisit = Number(row.received_at_ms) > lastVisitMs();
|
||||||
|
if (!viewed && (lastVisitMs() === 0 || sinceVisit)) {
|
||||||
|
tags.push(TAG_NEW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Array.isArray(row.tags)) {
|
||||||
|
row.tags.forEach((t) => {
|
||||||
|
if (!t || !t.id) return;
|
||||||
|
const id = String(t.id).toLowerCase();
|
||||||
|
if (id === 'new' || id === 'java' || id === 'ndk' || id === 'android') return;
|
||||||
|
tags.push({
|
||||||
|
label: t.label || t.id,
|
||||||
|
bg: t.bg || '#5c6b82',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return renderTagPills(tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
function apiSortKey(key) {
|
||||||
|
return SORT_API_MAP[key] || key;
|
||||||
|
}
|
||||||
|
|
||||||
|
function navigateTo(href) {
|
||||||
|
try {
|
||||||
|
sessionStorage.setItem(STORAGE.skipStamp, '1');
|
||||||
|
} catch { /* ignore */ }
|
||||||
|
window.location.href = href;
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindTreeInteractions(root) {
|
||||||
|
root.querySelectorAll('.report-tree-toggle').forEach((btn) => {
|
||||||
|
btn.addEventListener('click', (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
const id = btn.getAttribute('aria-controls');
|
||||||
|
const briefRow = id ? document.getElementById(id) : null;
|
||||||
|
const row = btn.closest('.report-row');
|
||||||
|
if (!briefRow || !row) return;
|
||||||
|
const open = briefRow.hidden;
|
||||||
|
briefRow.hidden = !open;
|
||||||
|
btn.setAttribute('aria-expanded', open ? 'true' : 'false');
|
||||||
|
row.classList.toggle('report-row--open', open);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
root.querySelectorAll('[data-href]').forEach((el) => {
|
||||||
|
const href = el.getAttribute('data-href');
|
||||||
|
if (!href) return;
|
||||||
|
const go = () => navigateTo(href);
|
||||||
|
const onActivate = (e) => {
|
||||||
|
if (e.target.closest('.report-tree-toggle')) return;
|
||||||
|
go();
|
||||||
|
};
|
||||||
|
el.addEventListener('click', onActivate);
|
||||||
|
el.addEventListener('keydown', (e) => {
|
||||||
|
if (e.target.closest('.report-tree-toggle')) return;
|
||||||
|
if (e.key === 'Enter' || e.key === ' ') {
|
||||||
|
e.preventDefault();
|
||||||
|
go();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function initReportsApp() {
|
||||||
|
const app = document.getElementById('reports-app');
|
||||||
|
if (!app) return;
|
||||||
|
|
||||||
|
const thead = document.getElementById('reports-thead');
|
||||||
|
const tbody = document.getElementById('reports-tbody');
|
||||||
|
const pagination = document.getElementById('reports-pagination');
|
||||||
|
const statusEl = document.getElementById('reports-status');
|
||||||
|
const perPageSel = document.getElementById('per-page-select');
|
||||||
|
|
||||||
|
let grouped = app.getAttribute('data-grouped') === '1';
|
||||||
|
let page = 1;
|
||||||
|
let perPage = Number(lsGet(STORAGE.perPage, '50')) || 50;
|
||||||
|
let sort = grouped ? 'cnt' : 'generated_at_ms';
|
||||||
|
let dir = 'desc';
|
||||||
|
let loading = false;
|
||||||
|
|
||||||
|
const savedSort = lsGet(STORAGE.sort, '');
|
||||||
|
if (savedSort) {
|
||||||
|
try {
|
||||||
|
const s = JSON.parse(savedSort);
|
||||||
|
if (s && s.sort) sort = s.sort;
|
||||||
|
if (s && s.dir) dir = s.dir;
|
||||||
|
} catch { /* ignore */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (perPageSel) {
|
||||||
|
perPageSel.value = String(perPage);
|
||||||
|
perPageSel.addEventListener('change', () => {
|
||||||
|
perPage = Number(perPageSel.value) || 50;
|
||||||
|
lsSet(STORAGE.perPage, String(perPage));
|
||||||
|
page = 1;
|
||||||
|
load();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
app.querySelectorAll('.reports-mode-btn').forEach((btn) => {
|
||||||
|
btn.addEventListener('click', () => {
|
||||||
|
grouped = btn.getAttribute('data-grouped') === '1';
|
||||||
|
app.setAttribute('data-grouped', grouped ? '1' : '0');
|
||||||
|
app.querySelectorAll('.reports-mode-btn').forEach((b) => {
|
||||||
|
b.classList.toggle('active', b === btn);
|
||||||
|
});
|
||||||
|
sort = grouped ? 'cnt' : 'generated_at_ms';
|
||||||
|
page = 1;
|
||||||
|
load();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const maybeStampVisit = () => {
|
||||||
|
try {
|
||||||
|
if (sessionStorage.getItem(STORAGE.skipStamp)) {
|
||||||
|
sessionStorage.removeItem(STORAGE.skipStamp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch { /* ignore */ }
|
||||||
|
stampLastVisit();
|
||||||
|
};
|
||||||
|
window.addEventListener('pagehide', maybeStampVisit);
|
||||||
|
|
||||||
|
function columns() {
|
||||||
|
return grouped ? GROUP_COLUMNS : LIST_COLUMNS;
|
||||||
|
}
|
||||||
|
|
||||||
|
function colspan() {
|
||||||
|
return columns().length + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderHead() {
|
||||||
|
const cols = columns();
|
||||||
|
let html = '<tr><th class="report-tree-head" aria-label="Expand"></th>';
|
||||||
|
cols.forEach((c) => {
|
||||||
|
const active = sort === c.key || apiSortKey(sort) === apiSortKey(c.key);
|
||||||
|
if (c.noSort) {
|
||||||
|
html += '<th scope="col">' + escapeHtml(c.label) + '</th>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const arrow =
|
||||||
|
active ? (dir === 'asc' ? '▲' : '▼') : '<span class="sort-idle">↕</span>';
|
||||||
|
html +=
|
||||||
|
'<th class="sortable' +
|
||||||
|
(active ? ' sortable--active' : '') +
|
||||||
|
'" data-sort="' +
|
||||||
|
escapeHtml(c.key) +
|
||||||
|
'" scope="col">' +
|
||||||
|
escapeHtml(c.label) +
|
||||||
|
' <span class="sort-ind" aria-hidden="true">' +
|
||||||
|
arrow +
|
||||||
|
'</span></th>';
|
||||||
|
});
|
||||||
|
html += '<th class="col-tags">Tags</th></tr>';
|
||||||
|
thead.innerHTML = html;
|
||||||
|
thead.querySelectorAll('.sortable').forEach((th) => {
|
||||||
|
th.addEventListener('click', () => {
|
||||||
|
const key = th.getAttribute('data-sort');
|
||||||
|
if (!key) return;
|
||||||
|
if (sort === key) {
|
||||||
|
dir = dir === 'asc' ? 'desc' : 'asc';
|
||||||
|
} else {
|
||||||
|
sort = key;
|
||||||
|
dir = 'desc';
|
||||||
|
}
|
||||||
|
lsSet(STORAGE.sort, JSON.stringify({ sort, dir, grouped }));
|
||||||
|
page = 1;
|
||||||
|
load();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderPagination(total) {
|
||||||
|
const pages = Math.max(1, Math.ceil(total / perPage));
|
||||||
|
if (page > pages) page = pages;
|
||||||
|
const prev = page > 1 ? page - 1 : null;
|
||||||
|
const next = page < pages ? page + 1 : null;
|
||||||
|
let html = '<div class="pagination-inner">';
|
||||||
|
html +=
|
||||||
|
'<button type="button" class="btn page-btn" data-page="' +
|
||||||
|
(prev || '') +
|
||||||
|
'" ' +
|
||||||
|
(prev ? '' : 'disabled') +
|
||||||
|
'>← Previous</button>';
|
||||||
|
html +=
|
||||||
|
'<span class="page-info">Page ' +
|
||||||
|
page +
|
||||||
|
' / ' +
|
||||||
|
pages +
|
||||||
|
' · ' +
|
||||||
|
total +
|
||||||
|
' reports</span>';
|
||||||
|
html +=
|
||||||
|
'<button type="button" class="btn page-btn" data-page="' +
|
||||||
|
(next || '') +
|
||||||
|
'" ' +
|
||||||
|
(next ? '' : 'disabled') +
|
||||||
|
'>Next →</button>';
|
||||||
|
html += '</div>';
|
||||||
|
pagination.innerHTML = html;
|
||||||
|
pagination.querySelectorAll('.page-btn').forEach((btn) => {
|
||||||
|
btn.addEventListener('click', () => {
|
||||||
|
const p = Number(btn.getAttribute('data-page'));
|
||||||
|
if (!p) return;
|
||||||
|
page = p;
|
||||||
|
load();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderRows(items) {
|
||||||
|
const cols = columns();
|
||||||
|
if (!items.length) {
|
||||||
|
tbody.innerHTML =
|
||||||
|
'<tr><td colspan="' +
|
||||||
|
colspan() +
|
||||||
|
'" class="muted">No reports yet.</td></tr>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let html = '';
|
||||||
|
items.forEach((row, i) => {
|
||||||
|
const rowKey = grouped ? 'g' + i + '-' + page : 'r' + row.id;
|
||||||
|
const briefId = 'brief-' + rowKey;
|
||||||
|
const openUrl = !grouped && row.id
|
||||||
|
? basePath() + '/?view=report&id=' + row.id
|
||||||
|
: '';
|
||||||
|
const navClass = openUrl ? ' report-row--nav' : '';
|
||||||
|
const hrefAttr = openUrl ? ' data-href="' + escapeHtml(openUrl) + '"' : '';
|
||||||
|
const tabAttr = openUrl ? ' tabindex="0" role="link"' : '';
|
||||||
|
|
||||||
|
html += '<tr class="report-row' + navClass + '"' + hrefAttr + tabAttr + '>';
|
||||||
|
html +=
|
||||||
|
'<td class="report-tree-cell"><button type="button" class="report-tree-toggle" aria-expanded="false" aria-controls="' +
|
||||||
|
briefId +
|
||||||
|
'" title="Show summary"><span class="report-tree-arrow" aria-hidden="true"></span></button></td>';
|
||||||
|
cols.forEach((c) => {
|
||||||
|
if (c.key === 'cnt') {
|
||||||
|
html += '<td><span class="badge">' + escapeHtml(row.cnt) + '</span></td>';
|
||||||
|
} else {
|
||||||
|
html += '<td>' + formatCell(c, row) + '</td>';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
html += '<td class="col-tags"><div class="report-tags">' + buildTags(row, grouped) + '</div></td>';
|
||||||
|
html += '</tr>';
|
||||||
|
|
||||||
|
const briefLines = row.brief || [];
|
||||||
|
let panelOpen = '<div class="report-brief-panel">';
|
||||||
|
if (openUrl) {
|
||||||
|
panelOpen =
|
||||||
|
'<div class="report-brief-panel report-brief-panel--nav report-row--nav" data-href="' +
|
||||||
|
escapeHtml(openUrl) +
|
||||||
|
'" tabindex="0" role="link">';
|
||||||
|
}
|
||||||
|
html +=
|
||||||
|
'<tr class="report-brief-row" id="' +
|
||||||
|
briefId +
|
||||||
|
'" hidden><td colspan="' +
|
||||||
|
colspan() +
|
||||||
|
'" class="report-brief-cell">' +
|
||||||
|
panelOpen +
|
||||||
|
'<div class="report-brief">';
|
||||||
|
briefLines.forEach((line) => {
|
||||||
|
html += '<p>' + escapeHtml(line) + '</p>';
|
||||||
|
});
|
||||||
|
if (openUrl) {
|
||||||
|
html += '<p class="report-brief-hint muted">Click to open full report</p>';
|
||||||
|
}
|
||||||
|
html += '</div></div></td></tr>';
|
||||||
|
});
|
||||||
|
tbody.innerHTML = html;
|
||||||
|
bindTreeInteractions(tbody);
|
||||||
|
}
|
||||||
|
|
||||||
|
function load() {
|
||||||
|
if (loading) return;
|
||||||
|
loading = true;
|
||||||
|
statusEl.textContent = 'Loading…';
|
||||||
|
const qs =
|
||||||
|
'page=' +
|
||||||
|
page +
|
||||||
|
'&per_page=' +
|
||||||
|
perPage +
|
||||||
|
'&sort=' +
|
||||||
|
encodeURIComponent(apiSortKey(sort)) +
|
||||||
|
'&dir=' +
|
||||||
|
encodeURIComponent(dir) +
|
||||||
|
'&since_ms=' +
|
||||||
|
encodeURIComponent(String(lastVisitMs())) +
|
||||||
|
(grouped ? '&group=1' : '');
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
xhr.open('GET', basePath() + '/api/reports.php?' + qs, true);
|
||||||
|
xhr.onload = function () {
|
||||||
|
loading = false;
|
||||||
|
let data;
|
||||||
|
try {
|
||||||
|
data = JSON.parse(xhr.responseText);
|
||||||
|
} catch {
|
||||||
|
statusEl.textContent = 'Invalid response';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!data.ok) {
|
||||||
|
statusEl.textContent = data.error || 'Load failed';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
renderHead();
|
||||||
|
renderRows(data.items || []);
|
||||||
|
renderPagination(Number(data.total) || 0);
|
||||||
|
statusEl.textContent =
|
||||||
|
'Showing ' +
|
||||||
|
(data.items?.length || 0) +
|
||||||
|
' of ' +
|
||||||
|
(data.total || 0) +
|
||||||
|
(grouped ? ' (grouped)' : '');
|
||||||
|
};
|
||||||
|
xhr.onerror = function () {
|
||||||
|
loading = false;
|
||||||
|
statusEl.textContent = 'Network error';
|
||||||
|
};
|
||||||
|
xhr.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
renderHead();
|
||||||
|
load();
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
initTheme();
|
||||||
|
initNav();
|
||||||
|
initReportDetail();
|
||||||
|
initReportsApp();
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|||||||
@@ -25,6 +25,21 @@ if ($route === '/api/upload.php' || str_ends_with($route, '/api/upload.php')) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($route === '/api/diag.php' || str_ends_with($route, '/api/diag.php')) {
|
||||||
|
require __DIR__ . '/api/diag.php';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($route === '/api/reports.php' || str_ends_with($route, '/api/reports.php')) {
|
||||||
|
require __DIR__ . '/api/reports.php';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($route === '/api/report_viewed.php' || str_ends_with($route, '/api/report_viewed.php')) {
|
||||||
|
require __DIR__ . '/api/report_viewed.php';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
if ($route === '/logout') {
|
if ($route === '/logout') {
|
||||||
Auth::logout();
|
Auth::logout();
|
||||||
header('Location: ' . $base . '/login');
|
header('Location: ' . $base . '/login');
|
||||||
@@ -60,11 +75,11 @@ if ($view === 'report' && isset($_GET['id'])) {
|
|||||||
echo 'Not found';
|
echo 'Not found';
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
ReportRepository::markViewed((int) $report['id'], (int) Auth::user()['id']);
|
||||||
$pageTitle = 'Report';
|
$pageTitle = 'Report';
|
||||||
require __DIR__ . '/../views/layout.php';
|
require __DIR__ . '/../views/layout.php';
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$pageTitle = $view === 'home' ? 'Home' : 'Crash reports';
|
$pageTitle = $view === 'home' ? 'Home' : 'Crash reports';
|
||||||
$reports = $view === 'reports' ? ReportRepository::listReports($grouped) : [];
|
|
||||||
require __DIR__ . '/../views/layout.php';
|
require __DIR__ . '/../views/layout.php';
|
||||||
|
|||||||
@@ -17,7 +17,16 @@ CREATE TABLE IF NOT EXISTS reports (
|
|||||||
received_at_ms INTEGER NOT NULL,
|
received_at_ms INTEGER NOT NULL,
|
||||||
device_model TEXT,
|
device_model TEXT,
|
||||||
app_version TEXT,
|
app_version TEXT,
|
||||||
payload_json TEXT NOT NULL
|
payload_json TEXT NOT NULL,
|
||||||
|
tags_json TEXT NOT NULL DEFAULT '[]'
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS report_views (
|
||||||
|
user_id INTEGER NOT NULL,
|
||||||
|
report_id INTEGER NOT NULL,
|
||||||
|
viewed_at_ms INTEGER NOT NULL,
|
||||||
|
PRIMARY KEY (user_id, report_id),
|
||||||
|
FOREIGN KEY (report_id) REFERENCES reports(id) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_reports_generated ON reports(generated_at_ms DESC);
|
CREATE INDEX IF NOT EXISTS idx_reports_generated ON reports(generated_at_ms DESC);
|
||||||
|
|||||||
@@ -67,13 +67,56 @@ final class Database {
|
|||||||
$stmt->execute([$table]);
|
$stmt->execute([$table]);
|
||||||
return $stmt->fetchColumn() === false;
|
return $stmt->fetchColumn() === false;
|
||||||
};
|
};
|
||||||
if (!$need('users') && !$need('reports')) {
|
if (!$need('users') && !$need('reports') && self::reportsSchemaOk($pdo)) {
|
||||||
|
self::ensureReportColumns($pdo);
|
||||||
|
self::ensureReportViewsTable($pdo);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$schemaFile = __DIR__ . '/../sql/schema.sqlite.sql';
|
$schemaFile = __DIR__ . '/../sql/schema.sqlite.sql';
|
||||||
if (!is_readable($schemaFile)) {
|
if (!is_readable($schemaFile)) {
|
||||||
throw new RuntimeException('schema file missing: ' . $schemaFile);
|
throw new RuntimeException('schema file missing: ' . $schemaFile);
|
||||||
}
|
}
|
||||||
|
if (!$need('reports') && !self::reportsSchemaOk($pdo)) {
|
||||||
|
$pdo->exec('DROP TABLE IF EXISTS reports');
|
||||||
|
}
|
||||||
$pdo->exec((string) file_get_contents($schemaFile));
|
$pdo->exec((string) file_get_contents($schemaFile));
|
||||||
|
self::ensureReportColumns($pdo);
|
||||||
|
self::ensureReportViewsTable($pdo);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function ensureReportColumns(PDO $pdo): void {
|
||||||
|
$names = array_column($pdo->query('PRAGMA table_info(reports)')->fetchAll(PDO::FETCH_ASSOC), 'name');
|
||||||
|
if (!in_array('tags_json', $names, true)) {
|
||||||
|
$pdo->exec("ALTER TABLE reports ADD COLUMN tags_json TEXT NOT NULL DEFAULT '[]'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function ensureReportViewsTable(PDO $pdo): void {
|
||||||
|
$pdo->exec(
|
||||||
|
'CREATE TABLE IF NOT EXISTS report_views (
|
||||||
|
user_id INTEGER NOT NULL,
|
||||||
|
report_id INTEGER NOT NULL,
|
||||||
|
viewed_at_ms INTEGER NOT NULL,
|
||||||
|
PRIMARY KEY (user_id, report_id)
|
||||||
|
)'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function reportsSchemaOk(PDO $pdo): bool {
|
||||||
|
try {
|
||||||
|
$cols = $pdo->query('PRAGMA table_info(reports)')->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
} catch (PDOException) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($cols === []) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$names = array_column($cols, 'name');
|
||||||
|
foreach (['report_id', 'fingerprint', 'crash_type', 'generated_at_ms', 'received_at_ms', 'payload_json'] as $col) {
|
||||||
|
if (!in_array($col, $names, true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,37 @@
|
|||||||
<?php
|
<?php
|
||||||
/*
|
|
||||||
* package examples/crash_reporter/backend/src/ReportRepository.php
|
|
||||||
* ReportRepository.php
|
|
||||||
* Created at: Wed 20 May 2026 14:31:55 +0200
|
|
||||||
* Updated at: Wed 20 May 2026 15:17:13 +0200 by Anton Afanasyeu <a.afanasieff@gmail.com>
|
|
||||||
* Commit: 5d8e82d2e60a21fff3138d2a394ee4e8b4c6dcb8
|
|
||||||
* Contributors:
|
|
||||||
* - Anton Afanasyeu <a.afanasieff@gmail.com> (2 commits, 61 lines)
|
|
||||||
* - Cursor Agent (project assistant)
|
|
||||||
* Digest: SHA256 5da7d17c78a5f2dbddfbabcbf0d2b4f391edb314902c758ce1c0df59c9140bd5
|
|
||||||
*/
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
final class ReportRepository {
|
final class ReportRepository {
|
||||||
|
private const LIST_SORT = [
|
||||||
|
'generated_at_ms',
|
||||||
|
'received_at_ms',
|
||||||
|
'crash_type',
|
||||||
|
'device_model',
|
||||||
|
'app_version',
|
||||||
|
'fingerprint',
|
||||||
|
'fingerprint_cnt',
|
||||||
|
];
|
||||||
|
private const GROUP_SORT = [
|
||||||
|
'cnt',
|
||||||
|
'fingerprint',
|
||||||
|
'crash_type',
|
||||||
|
'last_generated_ms',
|
||||||
|
'last_received_ms',
|
||||||
|
];
|
||||||
|
|
||||||
public static function insert(array $payload): void {
|
public static function insert(array $payload): void {
|
||||||
$pdo = Database::pdo();
|
$pdo = Database::pdo();
|
||||||
$device = $payload['device'] ?? [];
|
$device = $payload['device'] ?? [];
|
||||||
$app = $payload['app'] ?? [];
|
$app = $payload['app'] ?? [];
|
||||||
|
$json = json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||||
|
if ($json === false) {
|
||||||
|
throw new RuntimeException('payload json_encode failed: ' . json_last_error_msg());
|
||||||
|
}
|
||||||
|
$tags = json_encode($payload['tags'] ?? [], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||||
$stmt = $pdo->prepare(
|
$stmt = $pdo->prepare(
|
||||||
'INSERT INTO reports (report_id, fingerprint, crash_type, generated_at_ms, received_at_ms, device_model, app_version, payload_json)
|
'INSERT INTO reports (report_id, fingerprint, crash_type, generated_at_ms, received_at_ms,
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)'
|
device_model, app_version, payload_json, tags_json)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)'
|
||||||
);
|
);
|
||||||
$stmt->execute([
|
$stmt->execute([
|
||||||
$payload['report_id'] ?? uniqid('rpt_', true),
|
$payload['report_id'] ?? uniqid('rpt_', true),
|
||||||
@@ -29,14 +41,36 @@ final class ReportRepository {
|
|||||||
(int) round(microtime(true) * 1000),
|
(int) round(microtime(true) * 1000),
|
||||||
$device['model'] ?? null,
|
$device['model'] ?? null,
|
||||||
$app['version_name'] ?? null,
|
$app['version_name'] ?? null,
|
||||||
json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
|
$json,
|
||||||
|
$tags ?: '[]',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function listReports(bool $grouped): array {
|
public static function listReports(bool $grouped): array {
|
||||||
|
return self::listPage($grouped, 1, 500, 'generated_at_ms', 'desc')['items'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function listPage(
|
||||||
|
bool $grouped,
|
||||||
|
int $page,
|
||||||
|
int $perPage,
|
||||||
|
string $sort,
|
||||||
|
string $dir,
|
||||||
|
int $sinceMs = 0
|
||||||
|
): array {
|
||||||
$pdo = Database::pdo();
|
$pdo = Database::pdo();
|
||||||
|
$page = max(1, $page);
|
||||||
|
$perPage = max(1, min(200, $perPage));
|
||||||
|
$dir = strtolower($dir) === 'asc' ? 'ASC' : 'DESC';
|
||||||
|
$offset = ($page - 1) * $perPage;
|
||||||
|
$userId = (int) (Auth::user()['id'] ?? 0);
|
||||||
|
|
||||||
if ($grouped) {
|
if ($grouped) {
|
||||||
$sql = 'SELECT fingerprint, crash_type,
|
$sortCol = in_array($sort, self::GROUP_SORT, true) ? $sort : 'cnt';
|
||||||
|
$total = (int) $pdo->query(
|
||||||
|
'SELECT COUNT(*) FROM (SELECT 1 FROM reports GROUP BY fingerprint, crash_type)'
|
||||||
|
)->fetchColumn();
|
||||||
|
$sql = "SELECT fingerprint, crash_type,
|
||||||
MIN(device_model) AS device_model,
|
MIN(device_model) AS device_model,
|
||||||
MAX(app_version) AS app_version,
|
MAX(app_version) AS app_version,
|
||||||
COUNT(*) AS cnt,
|
COUNT(*) AS cnt,
|
||||||
@@ -44,25 +78,93 @@ final class ReportRepository {
|
|||||||
MAX(received_at_ms) AS last_received_ms
|
MAX(received_at_ms) AS last_received_ms
|
||||||
FROM reports
|
FROM reports
|
||||||
GROUP BY fingerprint, crash_type
|
GROUP BY fingerprint, crash_type
|
||||||
ORDER BY cnt DESC, last_generated_ms DESC';
|
ORDER BY $sortCol $dir
|
||||||
return $pdo->query($sql)->fetchAll();
|
LIMIT $perPage OFFSET $offset";
|
||||||
|
$items = $pdo->query($sql)->fetchAll();
|
||||||
|
foreach ($items as &$row) {
|
||||||
|
$row['fingerprint_cnt'] = (int) ($row['cnt'] ?? 0);
|
||||||
|
$row['fingerprint_recent_cnt'] = $sinceMs > 0 && (int) ($row['last_received_ms'] ?? 0) > $sinceMs
|
||||||
|
? (int) $row['cnt'] : 0;
|
||||||
|
$row['rating'] = report_rating_score((int) $row['cnt'], (int) $row['fingerprint_recent_cnt'], (int) $row['cnt']);
|
||||||
|
$row['os_name'] = '';
|
||||||
|
$row['os_version'] = '';
|
||||||
|
$row['brief'] = report_brief_lines($row, true);
|
||||||
}
|
}
|
||||||
$sql = 'SELECT id, report_id, fingerprint, crash_type, generated_at_ms, received_at_ms, device_model, app_version
|
unset($row);
|
||||||
FROM reports
|
return [
|
||||||
ORDER BY generated_at_ms DESC, received_at_ms DESC
|
'items' => $items,
|
||||||
LIMIT 500';
|
'total' => $total,
|
||||||
return $pdo->query($sql)->fetchAll();
|
'page' => $page,
|
||||||
|
'per_page' => $perPage,
|
||||||
|
'sort' => $sortCol,
|
||||||
|
'dir' => strtolower($dir),
|
||||||
|
'grouped' => true,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$sortCol = in_array($sort, self::LIST_SORT, true) ? $sort : 'generated_at_ms';
|
||||||
|
if ($sortCol === 'fingerprint_cnt') {
|
||||||
|
$sortCol = 'fingerprint_cnt';
|
||||||
|
}
|
||||||
|
$total = (int) $pdo->query('SELECT COUNT(*) FROM reports')->fetchColumn();
|
||||||
|
$sql = "SELECT r.id, r.report_id, r.fingerprint, r.crash_type, r.generated_at_ms, r.received_at_ms,
|
||||||
|
r.device_model, r.app_version, r.payload_json, r.tags_json,
|
||||||
|
CASE WHEN v.viewed_at_ms IS NOT NULL THEN 1 ELSE 0 END AS viewed,
|
||||||
|
(SELECT COUNT(*) FROM reports r2 WHERE r2.fingerprint = r.fingerprint) AS fingerprint_cnt,
|
||||||
|
(SELECT COUNT(*) FROM reports r2 WHERE r2.fingerprint = r.fingerprint
|
||||||
|
AND r2.received_at_ms > ?) AS fingerprint_recent_cnt
|
||||||
|
FROM reports r
|
||||||
|
LEFT JOIN report_views v ON v.report_id = r.id AND v.user_id = ?
|
||||||
|
ORDER BY " . ($sortCol === 'fingerprint_cnt' ? 'fingerprint_cnt' : "r.$sortCol") . " $dir
|
||||||
|
LIMIT $perPage OFFSET $offset";
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
$stmt->execute([$sinceMs, $userId]);
|
||||||
|
$items = $stmt->fetchAll();
|
||||||
|
foreach ($items as &$row) {
|
||||||
|
$row['viewed'] = (bool) ($row['viewed'] ?? false);
|
||||||
|
$row['tags'] = parse_report_tags($row['tags_json'] ?? '[]');
|
||||||
|
report_enrich_list_row($row, $sinceMs);
|
||||||
|
$row['brief'] = report_brief_lines($row, false);
|
||||||
|
unset($row['payload_json'], $row['tags_json']);
|
||||||
|
}
|
||||||
|
unset($row);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'items' => $items,
|
||||||
|
'total' => $total,
|
||||||
|
'page' => $page,
|
||||||
|
'per_page' => $perPage,
|
||||||
|
'sort' => $sortCol,
|
||||||
|
'dir' => strtolower($dir),
|
||||||
|
'grouped' => false,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function markViewed(int $reportId, int $userId): void {
|
||||||
|
$pdo = Database::pdo();
|
||||||
|
$stmt = $pdo->prepare(
|
||||||
|
'INSERT OR REPLACE INTO report_views (user_id, report_id, viewed_at_ms) VALUES (?, ?, ?)'
|
||||||
|
);
|
||||||
|
$stmt->execute([$userId, $reportId, (int) round(microtime(true) * 1000)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getById(int $id): ?array {
|
public static function getById(int $id): ?array {
|
||||||
$pdo = Database::pdo();
|
$pdo = Database::pdo();
|
||||||
$stmt = $pdo->prepare('SELECT * FROM reports WHERE id = ?');
|
$userId = (int) (Auth::user()['id'] ?? 0);
|
||||||
$stmt->execute([$id]);
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT r.*, CASE WHEN v.viewed_at_ms IS NOT NULL THEN 1 ELSE 0 END AS viewed
|
||||||
|
FROM reports r
|
||||||
|
LEFT JOIN report_views v ON v.report_id = r.id AND v.user_id = ?
|
||||||
|
WHERE r.id = ?'
|
||||||
|
);
|
||||||
|
$stmt->execute([$userId, $id]);
|
||||||
$row = $stmt->fetch();
|
$row = $stmt->fetch();
|
||||||
if (!$row) {
|
if (!$row) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
$row['payload'] = json_decode($row['payload_json'], true);
|
$row['payload'] = json_decode($row['payload_json'], true);
|
||||||
|
$row['tags'] = parse_report_tags($row['tags_json'] ?? '[]');
|
||||||
|
$row['viewed'] = (bool) ($row['viewed'] ?? false);
|
||||||
return $row;
|
return $row;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,3 +59,154 @@ function json_out(array $data, int $code = 200): void {
|
|||||||
echo json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
echo json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Short lines for expandable list preview (not full report detail). */
|
||||||
|
function report_brief_lines(array $row, bool $grouped): array {
|
||||||
|
if ($grouped) {
|
||||||
|
return array_filter([
|
||||||
|
sprintf('%d reports · %s', (int) ($row['cnt'] ?? 0), $row['crash_type'] ?? ''),
|
||||||
|
'Fingerprint: ' . ($row['fingerprint'] ?? ''),
|
||||||
|
trim(sprintf(
|
||||||
|
'%s · app %s',
|
||||||
|
$row['device_model'] ?? '',
|
||||||
|
$row['app_version'] ?? ''
|
||||||
|
), ' ·'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
$p = json_decode($row['payload_json'] ?? '', true);
|
||||||
|
if (!is_array($p)) {
|
||||||
|
$p = [];
|
||||||
|
}
|
||||||
|
$lines = [
|
||||||
|
sprintf(
|
||||||
|
'%s · %s · %s',
|
||||||
|
$row['crash_type'] ?? ($p['crash_type'] ?? ''),
|
||||||
|
$p['scenario'] ?? '—',
|
||||||
|
substr($row['fingerprint'] ?? ($p['fingerprint'] ?? ''), 0, 16)
|
||||||
|
),
|
||||||
|
trim(sprintf(
|
||||||
|
'%s %s · %s v%s',
|
||||||
|
$p['device']['manufacturer'] ?? '',
|
||||||
|
$row['device_model'] ?? ($p['device']['model'] ?? ''),
|
||||||
|
$p['app']['package'] ?? 'com.foxx.androidcast',
|
||||||
|
$row['app_version'] ?? ($p['app']['version_name'] ?? '')
|
||||||
|
)),
|
||||||
|
];
|
||||||
|
if (!empty($p['java'])) {
|
||||||
|
$j = $p['java'];
|
||||||
|
$exc = trim(($j['exception'] ?? '') . (!empty($j['message']) ? ': ' . $j['message'] : ''));
|
||||||
|
$lines[] = $exc !== '' ? $exc : 'Java crash';
|
||||||
|
$frames = $j['stack_frames'] ?? [];
|
||||||
|
if (!empty($frames[0])) {
|
||||||
|
$lines[] = (string) $frames[0];
|
||||||
|
}
|
||||||
|
} elseif (!empty($p['native'])) {
|
||||||
|
$lines[] = 'Native: ' . ($p['native']['signal'] ?? 'crash');
|
||||||
|
$bt = $p['native']['backtrace'] ?? [];
|
||||||
|
if (!empty($bt[0])) {
|
||||||
|
$lines[] = (string) $bt[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!empty($p['runtime_context']['last_activity'])) {
|
||||||
|
$lines[] = 'Activity: ' . $p['runtime_context']['last_activity'];
|
||||||
|
}
|
||||||
|
return array_values(array_filter($lines, static fn ($l) => trim($l) !== '' && trim($l) !== '·'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return array{label:string,bg:string} */
|
||||||
|
function crash_kind_tag(string $crashType): array {
|
||||||
|
$t = strtolower($crashType);
|
||||||
|
return match ($t) {
|
||||||
|
'native' => ['label' => 'NDK', 'bg' => '#b45309'],
|
||||||
|
'java' => ['label' => 'Java', 'bg' => '#6d28d9'],
|
||||||
|
'android' => ['label' => 'Android', 'bg' => '#047857'],
|
||||||
|
default => ['label' => ucfirst($t ?: '?'), 'bg' => '#5c6b82'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Enrich list row with OS fields and rating inputs (keeps payload_json until unset). */
|
||||||
|
function report_enrich_list_row(array &$row, int $sinceMs = 0): void {
|
||||||
|
$p = json_decode($row['payload_json'] ?? '', true);
|
||||||
|
if (!is_array($p)) {
|
||||||
|
$p = [];
|
||||||
|
}
|
||||||
|
$d = $p['device'] ?? [];
|
||||||
|
$row['os_name'] = trim((string) ($d['manufacturer'] ?? $d['brand'] ?? ''));
|
||||||
|
$rel = (string) ($d['release'] ?? '');
|
||||||
|
$sdk = (int) ($d['sdk_int'] ?? 0);
|
||||||
|
if ($rel !== '' && $sdk > 0) {
|
||||||
|
$row['os_version'] = $rel . ' (API ' . $sdk . ')';
|
||||||
|
} elseif ($rel !== '') {
|
||||||
|
$row['os_version'] = $rel;
|
||||||
|
} elseif ($sdk > 0) {
|
||||||
|
$row['os_version'] = 'API ' . $sdk;
|
||||||
|
} else {
|
||||||
|
$row['os_version'] = '';
|
||||||
|
}
|
||||||
|
$row['scenario'] = (string) ($p['scenario'] ?? '');
|
||||||
|
$total = (int) ($row['fingerprint_cnt'] ?? 1);
|
||||||
|
$recent = (int) ($row['fingerprint_recent_cnt'] ?? 0);
|
||||||
|
if ($sinceMs > 0 && $recent === 0 && !empty($row['received_at_ms'])) {
|
||||||
|
$recent = (int) $row['received_at_ms'] > $sinceMs ? 1 : 0;
|
||||||
|
}
|
||||||
|
$row['rating'] = report_rating_score($total, $recent, (int) ($row['cnt'] ?? 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
function report_rating_score(int $fingerprintTotal, int $fingerprintRecent, int $groupCnt = 0): int {
|
||||||
|
$t = $groupCnt > 0 ? $groupCnt : max(1, $fingerprintTotal);
|
||||||
|
$r = $fingerprintRecent;
|
||||||
|
$score = 0;
|
||||||
|
if ($t >= 40) {
|
||||||
|
$score = 5;
|
||||||
|
} elseif ($t >= 20) {
|
||||||
|
$score = 4;
|
||||||
|
} elseif ($t >= 10) {
|
||||||
|
$score = 3;
|
||||||
|
} elseif ($t >= 4) {
|
||||||
|
$score = 2;
|
||||||
|
} elseif ($t >= 2) {
|
||||||
|
$score = 1;
|
||||||
|
}
|
||||||
|
if ($r >= 8) {
|
||||||
|
$score = min(5, $score + 2);
|
||||||
|
} elseif ($r >= 3) {
|
||||||
|
$score = min(5, $score + 1);
|
||||||
|
}
|
||||||
|
return max(0, min(5, $score));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return list<array{id:string,label:string,bg:string}> */
|
||||||
|
function parse_report_tags(?string $json): array {
|
||||||
|
if ($json === null || $json === '') {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
$raw = json_decode($json, true);
|
||||||
|
if (!is_array($raw)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
$out = [];
|
||||||
|
foreach ($raw as $tag) {
|
||||||
|
if (!is_array($tag)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$id = (string) ($tag['id'] ?? $tag['label'] ?? '');
|
||||||
|
if ($id === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$out[] = [
|
||||||
|
'id' => $id,
|
||||||
|
'label' => (string) ($tag['label'] ?? $id),
|
||||||
|
'bg' => (string) ($tag['bg'] ?? '#5c6b82'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
function log_crash_event(string $channel, string $message): void {
|
||||||
|
$dir = dirname(__DIR__) . '/storage';
|
||||||
|
if (!is_dir($dir)) {
|
||||||
|
@mkdir($dir, 0775, true);
|
||||||
|
}
|
||||||
|
$line = date('c') . " [$channel] $message\n";
|
||||||
|
@file_put_contents($dir . '/crash.log', $line, FILE_APPEND | LOCK_EX);
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,16 +12,23 @@
|
|||||||
*/
|
*/
|
||||||
?>
|
?>
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en" data-theme="dark">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title><?= h($pageTitle ?? 'Console') ?> — <?= h(cfg('app_name')) ?></title>
|
<title><?= h($pageTitle ?? 'Console') ?> — <?= h(cfg('app_name')) ?></title>
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
var t = localStorage.getItem('crash_console_theme');
|
||||||
|
if (t === 'light' || t === 'dark') document.documentElement.setAttribute('data-theme', t);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
<link rel="stylesheet" href="<?= h(Auth::basePath()) ?>/assets/css/app.css">
|
<link rel="stylesheet" href="<?= h(Auth::basePath()) ?>/assets/css/app.css">
|
||||||
<script src="https://code.jquery.com/jquery-3.7.1.min.js" defer></script>
|
|
||||||
<script src="<?= h(Auth::basePath()) ?>/assets/js/app.js" defer></script>
|
<script src="<?= h(Auth::basePath()) ?>/assets/js/app.js" defer></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body data-base-path="<?= h(Auth::basePath()) ?>"
|
||||||
|
data-view="<?= h($view ?? 'home') ?>"
|
||||||
|
<?= (($view ?? '') === 'report' && !empty($report['id'])) ? ' data-report-id="' . (int) $report['id'] . '"' : '' ?>>
|
||||||
<header class="top-menu" hidden aria-hidden="true"></header>
|
<header class="top-menu" hidden aria-hidden="true"></header>
|
||||||
<div class="shell">
|
<div class="shell">
|
||||||
<nav class="nav-pane" id="nav-pane" aria-label="Console navigation">
|
<nav class="nav-pane" id="nav-pane" aria-label="Console navigation">
|
||||||
@@ -73,47 +80,40 @@
|
|||||||
<?php elseif (($view ?? '') === 'report' && !empty($report)): ?>
|
<?php elseif (($view ?? '') === 'report' && !empty($report)): ?>
|
||||||
<?php require __DIR__ . '/report_detail.php'; ?>
|
<?php require __DIR__ . '/report_detail.php'; ?>
|
||||||
<?php elseif (($view ?? '') === 'reports'): ?>
|
<?php elseif (($view ?? '') === 'reports'): ?>
|
||||||
<div class="toolbar">
|
<div id="reports-app" class="reports-app" data-grouped="0">
|
||||||
|
<div class="toolbar reports-toolbar">
|
||||||
<h1>Crash reports</h1>
|
<h1>Crash reports</h1>
|
||||||
<div class="toolbar-actions">
|
<div class="toolbar-actions">
|
||||||
<a class="btn <?= empty($grouped) ? 'active' : '' ?>" href="<?= h(Auth::basePath()) ?>/?view=reports">By time</a>
|
<button type="button" class="btn reports-mode-btn active" data-grouped="0">By time</button>
|
||||||
<a class="btn <?= !empty($grouped) ? 'active' : '' ?>" href="<?= h(Auth::basePath()) ?>/?view=reports&group=1">Grouped</a>
|
<button type="button" class="btn reports-mode-btn" data-grouped="1">Grouped</button>
|
||||||
|
<label class="toolbar-select">
|
||||||
|
Theme
|
||||||
|
<select id="theme-select" aria-label="UI theme">
|
||||||
|
<option value="dark">Dark</option>
|
||||||
|
<option value="light">Light</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<label class="toolbar-select">
|
||||||
|
Per page
|
||||||
|
<select id="per-page-select" aria-label="Reports per page">
|
||||||
|
<option value="25">25</option>
|
||||||
|
<option value="50" selected>50</option>
|
||||||
|
<option value="75">75</option>
|
||||||
|
<option value="100">100</option>
|
||||||
|
<option value="200">200</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<table class="data-table">
|
<p id="reports-status" class="reports-status muted" aria-live="polite">Loading…</p>
|
||||||
<thead>
|
<div class="reports-table-wrap">
|
||||||
<tr>
|
<table class="data-table reports-tree" id="reports-tree">
|
||||||
<?php if (!empty($grouped)): ?>
|
<thead id="reports-thead"></thead>
|
||||||
<th>Count</th><th>Fingerprint</th><th>Type</th><th>Last generated</th><th>Last received</th>
|
<tbody id="reports-tbody"></tbody>
|
||||||
<?php else: ?>
|
|
||||||
<th>Generated</th><th>Received</th><th>Type</th><th>Device</th><th>App</th><th></th>
|
|
||||||
<?php endif; ?>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<?php foreach ($reports as $r): ?>
|
|
||||||
<tr>
|
|
||||||
<?php if (!empty($grouped)): ?>
|
|
||||||
<td><span class="badge"><?= (int) $r['cnt'] ?></span></td>
|
|
||||||
<td><code class="fp"><?= h(substr($r['fingerprint'], 0, 12)) ?>…</code></td>
|
|
||||||
<td><?= h($r['crash_type']) ?></td>
|
|
||||||
<td><?= h(date('Y-m-d H:i:s', (int)($r['last_generated_ms']/1000))) ?></td>
|
|
||||||
<td><?= h(date('Y-m-d H:i:s', (int)($r['last_received_ms']/1000))) ?></td>
|
|
||||||
<?php else: ?>
|
|
||||||
<td><?= h(date('Y-m-d H:i:s', (int)($r['generated_at_ms']/1000))) ?></td>
|
|
||||||
<td><?= h(date('Y-m-d H:i:s', (int)($r['received_at_ms']/1000))) ?></td>
|
|
||||||
<td><?= h($r['crash_type']) ?></td>
|
|
||||||
<td><?= h($r['device_model'] ?? '') ?></td>
|
|
||||||
<td><?= h($r['app_version'] ?? '') ?></td>
|
|
||||||
<td><a href="<?= h(Auth::basePath()) ?>/?view=report&id=<?= (int)$r['id'] ?>">Open</a></td>
|
|
||||||
<?php endif; ?>
|
|
||||||
</tr>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
<?php if (empty($reports)): ?>
|
|
||||||
<tr><td colspan="6" class="muted">No reports yet.</td></tr>
|
|
||||||
<?php endif; ?>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
|
<nav class="reports-pagination" id="reports-pagination" aria-label="Reports pages"></nav>
|
||||||
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,39 +1,39 @@
|
|||||||
<?php
|
<?php
|
||||||
/*
|
|
||||||
* package examples/crash_reporter/backend/views/report_detail.php
|
|
||||||
* report_detail.php
|
|
||||||
* Created at: Wed 20 May 2026 14:31:55 +0200
|
|
||||||
* Updated at: Wed 20 May 2026 15:17:13 +0200 by Anton Afanasyeu <a.afanasieff@gmail.com>
|
|
||||||
* Commit: 5d8e82d2e60a21fff3138d2a394ee4e8b4c6dcb8
|
|
||||||
* Contributors:
|
|
||||||
* - Anton Afanasyeu <a.afanasieff@gmail.com> (2 commits, 54 lines)
|
|
||||||
* - Cursor Agent (project assistant)
|
|
||||||
* Digest: SHA256 f1e2aee2d8f36904e3a143c7a60e4812de32a58c94d7792334f7ac9ab12f6f25
|
|
||||||
*/
|
|
||||||
$p = $report['payload'] ?? [];
|
$p = $report['payload'] ?? [];
|
||||||
$device = $p['device'] ?? [];
|
$device = $p['device'] ?? [];
|
||||||
$app = $p['app'] ?? [];
|
$app = $p['app'] ?? [];
|
||||||
$pageTitle = 'Report ' . ($report['report_id'] ?? '');
|
$pageTitle = 'Report ' . ($report['report_id'] ?? '');
|
||||||
$view = 'reports';
|
$view = 'reports';
|
||||||
|
$rawJson = json_encode($p, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||||
|
$sessionJson = !empty($p['session_context'])
|
||||||
|
? json_encode($p['session_context'], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)
|
||||||
|
: '';
|
||||||
?>
|
?>
|
||||||
<h1>Crash report</h1>
|
<div class="detail-header">
|
||||||
<p class="muted">Report <?= h($report['report_id'] ?? '') ?> · <?= h($p['crash_type'] ?? '') ?></p>
|
<a href="<?= h(Auth::basePath()) ?>/?view=reports" class="back-link" aria-label="Back to reports list" title="Back to list">
|
||||||
<div class="cards">
|
<span class="back-icon" aria-hidden="true"></span>
|
||||||
<div class="card"><h3>Device</h3>
|
</a>
|
||||||
|
<div>
|
||||||
|
<h1>Crash report</h1>
|
||||||
|
<p class="muted">Report <?= h($report['report_id'] ?? '') ?></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cards cards--lift">
|
||||||
|
<div class="card card--lift"><h3>Device</h3>
|
||||||
<p><?= h(trim(($device['manufacturer'] ?? '') . ' ' . ($device['model'] ?? ''))) ?></p>
|
<p><?= h(trim(($device['manufacturer'] ?? '') . ' ' . ($device['model'] ?? ''))) ?></p>
|
||||||
<p>Android <?= h($device['release'] ?? '') ?> (SDK <?= (int)($device['sdk_int'] ?? 0) ?>)</p>
|
<p>Android <?= h($device['release'] ?? '') ?> (SDK <?= (int)($device['sdk_int'] ?? 0) ?>)</p>
|
||||||
<?php if (!empty($device['abis'])): ?>
|
<?php if (!empty($device['abis'])): ?>
|
||||||
<p class="muted">ABIs: <?= h(implode(', ', (array)$device['abis'])) ?></p>
|
<p class="muted">ABIs: <?= h(implode(', ', (array)$device['abis'])) ?></p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
<div class="card"><h3>App</h3>
|
<div class="card card--lift"><h3>App</h3>
|
||||||
<p><?= h($app['package'] ?? '') ?></p>
|
<p><?= h($app['package'] ?? '') ?></p>
|
||||||
<p>v<?= h($app['version_name'] ?? '') ?> (<?= h((string)($app['version_code'] ?? '')) ?>)</p>
|
<p>v<?= h($app['version_name'] ?? '') ?> (<?= h((string)($app['version_code'] ?? '')) ?>)</p>
|
||||||
<?php if (!empty($p['build'])): $b = $p['build']; ?>
|
<?php if (!empty($p['build'])): $b = $p['build']; ?>
|
||||||
<p class="muted">Build: <?= h($b['git_commit'] ?? $b['git'] ?? '') ?></p>
|
<p class="muted">Build: <?= h($b['git_commit'] ?? $b['git'] ?? '') ?></p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
<div class="card"><h3>Timing</h3>
|
<div class="card card--lift"><h3>Timing</h3>
|
||||||
<p>Generated: <?= h(date('c', (int)(($p['generated_at_epoch_ms'] ?? 0)/1000))) ?></p>
|
<p>Generated: <?= h(date('c', (int)(($p['generated_at_epoch_ms'] ?? 0)/1000))) ?></p>
|
||||||
<p>Received: <?= h(date('c', (int)(($report['received_at_ms'] ?? 0)/1000))) ?></p>
|
<p>Received: <?= h(date('c', (int)(($report['received_at_ms'] ?? 0)/1000))) ?></p>
|
||||||
<p class="muted">Fingerprint: <code><?= h($p['fingerprint'] ?? $report['fingerprint'] ?? '') ?></code></p>
|
<p class="muted">Fingerprint: <code><?= h($p['fingerprint'] ?? $report['fingerprint'] ?? '') ?></code></p>
|
||||||
@@ -54,8 +54,34 @@ $view = 'reports';
|
|||||||
<pre class="stack"><?php foreach ($n['backtrace'] ?? [] as $frame) { echo h((string)$frame) . "\n"; } ?></pre>
|
<pre class="stack"><?php foreach ($n['backtrace'] ?? [] as $frame) { echo h((string)$frame) . "\n"; } ?></pre>
|
||||||
</section>
|
</section>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<?php if (!empty($p['session_context'])): ?>
|
|
||||||
<details><summary>Session context (crash)</summary><pre class="stack"><?= h(json_encode($p['session_context'], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES)) ?></pre></details>
|
<div class="detail-tree" id="detail-tree">
|
||||||
<?php endif; ?>
|
<?php if ($sessionJson !== ''): ?>
|
||||||
<details><summary>Raw JSON</summary><pre class="raw-json stack"><?= h(json_encode($p, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES)) ?></pre></details>
|
<div class="detail-tree-item">
|
||||||
<p><a href="<?= h(Auth::basePath()) ?>/?view=reports">← Back to list</a></p>
|
<div class="detail-tree-row report-row" role="button" tabindex="0" data-tree-toggle data-controls="detail-session">
|
||||||
|
<span class="report-tree-cell">
|
||||||
|
<button type="button" class="report-tree-toggle" aria-expanded="false" aria-controls="detail-session" tabindex="-1">
|
||||||
|
<span class="report-tree-arrow" aria-hidden="true"></span>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
<span class="detail-tree-caption">Session context (crash)</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-tree-body" id="detail-session" hidden>
|
||||||
|
<pre class="stack"><?= h($sessionJson) ?></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<div class="detail-tree-item">
|
||||||
|
<div class="detail-tree-row report-row" role="button" tabindex="0" data-tree-toggle data-controls="detail-raw-json">
|
||||||
|
<span class="report-tree-cell">
|
||||||
|
<button type="button" class="report-tree-toggle" aria-expanded="false" aria-controls="detail-raw-json" tabindex="-1">
|
||||||
|
<span class="report-tree-arrow" aria-hidden="true"></span>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
<span class="detail-tree-caption">Raw JSON</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-tree-body" id="detail-raw-json" hidden>
|
||||||
|
<pre class="stack raw-json"><?= h($rawJson) ?></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
339
examples/crash_reporter/generate_test_reports.py
Executable file
339
examples/crash_reporter/generate_test_reports.py
Executable file
@@ -0,0 +1,339 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Generate fake crash JSON files (java + native) for batch upload testing."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import random
|
||||||
|
import uuid
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
OUT_DIR = Path(__file__).resolve().parent / "test_reports"
|
||||||
|
JAVA_COUNT = 35
|
||||||
|
NATIVE_COUNT = 30
|
||||||
|
BASE_MS = int(datetime(2026, 5, 1, 12, 0, tzinfo=timezone.utc).timestamp() * 1000)
|
||||||
|
GENERATION_SEED = 20260523
|
||||||
|
|
||||||
|
DEVICES = [
|
||||||
|
("Samsung", "samsung", "Galaxy Tab A9+", "gta9pwifi", 34, "14"),
|
||||||
|
("Lenovo", "Lenovo", "Tab P12", "TB370FU", 34, "14"),
|
||||||
|
("Xiaomi", "Xiaomi", "Redmi Pad SE", "xun", 33, "13"),
|
||||||
|
("Doogee", "DOOGEE", "Tab G6 Max", "TabG6Max", 34, "14"),
|
||||||
|
("Huawei", "HUAWEI", "MatePad 11", "BAH3", 31, "12"),
|
||||||
|
("Amazon", "Amazon", "Fire HD 10", "trona", 30, "11"),
|
||||||
|
("Google", "google", "Pixel Tablet", "tangorpro", 34, "14"),
|
||||||
|
("OnePlus", "OnePlus", "Pad Go", "OPD2303", 33, "13"),
|
||||||
|
("Realme", "realme", "Pad 2", "RMX2201", 33, "13"),
|
||||||
|
("Nokia", "HMD Global", "T21", "RON", 33, "13"),
|
||||||
|
("TCL", "TCL", "Tab 10 Gen2", "9081G", 31, "12"),
|
||||||
|
("Vivo", "vivo", "Pad Air", "PA2353", 34, "14"),
|
||||||
|
("Oppo", "OPPO", "Pad Neo", "OPD2301", 33, "13"),
|
||||||
|
("Asus", "asus", "ZenPad 10", "P00C", 29, "10"),
|
||||||
|
("Acer", "Acer", "Iconia Tab P10", "acer_p10", 31, "12"),
|
||||||
|
("Motorola", "motorola", "Tab G70", "scout", 33, "13"),
|
||||||
|
("Honor", "HONOR", "Pad X8a", "HEY2", 34, "14"),
|
||||||
|
]
|
||||||
|
|
||||||
|
JAVA_TEMPLATES = [
|
||||||
|
{
|
||||||
|
"fingerprint": "a1b2c3d4e5f6npe01",
|
||||||
|
"scenario_weights": ("cast_session", "cast_session", "app_runtime"),
|
||||||
|
"process": "main",
|
||||||
|
"activity": "ScreenCastActivity",
|
||||||
|
"java": {
|
||||||
|
"thread": "main",
|
||||||
|
"exception": "java.lang.NullPointerException",
|
||||||
|
"message": "Attempt to invoke virtual method on a null object reference",
|
||||||
|
"stack_frames": [
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.onCreate(ScreenCastService.java:118)",
|
||||||
|
"at android.app.ActivityThread.handleCreateService(ActivityThread.java:5148)",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fingerprint": "a1b2c3d4e5f6npe01",
|
||||||
|
"scenario_weights": ("cast_session", "cast_session"),
|
||||||
|
"process": "main",
|
||||||
|
"activity": "CastSettingsActivity",
|
||||||
|
"java": {
|
||||||
|
"thread": "main",
|
||||||
|
"exception": "java.lang.NullPointerException",
|
||||||
|
"message": "encoderSurface was null when starting capture",
|
||||||
|
"stack_frames": [
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.startCapture(ScreenCastService.java:412)",
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.onStartCommand(ScreenCastService.java:205)",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fingerprint": "b2c3d4e5f6a01codec",
|
||||||
|
"scenario_weights": ("cast_session", "cast_session"),
|
||||||
|
"process": "main",
|
||||||
|
"activity": "ScreenCastActivity",
|
||||||
|
"java": {
|
||||||
|
"thread": "EncoderThread-1",
|
||||||
|
"exception": "java.lang.IllegalStateException",
|
||||||
|
"message": "MediaCodec codec is released already",
|
||||||
|
"stack_frames": [
|
||||||
|
"at android.media.MediaCodec.native_dequeueOutputBuffer(Native Method)",
|
||||||
|
"at com.foxx.androidcast.encoder.H264Encoder.drain(H264Encoder.java:88)",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fingerprint": "c3d4e5f6a01b02oom",
|
||||||
|
"scenario_weights": ("cast_session", "app_runtime"),
|
||||||
|
"process": "main",
|
||||||
|
"activity": "MainActivity",
|
||||||
|
"java": {
|
||||||
|
"thread": "pool-3-thread-2",
|
||||||
|
"exception": "java.lang.OutOfMemoryError",
|
||||||
|
"message": "Failed to allocate a 8294400 byte allocation with 524288 free bytes",
|
||||||
|
"stack_frames": [
|
||||||
|
"at android.graphics.Bitmap.createBitmap(Bitmap.java:1234)",
|
||||||
|
"at com.foxx.androidcast.capture.FrameRingBuffer.push(FrameRingBuffer.java:56)",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fingerprint": "d4e5f6a01b02c03net",
|
||||||
|
"scenario_weights": ("app_runtime", "cast_session", "app_runtime"),
|
||||||
|
"process": "main",
|
||||||
|
"activity": "MainActivity",
|
||||||
|
"java": {
|
||||||
|
"thread": "UdpSender-1",
|
||||||
|
"exception": "java.net.SocketTimeoutException",
|
||||||
|
"message": "connect timed out",
|
||||||
|
"stack_frames": [
|
||||||
|
"at com.foxx.androidcast.network.udp.UdpCastTransport.send(UdpCastTransport.java:142)",
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.flushStats(ScreenCastService.java:455)",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fingerprint": "f6a01b02c03d04e05perm",
|
||||||
|
"scenario_weights": ("app_runtime", "app_runtime"),
|
||||||
|
"process": "main",
|
||||||
|
"activity": "MainActivity",
|
||||||
|
"java": {
|
||||||
|
"thread": "main",
|
||||||
|
"exception": "java.lang.SecurityException",
|
||||||
|
"message": "MediaProjection requires FOREGROUND_SERVICE_MEDIA_PROJECTION",
|
||||||
|
"stack_frames": [
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.acquireProjection(ScreenCastService.java:167)",
|
||||||
|
"at com.foxx.androidcast.ui.MainActivity.startCast(MainActivity.java:89)",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
NATIVE_TEMPLATES = [
|
||||||
|
{
|
||||||
|
"fingerprint": "e5f6a01b02c03d04nat",
|
||||||
|
"scenario_weights": ("cast_session", "cast_session"),
|
||||||
|
"process": "main",
|
||||||
|
"activity": "ScreenCastActivity",
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGSEGV",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 00012ab4 /data/app/.../lib/arm64/libandroidcast_crash_hook.so (crash_hook_backtrace+64)",
|
||||||
|
"#01 pc 0003f210 /data/app/.../lib/arm64/libandroidcast_jni.so (Java_com_foxx_androidcast_native_CrashHook_notify+28)",
|
||||||
|
"#02 pc 00021c44 /system/lib64/libart.so (art_quick_generic_jni_trampoline+148)",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fingerprint": "e5f6a01b02c03d04nat",
|
||||||
|
"scenario_weights": ("cast_session", "cast_session"),
|
||||||
|
"process": ":crashwatcher",
|
||||||
|
"activity": "ScreenCastActivity",
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGSEGV",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 00008f20 /data/app/.../lib/arm64/libandroidcast_crash_hook.so (unwind_stub+32)",
|
||||||
|
"#01 pc 00011a04 /data/app/.../lib/arm64/libandroidcast_crash_hook.so (native_stub_write+96)",
|
||||||
|
"#02 pc 0002bc10 /apex/com.android.runtime/lib64/bionic/libc.so (__restore_rt)",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fingerprint": "nat_stfg_omx01",
|
||||||
|
"scenario_weights": ("cast_session", "cast_session"),
|
||||||
|
"process": "main",
|
||||||
|
"activity": "ScreenCastActivity",
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGSEGV",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 000a4120 /system/lib64/libstagefright.so (android::MediaCodec::onMessageReceived+312)",
|
||||||
|
"#01 pc 0004e8c4 /system/lib64/libhidlbase.so (android::hardware::media::omx::V1_0::IOmxNode::dispatchMessage+68)",
|
||||||
|
"#02 pc 0001d330 /data/app/.../lib/arm64/libandroidcast_encoder.so (AvcEncoder::drainNAL+44)",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fingerprint": "nat_abort01",
|
||||||
|
"scenario_weights": ("cast_session", "app_runtime"),
|
||||||
|
"process": "main",
|
||||||
|
"activity": "ScreenCastActivity",
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGABRT",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 0008c4bc /apex/com.android.runtime/lib64/bionic/libc.so (abort+164)",
|
||||||
|
"#01 pc 00005120 /data/app/.../lib/arm64/libandroidcast_crash_hook.so (crash_hook_abort+48)",
|
||||||
|
"#02 pc 0003a8f0 /data/app/.../lib/arm64/libandroidcast_jni.so (jni_fatal_callback+20)",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fingerprint": "nat_bus_frb02",
|
||||||
|
"scenario_weights": ("cast_session", "cast_session"),
|
||||||
|
"process": "main",
|
||||||
|
"activity": "ScreenCastActivity",
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGBUS",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 0000c210 /data/app/.../lib/arm64/libandroidcast_capture.so (FrameRingBuffer::slot_at+28)",
|
||||||
|
"#01 pc 0000d884 /data/app/.../lib/arm64/libandroidcast_capture.so (FrameRingBuffer::push_copy+112)",
|
||||||
|
"#02 pc 0002f1a0 /data/app/.../lib/arm64/libandroidcast_jni.so (native_on_frame+64)",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fingerprint": "nat_fpe_swr03",
|
||||||
|
"scenario_weights": ("cast_session",),
|
||||||
|
"process": "main",
|
||||||
|
"activity": "ScreenCastActivity",
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGFPE",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 0006b2c4 /vendor/lib64/libswresample.so (resample_internal+196)",
|
||||||
|
"#01 pc 0004a018 /data/app/.../lib/arm64/libandroidcast_audio.so (AudioResampler::convert+80)",
|
||||||
|
"#02 pc 0001ac44 /data/app/.../lib/arm64/libandroidcast_jni.so (native_audio_tick+36)",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fingerprint": "nat_trap_jni05",
|
||||||
|
"scenario_weights": ("app_runtime", "cast_session"),
|
||||||
|
"process": ":crashwatcher",
|
||||||
|
"activity": "MainActivity",
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGTRAP",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 00002d10 /data/app/.../lib/arm64/libandroidcast_crash_hook.so (debug_trap_handler+16)",
|
||||||
|
"#01 pc 00019c80 /system/lib64/libart.so (art::Thread::DumpStack+320)",
|
||||||
|
"#02 pc 0000e4a8 /data/app/.../lib/arm64/libandroidcast_jni.so (CrashHook::selfTest+24)",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fingerprint": "nat_ill_insn06",
|
||||||
|
"scenario_weights": ("cast_session", "cast_session"),
|
||||||
|
"process": "main",
|
||||||
|
"activity": "ScreenCastActivity",
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGILL",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 00004580 /data/app/.../lib/arm64/libh264_neon.so (neon_idct_invalid+8)",
|
||||||
|
"#01 pc 00012f40 /data/app/.../lib/arm64/libandroidcast_encoder.so (H264Encoder::decode_slice+128)",
|
||||||
|
"#02 pc 00008c00 /data/app/.../lib/arm64/libandroidcast_jni.so (encoder_worker+200)",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
APP_VERSIONS = [
|
||||||
|
("0.1.0", 100, "deadbeef"),
|
||||||
|
("0.1.1", 101, "cafebabe"),
|
||||||
|
("0.2.0-dev", 120, "a1b2c3d4"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def pick(seq):
|
||||||
|
return random.choice(seq)
|
||||||
|
|
||||||
|
|
||||||
|
def build_report(index: int, kind: str, tpl: dict) -> dict:
|
||||||
|
mfr, brand, model, device, sdk, release = pick(DEVICES)
|
||||||
|
ver_name, ver_code, git = pick(APP_VERSIONS)
|
||||||
|
scenario = pick(tpl["scenario_weights"])
|
||||||
|
ts = BASE_MS + index * 29 * 60 * 1000 + random.randint(0, 3600000)
|
||||||
|
slug = model.lower().replace(" ", "_")[:12]
|
||||||
|
report_id = str(uuid.uuid5(uuid.NAMESPACE_DNS, f"fake-{kind}-{index}-{slug}"))
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": report_id,
|
||||||
|
"generated_at_epoch_ms": ts,
|
||||||
|
"crash_type": "java" if kind == "java" else "native",
|
||||||
|
"scenario": scenario,
|
||||||
|
"process": tpl["process"],
|
||||||
|
"report_file": f"crash_{datetime.fromtimestamp(ts / 1000, tz=timezone.utc).strftime('%Y%m%d_%H%M%S')}.json",
|
||||||
|
"fingerprint": tpl["fingerprint"],
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": ts - random.randint(60_000, 3_600_000),
|
||||||
|
"last_activity": tpl["activity"],
|
||||||
|
"sender_cast_active": scenario == "cast_session",
|
||||||
|
"receiver_cast_active": False,
|
||||||
|
"cast_active": scenario == "cast_session",
|
||||||
|
"session_stats_active": scenario == "cast_session" and random.random() > 0.4,
|
||||||
|
"last_session_file": f"session_send_{datetime.fromtimestamp(ts / 1000, tz=timezone.utc).strftime('%Y%m%d_%H%M%S')}.json",
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": mfr,
|
||||||
|
"brand": brand,
|
||||||
|
"model": model,
|
||||||
|
"device": device,
|
||||||
|
"product": device,
|
||||||
|
"sdk_int": sdk,
|
||||||
|
"release": release,
|
||||||
|
"abis": ["arm64-v8a", "armeabi-v7a"] if sdk >= 21 else ["armeabi-v7a"],
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": ver_name,
|
||||||
|
"version_code": ver_code,
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": ver_name.endswith("-dev") or random.random() > 0.6,
|
||||||
|
"git_commit": git,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if kind == "java":
|
||||||
|
payload["java"] = dict(tpl["java"])
|
||||||
|
else:
|
||||||
|
payload["native"] = {
|
||||||
|
"signal": tpl["native"]["signal"],
|
||||||
|
"backtrace": list(tpl["native"]["backtrace"]),
|
||||||
|
}
|
||||||
|
return payload
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
random.seed(GENERATION_SEED)
|
||||||
|
OUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
|
for old in OUT_DIR.glob("crash*.json"):
|
||||||
|
old.unlink()
|
||||||
|
|
||||||
|
for i in range(JAVA_COUNT):
|
||||||
|
tpl = pick(JAVA_TEMPLATES)
|
||||||
|
path = OUT_DIR / f"crash_java_{i + 1:03d}.json"
|
||||||
|
path.write_text(
|
||||||
|
json.dumps(build_report(i, "java", tpl), indent=2, ensure_ascii=False) + "\n",
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
|
||||||
|
for i in range(NATIVE_COUNT):
|
||||||
|
tpl = pick(NATIVE_TEMPLATES)
|
||||||
|
path = OUT_DIR / f"crash_native_{i + 1:03d}.json"
|
||||||
|
path.write_text(
|
||||||
|
json.dumps(build_report(i, "native", tpl), indent=2, ensure_ascii=False) + "\n",
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
|
||||||
|
total = JAVA_COUNT + NATIVE_COUNT
|
||||||
|
print(f"Wrote {total} reports to {OUT_DIR} ({JAVA_COUNT} java, {NATIVE_COUNT} native)")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
23
examples/crash_reporter/test_reports/README.md
Normal file
23
examples/crash_reporter/test_reports/README.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Test crash reports
|
||||||
|
|
||||||
|
**65** fake payloads: **35 java** + **30 native** (`crash_java_*.json`, `crash_native_*.json`).
|
||||||
|
|
||||||
|
Regenerate:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 ../generate_test_reports.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Batch upload (all):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
../upload_test.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Upload only native:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ONLY=native ../upload_test.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Native clusters use signals `SIGSEGV`, `SIGABRT`, `SIGBUS`, `SIGFPE`, `SIGTRAP`, `SIGILL` with shared fingerprints per crash family (see `generate_test_reports.py`).
|
||||||
50
examples/crash_reporter/test_reports/crash_java_001.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_001.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "3046575f-58f6-5542-a72e-135ed5f562c6",
|
||||||
|
"generated_at_epoch_ms": 1777637675884,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "app_runtime",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_121435.json",
|
||||||
|
"fingerprint": "d4e5f6a01b02c03net",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777635763408,
|
||||||
|
"last_activity": "MainActivity",
|
||||||
|
"sender_cast_active": false,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": false,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260501_121435.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Realme",
|
||||||
|
"brand": "realme",
|
||||||
|
"model": "Pad 2",
|
||||||
|
"device": "RMX2201",
|
||||||
|
"product": "RMX2201",
|
||||||
|
"sdk_int": 33,
|
||||||
|
"release": "13",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.1",
|
||||||
|
"version_code": 101
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "cafebabe"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "UdpSender-1",
|
||||||
|
"exception": "java.net.SocketTimeoutException",
|
||||||
|
"message": "connect timed out",
|
||||||
|
"stack_frames": [
|
||||||
|
"at com.foxx.androidcast.network.udp.UdpCastTransport.send(UdpCastTransport.java:142)",
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.flushStats(ScreenCastService.java:455)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_002.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_002.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "c49c498a-23dc-5afd-a37f-cf0fc965c3b9",
|
||||||
|
"generated_at_epoch_ms": 1777641978209,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_132618.json",
|
||||||
|
"fingerprint": "c3d4e5f6a01b02oom",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777641560292,
|
||||||
|
"last_activity": "MainActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260501_132618.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "TCL",
|
||||||
|
"brand": "TCL",
|
||||||
|
"model": "Tab 10 Gen2",
|
||||||
|
"device": "9081G",
|
||||||
|
"product": "9081G",
|
||||||
|
"sdk_int": 31,
|
||||||
|
"release": "12",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.2.0-dev",
|
||||||
|
"version_code": 120
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "a1b2c3d4"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "pool-3-thread-2",
|
||||||
|
"exception": "java.lang.OutOfMemoryError",
|
||||||
|
"message": "Failed to allocate a 8294400 byte allocation with 524288 free bytes",
|
||||||
|
"stack_frames": [
|
||||||
|
"at android.graphics.Bitmap.createBitmap(Bitmap.java:1234)",
|
||||||
|
"at com.foxx.androidcast.capture.FrameRingBuffer.push(FrameRingBuffer.java:56)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_003.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_003.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "0af0cae6-95b3-56bb-9ea4-be2a2759c7b2",
|
||||||
|
"generated_at_epoch_ms": 1777643375148,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_134935.json",
|
||||||
|
"fingerprint": "b2c3d4e5f6a01codec",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777641833812,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260501_134935.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Samsung",
|
||||||
|
"brand": "samsung",
|
||||||
|
"model": "Galaxy Tab A9+",
|
||||||
|
"device": "gta9pwifi",
|
||||||
|
"product": "gta9pwifi",
|
||||||
|
"sdk_int": 34,
|
||||||
|
"release": "14",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.0",
|
||||||
|
"version_code": 100
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "deadbeef"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "EncoderThread-1",
|
||||||
|
"exception": "java.lang.IllegalStateException",
|
||||||
|
"message": "MediaCodec codec is released already",
|
||||||
|
"stack_frames": [
|
||||||
|
"at android.media.MediaCodec.native_dequeueOutputBuffer(Native Method)",
|
||||||
|
"at com.foxx.androidcast.encoder.H264Encoder.drain(H264Encoder.java:88)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_004.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_004.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "ffe2d35c-b0bd-5ff4-a3f1-eb45a535350a",
|
||||||
|
"generated_at_epoch_ms": 1777643114406,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_134514.json",
|
||||||
|
"fingerprint": "b2c3d4e5f6a01codec",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777641026858,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260501_134514.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Asus",
|
||||||
|
"brand": "asus",
|
||||||
|
"model": "ZenPad 10",
|
||||||
|
"device": "P00C",
|
||||||
|
"product": "P00C",
|
||||||
|
"sdk_int": 29,
|
||||||
|
"release": "10",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.2.0-dev",
|
||||||
|
"version_code": 120
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "a1b2c3d4"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "EncoderThread-1",
|
||||||
|
"exception": "java.lang.IllegalStateException",
|
||||||
|
"message": "MediaCodec codec is released already",
|
||||||
|
"stack_frames": [
|
||||||
|
"at android.media.MediaCodec.native_dequeueOutputBuffer(Native Method)",
|
||||||
|
"at com.foxx.androidcast.encoder.H264Encoder.drain(H264Encoder.java:88)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_005.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_005.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "dad727ca-0ff7-5d50-b7cf-211a19ea47f8",
|
||||||
|
"generated_at_epoch_ms": 1777644027249,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_140027.json",
|
||||||
|
"fingerprint": "d4e5f6a01b02c03net",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777643125367,
|
||||||
|
"last_activity": "MainActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260501_140027.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Samsung",
|
||||||
|
"brand": "samsung",
|
||||||
|
"model": "Galaxy Tab A9+",
|
||||||
|
"device": "gta9pwifi",
|
||||||
|
"product": "gta9pwifi",
|
||||||
|
"sdk_int": 34,
|
||||||
|
"release": "14",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.2.0-dev",
|
||||||
|
"version_code": 120
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "a1b2c3d4"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "UdpSender-1",
|
||||||
|
"exception": "java.net.SocketTimeoutException",
|
||||||
|
"message": "connect timed out",
|
||||||
|
"stack_frames": [
|
||||||
|
"at com.foxx.androidcast.network.udp.UdpCastTransport.send(UdpCastTransport.java:142)",
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.flushStats(ScreenCastService.java:455)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_006.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_006.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "bb62d9ee-1262-551d-8ec0-21250d2bd3e9",
|
||||||
|
"generated_at_epoch_ms": 1777647916919,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_150516.json",
|
||||||
|
"fingerprint": "c3d4e5f6a01b02oom",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777644480507,
|
||||||
|
"last_activity": "MainActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260501_150516.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Samsung",
|
||||||
|
"brand": "samsung",
|
||||||
|
"model": "Galaxy Tab A9+",
|
||||||
|
"device": "gta9pwifi",
|
||||||
|
"product": "gta9pwifi",
|
||||||
|
"sdk_int": 34,
|
||||||
|
"release": "14",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.1",
|
||||||
|
"version_code": 101
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "cafebabe"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "pool-3-thread-2",
|
||||||
|
"exception": "java.lang.OutOfMemoryError",
|
||||||
|
"message": "Failed to allocate a 8294400 byte allocation with 524288 free bytes",
|
||||||
|
"stack_frames": [
|
||||||
|
"at android.graphics.Bitmap.createBitmap(Bitmap.java:1234)",
|
||||||
|
"at com.foxx.androidcast.capture.FrameRingBuffer.push(FrameRingBuffer.java:56)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_007.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_007.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "7151b615-1421-595f-80a8-de0a26ef7b39",
|
||||||
|
"generated_at_epoch_ms": 1777649652277,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "app_runtime",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_153412.json",
|
||||||
|
"fingerprint": "f6a01b02c03d04e05perm",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777646750557,
|
||||||
|
"last_activity": "MainActivity",
|
||||||
|
"sender_cast_active": false,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": false,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260501_153412.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Honor",
|
||||||
|
"brand": "HONOR",
|
||||||
|
"model": "Pad X8a",
|
||||||
|
"device": "HEY2",
|
||||||
|
"product": "HEY2",
|
||||||
|
"sdk_int": 34,
|
||||||
|
"release": "14",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.2.0-dev",
|
||||||
|
"version_code": 120
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "a1b2c3d4"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "main",
|
||||||
|
"exception": "java.lang.SecurityException",
|
||||||
|
"message": "MediaProjection requires FOREGROUND_SERVICE_MEDIA_PROJECTION",
|
||||||
|
"stack_frames": [
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.acquireProjection(ScreenCastService.java:167)",
|
||||||
|
"at com.foxx.androidcast.ui.MainActivity.startCast(MainActivity.java:89)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_008.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_008.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "96e585ab-41d0-5862-a1d7-221fb191463b",
|
||||||
|
"generated_at_epoch_ms": 1777652246115,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_161726.json",
|
||||||
|
"fingerprint": "b2c3d4e5f6a01codec",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777649964933,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260501_161726.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Huawei",
|
||||||
|
"brand": "HUAWEI",
|
||||||
|
"model": "MatePad 11",
|
||||||
|
"device": "BAH3",
|
||||||
|
"product": "BAH3",
|
||||||
|
"sdk_int": 31,
|
||||||
|
"release": "12",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.2.0-dev",
|
||||||
|
"version_code": 120
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "a1b2c3d4"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "EncoderThread-1",
|
||||||
|
"exception": "java.lang.IllegalStateException",
|
||||||
|
"message": "MediaCodec codec is released already",
|
||||||
|
"stack_frames": [
|
||||||
|
"at android.media.MediaCodec.native_dequeueOutputBuffer(Native Method)",
|
||||||
|
"at com.foxx.androidcast.encoder.H264Encoder.drain(H264Encoder.java:88)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_009.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_009.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "ceaedbcf-a8e6-56f9-b813-ee9ed5571690",
|
||||||
|
"generated_at_epoch_ms": 1777653179464,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_163259.json",
|
||||||
|
"fingerprint": "a1b2c3d4e5f6npe01",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777652675161,
|
||||||
|
"last_activity": "CastSettingsActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260501_163259.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Asus",
|
||||||
|
"brand": "asus",
|
||||||
|
"model": "ZenPad 10",
|
||||||
|
"device": "P00C",
|
||||||
|
"product": "P00C",
|
||||||
|
"sdk_int": 29,
|
||||||
|
"release": "10",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.1",
|
||||||
|
"version_code": 101
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "cafebabe"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "main",
|
||||||
|
"exception": "java.lang.NullPointerException",
|
||||||
|
"message": "encoderSurface was null when starting capture",
|
||||||
|
"stack_frames": [
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.startCapture(ScreenCastService.java:412)",
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.onStartCommand(ScreenCastService.java:205)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_010.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_010.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "5511c727-8375-57ba-805b-3335ef39649c",
|
||||||
|
"generated_at_epoch_ms": 1777653519182,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "app_runtime",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_163839.json",
|
||||||
|
"fingerprint": "f6a01b02c03d04e05perm",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777652291653,
|
||||||
|
"last_activity": "MainActivity",
|
||||||
|
"sender_cast_active": false,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": false,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260501_163839.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Doogee",
|
||||||
|
"brand": "DOOGEE",
|
||||||
|
"model": "Tab G6 Max",
|
||||||
|
"device": "TabG6Max",
|
||||||
|
"product": "TabG6Max",
|
||||||
|
"sdk_int": 34,
|
||||||
|
"release": "14",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.2.0-dev",
|
||||||
|
"version_code": 120
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "a1b2c3d4"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "main",
|
||||||
|
"exception": "java.lang.SecurityException",
|
||||||
|
"message": "MediaProjection requires FOREGROUND_SERVICE_MEDIA_PROJECTION",
|
||||||
|
"stack_frames": [
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.acquireProjection(ScreenCastService.java:167)",
|
||||||
|
"at com.foxx.androidcast.ui.MainActivity.startCast(MainActivity.java:89)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_011.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_011.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "6869f88e-5ea9-5d0b-8f54-a42d28b34669",
|
||||||
|
"generated_at_epoch_ms": 1777657433843,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "app_runtime",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_174353.json",
|
||||||
|
"fingerprint": "d4e5f6a01b02c03net",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777654788397,
|
||||||
|
"last_activity": "MainActivity",
|
||||||
|
"sender_cast_active": false,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": false,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260501_174353.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Google",
|
||||||
|
"brand": "google",
|
||||||
|
"model": "Pixel Tablet",
|
||||||
|
"device": "tangorpro",
|
||||||
|
"product": "tangorpro",
|
||||||
|
"sdk_int": 34,
|
||||||
|
"release": "14",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.1",
|
||||||
|
"version_code": 101
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "cafebabe"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "UdpSender-1",
|
||||||
|
"exception": "java.net.SocketTimeoutException",
|
||||||
|
"message": "connect timed out",
|
||||||
|
"stack_frames": [
|
||||||
|
"at com.foxx.androidcast.network.udp.UdpCastTransport.send(UdpCastTransport.java:142)",
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.flushStats(ScreenCastService.java:455)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_012.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_012.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "067d7e49-9346-5e0a-adec-ad0e9e381cbd",
|
||||||
|
"generated_at_epoch_ms": 1777657112214,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_173832.json",
|
||||||
|
"fingerprint": "d4e5f6a01b02c03net",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777656083966,
|
||||||
|
"last_activity": "MainActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260501_173832.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Realme",
|
||||||
|
"brand": "realme",
|
||||||
|
"model": "Pad 2",
|
||||||
|
"device": "RMX2201",
|
||||||
|
"product": "RMX2201",
|
||||||
|
"sdk_int": 33,
|
||||||
|
"release": "13",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.1",
|
||||||
|
"version_code": 101
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "cafebabe"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "UdpSender-1",
|
||||||
|
"exception": "java.net.SocketTimeoutException",
|
||||||
|
"message": "connect timed out",
|
||||||
|
"stack_frames": [
|
||||||
|
"at com.foxx.androidcast.network.udp.UdpCastTransport.send(UdpCastTransport.java:142)",
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.flushStats(ScreenCastService.java:455)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_013.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_013.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "15a408ce-98f6-54a7-949f-4006dae99652",
|
||||||
|
"generated_at_epoch_ms": 1777659308389,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_181508.json",
|
||||||
|
"fingerprint": "a1b2c3d4e5f6npe01",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777655747320,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260501_181508.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Google",
|
||||||
|
"brand": "google",
|
||||||
|
"model": "Pixel Tablet",
|
||||||
|
"device": "tangorpro",
|
||||||
|
"product": "tangorpro",
|
||||||
|
"sdk_int": 34,
|
||||||
|
"release": "14",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.2.0-dev",
|
||||||
|
"version_code": 120
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "a1b2c3d4"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "main",
|
||||||
|
"exception": "java.lang.NullPointerException",
|
||||||
|
"message": "Attempt to invoke virtual method on a null object reference",
|
||||||
|
"stack_frames": [
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.onCreate(ScreenCastService.java:118)",
|
||||||
|
"at android.app.ActivityThread.handleCreateService(ActivityThread.java:5148)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_014.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_014.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "7893ac74-3588-597a-af7c-f93526eb15e5",
|
||||||
|
"generated_at_epoch_ms": 1777660062021,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_182742.json",
|
||||||
|
"fingerprint": "b2c3d4e5f6a01codec",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777656784323,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260501_182742.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Doogee",
|
||||||
|
"brand": "DOOGEE",
|
||||||
|
"model": "Tab G6 Max",
|
||||||
|
"device": "TabG6Max",
|
||||||
|
"product": "TabG6Max",
|
||||||
|
"sdk_int": 34,
|
||||||
|
"release": "14",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.0",
|
||||||
|
"version_code": 100
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "deadbeef"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "EncoderThread-1",
|
||||||
|
"exception": "java.lang.IllegalStateException",
|
||||||
|
"message": "MediaCodec codec is released already",
|
||||||
|
"stack_frames": [
|
||||||
|
"at android.media.MediaCodec.native_dequeueOutputBuffer(Native Method)",
|
||||||
|
"at com.foxx.androidcast.encoder.H264Encoder.drain(H264Encoder.java:88)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_015.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_015.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "2c8cb70c-92e2-51a8-9df1-469b7706f60a",
|
||||||
|
"generated_at_epoch_ms": 1777663450481,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_192410.json",
|
||||||
|
"fingerprint": "a1b2c3d4e5f6npe01",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777660388518,
|
||||||
|
"last_activity": "CastSettingsActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260501_192410.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Honor",
|
||||||
|
"brand": "HONOR",
|
||||||
|
"model": "Pad X8a",
|
||||||
|
"device": "HEY2",
|
||||||
|
"product": "HEY2",
|
||||||
|
"sdk_int": 34,
|
||||||
|
"release": "14",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.1",
|
||||||
|
"version_code": 101
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "cafebabe"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "main",
|
||||||
|
"exception": "java.lang.NullPointerException",
|
||||||
|
"message": "encoderSurface was null when starting capture",
|
||||||
|
"stack_frames": [
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.startCapture(ScreenCastService.java:412)",
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.onStartCommand(ScreenCastService.java:205)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_016.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_016.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "f73fd6a9-7443-54b1-9eb2-a5a535ea2cd8",
|
||||||
|
"generated_at_epoch_ms": 1777663799507,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_192959.json",
|
||||||
|
"fingerprint": "a1b2c3d4e5f6npe01",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777660983648,
|
||||||
|
"last_activity": "CastSettingsActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260501_192959.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Google",
|
||||||
|
"brand": "google",
|
||||||
|
"model": "Pixel Tablet",
|
||||||
|
"device": "tangorpro",
|
||||||
|
"product": "tangorpro",
|
||||||
|
"sdk_int": 34,
|
||||||
|
"release": "14",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.0",
|
||||||
|
"version_code": 100
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "deadbeef"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "main",
|
||||||
|
"exception": "java.lang.NullPointerException",
|
||||||
|
"message": "encoderSurface was null when starting capture",
|
||||||
|
"stack_frames": [
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.startCapture(ScreenCastService.java:412)",
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.onStartCommand(ScreenCastService.java:205)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_017.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_017.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "c9e9926b-76fa-561d-aa17-46978c0e47f9",
|
||||||
|
"generated_at_epoch_ms": 1777668153571,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_204233.json",
|
||||||
|
"fingerprint": "b2c3d4e5f6a01codec",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777664867614,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260501_204233.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Honor",
|
||||||
|
"brand": "HONOR",
|
||||||
|
"model": "Pad X8a",
|
||||||
|
"device": "HEY2",
|
||||||
|
"product": "HEY2",
|
||||||
|
"sdk_int": 34,
|
||||||
|
"release": "14",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.0",
|
||||||
|
"version_code": 100
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "deadbeef"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "EncoderThread-1",
|
||||||
|
"exception": "java.lang.IllegalStateException",
|
||||||
|
"message": "MediaCodec codec is released already",
|
||||||
|
"stack_frames": [
|
||||||
|
"at android.media.MediaCodec.native_dequeueOutputBuffer(Native Method)",
|
||||||
|
"at com.foxx.androidcast.encoder.H264Encoder.drain(H264Encoder.java:88)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_018.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_018.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "9505baac-56ab-5c01-af00-bee4b7f9c890",
|
||||||
|
"generated_at_epoch_ms": 1777666722712,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_201842.json",
|
||||||
|
"fingerprint": "a1b2c3d4e5f6npe01",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777664270872,
|
||||||
|
"last_activity": "CastSettingsActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260501_201842.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Google",
|
||||||
|
"brand": "google",
|
||||||
|
"model": "Pixel Tablet",
|
||||||
|
"device": "tangorpro",
|
||||||
|
"product": "tangorpro",
|
||||||
|
"sdk_int": 34,
|
||||||
|
"release": "14",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.2.0-dev",
|
||||||
|
"version_code": 120
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "a1b2c3d4"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "main",
|
||||||
|
"exception": "java.lang.NullPointerException",
|
||||||
|
"message": "encoderSurface was null when starting capture",
|
||||||
|
"stack_frames": [
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.startCapture(ScreenCastService.java:412)",
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.onStartCommand(ScreenCastService.java:205)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_019.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_019.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "73770992-8cb1-5e89-b4a8-4071aea02efd",
|
||||||
|
"generated_at_epoch_ms": 1777671482437,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "app_runtime",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_213802.json",
|
||||||
|
"fingerprint": "f6a01b02c03d04e05perm",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777669937160,
|
||||||
|
"last_activity": "MainActivity",
|
||||||
|
"sender_cast_active": false,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": false,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260501_213802.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Vivo",
|
||||||
|
"brand": "vivo",
|
||||||
|
"model": "Pad Air",
|
||||||
|
"device": "PA2353",
|
||||||
|
"product": "PA2353",
|
||||||
|
"sdk_int": 34,
|
||||||
|
"release": "14",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.1",
|
||||||
|
"version_code": 101
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "cafebabe"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "main",
|
||||||
|
"exception": "java.lang.SecurityException",
|
||||||
|
"message": "MediaProjection requires FOREGROUND_SERVICE_MEDIA_PROJECTION",
|
||||||
|
"stack_frames": [
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.acquireProjection(ScreenCastService.java:167)",
|
||||||
|
"at com.foxx.androidcast.ui.MainActivity.startCast(MainActivity.java:89)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_020.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_020.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "4f69ca8b-dd03-5f07-8f93-835351975536",
|
||||||
|
"generated_at_epoch_ms": 1777671370829,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_213610.json",
|
||||||
|
"fingerprint": "b2c3d4e5f6a01codec",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777669067031,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260501_213610.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Oppo",
|
||||||
|
"brand": "OPPO",
|
||||||
|
"model": "Pad Neo",
|
||||||
|
"device": "OPD2301",
|
||||||
|
"product": "OPD2301",
|
||||||
|
"sdk_int": 33,
|
||||||
|
"release": "13",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.1",
|
||||||
|
"version_code": 101
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "cafebabe"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "EncoderThread-1",
|
||||||
|
"exception": "java.lang.IllegalStateException",
|
||||||
|
"message": "MediaCodec codec is released already",
|
||||||
|
"stack_frames": [
|
||||||
|
"at android.media.MediaCodec.native_dequeueOutputBuffer(Native Method)",
|
||||||
|
"at com.foxx.androidcast.encoder.H264Encoder.drain(H264Encoder.java:88)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_021.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_021.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "216c116a-6d0e-597f-bdf3-03bd39c4ce4e",
|
||||||
|
"generated_at_epoch_ms": 1777672002596,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "app_runtime",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_214642.json",
|
||||||
|
"fingerprint": "f6a01b02c03d04e05perm",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777668703009,
|
||||||
|
"last_activity": "MainActivity",
|
||||||
|
"sender_cast_active": false,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": false,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260501_214642.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Asus",
|
||||||
|
"brand": "asus",
|
||||||
|
"model": "ZenPad 10",
|
||||||
|
"device": "P00C",
|
||||||
|
"product": "P00C",
|
||||||
|
"sdk_int": 29,
|
||||||
|
"release": "10",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.0",
|
||||||
|
"version_code": 100
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "deadbeef"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "main",
|
||||||
|
"exception": "java.lang.SecurityException",
|
||||||
|
"message": "MediaProjection requires FOREGROUND_SERVICE_MEDIA_PROJECTION",
|
||||||
|
"stack_frames": [
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.acquireProjection(ScreenCastService.java:167)",
|
||||||
|
"at com.foxx.androidcast.ui.MainActivity.startCast(MainActivity.java:89)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_022.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_022.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "34c1ee1b-8907-55c5-b0a7-09f6bcd56772",
|
||||||
|
"generated_at_epoch_ms": 1777674255484,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_222415.json",
|
||||||
|
"fingerprint": "a1b2c3d4e5f6npe01",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777672968511,
|
||||||
|
"last_activity": "CastSettingsActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260501_222415.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Vivo",
|
||||||
|
"brand": "vivo",
|
||||||
|
"model": "Pad Air",
|
||||||
|
"device": "PA2353",
|
||||||
|
"product": "PA2353",
|
||||||
|
"sdk_int": 34,
|
||||||
|
"release": "14",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.1",
|
||||||
|
"version_code": 101
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "cafebabe"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "main",
|
||||||
|
"exception": "java.lang.NullPointerException",
|
||||||
|
"message": "encoderSurface was null when starting capture",
|
||||||
|
"stack_frames": [
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.startCapture(ScreenCastService.java:412)",
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.onStartCommand(ScreenCastService.java:205)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_023.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_023.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "c419acfc-0ddf-5078-9e4a-f4911cd37c28",
|
||||||
|
"generated_at_epoch_ms": 1777675148668,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_223908.json",
|
||||||
|
"fingerprint": "b2c3d4e5f6a01codec",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777671602955,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260501_223908.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Doogee",
|
||||||
|
"brand": "DOOGEE",
|
||||||
|
"model": "Tab G6 Max",
|
||||||
|
"device": "TabG6Max",
|
||||||
|
"product": "TabG6Max",
|
||||||
|
"sdk_int": 34,
|
||||||
|
"release": "14",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.0",
|
||||||
|
"version_code": 100
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "deadbeef"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "EncoderThread-1",
|
||||||
|
"exception": "java.lang.IllegalStateException",
|
||||||
|
"message": "MediaCodec codec is released already",
|
||||||
|
"stack_frames": [
|
||||||
|
"at android.media.MediaCodec.native_dequeueOutputBuffer(Native Method)",
|
||||||
|
"at com.foxx.androidcast.encoder.H264Encoder.drain(H264Encoder.java:88)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_024.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_024.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "6d7f8cdc-70d0-56e2-b759-5db3af4f5d9d",
|
||||||
|
"generated_at_epoch_ms": 1777677455341,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "app_runtime",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_231735.json",
|
||||||
|
"fingerprint": "f6a01b02c03d04e05perm",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777677176599,
|
||||||
|
"last_activity": "MainActivity",
|
||||||
|
"sender_cast_active": false,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": false,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260501_231735.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Acer",
|
||||||
|
"brand": "Acer",
|
||||||
|
"model": "Iconia Tab P10",
|
||||||
|
"device": "acer_p10",
|
||||||
|
"product": "acer_p10",
|
||||||
|
"sdk_int": 31,
|
||||||
|
"release": "12",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.1",
|
||||||
|
"version_code": 101
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "cafebabe"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "main",
|
||||||
|
"exception": "java.lang.SecurityException",
|
||||||
|
"message": "MediaProjection requires FOREGROUND_SERVICE_MEDIA_PROJECTION",
|
||||||
|
"stack_frames": [
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.acquireProjection(ScreenCastService.java:167)",
|
||||||
|
"at com.foxx.androidcast.ui.MainActivity.startCast(MainActivity.java:89)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_025.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_025.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "5ce2bedf-456c-56fb-b52a-9803939195c2",
|
||||||
|
"generated_at_epoch_ms": 1777679299939,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_234819.json",
|
||||||
|
"fingerprint": "a1b2c3d4e5f6npe01",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777677955182,
|
||||||
|
"last_activity": "CastSettingsActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260501_234819.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Asus",
|
||||||
|
"brand": "asus",
|
||||||
|
"model": "ZenPad 10",
|
||||||
|
"device": "P00C",
|
||||||
|
"product": "P00C",
|
||||||
|
"sdk_int": 29,
|
||||||
|
"release": "10",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.1",
|
||||||
|
"version_code": 101
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "cafebabe"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "main",
|
||||||
|
"exception": "java.lang.NullPointerException",
|
||||||
|
"message": "encoderSurface was null when starting capture",
|
||||||
|
"stack_frames": [
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.startCapture(ScreenCastService.java:412)",
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.onStartCommand(ScreenCastService.java:205)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_026.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_026.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "d7e67547-cf4f-5f36-8258-c564d06fe3b2",
|
||||||
|
"generated_at_epoch_ms": 1777680351805,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260502_000551.json",
|
||||||
|
"fingerprint": "d4e5f6a01b02c03net",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777679810598,
|
||||||
|
"last_activity": "MainActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260502_000551.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Asus",
|
||||||
|
"brand": "asus",
|
||||||
|
"model": "ZenPad 10",
|
||||||
|
"device": "P00C",
|
||||||
|
"product": "P00C",
|
||||||
|
"sdk_int": 29,
|
||||||
|
"release": "10",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.2.0-dev",
|
||||||
|
"version_code": 120
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "a1b2c3d4"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "UdpSender-1",
|
||||||
|
"exception": "java.net.SocketTimeoutException",
|
||||||
|
"message": "connect timed out",
|
||||||
|
"stack_frames": [
|
||||||
|
"at com.foxx.androidcast.network.udp.UdpCastTransport.send(UdpCastTransport.java:142)",
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.flushStats(ScreenCastService.java:455)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_027.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_027.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "060694f6-1db5-5abe-88b0-b075e4df5340",
|
||||||
|
"generated_at_epoch_ms": 1777684548897,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260502_011548.json",
|
||||||
|
"fingerprint": "a1b2c3d4e5f6npe01",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777683703283,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260502_011548.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Acer",
|
||||||
|
"brand": "Acer",
|
||||||
|
"model": "Iconia Tab P10",
|
||||||
|
"device": "acer_p10",
|
||||||
|
"product": "acer_p10",
|
||||||
|
"sdk_int": 31,
|
||||||
|
"release": "12",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.2.0-dev",
|
||||||
|
"version_code": 120
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "a1b2c3d4"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "main",
|
||||||
|
"exception": "java.lang.NullPointerException",
|
||||||
|
"message": "Attempt to invoke virtual method on a null object reference",
|
||||||
|
"stack_frames": [
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.onCreate(ScreenCastService.java:118)",
|
||||||
|
"at android.app.ActivityThread.handleCreateService(ActivityThread.java:5148)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_028.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_028.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "93d50ff3-01c8-5730-a302-ae7ca81e5957",
|
||||||
|
"generated_at_epoch_ms": 1777684971194,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "app_runtime",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260502_012251.json",
|
||||||
|
"fingerprint": "f6a01b02c03d04e05perm",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777683058572,
|
||||||
|
"last_activity": "MainActivity",
|
||||||
|
"sender_cast_active": false,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": false,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260502_012251.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Lenovo",
|
||||||
|
"brand": "Lenovo",
|
||||||
|
"model": "Tab P12",
|
||||||
|
"device": "TB370FU",
|
||||||
|
"product": "TB370FU",
|
||||||
|
"sdk_int": 34,
|
||||||
|
"release": "14",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.0",
|
||||||
|
"version_code": 100
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "deadbeef"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "main",
|
||||||
|
"exception": "java.lang.SecurityException",
|
||||||
|
"message": "MediaProjection requires FOREGROUND_SERVICE_MEDIA_PROJECTION",
|
||||||
|
"stack_frames": [
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.acquireProjection(ScreenCastService.java:167)",
|
||||||
|
"at com.foxx.androidcast.ui.MainActivity.startCast(MainActivity.java:89)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_029.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_029.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "2a388a20-7176-5e15-815a-195946cd4329",
|
||||||
|
"generated_at_epoch_ms": 1777688175910,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "app_runtime",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260502_021615.json",
|
||||||
|
"fingerprint": "a1b2c3d4e5f6npe01",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777687798182,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": false,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": false,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260502_021615.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Doogee",
|
||||||
|
"brand": "DOOGEE",
|
||||||
|
"model": "Tab G6 Max",
|
||||||
|
"device": "TabG6Max",
|
||||||
|
"product": "TabG6Max",
|
||||||
|
"sdk_int": 34,
|
||||||
|
"release": "14",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.1",
|
||||||
|
"version_code": 101
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "cafebabe"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "main",
|
||||||
|
"exception": "java.lang.NullPointerException",
|
||||||
|
"message": "Attempt to invoke virtual method on a null object reference",
|
||||||
|
"stack_frames": [
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.onCreate(ScreenCastService.java:118)",
|
||||||
|
"at android.app.ActivityThread.handleCreateService(ActivityThread.java:5148)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_030.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_030.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "5d5760dd-5361-5b1a-83f9-db23254ee251",
|
||||||
|
"generated_at_epoch_ms": 1777689521981,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "app_runtime",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260502_023841.json",
|
||||||
|
"fingerprint": "c3d4e5f6a01b02oom",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777687702443,
|
||||||
|
"last_activity": "MainActivity",
|
||||||
|
"sender_cast_active": false,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": false,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260502_023841.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Amazon",
|
||||||
|
"brand": "Amazon",
|
||||||
|
"model": "Fire HD 10",
|
||||||
|
"device": "trona",
|
||||||
|
"product": "trona",
|
||||||
|
"sdk_int": 30,
|
||||||
|
"release": "11",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.2.0-dev",
|
||||||
|
"version_code": 120
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "a1b2c3d4"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "pool-3-thread-2",
|
||||||
|
"exception": "java.lang.OutOfMemoryError",
|
||||||
|
"message": "Failed to allocate a 8294400 byte allocation with 524288 free bytes",
|
||||||
|
"stack_frames": [
|
||||||
|
"at android.graphics.Bitmap.createBitmap(Bitmap.java:1234)",
|
||||||
|
"at com.foxx.androidcast.capture.FrameRingBuffer.push(FrameRingBuffer.java:56)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_031.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_031.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "d4d7b8c2-c343-51c7-aa67-09d6ddf652ee",
|
||||||
|
"generated_at_epoch_ms": 1777691419279,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260502_031019.json",
|
||||||
|
"fingerprint": "a1b2c3d4e5f6npe01",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777688889307,
|
||||||
|
"last_activity": "CastSettingsActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260502_031019.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Honor",
|
||||||
|
"brand": "HONOR",
|
||||||
|
"model": "Pad X8a",
|
||||||
|
"device": "HEY2",
|
||||||
|
"product": "HEY2",
|
||||||
|
"sdk_int": 34,
|
||||||
|
"release": "14",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.2.0-dev",
|
||||||
|
"version_code": 120
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "a1b2c3d4"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "main",
|
||||||
|
"exception": "java.lang.NullPointerException",
|
||||||
|
"message": "encoderSurface was null when starting capture",
|
||||||
|
"stack_frames": [
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.startCapture(ScreenCastService.java:412)",
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.onStartCommand(ScreenCastService.java:205)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_032.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_032.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "70ae76e3-e960-5b23-8fca-52f545543a64",
|
||||||
|
"generated_at_epoch_ms": 1777694253068,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "app_runtime",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260502_035733.json",
|
||||||
|
"fingerprint": "c3d4e5f6a01b02oom",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777690690282,
|
||||||
|
"last_activity": "MainActivity",
|
||||||
|
"sender_cast_active": false,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": false,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260502_035733.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "TCL",
|
||||||
|
"brand": "TCL",
|
||||||
|
"model": "Tab 10 Gen2",
|
||||||
|
"device": "9081G",
|
||||||
|
"product": "9081G",
|
||||||
|
"sdk_int": 31,
|
||||||
|
"release": "12",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.2.0-dev",
|
||||||
|
"version_code": 120
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "a1b2c3d4"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "pool-3-thread-2",
|
||||||
|
"exception": "java.lang.OutOfMemoryError",
|
||||||
|
"message": "Failed to allocate a 8294400 byte allocation with 524288 free bytes",
|
||||||
|
"stack_frames": [
|
||||||
|
"at android.graphics.Bitmap.createBitmap(Bitmap.java:1234)",
|
||||||
|
"at com.foxx.androidcast.capture.FrameRingBuffer.push(FrameRingBuffer.java:56)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_033.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_033.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "13077573-3fca-55ce-a709-89858ffc58eb",
|
||||||
|
"generated_at_epoch_ms": 1777694523542,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260502_040203.json",
|
||||||
|
"fingerprint": "c3d4e5f6a01b02oom",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777694104868,
|
||||||
|
"last_activity": "MainActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260502_040203.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Asus",
|
||||||
|
"brand": "asus",
|
||||||
|
"model": "ZenPad 10",
|
||||||
|
"device": "P00C",
|
||||||
|
"product": "P00C",
|
||||||
|
"sdk_int": 29,
|
||||||
|
"release": "10",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.1",
|
||||||
|
"version_code": 101
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "cafebabe"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "pool-3-thread-2",
|
||||||
|
"exception": "java.lang.OutOfMemoryError",
|
||||||
|
"message": "Failed to allocate a 8294400 byte allocation with 524288 free bytes",
|
||||||
|
"stack_frames": [
|
||||||
|
"at android.graphics.Bitmap.createBitmap(Bitmap.java:1234)",
|
||||||
|
"at com.foxx.androidcast.capture.FrameRingBuffer.push(FrameRingBuffer.java:56)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_034.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_034.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "83b1155e-07e3-5529-b4cf-7db9cef67e9b",
|
||||||
|
"generated_at_epoch_ms": 1777694454405,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260502_040054.json",
|
||||||
|
"fingerprint": "a1b2c3d4e5f6npe01",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777692361013,
|
||||||
|
"last_activity": "CastSettingsActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260502_040054.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Motorola",
|
||||||
|
"brand": "motorola",
|
||||||
|
"model": "Tab G70",
|
||||||
|
"device": "scout",
|
||||||
|
"product": "scout",
|
||||||
|
"sdk_int": 33,
|
||||||
|
"release": "13",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.1",
|
||||||
|
"version_code": 101
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "cafebabe"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "main",
|
||||||
|
"exception": "java.lang.NullPointerException",
|
||||||
|
"message": "encoderSurface was null when starting capture",
|
||||||
|
"stack_frames": [
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.startCapture(ScreenCastService.java:412)",
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.onStartCommand(ScreenCastService.java:205)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
examples/crash_reporter/test_reports/crash_java_035.json
Normal file
50
examples/crash_reporter/test_reports/crash_java_035.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "67ec48ff-beee-59d5-aa7e-19365855f34a",
|
||||||
|
"generated_at_epoch_ms": 1777697828519,
|
||||||
|
"crash_type": "java",
|
||||||
|
"scenario": "app_runtime",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260502_045708.json",
|
||||||
|
"fingerprint": "d4e5f6a01b02c03net",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777696674589,
|
||||||
|
"last_activity": "MainActivity",
|
||||||
|
"sender_cast_active": false,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": false,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260502_045708.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Realme",
|
||||||
|
"brand": "realme",
|
||||||
|
"model": "Pad 2",
|
||||||
|
"device": "RMX2201",
|
||||||
|
"product": "RMX2201",
|
||||||
|
"sdk_int": 33,
|
||||||
|
"release": "13",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.0",
|
||||||
|
"version_code": 100
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "deadbeef"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"thread": "UdpSender-1",
|
||||||
|
"exception": "java.net.SocketTimeoutException",
|
||||||
|
"message": "connect timed out",
|
||||||
|
"stack_frames": [
|
||||||
|
"at com.foxx.androidcast.network.udp.UdpCastTransport.send(UdpCastTransport.java:142)",
|
||||||
|
"at com.foxx.androidcast.sender.ScreenCastService.flushStats(ScreenCastService.java:455)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_001.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_001.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "c526b61e-820c-5254-992c-cd4766f555ca",
|
||||||
|
"generated_at_epoch_ms": 1777637950372,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_121910.json",
|
||||||
|
"fingerprint": "nat_fpe_swr03",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777636032824,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260501_121910.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Xiaomi",
|
||||||
|
"brand": "Xiaomi",
|
||||||
|
"model": "Redmi Pad SE",
|
||||||
|
"device": "xun",
|
||||||
|
"product": "xun",
|
||||||
|
"sdk_int": 33,
|
||||||
|
"release": "13",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.2.0-dev",
|
||||||
|
"version_code": 120
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "a1b2c3d4"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGFPE",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 0006b2c4 /vendor/lib64/libswresample.so (resample_internal+196)",
|
||||||
|
"#01 pc 0004a018 /data/app/.../lib/arm64/libandroidcast_audio.so (AudioResampler::convert+80)",
|
||||||
|
"#02 pc 0001ac44 /data/app/.../lib/arm64/libandroidcast_jni.so (native_audio_tick+36)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_002.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_002.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "72952232-109d-588b-a520-662591ba485b",
|
||||||
|
"generated_at_epoch_ms": 1777639901368,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_125141.json",
|
||||||
|
"fingerprint": "e5f6a01b02c03d04nat",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777638604183,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260501_125141.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Amazon",
|
||||||
|
"brand": "Amazon",
|
||||||
|
"model": "Fire HD 10",
|
||||||
|
"device": "trona",
|
||||||
|
"product": "trona",
|
||||||
|
"sdk_int": 30,
|
||||||
|
"release": "11",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.0",
|
||||||
|
"version_code": 100
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "deadbeef"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGSEGV",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 00012ab4 /data/app/.../lib/arm64/libandroidcast_crash_hook.so (crash_hook_backtrace+64)",
|
||||||
|
"#01 pc 0003f210 /data/app/.../lib/arm64/libandroidcast_jni.so (Java_com_foxx_androidcast_native_CrashHook_notify+28)",
|
||||||
|
"#02 pc 00021c44 /system/lib64/libart.so (art_quick_generic_jni_trampoline+148)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_003.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_003.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "aa4956be-2153-50c5-85ce-981c4acaf4a1",
|
||||||
|
"generated_at_epoch_ms": 1777642392539,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_133312.json",
|
||||||
|
"fingerprint": "nat_bus_frb02",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777639939868,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260501_133312.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Honor",
|
||||||
|
"brand": "HONOR",
|
||||||
|
"model": "Pad X8a",
|
||||||
|
"device": "HEY2",
|
||||||
|
"product": "HEY2",
|
||||||
|
"sdk_int": 34,
|
||||||
|
"release": "14",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.1",
|
||||||
|
"version_code": 101
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "cafebabe"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGBUS",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 0000c210 /data/app/.../lib/arm64/libandroidcast_capture.so (FrameRingBuffer::slot_at+28)",
|
||||||
|
"#01 pc 0000d884 /data/app/.../lib/arm64/libandroidcast_capture.so (FrameRingBuffer::push_copy+112)",
|
||||||
|
"#02 pc 0002f1a0 /data/app/.../lib/arm64/libandroidcast_jni.so (native_on_frame+64)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_004.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_004.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "76bd7725-4c33-5e86-95bd-d0e864788736",
|
||||||
|
"generated_at_epoch_ms": 1777644518166,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_140838.json",
|
||||||
|
"fingerprint": "nat_ill_insn06",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777641260785,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260501_140838.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Oppo",
|
||||||
|
"brand": "OPPO",
|
||||||
|
"model": "Pad Neo",
|
||||||
|
"device": "OPD2301",
|
||||||
|
"product": "OPD2301",
|
||||||
|
"sdk_int": 33,
|
||||||
|
"release": "13",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.1",
|
||||||
|
"version_code": 101
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "cafebabe"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGILL",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 00004580 /data/app/.../lib/arm64/libh264_neon.so (neon_idct_invalid+8)",
|
||||||
|
"#01 pc 00012f40 /data/app/.../lib/arm64/libandroidcast_encoder.so (H264Encoder::decode_slice+128)",
|
||||||
|
"#02 pc 00008c00 /data/app/.../lib/arm64/libandroidcast_jni.so (encoder_worker+200)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_005.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_005.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "5f9bd6e4-41ba-5791-92fd-fc1405490a3b",
|
||||||
|
"generated_at_epoch_ms": 1777646268225,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_143748.json",
|
||||||
|
"fingerprint": "nat_fpe_swr03",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777645932614,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260501_143748.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Lenovo",
|
||||||
|
"brand": "Lenovo",
|
||||||
|
"model": "Tab P12",
|
||||||
|
"device": "TB370FU",
|
||||||
|
"product": "TB370FU",
|
||||||
|
"sdk_int": 34,
|
||||||
|
"release": "14",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.0",
|
||||||
|
"version_code": 100
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "deadbeef"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGFPE",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 0006b2c4 /vendor/lib64/libswresample.so (resample_internal+196)",
|
||||||
|
"#01 pc 0004a018 /data/app/.../lib/arm64/libandroidcast_audio.so (AudioResampler::convert+80)",
|
||||||
|
"#02 pc 0001ac44 /data/app/.../lib/arm64/libandroidcast_jni.so (native_audio_tick+36)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_006.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_006.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "6cfc9c6e-8b4d-5d49-bcc2-66fcf02b1716",
|
||||||
|
"generated_at_epoch_ms": 1777648880741,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "app_runtime",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_152120.json",
|
||||||
|
"fingerprint": "nat_abort01",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777648347993,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": false,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": false,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260501_152120.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Xiaomi",
|
||||||
|
"brand": "Xiaomi",
|
||||||
|
"model": "Redmi Pad SE",
|
||||||
|
"device": "xun",
|
||||||
|
"product": "xun",
|
||||||
|
"sdk_int": 33,
|
||||||
|
"release": "13",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.1",
|
||||||
|
"version_code": 101
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "cafebabe"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGABRT",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 0008c4bc /apex/com.android.runtime/lib64/bionic/libc.so (abort+164)",
|
||||||
|
"#01 pc 00005120 /data/app/.../lib/arm64/libandroidcast_crash_hook.so (crash_hook_abort+48)",
|
||||||
|
"#02 pc 0003a8f0 /data/app/.../lib/arm64/libandroidcast_jni.so (jni_fatal_callback+20)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_007.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_007.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "556fa879-3b4a-5685-9dfb-ab4c35cd8d72",
|
||||||
|
"generated_at_epoch_ms": 1777649186965,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": ":crashwatcher",
|
||||||
|
"report_file": "crash_20260501_152626.json",
|
||||||
|
"fingerprint": "nat_trap_jni05",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777646381894,
|
||||||
|
"last_activity": "MainActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260501_152626.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Motorola",
|
||||||
|
"brand": "motorola",
|
||||||
|
"model": "Tab G70",
|
||||||
|
"device": "scout",
|
||||||
|
"product": "scout",
|
||||||
|
"sdk_int": 33,
|
||||||
|
"release": "13",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.2.0-dev",
|
||||||
|
"version_code": 120
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "a1b2c3d4"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGTRAP",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 00002d10 /data/app/.../lib/arm64/libandroidcast_crash_hook.so (debug_trap_handler+16)",
|
||||||
|
"#01 pc 00019c80 /system/lib64/libart.so (art::Thread::DumpStack+320)",
|
||||||
|
"#02 pc 0000e4a8 /data/app/.../lib/arm64/libandroidcast_jni.so (CrashHook::selfTest+24)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_008.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_008.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "17f5426b-0c1c-555d-8655-a1219afbee42",
|
||||||
|
"generated_at_epoch_ms": 1777651861776,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_161101.json",
|
||||||
|
"fingerprint": "nat_fpe_swr03",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777650609201,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260501_161101.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "OnePlus",
|
||||||
|
"brand": "OnePlus",
|
||||||
|
"model": "Pad Go",
|
||||||
|
"device": "OPD2303",
|
||||||
|
"product": "OPD2303",
|
||||||
|
"sdk_int": 33,
|
||||||
|
"release": "13",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.0",
|
||||||
|
"version_code": 100
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "deadbeef"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGFPE",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 0006b2c4 /vendor/lib64/libswresample.so (resample_internal+196)",
|
||||||
|
"#01 pc 0004a018 /data/app/.../lib/arm64/libandroidcast_audio.so (AudioResampler::convert+80)",
|
||||||
|
"#02 pc 0001ac44 /data/app/.../lib/arm64/libandroidcast_jni.so (native_audio_tick+36)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_009.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_009.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "b03ab2b4-7488-558d-a50a-f0bc90d5ff56",
|
||||||
|
"generated_at_epoch_ms": 1777651475761,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_160435.json",
|
||||||
|
"fingerprint": "nat_stfg_omx01",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777649872633,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260501_160435.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Vivo",
|
||||||
|
"brand": "vivo",
|
||||||
|
"model": "Pad Air",
|
||||||
|
"device": "PA2353",
|
||||||
|
"product": "PA2353",
|
||||||
|
"sdk_int": 34,
|
||||||
|
"release": "14",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.1",
|
||||||
|
"version_code": 101
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "cafebabe"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGSEGV",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 000a4120 /system/lib64/libstagefright.so (android::MediaCodec::onMessageReceived+312)",
|
||||||
|
"#01 pc 0004e8c4 /system/lib64/libhidlbase.so (android::hardware::media::omx::V1_0::IOmxNode::dispatchMessage+68)",
|
||||||
|
"#02 pc 0001d330 /data/app/.../lib/arm64/libandroidcast_encoder.so (AvcEncoder::drainNAL+44)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_010.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_010.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "6b948858-84a5-518f-8286-2f7e14b96274",
|
||||||
|
"generated_at_epoch_ms": 1777653157299,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_163237.json",
|
||||||
|
"fingerprint": "nat_abort01",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777651309087,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260501_163237.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Samsung",
|
||||||
|
"brand": "samsung",
|
||||||
|
"model": "Galaxy Tab A9+",
|
||||||
|
"device": "gta9pwifi",
|
||||||
|
"product": "gta9pwifi",
|
||||||
|
"sdk_int": 34,
|
||||||
|
"release": "14",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.2.0-dev",
|
||||||
|
"version_code": 120
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "a1b2c3d4"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGABRT",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 0008c4bc /apex/com.android.runtime/lib64/bionic/libc.so (abort+164)",
|
||||||
|
"#01 pc 00005120 /data/app/.../lib/arm64/libandroidcast_crash_hook.so (crash_hook_abort+48)",
|
||||||
|
"#02 pc 0003a8f0 /data/app/.../lib/arm64/libandroidcast_jni.so (jni_fatal_callback+20)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_011.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_011.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "10fcd204-f8c5-5ba2-85a3-be27922d979a",
|
||||||
|
"generated_at_epoch_ms": 1777654532940,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_165532.json",
|
||||||
|
"fingerprint": "nat_fpe_swr03",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777652755681,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260501_165532.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Huawei",
|
||||||
|
"brand": "HUAWEI",
|
||||||
|
"model": "MatePad 11",
|
||||||
|
"device": "BAH3",
|
||||||
|
"product": "BAH3",
|
||||||
|
"sdk_int": 31,
|
||||||
|
"release": "12",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.1",
|
||||||
|
"version_code": 101
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "cafebabe"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGFPE",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 0006b2c4 /vendor/lib64/libswresample.so (resample_internal+196)",
|
||||||
|
"#01 pc 0004a018 /data/app/.../lib/arm64/libandroidcast_audio.so (AudioResampler::convert+80)",
|
||||||
|
"#02 pc 0001ac44 /data/app/.../lib/arm64/libandroidcast_jni.so (native_audio_tick+36)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_012.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_012.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "ddc19d03-1386-5463-ab42-d121149515ef",
|
||||||
|
"generated_at_epoch_ms": 1777658169535,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_175609.json",
|
||||||
|
"fingerprint": "nat_fpe_swr03",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777654789261,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260501_175609.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Acer",
|
||||||
|
"brand": "Acer",
|
||||||
|
"model": "Iconia Tab P10",
|
||||||
|
"device": "acer_p10",
|
||||||
|
"product": "acer_p10",
|
||||||
|
"sdk_int": 31,
|
||||||
|
"release": "12",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.2.0-dev",
|
||||||
|
"version_code": 120
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "a1b2c3d4"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGFPE",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 0006b2c4 /vendor/lib64/libswresample.so (resample_internal+196)",
|
||||||
|
"#01 pc 0004a018 /data/app/.../lib/arm64/libandroidcast_audio.so (AudioResampler::convert+80)",
|
||||||
|
"#02 pc 0001ac44 /data/app/.../lib/arm64/libandroidcast_jni.so (native_audio_tick+36)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_013.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_013.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "825f1bb7-2ce1-584e-aed0-998a788a9c70",
|
||||||
|
"generated_at_epoch_ms": 1777660865516,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_184105.json",
|
||||||
|
"fingerprint": "e5f6a01b02c03d04nat",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777658753664,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260501_184105.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Xiaomi",
|
||||||
|
"brand": "Xiaomi",
|
||||||
|
"model": "Redmi Pad SE",
|
||||||
|
"device": "xun",
|
||||||
|
"product": "xun",
|
||||||
|
"sdk_int": 33,
|
||||||
|
"release": "13",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.2.0-dev",
|
||||||
|
"version_code": 120
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "a1b2c3d4"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGSEGV",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 00012ab4 /data/app/.../lib/arm64/libandroidcast_crash_hook.so (crash_hook_backtrace+64)",
|
||||||
|
"#01 pc 0003f210 /data/app/.../lib/arm64/libandroidcast_jni.so (Java_com_foxx_androidcast_native_CrashHook_notify+28)",
|
||||||
|
"#02 pc 00021c44 /system/lib64/libart.so (art_quick_generic_jni_trampoline+148)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_014.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_014.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "b822f590-a767-5daa-b7cf-922cc55a8e2e",
|
||||||
|
"generated_at_epoch_ms": 1777662111621,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_190151.json",
|
||||||
|
"fingerprint": "nat_stfg_omx01",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777660533523,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260501_190151.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Google",
|
||||||
|
"brand": "google",
|
||||||
|
"model": "Pixel Tablet",
|
||||||
|
"device": "tangorpro",
|
||||||
|
"product": "tangorpro",
|
||||||
|
"sdk_int": 34,
|
||||||
|
"release": "14",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.1",
|
||||||
|
"version_code": 101
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "cafebabe"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGSEGV",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 000a4120 /system/lib64/libstagefright.so (android::MediaCodec::onMessageReceived+312)",
|
||||||
|
"#01 pc 0004e8c4 /system/lib64/libhidlbase.so (android::hardware::media::omx::V1_0::IOmxNode::dispatchMessage+68)",
|
||||||
|
"#02 pc 0001d330 /data/app/.../lib/arm64/libandroidcast_encoder.so (AvcEncoder::drainNAL+44)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_015.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_015.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "a2e8b6a8-99c8-5748-bd6f-b00f0a2bb2ec",
|
||||||
|
"generated_at_epoch_ms": 1777664275146,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_193755.json",
|
||||||
|
"fingerprint": "nat_bus_frb02",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777663387589,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260501_193755.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Oppo",
|
||||||
|
"brand": "OPPO",
|
||||||
|
"model": "Pad Neo",
|
||||||
|
"device": "OPD2301",
|
||||||
|
"product": "OPD2301",
|
||||||
|
"sdk_int": 33,
|
||||||
|
"release": "13",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.0",
|
||||||
|
"version_code": 100
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "deadbeef"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGBUS",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 0000c210 /data/app/.../lib/arm64/libandroidcast_capture.so (FrameRingBuffer::slot_at+28)",
|
||||||
|
"#01 pc 0000d884 /data/app/.../lib/arm64/libandroidcast_capture.so (FrameRingBuffer::push_copy+112)",
|
||||||
|
"#02 pc 0002f1a0 /data/app/.../lib/arm64/libandroidcast_jni.so (native_on_frame+64)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_016.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_016.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "d3089352-3954-5b40-ae17-e9305c8040af",
|
||||||
|
"generated_at_epoch_ms": 1777665414119,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_195654.json",
|
||||||
|
"fingerprint": "e5f6a01b02c03d04nat",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777662872545,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260501_195654.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Google",
|
||||||
|
"brand": "google",
|
||||||
|
"model": "Pixel Tablet",
|
||||||
|
"device": "tangorpro",
|
||||||
|
"product": "tangorpro",
|
||||||
|
"sdk_int": 34,
|
||||||
|
"release": "14",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.2.0-dev",
|
||||||
|
"version_code": 120
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "a1b2c3d4"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGSEGV",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 00012ab4 /data/app/.../lib/arm64/libandroidcast_crash_hook.so (crash_hook_backtrace+64)",
|
||||||
|
"#01 pc 0003f210 /data/app/.../lib/arm64/libandroidcast_jni.so (Java_com_foxx_androidcast_native_CrashHook_notify+28)",
|
||||||
|
"#02 pc 00021c44 /system/lib64/libart.so (art_quick_generic_jni_trampoline+148)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_017.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_017.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "c496da41-05ed-583b-9fc3-3b9f89b98275",
|
||||||
|
"generated_at_epoch_ms": 1777665065168,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": ":crashwatcher",
|
||||||
|
"report_file": "crash_20260501_195105.json",
|
||||||
|
"fingerprint": "e5f6a01b02c03d04nat",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777663543751,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260501_195105.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Motorola",
|
||||||
|
"brand": "motorola",
|
||||||
|
"model": "Tab G70",
|
||||||
|
"device": "scout",
|
||||||
|
"product": "scout",
|
||||||
|
"sdk_int": 33,
|
||||||
|
"release": "13",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.2.0-dev",
|
||||||
|
"version_code": 120
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "a1b2c3d4"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGSEGV",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 00008f20 /data/app/.../lib/arm64/libandroidcast_crash_hook.so (unwind_stub+32)",
|
||||||
|
"#01 pc 00011a04 /data/app/.../lib/arm64/libandroidcast_crash_hook.so (native_stub_write+96)",
|
||||||
|
"#02 pc 0002bc10 /apex/com.android.runtime/lib64/bionic/libc.so (__restore_rt)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_018.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_018.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "65038fa7-0791-5e19-8d80-2e489cc3b066",
|
||||||
|
"generated_at_epoch_ms": 1777668938569,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "app_runtime",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_205538.json",
|
||||||
|
"fingerprint": "nat_abort01",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777666345594,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": false,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": false,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260501_205538.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Amazon",
|
||||||
|
"brand": "Amazon",
|
||||||
|
"model": "Fire HD 10",
|
||||||
|
"device": "trona",
|
||||||
|
"product": "trona",
|
||||||
|
"sdk_int": 30,
|
||||||
|
"release": "11",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.1",
|
||||||
|
"version_code": 101
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "cafebabe"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGABRT",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 0008c4bc /apex/com.android.runtime/lib64/bionic/libc.so (abort+164)",
|
||||||
|
"#01 pc 00005120 /data/app/.../lib/arm64/libandroidcast_crash_hook.so (crash_hook_abort+48)",
|
||||||
|
"#02 pc 0003a8f0 /data/app/.../lib/arm64/libandroidcast_jni.so (jni_fatal_callback+20)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_019.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_019.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "43f0eaf8-e2ba-5354-9299-ea1797ecd1e7",
|
||||||
|
"generated_at_epoch_ms": 1777668794830,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_205314.json",
|
||||||
|
"fingerprint": "nat_fpe_swr03",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777666232562,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260501_205314.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Nokia",
|
||||||
|
"brand": "HMD Global",
|
||||||
|
"model": "T21",
|
||||||
|
"device": "RON",
|
||||||
|
"product": "RON",
|
||||||
|
"sdk_int": 33,
|
||||||
|
"release": "13",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.2.0-dev",
|
||||||
|
"version_code": 120
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "a1b2c3d4"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGFPE",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 0006b2c4 /vendor/lib64/libswresample.so (resample_internal+196)",
|
||||||
|
"#01 pc 0004a018 /data/app/.../lib/arm64/libandroidcast_audio.so (AudioResampler::convert+80)",
|
||||||
|
"#02 pc 0001ac44 /data/app/.../lib/arm64/libandroidcast_jni.so (native_audio_tick+36)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_020.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_020.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "5f2db805-2741-5055-8655-98c4b76968d7",
|
||||||
|
"generated_at_epoch_ms": 1777669941654,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": ":crashwatcher",
|
||||||
|
"report_file": "crash_20260501_211221.json",
|
||||||
|
"fingerprint": "nat_trap_jni05",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777666607883,
|
||||||
|
"last_activity": "MainActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260501_211221.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Amazon",
|
||||||
|
"brand": "Amazon",
|
||||||
|
"model": "Fire HD 10",
|
||||||
|
"device": "trona",
|
||||||
|
"product": "trona",
|
||||||
|
"sdk_int": 30,
|
||||||
|
"release": "11",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.0",
|
||||||
|
"version_code": 100
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "deadbeef"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGTRAP",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 00002d10 /data/app/.../lib/arm64/libandroidcast_crash_hook.so (debug_trap_handler+16)",
|
||||||
|
"#01 pc 00019c80 /system/lib64/libart.so (art::Thread::DumpStack+320)",
|
||||||
|
"#02 pc 0000e4a8 /data/app/.../lib/arm64/libandroidcast_jni.so (CrashHook::selfTest+24)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_021.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_021.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "cda272d4-c971-5663-a773-93204367cfb6",
|
||||||
|
"generated_at_epoch_ms": 1777673060868,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "app_runtime",
|
||||||
|
"process": ":crashwatcher",
|
||||||
|
"report_file": "crash_20260501_220420.json",
|
||||||
|
"fingerprint": "nat_trap_jni05",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777671317090,
|
||||||
|
"last_activity": "MainActivity",
|
||||||
|
"sender_cast_active": false,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": false,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260501_220420.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Asus",
|
||||||
|
"brand": "asus",
|
||||||
|
"model": "ZenPad 10",
|
||||||
|
"device": "P00C",
|
||||||
|
"product": "P00C",
|
||||||
|
"sdk_int": 29,
|
||||||
|
"release": "10",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.1",
|
||||||
|
"version_code": 101
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "cafebabe"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGTRAP",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 00002d10 /data/app/.../lib/arm64/libandroidcast_crash_hook.so (debug_trap_handler+16)",
|
||||||
|
"#01 pc 00019c80 /system/lib64/libart.so (art::Thread::DumpStack+320)",
|
||||||
|
"#02 pc 0000e4a8 /data/app/.../lib/arm64/libandroidcast_jni.so (CrashHook::selfTest+24)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_022.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_022.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "57db3ba8-967d-5b5c-9c1f-817818bb2746",
|
||||||
|
"generated_at_epoch_ms": 1777675665245,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_224745.json",
|
||||||
|
"fingerprint": "nat_abort01",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777673525589,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260501_224745.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Motorola",
|
||||||
|
"brand": "motorola",
|
||||||
|
"model": "Tab G70",
|
||||||
|
"device": "scout",
|
||||||
|
"product": "scout",
|
||||||
|
"sdk_int": 33,
|
||||||
|
"release": "13",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.0",
|
||||||
|
"version_code": 100
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "deadbeef"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGABRT",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 0008c4bc /apex/com.android.runtime/lib64/bionic/libc.so (abort+164)",
|
||||||
|
"#01 pc 00005120 /data/app/.../lib/arm64/libandroidcast_crash_hook.so (crash_hook_abort+48)",
|
||||||
|
"#02 pc 0003a8f0 /data/app/.../lib/arm64/libandroidcast_jni.so (jni_fatal_callback+20)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_023.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_023.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "68146db0-7eef-525c-b766-09018be3373b",
|
||||||
|
"generated_at_epoch_ms": 1777676969621,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260501_230929.json",
|
||||||
|
"fingerprint": "e5f6a01b02c03d04nat",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777673914387,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260501_230929.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Asus",
|
||||||
|
"brand": "asus",
|
||||||
|
"model": "ZenPad 10",
|
||||||
|
"device": "P00C",
|
||||||
|
"product": "P00C",
|
||||||
|
"sdk_int": 29,
|
||||||
|
"release": "10",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.1",
|
||||||
|
"version_code": 101
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "cafebabe"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGSEGV",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 00012ab4 /data/app/.../lib/arm64/libandroidcast_crash_hook.so (crash_hook_backtrace+64)",
|
||||||
|
"#01 pc 0003f210 /data/app/.../lib/arm64/libandroidcast_jni.so (Java_com_foxx_androidcast_native_CrashHook_notify+28)",
|
||||||
|
"#02 pc 00021c44 /system/lib64/libart.so (art_quick_generic_jni_trampoline+148)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_024.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_024.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "314c59be-c63a-5fbb-b24a-23e9275ccc7e",
|
||||||
|
"generated_at_epoch_ms": 1777678301197,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": ":crashwatcher",
|
||||||
|
"report_file": "crash_20260501_233141.json",
|
||||||
|
"fingerprint": "e5f6a01b02c03d04nat",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777676865364,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260501_233141.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "OnePlus",
|
||||||
|
"brand": "OnePlus",
|
||||||
|
"model": "Pad Go",
|
||||||
|
"device": "OPD2303",
|
||||||
|
"product": "OPD2303",
|
||||||
|
"sdk_int": 33,
|
||||||
|
"release": "13",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.1",
|
||||||
|
"version_code": 101
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "cafebabe"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGSEGV",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 00008f20 /data/app/.../lib/arm64/libandroidcast_crash_hook.so (unwind_stub+32)",
|
||||||
|
"#01 pc 00011a04 /data/app/.../lib/arm64/libandroidcast_crash_hook.so (native_stub_write+96)",
|
||||||
|
"#02 pc 0002bc10 /apex/com.android.runtime/lib64/bionic/libc.so (__restore_rt)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_025.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_025.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "159c7878-a641-5d95-8751-7462e861477d",
|
||||||
|
"generated_at_epoch_ms": 1777680848900,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260502_001408.json",
|
||||||
|
"fingerprint": "nat_bus_frb02",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777677570321,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260502_001408.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "TCL",
|
||||||
|
"brand": "TCL",
|
||||||
|
"model": "Tab 10 Gen2",
|
||||||
|
"device": "9081G",
|
||||||
|
"product": "9081G",
|
||||||
|
"sdk_int": 31,
|
||||||
|
"release": "12",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.0",
|
||||||
|
"version_code": 100
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "deadbeef"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGBUS",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 0000c210 /data/app/.../lib/arm64/libandroidcast_capture.so (FrameRingBuffer::slot_at+28)",
|
||||||
|
"#01 pc 0000d884 /data/app/.../lib/arm64/libandroidcast_capture.so (FrameRingBuffer::push_copy+112)",
|
||||||
|
"#02 pc 0002f1a0 /data/app/.../lib/arm64/libandroidcast_jni.so (native_on_frame+64)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_026.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_026.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "9f7265e7-4639-5784-9a53-9f3b22b1f8ca",
|
||||||
|
"generated_at_epoch_ms": 1777683021539,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260502_005021.json",
|
||||||
|
"fingerprint": "nat_bus_frb02",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777681133749,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260502_005021.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Realme",
|
||||||
|
"brand": "realme",
|
||||||
|
"model": "Pad 2",
|
||||||
|
"device": "RMX2201",
|
||||||
|
"product": "RMX2201",
|
||||||
|
"sdk_int": 33,
|
||||||
|
"release": "13",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.0",
|
||||||
|
"version_code": 100
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "deadbeef"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGBUS",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 0000c210 /data/app/.../lib/arm64/libandroidcast_capture.so (FrameRingBuffer::slot_at+28)",
|
||||||
|
"#01 pc 0000d884 /data/app/.../lib/arm64/libandroidcast_capture.so (FrameRingBuffer::push_copy+112)",
|
||||||
|
"#02 pc 0002f1a0 /data/app/.../lib/arm64/libandroidcast_jni.so (native_on_frame+64)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_027.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_027.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "cf206696-9e1e-5400-9df5-63a912e1a886",
|
||||||
|
"generated_at_epoch_ms": 1777682272559,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260502_003752.json",
|
||||||
|
"fingerprint": "nat_bus_frb02",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777679114435,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260502_003752.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Oppo",
|
||||||
|
"brand": "OPPO",
|
||||||
|
"model": "Pad Neo",
|
||||||
|
"device": "OPD2301",
|
||||||
|
"product": "OPD2301",
|
||||||
|
"sdk_int": 33,
|
||||||
|
"release": "13",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.2.0-dev",
|
||||||
|
"version_code": 120
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "a1b2c3d4"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGBUS",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 0000c210 /data/app/.../lib/arm64/libandroidcast_capture.so (FrameRingBuffer::slot_at+28)",
|
||||||
|
"#01 pc 0000d884 /data/app/.../lib/arm64/libandroidcast_capture.so (FrameRingBuffer::push_copy+112)",
|
||||||
|
"#02 pc 0002f1a0 /data/app/.../lib/arm64/libandroidcast_jni.so (native_on_frame+64)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_028.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_028.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "e6e264d0-e701-51a8-a220-9a3bcb2e59dd",
|
||||||
|
"generated_at_epoch_ms": 1777687156463,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260502_015916.json",
|
||||||
|
"fingerprint": "nat_stfg_omx01",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777685716746,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260502_015916.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "OnePlus",
|
||||||
|
"brand": "OnePlus",
|
||||||
|
"model": "Pad Go",
|
||||||
|
"device": "OPD2303",
|
||||||
|
"product": "OPD2303",
|
||||||
|
"sdk_int": 33,
|
||||||
|
"release": "13",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.1",
|
||||||
|
"version_code": 101
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": true,
|
||||||
|
"git_commit": "cafebabe"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGSEGV",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 000a4120 /system/lib64/libstagefright.so (android::MediaCodec::onMessageReceived+312)",
|
||||||
|
"#01 pc 0004e8c4 /system/lib64/libhidlbase.so (android::hardware::media::omx::V1_0::IOmxNode::dispatchMessage+68)",
|
||||||
|
"#02 pc 0001d330 /data/app/.../lib/arm64/libandroidcast_encoder.so (AvcEncoder::drainNAL+44)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_029.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_029.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "b3b37e98-a05b-58de-a6f1-80c7b1b3eec1",
|
||||||
|
"generated_at_epoch_ms": 1777685947705,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260502_013907.json",
|
||||||
|
"fingerprint": "nat_ill_insn06",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777683221308,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": true,
|
||||||
|
"last_session_file": "session_send_20260502_013907.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "Acer",
|
||||||
|
"brand": "Acer",
|
||||||
|
"model": "Iconia Tab P10",
|
||||||
|
"device": "acer_p10",
|
||||||
|
"product": "acer_p10",
|
||||||
|
"sdk_int": 31,
|
||||||
|
"release": "12",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.0",
|
||||||
|
"version_code": 100
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "deadbeef"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGILL",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 00004580 /data/app/.../lib/arm64/libh264_neon.so (neon_idct_invalid+8)",
|
||||||
|
"#01 pc 00012f40 /data/app/.../lib/arm64/libandroidcast_encoder.so (H264Encoder::decode_slice+128)",
|
||||||
|
"#02 pc 00008c00 /data/app/.../lib/arm64/libandroidcast_jni.so (encoder_worker+200)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
examples/crash_reporter/test_reports/crash_native_030.json
Normal file
49
examples/crash_reporter/test_reports/crash_native_030.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"report_id": "47e5cfc9-d568-5177-8db2-0c12a52d70aa",
|
||||||
|
"generated_at_epoch_ms": 1777690239513,
|
||||||
|
"crash_type": "native",
|
||||||
|
"scenario": "cast_session",
|
||||||
|
"process": "main",
|
||||||
|
"report_file": "crash_20260502_025039.json",
|
||||||
|
"fingerprint": "nat_abort01",
|
||||||
|
"runtime_context": {
|
||||||
|
"app_started_epoch_ms": 1777690003074,
|
||||||
|
"last_activity": "ScreenCastActivity",
|
||||||
|
"sender_cast_active": true,
|
||||||
|
"receiver_cast_active": false,
|
||||||
|
"cast_active": true,
|
||||||
|
"session_stats_active": false,
|
||||||
|
"last_session_file": "session_send_20260502_025039.json"
|
||||||
|
},
|
||||||
|
"device": {
|
||||||
|
"manufacturer": "TCL",
|
||||||
|
"brand": "TCL",
|
||||||
|
"model": "Tab 10 Gen2",
|
||||||
|
"device": "9081G",
|
||||||
|
"product": "9081G",
|
||||||
|
"sdk_int": 31,
|
||||||
|
"release": "12",
|
||||||
|
"abis": [
|
||||||
|
"arm64-v8a",
|
||||||
|
"armeabi-v7a"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"package": "com.foxx.androidcast",
|
||||||
|
"version_name": "0.1.1",
|
||||||
|
"version_code": 101
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"debug": false,
|
||||||
|
"git_commit": "cafebabe"
|
||||||
|
},
|
||||||
|
"native": {
|
||||||
|
"signal": "SIGABRT",
|
||||||
|
"backtrace": [
|
||||||
|
"#00 pc 0008c4bc /apex/com.android.runtime/lib64/bionic/libc.so (abort+164)",
|
||||||
|
"#01 pc 00005120 /data/app/.../lib/arm64/libandroidcast_crash_hook.so (crash_hook_abort+48)",
|
||||||
|
"#02 pc 0003a8f0 /data/app/.../lib/arm64/libandroidcast_jni.so (jni_fatal_callback+20)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user