Skip to content
This repository has been archived by the owner on May 27, 2024. It is now read-only.

Commit

Permalink
add go-daemon, add safe time.Ticker to prevent panic, which make atx-…
Browse files Browse the repository at this point in the history
…agent live longer
  • Loading branch information
codeskyblue committed Aug 3, 2018
1 parent 562392f commit 058be8b
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 63 deletions.
94 changes: 42 additions & 52 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import (
"syscall"
"time"

"github.com/codeskyblue/kexec"
"github.com/codeskyblue/procfs"
"github.com/franela/goreq"
"github.com/gorilla/mux"
Expand All @@ -40,6 +39,7 @@ import (
"github.com/pkg/errors"
"github.com/qiniu/log"
"github.com/rs/cors"
"github.com/sevlyar/go-daemon"
"github.com/shogo82148/androidbinary/apk"
)

Expand Down Expand Up @@ -786,7 +786,7 @@ func (server *Server) initHTTPServer() {
// keep ApkService always running
// if no activity in 5min, then restart apk service
const apkServiceTimeout = 5 * time.Minute
apkServiceTimer := time.NewTimer(apkServiceTimeout)
apkServiceTimer := NewSafeTimer(apkServiceTimeout)
go func() {
for range apkServiceTimer.C {
log.Println("startservice com.github.uiautomator/.Service")
Expand Down Expand Up @@ -1317,19 +1317,34 @@ func (s *Server) Serve(lis net.Listener) error {
return s.httpServer.Serve(lis)
}

func runDaemon() {
environ := os.Environ()
// env:IGNORE_SIGHUP forward stdout and stderr to file
// env:ATX_AGENT will ignore -d flag
environ = append(environ, "IGNORE_SIGHUP=true", "ATX_AGENT=1")
cmd := kexec.Command(os.Args[0], os.Args[1:]...)
cmd.Env = environ
cmd.Start()
select {
case err := <-GoFunc(cmd.Wait):
log.Fatalf("server started failed, %v", err)
case <-time.After(200 * time.Millisecond):
fmt.Printf("server started, listening on %v:%d\n", mustGetOoutboundIP(), listenPort)
func runDaemon() (cntxt *daemon.Context) {
cntxt = &daemon.Context{
PidFileName: "/sdcard/atx-agent.pid",
PidFilePerm: 0644,
LogFileName: "/sdcard/atx-agent.log",
LogFilePerm: 0640,
WorkDir: "./",
Umask: 022,
}
child, err := cntxt.Reborn()
if err != nil {
log.Fatal("Unale to run: ", err)
}
if child != nil {
return nil // return nil indicate program run in parent
}
return cntxt
}

func stopSelf() {
// kill previous daemon first
log.Println("stop server self")
_, err := http.Get(fmt.Sprintf("http://127.0.0.1:%d/stop", listenPort))
if err == nil {
log.Println("wait server stopped")
time.Sleep(1000 * time.Millisecond) // server will quit in 0.1s
} else {
log.Println(err)
}
}

Expand Down Expand Up @@ -1358,12 +1373,7 @@ func main() {
}()

if *fStop {
_, err := http.Get("http://127.0.0.1:7912/stop")
if err != nil {
log.Println(err)
} else {
log.Println("server stopped")
}
stopSelf()
return
}

Expand All @@ -1376,40 +1386,20 @@ func main() {
}
}

os.Setenv("TMPDIR", "/sdcard/")
if *fDaemon && os.Getenv("ATX_AGENT") == "" {
runDaemon()
return
if _, err := os.Stat("/sdcard/tmp"); err != nil {
os.MkdirAll("/sdcard/tmp", 0755)
}
os.Setenv("TMPDIR", "/sdcard/tmp")

if os.Getenv("IGNORE_SIGHUP") == "true" {
fmt.Println("Enter into daemon mode")
os.Unsetenv("IGNORE_SIGHUP")

os.Rename("/sdcard/atx-agent.log", "/sdcard/atx-agent.log.old")
f, err := os.Create("/sdcard/atx-agent.log")
if err != nil {
panic(err)
}
defer f.Close()

os.Stdout = f
os.Stderr = f
os.Stdin = nil

log.SetOutput(f)
log.Println("Ignore SIGHUP")
signal.Ignore(syscall.SIGHUP)

// kill previous daemon first
log.Println("Kill server")
_, err = http.Get(fmt.Sprintf("http://127.0.0.1:%d/stop", listenPort))
if err == nil {
log.Println("wait previous server stopped")
time.Sleep(1000 * time.Millisecond) // server will quit in 0.1s
} else {
log.Println(err)
if *fDaemon {
cntxt := runDaemon()
if cntxt == nil {
log.Printf("Enter into daemon mode, listening on %v:%d", mustGetOoutboundIP(), listenPort)
return
}
defer cntxt.Release()
log.Print("- - - - - - - - - - - - - - -")
log.Print("daemon started")
}

fmt.Printf("atx-agent version %s\n", version)
Expand Down
15 changes: 4 additions & 11 deletions minitouch.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"io/ioutil"
"net"

log "github.com/sirupsen/logrus"
"github.com/qiniu/log"
)

type toucher struct {
Expand Down Expand Up @@ -39,12 +39,8 @@ func drainTouchRequests(conn net.Conn, reqC chan TouchRequest) error {
if err := lineRd.Scanf("%s %d", &flag, &pid); err != nil {
return err
}
log.WithFields(log.Fields{
"maxX": maxX,
"maxY": maxY,
"maxPressure": maxPressure,
"maxContacts": maxContacts,
}).Info("handle touch requests")

log.Debugf("handle touch requests maxX:%d maxY:%d maxPressure:%d maxContacts:%s", maxX, maxY, maxPressure, maxContacts)
go io.Copy(ioutil.Discard, conn) // ignore the rest output
var posX, posY int
for req := range reqC {
Expand All @@ -60,10 +56,7 @@ func drainTouchRequests(conn net.Conn, reqC chan TouchRequest) error {
pressure = maxPressure - 1
}
line := fmt.Sprintf("%s %d %d %d %d\n", req.Operation, req.Index, posX, posY, pressure)
log.WithFields(log.Fields{
"touch": req,
"remoteAddr": conn.RemoteAddr(),
}).Debug("write to @minitouch", line)
log.Debugf("write to @minitouch %v", line)
_, err = conn.Write([]byte(line))
case "u":
_, err = conn.Write([]byte(fmt.Sprintf("u %d\n", req.Index)))
Expand Down
25 changes: 25 additions & 0 deletions safetimer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package main

import (
"sync"
"time"
)

// SafeTime add thread-safe for time.Timer
type SafeTimer struct {
*time.Timer
mu sync.Mutex
}

func NewSafeTimer(d time.Duration) *SafeTimer {
return &SafeTimer{
Timer: time.NewTimer(d),
}
}

// Reset is thread-safe now
func (t *SafeTimer) Reset(d time.Duration) bool {
t.mu.Lock()
defer t.mu.Unlock()
return t.Timer.Reset(d)
}
52 changes: 52 additions & 0 deletions safetimer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// +build windows

package main

import (
"sync"
"testing"
"time"
)

func TestSafeTimer(tt *testing.T) {
deadtime := time.Now().Add(2 * time.Second)
t := NewSafeTimer(100 * time.Hour)
wg := sync.WaitGroup{}
wg.Add(8)
for i := 0; i < 8; i++ {
go func() {
for {
t.Reset(10 * time.Hour)
if time.Now().After(deadtime) {
break
}
}
wg.Done()
}()
}
wg.Wait()
}

// func TestMustPanic(tt *testing.T) {
// defer func() {
// if r := recover(); r == nil {
// tt.Errorf("The code did not panic")
// }
// }()
// deadtime := time.Now().Add(2 * time.Second)
// t := time.NewTimer(100 * time.Hour)
// wg := sync.WaitGroup{}
// wg.Add(8)
// for i := 0; i < 8; i++ {
// go func() {
// for {
// t.Reset(10 * time.Hour)
// if time.Now().After(deadtime) {
// break
// }
// }
// wg.Done()
// }()
// }
// wg.Wait()
// }

0 comments on commit 058be8b

Please sign in to comment.