Skip to content

Commit

Permalink
feat: add USB and dev mode commands
Browse files Browse the repository at this point in the history
  • Loading branch information
sam80180 committed Nov 17, 2023
1 parent 9ffd12c commit 46aae6e
Show file tree
Hide file tree
Showing 20 changed files with 1,158 additions and 19 deletions.
20 changes: 20 additions & 0 deletions cmd/devmode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package cmd

import (
"github.com/SonicCloudOrg/sonic-ios-bridge/cmd/devmode"
"github.com/spf13/cobra"
)

var devmodeCmd = &cobra.Command{
Use: "devmode",
Short: "Enable Developer Mode on iOS 16+ devices or print the current status.",
Long: "Enable Developer Mode on iOS 16+ devices or print the current status.",
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
},
}

func init() {
rootCmd.AddCommand(devmodeCmd)
devmode.InitDevmode(devmodeCmd)
}
51 changes: 51 additions & 0 deletions cmd/devmode/arm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package devmode

import (
"fmt"
"net/http"

"github.com/SonicCloudOrg/sonic-ios-bridge/src/util"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"golang.org/x/xerrors"
)

var devmodeArmCmd = &cobra.Command{
Use: "arm",
Short: "Arm the Developer Mode (device will reboot)",
Long: "Arm the Developer Mode (device will reboot)",
RunE: func(cmd *cobra.Command, args []string) error {
util.InitLogger()
if bCan, eCan := canToggleDevMode(udid); eCan != nil {
strErrMsg := fmt.Sprintf("Failed to check device %s iOS version", udid)
logrus.Warn(strErrMsg)
return xerrors.New(strErrMsg)
} else if !bCan {
strErrMsg := fmt.Sprintf("Device %s iOS version below 16", udid)
logrus.Warn(strErrMsg)
return xerrors.New(strErrMsg)
}
amfi, errAmfi := getAmfiServer()
if errAmfi != nil {
return errAmfi
}
res, errArm := amfi.DevModeArm()
if errArm != nil {
return errArm
}
if res == http.StatusOK {
logrus.Infof("Developer Mode armed.")
return nil
} else {
strErrMsg := fmt.Sprintf("Failed to arm Developer Mode (%d).", res)
logrus.Warn(strErrMsg)
return xerrors.New(strErrMsg)
}
},
}

func initDevModeArmCmd() {
devmodeRootCMD.AddCommand(devmodeArmCmd)
devmodeArmCmd.Flags().StringVarP(&udid, "udid", "u", "", "target specific device by UDID")
devmodeArmCmd.MarkFlagRequired("udid")
}
53 changes: 53 additions & 0 deletions cmd/devmode/confirm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package devmode

import (
"fmt"
"net/http"

"github.com/SonicCloudOrg/sonic-ios-bridge/src/util"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"golang.org/x/xerrors"
)

var devmodeConfirmCmd = &cobra.Command{
Use: "confirm",
Short: "Confirm enabling of Developer Mode",
Long: "Confirm enabling of Developer Mode",
RunE: func(cmd *cobra.Command, args []string) error {
util.InitLogger()
if bPreCheckIOSVer {
if bCan, eCan := canToggleDevMode(udid); eCan != nil {
strErrMsg := fmt.Sprintf("Failed to check device %s iOS version", udid)
logrus.Warn(strErrMsg)
return xerrors.New(strErrMsg)
} else if !bCan {
strErrMsg := fmt.Sprintf("Device %s iOS version below 16", udid)
logrus.Warn(strErrMsg)
return xerrors.New(strErrMsg)
}
}
amfi, errAmfi := getAmfiServer()
if errAmfi != nil {
return errAmfi
}
res, errReveal := amfi.DevModeEnable()
if errReveal != nil {
return errReveal
}
if res == http.StatusOK {
logrus.Infof("Developer Mode menu enabled successfully.")
return nil
} else {
strErrMsg := fmt.Sprintf("Failed to enable Developer Mode menu (%d).", res)
logrus.Warn(strErrMsg)
return xerrors.New(strErrMsg)
}
},
}

func initDevModeConfirmCmd() {
devmodeRootCMD.AddCommand(devmodeConfirmCmd)
devmodeConfirmCmd.Flags().StringVarP(&udid, "udid", "u", "", "target specific device by UDID")
devmodeConfirmCmd.MarkFlagRequired("udid")
}
66 changes: 66 additions & 0 deletions cmd/devmode/devmodeinit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package devmode

import (
"encoding/json"
"os"
"reflect"

"github.com/SonicCloudOrg/sonic-ios-bridge/src/errorcodes"

giDevice "github.com/SonicCloudOrg/sonic-gidevice"
"github.com/SonicCloudOrg/sonic-ios-bridge/src/entity"
"github.com/SonicCloudOrg/sonic-ios-bridge/src/util"
"github.com/spf13/cobra"
"golang.org/x/xerrors"
)

var devmodeRootCMD *cobra.Command
var bPreCheckIOSVer bool = true

// option bindings
var udid string
var bIsOutputJson bool

func InitDevmode(devmodeCMD *cobra.Command) {
devmodeRootCMD = devmodeCMD
initDevModeListCmd()
initDevModeArmCmd()
initDevModeRevealCmd()
initDevModeEnableCmd()
initDevModeConfirmCmd()
}

func getAmfiServer() (giDevice.Amfi, error) {
device := util.GetDeviceByUdId(udid)
if device == nil {
os.Exit(errorcodes.ERROR_DEV_NOT_EXIST)
}
return device.AmfiService()
}

func canToggleDevMode(udid string) (bool, error) {
gidevice := util.GetDeviceByUdId(udid)
if gidevice == nil {
return false, xerrors.Errorf("Device %s not found", udid)
}
device := entity.Device{}
deviceByte, _ := json.Marshal(gidevice.Properties())
json.Unmarshal(deviceByte, &device)
detail, err2 := entity.GetDetail(gidevice)
if err2 != nil {
return false, err2
} else {
device.DeviceDetail = *detail
}
devmode := entity.DevMode{Device: device}
b, e := devmode.CanCheck()
if e != nil {
return false, e
}
return b, nil
}

func __PACKAGE__() string { // https://www.appsloveworld.com/go/3/how-to-get-name-of-current-package-in-go?expand_article=1
type dummy struct{}
return reflect.TypeOf(dummy{}).PkgPath()
}
89 changes: 89 additions & 0 deletions cmd/devmode/enable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package devmode

import (
"os"
"strings"
"sync"
"time"

giDevice "github.com/SonicCloudOrg/sonic-gidevice"
"github.com/SonicCloudOrg/sonic-ios-bridge/src/entity"
"github.com/SonicCloudOrg/sonic-ios-bridge/src/util"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

// option bindings
var bWaitReboot, bAutoConfirm bool
var intEnableWaitTimeout int

var devmodeEnableCmd = &cobra.Command{
Use: "enable",
Short: "Enable Developer Mode (device will reboot)",
Long: "Enable Developer Mode (device will reboot)",
RunE: func(cmd *cobra.Command, args []string) error {
//util.InitLogger()
errArm := devmodeArmCmd.RunE(cmd, args)
if errArm != nil {
return errArm
}
if bWaitReboot {
bIsDeviceOnline := true
wg := new(sync.WaitGroup)
wg.Add(1)
shutDownFun, errListen := util.UsbmuxListen(func(gidevice *giDevice.Device, device *entity.Device, e error, cancelFunc func()) {
if device == nil {
return
}
funcDone := func() {
cancelFunc()
bIsDeviceOnline = true
logrus.Infof("Device %s is online.", udid)
wg.Done()
}
if device.Status == "offline" {
bIsDeviceOnline = false
logrus.Infof("Device %s is offline.", udid)
} else if !bIsDeviceOnline && device.Status == "online" {
if device.SerialNumber == udid {
funcDone()
return
}
detail, _ := entity.GetDetail(*gidevice)
if detail != nil && detail.UniqueDeviceID == udid {
funcDone()
return
}
}
})
if errListen != nil {
return errListen
}
go func() {
time.Sleep(time.Duration(intEnableWaitTimeout) * time.Second)
logrus.Warnf("Timeout waiting for device %s to reboot.", udid)
shutDownFun()
wg.Done()
}()
wg.Wait()
if bIsDeviceOnline && bAutoConfirm {
bPreCheckIOSVer = false
devmodeConfirmCmd.RunE(cmd, args)
} else {
executable, _ := os.Executable()
pkgPath := strings.Split(__PACKAGE__(), "/")
logrus.Infof("Please check the device %s is online and then run '%s %s %s -u %s'.", udid, executable, pkgPath[len(pkgPath)-1], devmodeConfirmCmd.Use, udid)
}
}
return nil
},
}

func initDevModeEnableCmd() {
devmodeRootCMD.AddCommand(devmodeEnableCmd)
devmodeEnableCmd.Flags().StringVarP(&udid, "udid", "u", "", "target specific device by UDID")
devmodeEnableCmd.MarkFlagRequired("udid")
devmodeEnableCmd.Flags().BoolVar(&bWaitReboot, "wait", false, "wait for reboot to complete")
devmodeEnableCmd.Flags().IntVar(&intEnableWaitTimeout, "wait-timeout", 60, "wait timeout in seconds")
devmodeEnableCmd.Flags().BoolVarP(&bAutoConfirm, "confirm", "y", false, "automatically confirm after reboot")
}
Loading

0 comments on commit 46aae6e

Please sign in to comment.