diff --git a/experimental/libbox/redirect_linux.go b/experimental/libbox/redirect_linux.go index d9e96fec0..8984de7a9 100644 --- a/experimental/libbox/redirect_linux.go +++ b/experimental/libbox/redirect_linux.go @@ -48,7 +48,7 @@ func NewAutoRedirectService(options []byte, handler AutoRedirectHandler) (AutoRe autoRedirect, err := tun.NewAutoRedirect(tun.AutoRedirectOptions{ TunOptions: tunOptions, Context: context.Background(), - Handler: &autoRedirectServiceHandler{handler: handler, logger: autoRedirectLogger}, + Handler: &autoRedirectServiceHandler{handler: handler, logger: autoRedirectLogger, judgeSlots: make(chan struct{}, autoRedirectJudgeConcurrency)}, Logger: autoRedirectLogger, NetworkMonitor: networkMonitor, InterfaceFinder: control.NewDefaultInterfaceFinder(), @@ -96,13 +96,21 @@ func (s *autoRedirectServiceSession) UpdateRouteAddressSet() error { return s.autoRedirect.UpdateRouteAddressSet() } +// Each JudgeFlow call is a synchronous binder transaction into the app process. It occupies +// one thread of the app's binder pool (15 threads by default in libbinder), which also serves +// the system's calls into the app, until the app returns the verdict. +const autoRedirectJudgeConcurrency = 8 + type autoRedirectServiceHandler struct { - handler AutoRedirectHandler - logger logger.Logger + handler AutoRedirectHandler + logger logger.Logger + judgeSlots chan struct{} } func (h *autoRedirectServiceHandler) JudgeFlow(network uint8, source netip.AddrPort, destination netip.AddrPort, firstPacket []byte) tun.FlowVerdict { + h.judgeSlots <- struct{}{} action, err := h.handler.JudgeFlow(int32(network), source.Addr().String(), int32(source.Port()), destination.Addr().String(), int32(destination.Port()), firstPacket) + <-h.judgeSlots if err != nil { h.logger.Error("judge flow ", source, " -> ", destination, ": ", err) return tun.FlowVerdict{Action: tun.ActionAccept}