Add expert option to save logs

This commit is contained in:
Torsten Grote 2022-11-11 17:32:03 -03:00 committed by Chirayu Desai
parent 374ba8b64f
commit 1a7fc5f028
6 changed files with 77 additions and 6 deletions

View file

@ -54,6 +54,16 @@
<!-- Used to authenticate saving a new recovery code --> <!-- Used to authenticate saving a new recovery code -->
<uses-permission android:name="android.permission.USE_BIOMETRIC" /> <uses-permission android:name="android.permission.USE_BIOMETRIC" />
<!-- This is needed to query content providers in other users -->
<uses-permission
android:name="android.permission.INTERACT_ACROSS_USERS_FULL"
tools:ignore="ProtectedPermissions" />
<!-- Used to get logcat for system part of backup API, gets permission dialog -->
<uses-permission
android:name="android.permission.READ_LOGS"
tools:ignore="ProtectedPermissions" />
<!-- Permission used to open settings --> <!-- Permission used to open settings -->
<permission <permission
android:name="com.stevesoltys.seedvault.OPEN_SETTINGS" android:name="com.stevesoltys.seedvault.OPEN_SETTINGS"
@ -64,11 +74,6 @@
android:name="com.stevesoltys.seedvault.RESTORE_BACKUP" android:name="com.stevesoltys.seedvault.RESTORE_BACKUP"
android:protectionLevel="system|signature" /> android:protectionLevel="system|signature" />
<!-- This is needed to query content providers in other users -->
<uses-permission
android:name="android.permission.INTERACT_ACROSS_USERS_FULL"
tools:ignore="ProtectedPermissions" />
<application <application
android:name=".App" android:name=".App"
android:allowBackup="false" android:allowBackup="false"

View file

@ -1,15 +1,35 @@
package com.stevesoltys.seedvault.settings package com.stevesoltys.seedvault.settings
import android.os.Bundle import android.os.Bundle
import androidx.activity.result.contract.ActivityResultContracts.CreateDocument
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import com.stevesoltys.seedvault.R import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.permitDiskReads import com.stevesoltys.seedvault.permitDiskReads
import com.stevesoltys.seedvault.transport.backup.PackageService
import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
class ExpertSettingsFragment : PreferenceFragmentCompat() { class ExpertSettingsFragment : PreferenceFragmentCompat() {
private val viewModel: SettingsViewModel by sharedViewModel()
private val packageService: PackageService by inject()
// TODO set mimeType when upgrading androidx lib
private val createFileLauncher = registerForActivityResult(CreateDocument()) { uri ->
viewModel.onLogcatUriReceived(uri)
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
permitDiskReads { permitDiskReads {
setPreferencesFromResource(R.xml.settings_expert, rootKey) setPreferencesFromResource(R.xml.settings_expert, rootKey)
} }
findPreference<Preference>("logcat")?.setOnPreferenceClickListener {
val versionName = packageService.getVersionName(requireContext().packageName) ?: "ver"
val timestamp = System.currentTimeMillis()
val name = "seedvault-$versionName-$timestamp.txt"
createFileLauncher.launch(name)
true
}
} }
override fun onStart() { override fun onStart() {

View file

@ -11,6 +11,7 @@ import android.net.Network
import android.net.NetworkCapabilities import android.net.NetworkCapabilities
import android.net.NetworkRequest import android.net.NetworkRequest
import android.net.Uri import android.net.Uri
import android.os.Process.myUid
import android.provider.Settings import android.provider.Settings
import android.util.Log import android.util.Log
import android.widget.Toast import android.widget.Toast
@ -35,8 +36,11 @@ import com.stevesoltys.seedvault.ui.RequireProvisioningViewModel
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.calyxos.backup.storage.api.StorageBackup import org.calyxos.backup.storage.api.StorageBackup
import org.calyxos.backup.storage.backup.BackupJobService import org.calyxos.backup.storage.backup.BackupJobService
import java.io.IOException
import java.lang.Runtime.getRuntime
import java.util.concurrent.TimeUnit.HOURS import java.util.concurrent.TimeUnit.HOURS
private const val TAG = "SettingsViewModel" private const val TAG = "SettingsViewModel"
@ -233,4 +237,28 @@ internal class SettingsViewModel(
BackupJobService.cancelJob(app) BackupJobService.cancelJob(app)
} }
fun onLogcatUriReceived(uri: Uri?) = viewModelScope.launch(Dispatchers.IO) {
if (uri == null) {
onLogcatError()
return@launch
}
// 1000 is system uid, needed to get backup logs from the OS code.
val command = "logcat -d --uid=1000,${myUid()} *:V"
try {
app.contentResolver.openOutputStream(uri, "wt")?.use { outputStream ->
getRuntime().exec(command).inputStream.use { inputStream ->
inputStream.copyTo(outputStream)
}
} ?: throw IOException("OutputStream was null")
} catch (e: Exception) {
Log.e(TAG, "Error saving logcat ", e)
onLogcatError()
}
}
private suspend fun onLogcatError() = withContext(Dispatchers.Main) {
val str = app.getString(R.string.settings_expert_logcat_error)
Toast.makeText(app, str, LENGTH_LONG).show()
}
} }

View file

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?android:attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M20,8h-2.81c-0.45,-0.78 -1.07,-1.45 -1.82,-1.96L17,4.41 15.59,3l-2.17,2.17C12.96,5.06 12.49,5 12,5c-0.49,0 -0.96,0.06 -1.41,0.17L8.41,3 7,4.41l1.62,1.63C7.88,6.55 7.26,7.22 6.81,8L4,8v2h2.09c-0.05,0.33 -0.09,0.66 -0.09,1v1L4,12v2h2v1c0,0.34 0.04,0.67 0.09,1L4,16v2h2.81c1.04,1.79 2.97,3 5.19,3s4.15,-1.21 5.19,-3L20,18v-2h-2.09c0.05,-0.33 0.09,-0.66 0.09,-1v-1h2v-2h-2v-1c0,-0.34 -0.04,-0.67 -0.09,-1L20,10L20,8zM14,16h-4v-2h4v2zM14,12h-4v-2h4v2z" />
</vector>

View file

@ -46,6 +46,9 @@
<string name="settings_expert_title">Expert settings</string> <string name="settings_expert_title">Expert settings</string>
<string name="settings_expert_quota_title">Unlimited app quota</string> <string name="settings_expert_quota_title">Unlimited app quota</string>
<string name="settings_expert_quota_summary">Do not impose a limitation on the size of app backups.\n\nWarning: This can fill up your storage location quickly. Not needed for most apps.</string> <string name="settings_expert_quota_summary">Do not impose a limitation on the size of app backups.\n\nWarning: This can fill up your storage location quickly. Not needed for most apps.</string>
<string name="settings_expert_logcat_title">Save app log</string>
<string name="settings_expert_logcat_summary">Developers can diagnose bugs with these logs.\n\nWarning: The log file might contain personally identifiable information. Review before and delete after sharing!</string>
<string name="settings_expert_logcat_error">Error: Could not save app log</string>
<!-- Storage Location --> <!-- Storage Location -->
<string name="storage_fragment_backup_title">Choose where to store backups</string> <string name="storage_fragment_backup_title">Choose where to store backups</string>

View file

@ -5,4 +5,9 @@
android:key="unlimited_quota" android:key="unlimited_quota"
android:summary="@string/settings_expert_quota_summary" android:summary="@string/settings_expert_quota_summary"
android:title="@string/settings_expert_quota_title" /> android:title="@string/settings_expert_quota_title" />
<Preference
android:icon="@drawable/ic_bug_report"
android:key="logcat"
android:summary="@string/settings_expert_logcat_summary"
android:title="@string/settings_expert_logcat_title" />
</PreferenceScreen> </PreferenceScreen>