yijianlianUI/app/src/main/java/com/yingmao/clash/levellog/LogcatService.kt

182 lines
6.3 KiB
Kotlin

package com.yingmao.clash.levellog
import android.app.PendingIntent
import android.app.Service
import android.content.ComponentName
import android.content.Intent
import android.content.ServiceConnection
import android.os.Binder
import android.os.Build
import android.os.IBinder
import android.os.IInterface
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationChannelCompat
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.cncat.vpn.common.compat.getColorCompat
import com.cncat.vpn.common.compat.pendingIntentFlags
import com.cncat.vpn.common.compat.startForegroundCompat
import com.cncat.vpn.common.util.intent
import com.cncat.vpn.core.model.LogMessage
import com.cncat.vpn.service.RemoteService
import com.cncat.vpn.service.remote.ILogObserver
import com.cncat.vpn.service.remote.IRemoteService
import com.cncat.vpn.service.remote.unwrap
import com.tencent.mmkv.MMKV
import com.yingmao.clash.R
import com.yingmao.clash.act.MainActivity
import com.yingmao.clash.act.SettingActivity
import com.yingmao.clash.app.MainApplication
import com.yingmao.clash.conf.BZYConstants
import com.yingmao.clash.util.Utils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.cancel
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.IOException
class LogcatService : Service(), CoroutineScope by CoroutineScope(Dispatchers.Default), IInterface {
private val connection = object : ServiceConnection {
override fun onServiceDisconnected(name: ComponentName?) {
Log.i("LogcatServiceClose","onServiceDisconnected::${name}")
stopSelf()
}
@RequiresApi(Build.VERSION_CODES.KITKAT)
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
Log.i("LogcatServiceConnect","onServiceConnected::${name}")
startObserver(service ?: return stopSelf())
}
}
override fun onCreate() {
super.onCreate()
running = true
createNotificationChannel()
showNotification()
bindService(RemoteService::class.intent, connection, BIND_AUTO_CREATE)
}
override fun onDestroy() {
cancel()
unbindService(connection)
stopForeground(true)
running = false
super.onDestroy()
}
override fun onBind(intent: Intent?): IBinder {
return this.asBinder()
}
override fun asBinder(): IBinder {
return object : Binder() {
override fun queryLocalInterface(descriptor: String): IInterface {
return this@LogcatService
}
}
}
@RequiresApi(Build.VERSION_CODES.KITKAT)
private fun startObserver(binder: IBinder) {
if (!binder.isBinderAlive)
return stopSelf()
launch(Dispatchers.IO) {
val service = binder.unwrap(IRemoteService::class).clash()
val channel = Channel<LogMessage>(CACHE_CAPACITY)
try {
MMKV.defaultMMKV().encode(BZYConstants.Companion.BehaviorLogSwitch, true)
val selectedName =
MMKV.defaultMMKV().decodeString(BZYConstants.Companion.NODE_SELECTED_NAME_KEY, "")
val equipmentModel = Utils.getEquipmentModel()
AppLog.i("LogcatService", "selectedName===>${selectedName}")
AppLog.i("LogcatService", "用户是否过期===>${checkExpire()}")
AppLog.i("LogcatService", "机型数据===>${equipmentModel}")
AppLog.i("LogcatService", "OAID===>${MainApplication.Companion.OAID}")
val observer = object : ILogObserver {
override fun newItem(log: LogMessage) {
channel.trySend(log)
}
}
service.setLogObserver(observer)
while (isActive) {
val msg = channel.receive()
AppLog.i("LogcatServiceMsg", "core msg===>${msg}")
}
} catch (e: IOException) {
Log.e("Write log file: $e", e.toString())
} finally {
withContext(NonCancellable) {
if (binder.isBinderAlive) {
service.setLogObserver(null)
}
stopSelf()
}
}
}
}
private fun createNotificationChannel() {
NotificationManagerCompat.from(this)
.createNotificationChannel(
NotificationChannelCompat.Builder(
CHANNEL_ID,
NotificationManagerCompat.IMPORTANCE_DEFAULT
).setName(getString(R.string.clash_logcat)).build()
)
}
private fun showNotification() {
val notification = NotificationCompat
.Builder(this, CHANNEL_ID)
.setSmallIcon(R.mipmap.oneclickconnection)
.setColor(getColorCompat(R.color.color_clash))
.setContentTitle(getString(R.string.clash_logcat))
.setContentText("采集中")
.setContentIntent(
PendingIntent.getActivity(
this,
R.id.nf_logcat_status,
MainActivity::class.intent
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP),
pendingIntentFlags(PendingIntent.FLAG_UPDATE_CURRENT)
)
)
.build()
startForegroundCompat(R.id.nf_logcat_status, notification)
}
companion object {
private const val CHANNEL_ID = "clash_logcat_channel_id"
private const val CACHE_CAPACITY = 129
var running: Boolean = false
}
private fun checkExpire(): Boolean {
val validPeriod = MMKV.defaultMMKV().decodeLong(BZYConstants.Companion.MMKV_KEY_VPN_VALID_PERIOD)
if (validPeriod > 0) {
val nowTime = System.currentTimeMillis();
com.cncat.vpn.common.log.Log.d("validPeriod==>$validPeriod, nowTime==>$nowTime")
if (validPeriod >= nowTime) {
return false
}
}
return true
}
}