Commit 5c7431f6 authored by gunsch's avatar gunsch Committed by Commit bot

Chromecast: updates Android crash uploader to use HttpURLConnection.

Android deprecated the Apache APIs in L and removed them in M.

R=halliwell@chromium.org,byungchul@chromium.org,alokp@chromium.org
BUG=488200

Review URL: https://codereview.chromium.org/1153263009

Cr-Commit-Position: refs/heads/master@{#333141}
parent 5a47c761
...@@ -4,23 +4,20 @@ ...@@ -4,23 +4,20 @@
package org.chromium.chromecast.shell; package org.chromium.chromecast.shell;
import android.net.http.AndroidHttpClient; import org.chromium.base.Log;
import android.util.Log;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.InputStreamEntity;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.SequenceInputStream; import java.io.SequenceInputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
...@@ -37,7 +34,7 @@ import java.util.concurrent.TimeUnit; ...@@ -37,7 +34,7 @@ import java.util.concurrent.TimeUnit;
* explicitly blocks any post-dump hooks or uploading for Android builds. * explicitly blocks any post-dump hooks or uploading for Android builds.
*/ */
public final class CastCrashUploader { public final class CastCrashUploader {
private static final String TAG = "CastCrashUploader"; private static final String TAG = Log.makeTag("CastCrashUploader");
private static final String CRASH_REPORT_HOST = "clients2.google.com"; private static final String CRASH_REPORT_HOST = "clients2.google.com";
private static final String CAST_SHELL_USER_AGENT = android.os.Build.MODEL + "/CastShell"; private static final String CAST_SHELL_USER_AGENT = android.os.Build.MODEL + "/CastShell";
// Multipart dump filename has format "[random string].dmp[pid]", e.g. // Multipart dump filename has format "[random string].dmp[pid]", e.g.
...@@ -93,10 +90,9 @@ public final class CastCrashUploader { ...@@ -93,10 +90,9 @@ public final class CastCrashUploader {
*/ */
private void queueAllCrashDumpUploads(boolean synchronous, String logFile) { private void queueAllCrashDumpUploads(boolean synchronous, String logFile) {
if (mCrashDumpPath == null) return; if (mCrashDumpPath == null) return;
Log.d(TAG, "Checking for crash dumps"); Log.i(TAG, "Checking for crash dumps");
LinkedList<Future> tasks = new LinkedList<Future>(); LinkedList<Future> tasks = new LinkedList<Future>();
final AndroidHttpClient httpClient = AndroidHttpClient.newInstance(CAST_SHELL_USER_AGENT);
File crashDumpDirectory = new File(mCrashDumpPath); File crashDumpDirectory = new File(mCrashDumpPath);
for (File potentialDump : crashDumpDirectory.listFiles()) { for (File potentialDump : crashDumpDirectory.listFiles()) {
String dumpName = potentialDump.getName(); String dumpName = potentialDump.getName();
...@@ -111,23 +107,15 @@ public final class CastCrashUploader { ...@@ -111,23 +107,15 @@ public final class CastCrashUploader {
} }
// Check if the dump we found has pid matching this process, and if so include // Check if the dump we found has pid matching this process, and if so include
// this process's log. // this process's log.
// TODO(kjoswiak): Currently, logs are lost if dump cannot be uploaded right away. // TODO(gunsch): Currently, logs are lost if dump cannot be uploaded right away.
if (dumpPid == android.os.Process.myPid()) { if (dumpPid == android.os.Process.myPid()) {
tasks.add(queueCrashDumpUpload(httpClient, potentialDump, new File(logFile))); tasks.add(queueCrashDumpUpload(potentialDump, new File(logFile)));
} else { } else {
tasks.add(queueCrashDumpUpload(httpClient, potentialDump, null)); tasks.add(queueCrashDumpUpload(potentialDump, null));
} }
} }
} }
// When finished uploading all of the queued dumps, release httpClient
tasks.add(mExecutorService.submit(new Runnable() {
@Override
public void run() {
httpClient.close();
}
}));
// Wait on tasks, if necessary. // Wait on tasks, if necessary.
if (synchronous) { if (synchronous) {
for (Future task : tasks) { for (Future task : tasks) {
...@@ -142,12 +130,11 @@ public final class CastCrashUploader { ...@@ -142,12 +130,11 @@ public final class CastCrashUploader {
/** /**
* Enqueues a background task to upload a single crash dump file. * Enqueues a background task to upload a single crash dump file.
*/ */
private Future queueCrashDumpUpload(final AndroidHttpClient httpClient, final File dumpFile, private Future queueCrashDumpUpload(final File dumpFile, final File logFile) {
final File logFile) {
return mExecutorService.submit(new Runnable() { return mExecutorService.submit(new Runnable() {
@Override @Override
public void run() { public void run() {
Log.d(TAG, "Uploading dump crash log: " + dumpFile.getName()); Log.i(TAG, "Uploading dump crash log: %s", dumpFile.getName());
try { try {
InputStream uploadCrashDumpStream = new FileInputStream(dumpFile); InputStream uploadCrashDumpStream = new FileInputStream(dumpFile);
...@@ -161,7 +148,7 @@ public final class CastCrashUploader { ...@@ -161,7 +148,7 @@ public final class CastCrashUploader {
String mimeBoundary = dumpFirstLine.substring(2); String mimeBoundary = dumpFirstLine.substring(2);
if (logFile != null) { if (logFile != null) {
Log.d(TAG, "Including log file: " + logFile.getName()); Log.i(TAG, "Including log file: %s", logFile.getName());
StringBuffer logHeader = new StringBuffer(); StringBuffer logHeader = new StringBuffer();
logHeader.append(dumpFirstLine); logHeader.append(dumpFirstLine);
logHeader.append("\n"); logHeader.append("\n");
...@@ -178,48 +165,79 @@ public final class CastCrashUploader { ...@@ -178,48 +165,79 @@ public final class CastCrashUploader {
uploadCrashDumpStream); uploadCrashDumpStream);
} }
InputStreamEntity entity = new InputStreamEntity(uploadCrashDumpStream, -1); HttpURLConnection connection =
entity.setContentType("multipart/form-data; boundary=" + mimeBoundary); (HttpURLConnection) new URL(mCrashReportUploadUrl).openConnection();
HttpPost uploadRequest = new HttpPost(mCrashReportUploadUrl);
uploadRequest.setEntity(entity);
HttpResponse response =
httpClient.execute(new HttpHost(CRASH_REPORT_HOST), uploadRequest);
// Expect a report ID as the entire response // Expect a report ID as the entire response
String responseLine = getFirstLine(response.getEntity().getContent()); try {
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type",
"multipart/form-data; boundary=" + mimeBoundary);
streamCopy(uploadCrashDumpStream, connection.getOutputStream());
String responseLine = getFirstLine(connection.getInputStream());
int statusCode = response.getStatusLine().getStatusCode(); int responseCode = connection.getResponseCode();
if (statusCode == HttpStatus.SC_OK) { if (responseCode == HttpURLConnection.HTTP_OK
Log.d(TAG, "Successfully uploaded to " + mCrashReportUploadUrl || responseCode == HttpURLConnection.HTTP_CREATED
+ ", report ID: " + responseLine); || responseCode == HttpURLConnection.HTTP_ACCEPTED) {
} else { Log.i(TAG, "Successfully uploaded to %s, report ID: %s",
Log.e(TAG, "Failed response (" + statusCode + "): " + responseLine); mCrashReportUploadUrl, responseLine);
} else {
Log.e(TAG, "Failed response (%d): %s", responseCode,
connection.getResponseMessage());
// 400 Bad Request is returned if the dump file is malformed. If requeset // 400 Bad Request is returned if the dump file is malformed. If request
// is not malformed, shortcircuit before clean up to avoid deletion and // is not malformed, short-circuit before cleanup to avoid deletion and
// retry later, otherwise pass through and delete malformed file // retry later, otherwise pass through and delete malformed file.
if (statusCode != HttpStatus.SC_BAD_REQUEST) { if (responseCode != HttpURLConnection.HTTP_BAD_REQUEST) {
return; return;
}
}
} catch (FileNotFoundException fnfe) {
// Android's HttpURLConnection implementation fires FNFE on some errors.
Log.e(TAG, "Failed response: " + connection.getResponseCode(), fnfe);
} finally {
connection.disconnect();
dumpFileStream.close();
if (logFileStream != null) {
logFileStream.close();
} }
} }
// Delete the file so we don't re-upload it next time. // Delete the file so we don't re-upload it next time.
uploadCrashDumpStream.close();
dumpFileStream.close();
dumpFile.delete(); dumpFile.delete();
if (logFile != null && logFile.exists()) { if (logFile != null && logFile.exists()) {
logFileStream.close();
logFile.delete(); logFile.delete();
} }
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "File I/O error trying to upload crash dump", e); Log.e(TAG, "Error occurred trying to upload crash dump", e);
} }
} }
}); });
} }
/**
* Copies all available data from |inStream| to |outStream|. Closes both
* streams when done.
*
* @param inStream the stream to read
* @param outStream the stream to write to
* @throws IOException
*/
private static void streamCopy(InputStream inStream,
OutputStream outStream) throws IOException {
byte[] temp = new byte[4096];
int bytesRead = inStream.read(temp);
while (bytesRead >= 0) {
outStream.write(temp, 0, bytesRead);
bytesRead = inStream.read(temp);
}
inStream.close();
outStream.close();
}
/** /**
* Gets the first line from an input stream, opening and closing readers to do so. * Gets the first line from an input stream, opening and closing readers to do so.
* We're targeting Java 6, so this is still tedious to do. * We're targeting Java 6, so this is still tedious to do.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment