Files
Android-pyApi/android_pyapi/android/system.py
T
shuiyu1123 b3d75f8cc2 fix: 修复 Windows 兼容性问题
- 修复 setup.py 中 README.md 读取的编码问题 (UTF-8)
- 修复 system.py 中 errno 常量在 Windows 上不存在的问题
- 使用 getattr 安全获取平台特定的 errno 常量
- 测试全部通过 (24/24 能力可用)
2026-06-26 21:32:56 +08:00

592 lines
18 KiB
Python

"""
Android System 组件 — Os, StructStat, StructUtsname, OsConstants 等
方法签名完全对齐 Android SDK (android.system 包)
"""
import os as _os
import stat as _stat
import platform
import errno
from typing import Any, Dict, List, Optional, Tuple
from .._core import Stub, AndroidOnlyError
# ═══════════════════════════════════════════════════════════════
# OsConstants
# ═══════════════════════════════════════════════════════════════
class OsConstants(Stub):
"""OsConstants — 系统调用常量,映射自 os/stat 模块"""
# 文件访问常量
R_OK = _os.R_OK
W_OK = _os.W_OK
X_OK = _os.X_OK
F_OK = _os.F_OK
# 文件权限常量
S_IRWXU = _stat.S_IRWXU
S_IRUSR = _stat.S_IRUSR
S_IWUSR = _stat.S_IWUSR
S_IXUSR = _stat.S_IXUSR
S_IRWXG = _stat.S_IRWXG
S_IRGRP = _stat.S_IRGRP
S_IWGRP = _stat.S_IWGRP
S_IXGRP = _stat.S_IXGRP
S_IRWXO = _stat.S_IRWXO
S_IROTH = _stat.S_IROTH
S_IWOTH = _stat.S_IWOTH
S_IXOTH = _stat.S_IXOTH
S_ISUID = _stat.S_ISUID
S_ISGID = _stat.S_ISGID
S_ISVTX = _stat.S_ISVTX
# 文件类型常量
S_IFMT = _stat.S_IFMT
S_IFSOCK = _stat.S_IFSOCK
S_IFLNK = _stat.S_IFLNK
S_IFREG = _stat.S_IFREG
S_IFBLK = _stat.S_IFBLK
S_IFDIR = _stat.S_IFDIR
S_IFCHR = _stat.S_IFCHR
S_IFIFO = _stat.S_IFIFO
# 标准文件描述符
STDIN_FILENO = 0
STDOUT_FILENO = 1
STDERR_FILENO = 2
# 信号常量
SIGHUP = 1
SIGINT = 2
SIGQUIT = 3
SIGILL = 4
SIGTRAP = 5
SIGABRT = 6
SIGBUS = 7
SIGFPE = 8
SIGKILL = 9
SIGUSR1 = 10
SIGSEGV = 11
SIGUSR2 = 12
SIGPIPE = 13
SIGALRM = 14
SIGTERM = 15
SIGCHLD = 17
SIGCONT = 18
SIGSTOP = 19
SIGTSTP = 20
SIGTTIN = 21
SIGTTOU = 22
# errno 常量 (使用 getattr 处理 Windows 上不存在的常量)
EPERM = errno.EPERM
ENOENT = errno.ENOENT
ESRCH = errno.ESRCH
EINTR = errno.EINTR
EIO = errno.EIO
ENXIO = errno.ENXIO
E2BIG = errno.E2BIG
ENOEXEC = errno.ENOEXEC
EBADF = errno.EBADF
ECHILD = errno.ECHILD
EAGAIN = errno.EAGAIN
ENOMEM = errno.ENOMEM
EACCES = errno.EACCES
EFAULT = errno.EFAULT
ENOTBLK = getattr(errno, 'ENOTBLK', 15) # Windows 不支持
EBUSY = errno.EBUSY
EEXIST = errno.EEXIST
EXDEV = errno.EXDEV
ENODEV = errno.ENODEV
ENOTDIR = errno.ENOTDIR
EISDIR = errno.EISDIR
EINVAL = errno.EINVAL
ENFILE = errno.ENFILE
EMFILE = errno.EMFILE
ENOTTY = errno.ENOTTY
ETXTBSY = getattr(errno, 'ETXTBSY', 139)
EFBIG = errno.EFBIG
ENOSPC = errno.ENOSPC
ESPIPE = errno.ESPIPE
EROFS = errno.EROFS
EMLINK = errno.EMLINK
EPIPE = errno.EPIPE
EDOM = errno.EDOM
ERANGE = errno.ERANGE
EDEADLK = errno.EDEADLK
ENAMETOOLONG = errno.ENAMETOOLONG
ENOLCK = errno.ENOLCK
ENOSYS = errno.ENOSYS
ENOTEMPTY = errno.ENOTEMPTY
ELOOP = errno.ELOOP
ENOMSG = errno.ENOMSG
EIDRM = errno.EIDRM
ENOSTR = getattr(errno, 'ENOSTR', 125)
ENODATA = getattr(errno, 'ENODATA', 120)
ETIME = getattr(errno, 'ETIME', 137)
ENOSR = getattr(errno, 'ENOSR', 124)
EREMOTE = getattr(errno, 'EREMOTE', 10071)
ENOLINK = getattr(errno, 'ENOLINK', 121)
EPROTO = errno.EPROTO
EMULTIHOP = getattr(errno, 'EMULTIHOP', 10072) # Windows 不支持
EBADMSG = getattr(errno, 'EBADMSG', 104)
EOVERFLOW = getattr(errno, 'EOVERFLOW', 132)
EILSEQ = errno.EILSEQ
ENOTSOCK = errno.ENOTSOCK
EDESTADDRREQ = errno.EDESTADDRREQ
EMSGSIZE = errno.EMSGSIZE
EPROTOTYPE = errno.EPROTOTYPE
ENOPROTOOPT = errno.ENOPROTOOPT
EPROTONOSUPPORT = errno.EPROTONOSUPPORT
ESOCKTNOSUPPORT = getattr(errno, 'ESOCKTNOSUPPORT', 10044)
EOPNOTSUPP = getattr(errno, 'EOPNOTSUPP', 10045)
EPFNOSUPPORT = getattr(errno, 'EPFNOSUPPORT', 10046)
EAFNOSUPPORT = getattr(errno, 'EAFNOSUPPORT', 10047)
EADDRINUSE = errno.EADDRINUSE
EADDRNOTAVAIL = errno.EADDRNOTAVAIL
ENETDOWN = errno.ENETDOWN
ENETUNREACH = errno.ENETUNREACH
ENETRESET = errno.ENETRESET
ECONNABORTED = errno.ECONNABORTED
ECONNRESET = errno.ECONNRESET
ENOBUFS = errno.ENOBUFS
EISCONN = errno.EISCONN
ENOTCONN = errno.ENOTCONN
ESHUTDOWN = getattr(errno, 'ESHUTDOWN', 10058)
ETOOMANYREFS = getattr(errno, 'ETOOMANYREFS', 10059)
ETIMEDOUT = errno.ETIMEDOUT
ECONNREFUSED = errno.ECONNREFUSED
EHOSTDOWN = getattr(errno, 'EHOSTDOWN', 10064)
EHOSTUNREACH = errno.EHOSTUNREACH
EALREADY = errno.EALREADY
EINPROGRESS = errno.EINPROGRESS
ESTALE = getattr(errno, 'ESTALE', 10070)
EUCLEAN = getattr(errno, 'EUCLEAN', 117) # Windows 不支持
ENOTNAM = getattr(errno, 'ENOTNAM', 118) # Windows 不支持
ENAVAIL = getattr(errno, 'ENAVAIL', 119) # Windows 不支持
EISNAM = getattr(errno, 'EISNAM', 120) # Windows 不支持
EREMOTEIO = getattr(errno, 'EREMOTEIO', 121) # Windows 不支持
EDQUOT = getattr(errno, 'EDQUOT', 10069)
ENOMEDIUM = getattr(errno, 'ENOMEDIUM', 123) # Windows 不支持
EMEDIUMTYPE = getattr(errno, 'EMEDIUMTYPE', 124) # Windows 不支持
ECANCELED = getattr(errno, 'ECANCELED', 105)
ENOKEY = getattr(errno, 'ENOKEY', 126) # Windows 不支持
EKEYEXPIRED = getattr(errno, 'EKEYEXPIRED', 127) # Windows 不支持
EKEYREVOKED = getattr(errno, 'EKEYREVOKED', 128) # Windows 不支持
EKEYREJECTED = getattr(errno, 'EKEYREJECTED', 129) # Windows 不支持
EOWNERDEAD = getattr(errno, 'EOWNERDEAD', 133)
ENOTRECOVERABLE = getattr(errno, 'ENOTRECOVERABLE', 127)
ERFKILL = getattr(errno, 'ERFKILL', 132) # Windows 不支持
EHWPOISON = getattr(errno, 'EHWPOISON', 1001) # Windows 不支持
def __init__(self):
super().__init__()
# ═══════════════════════════════════════════════════════════════
# StructStat
# ═══════════════════════════════════════════════════════════════
class StructStat(Stub):
"""StructStat — stat() 返回的文件状态结构体"""
def __init__(self, st_mode: int = 0, st_ino: int = 0, st_dev: int = 0,
st_nlink: int = 0, st_uid: int = 0, st_gid: int = 0,
st_size: int = 0, st_atime: int = 0, st_mtime: int = 0,
st_ctime: int = 0, st_blksize: int = 4096,
st_blocks: int = 0, st_rdev: int = 0):
super().__init__()
self.st_mode = st_mode
self.st_ino = st_ino
self.st_dev = st_dev
self.st_nlink = st_nlink
self.st_uid = st_uid
self.st_gid = st_gid
self.st_size = st_size
self.st_atime = st_atime
self.st_mtime = st_mtime
self.st_ctime = st_ctime
self.st_blksize = st_blksize
self.st_blocks = st_blocks
self.st_rdev = st_rdev
self.st_atime_ns = st_atime * 1_000_000_000
self.st_mtime_ns = st_mtime * 1_000_000_000
self.st_ctime_ns = st_ctime * 1_000_000_000
@staticmethod
def from_os_stat(st: _os.stat_result) -> "StructStat":
"""从 Python os.stat_result 创建 StructStat"""
return StructStat(
st_mode=st.st_mode,
st_ino=st.st_ino,
st_dev=st.st_dev,
st_nlink=st.st_nlink,
st_uid=st.st_uid,
st_gid=st.st_gid,
st_size=st.st_size,
st_atime=int(st.st_atime),
st_mtime=int(st.st_mtime),
st_ctime=int(st.st_ctime),
st_blksize=st.st_blksize,
st_blocks=st.st_blocks,
st_rdev=st.st_rdev,
)
def toString(self) -> str:
return (f"StructStat(st_mode={oct(self.st_mode)}, st_size={self.st_size}, "
f"st_mtime={self.st_mtime}, st_uid={self.st_uid}, st_gid={self.st_gid})")
def hashCode(self) -> int:
return hash((self.st_dev, self.st_ino, self.st_mode)) & 0x7FFFFFFF
def equals(self, other) -> bool:
if not isinstance(other, StructStat):
return False
return (self.st_dev == other.st_dev and self.st_ino == other.st_ino
and self.st_mode == other.st_mode and self.st_size == other.st_size)
# ═══════════════════════════════════════════════════════════════
# StructUtsname
# ═══════════════════════════════════════════════════════════════
class StructUtsname(Stub):
"""StructUtsname — uname() 返回的系统信息结构体"""
def __init__(self, sysname: str = "", nodename: str = "",
release: str = "", version: str = "", machine: str = ""):
super().__init__()
self.sysname = sysname or platform.system()
self.nodename = nodename or platform.node()
self.release = release or platform.release()
self.version = version or platform.version()
self.machine = machine or platform.machine()
@staticmethod
def from_platform() -> "StructUtsname":
"""从 Python platform 模块创建 StructUtsname"""
uname = platform.uname()
return StructUtsname(
sysname=uname.system,
nodename=uname.node,
release=uname.release,
version=uname.version,
machine=uname.machine,
)
def toString(self) -> str:
return (f"StructUtsname(sysname={self.sysname}, nodename={self.nodename}, "
f"release={self.release}, version={self.version}, machine={self.machine})")
def hashCode(self) -> int:
return hash((self.sysname, self.nodename, self.release)) & 0x7FFFFFFF
def equals(self, other) -> bool:
if not isinstance(other, StructUtsname):
return False
return (self.sysname == other.sysname and self.nodename == other.nodename
and self.release == other.release)
# ═══════════════════════════════════════════════════════════════
# Os
# ═══════════════════════════════════════════════════════════════
class Os(Stub):
"""Os — 系统调用包装器,代理到 Python os 模块"""
def __init__(self):
super().__init__()
# ── 文件操作 ──
@staticmethod
def stat(path: str) -> StructStat:
"""获取文件状态"""
st = _os.stat(path)
return StructStat.from_os_stat(st)
@staticmethod
def lstat(path: str) -> StructStat:
"""获取符号链接自身状态"""
st = _os.lstat(path)
return StructStat.from_os_stat(st)
@staticmethod
def chmod(path: str, mode: int):
"""修改文件权限"""
_os.chmod(path, mode)
@staticmethod
def chown(path: str, uid: int, gid: int):
"""修改文件所有者"""
_os.chown(path, uid, gid)
@staticmethod
def link(oldpath: str, newpath: str):
"""创建硬链接"""
_os.link(oldpath, newpath)
@staticmethod
def symlink(target: str, linkpath: str):
"""创建符号链接"""
_os.symlink(target, linkpath)
@staticmethod
def readlink(path: str) -> str:
"""读取符号链接目标"""
return _os.readlink(path)
@staticmethod
def unlink(pathname: str):
"""删除文件(解除链接)"""
_os.unlink(pathname)
@staticmethod
def remove(path: str):
"""删除文件"""
_os.remove(path)
@staticmethod
def rename(oldpath: str, newpath: str):
"""重命名文件"""
_os.rename(oldpath, newpath)
@staticmethod
def mkdir(path: str, mode: int = 0o777):
"""创建目录"""
_os.mkdir(path, mode)
@staticmethod
def rmdir(path: str):
"""删除空目录"""
_os.rmdir(path)
@staticmethod
def listdir(path: str) -> List[str]:
"""列出目录内容"""
return _os.listdir(path)
@staticmethod
def truncate(path: str, length: int):
"""截断文件到指定长度"""
with open(path, 'ab') as f:
f.truncate(length)
@staticmethod
def access(path: str, mode: int) -> bool:
"""检查文件访问权限"""
return _os.access(path, mode)
# ── 文件描述符操作 ──
@staticmethod
def dup(oldfd: int) -> int:
"""复制文件描述符"""
return _os.dup(oldfd)
@staticmethod
def dup2(oldfd: int, newfd: int):
"""复制文件描述符到指定值"""
_os.dup2(oldfd, newfd)
@staticmethod
def close(fd: int):
"""关闭文件描述符"""
_os.close(fd)
@staticmethod
def read(fd: int, count: int) -> bytes:
"""从文件描述符读取"""
return _os.read(fd, count)
@staticmethod
def write(fd: int, data: bytes) -> int:
"""写入文件描述符"""
return _os.write(fd, data)
@staticmethod
def lseek(fd: int, offset: int, whence: int) -> int:
"""移动文件读写位置"""
return _os.lseek(fd, offset, whence)
@staticmethod
def fsync(fd: int):
"""同步文件描述符"""
_os.fsync(fd)
@staticmethod
def fstat(fd: int) -> StructStat:
"""获取文件描述符对应文件状态"""
st = _os.fstat(fd)
return StructStat.from_os_stat(st)
@staticmethod
def isatty(fd: int) -> bool:
"""判断文件描述符是否为终端"""
return _os.isatty(fd)
# ── 进程相关 ──
@staticmethod
def getpid() -> int:
"""获取当前进程 ID"""
return _os.getpid()
@staticmethod
def getppid() -> int:
"""获取父进程 ID"""
return _os.getppid()
@staticmethod
def getuid() -> int:
"""获取当前用户 ID"""
return _os.getuid()
@staticmethod
def getgid() -> int:
"""获取当前组 ID"""
return _os.getgid()
@staticmethod
def geteuid() -> int:
"""获取有效用户 ID"""
return _os.geteuid()
@staticmethod
def getegid() -> int:
"""获取有效组 ID"""
return _os.getegid()
@staticmethod
def setuid(uid: int):
"""设置用户 ID"""
_os.setuid(uid)
@staticmethod
def setgid(gid: int):
"""设置组 ID"""
_os.setgid(gid)
@staticmethod
def setsid() -> int:
"""创建新会话"""
return _os.setsid()
@staticmethod
def umask(mask: int) -> int:
"""设置文件创建掩码"""
return _os.umask(mask)
@staticmethod
def kill(pid: int, sig: int):
"""发送信号给进程"""
_os.kill(pid, sig)
@staticmethod
def getenv(name: str, default: Optional[str] = None) -> Optional[str]:
"""获取环境变量"""
return _os.environ.get(name, default)
@staticmethod
def setenv(name: str, value: str, overwrite: bool = True):
"""设置环境变量"""
if overwrite or name not in _os.environ:
_os.environ[name] = value
@staticmethod
def unsetenv(name: str):
"""删除环境变量"""
_os.environ.pop(name, None)
@staticmethod
def environ() -> Dict[str, str]:
"""获取环境变量字典"""
return dict(_os.environ)
# ── 系统信息 ──
@staticmethod
def uname() -> StructUtsname:
"""获取系统信息"""
return StructUtsname.from_platform()
@staticmethod
def sysconf(name: str) -> int:
"""获取系统配置值"""
conf_names = {
"SC_CLK_TCK": 100,
"SC_PAGE_SIZE": 4096,
"SC_NPROCESSORS_CONF": _os.cpu_count() or 1,
"SC_NPROCESSORS_ONLN": _os.cpu_count() or 1,
}
return conf_names.get(name, -1)
@staticmethod
def getpagesize() -> int:
"""获取内存页大小"""
return 4096
@staticmethod
def getloadavg() -> List[float]:
"""获取系统负载平均值"""
try:
return list(_os.getloadavg())
except AttributeError:
return [0.0, 0.0, 0.0]
# ── 管道与 I/O ──
@staticmethod
def pipe() -> Tuple[int, int]:
"""创建管道"""
return _os.pipe()
@staticmethod
def mkfifo(path: str, mode: int = 0o666):
"""创建命名管道 (FIFO)"""
_os.mkfifo(path, mode)
@staticmethod
def tmpfile() -> str:
"""创建临时文件路径"""
import tempfile
return tempfile.mktemp()
# ── 时间 ──
@staticmethod
def time() -> int:
"""获取当前时间戳 (秒)"""
import time
return int(time.time())
# ── 其他 ──
@staticmethod
def strerror(errno: int) -> str:
"""将错误码转为错误描述"""
return _os.strerror(errno)
def toString(self) -> str:
return f"Os(sysname={platform.system()}, release={platform.release()})"
def hashCode(self) -> int:
return hash("android.system.Os") & 0x7FFFFFFF
def equals(self, other) -> bool:
return isinstance(other, Os)
# ═══════════════════════════════════════════════════════════════
# __all__
# ═══════════════════════════════════════════════════════════════
__all__ = [
"Os",
"StructStat",
"StructUtsname",
"OsConstants",
]