mirror of
git://f0xx.org/android_cast
synced 2026-07-29 04:18:09 +03:00
snap
This commit is contained in:
4
.githooks/post-commit
Executable file
4
.githooks/post-commit
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
ROOT="$(git rev-parse --show-toplevel)"
|
||||||
|
exec python3 "$ROOT/scripts/header-post-commit.py"
|
||||||
@@ -13,6 +13,8 @@ package com.foxx.androidcast.crash;
|
|||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import com.foxx.androidcast.util.IoUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
@@ -82,7 +84,7 @@ public final class CrashReportStore {
|
|||||||
|
|
||||||
public static JSONObject readJson(File file) {
|
public static JSONObject readJson(File file) {
|
||||||
try (FileInputStream fis = new FileInputStream(file)) {
|
try (FileInputStream fis = new FileInputStream(file)) {
|
||||||
return new JSONObject(new String(fis.readAllBytes(), StandardCharsets.UTF_8));
|
return new JSONObject(new String(IoUtils.readAllBytes(fis), StandardCharsets.UTF_8));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ import android.os.Build;
|
|||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.foxx.androidcast.util.IoUtils;
|
||||||
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -117,7 +119,7 @@ public final class CrashWatcherService extends Service {
|
|||||||
try {
|
try {
|
||||||
byte[] buf;
|
byte[] buf;
|
||||||
try (FileInputStream fis = new FileInputStream(stub)) {
|
try (FileInputStream fis = new FileInputStream(stub)) {
|
||||||
buf = fis.readAllBytes();
|
buf = IoUtils.readAllBytes(fis);
|
||||||
}
|
}
|
||||||
String text = new String(buf, StandardCharsets.UTF_8);
|
String text = new String(buf, StandardCharsets.UTF_8);
|
||||||
String signal = "UNKNOWN";
|
String signal = "UNKNOWN";
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ package com.foxx.androidcast.ota;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.foxx.androidcast.util.IoUtils;
|
||||||
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
@@ -81,7 +83,7 @@ public final class OtaBundleInstaller {
|
|||||||
File signFile = new File(extractDir, ENTRY_SIGN);
|
File signFile = new File(extractDir, ENTRY_SIGN);
|
||||||
if (signFile.isFile()) {
|
if (signFile.isFile()) {
|
||||||
try (FileInputStream fis = new FileInputStream(signFile)) {
|
try (FileInputStream fis = new FileInputStream(signFile)) {
|
||||||
byte[] buf = fis.readAllBytes();
|
byte[] buf = IoUtils.readAllBytes(fis);
|
||||||
OtaSignBundle sign = OtaSignBundle.fromJson(
|
OtaSignBundle sign = OtaSignBundle.fromJson(
|
||||||
new JSONObject(new String(buf, StandardCharsets.UTF_8)));
|
new JSONObject(new String(buf, StandardCharsets.UTF_8)));
|
||||||
expectedSha = sign.sha256Hex;
|
expectedSha = sign.sha256Hex;
|
||||||
|
|||||||
@@ -13,8 +13,9 @@ package com.foxx.androidcast.ota;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import com.foxx.androidcast.AppPreferences;
|
import com.foxx.androidcast.AppPreferences;
|
||||||
import com.foxx.androidcast.crash.CrashSettings;
|
|
||||||
import com.foxx.androidcast.BuildConfig;
|
import com.foxx.androidcast.BuildConfig;
|
||||||
|
import com.foxx.androidcast.crash.CrashSettings;
|
||||||
|
import com.foxx.androidcast.util.IoUtils;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
@@ -90,7 +91,7 @@ final class OtaSettingsStore {
|
|||||||
private static JSONObject readSettingsJson(Context context) {
|
private static JSONObject readSettingsJson(Context context) {
|
||||||
File f = new File(context.getFilesDir(), SETTINGS_FILE);
|
File f = new File(context.getFilesDir(), SETTINGS_FILE);
|
||||||
try (FileInputStream fis = new FileInputStream(f)) {
|
try (FileInputStream fis = new FileInputStream(f)) {
|
||||||
byte[] data = fis.readAllBytes();
|
byte[] data = IoUtils.readAllBytes(fis);
|
||||||
String text = new String(data, StandardCharsets.UTF_8);
|
String text = new String(data, StandardCharsets.UTF_8);
|
||||||
return new JSONObject(text);
|
return new JSONObject(text);
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ import android.content.Context;
|
|||||||
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import com.foxx.androidcast.util.IoUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
@@ -31,8 +33,8 @@ public final class AppSettingsJson {
|
|||||||
return new JSONObject();
|
return new JSONObject();
|
||||||
}
|
}
|
||||||
try (FileInputStream fis = new FileInputStream(f)) {
|
try (FileInputStream fis = new FileInputStream(f)) {
|
||||||
return new JSONObject(new String(fis.readAllBytes(), StandardCharsets.UTF_8));
|
return new JSONObject(new String(IoUtils.readAllBytes(fis), StandardCharsets.UTF_8));
|
||||||
} catch (Exception ignored) {
|
} catch (Throwable ignored) {
|
||||||
return new JSONObject();
|
return new JSONObject();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
36
app/src/main/java/com/foxx/androidcast/util/IoUtils.java
Normal file
36
app/src/main/java/com/foxx/androidcast/util/IoUtils.java
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package com.foxx.androidcast.util;
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* IoUtils.java
|
||||||
|
* Created at: Wed 20 May 2026 12:00:00 +0200
|
||||||
|
* Contributors:
|
||||||
|
* - Cursor Agent (project assistant)
|
||||||
|
**********************************************************************/
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/** Stream/file reads compatible with minSdk 29 (no {@code InputStream.readAllBytes()}). */
|
||||||
|
public final class IoUtils {
|
||||||
|
private static final int BUF_SIZE = 8192;
|
||||||
|
|
||||||
|
private IoUtils() {}
|
||||||
|
|
||||||
|
public static byte[] readAllBytes(InputStream in) throws IOException {
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
byte[] buf = new byte[BUF_SIZE];
|
||||||
|
int n;
|
||||||
|
while ((n = in.read(buf)) != -1) {
|
||||||
|
out.write(buf, 0, n);
|
||||||
|
}
|
||||||
|
return out.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] readAllBytes(File file) throws IOException {
|
||||||
|
try (FileInputStream fis = new FileInputStream(file)) {
|
||||||
|
return readAllBytes(fis);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,11 +5,37 @@ DEVICES_LIST="$(adb devices -l)"
|
|||||||
echo "${DEVICES_LIST}"
|
echo "${DEVICES_LIST}"
|
||||||
|
|
||||||
LOG_ROOT="log_capture/session_stats/"
|
LOG_ROOT="log_capture/session_stats/"
|
||||||
|
CRASH_ROOT="log_capture/crash_reports/"
|
||||||
CLEAN_LOGS="no"
|
CLEAN_LOGS="no"
|
||||||
|
|
||||||
|
pull_dir() {
|
||||||
|
local serial="$1"
|
||||||
|
local remote_subdir="$2"
|
||||||
|
local local_base="$3"
|
||||||
|
local local_path="${local_base}/${serial}/${remote_subdir}/"
|
||||||
|
|
||||||
|
mapfile -t FILES < <(adb -s "${serial}" shell run-as com.foxx.androidcast ls "files/${remote_subdir}/" </dev/null \
|
||||||
|
| tr -d '\r' | grep -v '^$' || true)
|
||||||
|
|
||||||
|
if ((${#FILES[@]} == 0)); then
|
||||||
|
echo " (no files in files/${remote_subdir}/ on ${serial})"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "${local_path}"
|
||||||
|
for f in "${FILES[@]}"; do
|
||||||
|
adb -s "${serial}" exec-out run-as com.foxx.androidcast cat "files/${remote_subdir}/${f}" </dev/null \
|
||||||
|
> "${local_path}/${f}"
|
||||||
|
if [[ "${CLEAN_LOGS}" == "yes" ]]; then
|
||||||
|
adb -s "${serial}" shell run-as com.foxx.androidcast rm -f "files/${remote_subdir}/${f}" </dev/null
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo " pulled ${#FILES[@]} file(s) -> ${local_path}"
|
||||||
|
}
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
yn=""
|
yn=""
|
||||||
read -rp "clean logs on device after fetch? [Y/n] " yn
|
read -rp "clean logs on device after fetch? [y/N] " yn
|
||||||
yn="${yn,,}"
|
yn="${yn,,}"
|
||||||
case "${yn}" in
|
case "${yn}" in
|
||||||
y|yes)
|
y|yes)
|
||||||
@@ -20,7 +46,7 @@ while true; do
|
|||||||
break
|
break
|
||||||
;;
|
;;
|
||||||
"")
|
"")
|
||||||
CLEAN_LOGS="yes"
|
CLEAN_LOGS="no"
|
||||||
break
|
break
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
@@ -40,29 +66,20 @@ while IFS= read -r DEV; do
|
|||||||
STATE="$(awk '{print $2}' <<<"${DEV}")"
|
STATE="$(awk '{print $2}' <<<"${DEV}")"
|
||||||
[[ "${STATE}" != "device" ]] && continue
|
[[ "${STATE}" != "device" ]] && continue
|
||||||
|
|
||||||
LOG_PATH="${LOG_ROOT}/${SERIAL}/"
|
echo "------------ ${SERIAL}"
|
||||||
echo "------------ dumping in ${LOG_PATH}"
|
echo "session_stats:"
|
||||||
mkdir -p "${LOG_PATH}"
|
pull_dir "${SERIAL}" "session_stats" "${LOG_ROOT}"
|
||||||
|
echo "crash_reports/pending:"
|
||||||
mapfile -t FILES < <(adb -s "${SERIAL}" shell run-as com.foxx.androidcast ls files/session_stats/ </dev/null \
|
pull_dir "${SERIAL}" "crash_reports/pending" "${CRASH_ROOT}"
|
||||||
| tr -d '\r' | grep -v '^$' || true)
|
echo "crash_reports/native (stubs):"
|
||||||
|
pull_dir "${SERIAL}" "crash_reports/native" "${CRASH_ROOT}"
|
||||||
if ((${#FILES[@]} == 0)); then
|
|
||||||
echo " (no session_stats files on ${SERIAL})"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
for f in "${FILES[@]}"; do
|
|
||||||
adb -s "${SERIAL}" exec-out run-as com.foxx.androidcast cat "files/session_stats/${f}" </dev/null \
|
|
||||||
> "${LOG_PATH}/${f}"
|
|
||||||
if [[ "${CLEAN_LOGS}" == "yes" ]]; then
|
|
||||||
adb -s "${SERIAL}" shell run-as com.foxx.androidcast rm -f "files/session_stats/${f}" </dev/null
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
done <<<"${DEVICES_LIST}"
|
done <<<"${DEVICES_LIST}"
|
||||||
|
|
||||||
echo "showing all the logs in ${LOG_ROOT} folder and derivatives:"
|
echo ""
|
||||||
|
echo "Session stats: ${LOG_ROOT}"
|
||||||
ls -a ${LOG_ROOT}/*/*
|
[[ -d "${LOG_ROOT}" ]] && find "${LOG_ROOT}" -type f 2>/dev/null | sort || true
|
||||||
|
echo ""
|
||||||
echo "run './gradlew :session-studio:run' to analyze logs; find the latest logs in ${LOG_ROOT}"
|
echo "Crash reports: ${CRASH_ROOT}"
|
||||||
|
[[ -d "${CRASH_ROOT}" ]] && find "${CRASH_ROOT}" -type f 2>/dev/null | sort || true
|
||||||
|
echo ""
|
||||||
|
echo "run './gradlew :session-studio:run' to analyze session logs"
|
||||||
|
|||||||
Reference in New Issue
Block a user