mirror of
				https://github.com/recloudstream/cloudstream.git
				synced 2024-08-15 01:53:11 +00:00 
			
		
		
		
	add safe mode that disabled extensions on crash
This commit is contained in:
		
							parent
							
								
									461f3d75d8
								
							
						
					
					
						commit
						93b176e3cd
					
				
					 4 changed files with 85 additions and 13 deletions
				
			
		|  | @ -4,11 +4,13 @@ import android.app.Activity | |||
| import android.app.Application | ||||
| import android.content.Context | ||||
| import android.content.ContextWrapper | ||||
| import android.content.Intent | ||||
| import android.widget.Toast | ||||
| import androidx.fragment.app.Fragment | ||||
| import com.google.auto.service.AutoService | ||||
| import com.lagradost.cloudstream3.mvvm.normalSafeApiCall | ||||
| import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall | ||||
| import com.lagradost.cloudstream3.plugins.PluginManager | ||||
| import com.lagradost.cloudstream3.utils.AppUtils.openBrowser | ||||
| import com.lagradost.cloudstream3.utils.Coroutines.runOnMainThread | ||||
| import com.lagradost.cloudstream3.utils.DataStore.getKey | ||||
|  | @ -17,6 +19,7 @@ import com.lagradost.cloudstream3.utils.DataStore.removeKey | |||
| import com.lagradost.cloudstream3.utils.DataStore.removeKeys | ||||
| import com.lagradost.cloudstream3.utils.DataStore.setKey | ||||
| import kotlinx.coroutines.runBlocking | ||||
| import org.acra.ACRA | ||||
| import org.acra.ReportField | ||||
| import org.acra.config.CoreConfiguration | ||||
| import org.acra.data.CrashReportData | ||||
|  | @ -24,8 +27,14 @@ import org.acra.data.StringFormat | |||
| import org.acra.ktx.initAcra | ||||
| import org.acra.sender.ReportSender | ||||
| import org.acra.sender.ReportSenderFactory | ||||
| import java.io.File | ||||
| import java.io.FileNotFoundException | ||||
| import java.io.PrintStream | ||||
| import java.lang.Exception | ||||
| import java.lang.ref.WeakReference | ||||
| import kotlin.concurrent.thread | ||||
| import kotlin.system.exitProcess | ||||
| 
 | ||||
| 
 | ||||
| class CustomReportSender : ReportSender { | ||||
|     // Sends all your crashes to google forms | ||||
|  | @ -65,7 +74,33 @@ class CustomSenderFactory : ReportSenderFactory { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| class ExceptionHandler(val errorFile: File, val onError: (() -> Unit)): Thread.UncaughtExceptionHandler { | ||||
|     override fun uncaughtException(thread: Thread, error: Throwable) { | ||||
|         ACRA.errorReporter.handleException(error) | ||||
|         try { | ||||
|             PrintStream(errorFile).use { ps -> | ||||
|                 ps.println(String.format("Currently loading extension: ${PluginManager.currentlyLoading ?: "none"}")) | ||||
|                 ps.println(String.format("Fatal exception on thread %s (%d)", thread.name, thread.id)) | ||||
|                 error.printStackTrace(ps) | ||||
|             } | ||||
|         } catch (ignored: FileNotFoundException) { } | ||||
|         try { | ||||
|             onError.invoke() | ||||
|         } catch (ignored: Exception) { } | ||||
|         exitProcess(1) | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| class AcraApplication : Application() { | ||||
|     override fun onCreate() { | ||||
|         super.onCreate() | ||||
|         Thread.setDefaultUncaughtExceptionHandler(ExceptionHandler(filesDir.resolve("last_error")){ | ||||
|             val intent = context!!.packageManager.getLaunchIntentForPackage(context!!.packageName) | ||||
|             startActivity(Intent.makeRestartActivityTask(intent!!.component)) | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     override fun attachBaseContext(base: Context?) { | ||||
|         super.attachBaseContext(base) | ||||
|         context = base | ||||
|  |  | |||
|  | @ -10,7 +10,9 @@ import android.view.KeyEvent | |||
| import android.view.Menu | ||||
| import android.view.MenuItem | ||||
| import android.view.WindowManager | ||||
| import android.widget.Toast | ||||
| import androidx.annotation.IdRes | ||||
| import androidx.appcompat.app.AlertDialog | ||||
| import androidx.appcompat.app.AppCompatActivity | ||||
| import androidx.core.view.isVisible | ||||
| import androidx.navigation.NavController | ||||
|  | @ -88,6 +90,7 @@ import kotlinx.coroutines.sync.Mutex | |||
| import kotlinx.coroutines.sync.withLock | ||||
| import java.io.File | ||||
| import java.net.URI | ||||
| import java.nio.charset.Charset | ||||
| import kotlin.reflect.KClass | ||||
| 
 | ||||
| 
 | ||||
|  | @ -455,6 +458,13 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { | |||
|     override fun onCreate(savedInstanceState: Bundle?) { | ||||
|         app.initClient(this) | ||||
|         val settingsManager = PreferenceManager.getDefaultSharedPreferences(this) | ||||
| 
 | ||||
|         val errorFile = filesDir.resolve("last_error") | ||||
|         var lastError: String? = null | ||||
|         if (errorFile.exists() && errorFile.isFile) { | ||||
|             lastError = errorFile.readText(Charset.defaultCharset()) | ||||
|             errorFile.delete() | ||||
|         } | ||||
|          | ||||
|         val settingsForProvider = SettingsJson() | ||||
|         settingsForProvider.enableAdult = settingsManager.getBoolean(getString(R.string.enable_nsfw_on_providers_key), false) | ||||
|  | @ -482,26 +492,44 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { | |||
| 
 | ||||
|         changeStatusBarState(isEmulatorSettings()) | ||||
| 
 | ||||
|         ioSafe { | ||||
|             getKey<String>(USER_SELECTED_HOMEPAGE_API)?.let { homeApi -> | ||||
|                 mainPluginsLoadedEvent.invoke(loadSinglePlugin(this@MainActivity, homeApi)) | ||||
|             } ?: run { | ||||
|                 mainPluginsLoadedEvent.invoke(false) | ||||
|             } | ||||
| 
 | ||||
|         if (lastError == null) { | ||||
|             ioSafe { | ||||
|                 if (settingsManager.getBoolean(getString(R.string.auto_update_plugins_key), true)) { | ||||
|                     PluginManager.updateAllOnlinePluginsAndLoadThem(this@MainActivity) | ||||
|                 } else { | ||||
|                     PluginManager.loadAllOnlinePlugins(this@MainActivity) | ||||
|                 getKey<String>(USER_SELECTED_HOMEPAGE_API)?.let { homeApi -> | ||||
|                     mainPluginsLoadedEvent.invoke(loadSinglePlugin(this@MainActivity, homeApi)) | ||||
|                 } ?: run { | ||||
|                     mainPluginsLoadedEvent.invoke(false) | ||||
|                 } | ||||
| 
 | ||||
|                 ioSafe { | ||||
|                     if (settingsManager.getBoolean(getString(R.string.auto_update_plugins_key), true)) { | ||||
|                         PluginManager.updateAllOnlinePluginsAndLoadThem(this@MainActivity) | ||||
|                     } else { | ||||
|                         PluginManager.loadAllOnlinePlugins(this@MainActivity) | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 ioSafe { | ||||
|                     PluginManager.loadAllLocalPlugins(this@MainActivity) | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             val builder: AlertDialog.Builder = AlertDialog.Builder(this) | ||||
|             builder.setTitle(R.string.safe_mode_title) | ||||
|             builder.setMessage(R.string.safe_mode_description) | ||||
|             builder.apply { | ||||
|                 setPositiveButton(R.string.safe_mode_crash_info) { _, _ -> | ||||
|                     val tbBuilder: AlertDialog.Builder = AlertDialog.Builder(context) | ||||
|                     tbBuilder.setTitle(R.string.safe_mode_title) | ||||
|                     tbBuilder.setMessage(lastError) | ||||
|                     tbBuilder.show() | ||||
|                 } | ||||
| 
 | ||||
|             ioSafe { | ||||
|                 PluginManager.loadAllLocalPlugins(this@MainActivity) | ||||
|                 setNegativeButton("Ok") { _, _ -> } | ||||
|             } | ||||
|             builder.show() | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
| //        ioSafe { | ||||
| //            val plugins = | ||||
| //                RepositoryParser.getRepoPlugins("https://raw.githubusercontent.com/recloudstream/TestPlugin/master/repo.json") | ||||
|  |  | |||
|  | @ -127,6 +127,8 @@ object PluginManager { | |||
|     private val LOCAL_PLUGINS_PATH = | ||||
|         Environment.getExternalStorageDirectory().absolutePath + "/Cloudstream3/plugins" | ||||
| 
 | ||||
|     public var currentlyLoading: String? = null | ||||
| 
 | ||||
|     // Maps filepath to plugin | ||||
|     val plugins: MutableMap<String, Plugin> = | ||||
|         LinkedHashMap<String, Plugin>() | ||||
|  | @ -283,6 +285,7 @@ object PluginManager { | |||
|     private suspend fun loadPlugin(activity: Activity, file: File, data: PluginData): Boolean { | ||||
|         val fileName = file.nameWithoutExtension | ||||
|         val filePath = file.absolutePath | ||||
|         currentlyLoading = fileName | ||||
|         Log.i(TAG, "Loading plugin: $data") | ||||
| 
 | ||||
|         return try { | ||||
|  | @ -341,6 +344,7 @@ object PluginManager { | |||
|             } | ||||
|             pluginInstance.load(activity) | ||||
|             Log.i(TAG, "Loaded plugin ${data.internalName} successfully") | ||||
|             currentlyLoading = null | ||||
|             true | ||||
|         } catch (e: Throwable) { | ||||
|             Log.e(TAG, "Failed to load $file: ${Log.getStackTraceString(e)}") | ||||
|  | @ -349,6 +353,7 @@ object PluginManager { | |||
|                 activity.getString(R.string.plugin_load_fail).format(fileName), | ||||
|                 Toast.LENGTH_LONG | ||||
|             ) | ||||
|             currentlyLoading = null | ||||
|             false | ||||
|         } | ||||
|     } | ||||
|  |  | |||
|  | @ -613,4 +613,8 @@ | |||
|     <string name="audio_tracks">Audio tracks</string> | ||||
|     <string name="video_tracks">Video tracks</string> | ||||
|     <string name="apply_on_restart">Apply on Restart</string> | ||||
| 
 | ||||
|     <string name="safe_mode_title">Safe Mode enabled</string> | ||||
|     <string name="safe_mode_description">An unrecoverable crash occurred and we\'ve automatically disabled all extensions, so you can find and remove the extension which is causing trouble.</string> | ||||
|     <string name="safe_mode_crash_info">View crash info</string> | ||||
| </resources> | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue