ios-hooks/AppRunMan/server/XSPhoneInfo.m
2025-09-05 18:48:22 +08:00

393 lines
13 KiB
Objective-C

//
// XSPhoneInfo.m
// nochange
//
// Created by mac on 2024/10/15.
//
#import <Foundation/Foundation.h>
#import <IOKit/IOKitLib.h>
#import <IOKit/ps/IOPowerSources.h>
#import <IOKit/ps/IOPSKeys.h>
#import <UIKit/UIKit.h>
#import <mach/mach.h>
#import <mach/mach_host.h>
#import <sys/sysctl.h>
#import <malloc/malloc.h>
#import "XSPhoneInfo.h"
@interface XSPhoneInfo()
{
}
@property (nonatomic, strong) NSTimer *monitorTimer;
@property (nonatomic, assign) BOOL isMonitoring;
@property (nonatomic, copy) void (^memoryWarningHandler)(double availableMemory);
@end
@implementation XSPhoneInfo {
dispatch_source_t _memoryPressureSource;
natural_t mem_free;
natural_t mem_total;
}
+(instancetype)sharedInstance
{
static XSPhoneInfo* _sharedInstance = nil;
static dispatch_once_t oncePredicate;
dispatch_once (&oncePredicate, ^{
_sharedInstance = [[XSPhoneInfo alloc] init];
});
return _sharedInstance;
}
-(instancetype)init {
if (self = [super init]) {
[self setupBatteryMonitoring];
_pageSize = vm_page_size;
[self startMemoryMonitoring];
[self updateMemoryInfo];
self.remoteIp = @"";
return self;
}
return nil;
}
- (void)setupBatteryMonitoring {
// 允许电池监控
[[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];
// 注册电池通知
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(batteryLevelDidChange:)
name:UIDeviceBatteryLevelDidChangeNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(batteryStateDidChange:)
name:UIDeviceBatteryStateDidChangeNotification
object:nil];
}
- (void)startBatteryMonitoring {
if (!self.isMonitoring) {
self.isMonitoring = YES;
// 创建定时器定期更新电池信息
self.monitorTimer = [NSTimer scheduledTimerWithTimeInterval:60.0
target:self
selector:@selector(updateBatteryInfo)
userInfo:nil
repeats:YES];
[self updateBatteryInfo];
}
}
- (void)updateBatteryInfo {
// 更新基本电池信息
_batteryLevel = [[UIDevice currentDevice] batteryLevel];
_isCharging = [[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateCharging;
_isFullyCharged = [[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateFull;
// 获取详细电池信息
[self updateDetailedBatteryInfo];
//[self updateMemoryInfo];
}
- (void)updateDetailedBatteryInfo {
@try {
// 使用IOKit获取电池详细信息
CFMutableDictionaryRef matching = IOServiceMatching("IOPMPowerSource");
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, matching);
if (service) {
CFMutableDictionaryRef properties = NULL;
kern_return_t kr = IORegistryEntryCreateCFProperties(service, &properties, kCFAllocatorDefault, 0);
if (kr == KERN_SUCCESS) {
NSDictionary *batteryProps = (__bridge_transfer NSDictionary *)properties;
// 更新基本信息
_batteryLevel = [[batteryProps objectForKey:@"CurrentCapacity"] floatValue] / 100.0;
_isCharging = [[batteryProps objectForKey:@"IsCharging"] boolValue];
_isFullyCharged = [[batteryProps objectForKey:@"FullyCharged"] boolValue];
// 获取电池容量信息
_designCapacity = [[batteryProps objectForKey:@"DesignCapacity"] floatValue];
_maxCapacity = [[batteryProps objectForKey:@"AppleRawMaxCapacity"] floatValue];
_currentCapacity = [[batteryProps objectForKey:@"CurrentCapacity"] floatValue];
// 获取电压信息
_batteryVoltage = [[batteryProps objectForKey:@"Voltage"] floatValue];
// 获取循环次数
_cycleCount = [[batteryProps objectForKey:@"CycleCount"] integerValue];
// 计算健康度
if (_designCapacity > 0 && _maxCapacity > 0) {
_batteryHealth = (_maxCapacity / _designCapacity) * 100;
}
// 更新电池状态描述
[self updateBatteryStatus:batteryProps];
}
IOObjectRelease(service);
}
} @catch (NSException *exception) {
NSLog(@"Battery info update error: %@", exception);
}
}
- (void)updateBatteryStatus:(NSDictionary *)batteryProps {
NSMutableString *status = [NSMutableString string];
// 基本状态
if (_isCharging) {
[status appendString:@"正在充电"];
} else {
[status appendString:@"使用电池中"];
}
// 健康状态
if (_batteryHealth > 0) {
//[status appendFormat:@"\n健康度: %ld%%", (long)_batteryHealth];
/*
if (_batteryHealth < 80) {
[status appendString:@" (建议更换电池)"];
} else if (_batteryHealth < 90) {
[status appendString:@" (性能可能降低)"];
}
*/
}
// 循环次数
if (_cycleCount > 0) {
//[status appendFormat:@"\n充电次数: %ld", (long)_cycleCount];
/*
if (_cycleCount > 500) {
[status appendString:@" (使用时间较长)"];
}
*/
}
self.batteryStatus = [status copy];
}
- (NSDictionary *)getBatteryInfo {
return @{
@"level": @(self.batteryLevel),
@"isCharging": @(self.isCharging),
@"isFullyCharged": @(self.isFullyCharged),
@"health": @(self.batteryHealth),
@"cycleCount": @(self.cycleCount),
@"temperature": @(self.temperature),
@"voltage": @(self.voltage),
@"status": self.batteryStatus ?: @"未知"
};
}
- (void)stopBatteryMonitoring {
if (self.isMonitoring) {
self.isMonitoring = NO;
[self.monitorTimer invalidate];
self.monitorTimer = nil;
}
}
- (void)batteryLevelDidChange:(NSNotification *)notification {
[self updateBatteryInfo];
}
- (void)batteryStateDidChange:(NSNotification *)notification {
[self updateBatteryInfo];
}
#pragma mark - Memory Info Methods
- (void)updateMemoryInfo {
mach_port_t host_port = mach_host_self();
mach_msg_type_number_t host_size = HOST_VM_INFO_COUNT;
vm_statistics_data_t vm_stat;
if (host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size) != KERN_SUCCESS) {
NSLog(@"Failed to fetch vm statistics");
return;
}
// 计算内存信息
natural_t mem_used = (vm_stat.active_count +
vm_stat.inactive_count +
vm_stat.wire_count) * _pageSize;
self->mem_free = vm_stat.free_count * _pageSize;
self->mem_total = mem_used + mem_free;
// 更新属性
_totalMemory = self->mem_total / (1024.0 * 1024.0 * 1024.0); // Convert to GB
_availableMemory = self->mem_free / (1024.0 * 1024.0 * 1024.0); // Convert to GB
_usedMemory = mem_used / (1024.0 * 1024.0 * 1024.0); // Convert to GB
_memoryUsage = (mem_used * 100.0) / self->mem_total; // Calculate percentage
}
- (double)getMemoryUsageForPid:(pid_t)pid {
task_vm_info_data_t vmInfo;
mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
kern_return_t kernReturn = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t)&vmInfo, &count);
if (kernReturn == KERN_SUCCESS) {
return (double)vmInfo.phys_footprint / 1024.0 / 1024.0; // Convert to MB
}
return 0;
}
#pragma mark - Memory Monitoring
- (void)handleCriticalMemoryPressure {
// 发送通知
[[NSNotificationCenter defaultCenter] postNotificationName:@"MemoryCriticalNotification"
object:nil
userInfo:@{@"availableMemory": @(self.availableMemory)}];
}
- (void)handleWarningMemoryPressure {
// 发送警告通知
[[NSNotificationCenter defaultCenter] postNotificationName:@"MemoryWarningNotification"
object:nil
userInfo:@{@"availableMemory": @(self.availableMemory)}];
}
- (void)startMemoryMonitoring {
// 创建定时器定期检查内存
self.monitorTimer = [NSTimer scheduledTimerWithTimeInterval:30.0
target:self
selector:@selector(checkMemoryStatus)
userInfo:nil
repeats:YES];
}
- (void)stopMemoryMonitoring {
[self.monitorTimer invalidate];
self.monitorTimer = nil;
}
- (void)checkMemoryStatus {
[self updateMemoryInfo];
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[UIDevice currentDevice] setBatteryMonitoringEnabled:NO];
[self stopBatteryMonitoring];
[self stopMemoryMonitoring];
if (_memoryPressureSource) {
dispatch_source_cancel(_memoryPressureSource);
}
}
- (NSString *)IPAddress {
NSDictionary *addresses = [self getIPAddresses];
__block NSString *address;
[addresses enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
address = obj;
if(address) *stop = YES;
}];
return address ? address : @"0.0.0.0";
}
- (NSDictionary *)getIPAddresses {
NSMutableDictionary *addresses = [NSMutableDictionary dictionaryWithCapacity:8];
// retrieve the current interfaces - returns 0 on success
struct ifaddrs *interfaces;
if(!getifaddrs(&interfaces)) {
// Loop through linked list of interfaces
struct ifaddrs *interface;
for(interface=interfaces; interface; interface=interface->ifa_next) {
if(!(interface->ifa_flags & IFF_UP) || (interface->ifa_flags & IFF_LOOPBACK)) {
continue; // deeply nested code harder to read
}
const struct sockaddr_in *addr = (const struct sockaddr_in*)interface->ifa_addr;
char addrBuf[ MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) ];
if(addr && (addr->sin_family==AF_INET)) {
NSString *name = [NSString stringWithUTF8String:interface->ifa_name];
NSString *type;
if(addr->sin_family == AF_INET) {
if(inet_ntop(AF_INET, &addr->sin_addr, addrBuf, INET_ADDRSTRLEN)) {
type = @"ipv4";
}
}
if(type) {
NSString *key = [NSString stringWithFormat:@"%@/%@", name, type];
addresses[key] = [NSString stringWithUTF8String:addrBuf];
}
}
}
// Free memory
freeifaddrs(interfaces);
}
return [addresses count] ? addresses : nil;
}
- (NSString *)CurrentThermalState {
NSProcessInfoThermalState state = [NSProcessInfo processInfo].thermalState;
switch (state) {
case NSProcessInfoThermalStateNominal:
return @"Nominal";
case NSProcessInfoThermalStateFair:
return @"Fair";
case NSProcessInfoThermalStateSerious:
return @"Serious";
case NSProcessInfoThermalStateCritical:
return @"Critical";
default:
return @"Unknown";
}
}
- (NSString *)DiskSize {
@try {
// 磁盘
NSDictionary<NSFileAttributeKey, id> *info = [[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:nil];
NSLog(@"diskinfo: %@", info);
int64_t size = [info[NSFileSystemSize] longLongValue]; // 总大小
int64_t space = [[info objectForKey:NSFileSystemFreeSize] longLongValue];
NSString *gb = [NSByteCountFormatter stringFromByteCount:size countStyle:NSByteCountFormatterCountStyleDecimal];
NSString *space_gb = [NSByteCountFormatter stringFromByteCount:space countStyle:NSByteCountFormatterCountStyleDecimal];
return [NSString stringWithFormat:@"%@/%@", space_gb,gb];
} @catch (NSException *exception) {
return @"";
}
}
- (NSString *)IPhoneStatus {
[self updateBatteryInfo];
[self updateMemoryInfo];
NSString *gb = [NSByteCountFormatter stringFromByteCount: self->mem_total countStyle:NSByteCountFormatterCountStyleDecimal];
NSString *space_gb = [NSByteCountFormatter stringFromByteCount:self->mem_free countStyle:NSByteCountFormatterCountStyleDecimal];
NSString *mem = [NSString stringWithFormat:@"%@/%@", space_gb,gb];
NSString *res = [NSString stringWithFormat:@"电池%ld%%,%@;内存%@;磁盘%@",(long)(self.batteryLevel*100), self.batteryStatus,
mem,self.DiskSize
];
return res;
}
@end