Use IcliKit 0.6.5 for guest Low Power Mode

This commit is contained in:
Lakr
2026-09-25 00:22:19 +09:00
parent 0e8946f4c9
commit 9e7d820412
7 changed files with 15 additions and 63 deletions
+5 -3
View File
@@ -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.
@@ -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"
}
},
{
+5 -20
View File
@@ -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":
@@ -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);
-33
View File
@@ -1,8 +1,6 @@
#import "Include/VphonedNative.h"
#import "vphoned_install.h"
#import <CommonCrypto/CommonDigest.h>
#import <dlfcn.h>
#import <objc/message.h>
#include <mach-o/dyld.h>
#include <unistd.h>
@@ -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);
@@ -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" */ = {
@@ -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"
}
},
{