From 07ef7ae18fbde468f67f6345115a963cf25cf1f9 Mon Sep 17 00:00:00 2001 From: Riley Testut Date: Fri, 4 Jun 2021 12:35:01 -0700 Subject: [PATCH] =?UTF-8?q?[AltServer]=20Adds=20=E2=80=9CEnable=20JIT?= =?UTF-8?q?=E2=80=9D=20menu=20option?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allows user to enable JIT execution for any sideloaded app by starting (and immediately stopping) a debug session on device. --- AltServer/AltServer-Bridging-Header.h | 1 + AltServer/AppDelegate.swift | 107 ++++++++++++++++++++++++++ AltServer/Base.lproj/Main.storyboard | 15 +++- 3 files changed, 121 insertions(+), 2 deletions(-) diff --git a/AltServer/AltServer-Bridging-Header.h b/AltServer/AltServer-Bridging-Header.h index b3ec0689..c42bab66 100644 --- a/AltServer/AltServer-Bridging-Header.h +++ b/AltServer/AltServer-Bridging-Header.h @@ -5,6 +5,7 @@ #import "ALTDeviceManager.h" #import "ALTWiredConnection.h" #import "ALTNotificationConnection.h" +#import "ALTDebugConnection.h" // Shared #import "ALTConstants.h" diff --git a/AltServer/AppDelegate.swift b/AltServer/AppDelegate.swift index b1f455e5..c5a4cc08 100644 --- a/AltServer/AppDelegate.swift +++ b/AltServer/AppDelegate.swift @@ -37,6 +37,8 @@ class AppDelegate: NSObject, NSApplicationDelegate { @IBOutlet private var appMenu: NSMenu! @IBOutlet private var connectedDevicesMenu: NSMenu! @IBOutlet private var sideloadIPAConnectedDevicesMenu: NSMenu! + @IBOutlet private var enableJITMenu: NSMenu! + @IBOutlet private var launchAtLoginMenuItem: NSMenuItem! @IBOutlet private var installMailPluginMenuItem: NSMenuItem! @@ -45,6 +47,9 @@ class AppDelegate: NSObject, NSApplicationDelegate { private var connectedDevicesMenuController: MenuController! private var sideloadIPAConnectedDevicesMenuController: MenuController! + private var enableJITMenuController: MenuController! + + private var _jitAppListMenuControllers = [AnyObject]() func applicationDidFinishLaunching(_ aNotification: Notification) { @@ -76,6 +81,9 @@ class AppDelegate: NSObject, NSApplicationDelegate { self?.sideloadIPA(to: device) } + self.enableJITMenuController = MenuController(menu: self.enableJITMenu, items: []) + self.enableJITMenuController.placeholder = placeholder + UNUserNotificationCenter.current().requestAuthorization(options: [.alert]) { (success, error) in guard success else { return } @@ -123,6 +131,47 @@ private extension AppDelegate } } + func enableJIT(for app: InstalledApp, on device: ALTDevice) + { + func finish(_ result: Result) + { + DispatchQueue.main.async { + switch result + { + case .failure(let error): + self.showErrorAlert(title: String(format: NSLocalizedString("JIT compilation could not be enabled for %@.", comment: ""), app.name), error: error) + + case .success: + let alert = NSAlert() + alert.messageText = String(format: NSLocalizedString("Successfully enabled JIT for %@.", comment: ""), app.name) + alert.informativeText = String(format: NSLocalizedString("JIT will remain enabled until you quit the app. You can now disconnect %@ from your computer.", comment: ""), device.name) + alert.runModal() + } + } + } + + ALTDeviceManager.shared.prepare(device) { (result) in + switch result + { + case .failure(let error as NSError): return finish(.failure(error)) + case .success: + ALTDeviceManager.shared.startDebugConnection(to: device) { (connection, error) in + guard let connection = connection else { + return finish(.failure(error! as NSError)) + } + + connection.enableUnsignedCodeExecutionForProcess(withName: app.executableName) { (success, error) in + guard success else { + return finish(.failure(error!)) + } + + finish(.success(())) + } + } + } + } + } + func installApplication(at url: URL, to device: ALTDevice) { let alert = NSAlert() @@ -311,11 +360,15 @@ extension AppDelegate: NSMenuDelegate func menuWillOpen(_ menu: NSMenu) { guard menu == self.appMenu else { return } + + // Clear any cached _jitAppListMenuControllers. + self._jitAppListMenuControllers.removeAll() self.connectedDevices = ALTDeviceManager.shared.availableDevices self.connectedDevicesMenuController.items = self.connectedDevices self.sideloadIPAConnectedDevicesMenuController.items = self.connectedDevices + self.enableJITMenuController.items = self.connectedDevices self.launchAtLoginMenuItem.target = self self.launchAtLoginMenuItem.action = #selector(AppDelegate.toggleLaunchAtLogin(_:)) @@ -335,6 +388,60 @@ extension AppDelegate: NSMenuDelegate } self.installMailPluginMenuItem.target = self self.installMailPluginMenuItem.action = #selector(AppDelegate.handleInstallMailPluginMenuItem(_:)) + + // Need to re-set this every time menu appears so we can refresh device app list. + self.enableJITMenuController.submenuHandler = { [weak self] device in + let submenu = NSMenu(title: NSLocalizedString("Sideloaded Apps", comment: "")) + + guard let `self` = self else { return submenu } + + let submenuController = MenuController(menu: submenu, items: []) + submenuController.placeholder = NSLocalizedString("Loading...", comment: "") + submenuController.action = { [weak self] (appInfo) in + self?.enableJIT(for: appInfo, on: device) + } + + // Keep strong reference + self._jitAppListMenuControllers.append(submenuController) + + ALTDeviceManager.shared.fetchInstalledApps(on: device) { (installedApps, error) in + DispatchQueue.main.async { + guard let installedApps = installedApps else { + print("Failed to fetch installed apps from \(device).", error!) + submenuController.placeholder = error?.localizedDescription + return + } + + print("Fetched \(installedApps.count) apps for \(device).") + + let sortedApps = installedApps.sorted { (app1, app2) in + if app1.name == app2.name + { + return app1.bundleIdentifier < app2.bundleIdentifier + } + else + { + return app1.name < app2.name + } + } + + submenuController.items = sortedApps + + if submenuController.items.isEmpty + { + submenuController.placeholder = NSLocalizedString("No Sideloaded Apps", comment: "") + } + } + } + + return submenu + } + } + + func menuDidClose(_ menu: NSMenu) + { + // Clearing _jitAppListMenuControllers now prevents action handler from being called. + // self._jitAppListMenuControllers = [] } } diff --git a/AltServer/Base.lproj/Main.storyboard b/AltServer/Base.lproj/Main.storyboard index b37cbc67..1c85367a 100644 --- a/AltServer/Base.lproj/Main.storyboard +++ b/AltServer/Base.lproj/Main.storyboard @@ -1,8 +1,8 @@ - + - + @@ -62,6 +62,7 @@ + @@ -108,6 +109,16 @@ + + + + + + + + + +