1
0
mirror of git://f0xx.org/android_cast synced 2026-07-29 06:18:42 +03:00

snap, 20260522_late_night

This commit is contained in:
Anton Afanasyeu
2026-05-22 21:43:18 +02:00
parent ab355e0512
commit d008afca73
81 changed files with 4935 additions and 102 deletions

View File

@@ -26,6 +26,30 @@
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/ {
include fastcgi_params;
fastcgi_pass unix:/run/php-fpm.socket;

View 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);

View 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);
}

View 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);
}

View File

@@ -33,6 +33,7 @@ try {
json_out(['ok' => false, 'error' => 'duplicate report_id'], 409);
}
error_log('crash upload PDO: ' . $msg);
log_crash_event('upload', 'PDO: ' . $msg);
$out = ['ok' => false, 'error' => 'store failed'];
if (cfg('debug')) {
$out['hint'] = $msg;
@@ -40,6 +41,7 @@ try {
json_out($out, 500);
} catch (Throwable $e) {
error_log('crash upload: ' . $e->getMessage());
log_crash_event('upload', $e->getMessage());
$out = ['ok' => false, 'error' => 'store failed'];
if (cfg('debug')) {
$out['hint'] = $e->getMessage();

View File

@@ -1,12 +1,30 @@
:root {
:root,
[data-theme="dark"] {
--bg: #0f1419;
--surface: #1a2332;
--surface2: #0a0e14;
--border: #2d3a4f;
--text: #e7ecf3;
--muted: #8b9cb3;
--accent: #3d8bfd;
--accent2: #5eead4;
--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; }
body {
@@ -331,10 +349,232 @@ a:hover { text-decoration: underline; }
.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 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; }
.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; }
.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; }
.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); }
.alert { background: rgba(248,113,113,.15); color: var(--danger); padding: 10px; border-radius: 8px; }

View File

@@ -1,10 +1,551 @@
document.addEventListener('DOMContentLoaded', () => {
const nav = document.getElementById('nav-pane');
const handle = document.getElementById('nav-handle');
if (!nav || !handle) return;
handle.addEventListener('click', () => {
const open = nav.classList.toggle('open');
handle.setAttribute('aria-expanded', open ? 'true' : 'false');
(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 handle = document.getElementById('nav-handle');
if (!nav || !handle) return;
handle.addEventListener('click', () => {
const open = nav.classList.toggle('open');
handle.setAttribute('aria-expanded', 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, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;');
}
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();
});
handle.setAttribute('aria-expanded', nav.classList.contains('open') ? 'true' : 'false');
});
})();

View File

@@ -25,6 +25,21 @@ if ($route === '/api/upload.php' || str_ends_with($route, '/api/upload.php')) {
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') {
Auth::logout();
header('Location: ' . $base . '/login');
@@ -60,11 +75,11 @@ if ($view === 'report' && isset($_GET['id'])) {
echo 'Not found';
exit;
}
ReportRepository::markViewed((int) $report['id'], (int) Auth::user()['id']);
$pageTitle = 'Report';
require __DIR__ . '/../views/layout.php';
exit;
}
$pageTitle = $view === 'home' ? 'Home' : 'Crash reports';
$reports = $view === 'reports' ? ReportRepository::listReports($grouped) : [];
require __DIR__ . '/../views/layout.php';

View File

@@ -17,7 +17,16 @@ CREATE TABLE IF NOT EXISTS reports (
received_at_ms INTEGER NOT NULL,
device_model 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);

View File

@@ -67,13 +67,56 @@ final class Database {
$stmt->execute([$table]);
return $stmt->fetchColumn() === false;
};
if (!$need('users') && !$need('reports')) {
if (!$need('users') && !$need('reports') && self::reportsSchemaOk($pdo)) {
self::ensureReportColumns($pdo);
self::ensureReportViewsTable($pdo);
return;
}
$schemaFile = __DIR__ . '/../sql/schema.sqlite.sql';
if (!is_readable($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));
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;
}
}

View File

@@ -1,25 +1,37 @@
<?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);
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 {
$pdo = Database::pdo();
$device = $payload['device'] ?? [];
$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(
'INSERT INTO reports (report_id, fingerprint, crash_type, generated_at_ms, received_at_ms, device_model, app_version, payload_json)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)'
'INSERT INTO reports (report_id, fingerprint, crash_type, generated_at_ms, received_at_ms,
device_model, app_version, payload_json, tags_json)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)'
);
$stmt->execute([
$payload['report_id'] ?? uniqid('rpt_', true),
@@ -29,14 +41,36 @@ final class ReportRepository {
(int) round(microtime(true) * 1000),
$device['model'] ?? null,
$app['version_name'] ?? null,
json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
$json,
$tags ?: '[]',
]);
}
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();
$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) {
$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,
MAX(app_version) AS app_version,
COUNT(*) AS cnt,
@@ -44,25 +78,93 @@ final class ReportRepository {
MAX(received_at_ms) AS last_received_ms
FROM reports
GROUP BY fingerprint, crash_type
ORDER BY cnt DESC, last_generated_ms DESC';
return $pdo->query($sql)->fetchAll();
ORDER BY $sortCol $dir
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);
}
unset($row);
return [
'items' => $items,
'total' => $total,
'page' => $page,
'per_page' => $perPage,
'sort' => $sortCol,
'dir' => strtolower($dir),
'grouped' => true,
];
}
$sql = 'SELECT id, report_id, fingerprint, crash_type, generated_at_ms, received_at_ms, device_model, app_version
FROM reports
ORDER BY generated_at_ms DESC, received_at_ms DESC
LIMIT 500';
return $pdo->query($sql)->fetchAll();
$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 {
$pdo = Database::pdo();
$stmt = $pdo->prepare('SELECT * FROM reports WHERE id = ?');
$stmt->execute([$id]);
$userId = (int) (Auth::user()['id'] ?? 0);
$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();
if (!$row) {
return null;
}
$row['payload'] = json_decode($row['payload_json'], true);
$row['tags'] = parse_report_tags($row['tags_json'] ?? '[]');
$row['viewed'] = (bool) ($row['viewed'] ?? false);
return $row;
}
}

View File

@@ -59,3 +59,154 @@ function json_out(array $data, int $code = 200): void {
echo json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
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);
}

View File

@@ -12,16 +12,23 @@
*/
?>
<!DOCTYPE html>
<html lang="en">
<html lang="en" data-theme="dark">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<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">
<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>
</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>
<div class="shell">
<nav class="nav-pane" id="nav-pane" aria-label="Console navigation">
@@ -73,47 +80,40 @@
<?php elseif (($view ?? '') === 'report' && !empty($report)): ?>
<?php require __DIR__ . '/report_detail.php'; ?>
<?php elseif (($view ?? '') === 'reports'): ?>
<div class="toolbar">
<h1>Crash reports</h1>
<div class="toolbar-actions">
<a class="btn <?= empty($grouped) ? 'active' : '' ?>" href="<?= h(Auth::basePath()) ?>/?view=reports">By time</a>
<a class="btn <?= !empty($grouped) ? 'active' : '' ?>" href="<?= h(Auth::basePath()) ?>/?view=reports&amp;group=1">Grouped</a>
<div id="reports-app" class="reports-app" data-grouped="0">
<div class="toolbar reports-toolbar">
<h1>Crash reports</h1>
<div class="toolbar-actions">
<button type="button" class="btn reports-mode-btn active" data-grouped="0">By time</button>
<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>
<p id="reports-status" class="reports-status muted" aria-live="polite">Loading…</p>
<div class="reports-table-wrap">
<table class="data-table reports-tree" id="reports-tree">
<thead id="reports-thead"></thead>
<tbody id="reports-tbody"></tbody>
</table>
</div>
<nav class="reports-pagination" id="reports-pagination" aria-label="Reports pages"></nav>
</div>
<table class="data-table">
<thead>
<tr>
<?php if (!empty($grouped)): ?>
<th>Count</th><th>Fingerprint</th><th>Type</th><th>Last generated</th><th>Last received</th>
<?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&amp;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>
<?php endif; ?>
</main>
</div>

View File

@@ -1,39 +1,39 @@
<?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'] ?? [];
$device = $p['device'] ?? [];
$app = $p['app'] ?? [];
$pageTitle = 'Report ' . ($report['report_id'] ?? '');
$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>
<p class="muted">Report <?= h($report['report_id'] ?? '') ?> · <?= h($p['crash_type'] ?? '') ?></p>
<div class="cards">
<div class="card"><h3>Device</h3>
<div class="detail-header">
<a href="<?= h(Auth::basePath()) ?>/?view=reports" class="back-link" aria-label="Back to reports list" title="Back to list">
<span class="back-icon" aria-hidden="true"></span>
</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>Android <?= h($device['release'] ?? '') ?> (SDK <?= (int)($device['sdk_int'] ?? 0) ?>)</p>
<?php if (!empty($device['abis'])): ?>
<p class="muted">ABIs: <?= h(implode(', ', (array)$device['abis'])) ?></p>
<?php endif; ?>
</div>
<div class="card"><h3>App</h3>
<div class="card card--lift"><h3>App</h3>
<p><?= h($app['package'] ?? '') ?></p>
<p>v<?= h($app['version_name'] ?? '') ?> (<?= h((string)($app['version_code'] ?? '')) ?>)</p>
<?php if (!empty($p['build'])): $b = $p['build']; ?>
<p class="muted">Build: <?= h($b['git_commit'] ?? $b['git'] ?? '') ?></p>
<?php endif; ?>
</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>Received: <?= h(date('c', (int)(($report['received_at_ms'] ?? 0)/1000))) ?></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>
</section>
<?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>
<?php endif; ?>
<details><summary>Raw JSON</summary><pre class="raw-json stack"><?= h(json_encode($p, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES)) ?></pre></details>
<p><a href="<?= h(Auth::basePath()) ?>/?view=reports">← Back to list</a></p>
<div class="detail-tree" id="detail-tree">
<?php if ($sessionJson !== ''): ?>
<div class="detail-tree-item">
<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>

View 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()

View 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`).

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}

View 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)"
]
}
}