TaskRunner.kt 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839
  1. package com.example.modifier.service
  2. import android.content.Context
  3. import android.os.Build
  4. import android.os.Environment
  5. import android.util.Log
  6. import android.view.accessibility.AccessibilityNodeInfo
  7. import androidx.core.content.ContextCompat
  8. import coil3.ImageLoader
  9. import coil3.request.crossfade
  10. import com.example.modifier.baseTag
  11. import com.example.modifier.TraverseResult
  12. import com.example.modifier.Utils
  13. import com.example.modifier.constants.CMD_BACK
  14. import com.example.modifier.constants.CMD_CONVERSATION_LIST_ACTIVITY
  15. import com.example.modifier.constants.CMD_MESSAGING_APP
  16. import com.example.modifier.constants.CMD_RCS_SETTINGS_ACTIVITY
  17. import com.example.modifier.constants.PACKAGE_GMS
  18. import com.example.modifier.constants.PACKAGE_MESSAGING
  19. import com.example.modifier.enums.RcsConfigureState
  20. import com.example.modifier.enums.RcsConnectionStatus
  21. import com.example.modifier.enums.ReqState
  22. import com.example.modifier.exception.RequestNumberException
  23. import com.example.modifier.exception.RequestNumberException.Companion.ErrorCode
  24. import com.example.modifier.extension.kill
  25. import com.example.modifier.http.api.DeviceApi
  26. import com.example.modifier.http.api.RcsNumberApi
  27. import com.example.modifier.http.api.SysConfigApi
  28. import com.example.modifier.http.downloadImage
  29. import com.example.modifier.http.ktorClient
  30. import com.example.modifier.http.response.SysConfigResponse
  31. import com.example.modifier.model.InstallApkAction
  32. import com.example.modifier.model.RunScriptAction
  33. import com.example.modifier.model.SpoofedSimInfo
  34. import com.example.modifier.model.TaskAction
  35. import com.example.modifier.model.TaskConfig
  36. import com.example.modifier.model.TaskExecutionResult
  37. import com.example.modifier.model.UpdateDeviceAction
  38. import com.example.modifier.repo.AppPrefsRepo
  39. import com.example.modifier.repo.AppStateRepo
  40. import com.example.modifier.repo.BackupRepository
  41. import com.example.modifier.repo.GmsgStateRepo
  42. import com.example.modifier.repo.SpoofedSimInfoRepo
  43. import com.example.modifier.utils.clearConv
  44. import com.example.modifier.utils.genICCID
  45. import com.example.modifier.utils.genIMEI
  46. import com.example.modifier.utils.genIMSI
  47. import com.example.modifier.utils.genMacAddress
  48. import com.example.modifier.utils.genSerialNo
  49. import com.example.modifier.utils.getContext
  50. import com.example.modifier.utils.isOldVersion
  51. import com.example.modifier.utils.resetAll
  52. import com.example.modifier.utils.shellRun
  53. import com.example.modifier.utils.smsIntent
  54. import com.example.modifier.utils.injectOTP
  55. import io.ktor.client.HttpClient
  56. import io.ktor.client.call.body
  57. import io.ktor.client.engine.okhttp.OkHttp
  58. import io.ktor.client.plugins.HttpResponseValidator
  59. import io.ktor.client.plugins.ServerResponseException
  60. import io.ktor.client.plugins.resources.get
  61. import io.ktor.client.request.prepareGet
  62. import io.ktor.utils.io.ByteReadChannel
  63. import io.ktor.utils.io.core.isEmpty
  64. import io.ktor.utils.io.core.readBytes
  65. import kotlinx.coroutines.CancellationException
  66. import kotlinx.coroutines.CoroutineScope
  67. import kotlinx.coroutines.Dispatchers
  68. import kotlinx.coroutines.Job
  69. import kotlinx.coroutines.delay
  70. import kotlinx.coroutines.isActive
  71. import kotlinx.coroutines.launch
  72. import kotlinx.coroutines.withContext
  73. import kotlinx.coroutines.withTimeout
  74. import kotlinx.coroutines.withTimeoutOrNull
  75. import org.apache.commons.lang3.RandomStringUtils
  76. import java.io.File
  77. import java.time.LocalDateTime
  78. import java.time.temporal.ChronoUnit
  79. import kotlin.coroutines.coroutineContext
  80. import kotlin.time.Duration.Companion.hours
  81. import kotlin.time.Duration.Companion.minutes
  82. import kotlin.time.Duration.Companion.seconds
  83. class TaskRunner(
  84. private val context: Context,
  85. private val screenInspector: ScreenInspector,
  86. val screenController: ScreenController,
  87. private val appStateRepo: AppStateRepo,
  88. private val appPrefsRepo: AppPrefsRepo,
  89. private val spoofedSimInfoRepo: SpoofedSimInfoRepo,
  90. val gmsgStateRepo: GmsgStateRepo,
  91. private val backupRepository: BackupRepository
  92. ) {
  93. companion object {
  94. private const val TAG = "$baseTag/TaskRunner"
  95. }
  96. private var lastSend = 0L
  97. private var currentTaskId = 0
  98. private var requestMode = 1
  99. private var storeNumberJob: Job? = null
  100. private val imageLoader = ImageLoader.Builder(context)
  101. .crossfade(true)
  102. .build()
  103. suspend fun send(
  104. to: String,
  105. body: String?,
  106. img: String?,
  107. taskConfig: TaskConfig
  108. ): Boolean {
  109. Log.i(TAG, "Sending SMS to $to: $body")
  110. var imgFile: File? = null
  111. if (img?.isNotBlank() == true) {
  112. imgFile = downloadImage(img)
  113. }
  114. context.startActivity(smsIntent(to, body, imgFile))
  115. try {
  116. Log.i(TAG, "Command executed successfully, waiting for app to open...")
  117. delay(1000)
  118. var success = false
  119. var traverseResult = TraverseResult()
  120. withTimeoutOrNull(taskConfig.rcsWait) {
  121. repeat(999) {
  122. traverseResult = TraverseResult()
  123. screenInspector.traverseNode(traverseResult)
  124. if (traverseResult.isRcsCapable && traverseResult.sendBtn != null) {
  125. return@withTimeoutOrNull
  126. }
  127. delay(200)
  128. }
  129. }
  130. if (traverseResult.isRcsCapable && traverseResult.sendBtn != null && taskConfig.e2ee > 0) {
  131. withTimeoutOrNull(taskConfig.e2eeTimeout) {
  132. repeat(999) {
  133. traverseResult = TraverseResult()
  134. screenInspector.traverseNode(traverseResult)
  135. if (traverseResult.encrypted) {
  136. return@withTimeoutOrNull
  137. }
  138. delay(200)
  139. }
  140. }
  141. }
  142. if (traverseResult.isRcsCapable) {
  143. if (traverseResult.sendBtn == null) {
  144. Log.i(TAG, "Send button not found")
  145. } else if (taskConfig.e2ee == 2 && !traverseResult.encrypted) {
  146. Log.i(TAG, "E2EE not detected")
  147. } else {
  148. Log.i(TAG, "Clicking send button")
  149. val dt = System.currentTimeMillis() - lastSend
  150. if (taskConfig.rcsInterval > 0 && dt < taskConfig.rcsInterval) {
  151. Log.i(TAG, "Waiting for RCS interval")
  152. delay(taskConfig.rcsInterval - dt)
  153. }
  154. traverseResult.sendBtn!!.performAction(AccessibilityNodeInfo.ACTION_CLICK)
  155. lastSend = System.currentTimeMillis()
  156. success = true
  157. }
  158. } else {
  159. Log.i(TAG, "RCS not detected")
  160. }
  161. appStateRepo.incrementExecutedNum(
  162. success = success,
  163. num = if (img?.isNotBlank() == true && body?.isNotBlank() == true) 2 else 1
  164. )
  165. Log.i(
  166. TAG,
  167. "executedNum: ${appStateRepo.appState.value.executedNum}, successNum: ${appStateRepo.appState.value.successNum}"
  168. )
  169. delay(2000)
  170. return success
  171. } catch (e: Exception) {
  172. e.printStackTrace()
  173. }
  174. return false
  175. }
  176. suspend fun runTask(
  177. taskAction: TaskAction,
  178. onSuccess: (List<TaskExecutionResult>) -> Unit,
  179. onError: (Exception) -> Unit
  180. ) {
  181. if (appStateRepo.appState.value.busy) {
  182. onError(Exception("device busy"))
  183. return
  184. }
  185. try {
  186. val taskConfig = taskAction.data.config
  187. currentTaskId = taskAction.data.taskId
  188. requestMode = if (taskAction.data.config.useBackup) 2 else 1
  189. if (!spoofedSimInfoRepo.spoofedSimInfo.value.available ||
  190. (taskAction.data.config.checkConnection && appStateRepo.appState.value.executedNum == 0)
  191. ) {
  192. appStateRepo.updateRuntimeFlags(checkingConnection = true)
  193. if (!spoofedSimInfoRepo.spoofedSimInfo.value.available || !checkRcsA10y()) {
  194. onError(Exception("RCS not available"))
  195. requestNumberOnTask()
  196. appStateRepo.updateRuntimeFlags(checkingConnection = false)
  197. return
  198. }
  199. appStateRepo.updateRuntimeFlags(checkingConnection = false)
  200. }
  201. appStateRepo.updateRuntimeFlags(running = true, checkingConnection = false)
  202. val results = mutableListOf<TaskExecutionResult>()
  203. for (i in 0 until taskAction.data.tasks.size) {
  204. val taskItem = taskAction.data.tasks[i]
  205. val result = TaskExecutionResult(
  206. id = taskItem.id,
  207. numberId = spoofedSimInfoRepo.spoofedSimInfo.value.numberId
  208. )
  209. results.add(result)
  210. try {
  211. gmsgStateRepo.addToWatchList(result)
  212. result.sent = send(taskItem.number, taskItem.message, taskItem.img, taskConfig)
  213. } catch (e: Exception) {
  214. Log.e(TAG, "runTaskError: ${e.message}", e)
  215. }
  216. }
  217. shellRun(CMD_BACK)
  218. delay(5000)
  219. onSuccess(results)
  220. if (taskConfig.requestNumberInterval in 1..appStateRepo.appState.value.successNum) {
  221. delay(3000)
  222. requestNumberOnTask()
  223. } else if (taskConfig.cleanCount in 1..appStateRepo.appState.value.executedNum && !appPrefsRepo.appPrefs.value.preventClean) {
  224. delay(3000)
  225. clearConv();
  226. shellRun(CMD_MESSAGING_APP)
  227. delay(3000)
  228. appStateRepo.resetExecutedNum()
  229. } else {
  230. delay(2000)
  231. }
  232. appStateRepo.updateRuntimeFlags(running = false)
  233. if (taskAction.data.config.checkConnection && results.none { it.sent }) {
  234. appStateRepo.updateRuntimeFlags(checkingConnection = true)
  235. if (!checkRcsA10y()) {
  236. onError(Exception("RCS not available"))
  237. requestNumberOnTask()
  238. }
  239. appStateRepo.updateRuntimeFlags(checkingConnection = false)
  240. }
  241. } catch (e: Exception) {
  242. Log.e(TAG, "runTaskError: ${e.message}", e)
  243. onError(e)
  244. appStateRepo.updateRuntimeFlags(running = false)
  245. }
  246. }
  247. suspend fun reset() {
  248. val context = getContext()
  249. val dir = ContextCompat.getExternalCacheDirs(context)[0]
  250. // val pifPath = File(dir, "pif1.json").path
  251. // Utils.copyAsset(context.assets, "pif1.json", pifPath)
  252. // shellRun("cp $pifPath /data/adb/pif.json")
  253. if (isOldVersion(context)) {
  254. withTimeout(1.hours) {
  255. while (true) {
  256. delay(100)
  257. appStateRepo.updateRuntimeFlags(reqState = ReqState.RESET)
  258. gmsgStateRepo.updateRcsState(RcsConfigureState.NOT_CONFIGURED)
  259. spoofedSimInfoRepo.mock()
  260. resetAll()
  261. var switchAppear = gmsgStateRepo.waitForRcsState(
  262. arrayOf(RcsConfigureState.WAITING_FOR_TOS),
  263. 2.minutes
  264. )?.let {
  265. it == RcsConfigureState.WAITING_FOR_TOS
  266. }
  267. if (switchAppear != true) {
  268. shellRun(
  269. PACKAGE_GMS.kill(), PACKAGE_MESSAGING.kill(), "sleep 1",
  270. CMD_MESSAGING_APP
  271. )
  272. switchAppear = gmsgStateRepo.waitForRcsState(
  273. arrayOf(RcsConfigureState.WAITING_FOR_TOS),
  274. 3.minutes
  275. )?.let {
  276. it == RcsConfigureState.WAITING_FOR_TOS
  277. }
  278. if (switchAppear != true) {
  279. shellRun(
  280. PACKAGE_GMS.kill(), PACKAGE_MESSAGING.kill(), "sleep 1",
  281. CMD_MESSAGING_APP
  282. )
  283. switchAppear = gmsgStateRepo.waitForRcsState(
  284. arrayOf(RcsConfigureState.WAITING_FOR_TOS),
  285. 2.minutes
  286. )?.let {
  287. it == RcsConfigureState.WAITING_FOR_TOS
  288. }
  289. if (switchAppear != true) {
  290. Log.e(TAG, "RCS not entered default on state, retrying...")
  291. continue
  292. }
  293. }
  294. }
  295. if (!screenController.toggleRcsSwitch(false)) {
  296. Log.e(TAG, "RCS switch not turned off, retrying...")
  297. continue
  298. }
  299. if (!screenController.toggleRcsSwitch(true)) {
  300. Log.e(TAG, "RCS switch not turned on, retrying...")
  301. continue
  302. }
  303. var resetSuccess = gmsgStateRepo.waitForRcsState(
  304. arrayOf(
  305. RcsConfigureState.READY
  306. ), 30.seconds
  307. ).let { it == RcsConfigureState.READY }
  308. if (!resetSuccess) {
  309. screenController.toggleRcsSwitch(false)
  310. delay(1000)
  311. screenController.toggleRcsSwitch(true)
  312. resetSuccess = gmsgStateRepo.waitForRcsState(
  313. arrayOf(
  314. RcsConfigureState.READY
  315. ), 1.minutes
  316. ).let { it == RcsConfigureState.READY }
  317. }
  318. Log.i(TAG, "waitForRcsState: $resetSuccess")
  319. appStateRepo.resetRequestedNum()
  320. if (resetSuccess) {
  321. delay(3000)
  322. break
  323. }
  324. }
  325. }
  326. } else {
  327. withTimeout(1.hours) {
  328. while (true) {
  329. delay(100)
  330. appStateRepo.updateRuntimeFlags(reqState = ReqState.RESET)
  331. gmsgStateRepo.updateRcsState(RcsConfigureState.NOT_CONFIGURED)
  332. spoofedSimInfoRepo.mock()
  333. resetAll()
  334. var switchAppear = gmsgStateRepo.waitForRcsState(
  335. arrayOf(RcsConfigureState.WAITING_FOR_DEFAULT_ON),
  336. 1.minutes
  337. )?.let {
  338. it == RcsConfigureState.WAITING_FOR_DEFAULT_ON
  339. }
  340. if (switchAppear != true) {
  341. shellRun(
  342. PACKAGE_GMS.kill(), PACKAGE_MESSAGING.kill(), "sleep 1",
  343. CMD_MESSAGING_APP
  344. )
  345. switchAppear = gmsgStateRepo.waitForRcsState(
  346. arrayOf(RcsConfigureState.WAITING_FOR_DEFAULT_ON),
  347. 2.minutes
  348. )?.let {
  349. it == RcsConfigureState.WAITING_FOR_DEFAULT_ON
  350. }
  351. if (switchAppear != true) {
  352. Log.e(TAG, "RCS not entered default on state, retrying...")
  353. continue
  354. }
  355. }
  356. val switchOn = screenController.toggleRcsSwitch(true)
  357. if (!switchOn) {
  358. Log.e(TAG, "RCS switch not turned on, retrying...")
  359. continue
  360. }
  361. var resetSuccess = gmsgStateRepo.waitForRcsState(
  362. arrayOf(
  363. RcsConfigureState.READY
  364. ), 30.seconds
  365. ).let { it == RcsConfigureState.READY }
  366. if (!resetSuccess) {
  367. screenController.toggleRcsSwitch(false)
  368. delay(1000)
  369. screenController.toggleRcsSwitch(true)
  370. resetSuccess = gmsgStateRepo.waitForRcsState(
  371. arrayOf(
  372. RcsConfigureState.READY
  373. ), 1.minutes
  374. ).let { it == RcsConfigureState.READY }
  375. }
  376. Log.i(TAG, "waitForRcsState: $resetSuccess")
  377. appStateRepo.resetRequestedNum()
  378. if (resetSuccess) {
  379. delay(1000)
  380. break
  381. }
  382. }
  383. }
  384. }
  385. appStateRepo.updateRuntimeFlags(reqState = ReqState.NONE)
  386. // shellRun("rm /data/adb/pif.json")
  387. }
  388. private suspend fun requestNumberAtomic(store: Boolean? = false) {
  389. appStateRepo.updateRuntimeFlags(reqState = ReqState.REQUEST)
  390. gmsgStateRepo.updateRcsState(RcsConfigureState.NOT_CONFIGURED)
  391. val device = DeviceApi.getDevice(appPrefsRepo.appPrefs.value.id)
  392. val rcsNumber = RcsNumberApi.getRcsNumber(
  393. deviceId = appPrefsRepo.appPrefs.value.id,
  394. taskId = currentTaskId,
  395. pinCountry = device.pinCountry,
  396. store = store
  397. )
  398. Log.i(TAG, "requestNumber response: $rcsNumber")
  399. appStateRepo.updateRuntimeFlags(reqState = ReqState.OTP_1)
  400. spoofedSimInfoRepo.updateSpoofedSimInfo(
  401. SpoofedSimInfo(
  402. numberId = rcsNumber.id,
  403. number = rcsNumber.number,
  404. mcc = rcsNumber.mcc,
  405. mnc = rcsNumber.mnc,
  406. iccid = genICCID(rcsNumber.mnc, rcsNumber.areaCode),
  407. imsi = genIMSI(rcsNumber.mcc + rcsNumber.mnc),
  408. imei = spoofedSimInfoRepo.spoofedSimInfo.value.imei,
  409. country = rcsNumber.country,
  410. areaCode = rcsNumber.areaCode,
  411. available = false,
  412. carrierId = rcsNumber.carrierId,
  413. carrierName = rcsNumber.carrierName,
  414. serialNo = spoofedSimInfoRepo.spoofedSimInfo.value.serialNo,
  415. mac = genMacAddress(),
  416. bssid = genMacAddress()
  417. )
  418. )
  419. shellRun(CMD_MESSAGING_APP)
  420. if (rcsNumber.expiryTime.isBefore(LocalDateTime.now())) {
  421. throw RequestNumberException(ErrorCode.CODE_NUMBER_EXPIRED)
  422. }
  423. val tosAgreeJob = CoroutineScope(coroutineContext).launch {
  424. run tos@{
  425. repeat(60 * 1000 / 200) {
  426. delay(500)
  427. val traverseResult = TraverseResult()
  428. screenInspector.traverseNode(traverseResult)
  429. if (traverseResult.tosAgreeBtn != null) {
  430. traverseResult.tosAgreeBtn!!.performAction(AccessibilityNodeInfo.ACTION_CLICK)
  431. return@tos
  432. }
  433. }
  434. }
  435. }
  436. var sendOtpTimeout =
  437. ChronoUnit.SECONDS.between(LocalDateTime.now(), rcsNumber.expiryTime).seconds
  438. if (sendOtpTimeout < 5.seconds) {
  439. throw RequestNumberException(ErrorCode.CODE_TIMEOUT_TOO_SHORT)
  440. }
  441. if (sendOtpTimeout > 2.minutes) {
  442. sendOtpTimeout = 2.minutes
  443. }
  444. if (gmsgStateRepo.waitForRcsState(
  445. arrayOf(RcsConfigureState.WAITING_FOR_OTP),
  446. sendOtpTimeout
  447. ) != RcsConfigureState.WAITING_FOR_OTP
  448. ) {
  449. tosAgreeJob.cancel()
  450. if (!screenController.toggleRcsSwitch(true)) {
  451. throw RequestNumberException(ErrorCode.CODE_RCS_TOGGLED_OFF)
  452. }
  453. if (RcsConfigureState.REPLAY_REQUEST == gmsgStateRepo.rcsConfigureState.value) {
  454. throw RequestNumberException(ErrorCode.CODE_REPLAY_RETRY)
  455. }
  456. throw RequestNumberException(ErrorCode.CODE_OTP_NOT_SENT)
  457. }
  458. tosAgreeJob.cancel()
  459. RcsNumberApi.notifyOtpState(rcsNumber.id)
  460. if (rcsNumber.expiryTime.isBefore(LocalDateTime.now())) {
  461. throw RequestNumberException(ErrorCode.CODE_NUMBER_EXPIRED)
  462. }
  463. appStateRepo.updateRuntimeFlags(reqState = ReqState.OTP_2)
  464. val otp = RcsNumberApi.waitForOtp(rcsNumber.id)
  465. ?: throw RequestNumberException(ErrorCode.CODE_OTP_NOT_RECEIVED)
  466. appStateRepo.updateRuntimeFlags(reqState = ReqState.CONFIG)
  467. val configured = run configuring@{
  468. repeat(2) {
  469. injectOTP(otp)
  470. val state =
  471. gmsgStateRepo.waitForRcsState(
  472. arrayOf(
  473. RcsConfigureState.CONFIGURED,
  474. RcsConfigureState.RETRY
  475. ), 60.seconds
  476. )
  477. when (state) {
  478. RcsConfigureState.CONFIGURED -> {
  479. return@configuring true
  480. }
  481. RcsConfigureState.RETRY -> {
  482. gmsgStateRepo.waitForRcsState(
  483. arrayOf(RcsConfigureState.WAITING_FOR_OTP),
  484. 60.seconds
  485. )
  486. }
  487. else -> {
  488. }
  489. }
  490. }
  491. false
  492. }
  493. if (!configured) {
  494. throw RequestNumberException(ErrorCode.CODE_OTP_VERIFY_FAILED)
  495. } else {
  496. RcsNumberApi.notifyConfigured(rcsNumber.id)
  497. delay(4000)
  498. shellRun(
  499. PACKAGE_GMS.kill(),
  500. "sleep 2",
  501. PACKAGE_MESSAGING.kill(),
  502. "sleep 1",
  503. CMD_MESSAGING_APP
  504. )
  505. delay(2000)
  506. }
  507. Build.getSerial()
  508. }
  509. suspend fun requestNumberOnTask(reset: Boolean = false, noBackup: Boolean = false) {
  510. appStateRepo.updateRuntimeFlags(suspended = false)
  511. if (appPrefsRepo.appPrefs.value.preventRequest) {
  512. return
  513. }
  514. if (appStateRepo.appState.value.reqState != ReqState.NONE) {
  515. return
  516. }
  517. appStateRepo.updateRuntimeFlags(reqState = ReqState.CLEAN)
  518. clearConv()
  519. if (spoofedSimInfoRepo.spoofedSimInfo.value.available) {
  520. backupRepository.backup(
  521. type = "auto",
  522. sendCount = appStateRepo.appState.value.successNum
  523. )
  524. }
  525. var needRest = reset
  526. val requestSuccess = withTimeoutOrNull(2.hours) {
  527. while (true) {
  528. delay(200)
  529. try {
  530. if (requestMode == 2 && !noBackup) {
  531. val backup = backupRepository.findBackupForRestore(
  532. spoofedSimInfoRepo.spoofedSimInfo.value.number
  533. )
  534. if (backup != null) {
  535. AppStateRepo.instance.updateRuntimeFlags(reqState = ReqState.RESTORE)
  536. if (backupRepository.restore(backup)) {
  537. return@withTimeoutOrNull true
  538. } else {
  539. continue
  540. }
  541. }
  542. }
  543. needRest = needRest || appStateRepo.appState.value.requestedNum >= 3
  544. if (needRest && !appPrefsRepo.appPrefs.value.preventReset) {
  545. reset()
  546. needRest = false
  547. }
  548. appStateRepo.incrementRequestedNum()
  549. requestNumberAtomic()
  550. return@withTimeoutOrNull true
  551. } catch (e: Exception) {
  552. if (e is RequestNumberException) {
  553. Log.e(TAG, "requestNumberError: ${e.message}")
  554. } else {
  555. Log.e(TAG, "requestNumberError: ${e.message}", e)
  556. }
  557. }
  558. }
  559. false
  560. }
  561. if (requestSuccess == true) {
  562. spoofedSimInfoRepo.updateAvailable(available = true)
  563. appStateRepo.resetSuccessNum()
  564. appStateRepo.resetExecutedNum()
  565. Log.i(TAG, "requestNumber success")
  566. } else {
  567. Log.e(TAG, "requestNumber failed")
  568. appStateRepo.updateSend(false)
  569. }
  570. appStateRepo.updateRuntimeFlags(
  571. reqState = ReqState.NONE,
  572. suspended = requestSuccess != true
  573. )
  574. appStateRepo.incrementRequestedNum()
  575. }
  576. private suspend fun checkRcsConnectivity(): Boolean = run checkRcsConnection@{
  577. repeat(3) {
  578. Log.i(TAG, "Checking RCS status...")
  579. shellRun(
  580. CMD_CONVERSATION_LIST_ACTIVITY,
  581. CMD_RCS_SETTINGS_ACTIVITY,
  582. "sleep 1",
  583. )
  584. val res = TraverseResult()
  585. screenInspector.traverseNode(res)
  586. if (res.rcsConnectionStatus == RcsConnectionStatus.CONNECTED) {
  587. Log.i(TAG, "RCS is connected")
  588. shellRun(CMD_BACK)
  589. return@checkRcsConnection true
  590. } else {
  591. Log.i(TAG, "RCS not connected, retrying...")
  592. }
  593. shellRun(CMD_BACK, "sleep ${it * 2}")
  594. }
  595. false
  596. }
  597. suspend fun checkRcsA10y(timeout: Int = 7500, repeatNum: Int = 2): Boolean {
  598. val availability = run checkA10y@{
  599. repeat(repeatNum) {
  600. val rcsConnected = checkRcsConnectivity()
  601. if (rcsConnected) {
  602. val checkRcsA10yNumbers = mutableListOf<String>()
  603. try {
  604. val config = ktorClient
  605. .get(SysConfigApi.Id(SysConfigApi(), "check_availability_numbers"))
  606. .body<SysConfigResponse>()
  607. Log.i(TAG, "sysConfig response: $config")
  608. checkRcsA10yNumbers.addAll(config.value.split(",").map { it.trim() })
  609. } catch (exception: Exception) {
  610. Log.e(TAG, "sysConfig Error: ${exception.message}", exception)
  611. }
  612. if (checkRcsA10yNumbers.isEmpty()) {
  613. Log.e(TAG, "checkRcsA10yNumbers is empty")
  614. return@checkA10y true
  615. }
  616. checkRcsA10yNumbers.forEach {
  617. context.startActivity(smsIntent(it, "", null))
  618. repeat(timeout / 200) {
  619. delay(200)
  620. val traverseResult = TraverseResult()
  621. screenInspector.traverseNode(traverseResult)
  622. if (traverseResult.isRcsCapable) {
  623. return@checkA10y true
  624. } else {
  625. Log.i(TAG, "checkRcsA10y: RCS not detected")
  626. }
  627. }
  628. }
  629. }
  630. shellRun(PACKAGE_MESSAGING.kill(), CMD_MESSAGING_APP, "sleep 5")
  631. }
  632. false
  633. }
  634. if (!availability) {
  635. RcsNumberApi.notifyWasted(spoofedSimInfoRepo.spoofedSimInfo.value.numberId)
  636. }
  637. return availability
  638. }
  639. suspend fun installApk(
  640. installApkAction: InstallApkAction,
  641. onSuccess: () -> Unit,
  642. onError: (Exception) -> Unit
  643. ) {
  644. try {
  645. val file = withContext(Dispatchers.IO) {
  646. File.createTempFile(
  647. "temp",
  648. ".apk",
  649. Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
  650. )
  651. }
  652. HttpClient(OkHttp) {
  653. HttpResponseValidator {
  654. validateResponse { response ->
  655. if (response.status.value !in 200..299) {
  656. throw ServerResponseException(
  657. response,
  658. "Error " + response.status.value.toString()
  659. )
  660. }
  661. }
  662. }
  663. }.prepareGet(installApkAction.data.apkUrl)
  664. .execute { httpResponse ->
  665. val channel: ByteReadChannel = httpResponse.body()
  666. while (!channel.isClosedForRead) {
  667. val packet = channel.readRemaining(DEFAULT_BUFFER_SIZE.toLong())
  668. while (!packet.isEmpty) {
  669. val bytes = packet.readBytes()
  670. file.appendBytes(bytes)
  671. }
  672. }
  673. }
  674. Log.i(TAG, "Apk file saved to ${file.path}")
  675. val installPath = "/data/local/tmp/${RandomStringUtils.randomAlphabetic(8)}.apk"
  676. shellRun(
  677. "cp ${file.path} $installPath",
  678. "pm install -d -r $installPath",
  679. "rm -f $installPath"
  680. )
  681. onSuccess()
  682. file.delete()
  683. } catch (e: Exception) {
  684. Log.e(TAG, "Failed to install apk", e)
  685. onError(e)
  686. }
  687. }
  688. suspend fun runScript(
  689. installApkAction: RunScriptAction,
  690. onSuccess: (String, String) -> Unit,
  691. onError: (Exception) -> Unit
  692. ) {
  693. try {
  694. val (out, err) = shellRun(*installApkAction.data.script.split("\n").toTypedArray())
  695. onSuccess(out, err)
  696. } catch (e: Exception) {
  697. Log.e(TAG, "Failed to run script", e)
  698. onError(e)
  699. }
  700. }
  701. suspend fun updateDevice(
  702. updateDeviceAction: UpdateDeviceAction,
  703. onSuccess: () -> Unit,
  704. onError: (Exception) -> Unit
  705. ) {
  706. try {
  707. if (updateDeviceAction.data.id != null) {
  708. appPrefsRepo.updateId(updateDeviceAction.data.id)
  709. }
  710. if (updateDeviceAction.data.name != null) {
  711. appPrefsRepo.updateName(updateDeviceAction.data.name)
  712. }
  713. onSuccess()
  714. } catch (e: Exception) {
  715. Log.e(TAG, "Failed to update device", e)
  716. onError(e)
  717. }
  718. }
  719. suspend fun storeNumbers(n: Int? = null) {
  720. if (storeNumberJob != null) {
  721. Log.e(TAG, "storeNumbers: another store number job is running")
  722. return
  723. }
  724. val num = n ?: appPrefsRepo.appPrefs.value.storeNum
  725. if (num <= 0) {
  726. Log.e(TAG, "storeNumbers: storeNum is 0")
  727. return
  728. }
  729. storeNumberJob = CoroutineScope(coroutineContext).launch {
  730. try {
  731. appStateRepo.updateRuntimeFlags(storing = true)
  732. if (spoofedSimInfoRepo.spoofedSimInfo.value.available && appStateRepo.appState.value.successNum <= 5) {
  733. screenController.toggleRcsSwitch(false)
  734. backupRepository.backup(
  735. type = "auto",
  736. sendCount = appStateRepo.appState.value.successNum,
  737. stock = 1
  738. )
  739. screenController.toggleRcsSwitch(true)
  740. }
  741. var success = true
  742. repeat(num) {
  743. if (!isActive) {
  744. Log.e(TAG, "storeNumbers: job is cancelled, stopping repeat")
  745. return@launch
  746. }
  747. Log.i(TAG, "storeNumbers: $it")
  748. try {
  749. if ((success || appStateRepo.appState.value.requestedNum > 3)
  750. && !(it == 0 && appStateRepo.appState.value.requestedNum == 0)
  751. ) {
  752. reset()
  753. }
  754. requestNumberAtomic(store = true)
  755. spoofedSimInfoRepo.updateAvailable(available = true)
  756. screenController.toggleRcsSwitch(false)
  757. backupRepository.backup(type = "auto", sendCount = 0, stock = 1)
  758. RcsNumberApi.updateStockFlag(
  759. id = spoofedSimInfoRepo.spoofedSimInfo.value.numberId,
  760. flag = 1
  761. )
  762. success = true
  763. } catch (e: CancellationException) {
  764. Log.e(TAG, "storeNumbers: job is cancelled", e)
  765. } catch (e: Exception) {
  766. success = false
  767. Log.e(TAG, "Error store number", e)
  768. }
  769. appStateRepo.incrementRequestedNum()
  770. }
  771. if (success) {
  772. reset()
  773. }
  774. appStateRepo.updateRuntimeFlags(
  775. reqState = ReqState.NONE,
  776. storing = false
  777. )
  778. storeNumberJob = null
  779. } catch (e: CancellationException) {
  780. Log.e(TAG, "storeNumbers: job is cancelled", e)
  781. }
  782. }
  783. }
  784. suspend fun cancelStoreNumber() {
  785. if (storeNumberJob != null) {
  786. if (storeNumberJob!!.isActive) {
  787. storeNumberJob!!.cancel()
  788. }
  789. appStateRepo.updateRuntimeFlags(
  790. reqState = ReqState.NONE,
  791. storing = false
  792. )
  793. storeNumberJob = null
  794. }
  795. }
  796. suspend fun cleanBackup(start: Long, end: Long) {
  797. backupRepository.cleanBackup(start, end)
  798. }
  799. }