TaskRunner.kt 34 KB

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