| 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;
|
| }
|
|
|
| /**
|
|
|