From de797e759a611373115c18ac5ddae76a4e76344e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A5=A5=E5=88=A9=E5=97=B7=E5=97=B7=E5=97=B7=E5=8F=AB?= Date: Sun, 14 Jul 2024 03:15:41 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=88=E5=B9=B6touch=E4=B8=8Eperf=E5=88=B0?= =?UTF-8?q?=E5=90=8C=E4=B8=80=E4=B8=AAws?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/scrcpy_client/control.go | 52 ++++++------ android/scrcpy_client/scrcpy.go | 20 ++++- .../{perf_ws_info.go => control_ws_info.go} | 28 ++++--- entity/scrcpy_ws_info.go | 39 +++++---- server/android/android_control_ws.go | 80 +++++++++++++------ server/android/perf_server.go | 52 ++++++++++++ server/android/scrcpy_server.go | 21 ++++- server/server.go | 4 +- 8 files changed, 211 insertions(+), 85 deletions(-) rename entity/{perf_ws_info.go => control_ws_info.go} (70%) diff --git a/android/scrcpy_client/control.go b/android/scrcpy_client/control.go index 9b54497..9b9766f 100644 --- a/android/scrcpy_client/control.go +++ b/android/scrcpy_client/control.go @@ -3,7 +3,6 @@ package scrcpy_client import ( "bytes" "encoding/binary" - "fionna/entity" log "github.com/sirupsen/logrus" "net" ) @@ -53,31 +52,32 @@ func (c *Control) Text(text string) error { } return nil } -func (c *Control) Touch(touch *entity.ScrcpyTouch, touchID int) error { - var data = []interface{}{ - uint8(TypeInjectTOUCHEvent), // base 1 - uint8(touch.ActionType), // B 1 byte 2 - int64(touchID), // q 8 byte 10 - uint32(touch.X), // i 4 byte 14 - uint32(touch.Y), // i 4 byte 18 - uint16(touch.Width), // H 2 byte 20 - uint16(touch.Height), // H 2 byte 22 - uint16(0xffff), // H 2 byte 24 - uint32(1), // i 4 byte 28 - uint32(1), // i 4 byte 32 - } - msg, err := serializePack(data) - if err != nil { - log.Error("control serialize touch packet err", err) - return err - } - _, err = c.controlConn.Write(msg) - if err != nil { - log.Error("control send touch packet err", err) - return err - } - return nil -} + +//func (c *Control) Touch(touch *entity.ScrcpyTouch, touchID int) error { +// var data = []interface{}{ +// uint8(TypeInjectTOUCHEvent), // base 1 +// uint8(touch.ActionType), // B 1 byte 2 +// int64(touchID), // q 8 byte 10 +// uint32(touch.X), // i 4 byte 14 +// uint32(touch.Y), // i 4 byte 18 +// uint16(touch.Width), // H 2 byte 20 +// uint16(touch.Height), // H 2 byte 22 +// uint16(0xffff), // H 2 byte 24 +// uint32(1), // i 4 byte 28 +// uint32(1), // i 4 byte 32 +// } +// msg, err := serializePack(data) +// if err != nil { +// log.Error("control serialize touch packet err", err) +// return err +// } +// _, err = c.controlConn.Write(msg) +// if err != nil { +// log.Error("control send touch packet err", err) +// return err +// } +// return nil +//} func serializePack(data []interface{}) ([]byte, error) { buf := new(bytes.Buffer) diff --git a/android/scrcpy_client/scrcpy.go b/android/scrcpy_client/scrcpy.go index 1358215..90ac5f2 100644 --- a/android/scrcpy_client/scrcpy.go +++ b/android/scrcpy_client/scrcpy.go @@ -25,6 +25,7 @@ const ( ) var ( + // 来源:https://github.com/aoliaoaoaojiao/scrcpy //go:embed scrcpy-server scrcpyBytes []byte scrcpyPtrLen int32 @@ -90,7 +91,7 @@ func NewScrcpy(device *gadb.Device, ctx context.Context, forwardWs *websocket.Co } } -func (s *Scrcpy) Start() { +func (s *Scrcpy) Start(pic entity.ScrcpyPic) { // todo var err error err = s.dev.Push(bytes.NewReader(scrcpyBytes), deviceServerPath, time.Now()) @@ -110,14 +111,25 @@ func (s *Scrcpy) Start() { s.startServer() - s.runBinary() + s.runBinary(pic) } -func (s *Scrcpy) runBinary() { +func (s *Scrcpy) runBinary(pic entity.ScrcpyPic) { var output io.Reader - output, err := s.dev.RunShellLoopCommand(fmt.Sprintf("CLASSPATH=/data/local/tmp/scrcpy-server.jar app_process / com.genymobile.scrcpy.Server v2.2 log_level=debug max_size=0 max_fps=60 control=false audio=false audio=false size_info=true")) + var maxSize int + + switch pic { + case entity.ScrcpyPicLow: + maxSize = 640 + case entity.ScrcpyPicMid: + maxSize = 1280 + case entity.ScrcpyPicHeight: + maxSize = 1920 + } + + output, err := s.dev.RunShellLoopCommand(fmt.Sprintf("CLASSPATH=/data/local/tmp/scrcpy-server.jar app_process / com.genymobile.scrcpy.Server v2.2 log_level=debug max_size=0 max_fps=60 control=false max_size=%d audio=false audio=false size_info=true", maxSize)) if err != nil { log.Error("execute scrcpy err:", err) s.exitCallBackFunc() diff --git a/entity/perf_ws_info.go b/entity/control_ws_info.go similarity index 70% rename from entity/perf_ws_info.go rename to entity/control_ws_info.go index 0e66e4b..f33577b 100644 --- a/entity/perf_ws_info.go +++ b/entity/control_ws_info.go @@ -2,20 +2,22 @@ package entity import "context" -type PerfRecvMessageType string -type PerfSendMessageType string +type ControlRecvMessageType string +type ControlSendMessageType string const ( - StartPerfType PerfRecvMessageType = "startPerfmon" - ClosePerfType PerfRecvMessageType = "closePerfmon" - PongPerfType PerfRecvMessageType = "pongPerfmon" - PerfDataType PerfSendMessageType = "perfdata" - PerfErrorType PerfSendMessageType = "error" + ControlTouchType ControlRecvMessageType = "touch" + StartPerfType ControlRecvMessageType = "startPerfmon" + ClosePerfType ControlRecvMessageType = "closePerfmon" + PongPerfType ControlRecvMessageType = "pongPerfmon" + PerfDataType ControlSendMessageType = "perfdata" + RotationDataType ControlSendMessageType = "rotation" + PerfErrorType ControlSendMessageType = "perfError" ) type PerfRecvMessage struct { - MessageType PerfRecvMessageType `json:"messageType"` - Data interface{} `json:"data"` + MessageType ControlRecvMessageType `json:"messageType"` + Data interface{} `json:"data"` } type PerfData struct { @@ -31,8 +33,8 @@ func NewPerfDataMessage(PerfData *PerfData) *PerfDataMessage { } type PerfDataMessage struct { - MessageType PerfSendMessageType `json:"messageType"` - Data interface{} `json:"perfData"` + MessageType ControlSendMessageType `json:"messageType"` + Data interface{} `json:"perfData"` } func NewPerfDataError(message string) *PerfErrorMessage { @@ -43,8 +45,8 @@ func NewPerfDataError(message string) *PerfErrorMessage { } type PerfErrorMessage struct { - MessageType PerfSendMessageType `json:"messageType"` - ErrorInfo string `json:"errorInfo"` + MessageType ControlSendMessageType `json:"messageType"` + ErrorInfo string `json:"errorInfo"` } type PerfConfig struct { diff --git a/entity/scrcpy_ws_info.go b/entity/scrcpy_ws_info.go index 3318673..27f5c60 100644 --- a/entity/scrcpy_ws_info.go +++ b/entity/scrcpy_ws_info.go @@ -9,28 +9,37 @@ const ( ScrcpyPongType ScrcpyRecvMessageType = "pong" ScrcpyDeviceType ScrcpyRecvMessageType = "device" ScrcpySizeInfoType ScrcpySendMessageType = "sizeInfo" + ScrcpyPicType ScrcpyRecvMessageType = "pic" ScrcpyErrorType ScrcpySendMessageType = "error" ) +type ScrcpyPic string + +const ( + ScrcpyPicLow ScrcpyPic = "low" + ScrcpyPicMid ScrcpyPic = "mid" + ScrcpyPicHeight ScrcpyPic = "height" +) + type ScrcpyDevice struct { UDID string `json:"udid"` } -type ScrcpyTouch struct { - ActionType ActionType `json:"actionType"` - X int `json:"x"` - Y int `json:"y"` - Width int `json:"width"` - Height int `json:"height"` -} - -type ActionType int - -const ( - ActionDown ActionType = 0 - ActionUp ActionType = 1 - ActionMove ActionType = 2 -) +//type ScrcpyTouch struct { +// ActionType ActionType `json:"actionType"` +// X int `json:"x"` +// Y int `json:"y"` +// Width int `json:"width"` +// Height int `json:"height"` +//} +// +//type ActionType int +// +//const ( +// ActionDown ActionType = 0 +// ActionUp ActionType = 1 +// ActionMove ActionType = 2 +//) type ScrcpySizeInfo struct { Rotation int `json:"rotation"` diff --git a/server/android/android_control_ws.go b/server/android/android_control_ws.go index 91a4491..0298d6a 100644 --- a/server/android/android_control_ws.go +++ b/server/android/android_control_ws.go @@ -2,51 +2,51 @@ package android import ( "context" + "encoding/json" "fionna/android/android_util" "fionna/android/touch" "fionna/entity" - "fmt" "github.com/gin-gonic/gin" log "github.com/sirupsen/logrus" - "net/http" ) -func Android_Control(r *gin.Engine) { +var touchMap map[string]*touch.Touch = make(map[string]*touch.Touch) + +func AndroidControl(r *gin.Engine) { r.GET("/android/control", func(c *gin.Context) { - serial := c.Query("udid") - if serial == "" { - log.Error("serial is empty") - c.JSON(http.StatusOK, entity.ResponseData{ - Data: "serial is empty", - Code: entity.ParameterErr, - }) + ws, err := upGrader.Upgrade(c.Writer, c.Request, nil) + if err != nil { + log.Print("Error during connection upgradation:", err) return } - device, err := android_util.GetDevice(client, serial) + + serialInfo := &entity.SerialInfo{} + // todo add error + ws.ReadJSON(serialInfo) + + device, err := android_util.GetDevice(client, serialInfo.SerialName) if err != nil { - c.JSON(http.StatusOK, entity.ResponseData{ - Data: entity.CodeDefaultMessage[entity.GetDeviceErr], - Code: entity.GetDeviceErr, - }) + ws.WriteJSON(entity.NewPerfDataError(err.Error())) log.Error(err) } - ws, err := upGrader.Upgrade(c.Writer, c.Request, nil) - if err != nil { - log.Print("Error during connection upgradation:", err) - return + if touchMap[device.Serial()] == nil { + touchMap[device.Serial()] = touch.NewTouch(device) } - control := touch.NewTouch(device) + control := touchMap[device.Serial()] exitCtx, exitFn := context.WithCancel(context.Background()) - var message entity.TouchInfo + perfExitCtx, perfExitFn := context.WithCancel(exitCtx) + + var message entity.PerfRecvMessage go func() { for { select { case <-exitCtx.Done(): + delete(touchMap, device.Serial()) return default: defer func() { @@ -56,13 +56,45 @@ func Android_Control(r *gin.Engine) { } }() err := ws.ReadJSON(&message) - fmt.Println(message) if err != nil { log.Error("android control read message steam err:", err) ws.WriteJSON(entity.NewPerfDataError("android control read message steam err:" + err.Error())) - break + return } else { - control.Touch(message) + data, err1 := json.Marshal(message.Data) + if err1 != nil { + log.Error("control the data sent is not json") + ws.WriteJSON(entity.NewPerfDataError("control the data sent is not json")) + return + } + switch message.MessageType { + case entity.ClosePerfType: + log.Println("client send close perf info,close perf...") + perfExitFn() + case entity.StartPerfType: + var perfConfig = &entity.PerfConfig{ + IntervalTime: 1, + } + err1 = json.Unmarshal(data, perfConfig) + if err1 != nil { + break + } + perfConfig.Ctx = perfExitCtx + perfConfig.CancelFn = perfExitFn + initPerfAndStart(serialInfo, perfConfig, device, ws) + case entity.ControlTouchType: + touchInfo := &entity.TouchInfo{} + err1 = json.Unmarshal(data, touchInfo) + if err1 != nil { + break + } + control.Touch(*touchInfo) + } + + if err1 != nil { + log.Error("conversion message error,", err1) + ws.WriteJSON(entity.NewPerfDataError(err1.Error())) + } } } } diff --git a/server/android/perf_server.go b/server/android/perf_server.go index b840e50..b77e5b4 100644 --- a/server/android/perf_server.go +++ b/server/android/perf_server.go @@ -551,3 +551,55 @@ func WebSocketPerf(r *gin.Engine) { }() }) } + +func initPerfAndStart(serialInfo *entity.SerialInfo, perfConfig *entity.PerfConfig, device *gadb.Device, ws *websocket.Conn) { + id := uuid.New() + + currentTime := time.Now() + + // 格式化时间为字符串 + formattedTime := currentTime.Format("2006-01-02 15:04:05") + + var testName = "" + var err error + + if perfConfig.PackageName != "" && perfConfig.Pid != "" { + testName = fmt.Sprintf("%s_%s_%s_pid%s_%s", serialInfo.ProductDevice, serialInfo.Model, perfConfig.PackageName, perfConfig.Pid, formattedTime) + } else if perfConfig.PackageName != "" && perfConfig.Pid == "" { + + testName = fmt.Sprintf("%s_%s_%s_%s", serialInfo.ProductDevice, serialInfo.Model, perfConfig.PackageName, formattedTime) + + perfConfig.Pid, err = android_util.GetPidOnPackageName(device, perfConfig.PackageName) + + if err != nil { + log.Error("get pid err:", err) + ws.WriteJSON(entity.NewPerfDataError("get pid err:" + err.Error())) + return + } + } else if perfConfig.PackageName == "" && perfConfig.Pid != "" { + testName = fmt.Sprintf("%s_%s_pid%s_%s", serialInfo.ProductDevice, serialInfo.Model, perfConfig.Pid, formattedTime) + } else { + testName = fmt.Sprintf("%s_%s_%s", serialInfo.ProductDevice, serialInfo.Model, formattedTime) + } + + serialInfo.TestName = &testName + timestamp := time.Now().UnixMilli() + + serialInfo.Timestamp = ×tamp + serialInfo.PackageName = &perfConfig.PackageName + + if serialInfo.UUID == "" { + serialInfo.UUID = id.String() + } + + db.GetDB().Create(serialInfo) + + if perfConfig.IntervalTime == 0 { + perfConfig.IntervalTime = 1 + } + + perfConfig.UUID = id.String() + db.GetDB().Create(perfConfig) + + startGetPerf(ws, device, *perfConfig) +} diff --git a/server/android/scrcpy_server.go b/server/android/scrcpy_server.go index b414176..a976ae1 100644 --- a/server/android/scrcpy_server.go +++ b/server/android/scrcpy_server.go @@ -7,10 +7,22 @@ import ( "fionna/entity" "github.com/gin-gonic/gin" log "github.com/sirupsen/logrus" + "net/http" ) func WebSocketScrcpy(r *gin.Engine) { r.GET("/android/scrcpy", func(c *gin.Context) { + + pic := c.Query("pic") + if pic == "" { + log.Error("pic is empty") + c.JSON(http.StatusOK, entity.ResponseData{ + Data: "pic is empty", + Code: entity.ParameterErr, + }) + return + } + ws, err := upGrader.Upgrade(c.Writer, c.Request, nil) if err != nil { log.Print("Error during connection upgradation:", err) @@ -36,7 +48,7 @@ func WebSocketScrcpy(r *gin.Engine) { scrcpyClient := scrcpy_client.NewScrcpy(dev, exitCtx, ws) - scrcpyClient.Start() + scrcpyClient.Start(entity.ScrcpyPic(pic)) var message entity.ScrcpyRecvMessage @@ -57,6 +69,7 @@ func WebSocketScrcpy(r *gin.Engine) { log.Error("read message steam err:", err) ws.WriteJSON(entity.NewScrcpyError("read message steam err:" + err.Error())) scrcpyClient.ClientStop() + return } else { if message.MessageType == entity.ScrcpyCloseType { scrcpyClient.ClientStop() @@ -64,6 +77,12 @@ func WebSocketScrcpy(r *gin.Engine) { if message.MessageType == entity.ScrcpyPongType { continue } + //if message.MessageType == entity.ScrcpyPicType { + // if pic, ok := message.Data.(entity.ScrcpyPic); ok { + // scrcpyClient.ClientStop() + // scrcpyClient.Start(pic) + // } + //} } } } diff --git a/server/server.go b/server/server.go index 9584b74..4dc21cd 100644 --- a/server/server.go +++ b/server/server.go @@ -93,7 +93,7 @@ func AndroidServerInit(r *gin.Engine) { android.GroupAndroidSerialUrl(r) android.GroupAndroidPackageUrl(r) android.WebSocketScrcpy(r) - android.WebSocketPerf(r) + //android.WebSocketPerf(r) android.WebSocketTerminal(r) - android.Android_Control(r) + android.AndroidControl(r) }