Logcat-crash-reports-UI.patch 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869
  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 | 166 ++++++++++++++++--
  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, 374 insertions(+), 80 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. @@ -45,6 +45,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. @@ -455,4 +460,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. @@ -131,6 +131,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. @@ -594,6 +594,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" // nogncheck
  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(base::Value::ConstListView args);
  196. + void RequestCrashesList();
  197. +
  198. #if BUILDFLAG(IS_CHROMEOS_ASH)
  199. // Asynchronously triggers crash uploading. Called from JS.
  200. void HandleRequestUploads(base::Value::ConstListView args);
  201. @@ -107,15 +124,28 @@ class CrashesDOMHandler : public WebUIMessageHandler {
  202. // Asynchronously requests a user triggered upload. Called from JS.
  203. void HandleRequestSingleCrashUpload(base::Value::ConstListView 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(base::Value::ConstListView args);
  209. + void RequestNewExtraction();
  210. +
  211. + // Requests remove all crash files. Called from JS.
  212. + void HandleRequestClearAll(base::Value::ConstListView 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(base::Value::ConstListView 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. @@ -235,14 +278,112 @@ void CrashesDOMHandler::UpdateUI() {
  261. void CrashesDOMHandler::HandleRequestSingleCrashUpload(
  262. base::Value::ConstListView args) {
  263. - // Only allow manual uploads if crash uploads aren’t disabled by policy.
  264. - if (!ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled() &&
  265. - IsMetricsReportingPolicyManaged()) {
  266. - return;
  267. + std::string local_id = args[0].GetString();
  268. + base::ThreadPool::PostTaskAndReplyWithResult(
  269. + FROM_HERE, kLoadingTaskTraits,
  270. + base::BindOnce(&CrashesDOMHandler::RequestSingleUpload, base::Unretained(this), local_id),
  271. + base::BindOnce(&CrashesDOMHandler::RequestSingleUploadCallback, base::Unretained(this), local_id));
  272. +}
  273. +
  274. +std::string CrashesDOMHandler::RequestSingleUpload(const std::string& local_id) const {
  275. + // get crash file path
  276. + std::string info_file_path = upload_list_->GetFilePathByLocalId(local_id);
  277. + if (info_file_path.empty()) {
  278. + LOG(ERROR) << "Crash report: file path is not set for " << local_id;
  279. + return std::string();
  280. + }
  281. + base::FilePath crash_file_path(info_file_path);
  282. +
  283. + // get android crash report dir
  284. + base::FilePath cache_dir;
  285. + base::android::GetCacheDirectory(&cache_dir);
  286. + base::FilePath upload_log_path = cache_dir.Append("Crash Reports");
  287. +
  288. + // crash reports can have multiple extensions (e.g. foo.dmp, foo.dmp.try1,
  289. + // foo.skipped.try0), remove it
  290. + base::FilePath zip_file_name = crash_file_path;
  291. + while (zip_file_name != zip_file_name.RemoveExtension())
  292. + zip_file_name = zip_file_name.RemoveExtension();
  293. +
  294. + // make zip file name, like "ec708a7b-cb17-44e7-8dae-e32f6c45cb8c.zip"
  295. + zip_file_name = upload_log_path.Append(zip_file_name.BaseName())
  296. + .AddExtensionASCII(".zip");
  297. + // since the download is always allowed, the generation takes place only
  298. + // at the first request, so if exists return it
  299. + if (base::PathExists(zip_file_name))
  300. + return zip_file_name.value();
  301. +
  302. + // original code remove the file immediately after upload.
  303. + // we changed this behavior but it is still possible that the file no longer exists
  304. + // because in uploads.log it could be indicated but the file was deleted by self-cleaning
  305. + if (!base::PathExists(crash_file_path)) {
  306. + LOG(ERROR) << "Crash report: file " << crash_file_path
  307. + << " no more available";
  308. + return std::string();
  309. }
  310. - std::string local_id = args[0].GetString();
  311. - upload_list_->RequestSingleUploadAsync(local_id);
  312. + std::vector<base::FilePath> files_list;
  313. + files_list.push_back(crash_file_path.BaseName());
  314. +
  315. + // open zip file
  316. + base::File zip_f(zip_file_name,
  317. + base::File::FLAG_CREATE | base::File::FLAG_WRITE);
  318. + auto result = zip::ZipFiles(crash_file_path.DirName(), files_list, zip_f.GetPlatformFile());
  319. + zip_f.Close();
  320. + if (result) {
  321. + return zip_file_name.value();
  322. + }
  323. +
  324. + LOG(ERROR) << "Crash report: cannot create zip content";
  325. + return std::string();
  326. +}
  327. +
  328. +void CrashesDOMHandler::RequestSingleUploadCallback(const std::string& local_id,
  329. + const std::string& file_name) {
  330. + if (!file_name.empty()) {
  331. + upload_list_->RequestSingleUploadAsync(local_id);
  332. +
  333. + base::FilePath file_path(file_name);
  334. + web_contents_->GetController().LoadURL(
  335. + net::FilePathToFileURL(file_path), {}, {}, {});
  336. + }
  337. +}
  338. +
  339. +void CrashesDOMHandler::HandleRequestNewExtraction(
  340. + base::Value::ConstListView args) {
  341. + base::ThreadPool::PostTask(
  342. + FROM_HERE, kLoadingTaskTraits,
  343. + base::BindOnce(&CrashesDOMHandler::RequestNewExtraction, base::Unretained(this)));
  344. +}
  345. +
  346. +void CrashesDOMHandler::RequestNewExtraction() {
  347. + base::debug::DumpWithoutCrashing();
  348. + // ask java to get file from crashpad and to add logcat
  349. + upload_list_->RequestNewExtraction();
  350. +}
  351. +
  352. +void CrashesDOMHandler::HandleRequestClearAll(
  353. + base::Value::ConstListView args) {
  354. + base::ThreadPool::PostTaskAndReply(
  355. + FROM_HERE, kLoadingTaskTraits,
  356. + base::BindOnce(&CrashesDOMHandler::ClearAll, base::Unretained(this)),
  357. + base::BindOnce(&CrashesDOMHandler::RequestCrashesList, base::Unretained(this)));
  358. +}
  359. +
  360. +void CrashesDOMHandler::ClearAll() {
  361. + // get android crash report dir
  362. + base::FilePath cache_dir;
  363. + base::android::GetCacheDirectory(&cache_dir);
  364. + base::FilePath upload_log_path = cache_dir.Append("Crash Reports");
  365. +
  366. + base::FileEnumerator dir_enum(
  367. + upload_log_path,
  368. + /*recursive=*/false, base::FileEnumerator::FILES);
  369. + base::FilePath full_name;
  370. + while (full_name = dir_enum.Next(), !full_name.empty()) {
  371. + // remove all files, don't care for result
  372. + base::DeleteFile(full_name);
  373. + }
  374. }
  375. } // namespace
  376. @@ -254,7 +395,8 @@ void CrashesDOMHandler::HandleRequestSingleCrashUpload(
  377. ///////////////////////////////////////////////////////////////////////////////
  378. CrashesUI::CrashesUI(content::WebUI* web_ui) : WebUIController(web_ui) {
  379. - web_ui->AddMessageHandler(std::make_unique<CrashesDOMHandler>());
  380. + web_ui->AddMessageHandler(std::make_unique<CrashesDOMHandler>(
  381. + web_ui->GetWebContents()));
  382. // Set up the chrome://crashes/ source.
  383. Profile* profile = Profile::FromWebUI(web_ui);
  384. diff --git a/components/crash/core/browser/crashes_ui_util.cc b/components/crash/core/browser/crashes_ui_util.cc
  385. --- a/components/crash/core/browser/crashes_ui_util.cc
  386. +++ b/components/crash/core/browser/crashes_ui_util.cc
  387. @@ -39,6 +39,8 @@ const CrashesUILocalizedString kCrashesUILocalizedStrings[] = {
  388. {"uploadId", IDS_CRASH_REPORT_UPLOADED_ID},
  389. {"uploadNowLinkText", IDS_CRASH_UPLOAD_NOW_LINK_TEXT},
  390. {"uploadTime", IDS_CRASH_REPORT_UPLOADED_TIME},
  391. + {"clearAll", IDS_CRASH_CLEAR_ALL_TEXT},
  392. + {"extractNow", IDS_CRASH_EXTRACT_NOW_TEXT},
  393. };
  394. const size_t kCrashesUILocalizedStringsCount =
  395. @@ -52,6 +54,8 @@ const char kCrashesUIRequestCrashUpload[] = "requestCrashUpload";
  396. const char kCrashesUIShortProductName[] = "shortProductName";
  397. const char kCrashesUIUpdateCrashList[] = "update-crash-list";
  398. const char kCrashesUIRequestSingleCrashUpload[] = "requestSingleCrashUpload";
  399. +const char kCrashesUIHandleClearAll[] = "requestClearAll";
  400. +const char kCrashesUIHandleRequestNewExtraction[] = "requestNewExtraction";
  401. std::string UploadInfoStateAsString(UploadList::UploadInfo::State state) {
  402. switch (state) {
  403. diff --git a/components/crash/core/browser/crashes_ui_util.h b/components/crash/core/browser/crashes_ui_util.h
  404. --- a/components/crash/core/browser/crashes_ui_util.h
  405. +++ b/components/crash/core/browser/crashes_ui_util.h
  406. @@ -36,6 +36,8 @@ extern const char kCrashesUIRequestCrashUpload[];
  407. extern const char kCrashesUIShortProductName[];
  408. extern const char kCrashesUIUpdateCrashList[];
  409. extern const char kCrashesUIRequestSingleCrashUpload[];
  410. +extern const char kCrashesUIHandleClearAll[];
  411. +extern const char kCrashesUIHandleRequestNewExtraction[];
  412. // Converts and appends the most recent uploads to |out_value|.
  413. void UploadListToValue(UploadList* upload_list, base::ListValue* out_value);
  414. diff --git a/components/crash/core/browser/resources/crashes.css b/components/crash/core/browser/resources/crashes.css
  415. --- a/components/crash/core/browser/resources/crashes.css
  416. +++ b/components/crash/core/browser/resources/crashes.css
  417. @@ -3,7 +3,9 @@
  418. * found in the LICENSE file. */
  419. body {
  420. - margin: 20px;
  421. + margin: 0;
  422. + padding: 1em;
  423. + font-size: 100%;
  424. }
  425. h1 {
  426. @@ -27,7 +29,6 @@ html[dir=rtl] h1 {
  427. background-color: rgb(235, 239, 250);
  428. border: 1px solid #bbb;
  429. border-radius: 2px;
  430. - display: flex;
  431. font-size: 100%;
  432. padding: 4px;
  433. }
  434. @@ -80,3 +81,65 @@ html[dir=rtl] h1 {
  435. .not-uploaded {
  436. color: #a0a0a0;
  437. }
  438. +
  439. +label {
  440. + float: right;
  441. +}
  442. +
  443. +#countBanner > div {
  444. + display: flex;
  445. + justify-content: flex-end;
  446. + margin-top: 10px;
  447. +}
  448. +
  449. +.spinner {
  450. + width: 50px;
  451. + height: 40px;
  452. + text-align: center;
  453. + font-size: 10px;
  454. +}
  455. +
  456. +.spinner > div {
  457. + background-color: #333;
  458. + height: 100%;
  459. + width: 6px;
  460. + display: inline-block;
  461. +
  462. + -webkit-animation: sk-stretchdelay 1.2s infinite ease-in-out;
  463. + animation: sk-stretchdelay 1.2s infinite ease-in-out;
  464. +}
  465. +
  466. +.spinner .rect2 {
  467. + -webkit-animation-delay: -1.1s;
  468. + animation-delay: -1.1s;
  469. +}
  470. +
  471. +.spinner .rect3 {
  472. + -webkit-animation-delay: -1.0s;
  473. + animation-delay: -1.0s;
  474. +}
  475. +
  476. +.spinner .rect4 {
  477. + -webkit-animation-delay: -0.9s;
  478. + animation-delay: -0.9s;
  479. +}
  480. +
  481. +.spinner .rect5 {
  482. + -webkit-animation-delay: -0.8s;
  483. + animation-delay: -0.8s;
  484. +}
  485. +
  486. +@-webkit-keyframes sk-stretchdelay {
  487. + 0%, 40%, 100% { -webkit-transform: scaleY(0.4) }
  488. + 20% { -webkit-transform: scaleY(1.0) }
  489. +}
  490. +
  491. +@keyframes sk-stretchdelay {
  492. + 0%, 40%, 100% {
  493. + transform: scaleY(0.4);
  494. + -webkit-transform: scaleY(0.4);
  495. + } 20% {
  496. + transform: scaleY(1.0);
  497. + -webkit-transform: scaleY(1.0);
  498. + }
  499. +}
  500. diff --git a/components/crash/core/browser/resources/crashes.html b/components/crash/core/browser/resources/crashes.html
  501. --- a/components/crash/core/browser/resources/crashes.html
  502. +++ b/components/crash/core/browser/resources/crashes.html
  503. @@ -1,6 +1,7 @@
  504. <!doctype html>
  505. <html dir="$i18n{textdirection}" lang="$i18n{language}">
  506. <head>
  507. + <meta name="viewport" content="width=device-width, initial-scale=1.0">
  508. <meta charset="utf-8">
  509. <if expr="is_ios">
  510. @@ -39,6 +40,22 @@
  511. <input type="checkbox" id="showDevDetails">
  512. $i18n{showDeveloperDetails}
  513. </label>
  514. + <div style="clear: both"></div>
  515. + <div>
  516. + <button class="button" id="clearAll">
  517. + $i18n{clearAll}
  518. + </button>
  519. + <button class="button" id="newExtraction">
  520. + $i18n{extractNow}
  521. + </button>
  522. + <div class="spinner" id="spinner" hidden>
  523. + <div class="rect1"></div>
  524. + <div class="rect2"></div>
  525. + <div class="rect3"></div>
  526. + <div class="rect4"></div>
  527. + <div class="rect5"></div>
  528. + </div>
  529. + </div>
  530. </h2>
  531. <div id="crashList">
  532. diff --git a/components/crash/core/browser/resources/crashes.js b/components/crash/core/browser/resources/crashes.js
  533. --- a/components/crash/core/browser/resources/crashes.js
  534. +++ b/components/crash/core/browser/resources/crashes.js
  535. @@ -49,6 +49,7 @@ function updateCrashList({
  536. $('disabledMode').hidden = enabled;
  537. $('crashUploadStatus').hidden = !enabled || !dynamicBackend;
  538. + $('spinner').hidden = true;
  539. const template = crashList.getElementsByTagName('template')[0];
  540. @@ -115,22 +116,16 @@ function updateCrashList({
  541. uploadTime.querySelector('.value').textContent = crash.upload_time;
  542. - sendNowButton.remove();
  543. - fileBugButton.onclick = () => fileBug(crash.id, os, version);
  544. + fileBugButton.remove();
  545. } else {
  546. uploadId.remove();
  547. uploadTime.remove();
  548. fileBugButton.remove();
  549. - // Do not allow crash submission if the Chromium build does not support
  550. - // it, or if the user already requested it.
  551. - if (!manualUploads || crash.state === 'pending_user_requested') {
  552. - sendNowButton.remove();
  553. - }
  554. - sendNowButton.onclick = (e) => {
  555. - e.target.disabled = true;
  556. - chrome.send('requestSingleCrashUpload', [crash.local_id]);
  557. - };
  558. }
  559. + sendNowButton.onclick = (e) => {
  560. + e.target.disabled = true;
  561. + chrome.send('requestSingleCrashUpload', [crash.local_id]);
  562. + };
  563. const fileSize = crashRow.querySelector('.file-size');
  564. if (crash.file_size === '') {
  565. @@ -201,6 +196,27 @@ function requestCrashUpload() {
  566. refreshCrashListId = setTimeout(requestCrashes, 5000);
  567. }
  568. +/**
  569. + * Request new log extraction.
  570. + */
  571. + function requestNewExtraction() {
  572. + chrome.send('requestNewExtraction');
  573. +
  574. + // show spinner
  575. + $('spinner').hidden = false;
  576. +
  577. + // Trigger a refresh in 3 seconds. Clear any previous requests.
  578. + clearTimeout(refreshCrashListId);
  579. + refreshCrashListId = setTimeout(requestCrashes, 3000);
  580. +}
  581. +
  582. +/**
  583. + * Request remove all crash files.
  584. + */
  585. + function requestClearAll() {
  586. + chrome.send('requestClearAll');
  587. +}
  588. +
  589. /**
  590. * Toggles hiding/showing the developer details of a crash report, depending
  591. * on the value of the check box.
  592. @@ -214,5 +230,7 @@ document.addEventListener('DOMContentLoaded', function() {
  593. addWebUIListener('update-crash-list', updateCrashList);
  594. $('uploadCrashes').onclick = requestCrashUpload;
  595. $('showDevDetails').onclick = toggleDevDetails;
  596. + $('clearAll').onclick = requestClearAll;
  597. + $('newExtraction').onclick = requestNewExtraction;
  598. requestCrashes();
  599. });
  600. diff --git a/components/crash_strings.grdp b/components/crash_strings.grdp
  601. --- a/components/crash_strings.grdp
  602. +++ b/components/crash_strings.grdp
  603. @@ -19,22 +19,22 @@
  604. Status:
  605. </message>
  606. <message name="IDS_CRASH_REPORT_STATUS_NOT_UPLOADED" desc="Value on chrome://crashes for the 'not uploaded' status of a crash report.">
  607. - Not uploaded
  608. + Not saved
  609. </message>
  610. <message name="IDS_CRASH_REPORT_STATUS_PENDING" desc="Value on chrome://crashes for the 'pending' status of a crash report.">
  611. - Not yet uploaded, or ignored
  612. + Not yet saved, or ignored
  613. </message>
  614. <message name="IDS_CRASH_REPORT_STATUS_PENDING_USER_REQUESTED" desc="Value on chrome://crashes for the 'pending user requested' status of a crash report.">
  615. - Upload requested by user
  616. + Save requested by user
  617. </message>
  618. <message name="IDS_CRASH_REPORT_STATUS_UPLOADED" desc="Value on chrome://crashes for the 'uploaded' status of a crash report.">
  619. - Uploaded
  620. + Saved
  621. </message>
  622. <message name="IDS_CRASH_REPORT_UPLOADED_ID" desc="Label on chrome://crashes for the identifier for an uploaded crash report on chrome://crashes">
  623. - Uploaded Crash Report ID:
  624. + Saved Crash Report File:
  625. </message>
  626. <message name="IDS_CRASH_REPORT_UPLOADED_TIME" desc="Label on chrome://crashes for the time at which the crash report was uploaded.">
  627. - Upload Time:
  628. + Saved Time:
  629. </message>
  630. <message name="IDS_CRASH_REPORT_LOCAL_ID" desc="Label on chrome://crashes for the identifier of a crash report on the user's machine">
  631. Local Crash Context:
  632. @@ -53,9 +53,15 @@
  633. Crash reporting is disabled.
  634. </message>
  635. <message name="IDS_CRASH_UPLOAD_MESSAGE" desc="Link text for triggering crash uploading on chrome://crashes">
  636. - Start uploading crashes
  637. + Start saving crashes
  638. </message>
  639. <message name="IDS_CRASH_UPLOAD_NOW_LINK_TEXT" desc="Link text for manual uploads of a crash report">
  640. - Send now
  641. + Save now
  642. + </message>
  643. + <message name="IDS_CRASH_CLEAR_ALL_TEXT" desc="Link text for clear all crash files">
  644. + Clear all
  645. + </message>
  646. + <message name="IDS_CRASH_EXTRACT_NOW_TEXT" desc="Link text for manual generation of a crash report">
  647. + Generate report
  648. </message>
  649. </grit-part>
  650. 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
  651. --- a/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/CrashFileManager.java
  652. +++ b/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/CrashFileManager.java
  653. @@ -107,6 +107,8 @@ public class CrashFileManager {
  654. private static final Pattern TMP_PATTERN = Pattern.compile("\\.tmp\\z");
  655. + private static final String SAVED_MINIDUMP_ZIP_SUFFIX = ".zip";
  656. +
  657. // The maximum number of non-uploaded crashes that may be kept in the crash reports directory.
  658. // Chosen to attempt to balance between keeping a generous number of crashes, and not using up
  659. // too much filesystem storage space for obsolete crash reports.
  660. @@ -116,7 +118,7 @@ public class CrashFileManager {
  661. // The maximum age, in days, considered acceptable for a crash report. Reports older than this
  662. // age will be removed. The constant is chosen to be quite conservative, while still allowing
  663. // users to eventually reclaim filesystem storage space from obsolete crash reports.
  664. - private static final int MAX_CRASH_REPORT_AGE_IN_DAYS = 30;
  665. + private static final int MAX_CRASH_REPORT_AGE_IN_DAYS = 5;
  666. // The maximum number of non-uploaded crashes to copy to the crash reports directory. The
  667. // difference between this value and MAX_CRASH_REPORTS_TO_KEEP is that TO_KEEP is only checked
  668. @@ -586,6 +588,9 @@ public class CrashFileManager {
  669. && !f.getName().contains(UPLOAD_FORCED_MINIDUMP_SUFFIX)) {
  670. continue;
  671. }
  672. + // as above, zip files must also be excluded
  673. + if (f.getName().endsWith(SAVED_MINIDUMP_ZIP_SUFFIX))
  674. + continue;
  675. String filenameSansExtension = f.getName().split("\\.")[0];
  676. if (filenameSansExtension.endsWith(localId)) {
  677. 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
  678. --- a/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/MinidumpUploadCallable.java
  679. +++ b/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/MinidumpUploadCallable.java
  680. @@ -63,26 +63,8 @@ public class MinidumpUploadCallable implements Callable<Integer> {
  681. if (mPermManager.isUploadEnabledForTests()) {
  682. Log.i(TAG, "Minidump upload enabled for tests, skipping other checks.");
  683. } else if (!CrashFileManager.isForcedUpload(mFileToUpload)) {
  684. - if (!mPermManager.isUsageAndCrashReportingPermittedByUser()) {
  685. - Log.i(TAG, "Minidump upload is not permitted by user. Marking file as skipped for "
  686. - + "cleanup to prevent future uploads.");
  687. - CrashFileManager.markUploadSkipped(mFileToUpload);
  688. - return MinidumpUploadStatus.USER_DISABLED;
  689. - }
  690. -
  691. - if (!mPermManager.isClientInMetricsSample()) {
  692. - Log.i(TAG, "Minidump upload skipped due to sampling. Marking file as skipped for "
  693. - + "cleanup to prevent future uploads.");
  694. - CrashFileManager.markUploadSkipped(mFileToUpload);
  695. - return MinidumpUploadStatus.DISABLED_BY_SAMPLING;
  696. - }
  697. -
  698. - if (!mPermManager.isNetworkAvailableForCrashUploads()) {
  699. - Log.i(TAG, "Minidump cannot currently be uploaded due to network constraints.");
  700. - return MinidumpUploadStatus.FAILURE;
  701. - }
  702. + return MinidumpUploadStatus.USER_DISABLED;
  703. }
  704. -
  705. MinidumpUploader.Result result = mMinidumpUploader.upload(mFileToUpload);
  706. if (result.isSuccess()) {
  707. String uploadId = result.message();
  708. 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
  709. --- a/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/MinidumpUploader.java
  710. +++ b/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/MinidumpUploader.java
  711. @@ -120,31 +120,10 @@ public class MinidumpUploader {
  712. if (fileToUpload == null || !fileToUpload.exists()) {
  713. return Result.failure("Crash report does not exist");
  714. }
  715. - HttpURLConnection connection =
  716. - mHttpURLConnectionFactory.createHttpURLConnection(CRASH_URL_STRING);
  717. - if (connection == null) {
  718. - return Result.failure("Failed to create connection");
  719. - }
  720. - configureConnectionForHttpPost(connection, readBoundary(fileToUpload));
  721. -
  722. - try (InputStream minidumpInputStream = new FileInputStream(fileToUpload);
  723. - OutputStream requestBodyStream =
  724. - new GZIPOutputStream(connection.getOutputStream())) {
  725. - streamCopy(minidumpInputStream, requestBodyStream);
  726. - int responseCode = connection.getResponseCode();
  727. - if (isSuccessful(responseCode)) {
  728. - // The crash server returns the crash ID in the response body.
  729. - String responseContent = getResponseContentAsString(connection);
  730. - String uploadId = responseContent != null ? responseContent : "unknown";
  731. - return Result.success(uploadId);
  732. - } else {
  733. - // Return the remote error code and message.
  734. - return Result.uploadError(responseCode, connection.getResponseMessage());
  735. - }
  736. - } finally {
  737. - connection.disconnect();
  738. - }
  739. - } catch (IOException | RuntimeException e) {
  740. + // for us, it's always good
  741. + // returns the file name without path, which will be registered as local_id
  742. + return Result.success(fileToUpload.getName());
  743. + } catch (RuntimeException e) {
  744. return Result.failure(e.toString());
  745. }
  746. }
  747. diff --git a/components/upload_list/text_log_upload_list.cc b/components/upload_list/text_log_upload_list.cc
  748. --- a/components/upload_list/text_log_upload_list.cc
  749. +++ b/components/upload_list/text_log_upload_list.cc
  750. @@ -108,6 +108,7 @@ std::unique_ptr<TextLogUploadList::UploadInfo> TryParseCsvLogEntry(
  751. }
  752. auto info = std::make_unique<TextLogUploadList::UploadInfo>(components[1],
  753. upload_time);
  754. + info->file_path = components[1];
  755. // Add local ID if present.
  756. if (components.size() > 2)
  757. diff --git a/components/upload_list/upload_list.cc b/components/upload_list/upload_list.cc
  758. --- a/components/upload_list/upload_list.cc
  759. +++ b/components/upload_list/upload_list.cc
  760. @@ -55,7 +55,8 @@ UploadList::UploadInfo::UploadInfo(const UploadInfo& upload_info)
  761. capture_time(upload_info.capture_time),
  762. state(upload_info.state),
  763. source(upload_info.source),
  764. - file_size(upload_info.file_size) {}
  765. + file_size(upload_info.file_size),
  766. + file_path(upload_info.file_path) {}
  767. UploadList::UploadInfo::~UploadInfo() = default;
  768. @@ -108,6 +109,11 @@ void UploadList::RequestSingleUpload(const std::string& local_id) {
  769. NOTREACHED();
  770. }
  771. +void UploadList::RequestNewExtraction() {
  772. + // only available for Android. overrided in crash_upload_list_android.cc
  773. + NOTREACHED();
  774. +}
  775. +
  776. void UploadList::OnLoadComplete(const std::vector<UploadInfo>& uploads) {
  777. uploads_ = uploads;
  778. if (!load_callback_.is_null())
  779. @@ -118,3 +124,12 @@ void UploadList::OnClearComplete() {
  780. if (!clear_callback_.is_null())
  781. std::move(clear_callback_).Run();
  782. }
  783. +
  784. +std::string UploadList::GetFilePathByLocalId(const std::string& local_id) {
  785. + for (auto info : uploads_) {
  786. + if (info.local_id == local_id) {
  787. + return info.file_path;
  788. + }
  789. + }
  790. + return std::string();
  791. +}
  792. diff --git a/components/upload_list/upload_list.h b/components/upload_list/upload_list.h
  793. --- a/components/upload_list/upload_list.h
  794. +++ b/components/upload_list/upload_list.h
  795. @@ -66,6 +66,9 @@ class UploadList : public base::RefCountedThreadSafe<UploadList> {
  796. // Formatted file size for locally stored data.
  797. std::u16string file_size;
  798. +
  799. + // path of crash file
  800. + std::string file_path;
  801. };
  802. UploadList();
  803. @@ -92,6 +95,12 @@ class UploadList : public base::RefCountedThreadSafe<UploadList> {
  804. // Must be called only after a Load() callback has been received.
  805. void GetUploads(size_t max_count, std::vector<UploadInfo>* uploads);
  806. + // Get full path of crash file for local_id
  807. + std::string GetFilePathByLocalId(const std::string& local_id);
  808. +
  809. + // Request new log extraction
  810. + virtual void RequestNewExtraction();
  811. +
  812. protected:
  813. virtual ~UploadList();
  814. --
  815. 2.20.1