From 9e7d82041245660ddb2445e8e4e10092099d08fd Mon Sep 17 00:00:00 2001 From: Lakr Date: Fri, 25 Sep 2026 00:22:19 +0900 Subject: [PATCH] Use IcliKit 0.6.5 for guest Low Power Mode --- Research/vphoned_http_api.md | 8 +++-- .../xcshareddata/swiftpm/Package.resolved | 4 +-- VPhoneDaemon/Daemon/GuestAPI.swift | 25 +++----------- VPhoneDaemon/Native/Include/VphonedNative.h | 2 -- VPhoneDaemon/Native/vphoned_native.m | 33 ------------------- .../VPhoneDaemon.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 4 +-- 7 files changed, 15 insertions(+), 63 deletions(-) diff --git a/Research/vphoned_http_api.md b/Research/vphoned_http_api.md index fc7f775..c1f28a5 100644 --- a/Research/vphoned_http_api.md +++ b/Research/vphoned_http_api.md @@ -35,7 +35,7 @@ directory then renames it after all chunks have been written. JSON bodies have a 1 MiB limit. Binary transfers stream without loading the entire file into memory. -`apps.launch` returns a PID and `frontmost_verified`. IcliKit 0.6.4 checks +`apps.launch` returns a PID and `frontmost_verified`. IcliKit 0.6.5 checks RunningBoard's live focal assertion and accepts it only when one real app owns it. iOS 26.6.2 uses `SuspendableRole-UIFocal`; older systems may use `Workspace-ForegroundFocal`. The Home screen's widget renderer can also hold @@ -62,12 +62,14 @@ correlate them by `id`. The socket also sends receive pong frames. JSON WebSocket frames are limited to 1 MiB after fragment reassembly. -SwiftNIO handles parsing, upgrade, masking, and backpressure. IcliKit 0.6.4 +SwiftNIO handles parsing, upgrade, masking, and backpressure. IcliKit 0.6.5 owns general device operations. Each HTTP or WebSocket request runs independently on a concurrent worker queue, so a stalled system service does not block HID, file browsing, or unrelated requests. The host serializes the input events it sends so touch and key sequences retain their order. State polling uses its own -worker queue. The vphone-specific IPA signing remains in native Objective-C. +worker queue. `power.low_power_mode` uses IcliKit's completion-based powerd +setter and verifies the resulting state. The vphone-specific IPA signing remains +in native Objective-C. Keychain listings combine IcliKit's accessible Security.framework attributes with its protected database metadata. They return no value data, and possible duplicates remain visible because the two sources have no stable join key. diff --git a/VPhone.xcworkspace/xcshareddata/swiftpm/Package.resolved b/VPhone.xcworkspace/xcshareddata/swiftpm/Package.resolved index e8839db..d8a90d1 100644 --- a/VPhone.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/VPhone.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -24,8 +24,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/owngoal-dev/icli.git", "state" : { - "revision" : "12a4fb47bcc68c27bd44a681358289e1a4ffe0c9", - "version" : "0.6.4" + "revision" : "bbb4d238bb06285dacb5385e372b5e990398d688", + "version" : "0.6.5" } }, { diff --git a/VPhoneDaemon/Daemon/GuestAPI.swift b/VPhoneDaemon/Daemon/GuestAPI.swift index f60da86..cff6f68 100644 --- a/VPhoneDaemon/Daemon/GuestAPI.swift +++ b/VPhoneDaemon/Daemon/GuestAPI.swift @@ -154,9 +154,12 @@ enum GuestAPI { let id = front["bundle_id"] as? String ?? "" let apps = try searchApps(id)["apps"] as? [[String: Any]] ?? [] let running = try runningApps()["apps"] as? [[String: Any]] ?? [] + let name = id == "com.apple.springboard" + ? "Home Screen" + : (apps.first(where: { $0["bundle_id"] as? String == id })?["name"] as? String ?? "") return [ "bundle_id": id, - "name": apps.first?["name"] ?? "", + "name": name, "pid": running.first(where: { $0["bundle_id"] as? String == id })?["pid"] ?? 0, "verified": front["verified"] ?? false, "source": front["source"] ?? "", @@ -203,25 +206,7 @@ enum GuestAPI { return try enableDeveloperMode() case "power.low_power_mode": if let enabled = params["enabled"] as? Bool { - let before = try lowPowerMode()["enabled"] as? Bool ?? false - switch vp_low_power_mode_set_async(enabled) { - case -1: - throw GuestAPIError.operationFailed("powerd's asynchronous Low Power Mode API is unavailable") - case -2: - throw GuestAPIError.operationFailed("powerd did not answer the Low Power Mode request within 3 seconds") - case -3: - throw GuestAPIError.operationFailed("powerd rejected the Low Power Mode request") - default: - break - } - let deadline = Date().addingTimeInterval(2) - while Date() < deadline { - if try lowPowerMode()["enabled"] as? Bool == enabled { - return ["enabled": enabled, "changed": before != enabled, "method": "powerd"] - } - Thread.sleep(forTimeInterval: 0.05) - } - throw GuestAPIError.operationFailed("powerd replied but did not apply Low Power Mode") + return try setLowPowerMode(enabled) } return try lowPowerMode() case "clipboard.get": diff --git a/VPhoneDaemon/Native/Include/VphonedNative.h b/VPhoneDaemon/Native/Include/VphonedNative.h index a16cffe..f455524 100644 --- a/VPhoneDaemon/Native/Include/VphonedNative.h +++ b/VPhoneDaemon/Native/Include/VphonedNative.h @@ -6,5 +6,3 @@ NSDictionary *vp_native_api_command(NSDictionary *message); void vp_native_bootstrap_cached_binary(void); void vp_native_confirm_cached_binary(void); void vp_vcam_start(void); -/// Returns 0 on acceptance, -1 when unavailable, -2 on timeout, or -3 on rejection. -int vp_low_power_mode_set_async(bool enabled); diff --git a/VPhoneDaemon/Native/vphoned_native.m b/VPhoneDaemon/Native/vphoned_native.m index 5339fec..b3835fc 100644 --- a/VPhoneDaemon/Native/vphoned_native.m +++ b/VPhoneDaemon/Native/vphoned_native.m @@ -1,8 +1,6 @@ #import "Include/VphonedNative.h" #import "vphoned_install.h" #import -#import -#import #include #include @@ -10,37 +8,6 @@ static const char *marker = "/var/root/Library/Caches/vphoned.api-v2"; static const char *pending = "/var/root/Library/Caches/vphoned.api-v2.pending"; -int vp_low_power_mode_set_async(bool enabled) { - dlopen("/System/Library/PrivateFrameworks/LowPowerMode.framework/LowPowerMode", RTLD_NOW); - Class cls = NSClassFromString(@"_PMLowPowerMode"); - SEL shared = NSSelectorFromString(@"sharedInstance"); - SEL set = NSSelectorFromString(@"setPowerMode:fromSource:withCompletion:"); - if (![cls respondsToSelector:shared]) return -1; - id service = ((id (*)(Class, SEL))objc_msgSend)(cls, shared); - if (![service respondsToSelector:set]) return -1; - - dispatch_semaphore_t done = dispatch_semaphore_create(0); - __block BOOL accepted = NO; - __block NSError *failure = nil; - NSLog(@"vphoned: low power mode async request enabled=%d", enabled); - // The iOS 26 synchronous selector waits for a powerd XPC reply without a - // deadline. Its completion variant uses an asynchronous remote proxy. - void (^completion)(BOOL, NSError *) = ^(BOOL applied, NSError *error) { - accepted = applied; - failure = error; - NSLog(@"vphoned: low power mode async reply applied=%d error_domain=%@ error_code=%ld error_info=%@", - applied, error.domain, (long)error.code, error.userInfo); - dispatch_semaphore_signal(done); - }; - ((void (*)(id, SEL, long, NSString *, id))objc_msgSend)(service, set, - enabled ? 1 : 0, @"ControlCenter", completion); - if (dispatch_semaphore_wait(done, dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC)) != 0) { - NSLog(@"vphoned: low power mode async request timed out after 3 seconds"); - return -2; - } - return accepted && !failure ? 0 : -3; -} - NSDictionary *vp_native_api_command(NSDictionary *message) { NSString *type = message[@"t"]; if ([type isEqualToString:@"ipa_install"]) return vp_handle_custom_install(message); diff --git a/VPhoneDaemon/VPhoneDaemon.xcodeproj/project.pbxproj b/VPhoneDaemon/VPhoneDaemon.xcodeproj/project.pbxproj index cee7fd9..67304b1 100644 --- a/VPhoneDaemon/VPhoneDaemon.xcodeproj/project.pbxproj +++ b/VPhoneDaemon/VPhoneDaemon.xcodeproj/project.pbxproj @@ -351,7 +351,7 @@ repositoryURL = "https://github.com/owngoal-dev/icli.git"; requirement = { kind = exactVersion; - version = 0.6.4; + version = 0.6.5; }; }; C10000000000000000000072 /* XCRemoteSwiftPackageReference "swift-nio" */ = { diff --git a/VPhoneDaemon/VPhoneDaemon.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/VPhoneDaemon/VPhoneDaemon.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 76c8c25..60ac16a 100644 --- a/VPhoneDaemon/VPhoneDaemon.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/VPhoneDaemon/VPhoneDaemon.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -6,8 +6,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/owngoal-dev/icli.git", "state" : { - "revision" : "12a4fb47bcc68c27bd44a681358289e1a4ffe0c9", - "version" : "0.6.4" + "revision" : "bbb4d238bb06285dacb5385e372b5e990398d688", + "version" : "0.6.5" } }, {