service refactored

This commit is contained in:
Kr328 committed 2020-01-21 20:17:31 +08:00
1 parent c60d8cfb53
commit a29c95ceef
15 files changed
+115 -92

No files matched your search

@@ -39,12 +39,12 @@ class MainApplication : Application() {
private fun ByteArray.toHexString(): String {
return this.map {
Integer.toHexString(it.toInt() and 0xff)
}.map {
}.joinToString(separator = "") {
if (it.length < 2)
"0$it"
else
it
}.joinToString(separator = "")
}
}
}
@@ -68,40 +68,6 @@ class MainApplication : Application() {
Crashlytics.setBool(CRASHLYTICS_SPLIT_APK_KEY, detectSplitArchive())
Crashlytics.setString(CRASHLYTICS_BASE_SIZE_KEY, getBaseApkSize())
Crashlytics.setUserIdentifier(userIdentifier)
Log.handler = object : Log.LogHandler {
override fun info(message: String, throwable: Throwable?) {
android.util.Log.i(Constants.TAG, message, throwable)
}
override fun warn(message: String, throwable: Throwable?) {
throwable?.also {
Crashlytics.logException(it)
}
android.util.Log.w(Constants.TAG, message, throwable)
}
override fun error(message: String, throwable: Throwable?) {
throwable?.also {
Crashlytics.logException(it)
}
android.util.Log.e(Constants.TAG, message, throwable)
}
override fun wtf(message: String, throwable: Throwable?) {
throwable?.also {
Crashlytics.logException(it)
}
android.util.Log.wtf(Constants.TAG, message, throwable)
}
override fun debug(message: String, throwable: Throwable?) {
android.util.Log.d(Constants.TAG, message, throwable)
}
}
}
private fun detectFromPlay(): Boolean {
@@ -1,7 +1,6 @@
package com.github.kr328.clash.service
import android.content.Context
import android.content.SharedPreferences
import androidx.core.content.edit
import com.github.kr328.clash.core.Clash
import com.github.kr328.clash.core.model.General
@@ -9,7 +8,7 @@ import com.github.kr328.clash.core.model.ProxyGroup
import com.github.kr328.clash.service.ipc.ParcelableCompletedFuture
import com.github.kr328.clash.service.ipc.ParcelablePipe
class ClashManager(context: Context): IClashManager.Stub() {
class ClashManager(context: Context) : IClashManager.Stub() {
private val settings = context.getSharedPreferences("service", Context.MODE_PRIVATE)
override fun queryAllProxies(): Array<ProxyGroup> {
@@ -27,7 +26,7 @@ class ClashManager(context: Context): IClashManager.Stub() {
}
override fun openBandwidthEvent(): ParcelablePipe {
return object: ParcelablePipe() {
return object : ParcelablePipe() {
val stream = Clash.openBandwidthEvent().apply {
onEvent {
send(it)
@@ -45,7 +44,7 @@ class ClashManager(context: Context): IClashManager.Stub() {
return ParcelableCompletedFuture().apply {
Clash.startHealthCheck(group).whenComplete { _: Unit?, u: Throwable? ->
if ( u != null )
if (u != null)
this.completeExceptionally(u)
else
this.complete(null)
@@ -54,7 +53,7 @@ class ClashManager(context: Context): IClashManager.Stub() {
}
override fun openLogEvent(): ParcelablePipe {
return object: ParcelablePipe() {
return object : ParcelablePipe() {
val stream = Clash.openLogEvent().apply {
onEvent {
send(it)
@@ -17,8 +17,10 @@ class ClashProfileManager(private val context: Context, private val database: Cl
override fun updateProfile(id: Int): ParcelableCompletedFuture {
val entity = database.openClashProfileDao().queryProfileById(id)
require(entity != null && (entity.type == ClashProfileEntity.Type.URL ||
entity.type == ClashProfileEntity.Type.FILE))
require(
entity != null && (entity.type == ClashProfileEntity.Type.URL ||
entity.type == ClashProfileEntity.Type.FILE)
)
val result = ParcelableCompletedFuture()
@@ -1,13 +1,13 @@
package com.github.kr328.clash.service
import android.app.Service
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.content.*
import android.os.Binder
import android.os.IBinder
import com.github.kr328.clash.core.Clash
import com.github.kr328.clash.service.data.ClashDatabase
import com.github.kr328.clash.service.util.DefaultThreadPool
import com.github.kr328.clash.service.util.sendBroadcastSelf
class ClashService : Service() {
companion object {
@@ -25,16 +25,18 @@ class ClashService : Service() {
val tun = service.queryLocalInterface(TunService::class.java.name) as TunService
tun.startTun().whenComplete { _, u ->
if (u != null) {
stopReason = u.message
stopSelf()
return@whenComplete
}
if (u != null)
return@whenComplete stopSelf(u.message ?: "Start tun failure")
notification.setVpn(true)
}
}
}
private val profileObserver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
reloadProfile()
}
}
override fun onCreate() {
super.onCreate()
@@ -49,7 +51,7 @@ class ClashService : Service() {
Clash.start()
sendBroadcast(Intent(Intents.INTENT_ACTION_CLASH_STARTED))
sendBroadcastSelf(Intent(Intents.INTENT_ACTION_CLASH_STARTED))
val startVpn = intent?.getBooleanExtra(INTENT_EXTRA_START_TUN, true) ?: true
@@ -61,6 +63,10 @@ class ClashService : Service() {
Context.BIND_AUTO_CREATE
)
reloadProfile()
registerReceiver(profileObserver, IntentFilter(Intents.INTENT_ACTION_PROFILE_CHANGED))
return START_NOT_STICKY
}
@@ -77,15 +83,33 @@ class ClashService : Service() {
notification.destroy()
sendBroadcast(
sendBroadcastSelf(
Intent(Intents.INTENT_ACTION_CLASH_STOPPED)
.putExtra(Intents.INTENT_ACTION_CLASH_STOP_REASON, stopReason)
)
unregisterReceiver(profileObserver)
super.onDestroy()
}
private fun reloadProfile() {
DefaultThreadPool.submit {
val active = ClashDatabase.getInstance(this).openClashProfileDao().queryActiveProfile()
?: return@submit stopSelf("Empty active profile")
Clash.loadProfile(
filesDir.resolve(Constants.PROFILES_DIR).resolve(active.file),
filesDir.resolve(Constants.CLASH_DIR).resolve(active.base)
).whenComplete { _, u ->
if (u != null)
return@whenComplete stopSelf(u.message ?: "Load profile failure")
}
}
}
private fun stopSelf(reason: String) {
stopReason = reason
stopSelf()
}
}
@@ -1,8 +1,10 @@
package com.github.kr328.clash.service
object Constants {
const val CLASH_PROCESS_BROADCAST_ACTION = "com.github.kr328.clash.ClashService.ClashProcessEvent"
const val CLASH_RELOAD_BROADCAST_ACTION = "com.github.kr328.clash.ClashService.ProfileReloadEvent"
const val CLASH_PROCESS_BROADCAST_ACTION =
"com.github.kr328.clash.ClashService.ClashProcessEvent"
const val CLASH_RELOAD_BROADCAST_ACTION =
"com.github.kr328.clash.ClashService.ProfileReloadEvent"
const val CLASH_DIR = "clash"
const val PROFILES_DIR = "profiles"
@@ -1,9 +1,15 @@
package com.github.kr328.clash.service
object Intents {
const val INTENT_ACTION_BIND_TUN_SERVICE = "${BuildConfig.LIBRARY_PACKAGE_NAME}.intent.action.bind.tun"
const val INTENT_ACTION_CLASH_STARTED = "${BuildConfig.LIBRARY_PACKAGE_NAME}.intent.action.clash.started"
const val INTENT_ACTION_CLASH_STOPPED = "${BuildConfig.LIBRARY_PACKAGE_NAME}.intent.action.clash.stopped"
const val INTENT_ACTION_BIND_TUN_SERVICE =
"${BuildConfig.LIBRARY_PACKAGE_NAME}.intent.action.bind.tun"
const val INTENT_ACTION_CLASH_STARTED =
"${BuildConfig.LIBRARY_PACKAGE_NAME}.intent.action.clash.started"
const val INTENT_ACTION_CLASH_STOPPED =
"${BuildConfig.LIBRARY_PACKAGE_NAME}.intent.action.clash.stopped"
const val INTENT_ACTION_PROFILE_CHANGED =
"${BuildConfig.LIBRARY_PACKAGE_NAME}.intent.action.profile.changed"
const val INTENT_ACTION_CLASH_STOP_REASON = "${BuildConfig.LIBRARY_PACKAGE_NAME}.intent.extra.clash.stop.reason"
const val INTENT_ACTION_CLASH_STOP_REASON =
"${BuildConfig.LIBRARY_PACKAGE_NAME}.intent.extra.clash.stop.reason"
}
@@ -20,11 +20,11 @@ class Settings(private val clashManager: IClashManager) {
return clashManager.getSetting(key)
}
fun <T>get(setting: Setting<T>): T {
fun <T> get(setting: Setting<T>): T {
return setting.parseValue(get(setting.key))
}
fun <T>put(setting: Setting<T>, value: T) {
fun <T> put(setting: Setting<T>, value: T) {
put(setting.key, setting.valueToString(value))
}
@@ -34,41 +34,46 @@ class Settings(private val clashManager: IClashManager) {
fun valueToString(value: T): String
}
class BooleanSetting(override val key: String, private val def: Boolean): Setting<Boolean> {
class BooleanSetting(override val key: String, private val def: Boolean) : Setting<Boolean> {
override fun parseValue(value: String?): Boolean {
val v = value ?: return def
return v.toBoolean()
}
override fun valueToString(value: Boolean): String {
return value.toString()
}
}
class IntSetting(override val key: String, private val def: Int): Setting<Int> {
class IntSetting(override val key: String, private val def: Int) : Setting<Int> {
override fun parseValue(value: String?): Int {
val v = value ?: return def
return v.toIntOrNull() ?: def
}
override fun valueToString(value: Int): String {
return value.toString()
}
}
class StringSetting(override val key: String, val def: String): Setting<String> {
class StringSetting(override val key: String, val def: String) : Setting<String> {
override fun parseValue(value: String?): String {
return value ?: def
}
override fun valueToString(value: String): String {
return value
}
}
class PackageListSetting(override val key: String, private val def: List<String>): Setting<List<String>> {
class PackageListSetting(override val key: String, private val def: List<String>) :
Setting<List<String>> {
override fun parseValue(value: String?): List<String> {
val v = value ?: return def
return v.split(":")
}
override fun valueToString(value: List<String>): String {
return value.joinToString(":")
}
@@ -5,7 +5,11 @@ import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
@Database(version = 2, exportSchema = false, entities = [ClashProfileEntity::class, ClashProfileProxyEntity::class])
@Database(
version = 2,
exportSchema = false,
entities = [ClashProfileEntity::class, ClashProfileProxyEntity::class]
)
abstract class ClashDatabase : RoomDatabase() {
abstract fun openClashProfileDao(): ClashProfileDao
abstract fun openClashProfileProxyDao(): ClashProfileProxyDao
@@ -14,22 +14,25 @@ object ClashDatabaseMigrations {
database.execSQL("ALTER TABLE profiles RENAME TO _profiles")
database.execSQL("CREATE TABLE profiles(" +
"name TEXT NOT NULL, " +
"type INTEGER NOT NULL, " +
"uri TEXT NOT NULL, " +
"file TEXT NOT NULL, " +
"base TEXT NOT NULL" +
"active INTEGER NOT NULL, " +
"last_update INTEGER NOT NULL, " +
"id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)")
database.execSQL(
"CREATE TABLE profiles(" +
"name TEXT NOT NULL, " +
"type INTEGER NOT NULL, " +
"uri TEXT NOT NULL, " +
"file TEXT NOT NULL, " +
"base TEXT NOT NULL" +
"active INTEGER NOT NULL, " +
"last_update INTEGER NOT NULL, " +
"id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)"
)
val cursor = database.query("SELECT name, token, file, active, last_update FROM _profile")
val cursor =
database.query("SELECT name, token, file, active, last_update FROM _profile")
val random = SecureRandom()
val bases = mutableSetOf<Long>()
cursor.moveToFirst()
while ( !cursor.isAfterLast ) {
while (!cursor.isAfterLast) {
// old
val name = cursor.getString(0)
val token = cursor.getString(1)
@@ -46,7 +49,7 @@ object ClashDatabaseMigrations {
val uri = token.removePrefix("url|").removePrefix("file|")
var base = random.nextLong().absoluteValue
while ( bases.contains(base) )
while (bases.contains(base))
base = random.nextLong().absoluteValue
database.insert("profiles",
@@ -59,7 +62,7 @@ object ClashDatabaseMigrations {
put("active", active)
put("last_update", lastUpdate)
put("base", base.toString())
})
})
}
cursor.close()
@@ -41,7 +41,7 @@ data class ClashProfileEntity(
@TypeConverter
fun intToType(value: Int?): Type {
return when ( value ) {
return when (value) {
Type.URL.id -> Type.URL
Type.FILE.id -> Type.FILE
Type.UNKNOWN.id -> Type.UNKNOWN
@@ -2,13 +2,17 @@ package com.github.kr328.clash.service.data
import androidx.room.*
@Entity(tableName = "profile_select_proxies",
@Entity(
tableName = "profile_select_proxies",
indices = [Index("profile_id")],
foreignKeys = [ForeignKey(entity = ClashProfileEntity::class,
foreignKeys = [ForeignKey(
entity = ClashProfileEntity::class,
childColumns = ["profile_id"],
parentColumns = ["id"],
onDelete = ForeignKey.CASCADE,
onUpdate = ForeignKey.CASCADE)])
onUpdate = ForeignKey.CASCADE
)]
)
data class ClashProfileProxyEntity(
@ColumnInfo(name = "profile_id") val profileId: Int,
@ColumnInfo(name = "proxy") val proxy: String,
@@ -7,7 +7,7 @@ import java.util.concurrent.CompletableFuture
class ParcelableCompletedFuture private constructor(private val pipe: ParcelablePipe) :
CompletableFuture<Parcelable?>(), Parcelable {
constructor(): this(ParcelablePipe())
constructor() : this(ParcelablePipe())
constructor(parcel: Parcel) : this(
parcel.readParcelable<ParcelablePipe>(
ParcelableCompletedFuture::class.java.classLoader
@@ -16,17 +16,16 @@ class ParcelableCompletedFuture private constructor(private val pipe: Parcelable
pipe.onReceive {
val result = (it ?: throw NullPointerException()) as ParcelableResult
if ( result.exception != null ) {
if (result.exception != null) {
completeExceptionally(RemoteException(result.exception))
}
else {
} else {
complete(result.data)
}
}
}
override fun complete(value: Parcelable?): Boolean {
if ( super.complete(value) ) {
if (super.complete(value)) {
pipe.send(ParcelableResult(value, null))
return true
}
@@ -34,7 +33,7 @@ class ParcelableCompletedFuture private constructor(private val pipe: Parcelable
}
override fun completeExceptionally(ex: Throwable?): Boolean {
if ( super.completeExceptionally(ex) ) {
if (super.completeExceptionally(ex)) {
pipe.send(ParcelableResult(null, ex?.message ?: "Unknown"))
return true
}
@@ -3,7 +3,7 @@ package com.github.kr328.clash.service.ipc
import android.os.Parcel
import android.os.Parcelable
data class ParcelableResult(val data: Parcelable?, val exception: String?): Parcelable {
data class ParcelableResult(val data: Parcelable?, val exception: String?) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readParcelable(ParcelableResult::class.java.classLoader),
parcel.readString()
@@ -50,7 +50,8 @@ class DefaultNetworkObserver(val context: Context, val listener: (Network?) -> U
return try {
connectivity.allNetworks
.flatMap { network ->
connectivity.getNetworkCapabilities(network)?.let { listOf(it to network) } ?: emptyList()
connectivity.getNetworkCapabilities(network)?.let { listOf(it to network) }
?: emptyList()
}
.asSequence()
.filterNot {
@@ -0,0 +1,8 @@
package com.github.kr328.clash.service.util
import android.content.Context
import android.content.Intent
fun Context.sendBroadcastSelf(intent: Intent) {
this.sendBroadcast(intent.setPackage(this.packageName))
}