github.com/metacubex/sing-tun@v0.2.7-0.20240512075008-89e7c6208eec/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 }