mirror of
https://github.com/Lakr233/vphone-cli.git
synced 2026-04-05 13:09:06 +08:00
Isolate multi-VM setup with deterministic device targeting (#119)
This commit is contained in:
@@ -544,7 +544,7 @@ class VPhoneControl {
|
||||
let timeoutSeconds = max(Int(timeout.rounded()), 1)
|
||||
DispatchQueue.global(qos: .utility).asyncAfter(deadline: .now() + timeout) { [weak self] in
|
||||
guard let self else { return }
|
||||
guard let pending = self.removePending(id: id) else { return }
|
||||
guard let pending = removePending(id: id) else { return }
|
||||
pending.handler(.failure(ControlError.requestTimedOut(type: type, seconds: timeoutSeconds)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,7 +195,7 @@ class VPhoneFileBrowserModel {
|
||||
transferName = nil
|
||||
await refresh()
|
||||
// Set error after refresh so refresh() doesn't clear it before the alert fires.
|
||||
if let e = uploadError { self.error = e }
|
||||
if let e = uploadError { error = e }
|
||||
}
|
||||
|
||||
func createNewFolder(name: String) async {
|
||||
|
||||
@@ -13,6 +13,9 @@ import Virtualization
|
||||
/// Minimum host OS for PV=3: macOS 15.0 (Sequoia)
|
||||
///
|
||||
enum VPhoneHardware {
|
||||
/// Fixed CPID for the current vphone hardware descriptor.
|
||||
static let udidChipID: UInt32 = 0xFE01
|
||||
|
||||
static func createModel() throws -> VZMacHardwareModel {
|
||||
// platformVersion=3, boardID=0x90, ISA=2 matches vresearch101
|
||||
let desc = Dynamic._VZMacHardwareModelDescriptor()
|
||||
|
||||
@@ -46,7 +46,9 @@ class VPhoneLocationProvider: NSObject {
|
||||
private var replayTask: Task<Void, Never>?
|
||||
private var replayName: String?
|
||||
|
||||
var isReplaying: Bool { replayTask != nil }
|
||||
var isReplaying: Bool {
|
||||
replayTask != nil
|
||||
}
|
||||
|
||||
init(control: VPhoneControl) {
|
||||
self.control = control
|
||||
@@ -135,7 +137,7 @@ class VPhoneLocationProvider: NSObject {
|
||||
var index = 0
|
||||
while !Task.isCancelled {
|
||||
let point = points[index]
|
||||
self.sendSimulatedLocation(
|
||||
sendSimulatedLocation(
|
||||
latitude: point.latitude,
|
||||
longitude: point.longitude,
|
||||
altitude: point.altitude,
|
||||
|
||||
@@ -27,6 +27,12 @@ class VPhoneVirtualMachine: NSObject, VZVirtualMachineDelegate {
|
||||
var kernelDebugPort: Int = 5909
|
||||
}
|
||||
|
||||
private struct DeviceIdentity {
|
||||
let cpidHex: String
|
||||
let ecidHex: String
|
||||
let udid: String
|
||||
}
|
||||
|
||||
init(options: Options) throws {
|
||||
// --- Hardware model (PV=3) ---
|
||||
let hwModel = try VPhoneHardware.createModel()
|
||||
@@ -36,17 +42,34 @@ class VPhoneVirtualMachine: NSObject, VZVirtualMachineDelegate {
|
||||
let platform = VZMacPlatformConfiguration()
|
||||
|
||||
// Persist machineIdentifier for stable ECID
|
||||
let machineIdentifier: VZMacMachineIdentifier
|
||||
if let savedData = try? Data(contentsOf: options.machineIDURL),
|
||||
let savedID = VZMacMachineIdentifier(dataRepresentation: savedData)
|
||||
{
|
||||
platform.machineIdentifier = savedID
|
||||
machineIdentifier = savedID
|
||||
print("[vphone] Loaded machineIdentifier (ECID stable)")
|
||||
} else {
|
||||
let newID = VZMacMachineIdentifier()
|
||||
platform.machineIdentifier = newID
|
||||
machineIdentifier = newID
|
||||
try newID.dataRepresentation.write(to: options.machineIDURL)
|
||||
print("[vphone] Created new machineIdentifier -> \(options.machineIDURL.lastPathComponent)")
|
||||
}
|
||||
platform.machineIdentifier = machineIdentifier
|
||||
|
||||
if let identity = Self.resolveDeviceIdentity(machineIdentifier: machineIdentifier) {
|
||||
print("[vphone] ECID: 0x\(identity.ecidHex)")
|
||||
print("[vphone] Predicted UDID: \(identity.udid)")
|
||||
do {
|
||||
let outputURL = try Self.writeUDIDPrediction(
|
||||
identity: identity, machineIDURL: options.machineIDURL
|
||||
)
|
||||
print("[vphone] Wrote UDID prediction: \(outputURL.path)")
|
||||
} catch {
|
||||
print("[vphone] Warning: failed to write udid-prediction.txt: \(error)")
|
||||
}
|
||||
} else {
|
||||
print("[vphone] Warning: failed to resolve ECID from machineIdentifier")
|
||||
}
|
||||
|
||||
let auxStorage = try VZMacAuxiliaryStorage(
|
||||
creatingStorageAt: options.nvramURL,
|
||||
@@ -204,6 +227,39 @@ class VPhoneVirtualMachine: NSObject, VZVirtualMachineDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
private static func resolveDeviceIdentity(machineIdentifier: VZMacMachineIdentifier)
|
||||
-> DeviceIdentity?
|
||||
{
|
||||
let ecidValue: UInt64? = if let ecid = Dynamic(machineIdentifier)._ECID.asUInt64 {
|
||||
ecid
|
||||
} else if let ecidNumber = Dynamic(machineIdentifier)._ECID.asObject as? NSNumber {
|
||||
ecidNumber.uint64Value
|
||||
} else {
|
||||
nil
|
||||
}
|
||||
|
||||
guard let ecidValue else { return nil }
|
||||
|
||||
let cpidHex = String(format: "%08X", VPhoneHardware.udidChipID)
|
||||
let ecidHex = String(format: "%016llX", ecidValue)
|
||||
let udid = "\(cpidHex)-\(ecidHex)"
|
||||
return DeviceIdentity(cpidHex: cpidHex, ecidHex: ecidHex, udid: udid)
|
||||
}
|
||||
|
||||
private static func writeUDIDPrediction(identity: DeviceIdentity, machineIDURL: URL) throws -> URL {
|
||||
let outputURL = machineIDURL.deletingLastPathComponent().appendingPathComponent(
|
||||
"udid-prediction.txt"
|
||||
)
|
||||
let content = """
|
||||
UDID=\(identity.udid)
|
||||
CPID=0x\(identity.cpidHex)
|
||||
ECID=0x\(identity.ecidHex)
|
||||
MACHINE_IDENTIFIER=\(machineIDURL.lastPathComponent)
|
||||
"""
|
||||
try content.write(to: outputURL, atomically: true, encoding: .utf8)
|
||||
return outputURL
|
||||
}
|
||||
|
||||
// MARK: - Battery
|
||||
|
||||
/// Update the synthetic battery charge and connectivity at runtime.
|
||||
|
||||
Reference in New Issue
Block a user