class VirtualApkCheckUtil private constructor() {
companion object {
const val TAG = "VirtualApkCheckUtil"
var portIndex = 0
var loopCount = 0
@Volatile
private var singleInstance: VirtualApkCheckUtil? = null
private var receiveJob: Job? = null
@JvmStatic
fun getSingleInstance(): VirtualApkCheckUtil {
if (singleInstance == null) {
synchronized(VirtualApkCheckUtil::class.java) {
if (singleInstance == null) {
singleInstance = VirtualApkCheckUtil()
}
}
}
return singleInstance!!
}
}
var virtualCheckCallback: ((String) -> Unit)? = null
/**
* 多开端口
*/
private val ports = intArrayOf(
50245,
51328,
52423,
53286,
54213,
55324
)
/**
* secret 检测的根据
* carry 携带的数据,会回传
*
*/
fun checkByPortListening(secret: String, carry: String) {
clearJob()
startSendJob(secret, carry)
//startClient(secret, callback)
//ServerThread(secret, callback).start()
}
private fun startSendJob(secret: String, carry: String) {
CoroutineScope(Dispatchers.Main).launch {
var flag = false
val job = async(Dispatchers.IO) {
flag = createSendJob(secret, carry)
flag
}
if (job.await()) {
job.cancel()
} else {
//clearJob()
receiveJob = launch(Dispatchers.IO) {
var serverSocket: ServerSocket? = null
try {
serverSocket = ServerSocket()
val hostName = "127.0.0.1"
val portEnable = ports[portIndex]
serverSocket.bind(
InetSocketAddress(
hostName,
portEnable
)
)
while (true) {
val socket = serverSocket.accept()
withContext(Dispatchers.IO) {
try {
var inputStream: InputStream? = null
var outputStream: OutputStream? = null
inputStream = socket.getInputStream()
outputStream = socket.getOutputStream()
val buffer = ByteArray(1024 * 4)
var temp = 0
while (inputStream.read(buffer).also { temp = it } != -1) {
val result = String(buffer, 0, temp)
if (result.contains(secret)) {
//Log.e(TAG, "收到secret: $secret")
outputStream.write(
"""$secret$carry
""".toByteArray(charset("utf-8"))
)
outputStream.flush()
socket.shutdownOutput()
}
}
inputStream.close()
outputStream.close()
socket.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
}
} catch (e: BindException) {
//Log.e(TAG, "BindException:${e.printStackTrace()}")
if (loopCount < 10) {
//最多循环10次
if (portIndex >= ports.size - 1) portIndex = 0 else portIndex++
startSendJob(secret, carry) //may be loop forever
loopCount++
}
} catch (e: IOException) {
e.printStackTrace()
}
}
}
}
}
private fun createSendJob(secret: String, carry: String): Boolean {
var flag = false
ports.forEach { port ->
try {
val socket = Socket("127.0.0.1", port)
socket.soTimeout = 2000
val outputStream = socket.getOutputStream()
outputStream.write(
"""$secret$carry
""".toByteArray(charset("utf-8"))
)
outputStream.flush()
val inputStream = socket.getInputStream()
val bufferedReader = BufferedReader(InputStreamReader(inputStream))
var info: String? = null
while (bufferedReader.readLine().also { info = it } != null) {
//Log.e(TAG, "ClientThread: $info")
flag = true
val userId = info!!.replace(secret, "")
if (!TextUtils.isEmpty(userId)) {
virtualCheckCallback?.invoke(userId)
break
}
}
bufferedReader.close()
inputStream.close()
outputStream.close()
socket.shutdownOutput()
socket.close()
} catch (e: ConnectException) {
e.printStackTrace()
//Log.e("VirtualApkCheckUtil", it.toString() + "port refused")
} catch (e: SocketException) {
e.printStackTrace()
} catch (e: UnknownHostException) {
e.printStackTrace()
} catch (e: UnsupportedEncodingException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
}
}
return flag
}
fun clearJob() {
receiveJob?.cancel()
}
}
使用
private fun startCheck() {
VirtualApkCheckUtil.getSingleInstance().apply {
virtualCheckCallback = {
try {
val cUserId = viewModel.getUserId()
val rUserId = it
if (!TextUtils.isEmpty(cUserId) && !TextUtils.isEmpty(rUserId) && cUserId != rUserId) {
val userIds = arrayOf(cUserId, rUserId)
//Timber.e("send userId:${viewModel.getUserId()}, receive userId:${it}")
viewModel.cheatLog(userIds.toList())
val intent =
Intent(RideLifeGCApp.context, CrashMultiOpenErrorActivity::class.java)
intent.flags =
Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
startActivity(intent)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
checkByPortListening(packageName, viewModel.getUserId())
}
}
退出登录后取消本次监听
VirtualApkCheckUtil.getSingleInstance().clearJob()