Logcat-crash-reports-UI.patch 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871
  1. From: uazo <uazo@users.noreply.github.com>
  2. Date: Tue, 15 Jun 2021 11:49:43 +0000
  3. Subject: Logcat crash reports UI
  4. ---
  5. .../crash/MinidumpUploadServiceImpl.java | 22 +++
  6. .../crash_upload_list_android.cc | 22 ++-
  7. .../crash_upload_list_android.h | 1 +
  8. chrome/browser/net/chrome_network_delegate.cc | 7 +
  9. chrome/browser/ui/BUILD.gn | 1 +
  10. chrome/browser/ui/webui/crashes_ui.cc | 170 ++++++++++++++++--
  11. .../crash/core/browser/crashes_ui_util.cc | 4 +
  12. .../crash/core/browser/crashes_ui_util.h | 2 +
  13. .../crash/core/browser/resources/crashes.css | 67 ++++++-
  14. .../crash/core/browser/resources/crashes.html | 17 ++
  15. .../crash/core/browser/resources/crashes.js | 40 +++--
  16. components/crash_strings.grdp | 22 ++-
  17. .../minidump_uploader/CrashFileManager.java | 7 +-
  18. .../MinidumpUploadCallable.java | 20 +--
  19. .../minidump_uploader/MinidumpUploader.java | 29 +--
  20. .../upload_list/text_log_upload_list.cc | 1 +
  21. components/upload_list/upload_list.cc | 17 +-
  22. components/upload_list/upload_list.h | 9 +
  23. 18 files changed, 379 insertions(+), 79 deletions(-)
  24. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadServiceImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadServiceImpl.java
  25. --- a/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadServiceImpl.java
  26. +++ b/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadServiceImpl.java
  27. @@ -42,6 +42,11 @@ import java.lang.annotation.Retention;
  28. import java.lang.annotation.RetentionPolicy;
  29. import java.util.concurrent.atomic.AtomicBoolean;
  30. +import org.chromium.base.task.AsyncTask;
  31. +import org.chromium.base.task.PostTask;
  32. +import org.chromium.base.task.TaskTraits;
  33. +import org.chromium.chrome.browser.crash.LogcatExtractionRunnable;
  34. +
  35. /**
  36. * Service that is responsible for uploading crash minidumps to the Google crash server.
  37. */
  38. @@ -445,4 +450,21 @@ public class MinidumpUploadServiceImpl extends MinidumpUploadService.Impl {
  39. tryUploadCrashDump(renamedMinidumpFile);
  40. }
  41. }
  42. +
  43. + @CalledByNative
  44. + public static void requestNewExtraction() {
  45. + CrashFileManager crashFileManager =
  46. + new CrashFileManager(ContextUtils.getApplicationContext().getCacheDir());
  47. +
  48. + // Append logcat output to minidumps where are missing
  49. + // getMinidumpsSansLogcat() also extract new files from crashpad
  50. + File[] minidumpsSansLogcat = crashFileManager.getMinidumpsSansLogcat();
  51. + if (minidumpsSansLogcat.length >= 1) {
  52. + for (int i = 0; i < minidumpsSansLogcat.length; ++i) {
  53. + File minidump = minidumpsSansLogcat[i];
  54. + AsyncTask.THREAD_POOL_EXECUTOR.execute(
  55. + new LogcatExtractionRunnable(minidump));
  56. + }
  57. + }
  58. + }
  59. }
  60. diff --git a/chrome/browser/crash_upload_list/crash_upload_list_android.cc b/chrome/browser/crash_upload_list/crash_upload_list_android.cc
  61. --- a/chrome/browser/crash_upload_list/crash_upload_list_android.cc
  62. +++ b/chrome/browser/crash_upload_list/crash_upload_list_android.cc
  63. @@ -14,6 +14,7 @@
  64. #include "base/metrics/histogram_macros_local.h"
  65. #include "chrome/android/chrome_jni_headers/MinidumpUploadServiceImpl_jni.h"
  66. #include "ui/base/text/bytes_formatting.h"
  67. +#include "base/strings/string_util.h"
  68. namespace {
  69. @@ -76,16 +77,26 @@ void CrashUploadListAndroid::RequestSingleUpload(const std::string& local_id) {
  70. Java_MinidumpUploadServiceImpl_tryUploadCrashDumpWithLocalId(env, j_local_id);
  71. }
  72. +void CrashUploadListAndroid::RequestNewExtraction() {
  73. + JNIEnv* env = base::android::AttachCurrentThread();
  74. + Java_MinidumpUploadServiceImpl_requestNewExtraction(env);
  75. +}
  76. +
  77. void CrashUploadListAndroid::LoadUnsuccessfulUploadList(
  78. std::vector<UploadInfo>* uploads) {
  79. const char pending_uploads[] = ".dmp";
  80. const char skipped_uploads[] = ".skipped";
  81. const char manually_forced_uploads[] = ".forced";
  82. + const char zipped_uploads[] = ".zip";
  83. base::FileEnumerator files(upload_log_path().DirName(), false,
  84. base::FileEnumerator::FILES);
  85. for (base::FilePath file = files.Next(); !file.empty(); file = files.Next()) {
  86. UploadList::UploadInfo::State upload_state;
  87. + if (base::EndsWith(file.value(), zipped_uploads, base::CompareCase::INSENSITIVE_ASCII)) {
  88. + // skip zip files
  89. + continue;
  90. + }
  91. if (file.value().find(manually_forced_uploads) != std::string::npos) {
  92. RecordUnsuccessfulUploadListState(UnsuccessfulUploadListState::FORCED);
  93. upload_state = UploadList::UploadInfo::State::Pending_UserRequested;
  94. @@ -117,6 +128,8 @@ void CrashUploadListAndroid::LoadUnsuccessfulUploadList(
  95. continue;
  96. }
  97. + std::string file_path = file.value();
  98. +
  99. // Crash reports can have multiple extensions (e.g. foo.dmp, foo.dmp.try1,
  100. // foo.skipped.try0).
  101. file = file.BaseName();
  102. @@ -136,8 +149,15 @@ void CrashUploadListAndroid::LoadUnsuccessfulUploadList(
  103. RecordUnsuccessfulUploadListState(
  104. UnsuccessfulUploadListState::ADDING_AN_UPLOAD_ENTRY);
  105. id = id.substr(pos + 1);
  106. + // Since current thread is an IO thread
  107. + // to avoid failed DCHECK ThreadRestrictions::AssertSingletonAllowed()
  108. + // remove ui::FormatBytes(): dcheck fail because it use base::FormatDouble()
  109. + // and LazyInstance<NumberFormatWrapper>::DestructorAtExit().
  110. + // also "upload.file_size" is unused.
  111. + std::u16string file_size_string;
  112. UploadList::UploadInfo upload(id, info.creation_time, upload_state,
  113. - ui::FormatBytes(file_size));
  114. + file_size_string);
  115. + upload.file_path = file_path;
  116. uploads->push_back(upload);
  117. }
  118. }
  119. diff --git a/chrome/browser/crash_upload_list/crash_upload_list_android.h b/chrome/browser/crash_upload_list/crash_upload_list_android.h
  120. --- a/chrome/browser/crash_upload_list/crash_upload_list_android.h
  121. +++ b/chrome/browser/crash_upload_list/crash_upload_list_android.h
  122. @@ -32,6 +32,7 @@ class CrashUploadListAndroid : public TextLogUploadList {
  123. std::vector<UploadInfo> LoadUploadList() override;
  124. void RequestSingleUpload(const std::string& local_id) override;
  125. + void RequestNewExtraction() override;
  126. private:
  127. void LoadUnsuccessfulUploadList(std::vector<UploadInfo>* uploads);
  128. diff --git a/chrome/browser/net/chrome_network_delegate.cc b/chrome/browser/net/chrome_network_delegate.cc
  129. --- a/chrome/browser/net/chrome_network_delegate.cc
  130. +++ b/chrome/browser/net/chrome_network_delegate.cc
  131. @@ -129,6 +129,13 @@ bool IsAccessAllowedAndroid(const base::FilePath& path) {
  132. if (external_storage_path.IsParent(path))
  133. return true;
  134. + // access to the crash folder is allowed for the download by the user
  135. + base::FilePath cache_dir;
  136. + base::android::GetCacheDirectory(&cache_dir);
  137. + base::FilePath upload_log_path = cache_dir.Append("Crash Reports");
  138. + if (upload_log_path.IsParent(path))
  139. + return true;
  140. +
  141. std::vector<base::FilePath> allowlist;
  142. std::vector<base::FilePath> all_download_dirs =
  143. base::android::GetAllPrivateDownloadsDirectories();
  144. diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
  145. --- a/chrome/browser/ui/BUILD.gn
  146. +++ b/chrome/browser/ui/BUILD.gn
  147. @@ -577,6 +577,7 @@ static_library("ui") {
  148. "//third_party/re2",
  149. "//third_party/webrtc_overrides:webrtc_component",
  150. "//third_party/zlib",
  151. + "//third_party/zlib/google:zip",
  152. "//ui/accessibility",
  153. "//ui/base",
  154. "//ui/base:data_exchange",
  155. diff --git a/chrome/browser/ui/webui/crashes_ui.cc b/chrome/browser/ui/webui/crashes_ui.cc
  156. --- a/chrome/browser/ui/webui/crashes_ui.cc
  157. +++ b/chrome/browser/ui/webui/crashes_ui.cc
  158. @@ -38,6 +38,17 @@
  159. #include "google_apis/gaia/gaia_auth_util.h"
  160. #include "ui/base/resource/resource_bundle.h"
  161. +#include "base/logging.h"
  162. +#include "base/debug/dump_without_crashing.h"
  163. +#include "base/files/file_util.h"
  164. +#include "base/files/file_enumerator.h"
  165. +#include "base/files/scoped_temp_dir.h"
  166. +#include "base/task/task_traits.h"
  167. +#include "base/task/thread_pool.h"
  168. +#include "base/android/path_utils.h"
  169. +#include "net/base/filename_util.h"
  170. +#include "third_party/zlib/google/zip.h"
  171. +
  172. #if BUILDFLAG(IS_CHROMEOS_ASH)
  173. #include "chromeos/dbus/dbus_thread_manager.h"
  174. #include "chromeos/dbus/debug_daemon/debug_daemon_client.h"
  175. @@ -75,6 +86,10 @@ content::WebUIDataSource* CreateCrashesUIHTMLSource() {
  176. return source;
  177. }
  178. +constexpr base::TaskTraits kLoadingTaskTraits = {
  179. + base::MayBlock(), base::TaskPriority::USER_BLOCKING,
  180. + base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN};
  181. +
  182. ////////////////////////////////////////////////////////////////////////////////
  183. //
  184. // CrashesDOMHandler
  185. @@ -84,7 +99,7 @@ content::WebUIDataSource* CreateCrashesUIHTMLSource() {
  186. // The handler for Javascript messages for the chrome://crashes/ page.
  187. class CrashesDOMHandler : public WebUIMessageHandler {
  188. public:
  189. - CrashesDOMHandler();
  190. + CrashesDOMHandler(content::WebContents* web_contents);
  191. ~CrashesDOMHandler() override;
  192. // WebUIMessageHandler implementation.
  193. @@ -96,6 +111,8 @@ class CrashesDOMHandler : public WebUIMessageHandler {
  194. // Asynchronously fetches the list of crashes. Called from JS.
  195. void HandleRequestCrashes(const base::ListValue* args);
  196. + void RequestCrashesList();
  197. +
  198. #if BUILDFLAG(IS_CHROMEOS_ASH)
  199. // Asynchronously triggers crash uploading. Called from JS.
  200. void HandleRequestUploads(const base::ListValue* args);
  201. @@ -107,15 +124,28 @@ class CrashesDOMHandler : public WebUIMessageHandler {
  202. // Asynchronously requests a user triggered upload. Called from JS.
  203. void HandleRequestSingleCrashUpload(const base::ListValue* args);
  204. + std::string RequestSingleUpload(const std::string& local_id) const;
  205. + void RequestSingleUploadCallback(const std::string& local_id, const std::string& filename);
  206. +
  207. + // Asynchronously requests a user log extraction. Called from JS.
  208. + void HandleRequestNewExtraction(const base::ListValue* args);
  209. + void RequestNewExtraction();
  210. +
  211. + // Requests remove all crash files. Called from JS.
  212. + void HandleRequestClearAll(const base::ListValue* args);
  213. + void ClearAll();
  214. +
  215. scoped_refptr<UploadList> upload_list_;
  216. bool list_available_;
  217. bool first_load_;
  218. + content::WebContents* web_contents_;
  219. DISALLOW_COPY_AND_ASSIGN(CrashesDOMHandler);
  220. };
  221. -CrashesDOMHandler::CrashesDOMHandler()
  222. - : list_available_(false), first_load_(true) {
  223. +CrashesDOMHandler::CrashesDOMHandler(content::WebContents* web_contents)
  224. + : list_available_(false), first_load_(true),
  225. + web_contents_(web_contents) {
  226. upload_list_ = CreateCrashUploadList();
  227. }
  228. @@ -142,10 +172,24 @@ void CrashesDOMHandler::RegisterMessages() {
  229. crash_reporter::kCrashesUIRequestSingleCrashUpload,
  230. base::BindRepeating(&CrashesDOMHandler::HandleRequestSingleCrashUpload,
  231. base::Unretained(this)));
  232. +
  233. + web_ui()->RegisterMessageCallback(
  234. + crash_reporter::kCrashesUIHandleClearAll,
  235. + base::BindRepeating(&CrashesDOMHandler::HandleRequestClearAll,
  236. + base::Unretained(this)));
  237. +
  238. + web_ui()->RegisterMessageCallback(
  239. + crash_reporter::kCrashesUIHandleRequestNewExtraction,
  240. + base::BindRepeating(&CrashesDOMHandler::HandleRequestNewExtraction,
  241. + base::Unretained(this)));
  242. }
  243. void CrashesDOMHandler::HandleRequestCrashes(const base::ListValue* args) {
  244. AllowJavascript();
  245. + RequestCrashesList();
  246. +}
  247. +
  248. +void CrashesDOMHandler::RequestCrashesList() {
  249. if (first_load_) {
  250. first_load_ = false;
  251. if (list_available_)
  252. @@ -178,8 +222,7 @@ void CrashesDOMHandler::OnUploadListAvailable() {
  253. }
  254. void CrashesDOMHandler::UpdateUI() {
  255. - bool crash_reporting_enabled =
  256. - ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled();
  257. + bool crash_reporting_enabled = true;
  258. bool system_crash_reporter = false;
  259. #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
  260. @@ -241,12 +284,116 @@ void CrashesDOMHandler::HandleRequestSingleCrashUpload(
  261. bool success = args->GetString(0, &local_id);
  262. DCHECK(success);
  263. - // Only allow manual uploads if crash uploads aren’t disabled by policy.
  264. - if (!ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled() &&
  265. - IsMetricsReportingPolicyManaged()) {
  266. - return;
  267. + base::ThreadPool::PostTaskAndReplyWithResult(
  268. + FROM_HERE, kLoadingTaskTraits,
  269. + base::BindOnce(&CrashesDOMHandler::RequestSingleUpload, base::Unretained(this), local_id),
  270. + base::BindOnce(&CrashesDOMHandler::RequestSingleUploadCallback, base::Unretained(this), local_id));
  271. +}
  272. +
  273. +std::string CrashesDOMHandler::RequestSingleUpload(const std::string& local_id) const {
  274. + // get crash file path
  275. + std::string info_file_path = upload_list_->GetFilePathByLocalId(local_id);
  276. + if (info_file_path.empty()) {
  277. + LOG(ERROR) << "Crash report: file path is not set for " << local_id;
  278. + return std::string();
  279. + }
  280. + base::FilePath crash_file_path(info_file_path);
  281. +
  282. + // get android crash report dir
  283. + base::FilePath cache_dir;
  284. + base::android::GetCacheDirectory(&cache_dir);
  285. + base::FilePath upload_log_path = cache_dir.Append("Crash Reports");
  286. +
  287. + // crash reports can have multiple extensions (e.g. foo.dmp, foo.dmp.try1,
  288. + // foo.skipped.try0), remove it
  289. + base::FilePath zip_file = crash_file_path;
  290. + while (zip_file != zip_file.RemoveExtension())
  291. + zip_file = zip_file.RemoveExtension();
  292. +
  293. + // make zip file name, like "ec708a7b-cb17-44e7-8dae-e32f6c45cb8c.zip"
  294. + zip_file = upload_log_path.Append(zip_file.BaseName())
  295. + .AddExtensionASCII(".zip");
  296. + // since the download is always allowed, the generation takes place only
  297. + // at the first request, so if exists return it
  298. + if (base::PathExists(zip_file))
  299. + return zip_file.value();
  300. +
  301. + // original code remove the file immediately after upload.
  302. + // we changed this behavior but it is still possible that the file no longer exists
  303. + // because in uploads.log it could be indicated but the file was deleted by self-cleaning
  304. + if (!base::PathExists(crash_file_path)) {
  305. + LOG(ERROR) << "Crash report: file " << crash_file_path
  306. + << " no more avaiable";
  307. + return std::string();
  308. + }
  309. +
  310. + // temporary folder for zip, auto-removed when out of scope
  311. + base::ScopedTempDir temp_dir;
  312. + if (!temp_dir.CreateUniqueTempDir()) {
  313. + LOG(ERROR) << "Crash report: cannot create temp directory";
  314. + return std::string();
  315. + }
  316. +
  317. + // temporary file for zip content
  318. + base::FilePath dest_file = temp_dir.GetPath().Append(crash_file_path.BaseName());
  319. +
  320. + // make zip file
  321. + if (base::CopyFile(crash_file_path, dest_file)) {
  322. + if (zip::Zip(temp_dir.GetPath(), zip_file, false)) {
  323. + return zip_file.value();
  324. + }
  325. + }
  326. +
  327. + LOG(ERROR) << "Crash report: cannot create zip content";
  328. + return std::string();
  329. +}
  330. +
  331. +void CrashesDOMHandler::RequestSingleUploadCallback(const std::string& local_id,
  332. + const std::string& file_name) {
  333. + if (!file_name.empty()) {
  334. + upload_list_->RequestSingleUploadAsync(local_id);
  335. +
  336. + base::FilePath file_path(file_name);
  337. + web_contents_->GetController().LoadURL(
  338. + net::FilePathToFileURL(file_path), {}, {}, {});
  339. + }
  340. +}
  341. +
  342. +void CrashesDOMHandler::HandleRequestNewExtraction(
  343. + const base::ListValue* args) {
  344. + base::ThreadPool::PostTask(
  345. + FROM_HERE, kLoadingTaskTraits,
  346. + base::BindOnce(&CrashesDOMHandler::RequestNewExtraction, base::Unretained(this)));
  347. +}
  348. +
  349. +void CrashesDOMHandler::RequestNewExtraction() {
  350. + base::debug::DumpWithoutCrashing();
  351. + // ask java to get file from crashpad and to add logcat
  352. + upload_list_->RequestNewExtraction();
  353. +}
  354. +
  355. +void CrashesDOMHandler::HandleRequestClearAll(
  356. + const base::ListValue* args) {
  357. + base::ThreadPool::PostTaskAndReply(
  358. + FROM_HERE, kLoadingTaskTraits,
  359. + base::BindOnce(&CrashesDOMHandler::ClearAll, base::Unretained(this)),
  360. + base::BindOnce(&CrashesDOMHandler::RequestCrashesList, base::Unretained(this)));
  361. +}
  362. +
  363. +void CrashesDOMHandler::ClearAll() {
  364. + // get android crash report dir
  365. + base::FilePath cache_dir;
  366. + base::android::GetCacheDirectory(&cache_dir);
  367. + base::FilePath upload_log_path = cache_dir.Append("Crash Reports");
  368. +
  369. + base::FileEnumerator dir_enum(
  370. + upload_log_path,
  371. + /*recursive=*/false, base::FileEnumerator::FILES);
  372. + base::FilePath full_name;
  373. + while (full_name = dir_enum.Next(), !full_name.empty()) {
  374. + // remove all files, don't care for result
  375. + base::DeleteFile(full_name);
  376. }
  377. - upload_list_->RequestSingleUploadAsync(local_id);
  378. }
  379. } // namespace
  380. @@ -258,7 +405,8 @@ void CrashesDOMHandler::HandleRequestSingleCrashUpload(
  381. ///////////////////////////////////////////////////////////////////////////////
  382. CrashesUI::CrashesUI(content::WebUI* web_ui) : WebUIController(web_ui) {
  383. - web_ui->AddMessageHandler(std::make_unique<CrashesDOMHandler>());
  384. + web_ui->AddMessageHandler(std::make_unique<CrashesDOMHandler>(
  385. + web_ui->GetWebContents()));
  386. // Set up the chrome://crashes/ source.
  387. Profile* profile = Profile::FromWebUI(web_ui);
  388. diff --git a/components/crash/core/browser/crashes_ui_util.cc b/components/crash/core/browser/crashes_ui_util.cc
  389. --- a/components/crash/core/browser/crashes_ui_util.cc
  390. +++ b/components/crash/core/browser/crashes_ui_util.cc
  391. @@ -39,6 +39,8 @@ const CrashesUILocalizedString kCrashesUILocalizedStrings[] = {
  392. {"uploadId", IDS_CRASH_REPORT_UPLOADED_ID},
  393. {"uploadNowLinkText", IDS_CRASH_UPLOAD_NOW_LINK_TEXT},
  394. {"uploadTime", IDS_CRASH_REPORT_UPLOADED_TIME},
  395. + {"clearAll", IDS_CRASH_CLEAR_ALL_TEXT},
  396. + {"extractNow", IDS_CRASH_EXTRACT_NOW_TEXT},
  397. };
  398. const size_t kCrashesUILocalizedStringsCount =
  399. @@ -52,6 +54,8 @@ const char kCrashesUIRequestCrashUpload[] = "requestCrashUpload";
  400. const char kCrashesUIShortProductName[] = "shortProductName";
  401. const char kCrashesUIUpdateCrashList[] = "update-crash-list";
  402. const char kCrashesUIRequestSingleCrashUpload[] = "requestSingleCrashUpload";
  403. +const char kCrashesUIHandleClearAll[] = "requestClearAll";
  404. +const char kCrashesUIHandleRequestNewExtraction[] = "requestNewExtraction";
  405. std::string UploadInfoStateAsString(UploadList::UploadInfo::State state) {
  406. switch (state) {
  407. diff --git a/components/crash/core/browser/crashes_ui_util.h b/components/crash/core/browser/crashes_ui_util.h
  408. --- a/components/crash/core/browser/crashes_ui_util.h
  409. +++ b/components/crash/core/browser/crashes_ui_util.h
  410. @@ -36,6 +36,8 @@ extern const char kCrashesUIRequestCrashUpload[];
  411. extern const char kCrashesUIShortProductName[];
  412. extern const char kCrashesUIUpdateCrashList[];
  413. extern const char kCrashesUIRequestSingleCrashUpload[];
  414. +extern const char kCrashesUIHandleClearAll[];
  415. +extern const char kCrashesUIHandleRequestNewExtraction[];
  416. // Converts and appends the most recent uploads to |out_value|.
  417. void UploadListToValue(UploadList* upload_list, base::ListValue* out_value);
  418. diff --git a/components/crash/core/browser/resources/crashes.css b/components/crash/core/browser/resources/crashes.css
  419. --- a/components/crash/core/browser/resources/crashes.css
  420. +++ b/components/crash/core/browser/resources/crashes.css
  421. @@ -3,7 +3,9 @@
  422. * found in the LICENSE file. */
  423. body {
  424. - margin: 20px;
  425. + margin: 0;
  426. + padding: 1em;
  427. + font-size: 100%;
  428. }
  429. h1 {
  430. @@ -27,7 +29,6 @@ html[dir=rtl] h1 {
  431. background-color: rgb(235, 239, 250);
  432. border: 1px solid #bbb;
  433. border-radius: 2px;
  434. - display: flex;
  435. font-size: 100%;
  436. padding: 4px;
  437. }
  438. @@ -80,3 +81,65 @@ html[dir=rtl] h1 {
  439. .not-uploaded {
  440. color: #a0a0a0;
  441. }
  442. +
  443. +label {
  444. + float: right;
  445. +}
  446. +
  447. +#countBanner > div {
  448. + display: flex;
  449. + justify-content: flex-end;
  450. + margin-top: 10px;
  451. +}
  452. +
  453. +.spinner {
  454. + width: 50px;
  455. + height: 40px;
  456. + text-align: center;
  457. + font-size: 10px;
  458. +}
  459. +
  460. +.spinner > div {
  461. + background-color: #333;
  462. + height: 100%;
  463. + width: 6px;
  464. + display: inline-block;
  465. +
  466. + -webkit-animation: sk-stretchdelay 1.2s infinite ease-in-out;
  467. + animation: sk-stretchdelay 1.2s infinite ease-in-out;
  468. +}
  469. +
  470. +.spinner .rect2 {
  471. + -webkit-animation-delay: -1.1s;
  472. + animation-delay: -1.1s;
  473. +}
  474. +
  475. +.spinner .rect3 {
  476. + -webkit-animation-delay: -1.0s;
  477. + animation-delay: -1.0s;
  478. +}
  479. +
  480. +.spinner .rect4 {
  481. + -webkit-animation-delay: -0.9s;
  482. + animation-delay: -0.9s;
  483. +}
  484. +
  485. +.spinner .rect5 {
  486. + -webkit-animation-delay: -0.8s;
  487. + animation-delay: -0.8s;
  488. +}
  489. +
  490. +@-webkit-keyframes sk-stretchdelay {
  491. + 0%, 40%, 100% { -webkit-transform: scaleY(0.4) }
  492. + 20% { -webkit-transform: scaleY(1.0) }
  493. +}
  494. +
  495. +@keyframes sk-stretchdelay {
  496. + 0%, 40%, 100% {
  497. + transform: scaleY(0.4);
  498. + -webkit-transform: scaleY(0.4);
  499. + } 20% {
  500. + transform: scaleY(1.0);
  501. + -webkit-transform: scaleY(1.0);
  502. + }
  503. +}
  504. diff --git a/components/crash/core/browser/resources/crashes.html b/components/crash/core/browser/resources/crashes.html
  505. --- a/components/crash/core/browser/resources/crashes.html
  506. +++ b/components/crash/core/browser/resources/crashes.html
  507. @@ -1,6 +1,7 @@
  508. <!doctype html>
  509. <html dir="$i18n{textdirection}" lang="$i18n{language}">
  510. <head>
  511. + <meta name="viewport" content="width=device-width, initial-scale=1.0">
  512. <meta charset="utf-8">
  513. <if expr="is_ios">
  514. @@ -39,6 +40,22 @@
  515. <input type="checkbox" id="showDevDetails">
  516. $i18n{showDeveloperDetails}
  517. </label>
  518. + <div></div>
  519. + <div>
  520. + <button class="button" id="clearAll">
  521. + $i18n{clearAll}
  522. + </button>
  523. + <button class="button" id="newExtraction">
  524. + $i18n{extractNow}
  525. + </button>
  526. + <div class="spinner" id="spinner" hidden>
  527. + <div class="rect1"></div>
  528. + <div class="rect2"></div>
  529. + <div class="rect3"></div>
  530. + <div class="rect4"></div>
  531. + <div class="rect5"></div>
  532. + </div>
  533. + </div>
  534. </h2>
  535. <div id="crashList">
  536. diff --git a/components/crash/core/browser/resources/crashes.js b/components/crash/core/browser/resources/crashes.js
  537. --- a/components/crash/core/browser/resources/crashes.js
  538. +++ b/components/crash/core/browser/resources/crashes.js
  539. @@ -49,6 +49,7 @@ function updateCrashList({
  540. $('disabledMode').hidden = enabled;
  541. $('crashUploadStatus').hidden = !enabled || !dynamicBackend;
  542. + $('spinner').hidden = true;
  543. const template = crashList.getElementsByTagName('template')[0];
  544. @@ -115,22 +116,16 @@ function updateCrashList({
  545. uploadTime.querySelector('.value').textContent = crash.upload_time;
  546. - sendNowButton.remove();
  547. - fileBugButton.onclick = () => fileBug(crash.id, os, version);
  548. + fileBugButton.remove();
  549. } else {
  550. uploadId.remove();
  551. uploadTime.remove();
  552. fileBugButton.remove();
  553. - // Do not allow crash submission if the Chromium build does not support
  554. - // it, or if the user already requested it.
  555. - if (!manualUploads || crash.state === 'pending_user_requested') {
  556. - sendNowButton.remove();
  557. - }
  558. - sendNowButton.onclick = (e) => {
  559. - e.target.disabled = true;
  560. - chrome.send('requestSingleCrashUpload', [crash.local_id]);
  561. - };
  562. }
  563. + sendNowButton.onclick = (e) => {
  564. + e.target.disabled = true;
  565. + chrome.send('requestSingleCrashUpload', [crash.local_id]);
  566. + };
  567. const fileSize = crashRow.querySelector('.file-size');
  568. if (crash.file_size === '') {
  569. @@ -201,6 +196,27 @@ function requestCrashUpload() {
  570. refreshCrashListId = setTimeout(requestCrashes, 5000);
  571. }
  572. +/**
  573. + * Request new log extraction.
  574. + */
  575. + function requestNewExtraction() {
  576. + chrome.send('requestNewExtraction');
  577. +
  578. + // show spinner
  579. + $('spinner').hidden = false;
  580. +
  581. + // Trigger a refresh in 3 seconds. Clear any previous requests.
  582. + clearTimeout(refreshCrashListId);
  583. + refreshCrashListId = setTimeout(requestCrashes, 3000);
  584. +}
  585. +
  586. +/**
  587. + * Request remove all crash files.
  588. + */
  589. + function requestClearAll() {
  590. + chrome.send('requestClearAll');
  591. +}
  592. +
  593. /**
  594. * Toggles hiding/showing the developer details of a crash report, depending
  595. * on the value of the check box.
  596. @@ -214,5 +230,7 @@ document.addEventListener('DOMContentLoaded', function() {
  597. addWebUIListener('update-crash-list', updateCrashList);
  598. $('uploadCrashes').onclick = requestCrashUpload;
  599. $('showDevDetails').onclick = toggleDevDetails;
  600. + $('clearAll').onclick = requestClearAll;
  601. + $('newExtraction').onclick = requestNewExtraction;
  602. requestCrashes();
  603. });
  604. diff --git a/components/crash_strings.grdp b/components/crash_strings.grdp
  605. --- a/components/crash_strings.grdp
  606. +++ b/components/crash_strings.grdp
  607. @@ -19,22 +19,22 @@
  608. Status:
  609. </message>
  610. <message name="IDS_CRASH_REPORT_STATUS_NOT_UPLOADED" desc="Value on chrome://crashes for the 'not uploaded' status of a crash report.">
  611. - Not uploaded
  612. + Not saved
  613. </message>
  614. <message name="IDS_CRASH_REPORT_STATUS_PENDING" desc="Value on chrome://crashes for the 'pending' status of a crash report.">
  615. - Not yet uploaded, or ignored
  616. + Not yet saved, or ignored
  617. </message>
  618. <message name="IDS_CRASH_REPORT_STATUS_PENDING_USER_REQUESTED" desc="Value on chrome://crashes for the 'pending user requested' status of a crash report.">
  619. - Upload requested by user
  620. + Save requested by user
  621. </message>
  622. <message name="IDS_CRASH_REPORT_STATUS_UPLOADED" desc="Value on chrome://crashes for the 'uploaded' status of a crash report.">
  623. - Uploaded
  624. + Saved
  625. </message>
  626. <message name="IDS_CRASH_REPORT_UPLOADED_ID" desc="Label on chrome://crashes for the identifier for an uploaded crash report on chrome://crashes">
  627. - Uploaded Crash Report ID:
  628. + Saved Crash Report File:
  629. </message>
  630. <message name="IDS_CRASH_REPORT_UPLOADED_TIME" desc="Label on chrome://crashes for the time at which the crash report was uploaded.">
  631. - Upload Time:
  632. + Saved Time:
  633. </message>
  634. <message name="IDS_CRASH_REPORT_LOCAL_ID" desc="Label on chrome://crashes for the identifier of a crash report on the user's machine">
  635. Local Crash Context:
  636. @@ -53,9 +53,15 @@
  637. Crash reporting is disabled.
  638. </message>
  639. <message name="IDS_CRASH_UPLOAD_MESSAGE" desc="Link text for triggering crash uploading on chrome://crashes">
  640. - Start uploading crashes
  641. + Start saving crashes
  642. </message>
  643. <message name="IDS_CRASH_UPLOAD_NOW_LINK_TEXT" desc="Link text for manual uploads of a crash report">
  644. - Send now
  645. + Save now
  646. + </message>
  647. + <message name="IDS_CRASH_CLEAR_ALL_TEXT" desc="Link text for clear all crash files">
  648. + Clear all
  649. + </message>
  650. + <message name="IDS_CRASH_EXTRACT_NOW_TEXT" desc="Link text for manual generation of a crash report">
  651. + Generate report
  652. </message>
  653. </grit-part>
  654. diff --git a/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/CrashFileManager.java b/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/CrashFileManager.java
  655. --- a/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/CrashFileManager.java
  656. +++ b/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/CrashFileManager.java
  657. @@ -107,6 +107,8 @@ public class CrashFileManager {
  658. private static final Pattern TMP_PATTERN = Pattern.compile("\\.tmp\\z");
  659. + private static final String SAVED_MINIDUMP_ZIP_SUFFIX = ".zip";
  660. +
  661. // The maximum number of non-uploaded crashes that may be kept in the crash reports directory.
  662. // Chosen to attempt to balance between keeping a generous number of crashes, and not using up
  663. // too much filesystem storage space for obsolete crash reports.
  664. @@ -116,7 +118,7 @@ public class CrashFileManager {
  665. // The maximum age, in days, considered acceptable for a crash report. Reports older than this
  666. // age will be removed. The constant is chosen to be quite conservative, while still allowing
  667. // users to eventually reclaim filesystem storage space from obsolete crash reports.
  668. - private static final int MAX_CRASH_REPORT_AGE_IN_DAYS = 30;
  669. + private static final int MAX_CRASH_REPORT_AGE_IN_DAYS = 5;
  670. // The maximum number of non-uploaded crashes to copy to the crash reports directory. The
  671. // difference between this value and MAX_CRASH_REPORTS_TO_KEEP is that TO_KEEP is only checked
  672. @@ -586,6 +588,9 @@ public class CrashFileManager {
  673. && !f.getName().contains(UPLOAD_FORCED_MINIDUMP_SUFFIX)) {
  674. continue;
  675. }
  676. + // as above, zip files must also be excluded
  677. + if (f.getName().endsWith(SAVED_MINIDUMP_ZIP_SUFFIX))
  678. + continue;
  679. String filenameSansExtension = f.getName().split("\\.")[0];
  680. if (filenameSansExtension.endsWith(localId)) {
  681. diff --git a/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/MinidumpUploadCallable.java b/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/MinidumpUploadCallable.java
  682. --- a/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/MinidumpUploadCallable.java
  683. +++ b/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/MinidumpUploadCallable.java
  684. @@ -63,26 +63,8 @@ public class MinidumpUploadCallable implements Callable<Integer> {
  685. if (mPermManager.isUploadEnabledForTests()) {
  686. Log.i(TAG, "Minidump upload enabled for tests, skipping other checks.");
  687. } else if (!CrashFileManager.isForcedUpload(mFileToUpload)) {
  688. - if (!mPermManager.isUsageAndCrashReportingPermittedByUser()) {
  689. - Log.i(TAG, "Minidump upload is not permitted by user. Marking file as skipped for "
  690. - + "cleanup to prevent future uploads.");
  691. - CrashFileManager.markUploadSkipped(mFileToUpload);
  692. - return MinidumpUploadStatus.USER_DISABLED;
  693. - }
  694. -
  695. - if (!mPermManager.isClientInMetricsSample()) {
  696. - Log.i(TAG, "Minidump upload skipped due to sampling. Marking file as skipped for "
  697. - + "cleanup to prevent future uploads.");
  698. - CrashFileManager.markUploadSkipped(mFileToUpload);
  699. - return MinidumpUploadStatus.DISABLED_BY_SAMPLING;
  700. - }
  701. -
  702. - if (!mPermManager.isNetworkAvailableForCrashUploads()) {
  703. - Log.i(TAG, "Minidump cannot currently be uploaded due to network constraints.");
  704. - return MinidumpUploadStatus.FAILURE;
  705. - }
  706. + return MinidumpUploadStatus.USER_DISABLED;
  707. }
  708. -
  709. MinidumpUploader.Result result = mMinidumpUploader.upload(mFileToUpload);
  710. if (result.isSuccess()) {
  711. String uploadId = result.message();
  712. diff --git a/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/MinidumpUploader.java b/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/MinidumpUploader.java
  713. --- a/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/MinidumpUploader.java
  714. +++ b/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/MinidumpUploader.java
  715. @@ -120,31 +120,10 @@ public class MinidumpUploader {
  716. if (fileToUpload == null || !fileToUpload.exists()) {
  717. return Result.failure("Crash report does not exist");
  718. }
  719. - HttpURLConnection connection =
  720. - mHttpURLConnectionFactory.createHttpURLConnection(CRASH_URL_STRING);
  721. - if (connection == null) {
  722. - return Result.failure("Failed to create connection");
  723. - }
  724. - configureConnectionForHttpPost(connection, readBoundary(fileToUpload));
  725. -
  726. - try (InputStream minidumpInputStream = new FileInputStream(fileToUpload);
  727. - OutputStream requestBodyStream =
  728. - new GZIPOutputStream(connection.getOutputStream())) {
  729. - streamCopy(minidumpInputStream, requestBodyStream);
  730. - int responseCode = connection.getResponseCode();
  731. - if (isSuccessful(responseCode)) {
  732. - // The crash server returns the crash ID in the response body.
  733. - String responseContent = getResponseContentAsString(connection);
  734. - String uploadId = responseContent != null ? responseContent : "unknown";
  735. - return Result.success(uploadId);
  736. - } else {
  737. - // Return the remote error code and message.
  738. - return Result.uploadError(responseCode, connection.getResponseMessage());
  739. - }
  740. - } finally {
  741. - connection.disconnect();
  742. - }
  743. - } catch (IOException | RuntimeException e) {
  744. + // for us, it's always good
  745. + // returns the file name without path, which will be registered as local_id
  746. + return Result.success(fileToUpload.getName());
  747. + } catch (RuntimeException e) {
  748. return Result.failure(e.toString());
  749. }
  750. }
  751. diff --git a/components/upload_list/text_log_upload_list.cc b/components/upload_list/text_log_upload_list.cc
  752. --- a/components/upload_list/text_log_upload_list.cc
  753. +++ b/components/upload_list/text_log_upload_list.cc
  754. @@ -108,6 +108,7 @@ std::unique_ptr<TextLogUploadList::UploadInfo> TryParseCsvLogEntry(
  755. }
  756. auto info = std::make_unique<TextLogUploadList::UploadInfo>(components[1],
  757. upload_time);
  758. + info->file_path = components[1];
  759. // Add local ID if present.
  760. if (components.size() > 2)
  761. diff --git a/components/upload_list/upload_list.cc b/components/upload_list/upload_list.cc
  762. --- a/components/upload_list/upload_list.cc
  763. +++ b/components/upload_list/upload_list.cc
  764. @@ -55,7 +55,8 @@ UploadList::UploadInfo::UploadInfo(const UploadInfo& upload_info)
  765. capture_time(upload_info.capture_time),
  766. state(upload_info.state),
  767. source(upload_info.source),
  768. - file_size(upload_info.file_size) {}
  769. + file_size(upload_info.file_size),
  770. + file_path(upload_info.file_path) {}
  771. UploadList::UploadInfo::~UploadInfo() = default;
  772. @@ -108,6 +109,11 @@ void UploadList::RequestSingleUpload(const std::string& local_id) {
  773. NOTREACHED();
  774. }
  775. +void UploadList::RequestNewExtraction() {
  776. + // only available for Android. overrided in crash_upload_list_android.cc
  777. + NOTREACHED();
  778. +}
  779. +
  780. void UploadList::OnLoadComplete(const std::vector<UploadInfo>& uploads) {
  781. uploads_ = uploads;
  782. if (!load_callback_.is_null())
  783. @@ -118,3 +124,12 @@ void UploadList::OnClearComplete() {
  784. if (!clear_callback_.is_null())
  785. std::move(clear_callback_).Run();
  786. }
  787. +
  788. +std::string UploadList::GetFilePathByLocalId(const std::string& local_id) {
  789. + for (auto info : uploads_) {
  790. + if (info.local_id == local_id) {
  791. + return info.file_path;
  792. + }
  793. + }
  794. + return std::string();
  795. +}
  796. diff --git a/components/upload_list/upload_list.h b/components/upload_list/upload_list.h
  797. --- a/components/upload_list/upload_list.h
  798. +++ b/components/upload_list/upload_list.h
  799. @@ -66,6 +66,9 @@ class UploadList : public base::RefCountedThreadSafe<UploadList> {
  800. // Formatted file size for locally stored data.
  801. std::u16string file_size;
  802. +
  803. + // path of crash file
  804. + std::string file_path;
  805. };
  806. UploadList();
  807. @@ -92,6 +95,12 @@ class UploadList : public base::RefCountedThreadSafe<UploadList> {
  808. // Must be called only after a Load() callback has been received.
  809. void GetUploads(size_t max_count, std::vector<UploadInfo>* uploads);
  810. + // Get full path of crash file for local_id
  811. + std::string GetFilePathByLocalId(const std::string& local_id);
  812. +
  813. + // Request new log extraction
  814. + virtual void RequestNewExtraction();
  815. +
  816. protected:
  817. virtual ~UploadList();
  818. --
  819. 2.17.1