blob: 67beaab8a5e653b7f28dac7fb14d07451bebb090 [file] [log] [blame]
Pankaj Gargf04dbda2014-10-02 13:52:46 -07001/*
2 * Copyright (c) 2014, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*/
29
30package com.android.browser;
31
32import android.app.Activity;
33import android.content.Context;
34import android.os.Build;
35import android.os.Build.VERSION;
36import android.os.SystemClock;
37import android.net.http.AndroidHttpClient;
38import android.util.Log;
39
40import org.codeaurora.swe.BrowserCommandLine;
41
42import org.apache.http.HttpEntity;
43import org.apache.http.HttpResponse;
44import org.apache.http.client.methods.HttpPost;
45import org.apache.http.entity.StringEntity;
46import org.apache.http.client.ClientProtocolException;
47
48import org.json.JSONArray;
49import org.json.JSONObject;
50import org.json.JSONException;
51
52import java.io.File;
53import java.io.FileOutputStream;
54import java.io.FileInputStream;
55import java.io.FileNotFoundException;
56import java.io.IOException;
57import java.io.BufferedReader;
58import java.io.InputStreamReader;
59import java.lang.Integer;
60import java.lang.StringBuilder;
61import java.lang.System;
62import java.lang.Thread.UncaughtExceptionHandler;
63import java.util.Calendar;
64
65public class CrashLogExceptionHandler implements Thread.UncaughtExceptionHandler {
66
67 private static final String CRASH_LOG_FILE = "crash.log";
68 private static final String CRASH_LOG_SERVER_CMD = "crash-log-server";
69 private static final String CRASH_LOG_MAX_FILE_SIZE_CMD = "crash-log-max-file-size";
70
71 private final static String LOGTAG = "CrashLog";
72
73 private Context mAppContext = null;
74
75 private UncaughtExceptionHandler mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
76
77 private String mLogServer = new String();
78
79 private boolean mOverrideHandler = false;
80
81 private int mMaxLogFileSize = 1024 * 1024;
82
83 public CrashLogExceptionHandler(Context ctx) {
84 mAppContext = ctx;
Vivek Sekhar7b3d2da2014-11-13 16:20:11 -080085 BrowserCommandLine cl = BrowserCommandLine.getInstance();
Pankaj Gargf04dbda2014-10-02 13:52:46 -070086 if (cl.hasSwitch(CRASH_LOG_SERVER_CMD)) {
87 mLogServer = cl.getSwitchValue(CRASH_LOG_SERVER_CMD);
88 if (mLogServer != null) {
89 uploadPastCrashLog();
90 mOverrideHandler = true;
91 }
92 }
93
94 try {
95 int size = Integer.parseInt(cl.getSwitchValue(CRASH_LOG_MAX_FILE_SIZE_CMD,
96 Integer.toString(mMaxLogFileSize)));
97 mMaxLogFileSize = size;
98 } catch (NumberFormatException nfe) {
99 Log.e(LOGTAG,"Max log file size is not configured properly. Using default: "
100 + mMaxLogFileSize);
101 }
102
103 }
104
105 private void saveCrashLog(String crashLog) {
106 // Check if log file exists and it's current size
107 try {
108 File file = new File(mAppContext.getFilesDir(), CRASH_LOG_FILE);
109 if (file.exists()) {
110 if (file.length() > mMaxLogFileSize) {
111 Log.e(LOGTAG,"CRASH Log file size(" + file.length()
112 + ") exceeded max log file size("
113 + mMaxLogFileSize + ")");
114 return;
115 }
116 }
117 } catch (NullPointerException npe) {
118 Log.e(LOGTAG,"Exception while checking file size: " + npe);
119 }
120
121 FileOutputStream crashLogFile = null;
122 try {
123 crashLogFile = mAppContext.openFileOutput(CRASH_LOG_FILE, Context.MODE_APPEND);
124 crashLogFile.write(crashLog.getBytes());
125 } catch(IOException ioe) {
126 Log.e(LOGTAG,"Exception while writing file: " + ioe);
127 } finally {
128 if (crashLogFile != null) {
129 try {
130 crashLogFile.close();
131 } catch (IOException ignore) {
132 }
133 }
134 }
135 }
136
137 private void uploadPastCrashLog() {
138 FileInputStream crashLogFile = null;
139 BufferedReader reader = null;
140 try {
141 crashLogFile = mAppContext.openFileInput(CRASH_LOG_FILE);
142
143 reader = new BufferedReader(new InputStreamReader(crashLogFile));
144 StringBuilder crashLog = new StringBuilder();
145 String line = reader.readLine();
146 if (line != null) {
147 crashLog.append(line);
148 }
149
150 // Typically there's only one line (JSON string) in the crash
151 // log file. This loop would not be executed.
152 while ((line = reader.readLine()) != null) {
153 crashLog.append("\n").append(line);
154 }
155
156 uploadCrashLog(crashLog.toString(), 3000);
157 } catch(FileNotFoundException fnfe) {
158 Log.v(LOGTAG,"No previous crash found");
159 } catch(IOException ioe) {
160 Log.e(LOGTAG,"Exception while reading crash file: " + ioe);
161 } finally {
162 if (crashLogFile != null) {
163 try {
164 crashLogFile.close();
165 } catch (IOException ignore) {
166 }
167 }
168 if (reader != null) {
169 try {
170 reader.close();
171 } catch (IOException ignore) {
172 }
173 }
174 }
175 }
176
177 private void uploadCrashLog(String data, int after) {
178 final String crashLog = data;
179 final int waitFor = after;
180 new Thread(new Runnable() {
181 public void run(){
182 try {
183 SystemClock.sleep(waitFor);
184 AndroidHttpClient httpClient = AndroidHttpClient.newInstance("Android");;
185 HttpPost httpPost = new HttpPost(mLogServer);
186 HttpEntity se = new StringEntity(crashLog);
187 httpPost.setEntity(se);
188 HttpResponse response = httpClient.execute(httpPost);
189
190 File crashLogFile = new File(mAppContext.getFilesDir(),
191 CRASH_LOG_FILE);
192 if (crashLogFile != null) {
193 crashLogFile.delete();
194 } else {
195 Log.e(LOGTAG,"crash log file could not be opened for deletion");
196 }
197 } catch (ClientProtocolException pe) {
198 Log.e(LOGTAG,"Exception while sending http post: " + pe);
199 } catch (IOException ioe1) {
200 Log.e(LOGTAG,"Exception while sending http post: " + ioe1);
201 }
202 }
203 }).start();
204 }
205
206 public void uncaughtException(Thread t, Throwable e) {
207 if (!mOverrideHandler) {
208 mDefaultHandler.uncaughtException(t, e);
209 return;
210 }
211
212 String crashLog = new String();
213
214 try {
215 Calendar calendar = Calendar.getInstance();
216 JSONObject jsonStackObj = new JSONObject();
217 String date = calendar.getTime().toString();
218 String aboutSWE = mAppContext.getResources().getString(R.string.about_text);
219 String sweVer = aboutSWE.substring(aboutSWE.indexOf("Hash"),
220 aboutSWE.length());
221
222 jsonStackObj.put("date", date);
223 jsonStackObj.put("device", android.os.Build.MODEL);
224 jsonStackObj.put("android-ver", android.os.Build.VERSION.RELEASE);
225 jsonStackObj.put("browser-ver", sweVer);
226 jsonStackObj.put("thread", t.toString());
227 jsonStackObj.put("cause", e.getCause());
228
229 Throwable cause = e.getCause();
230 if(cause != null) {
231 StackTraceElement[] arr = cause.getStackTrace();
232 JSONArray jsonStack = new JSONArray(arr);
233 jsonStackObj.put("stack", jsonStack);
234 }
235
236 JSONObject jsonMainObj = new JSONObject();
237 jsonMainObj.put("backtraces", jsonStackObj);
238
239 Log.e(LOGTAG, "Exception: " + jsonMainObj.toString(4));
240 crashLog = jsonMainObj.toString();
241
242 } catch (JSONException je) {
243 Log.e(LOGTAG, "Failed in JSON encoding: " + je);
244 }
245
246 saveCrashLog(crashLog);
247
248 uploadCrashLog(crashLog, 0);
249
250 mDefaultHandler.uncaughtException(t, e);
251 }
252}