#!/usr/bin/env python3 # -*- coding: utf-8 -*- import os import time import platform import logging from typing import Dict, Any logger = logging.getLogger(__name__) def _is_android() -> bool: """检测是否为 Android 环境 (Termux 等)""" return ( 'ANDROID_ROOT' in os.environ or os.path.exists('/system/bin/getprop') or platform.release().lower().find('android') != -1 ) class SystemInfoCollector: def __init__(self): self.is_android = 'ANDROID_ROOT' in os.environ or os.path.exists('/system/bin/getprop') self.psutil = None if not self.is_android: try: import psutil self.psutil = psutil except ImportError as e: logger.debug(f"psutil not available: {e}") else: logger.info("🤖 Android 平台识别,启用原生采集") def get_all(self): return { "platform": { "system": platform.system(), "machine": platform.machine(), "python": platform.python_version() }, "cpu": self._get_cpu(), "memory": self._get_memory(), "network": self._get_network() } def _get_cpu(self): if self.psutil: return { "percent": self.psutil.cpu_percent(interval=0.1), "cores": self.psutil.cpu_count(), "load_avg": os.getloadavg() if hasattr(os, 'getloadavg') else [0,0,0] } # Android 估算:负载率 = (1分钟负载 / 核心数) * 100 try: load = os.getloadavg() if hasattr(os, "getloadavg") else [0.0, 0.0, 0.0] cores = os.cpu_count() or 1 percent = min(100.0, (load[0] / cores) * 100) return {"percent": round(percent, 1), "cores": cores, "load_avg": load} except Exception as e: logger.error(f"System info collection error: {e}", exc_info=True) return {"percent": 0, "cores": 0, "load_avg": [0,0,0]} def _get_memory(self): if self.psutil: m = self.psutil.virtual_memory() return {"total_gb": round(m.total/1073741824, 1), "used_gb": round(m.used/1073741824, 1), "percent": m.percent} try: mem = {} with open('/proc/meminfo') as f: for line in f: parts = line.split() if len(parts) >= 2: mem[parts[0].rstrip(':')] = int(parts[1]) * 1024 t, a = mem.get('MemTotal', 1), mem.get('MemAvailable', mem.get('MemFree', 0)) return {"total_gb": round(t/1073741824, 1), "used_gb": round((t-a)/1073741824, 1), "percent": round(((t-a)/t)*100, 1)} except Exception as e: logger.warning(f"Memory info failed: {e}") return {"total_gb": 0, "used_gb": 0, "percent": 0} def _get_network(self): if self.psutil: io = self.psutil.net_io_counters() return {"rx": round(io.bytes_recv/1048576, 1), "tx": round(io.bytes_sent/1048576, 1)} # Android 解析 /proc/net/dev try: rx = 0 with open('/proc/net/dev', 'r') as f: for line in f: if ':' in line and 'lo' not in line: # 排除 lo 回环 parts = line.split(':')[1].split() rx += int(parts[0]) # RX bytes return {"rx": round(rx/1048576, 1), "tx": 0} except Exception as e: logger.warning(f"Network info failed: {e}") return {"rx": 0, "tx": 0}