Index: chrome/android/java/src/org/chromium/chrome/browser/crash/LogcatExtractionRunnable.java |
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/crash/LogcatExtractionCallable.java b/chrome/android/java/src/org/chromium/chrome/browser/crash/LogcatExtractionRunnable.java |
similarity index 70% |
rename from chrome/android/java/src/org/chromium/chrome/browser/crash/LogcatExtractionCallable.java |
rename to chrome/android/java/src/org/chromium/chrome/browser/crash/LogcatExtractionRunnable.java |
index fbd821abdd6e6411b53bd593a956276fa3c87ead..a56533a66c213dfbbcbf44f2bfde49449e4e3d4c 100644 |
--- a/chrome/android/java/src/org/chromium/chrome/browser/crash/LogcatExtractionCallable.java |
+++ b/chrome/android/java/src/org/chromium/chrome/browser/crash/LogcatExtractionRunnable.java |
@@ -5,7 +5,7 @@ |
package org.chromium.chrome.browser.crash; |
import android.content.Context; |
-import android.content.Intent; |
+import android.os.Build; |
import android.util.Patterns; |
import org.chromium.base.Log; |
@@ -14,36 +14,24 @@ import org.chromium.components.minidump_uploader.CrashFileManager; |
import java.io.BufferedReader; |
import java.io.File; |
-import java.io.FileInputStream; |
-import java.io.FileOutputStream; |
-import java.io.FileWriter; |
import java.io.IOException; |
-import java.io.InputStream; |
import java.io.InputStreamReader; |
-import java.io.OutputStream; |
-import java.io.PrintWriter; |
import java.util.ArrayList; |
-import java.util.Arrays; |
import java.util.Collections; |
import java.util.LinkedList; |
import java.util.List; |
-import java.util.concurrent.Callable; |
import java.util.regex.Matcher; |
import java.util.regex.Pattern; |
/** |
- * Extracts logcat out of Android devices and elide PII sensitive info from it. |
+ * Extracts the recent logcat output from an Android device, elides PII sensitive info from it, |
+ * prepends the logcat data to the caller-provided minidump file, and initiates upload for the crash |
+ * report. |
* |
* Elided information includes: Emails, IP address, MAC address, URL/domains as well as Javascript |
* console messages. |
- * |
- * Caller provides a list of minidump files as well as an intent. This Callable will then extract |
- * the most recent logcat and save a copy for each minidump. |
- * |
- * Upon completion, each minidump + logcat pairs will be passed to the MinidumpPreparationService |
- * along with the intent provided here. |
*/ |
-public class LogcatExtractionCallable implements Callable<Boolean> { |
+public class LogcatExtractionRunnable implements Runnable { |
private static final String TAG = "LogcatExtraction"; |
private static final long HALF_SECOND = 500; |
@@ -97,8 +85,6 @@ public class LogcatExtractionCallable implements Callable<Boolean> { |
@VisibleForTesting |
protected static final String MAC_ELISION = "01:23:45:67:89:AB"; |
- private static final String LOGCAT_EXTENSION = ".logcat"; |
- |
@VisibleForTesting |
protected static final String CONSOLE_ELISION = "[ELIDED:CONSOLE(0)] ELIDED CONSOLE MESSAGE"; |
@@ -107,8 +93,6 @@ public class LogcatExtractionCallable implements Callable<Boolean> { |
private static final Pattern CONSOLE_MSG = Pattern.compile("\\[\\w*:CONSOLE.*\\].*"); |
- private static final Pattern MINIDUMP_EXTENSION = Pattern.compile("\\.dmp"); |
- |
private static final String[] CHROME_NAMESPACE = new String[] {"org.chromium.", "com.google."}; |
private static final String[] SYSTEM_NAMESPACE = new String[] {"android.accessibilityservice", |
@@ -126,100 +110,47 @@ public class LogcatExtractionCallable implements Callable<Boolean> { |
"org.xmlpull."}; |
private final Context mContext; |
- private final String[] mMinidumpFilenames; |
- private final Intent mRedirectIntent; |
+ private final File mMinidumpFile; |
/** |
- * @param filenames List of minidump filenames that need logcat to be attached. |
- * @param redirectIntent The intent to be triggered once upon completion. |
+ * @param context The application context for accessing the cache directory and firing intents. |
+ * @param minidump The minidump file that needs logcat output to be attached. |
*/ |
- public LogcatExtractionCallable(Context context, String[] filenames, Intent redirectIntent) { |
- if (context == null) { |
- throw new NullPointerException("Context cannot be null."); |
- } |
+ public LogcatExtractionRunnable(Context context, File minidump) { |
mContext = context; |
- mMinidumpFilenames = Arrays.copyOf(filenames, filenames.length); |
- mRedirectIntent = redirectIntent; |
+ mMinidumpFile = minidump; |
} |
@Override |
- public Boolean call() { |
- Log.i(TAG, "Trying to extract logcat for minidump"); |
+ public void run() { |
+ Log.i(TAG, "Trying to extract logcat for minidump " + mMinidumpFile.getName()); |
+ CrashFileManager fileManager = new CrashFileManager(mContext.getCacheDir()); |
+ File fileToUpload = mMinidumpFile; |
try { |
- // Step 1: Extract a single logcat file. |
- File logcatFile = getElidedLogcat(); |
- |
- // Step 2: Make copies of logcat file for each minidump then invoke |
- // MinidumpPreparationService on each file pair. |
- int len = mMinidumpFilenames.length; |
- CrashFileManager fileManager = new CrashFileManager(mContext.getCacheDir()); |
- for (int i = 0; i < len; i++) { |
- // Output crash dump file path to logcat so non-browser crashes appear too. |
- Log.i(TAG, "Output crash dump:"); |
- Log.i(TAG, fileManager.getCrashFile(mMinidumpFilenames[i]).getAbsolutePath()); |
- processMinidump(logcatFile, mMinidumpFilenames[i], fileManager, i == len - 1); |
- } |
- return true; |
+ List<String> logcat = getElidedLogcat(); |
+ fileToUpload = new MinidumpLogcatPrepender(fileManager, mMinidumpFile, logcat).run(); |
} catch (IOException | InterruptedException e) { |
Log.w(TAG, e.toString()); |
- return false; |
} |
- } |
- |
- private void processMinidump(File logcatFile, String name, CrashFileManager manager, |
- boolean isLast) throws IOException { |
- String toPath = MINIDUMP_EXTENSION.matcher(name).replaceAll(LOGCAT_EXTENSION); |
- File toFile = manager.createNewTempFile(toPath); |
- |
- // For the last file, we don't need to make extra copies. We'll use the original |
- // logcat file but we would pass down the redirect intent so it can be triggered |
- // upon completion. |
- Intent intent = null; |
- if (isLast) { |
- move(logcatFile, toFile); |
- intent = MinidumpPreparationService.createMinidumpPreparationIntent( |
- mContext, manager.getCrashFile(name), toFile, mRedirectIntent); |
- } else { |
- copy(logcatFile, toFile); |
- intent = MinidumpPreparationService.createMinidumpPreparationIntent( |
- mContext, manager.getCrashFile(name), toFile, null); |
- } |
- mContext.startService(intent); |
- } |
- |
- private File getElidedLogcat() throws IOException, InterruptedException { |
- List<String> rawLogcat = getLogcat(); |
- List<String> elidedLogcat = Collections.unmodifiableList(processLogcat(rawLogcat)); |
- return writeLogcat(elidedLogcat); |
- } |
- private static void copy(File src, File dst) throws IOException { |
- InputStream in = null; |
- OutputStream out = null; |
+ // Regardless of success, initiate the upload. That way, even if there are errors augmenting |
+ // the minidump with logcat data, the service can still upload the unaugmented minidump. |
try { |
- in = new FileInputStream(src); |
- out = new FileOutputStream(dst); |
- // Transfer bytes from in to out |
- byte[] buf = new byte[1024]; |
- int len; |
- while ((len = in.read(buf)) > 0) { |
- out.write(buf, 0, len); |
- } |
- } catch (IOException e) { |
- Log.w(TAG, e.toString()); |
- } finally { |
- try { |
- if (in != null) in.close(); |
- } finally { |
- if (out != null) out.close(); |
+ MinidumpUploadService.tryUploadCrashDump(mContext, fileToUpload); |
+ } catch (SecurityException e) { |
+ // For KitKat and below, there was a framework bug which causes us to not be able to |
+ // find our own crash uploading service. Ignore a SecurityException here on older |
+ // OS versions since the crash will eventually get uploaded on next start. |
+ // crbug/542533 |
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
+ throw e; |
} |
} |
} |
- private static void move(File from, File to) { |
- if (!from.renameTo(to)) { |
- Log.w(TAG, "Fail to rename logcat file"); |
- } |
+ private List<String> getElidedLogcat() throws IOException, InterruptedException { |
+ List<String> rawLogcat = getLogcat(); |
+ return Collections.unmodifiableList(elideLogcat(rawLogcat)); |
} |
@VisibleForTesting |
@@ -296,35 +227,18 @@ public class LogcatExtractionCallable implements Callable<Boolean> { |
return rawLogcat; |
} |
- private File writeLogcat(List<String> elidedLogcat) throws IOException { |
- CrashFileManager fileManager = new CrashFileManager(mContext.getCacheDir()); |
- File logcatFile = fileManager.createNewTempFile("logcat.txt"); |
- PrintWriter pWriter = null; |
- try { |
- pWriter = new PrintWriter(new FileWriter(logcatFile)); |
- for (String ln : elidedLogcat) { |
- pWriter.println(ln); |
- } |
- return logcatFile; |
- } finally { |
- if (pWriter != null) { |
- pWriter.close(); |
- } |
- } |
- } |
- |
@VisibleForTesting |
- protected static List<String> processLogcat(List<String> rawLogcat) { |
- List<String> out = new ArrayList<String>(rawLogcat.size()); |
+ protected static List<String> elideLogcat(List<String> rawLogcat) { |
+ List<String> elided = new ArrayList<String>(rawLogcat.size()); |
for (String ln : rawLogcat) { |
ln = elideEmail(ln); |
ln = elideUrl(ln); |
ln = elideIp(ln); |
ln = elideMac(ln); |
ln = elideConsole(ln); |
- out.add(ln); |
+ elided.add(ln); |
} |
- return out; |
+ return elided; |
} |
/** |