Skip to content

Commit

Permalink
add cpuLimit and memLimit options
Browse files Browse the repository at this point in the history
  • Loading branch information
whalechoi committed Jul 26, 2024
1 parent e44fc8a commit 574f340
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 2 deletions.
2 changes: 2 additions & 0 deletions main/builds/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ var Config struct {
CoreConfig string `yaml:"coreConfig"`
DataDir string `yaml:"dataDir"`
RunDir string `yaml:"runDir"`
CPULimit string `default:"1.0" yaml:"cpuLimit"`
MemLimit string `default:"-1" yaml:"memLimit"`
ProxyTag string `default:"proxy" yaml:"proxyTag"`
AllowInsecure bool `default:"false" yaml:"allowInsecure"`
SubList []string `yaml:"subList"`
Expand Down
4 changes: 2 additions & 2 deletions main/builds/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import (
const (
VersionX byte = 1
VersionY byte = 4
VersionZ byte = 4
Build = "-release"
VersionZ byte = 5
Build = "-debug"
Intro = "A unified helper for Android to control system proxy.\n\nTelegram channel: https://t.me/Asterisk4Magisk\nTelegram chat: https://t.me/AsteriskFactory\n\nReport issues at https://github.com/Asterisk4Magisk/XrayHelper/issues\n"
)

Expand Down
109 changes: 109 additions & 0 deletions main/cgroup/cgroup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package cgroup

import (
"XrayHelper/main/builds"
e "XrayHelper/main/errors"
"bufio"
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
)

const (
tagCgroup = "cgroup"
name = "proxy"
)

var mountPoint string

// v1MountPoint returns the mount point where the cgroup
// mountpoints are mounted in a single hierarchy
func v1MountPoint() (string, error) {
f, err := os.Open("/proc/self/mountinfo")
if err != nil {
return "", err
}
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
var (
text = scanner.Text()
fields = strings.Split(text, " ")
numFields = len(fields)
)
if numFields < 10 {
return "", fmt.Errorf("mountinfo: bad entry %q", text)
}
if fields[numFields-3] == "cgroup" {
return filepath.Dir(fields[4]), nil
}
}
if err := scanner.Err(); err != nil {
return "", err
}
return "", e.New("cgroup v1 mount point not found").WithPrefix(tagCgroup)
}

// LimitProcess use cgroup v1 to limit process resource
func LimitProcess(pid int) error {
if mountPoint == "" {
cpuLimit, _ := strconv.ParseFloat(builds.Config.XrayHelper.CPULimit, 64)
memLimit, _ := strconv.ParseInt(builds.Config.XrayHelper.MemLimit, 10, 64)
mp, err := v1MountPoint()
if err != nil {
return err
}
mountPoint = mp
// create cpu limit
if cpuLimit != 1.0 {
uclampMax := int64(float64(1024) * cpuLimit)
if err := os.MkdirAll(filepath.Join(mountPoint, "cpuctl", name), 0o755); err != nil {
return e.New("cannot create cpuctl cgroup, ", err).WithPrefix(tagCgroup)
}
if err := os.WriteFile(
filepath.Join(mountPoint, "cpuctl", name, "cpu.uclamp.max"),
[]byte(strconv.FormatInt(uclampMax, 10)),
os.FileMode(0),
); err != nil {
return e.New("cannot apply cpuctl cgroup, ", err).WithPrefix(tagCgroup)
}
}
// create memory limit
if memLimit > 0 {
// convert limit to bytes
memLimitBytes := memLimit * 1024 * 1024
if err := os.MkdirAll(filepath.Join(mountPoint, "memcg", name), 0o755); err != nil {
return e.New("cannot create memcg cgroup, ", err).WithPrefix(tagCgroup)
}
if err := os.WriteFile(
filepath.Join(mountPoint, "memcg", name, "memory.limit_in_bytes"),
[]byte(strconv.FormatInt(memLimitBytes, 10)),
os.FileMode(0),
); err != nil {
return e.New("cannot apply memcg cgroup, ", err).WithPrefix(tagCgroup)
}
}

}
// apply cpu limit
f, err := os.OpenFile(filepath.Join(mountPoint, "cpuctl", name, "cgroup.procs"), os.O_CREATE|os.O_WRONLY|os.O_APPEND, os.FileMode(0))
if err != nil {
return e.New("cannot open cpuctl cgroup procs, ", err).WithPrefix(tagCgroup)
}
defer f.Close()
if _, err := f.WriteString(strconv.FormatInt(int64(pid), 10) + "\n"); err != nil {
return e.New("cannot add process to cpuctl cgroup, ", err).WithPrefix(tagCgroup)
}
// apply memory limit
f2, err := os.OpenFile(filepath.Join(mountPoint, "memcg", name, "cgroup.procs"), os.O_CREATE|os.O_WRONLY|os.O_APPEND, os.FileMode(0))
if err != nil {
return e.New("cannot open memcg cgroup procs, ", err).WithPrefix(tagCgroup)
}
defer f2.Close()
if _, err := f.WriteString(strconv.FormatInt(int64(pid), 10) + "\n"); err != nil {
return e.New("cannot add process to memcg cgroup, ", err).WithPrefix(tagCgroup)
}
return nil
}
12 changes: 12 additions & 0 deletions main/commands/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package commands

import (
"XrayHelper/main/builds"
"XrayHelper/main/cgroup"
"XrayHelper/main/common"
e "XrayHelper/main/errors"
"XrayHelper/main/log"
Expand Down Expand Up @@ -190,6 +191,11 @@ OUT:
}
}
if listenFlag {
if err := cgroup.LimitProcess(service.Pid()); err != nil {
_ = service.Kill()
stopService()
return err
}
if err := os.WriteFile(path.Join(builds.Config.XrayHelper.RunDir, "core.pid"), []byte(strconv.Itoa(service.Pid())), 0644); err != nil {
_ = service.Kill()
stopService()
Expand Down Expand Up @@ -274,6 +280,12 @@ func startAdgHome() error {
service.AppendEnv("SSL_CERT_DIR=/system/etc/security/cacerts/")
service.SetUidGid("0", common.CoreGid)
service.Start()
if service.Err() != nil {
return e.New("start adgHome service failed, ", service.Err()).WithPrefix(tagService)
}
if err := cgroup.LimitProcess(service.Pid()); err != nil {
return err
}
return nil
}

Expand Down
5 changes: 5 additions & 0 deletions main/proxies/tun/tun.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package tun

import (
"XrayHelper/main/builds"
"XrayHelper/main/cgroup"
"XrayHelper/main/common"
e "XrayHelper/main/errors"
"XrayHelper/main/log"
Expand Down Expand Up @@ -154,6 +155,10 @@ func startTun2socks() error {
return e.New("start tun2socks failed, ", service.Err()).WithPrefix(tagTun)
}
if tunDeviceReady(builds.Config.Proxy.TunDevice) {
if err := cgroup.LimitProcess(service.Pid()); err != nil {
_ = service.Kill()
return err
}
if err := os.WriteFile(path.Join(builds.Config.XrayHelper.RunDir, "tun2socks.pid"), []byte(strconv.Itoa(service.Pid())), 0644); err != nil {
_ = service.Kill()
return e.New("write tun2socks pid failed, ", err).WithPrefix(tagTun)
Expand Down

0 comments on commit 574f340

Please sign in to comment.