logs sender
This commit is contained in:
parent
5ce1e80e73
commit
8ea335501b
|
@ -312,6 +312,9 @@
|
|||
android:configChanges="orientation"
|
||||
android:exported="false"/>
|
||||
|
||||
<activity android:name=".ui.SendLogActivity"
|
||||
android:theme="@style/TransparentTheme"/>
|
||||
|
||||
<service android:name=".services.ExportBackupService" />
|
||||
<service android:name=".services.ImportBackupService" />
|
||||
<service
|
||||
|
|
426
src/main/java/eu/siacs/conversations/ui/SendLogActivity.java
Normal file
426
src/main/java/eu/siacs/conversations/ui/SendLogActivity.java
Normal file
|
@ -0,0 +1,426 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2009 Xtralogic, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package eu.siacs.conversations.ui;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.core.app.ShareCompat;
|
||||
import androidx.core.content.FileProvider;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import eu.siacs.conversations.Config;
|
||||
import eu.siacs.conversations.R;
|
||||
import eu.siacs.conversations.services.BarcodeProvider;
|
||||
|
||||
public class SendLogActivity extends ActionBarActivity {
|
||||
public final static String TAG = "com.xtralogic.android.logcollector";
|
||||
|
||||
public static final String ACTION_SEND_LOG = "com.xtralogic.logcollector.intent.action.SEND_LOG";
|
||||
public static final String EXTRA_SEND_INTENT_ACTION = "com.xtralogic.logcollector.intent.extra.SEND_INTENT_ACTION";
|
||||
public static final String EXTRA_DATA = "com.xtralogic.logcollector.intent.extra.DATA";
|
||||
public static final String EXTRA_ADDITIONAL_INFO = "com.xtralogic.logcollector.intent.extra.ADDITIONAL_INFO";
|
||||
public static final String EXTRA_SHOW_UI = "com.xtralogic.logcollector.intent.extra.SHOW_UI";
|
||||
public static final String EXTRA_FILTER_SPECS = "com.xtralogic.logcollector.intent.extra.FILTER_SPECS";
|
||||
public static final String EXTRA_FORMAT = "com.xtralogic.logcollector.intent.extra.FORMAT";
|
||||
public static final String EXTRA_BUFFER = "com.xtralogic.logcollector.intent.extra.BUFFER";
|
||||
|
||||
public final static String LINE_SEPARATOR = System.getProperty("line.separator");
|
||||
|
||||
final int MAX_LOG_MESSAGE_LENGTH = 100000;
|
||||
|
||||
private AlertDialog mMainDialog;
|
||||
private Intent mSendIntent;
|
||||
private CollectLogTask mCollectLogTask;
|
||||
private ProgressDialog mProgressDialog;
|
||||
private String mAdditonalInfo;
|
||||
private boolean mShowUi;
|
||||
private String[] mFilterSpecs;
|
||||
private String mFormat;
|
||||
private String mBuffer;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState){
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mSendIntent = null;
|
||||
|
||||
Intent intent = getIntent();
|
||||
if (null != intent){
|
||||
String action = intent.getAction();
|
||||
if (ACTION_SEND_LOG.equals(action)){
|
||||
String extraSendAction = intent.getStringExtra(EXTRA_SEND_INTENT_ACTION);
|
||||
if (extraSendAction == null){
|
||||
Log.e(Config.LOGTAG, "Quiting, EXTRA_SEND_INTENT_ACTION is not supplied");
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
mSendIntent = new Intent(extraSendAction);
|
||||
|
||||
Uri data = (Uri)intent.getParcelableExtra(EXTRA_DATA);
|
||||
if (data != null){
|
||||
mSendIntent.setData(data);
|
||||
}
|
||||
|
||||
String[] emails = intent.getStringArrayExtra(Intent.EXTRA_EMAIL);
|
||||
if (emails != null){
|
||||
mSendIntent.putExtra(Intent.EXTRA_EMAIL, emails);
|
||||
}
|
||||
|
||||
String[] ccs = intent.getStringArrayExtra(Intent.EXTRA_CC);
|
||||
if (ccs != null){
|
||||
mSendIntent.putExtra(Intent.EXTRA_CC, ccs);
|
||||
}
|
||||
|
||||
String[] bccs = intent.getStringArrayExtra(Intent.EXTRA_BCC);
|
||||
if (bccs != null){
|
||||
mSendIntent.putExtra(Intent.EXTRA_BCC, bccs);
|
||||
}
|
||||
|
||||
String subject = intent.getStringExtra(Intent.EXTRA_SUBJECT);
|
||||
if (subject != null){
|
||||
mSendIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
|
||||
}
|
||||
|
||||
mAdditonalInfo = intent.getStringExtra(EXTRA_ADDITIONAL_INFO);
|
||||
mShowUi = intent.getBooleanExtra(EXTRA_SHOW_UI, false);
|
||||
mFilterSpecs = intent.getStringArrayExtra(EXTRA_FILTER_SPECS);
|
||||
mFormat = intent.getStringExtra(EXTRA_FORMAT);
|
||||
mBuffer = intent.getStringExtra(EXTRA_BUFFER);
|
||||
}
|
||||
}
|
||||
|
||||
if (null == mSendIntent){
|
||||
//standalone application
|
||||
mShowUi = true;
|
||||
mSendIntent = new Intent(Intent.ACTION_SEND);
|
||||
mSendIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.message_subject));
|
||||
mSendIntent.setType("text/plain");
|
||||
|
||||
mAdditonalInfo = getString(R.string.device_info_fmt, getVersionNumber(this), Build.MODEL, Build.VERSION.RELEASE, getFormattedKernelVersion(), Build.DISPLAY);
|
||||
mFormat = "time";
|
||||
}
|
||||
|
||||
/*if (false && mShowUi){
|
||||
mMainDialog = new AlertDialog.Builder(this)
|
||||
.setTitle(getString(R.string.app_name))
|
||||
.setMessage(getString(R.string.main_dialog_text))
|
||||
.setPositiveButton(android.R.string.ok, (dialog, whichButton) -> collectAndSendLog())
|
||||
.setNegativeButton(android.R.string.cancel, (dialog, whichButton) -> finish())
|
||||
.show();
|
||||
}
|
||||
else{
|
||||
collectAndSendLog();
|
||||
} */
|
||||
|
||||
collectAndSendLog();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
void collectAndSendLog(){
|
||||
/*Usage: logcat [options] [filterspecs]
|
||||
options include:
|
||||
-s Set default filter to silent.
|
||||
Like specifying filterspec '*:s'
|
||||
-f <filename> Log to file. Default to stdout
|
||||
-r [<kbytes>] Rotate log every kbytes. (16 if unspecified). Requires -f
|
||||
-n <count> Sets max number of rotated logs to <count>, default 4
|
||||
-v <format> Sets the log print format, where <format> is one of:
|
||||
|
||||
brief process tag thread raw time threadtime long
|
||||
|
||||
-c clear (flush) the entire log and exit
|
||||
-d dump the log and then exit (don't block)
|
||||
-g get the size of the log's ring buffer and exit
|
||||
-b <buffer> request alternate ring buffer
|
||||
('main' (default), 'radio', 'events')
|
||||
-B output the log in binary
|
||||
filterspecs are a series of
|
||||
<tag>[:priority]
|
||||
|
||||
where <tag> is a log component tag (or * for all) and priority is:
|
||||
V Verbose
|
||||
D Debug
|
||||
I Info
|
||||
W Warn
|
||||
E Error
|
||||
F Fatal
|
||||
S Silent (supress all output)
|
||||
|
||||
'*' means '*:d' and <tag> by itself means <tag>:v
|
||||
|
||||
If not specified on the commandline, filterspec is set from ANDROID_LOG_TAGS.
|
||||
If no filterspec is found, filter defaults to '*:I'
|
||||
|
||||
If not specified with -v, format is set from ANDROID_PRINTF_LOG
|
||||
or defaults to "brief"*/
|
||||
|
||||
ArrayList<String> list = new ArrayList<String>();
|
||||
|
||||
if (mFormat != null){
|
||||
list.add("-v");
|
||||
list.add(mFormat);
|
||||
}
|
||||
|
||||
if (mBuffer != null){
|
||||
list.add("-b");
|
||||
list.add(mBuffer);
|
||||
}
|
||||
|
||||
if (mFilterSpecs != null){
|
||||
for (String filterSpec : mFilterSpecs){
|
||||
list.add(filterSpec);
|
||||
}
|
||||
}
|
||||
|
||||
mCollectLogTask = (CollectLogTask) new CollectLogTask().execute(list);
|
||||
}
|
||||
|
||||
private class CollectLogTask extends AsyncTask<ArrayList<String>, Void, File>{
|
||||
@Override
|
||||
protected void onPreExecute(){
|
||||
showProgressDialog(getString(R.string.acquiring_log_progress_dialog_message));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected File doInBackground(ArrayList<String>... params){
|
||||
final StringBuilder log = new StringBuilder();
|
||||
File logFile = new File(getCacheDir(),"logs/logcat.txt");
|
||||
|
||||
logFile.delete();
|
||||
logFile.getParentFile().mkdirs();
|
||||
|
||||
try{
|
||||
ArrayList<String> commandLine = new ArrayList<String>();
|
||||
commandLine.add("logcat");
|
||||
commandLine.add("-d");
|
||||
ArrayList<String> arguments = ((params != null) && (params.length > 0)) ? params[0] : null;
|
||||
if (null != arguments){
|
||||
commandLine.addAll(arguments);
|
||||
}
|
||||
|
||||
Process process = Runtime.getRuntime().exec(commandLine.toArray(new String[0]));
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
|
||||
String line;
|
||||
while ((line = bufferedReader.readLine()) != null){
|
||||
log.append(line);
|
||||
log.append(LINE_SEPARATOR);
|
||||
}
|
||||
|
||||
FileWriter fr = new FileWriter(logFile);
|
||||
BufferedWriter writer = new BufferedWriter(fr);
|
||||
|
||||
if (mAdditonalInfo != null){
|
||||
log.insert(0, LINE_SEPARATOR);
|
||||
log.insert(0, mAdditonalInfo);
|
||||
}
|
||||
|
||||
writer.write(log.toString());
|
||||
}
|
||||
catch (IOException e){
|
||||
Log.e(Config.LOGTAG, "CollectLogTask.doInBackground failed", e);
|
||||
}
|
||||
|
||||
return logFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(File logFile){
|
||||
if (null != logFile){
|
||||
Uri uri = FileProvider.getUriForFile(SendLogActivity.this, getPackageName() + ".files", logFile);
|
||||
|
||||
new ShareCompat
|
||||
.IntentBuilder(SendLogActivity.this)
|
||||
.setType("text/*")
|
||||
.addStream(uri)
|
||||
.setChooserTitle(getString(R.string.chooser_title))
|
||||
.startChooser();
|
||||
|
||||
/* Intent sharingIntent = new Intent(Intent.ACTION_SEND);
|
||||
sharingIntent.setType("text/*");
|
||||
sharingIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
|
||||
startActivity(Intent.createChooser(sharingIntent, getString(R.string.chooser_title)));*/
|
||||
dismissProgressDialog();
|
||||
dismissMainDialog();
|
||||
finish();
|
||||
}
|
||||
else{
|
||||
dismissProgressDialog();
|
||||
showErrorDialog(getString(R.string.failed_to_get_log_message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void showErrorDialog(String errorMessage){
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(getString(R.string.app_name))
|
||||
.setMessage(errorMessage)
|
||||
.setIcon(android.R.drawable.ic_dialog_alert)
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener(){
|
||||
public void onClick(DialogInterface dialog, int whichButton){
|
||||
finish();
|
||||
}
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
void dismissMainDialog(){
|
||||
if (null != mMainDialog && mMainDialog.isShowing()){
|
||||
mMainDialog.dismiss();
|
||||
mMainDialog = null;
|
||||
}
|
||||
}
|
||||
|
||||
void showProgressDialog(String message){
|
||||
mProgressDialog = new ProgressDialog(this);
|
||||
mProgressDialog.setIndeterminate(true);
|
||||
mProgressDialog.setMessage(message);
|
||||
mProgressDialog.setCancelable(true);
|
||||
mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener(){
|
||||
public void onCancel(DialogInterface dialog){
|
||||
cancellCollectTask();
|
||||
finish();
|
||||
}
|
||||
});
|
||||
mProgressDialog.show();
|
||||
}
|
||||
|
||||
private void dismissProgressDialog(){
|
||||
if (null != mProgressDialog && mProgressDialog.isShowing())
|
||||
{
|
||||
mProgressDialog.dismiss();
|
||||
mProgressDialog = null;
|
||||
}
|
||||
}
|
||||
|
||||
void cancellCollectTask(){
|
||||
if (mCollectLogTask != null && mCollectLogTask.getStatus() == AsyncTask.Status.RUNNING)
|
||||
{
|
||||
mCollectLogTask.cancel(true);
|
||||
mCollectLogTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause(){
|
||||
cancellCollectTask();
|
||||
dismissProgressDialog();
|
||||
dismissMainDialog();
|
||||
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
private static String getVersionNumber(Context context)
|
||||
{
|
||||
String version = "?";
|
||||
try
|
||||
{
|
||||
PackageInfo packagInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
|
||||
version = packagInfo.versionName;
|
||||
}
|
||||
catch (PackageManager.NameNotFoundException e){};
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
private String getFormattedKernelVersion()
|
||||
{
|
||||
String procVersionStr;
|
||||
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(new FileReader("/proc/version"), 256);
|
||||
try {
|
||||
procVersionStr = reader.readLine();
|
||||
} finally {
|
||||
reader.close();
|
||||
}
|
||||
|
||||
final String PROC_VERSION_REGEX =
|
||||
"\\w+\\s+" + /* ignore: Linux */
|
||||
"\\w+\\s+" + /* ignore: version */
|
||||
"([^\\s]+)\\s+" + /* group 1: 2.6.22-omap1 */
|
||||
"\\(([^\\s@]+(?:@[^\\s.]+)?)[^)]*\\)\\s+" + /* group 2: (xxxxxx@xxxxx.constant) */
|
||||
"\\([^)]+\\)\\s+" + /* ignore: (gcc ..) */
|
||||
"([^\\s]+)\\s+" + /* group 3: #26 */
|
||||
"(?:PREEMPT\\s+)?" + /* ignore: PREEMPT (optional) */
|
||||
"(.+)"; /* group 4: date */
|
||||
|
||||
Pattern p = Pattern.compile(PROC_VERSION_REGEX);
|
||||
Matcher m = p.matcher(procVersionStr);
|
||||
|
||||
if (!m.matches()) {
|
||||
Log.e(TAG, "Regex did not match on /proc/version: " + procVersionStr);
|
||||
return "Unavailable";
|
||||
} else if (m.groupCount() < 4) {
|
||||
Log.e(TAG, "Regex match on /proc/version only returned " + m.groupCount()
|
||||
+ " groups");
|
||||
return "Unavailable";
|
||||
} else {
|
||||
return (new StringBuilder(m.group(1)).append("\n").append(
|
||||
m.group(2)).append(" ").append(m.group(3)).append("\n")
|
||||
.append(m.group(4))).toString();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG,
|
||||
"IO Exception when getting kernel version for Device Info screen",
|
||||
e);
|
||||
|
||||
return "Unavailable";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package eu.siacs.conversations.ui;
|
||||
|
||||
import android.app.FragmentManager;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
|
@ -28,6 +29,7 @@ import com.google.common.collect.ImmutableList;
|
|||
import com.google.common.collect.Lists;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.security.KeyStoreException;
|
||||
|
@ -319,6 +321,16 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference
|
|||
});
|
||||
}
|
||||
|
||||
final Preference sendLogsPreference = mSettingsFragment.findPreference("send_logs");
|
||||
if (sendLogsPreference != null) {
|
||||
sendLogsPreference.setOnPreferenceClickListener(
|
||||
preference -> {
|
||||
final Intent intent = new Intent(this, SendLogActivity.class);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if (Config.ONLY_INTERNAL_STORAGE) {
|
||||
final Preference cleanCachePreference = mSettingsFragment.findPreference("clean_cache");
|
||||
if (cleanCachePreference != null) {
|
||||
|
|
|
@ -330,6 +330,8 @@
|
|||
<string name="pref_keep_foreground_service_summary">Prevents the operating system from killing your connection</string>
|
||||
<string name="pref_create_backup">Create backup</string>
|
||||
<string name="pref_create_backup_summary">Backup files will be stored in %s</string>
|
||||
<string name="pref_send_logs">Send report</string>
|
||||
<string name="pref_send_logs_summary">It can help us to fix your problem</string>
|
||||
<string name="notification_create_backup_title">Creating backup files</string>
|
||||
<string name="notification_backup_created_title">Your backup has been created</string>
|
||||
<string name="notification_backup_created_subtitle">The backup files have been stored in %s</string>
|
||||
|
|
18
src/main/res/values/strings_logs_reporter.xml
Normal file
18
src/main/res/values/strings_logs_reporter.xml
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="message_subject">Android device log</string>
|
||||
<string name="acquiring_log_progress_dialog_message">Acquiring log from the system...</string>
|
||||
<string name="chooser_title">"Select an application to send the log"</string>
|
||||
<string name="failed_to_get_log_message">"Failed to get the log from the system."</string>
|
||||
<string name="main_dialog_text">"This application will attempt to collect the device log.
|
||||
The collected log will be sent using an application of your choice.
|
||||
You also will have an opportunity to see and modify the data being sent."
|
||||
</string>
|
||||
<string name="device_info_fmt">
|
||||
Log Collector version: %1$s\n
|
||||
Device model: %2$s\n
|
||||
Firmware version: %3$s\n
|
||||
Kernel version: %4$s\n
|
||||
Build number: %5$s\n
|
||||
</string>
|
||||
</resources>
|
|
@ -390,6 +390,15 @@
|
|||
<item name="android:windowBackground">@drawable/background</item>
|
||||
</style>
|
||||
|
||||
<style name="TransparentTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
|
||||
<item name="android:windowIsTranslucent">true</item>
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowIsFloating">true</item>
|
||||
<item name="android:backgroundDimEnabled">false</item>
|
||||
</style>
|
||||
|
||||
<style name="ConversationsTheme.Dialog" parent="@style/Theme.AppCompat.Light.Dialog">
|
||||
<item name="colorPrimary">@color/green600</item>
|
||||
<item name="colorPrimaryDark">@color/green700</item>
|
||||
|
|
|
@ -21,4 +21,7 @@
|
|||
<cache-path
|
||||
name="camera"
|
||||
path="Camera/"/>
|
||||
<cache-path
|
||||
name="logs"
|
||||
path="logs"/>
|
||||
</paths>
|
|
@ -236,6 +236,10 @@
|
|||
android:summary="@string/pref_keep_foreground_service_summary"
|
||||
android:title="@string/pref_keep_foreground_service" />
|
||||
|
||||
<Preference
|
||||
android:key="send_logs"
|
||||
android:summary="@string/pref_send_logs_summary"
|
||||
android:title="@string/pref_send_logs" />
|
||||
<PreferenceScreen
|
||||
android:key="expert"
|
||||
android:summary="@string/pref_expert_options_summary"
|
||||
|
|
Loading…
Reference in a new issue