BackupRepository.kt 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. package com.example.modifier.repo
  2. import android.annotation.SuppressLint
  3. import android.content.Context
  4. import android.util.Log
  5. import androidx.core.content.ContextCompat
  6. import com.example.modifier.baseTag
  7. import com.example.modifier.constants.CMD_MESSAGING_APP
  8. import com.example.modifier.constants.CMD_RCS_SETTINGS_ACTIVITY
  9. import com.example.modifier.constants.PACKAGE_GMS
  10. import com.example.modifier.constants.PACKAGE_GSF
  11. import com.example.modifier.constants.PACKAGE_MESSAGING
  12. import com.example.modifier.data.BackupItem
  13. import com.example.modifier.data.BackupItemDao
  14. import com.example.modifier.enums.RcsConfigureState
  15. import com.example.modifier.enums.ReqState
  16. import com.example.modifier.extension.clear
  17. import com.example.modifier.extension.disable
  18. import com.example.modifier.extension.enable
  19. import com.example.modifier.extension.kill
  20. import com.example.modifier.http.api.RcsNumberApi
  21. import com.example.modifier.model.SpoofedInfo
  22. import com.example.modifier.service.ModifierService
  23. import com.example.modifier.utils.ROOT_ACCESS
  24. import com.example.modifier.utils.clearConv
  25. import com.example.modifier.utils.genAndroidId
  26. import com.example.modifier.utils.genMacAddress
  27. import com.example.modifier.utils.genSerialNo
  28. import com.example.modifier.utils.getContext
  29. import com.example.modifier.utils.shellRun
  30. import kotlinx.coroutines.CoroutineScope
  31. import kotlinx.coroutines.delay
  32. import kotlinx.coroutines.launch
  33. import java.io.File
  34. import java.util.Date
  35. import java.util.Optional
  36. import kotlin.coroutines.coroutineContext
  37. import kotlin.time.Duration.Companion.minutes
  38. class BackupRepository(
  39. private val context: Context,
  40. private val dao: BackupItemDao,
  41. ) {
  42. companion object {
  43. private const val TAG = "$baseTag/BackupRepository"
  44. }
  45. suspend fun backup(type: String, sendCount: Int, stock: Int = 0): BackupItem? {
  46. if (!ROOT_ACCESS) return null
  47. AppStateRepo.instance.updateRuntimeFlags(reqState = ReqState.BACKUP)
  48. val spoofedInfoRepo = SpoofedInfoRepo.instance
  49. clearConv()
  50. delay(3000)
  51. // ModifierService.instance!!.toggleRcsSwitch(false)
  52. val context = getContext()
  53. val dest = File(
  54. ContextCompat.getExternalFilesDirs(context, "backup")[0],
  55. System.currentTimeMillis().toString()
  56. )
  57. dest.mkdirs()
  58. val packages = mutableListOf(
  59. PACKAGE_MESSAGING,
  60. PACKAGE_GMS,
  61. PACKAGE_GSF
  62. )
  63. packages.forEach {
  64. File(dest, it).mkdirs()
  65. }
  66. val cmds = mutableListOf<String>()
  67. for (pkg in packages) {
  68. if (!shellRun("ls /data/data/$pkg").second
  69. .contains("No such file or directory")
  70. ) {
  71. cmds.add("tar zcpf $dest/$pkg/data.tar.gz -C /data/data $pkg ")
  72. }
  73. if (!shellRun("ls /data/user_de/0/$pkg").second
  74. .contains("No such file or directory")
  75. ) {
  76. cmds.add("tar zcpf $dest/$pkg/data_de.tar.gz -C /data/user_de/0 $pkg ")
  77. }
  78. if (!shellRun("ls /sdcard/Android/data/$pkg").second
  79. .contains("No such file or directory")
  80. ) {
  81. cmds.add("tar zcpf $dest/$pkg/data_ext.tar.gz -C /sdcard/Android/data $pkg ")
  82. }
  83. }
  84. shellRun(*cmds.toTypedArray())
  85. val spoofedSimInfo = spoofedInfoRepo.spoofedInfo.value
  86. val backup = BackupItem(
  87. createdAt = Date().time,
  88. numberId = spoofedSimInfo.numberId,
  89. number = spoofedSimInfo.number,
  90. code = spoofedSimInfo.areaCode,
  91. country = spoofedSimInfo.country,
  92. mcc = spoofedSimInfo.mcc,
  93. mnc = spoofedSimInfo.mnc,
  94. imei = spoofedSimInfo.imei,
  95. imsi = spoofedSimInfo.imsi,
  96. iccid = spoofedSimInfo.iccid,
  97. path = dest.path,
  98. sendCount = sendCount,
  99. lastUse = Date().time,
  100. type = type,
  101. stock = stock,
  102. carrierId = Optional.ofNullable(spoofedSimInfo.carrierId).orElse("1"),
  103. carrierName = Optional.ofNullable(spoofedSimInfo.carrierName).orElse("T-Mobile"),
  104. retry = 0
  105. )
  106. dao.findBackupForNumber(spoofedSimInfo.country, spoofedSimInfo.number)?.let {
  107. File(it.path).deleteRecursively()
  108. backup.sendCount += it.sendCount
  109. backup.stock = it.stock
  110. dao.delete(it)
  111. }
  112. backup.id = dao.insert(backup).toInt()
  113. return backup
  114. }
  115. @SuppressLint("SdCardPath")
  116. suspend fun restore(backup: BackupItem): Boolean {
  117. val spoofedInfoRepo = SpoofedInfoRepo.instance
  118. val simInfo = SpoofedInfo(
  119. numberId = backup.numberId,
  120. number = backup.number,
  121. mcc = backup.mcc,
  122. mnc = backup.mnc,
  123. country = backup.country,
  124. areaCode = backup.code,
  125. iccid = backup.iccid,
  126. imei = backup.imei,
  127. imsi = backup.imsi,
  128. available = false,
  129. carrierId = backup.carrierId,
  130. carrierName = backup.carrierName,
  131. serialNo = genSerialNo(),
  132. wifiMac = genMacAddress(),
  133. bssid = genMacAddress(),
  134. btMac = genMacAddress(),
  135. ethMac = genMacAddress(),
  136. androidId = genAndroidId(),
  137. gmsAid = genAndroidId(),
  138. rootAid = genAndroidId()
  139. )
  140. spoofedInfoRepo.updateSpoofedSimInfo(spoofedInfo = simInfo, suspend = false)
  141. val packages = mutableListOf(
  142. PACKAGE_MESSAGING,
  143. PACKAGE_GMS,
  144. PACKAGE_GSF
  145. )
  146. shellRun(PACKAGE_MESSAGING.clear(), "sleep 2", PACKAGE_MESSAGING.disable())
  147. for (pkg in packages) {
  148. for (item in listOf("data.tar.gz", "data_de.tar.gz", "data_ext.tar.gz")) {
  149. val file = File("${backup.path}/$pkg/$item")
  150. if (!file.exists()) {
  151. continue
  152. }
  153. val dest = when (item) {
  154. "data.tar.gz" -> "/data/data"
  155. "data_de.tar.gz" -> "/data/user_de/0"
  156. "data_ext.tar.gz" -> "/sdcard/Android/data"
  157. else -> ""
  158. }
  159. shellRun(
  160. "find $dest/$pkg -type f -delete",
  161. "tar zxf ${file.path} -C $dest --exclude \"**/AndroidPlatformServices.apk\""
  162. )
  163. }
  164. }
  165. val taskRunner = ModifierService.instance?.taskRunner
  166. shellRun(
  167. // "sed -i 's/<boolean name=\"enable_rcs\" value=\"true\" \\/>/<boolean name=\"enable_rcs\" value=\"false\" \\/>/g' /data/data/com.google.android.apps.messaging/shared_prefs/bugle.xml",
  168. PACKAGE_GSF.kill(),
  169. "sleep 1",
  170. PACKAGE_GMS.kill(),
  171. "settings put secure location_mode 0",
  172. "pm revoke com.google.android.gms android.permission.GET_ACCOUNTS",
  173. "pm revoke com.google.android.gms android.permission.SYSTEM_ALERT_WINDOW",
  174. "pm revoke com.google.android.gms android.permission.POST_NOTIFICATIONS",
  175. "pm revoke com.google.android.gms android.permission.READ_CONTACTS",
  176. "pm revoke com.google.android.gms android.permission.CAMERA",
  177. "pm revoke com.google.android.gms android.permission.RECEIVE_MMS",
  178. "pm revoke com.google.android.gms android.permission.GET_APP_OPS_STATS",
  179. "pm revoke com.google.android.gms android.permission.PROCESS_OUTGOING_CALLS",
  180. "pm revoke com.google.android.gms android.permission.BLUETOOTH_CONNECT",
  181. "pm revoke com.google.android.gms android.permission.BLUETOOTH_SCAN",
  182. "pm revoke com.google.android.gms android.permission.BLUETOOTH_ADVERTISE",
  183. "pm revoke com.google.android.gms android.permission.NEARBY_WIFI_DEVICES",
  184. "pm revoke com.google.android.gms android.permission.UWB_RANGING",
  185. "pm revoke com.google.android.gms android.permission.READ_CALL_LOG",
  186. "pm revoke com.google.android.gms android.permission.WRITE_CONTACTS",
  187. "pm revoke com.google.android.gms android.permission.CALL_PHONE",
  188. "pm revoke com.google.android.gms android.permission.RECORD_AUDIO",
  189. "pm revoke com.google.android.gms android.permission.READ_LOGS",
  190. "pm revoke com.google.android.gms android.permission.READ_MEDIA_AUDIO",
  191. "pm revoke com.google.android.gms android.permission.READ_MEDIA_IMAGES",
  192. "pm revoke com.google.android.gms android.permission.READ_MEDIA_VIDEO",
  193. "pm revoke com.google.android.gms android.permission.ACCESS_MEDIA_LOCATION",
  194. "pm revoke com.google.android.gms android.permission.ACCESS_BROADCAST_RESPONSE_STATS",
  195. "pm revoke com.google.android.gms android.permission.WRITE_CALL_LOG",
  196. "pm revoke com.google.android.gms android.permission.BODY_SENSORS",
  197. "pm revoke com.google.android.gms android.permission.DUMP",
  198. "sleep 30",
  199. PACKAGE_MESSAGING.enable(),
  200. "sleep 1",
  201. CMD_MESSAGING_APP,
  202. "sleep 5",
  203. CMD_RCS_SETTINGS_ACTIVITY,
  204. "sleep 5",
  205. PACKAGE_MESSAGING.kill(),
  206. "sleep 1",
  207. CMD_MESSAGING_APP,
  208. "sleep 5",
  209. )
  210. var otp = false
  211. val success = run isSuccess@{
  212. if (backup.stock != 1) {
  213. return@isSuccess true
  214. }
  215. if (taskRunner == null) return@isSuccess false
  216. if (!taskRunner.screenController.toggleRcsSwitch(true)) {
  217. shellRun(
  218. PACKAGE_GMS.kill(),
  219. PACKAGE_MESSAGING.kill(),
  220. "sleep 5",
  221. CMD_MESSAGING_APP
  222. )
  223. delay(5000)
  224. if (!taskRunner.screenController.toggleRcsSwitch(true)) {
  225. return@isSuccess false
  226. }
  227. }
  228. val job = CoroutineScope(coroutineContext).launch {
  229. taskRunner.gmsgStateRepo.rcsConfigureState.collect {
  230. if (it == RcsConfigureState.RETRY) {
  231. shellRun(
  232. PACKAGE_GMS.kill(),
  233. "sleep 5",
  234. PACKAGE_MESSAGING.kill(),
  235. CMD_MESSAGING_APP
  236. )
  237. }
  238. }
  239. }
  240. val state = taskRunner.gmsgStateRepo.waitForRcsState(
  241. arrayOf(RcsConfigureState.CONFIGURED, RcsConfigureState.WAITING_FOR_OTP), 5.minutes
  242. )
  243. job.cancel()
  244. if (state == RcsConfigureState.CONFIGURED) return@isSuccess true
  245. if (state == RcsConfigureState.WAITING_FOR_OTP) otp = true
  246. false
  247. }
  248. if (success) {
  249. Log.i(TAG, "restore: success")
  250. spoofedInfoRepo.updateAvailable(available = true)
  251. if (backup.stock == 1) {
  252. backup.stock = 2
  253. dao.update(backup)
  254. RcsNumberApi.updateStockFlag(backup.numberId, 2)
  255. }
  256. return true
  257. } else {
  258. Log.i(TAG, "restore: failed")
  259. if (backup.stock == 1) {
  260. backup.retry++
  261. if (backup.retry >= 3 || otp) {
  262. RcsNumberApi.updateStockFlag(backup.numberId, 3)
  263. if (otp) {
  264. dao.delete(backup)
  265. } else {
  266. backup.stock = 3
  267. dao.update(backup)
  268. }
  269. } else {
  270. dao.update(backup)
  271. }
  272. }
  273. }
  274. return false
  275. }
  276. suspend fun delete(backupItem: BackupItem) {
  277. dao.delete(backupItem)
  278. }
  279. suspend fun findBackupForRestore(number: String): BackupItem? {
  280. return dao.findBackupForRestore(number)
  281. }
  282. suspend fun cleanBackup(start: Long, end: Long) {
  283. dao.findBackupsBetween(start, end).forEach {
  284. runCatching {
  285. File(it.path).deleteRecursively()
  286. }
  287. dao.delete(it)
  288. }
  289. }
  290. }