github.com/MerlinKodo/sing-tun@v0.1.15/packages_android.go (about)

     1  package tun
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/xml"
     7  	"io"
     8  	"os"
     9  	"strconv"
    10  
    11  	"github.com/sagernet/sing/common"
    12  	"github.com/sagernet/sing/common/abx"
    13  	E "github.com/sagernet/sing/common/exceptions"
    14  
    15  	"github.com/fsnotify/fsnotify"
    16  )
    17  
    18  type packageManager struct {
    19  	callback        PackageManagerCallback
    20  	watcher         *fsnotify.Watcher
    21  	idByPackage     map[string]uint32
    22  	sharedByPackage map[string]uint32
    23  	packageById     map[uint32]string
    24  	sharedById      map[uint32]string
    25  }
    26  
    27  func NewPackageManager(callback PackageManagerCallback) (PackageManager, error) {
    28  	return &packageManager{callback: callback}, nil
    29  }
    30  
    31  func (m *packageManager) Start() error {
    32  	err := m.updatePackages()
    33  	if err != nil {
    34  		return E.Cause(err, "read packages list")
    35  	}
    36  	err = m.startWatcher()
    37  	if err != nil {
    38  		m.callback.NewError(context.Background(), E.Cause(err, "create fsnotify watcher"))
    39  	}
    40  	return nil
    41  }
    42  
    43  func (m *packageManager) startWatcher() error {
    44  	watcher, err := fsnotify.NewWatcher()
    45  	if err != nil {
    46  		return err
    47  	}
    48  	err = watcher.Add("/data/system/packages.xml")
    49  	if err != nil {
    50  		return err
    51  	}
    52  	m.watcher = watcher
    53  	go m.loopUpdate()
    54  	return nil
    55  }
    56  
    57  func (m *packageManager) loopUpdate() {
    58  	for {
    59  		select {
    60  		case _, ok := <-m.watcher.Events:
    61  			if !ok {
    62  				return
    63  			}
    64  			err := m.updatePackages()
    65  			if err != nil {
    66  				m.callback.NewError(context.Background(), E.Cause(err, "update packages"))
    67  			}
    68  		case err, ok := <-m.watcher.Errors:
    69  			if !ok {
    70  				return
    71  			}
    72  			m.callback.NewError(context.Background(), E.Cause(err, "fsnotify error"))
    73  		}
    74  	}
    75  }
    76  
    77  func (m *packageManager) Close() error {
    78  	return common.Close(common.PtrOrNil(m.watcher))
    79  }
    80  
    81  func (m *packageManager) IDByPackage(packageName string) (uint32, bool) {
    82  	id, loaded := m.idByPackage[packageName]
    83  	return id, loaded
    84  }
    85  
    86  func (m *packageManager) IDBySharedPackage(sharedPackage string) (uint32, bool) {
    87  	id, loaded := m.sharedByPackage[sharedPackage]
    88  	return id, loaded
    89  }
    90  
    91  func (m *packageManager) PackageByID(id uint32) (string, bool) {
    92  	packageName, loaded := m.packageById[id]
    93  	return packageName, loaded
    94  }
    95  
    96  func (m *packageManager) SharedPackageByID(id uint32) (string, bool) {
    97  	sharedPackage, loaded := m.sharedById[id]
    98  	return sharedPackage, loaded
    99  }
   100  
   101  func (m *packageManager) updatePackages() error {
   102  	packagesData, err := os.ReadFile("/data/system/packages.xml")
   103  	if err != nil {
   104  		return err
   105  	}
   106  	var decoder *xml.Decoder
   107  	reader, ok := abx.NewReader(packagesData)
   108  	if ok {
   109  		decoder = xml.NewTokenDecoder(reader)
   110  	} else {
   111  		decoder = xml.NewDecoder(bytes.NewReader(packagesData))
   112  	}
   113  	return m.decodePackages(decoder)
   114  }
   115  
   116  func (m *packageManager) decodePackages(decoder *xml.Decoder) error {
   117  	idByPackage := make(map[string]uint32)
   118  	sharedByPackage := make(map[string]uint32)
   119  	packageById := make(map[uint32]string)
   120  	sharedById := make(map[uint32]string)
   121  	for {
   122  		token, err := decoder.Token()
   123  		if err == io.EOF {
   124  			break
   125  		} else if err != nil {
   126  			return err
   127  		}
   128  
   129  		element, isStart := token.(xml.StartElement)
   130  		if !isStart {
   131  			continue
   132  		}
   133  
   134  		switch element.Name.Local {
   135  		case "package":
   136  			var name string
   137  			var userID uint64
   138  			for _, attr := range element.Attr {
   139  				switch attr.Name.Local {
   140  				case "name":
   141  					name = attr.Value
   142  				case "userId", "sharedUserId":
   143  					userID, err = strconv.ParseUint(attr.Value, 10, 32)
   144  					if err != nil {
   145  						return err
   146  					}
   147  				}
   148  			}
   149  			if userID == 0 && name == "" {
   150  				continue
   151  			}
   152  			idByPackage[name] = uint32(userID)
   153  			packageById[uint32(userID)] = name
   154  		case "shared-user":
   155  			var name string
   156  			var userID uint64
   157  			for _, attr := range element.Attr {
   158  				switch attr.Name.Local {
   159  				case "name":
   160  					name = attr.Value
   161  				case "userId":
   162  					userID, err = strconv.ParseUint(attr.Value, 10, 32)
   163  					if err != nil {
   164  						return err
   165  					}
   166  					packageById[uint32(userID)] = name
   167  				}
   168  			}
   169  			if userID == 0 && name == "" {
   170  				continue
   171  			}
   172  			sharedByPackage[name] = uint32(userID)
   173  			sharedById[uint32(userID)] = name
   174  		}
   175  	}
   176  	m.idByPackage = idByPackage
   177  	m.sharedByPackage = sharedByPackage
   178  	m.packageById = packageById
   179  	m.sharedById = sharedById
   180  	m.callback.OnPackagesUpdated(len(packageById), len(sharedById))
   181  	return nil
   182  }