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 -->
<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
android:name="com.stevesoltys.seedvault.OPEN_SETTINGS"
@ -64,11 +74,6 @@
android:name="com.stevesoltys.seedvault.RESTORE_BACKUP"
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
android:name=".App"
android:allowBackup="false"

View file

@ -1,15 +1,35 @@
package com.stevesoltys.seedvault.settings
import android.os.Bundle
import androidx.activity.result.contract.ActivityResultContracts.CreateDocument
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import com.stevesoltys.seedvault.R
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() {
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?) {
permitDiskReads {
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() {

View file

@ -11,6 +11,7 @@ import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.net.Uri
import android.os.Process.myUid
import android.provider.Settings
import android.util.Log
import android.widget.Toast
@ -35,8 +36,11 @@ import com.stevesoltys.seedvault.ui.RequireProvisioningViewModel
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.calyxos.backup.storage.api.StorageBackup
import org.calyxos.backup.storage.backup.BackupJobService
import java.io.IOException
import java.lang.Runtime.getRuntime
import java.util.concurrent.TimeUnit.HOURS
private const val TAG = "SettingsViewModel"
@ -233,4 +237,28 @@ internal class SettingsViewModel(
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_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_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 -->
<string name="storage_fragment_backup_title">Choose where to store backups</string>

View file

@ -5,4 +5,9 @@
android:key="unlimited_quota"
android:summary="@string/settings_expert_quota_summary"
android:title="@string/settings_expert_quota_title" />
</PreferenceScreen>
<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>