浏览代码

Fix doh & Option to disable traffic statistics

世界 4 年之前
父节点
当前提交
caa490e710

+ 1 - 0
app/src/main/aidl/io/nekohasekai/sagernet/aidl/ISagerNetService.aidl

@@ -15,5 +15,6 @@ interface ISagerNetService {
   oneway void protect(int fd);
   int urlTest();
   oneway void resetTrafficStats();
+  boolean getTrafficStatsEnabled();
 
 }

+ 1 - 0
app/src/main/java/io/nekohasekai/sagernet/Constants.kt

@@ -91,6 +91,7 @@ object Key {
     const val PROVIDER_SS_STREAM = "providerShadowsocksStream"
 
     const val UTLS_FINGERPRINT = "utlsFingerprint"
+    const val TRAFFIC_STATISTICS = "trafficStatistics"
 
     const val PROFILE_DIRTY = "profileDirty"
     const val PROFILE_ID = "profileId"

+ 10 - 8
app/src/main/java/io/nekohasekai/sagernet/bg/BaseService.kt

@@ -180,6 +180,8 @@ class BaseService {
         private suspend fun loopStats() {
             var lastQueryTime = 0L
             val tun = (data?.proxy?.service as? VpnService)?.tun2socks ?: return
+            if (!tun.trafficStatsEnabled) return
+
             while (true) {
                 val delayMs = statsListeners.values.minOrNull()
                 if (delayMs == 0L) return
@@ -191,19 +193,15 @@ class BaseService {
                 tun.readAppTraffics(this)
 
                 val statsList = AppStatsList(appStats.map {
-                    val uid = if (it.uid >= 10000) it.uid.toInt() else 1000
+                    val uid = if (it.uid >= 10000) it.uid else 1000
                     val packageName = if (uid != 1000) {
-                        PackageCache.uidMap[it.uid.toInt()]?.iterator()?.next() ?: "android"
+                        PackageCache.uidMap[it.uid]?.iterator()?.next() ?: "android"
                     } else {
                         "android"
                     }
                     AidlAppStats(
                         packageName,
-                        uid,
-                        it.tcpConn.toInt(),
-                        it.udpConn.toInt(),
-                        it.tcpConnTotal.toInt(),
-                        it.udpConnTotal.toInt(),
+                        uid, it.tcpConn, it.udpConn, it.tcpConnTotal, it.udpConnTotal,
                         it.uplink / sinceLastQueryInSeconds,
                         it.downlink / sinceLastQueryInSeconds,
                         it.uplinkTotal,
@@ -269,7 +267,7 @@ class BaseService {
             try {
                 return Libcore.urlTestV2ray(
                     data!!.proxy!!.v2rayPoint, TAG_SOCKS, DataStore.connectionTestURL, 5000
-                ).toInt()
+                )
             } catch (e: Exception) {
                 var msg = e.readableMessage
                 if (msg.lowercase().contains("timeout")) {
@@ -331,6 +329,10 @@ class BaseService {
             broadcast { it.missingPlugin(profileName, pluginName) }
         }
 
+        override fun getTrafficStatsEnabled(): Boolean {
+            return (data?.proxy?.service as? VpnService)?.tun2socks?.trafficStatsEnabled ?: false
+        }
+
         override fun close() {
             callbacks.kill()
             cancel()

+ 5 - 1
app/src/main/java/io/nekohasekai/sagernet/bg/VpnService.kt

@@ -261,7 +261,9 @@ class VpnService : BaseVpnService(),
             true,
             DataStore.trafficSniffing,
             DataStore.enableFakeDns,
-            DataStore.enableLog
+            DataStore.enableLog,
+            data.proxy!!.config.dumpUid,
+            DataStore.trafficStatistics
         )
     }
 
@@ -272,6 +274,8 @@ class VpnService : BaseVpnService(),
     }
 
     fun persistAppStats() {
+        if (!DataStore.trafficStatistics) return
+
         appStats.clear()
         tun2socks.readAppTraffics(this)
         val toUpdate = mutableListOf<StatsEntity>()

+ 1 - 0
app/src/main/java/io/nekohasekai/sagernet/database/DataStore.kt

@@ -194,6 +194,7 @@ object DataStore : OnPreferenceDataStoreChangeListener {
     var alwaysShowAddress by configurationStore.boolean(Key.ALWAYS_SHOW_ADDRESS)
 
     var utlsFingerprint by configurationStore.string(Key.UTLS_FINGERPRINT)
+    var trafficStatistics by configurationStore.boolean(Key.TRAFFIC_STATISTICS)
 
     // protocol
 

+ 10 - 3
app/src/main/java/io/nekohasekai/sagernet/fmt/ConfigBuilder.kt

@@ -82,6 +82,7 @@ class V2rayBuildResult(
     var bypassTag: String,
     var enableApi: Boolean,
     var observatoryTags: Set<String>,
+    val dumpUid: Boolean,
     val alerts: List<Pair<Int, String>>,
 ) {
     data class IndexEntity(var isBalancer: Boolean, var chain: LinkedHashMap<Int, ProxyEntity>)
@@ -157,6 +158,7 @@ fun buildV2RayConfig(
     val requireHttp = !forTest && (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M || DataStore.requireHttp)
     val requireTransproxy = if (forTest) false else DataStore.requireTransproxy
     val ipv6Mode = if (forTest) IPv6Mode.ENABLE else DataStore.ipv6Mode
+    var dumpUid = false
     val alerts = mutableListOf<Pair<Int, String>>()
 
     return V2RayConfig().apply {
@@ -907,9 +909,12 @@ fun buildV2RayConfig(
         val foregroundDetectorServiceStarted = ForegroundDetectorService::class.isRunning()
 
         for (rule in extraRules) {
-            if ((rule.packages.isNotEmpty() || rule.appStatus.isNotEmpty()) && notVpn) {
-                alerts.add(0 to rule.displayName())
-                continue
+            if (rule.packages.isNotEmpty() || rule.appStatus.isNotEmpty()) {
+                dumpUid = true
+                if (notVpn) {
+                    alerts.add(0 to rule.displayName())
+                    continue
+                }
             }
             if (rule.appStatus.isNotEmpty() && !foregroundDetectorServiceStarted) {
                 alerts.add(1 to rule.displayName())
@@ -1190,6 +1195,7 @@ fun buildV2RayConfig(
             TAG_BYPASS,
             !it.api?.services.isNullOrEmpty(),
             it.observatory?.subjectSelector ?: HashSet(),
+            dumpUid,
             alerts
         )
     }
@@ -1327,6 +1333,7 @@ fun buildCustomConfig(proxy: ProxyEntity, port: Int): V2rayBuildResult {
         directTag,
         false,
         emptySet(),
+        false,
         emptyList()
     )
 

+ 12 - 0
app/src/main/java/io/nekohasekai/sagernet/ui/ActiveFragment.kt

@@ -29,8 +29,11 @@ import androidx.appcompat.widget.PopupMenu
 import androidx.core.view.isVisible
 import androidx.fragment.app.Fragment
 import androidx.recyclerview.widget.RecyclerView
+import io.nekohasekai.sagernet.Key
 import io.nekohasekai.sagernet.R
+import io.nekohasekai.sagernet.SagerNet
 import io.nekohasekai.sagernet.aidl.AppStats
+import io.nekohasekai.sagernet.database.DataStore
 import io.nekohasekai.sagernet.databinding.LayoutTrafficItemBinding
 import io.nekohasekai.sagernet.databinding.LayoutTrafficListBinding
 import io.nekohasekai.sagernet.ktx.*
@@ -47,6 +50,7 @@ class ActiveFragment : Fragment(R.layout.layout_traffic_list) {
         binding.trafficList.layoutManager = FixedLinearLayoutManager(binding.trafficList)
         binding.trafficList.adapter = adapter
         (parentFragment as TrafficFragment).listeners.add(::emitStats)
+        emitStats(emptyList())
     }
 
     fun emitStats(statsList: List<AppStats>) {
@@ -54,6 +58,14 @@ class ActiveFragment : Fragment(R.layout.layout_traffic_list) {
             runOnMainDispatcher {
                 binding.holder.isVisible = true
                 binding.trafficList.isVisible = false
+
+                if (!SagerNet.started || DataStore.serviceMode != Key.MODE_VPN) {
+                    binding.holder.text = getString(R.string.traffic_holder)
+                } else if ((activity as MainActivity).connection.service?.trafficStatsEnabled != true) {
+                    binding.holder.text = getString(R.string.statistics_disabled)
+                } else {
+                    binding.holder.text = getString(R.string.no_statistics)
+                }
             }
             binding.trafficList.post {
                 adapter.data = emptyList()

+ 6 - 0
app/src/main/java/io/nekohasekai/sagernet/ui/MainActivity.kt

@@ -375,6 +375,12 @@ class MainActivity : ThemedActivity(),
         binding.stats.changeState(state)
         if (msg != null) snackbar(getString(R.string.vpn_error, msg)).show()
         this.state = state
+
+        when (state) {
+            BaseService.State.Connected, BaseService.State.Stopped -> {
+                statsUpdated(emptyList())
+            }
+        }
     }
 
     override fun snackbarInternal(text: CharSequence): Snackbar {

+ 2 - 0
app/src/main/java/io/nekohasekai/sagernet/ui/SettingsPreferenceFragment.kt

@@ -200,6 +200,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
         }
 
         val utlsFingerprint = findPreference<SimpleMenuPreference>(Key.UTLS_FINGERPRINT)!!
+        val trafficStatistics = findPreference<SwitchPreference>(Key.TRAFFIC_STATISTICS)!!
 
         serviceMode.setOnPreferenceChangeListener { _, _ ->
             if (SagerNet.started) SagerNet.stopService()
@@ -243,6 +244,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
         providerShadowsocksAEAD.onPreferenceChangeListener = reloadListener
         providerShadowsocksStream.onPreferenceChangeListener = reloadListener
         utlsFingerprint.onPreferenceChangeListener = reloadListener
+        trafficStatistics.onPreferenceChangeListener = reloadListener
 
     }
 

+ 11 - 0
app/src/main/java/io/nekohasekai/sagernet/ui/StatsFragment.kt

@@ -29,8 +29,11 @@ import androidx.appcompat.widget.PopupMenu
 import androidx.core.view.isVisible
 import androidx.fragment.app.Fragment
 import androidx.recyclerview.widget.RecyclerView
+import io.nekohasekai.sagernet.Key
 import io.nekohasekai.sagernet.R
+import io.nekohasekai.sagernet.SagerNet
 import io.nekohasekai.sagernet.aidl.AppStats
+import io.nekohasekai.sagernet.database.DataStore
 import io.nekohasekai.sagernet.database.SagerDatabase
 import io.nekohasekai.sagernet.databinding.LayoutTrafficItemBinding
 import io.nekohasekai.sagernet.databinding.LayoutTrafficListBinding
@@ -74,6 +77,14 @@ class StatsFragment : Fragment(R.layout.layout_traffic_list) {
             runOnMainDispatcher {
                 binding.holder.isVisible = true
                 binding.trafficList.isVisible = false
+
+                if (!SagerNet.started || DataStore.serviceMode != Key.MODE_VPN) {
+                    binding.holder.text = getString(R.string.traffic_holder)
+                } else if ((activity as MainActivity).connection.service?.trafficStatsEnabled != true) {
+                    binding.holder.text = getString(R.string.statistics_disabled)
+                } else {
+                    binding.holder.text = getString(R.string.no_statistics)
+                }
             }
             binding.trafficList.post {
                 adapter.data = emptyList()

+ 1 - 1
app/src/main/res/layout/layout_traffic_list.xml

@@ -10,7 +10,7 @@
         android:id="@+id/holder"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:text="@string/traffic_holder"
+        android:text="@string/no_statistics"
         android:textAppearance="?android:attr/textAppearanceMedium"
         android:textColor="?android:attr/textColorPrimary" />
 

+ 5 - 0
app/src/main/res/values/strings.xml

@@ -441,4 +441,9 @@
     <string name="route_need_vpn">Routing rule %s relies on the VPN to be in effect, so it is ignored.</string>
     <string name="route_need_fds">Routing rule %s relies on the Foreground Detector Service to be in effect, but is not enabled.</string>
 
+    <string name="traffic_statistics">Enable Traffic Statistics</string>
+    <string name="traffic_statistics_summary">May increase power consumption</string>
+    <string name="no_statistics">No statistics yet</string>
+    <string name="statistics_disabled">Traffic statistics disabled</string>
+
 </resources>

+ 7 - 0
app/src/main/res/xml/global_preferences.xml

@@ -33,6 +33,13 @@
             app:key="serviceMode"
             app:title="@string/service_mode"
             app:useSimpleSummaryProvider="true" />
+
+        <SwitchPreference
+            app:icon="@drawable/ic_baseline_manage_search_24"
+            app:key="trafficStatistics"
+            app:summary="@string/traffic_statistics_summary"
+            app:title="@string/traffic_statistics" />
+
         <SwitchPreference
             app:icon="@drawable/ic_baseline_center_focus_weak_24"
             app:key="alwaysShowAddress"

+ 1 - 1
library/core

@@ -1 +1 @@
-Subproject commit 780f88c06897fcc6b7d06466251a78adce660d98
+Subproject commit e0727c374ac795ff16f83c4bb8ff5bff853368ac

+ 2 - 2
sager.properties

@@ -1,6 +1,6 @@
 PACKAGE_NAME=io.nekohasekai.sagernet
-VERSION_NAME=0.5-beta03
-VERSION_CODE=94
+VERSION_NAME=0.5-beta04
+VERSION_CODE=95
 
 NAIVE_VERSION_NAME=92.0.4515.107-1
 NAIVE_VERSION=3