optimize code

This commit is contained in:
arm64v8a 2023-07-01 18:07:25 +09:00
parent d0c68e38ef
commit ad0dd1d63f
9 changed files with 133 additions and 164 deletions

View File

@ -6,8 +6,6 @@ import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.net.ConnectivityManager
import android.net.Network
@ -20,27 +18,21 @@ import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import go.Seq
import io.nekohasekai.sagernet.bg.SagerConnection
import io.nekohasekai.sagernet.bg.ServiceNotification
import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.database.SagerDatabase
import io.nekohasekai.sagernet.ktx.Logs
import io.nekohasekai.sagernet.ktx.runOnDefaultDispatcher
import io.nekohasekai.sagernet.ui.MainActivity
import io.nekohasekai.sagernet.utils.*
import kotlinx.coroutines.DEBUG_PROPERTY_NAME
import kotlinx.coroutines.DEBUG_PROPERTY_VALUE_ON
import libcore.BoxPlatformInterface
import libcore.Libcore
import libcore.NB4AInterface
import moe.matsuri.nb4a.NativeInterface
import moe.matsuri.nb4a.utils.JavaUtil
import moe.matsuri.nb4a.utils.LibcoreUtil
import moe.matsuri.nb4a.utils.cleanWebview
import java.net.InetSocketAddress
import androidx.work.Configuration as WorkConfiguration
class SagerNet : Application(),
BoxPlatformInterface,
WorkConfiguration.Provider, NB4AInterface {
WorkConfiguration.Provider {
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base)
@ -48,6 +40,8 @@ class SagerNet : Application(),
application = this
}
val nativeInterface = NativeInterface()
val externalAssets by lazy { getExternalFilesDir(null) ?: filesDir }
val process = JavaUtil.getProcessName()
val isMainProcess = process == BuildConfig.APPLICATION_ID
@ -81,12 +75,9 @@ class SagerNet : Application(),
externalAssets.absolutePath + "/",
DataStore.logBufSize,
DataStore.logLevel > 0,
this
nativeInterface, nativeInterface
)
// libbox: platform interface
Libcore.setBoxPlatformInterface(this)
if (isMainProcess) {
Theme.apply(this)
Theme.applyNightTheme()
@ -133,11 +124,6 @@ class SagerNet : Application(),
uiMode.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION
}
// /data/user_de available when not unlocked
val deviceStorage by lazy {
if (Build.VERSION.SDK_INT < 24) application else DeviceStorageApp(application)
}
val configureIntent: (Context) -> PendingIntent by lazy {
{
PendingIntent.getActivity(
@ -209,82 +195,4 @@ class SagerNet : Application(),
}
// libbox interface
override fun autoDetectInterfaceControl(fd: Int) {
DataStore.vpnService?.protect(fd)
}
override fun openTun(singTunOptionsJson: String, tunPlatformOptionsJson: String): Long {
if (DataStore.vpnService == null) {
throw Exception("no VpnService")
}
return DataStore.vpnService!!.startVpn(singTunOptionsJson, tunPlatformOptionsJson).toLong()
}
override fun useProcFS(): Boolean {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.Q
}
@RequiresApi(Build.VERSION_CODES.Q)
override fun findConnectionOwner(
ipProto: Int, srcIp: String, srcPort: Int, destIp: String, destPort: Int
): Int {
return connectivity.getConnectionOwnerUid(
ipProto, InetSocketAddress(srcIp, srcPort), InetSocketAddress(destIp, destPort)
)
}
override fun packageNameByUid(uid: Int): String {
PackageCache.awaitLoadSync()
if (uid <= 1000L) {
return "android"
}
val packageNames = PackageCache.uidMap[uid]
if (!packageNames.isNullOrEmpty()) for (packageName in packageNames) {
return packageName
}
error("unknown uid $uid")
}
override fun uidByPackageName(packageName: String): Int {
PackageCache.awaitLoadSync()
return PackageCache[packageName] ?: 0
}
// nb4a interface
override fun useOfficialAssets(): Boolean {
return DataStore.rulesProvider == 0
}
override fun selector_OnProxySelected(selectorTag: String, tag: String) {
if (selectorTag != "proxy") {
Logs.d("other selector: $selectorTag")
return
}
LibcoreUtil.resetAllConnections(true)
DataStore.baseService?.apply {
runOnDefaultDispatcher {
val id = data.proxy!!.config.profileTagMap
.filterValues { it == tag }.keys.firstOrNull() ?: -1
val ent = SagerDatabase.proxyDao.getById(id) ?: return@runOnDefaultDispatcher
// traffic & title
data.proxy?.apply {
looper?.selectMain(id)
displayProfileName = ServiceNotification.genTitle(ent)
data.notification?.postNotificationTitle(displayProfileName)
}
// post binder
data.binder.broadcast { b ->
b.cbSelectorUpdate(id)
}
}
}
}
}

View File

@ -1,6 +1,5 @@
package io.nekohasekai.sagernet.bg.proto
import android.os.Build
import android.os.SystemClock
import io.nekohasekai.sagernet.SagerNet
import io.nekohasekai.sagernet.bg.AbstractInstance
@ -117,10 +116,8 @@ abstract class BoxInstance(
override fun launch() {
// TODO move, this is not box
val context =
if (Build.VERSION.SDK_INT < 24 || SagerNet.user.isUserUnlocked) SagerNet.application else SagerNet.deviceStorage
val cache = File(context.cacheDir, "tmpcfg")
cache.mkdirs()
val cacheDir = File(SagerNet.application.cacheDir, "tmpcfg")
cacheDir.mkdirs()
for ((chain) in config.externalIndex) {
chain.entries.forEachIndexed { index, (port, profile) ->
@ -135,7 +132,7 @@ abstract class BoxInstance(
bean is TrojanGoBean -> {
val configFile = File(
cache, "trojan_go_" + SystemClock.elapsedRealtime() + ".json"
cacheDir, "trojan_go_" + SystemClock.elapsedRealtime() + ".json"
)
configFile.parentFile?.mkdirs()
configFile.writeText(config)
@ -150,7 +147,7 @@ abstract class BoxInstance(
bean is NaiveBean -> {
val configFile = File(
cache, "naive_" + SystemClock.elapsedRealtime() + ".json"
cacheDir, "naive_" + SystemClock.elapsedRealtime() + ".json"
)
configFile.parentFile?.mkdirs()
@ -161,7 +158,7 @@ abstract class BoxInstance(
if (bean.certificates.isNotBlank()) {
val certFile = File(
cache, "naive_" + SystemClock.elapsedRealtime() + ".crt"
cacheDir, "naive_" + SystemClock.elapsedRealtime() + ".crt"
)
certFile.parentFile?.mkdirs()
@ -180,7 +177,7 @@ abstract class BoxInstance(
bean is HysteriaBean -> {
val configFile = File(
cache, "hysteria_" + SystemClock.elapsedRealtime() + ".json"
cacheDir, "hysteria_" + SystemClock.elapsedRealtime() + ".json"
)
configFile.parentFile?.mkdirs()
@ -213,7 +210,7 @@ abstract class BoxInstance(
any as JSONObject
val name = any.getString("name")
val configFile = File(cache, name)
val configFile = File(cacheDir, name)
configFile.parentFile?.mkdirs()
val content = any.getString("content")
configFile.writeText(content)
@ -243,10 +240,8 @@ abstract class BoxInstance(
}
bean is TuicBean -> {
val configFile = File(
context.noBackupFilesDir,
"tuic_" + SystemClock.elapsedRealtime() + ".json"
)
val configFile =
File(cacheDir, "tuic_" + SystemClock.elapsedRealtime() + ".json")
configFile.parentFile?.mkdirs()
configFile.writeText(config)

View File

@ -422,24 +422,22 @@ fun buildConfig(
} catch (_: Exception) {
}
// domain_strategy
pastEntity?.requireBean()?.apply {
// don't loopback
if (currentDomainStrategy != "" && !serverAddress.isIpAddress()) {
domainListDNSDirectForce.add("full:$serverAddress")
}
}
currentOutbound["domain_strategy"] = if (forTest) "" else currentDomainStrategy
// custom JSON merge
if (bean.customOutboundJson.isNotBlank()) {
Util.mergeJSON(bean.customOutboundJson, currentOutbound)
}
}
pastEntity?.requireBean()?.apply {
// don't loopback
if (currentDomainStrategy != "" && !serverAddress.isIpAddress()) {
domainListDNSDirectForce.add("full:$serverAddress")
}
}
if (forTest) {
currentDomainStrategy = ""
}
currentOutbound["tag"] = tagOut
currentOutbound["domain_strategy"] = currentDomainStrategy
// External proxy need a dokodemo-door inbound to forward the traffic
// For external proxy software, their traffic must goes to v2ray-core to use protected fd.

View File

@ -1,20 +0,0 @@
package io.nekohasekai.sagernet.utils
import android.annotation.SuppressLint
import android.annotation.TargetApi
import android.app.Application
import android.content.Context
@SuppressLint("Registered")
@TargetApi(24)
class DeviceStorageApp(context: Context) : Application() {
init {
attachBaseContext(context.createDeviceProtectedStorageContext())
}
/**
* Thou shalt not get the REAL underlying application context which would no longer be operating under device
* protected storage.
*/
override fun getApplicationContext() = this
}

View File

@ -0,0 +1,96 @@
package moe.matsuri.nb4a
import android.os.Build
import androidx.annotation.RequiresApi
import io.nekohasekai.sagernet.SagerNet
import io.nekohasekai.sagernet.bg.ServiceNotification
import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.database.SagerDatabase
import io.nekohasekai.sagernet.ktx.Logs
import io.nekohasekai.sagernet.ktx.runOnDefaultDispatcher
import io.nekohasekai.sagernet.utils.PackageCache
import libcore.BoxPlatformInterface
import libcore.NB4AInterface
import moe.matsuri.nb4a.utils.LibcoreUtil
import java.net.InetSocketAddress
class NativeInterface : BoxPlatformInterface, NB4AInterface {
// libbox interface
override fun autoDetectInterfaceControl(fd: Int) {
DataStore.vpnService?.protect(fd)
}
override fun openTun(singTunOptionsJson: String, tunPlatformOptionsJson: String): Long {
if (DataStore.vpnService == null) {
throw Exception("no VpnService")
}
return DataStore.vpnService!!.startVpn(singTunOptionsJson, tunPlatformOptionsJson).toLong()
}
override fun useProcFS(): Boolean {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.Q
}
@RequiresApi(Build.VERSION_CODES.Q)
override fun findConnectionOwner(
ipProto: Int, srcIp: String, srcPort: Int, destIp: String, destPort: Int
): Int {
return SagerNet.connectivity.getConnectionOwnerUid(
ipProto, InetSocketAddress(srcIp, srcPort), InetSocketAddress(destIp, destPort)
)
}
override fun packageNameByUid(uid: Int): String {
PackageCache.awaitLoadSync()
if (uid <= 1000L) {
return "android"
}
val packageNames = PackageCache.uidMap[uid]
if (!packageNames.isNullOrEmpty()) for (packageName in packageNames) {
return packageName
}
error("unknown uid $uid")
}
override fun uidByPackageName(packageName: String): Int {
PackageCache.awaitLoadSync()
return PackageCache[packageName] ?: 0
}
// nb4a interface
override fun useOfficialAssets(): Boolean {
return DataStore.rulesProvider == 0
}
override fun selector_OnProxySelected(selectorTag: String, tag: String) {
if (selectorTag != "proxy") {
Logs.d("other selector: $selectorTag")
return
}
LibcoreUtil.resetAllConnections(true)
DataStore.baseService?.apply {
runOnDefaultDispatcher {
val id = data.proxy!!.config.profileTagMap
.filterValues { it == tag }.keys.firstOrNull() ?: -1
val ent = SagerDatabase.proxyDao.getById(id) ?: return@runOnDefaultDispatcher
// traffic & title
data.proxy?.apply {
looper?.selectMain(id)
displayProfileName = ServiceNotification.genTitle(ent)
data.notification?.postNotificationTitle(displayProfileName)
}
// post binder
data.binder.broadcast { b ->
b.cbSelectorUpdate(id)
}
}
}
}
}

View File

@ -1,5 +1,5 @@
if [ ! -z $ENV_NB4A ]; then
export COMMIT_SING_BOX_EXTRA="9400fd007ad5a19b5892a7c42aae0951e1163747"
export COMMIT_SING_BOX_EXTRA="3805838008319a97e4495f43e10a1d4c9c1e512a"
fi
if [ ! -z $ENV_SING_BOX_EXTRA ]; then

View File

@ -21,13 +21,10 @@ func init() {
D.RegisterTransport([]string{"underlying"}, createUnderlyingTransport)
}
// CreateUnderlyingTransport for Android
func createUnderlyingTransport(name string, ctx context.Context, logger logger.ContextLogger, dialer N.Dialer, link string) (D.Transport, error) {
return &androidUnderlyingTransportSing{name, underlyingResolver}, nil
}
//
type androidUnderlyingTransportSing struct {
name string
*androidUnderlyingTransport
@ -37,12 +34,10 @@ func (t *androidUnderlyingTransportSing) Name() string { return t.name }
//
var systemResolver = &net.Resolver{PreferGo: false} // Using System API, lookup from current network.
var underlyingResolver = &androidUnderlyingTransport{systemResolver: systemResolver} // Using System API, lookup from non-VPN network.
var systemResolver = &net.Resolver{PreferGo: false} // Using System API, lookup from current network.
var underlyingResolver = &androidUnderlyingTransport{} // Using System API, lookup from non-VPN network.
type androidUnderlyingTransport struct {
systemResolver *net.Resolver
}
type androidUnderlyingTransport struct{}
func (t *androidUnderlyingTransport) Start() error { return nil }
func (t *androidUnderlyingTransport) Close() error { return nil }
@ -96,7 +91,7 @@ func (t *androidUnderlyingTransport) Lookup(ctx context.Context, domain string,
ips = append(ips, netip.MustParseAddr(ip))
}
} else {
ips2, err2 := t.systemResolver.LookupIP(context.Background(), network, domain)
ips2, err2 := systemResolver.LookupIP(context.Background(), network, domain)
if err2 != nil {
err = err2
return

View File

@ -32,19 +32,17 @@ func ForceGc() {
go runtime.GC()
}
func SetLocalResolver(lr LocalResolver) {
localResolver = lr
}
func InitCore(process, cachePath, internalAssets, externalAssets string,
maxLogSizeKb int32, logEnable bool,
iif NB4AInterface,
if1 NB4AInterface, if2 BoxPlatformInterface,
) {
defer device.DeferPanicToError("InitCore", func(err error) { log.Println(err) })
isBgProcess := strings.HasSuffix(process, ":bg")
neko_common.RunMode = neko_common.RunMode_NekoBoxForAndroid
intfNB4A = iif
intfNB4A = if1
intfBox = if2
useProcfs = intfBox.UseProcFS()
// Working dir
tmp := filepath.Join(cachePath, "../no_backup")
@ -64,7 +62,7 @@ func InitCore(process, cachePath, internalAssets, externalAssets string,
boxmain.DisableColor()
// nekoutils
nekoutils.Selector_OnProxySelected = iif.Selector_OnProxySelected
nekoutils.Selector_OnProxySelected = intfNB4A.Selector_OnProxySelected
// Set up some component
go func() {

View File

@ -16,6 +16,10 @@ type LocalResolver interface {
var localResolver LocalResolver // Android: passed from java (only when VPNService)
func SetLocalResolver(lr LocalResolver) {
localResolver = lr
}
type BoxPlatformInterface interface {
AutoDetectInterfaceControl(fd int32) error
OpenTun(singTunOptionsJson, tunPlatformOptionsJson string) (int, error)
@ -24,8 +28,3 @@ type BoxPlatformInterface interface {
PackageNameByUid(uid int32) (string, error)
UIDByPackageName(packageName string) (int32, error)
}
func SetBoxPlatformInterface(iif BoxPlatformInterface) {
intfBox = iif
useProcfs = intfBox.UseProcFS()
}