@@ -118,6 +118,10 @@ class APApplication : Application(), Thread.UncaughtExceptionHandler, ImageLoade
118118 const val PREF_BLOCK_KERNELPATCH_UPDATE = " block_kernelpatch_update"
119119 const val PREF_BLOCK_ANDROIDPATCH_UPDATE = " block_androidpatch_update"
120120 private const val SHOW_BACKUP_WARN = " show_backup_warning"
121+ private const val CRASH_COUNT_KEY = " fp_crash_count"
122+ private const val CRASH_TIMESTAMP_KEY = " fp_crash_timestamp"
123+ private const val CRASH_LOOP_THRESHOLD = 2
124+ private const val CRASH_WINDOW_MS = 30_000L
121125 lateinit var sharedPreferences: SharedPreferences
122126 var isSignatureValid = true // removed signature check, always valid
123127
@@ -222,17 +226,20 @@ class APApplication : Application(), Thread.UncaughtExceptionHandler, ImageLoade
222226 var superKey: String = " "
223227 set(value) {
224228 field = value
225- val ready = BuildConfig .DEBUG_FAKE_ROOT || Natives .nativeReady(value)
226- _kpStateLiveData .value =
227- if (ready) State .KERNELPATCH_INSTALLED else State .UNKNOWN_STATE
228- _apStateLiveData .value =
229- if (ready) State .ANDROIDPATCH_NOT_INSTALLED else State .UNKNOWN_STATE
230- Log .d(TAG , " state: " + _kpStateLiveData .value)
231- if (! ready) return
229+ // Run entire init chain on a background thread to avoid blocking main thread
230+ thread(name = " superkey-init" ) {
231+ val ready = BuildConfig .DEBUG_FAKE_ROOT || Natives .nativeReady(value)
232+ _kpStateLiveData .postValue(
233+ if (ready) State .KERNELPATCH_INSTALLED else State .UNKNOWN_STATE
234+ )
235+ _apStateLiveData .postValue(
236+ if (ready) State .ANDROIDPATCH_NOT_INSTALLED else State .UNKNOWN_STATE
237+ )
238+ Log .d(TAG , " state: " + _kpStateLiveData .value)
239+ if (! ready) return @thread
232240
233- APatchKeyHelper .writeSPSuperKey(value)
241+ APatchKeyHelper .writeSPSuperKey(value)
234242
235- thread {
236243 val rc = BuildConfig .DEBUG_FAKE_ROOT || Natives .su(0 , null )
237244 if (! rc) {
238245 Log .e(TAG , " Native.su failed" )
@@ -243,8 +250,6 @@ class APApplication : Application(), Thread.UncaughtExceptionHandler, ImageLoade
243250 APatchCli .refresh()
244251
245252 // KernelPatch version
246- // val buildV = Version.buildKPVUInt()
247- // val installedV = Version.installedKPVUInt()
248253 // use build time to check update
249254 val buildV = Version .getKpImg()
250255 val installedV = Version .installedKPTime()
@@ -258,10 +263,8 @@ class APApplication : Application(), Thread.UncaughtExceptionHandler, ImageLoade
258263
259264 if (buildV != installedV) {
260265 if (isBlocked) {
261- // 如果屏蔽更新,将状态设置为已安装而不是需要更新
262266 _kpStateLiveData .postValue(State .KERNELPATCH_INSTALLED )
263267 } else {
264- // 正常显示更新提示
265268 _kpStateLiveData .postValue(State .KERNELPATCH_NEED_UPDATE )
266269 }
267270 }
@@ -293,8 +296,6 @@ class APApplication : Application(), Thread.UncaughtExceptionHandler, ImageLoade
293296 _apStateLiveData .postValue(State .ANDROIDPATCH_NOT_INSTALLED )
294297 }
295298 Log .d(TAG , " ap state: " + _apStateLiveData .value)
296-
297- return @thread
298299 }
299300 }
300301 }
@@ -332,12 +333,26 @@ class APApplication : Application(), Thread.UncaughtExceptionHandler, ImageLoade
332333 APatchKeyHelper .setSharedPreferences(sharedPreferences)
333334 me.bmax.apatch.util.LauncherIconUtils .applySaved(this )
334335 Log .d(TAG , " Reading superKey..." )
335- val savedKey = APatchKeyHelper .readSPSuperKey()
336+ val savedKey = try {
337+ APatchKeyHelper .readSPSuperKey()
338+ } catch (e: Exception ) {
339+ Log .e(TAG , " Failed to read superKey from SharedPreferences" , e)
340+ null
341+ }
336342 if (! savedKey.isNullOrEmpty()) {
337343 superKey = savedKey
338344 } else {
339345 val keyFile = java.io.File (" /data/adb/folk_superkey" )
340- superKey = if (keyFile.exists()) keyFile.readText().trim() else " su"
346+ superKey = if (keyFile.exists()) {
347+ try {
348+ keyFile.readText().trim()
349+ } catch (e: Exception ) {
350+ Log .e(TAG , " Failed to read folk_superkey file" , e)
351+ " su"
352+ }
353+ } else {
354+ " su"
355+ }
341356 }
342357 Log .d(TAG , " superKey read completed, length=${superKey.length} " )
343358
@@ -368,6 +383,12 @@ class APApplication : Application(), Thread.UncaughtExceptionHandler, ImageLoade
368383 MusicManager .init (this )
369384
370385 Log .d(TAG , " APApplication onCreate completed" )
386+
387+ // Reset crash counter on successful initialization
388+ sharedPreferences.edit()
389+ .remove(CRASH_COUNT_KEY )
390+ .remove(CRASH_TIMESTAMP_KEY )
391+ .apply ()
371392 }
372393
373394 fun getBackupWarningState (): Boolean {
@@ -390,12 +411,31 @@ class APApplication : Application(), Thread.UncaughtExceptionHandler, ImageLoade
390411 val exceptionMessage = Log .getStackTraceString(e)
391412 val threadName = t.name
392413 Log .e(TAG , " Error on thread $threadName :\n $exceptionMessage " )
393- val intent = Intent (this , CrashHandleActivity ::class .java).apply {
394- putExtra(" exception_message" , exceptionMessage)
395- putExtra(" thread" , threadName)
396- flags = Intent .FLAG_ACTIVITY_NEW_TASK
414+
415+ val now = System .currentTimeMillis()
416+ val prefs = getSharedPreferences(SP_NAME , Context .MODE_PRIVATE )
417+ val lastCrashTime = prefs.getLong(CRASH_TIMESTAMP_KEY , 0L )
418+ val crashCount = if (now - lastCrashTime < CRASH_WINDOW_MS ) {
419+ prefs.getInt(CRASH_COUNT_KEY , 0 ) + 1
420+ } else {
421+ 1
422+ }
423+ prefs.edit()
424+ .putInt(CRASH_COUNT_KEY , crashCount)
425+ .putLong(CRASH_TIMESTAMP_KEY , now)
426+ .commit()
427+
428+ if (crashCount <= CRASH_LOOP_THRESHOLD ) {
429+ val intent = Intent (this , CrashHandleActivity ::class .java).apply {
430+ putExtra(" exception_message" , exceptionMessage)
431+ putExtra(" thread" , threadName)
432+ flags = Intent .FLAG_ACTIVITY_NEW_TASK
433+ }
434+ startActivity(intent)
435+ } else {
436+ Log .e(TAG , " Crash loop detected ($crashCount crashes in ${CRASH_WINDOW_MS } ms window). " +
437+ " Skipping CrashHandleActivity to prevent infinite loop." )
397438 }
398- startActivity(intent)
399439 exitProcess(10 )
400440 }
401441}
0 commit comments