| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.chrome.browser.crash; | 5 package org.chromium.chrome.browser.crash; |
| 6 | 6 |
| 7 import android.annotation.SuppressLint; | 7 import android.annotation.SuppressLint; |
| 8 import android.app.IntentService; | 8 import android.app.IntentService; |
| 9 import android.app.job.JobInfo; | 9 import android.app.job.JobInfo; |
| 10 import android.content.ComponentName; | 10 import android.content.ComponentName; |
| 11 import android.content.Context; |
| 11 import android.content.Intent; | 12 import android.content.Intent; |
| 12 import android.os.Build; | 13 import android.os.Build; |
| 13 import android.os.PersistableBundle; | 14 import android.os.PersistableBundle; |
| 14 import android.support.annotation.StringDef; | 15 import android.support.annotation.StringDef; |
| 15 | 16 |
| 16 import org.chromium.base.ContextUtils; | |
| 17 import org.chromium.base.Log; | 17 import org.chromium.base.Log; |
| 18 import org.chromium.base.StreamUtil; | 18 import org.chromium.base.StreamUtil; |
| 19 import org.chromium.base.VisibleForTesting; | 19 import org.chromium.base.VisibleForTesting; |
| 20 import org.chromium.base.annotations.CalledByNative; | 20 import org.chromium.base.annotations.CalledByNative; |
| 21 import org.chromium.base.metrics.RecordHistogram; | 21 import org.chromium.base.metrics.RecordHistogram; |
| 22 import org.chromium.chrome.browser.preferences.ChromePreferenceManager; | 22 import org.chromium.chrome.browser.preferences.ChromePreferenceManager; |
| 23 import org.chromium.chrome.browser.preferences.privacy.PrivacyPreferencesManager
; | 23 import org.chromium.chrome.browser.preferences.privacy.PrivacyPreferencesManager
; |
| 24 import org.chromium.components.background_task_scheduler.TaskIds; | 24 import org.chromium.components.background_task_scheduler.TaskIds; |
| 25 import org.chromium.components.minidump_uploader.CrashFileManager; | 25 import org.chromium.components.minidump_uploader.CrashFileManager; |
| 26 import org.chromium.components.minidump_uploader.MinidumpUploadCallable; | 26 import org.chromium.components.minidump_uploader.MinidumpUploadCallable; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 80 */ | 80 */ |
| 81 public static boolean shouldUseJobSchedulerForUploads() { | 81 public static boolean shouldUseJobSchedulerForUploads() { |
| 82 // The JobScheduler API is only usable as of Android M. | 82 // The JobScheduler API is only usable as of Android M. |
| 83 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; | 83 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; |
| 84 } | 84 } |
| 85 | 85 |
| 86 /** | 86 /** |
| 87 * Schedules uploading of all pending minidumps, using the JobScheduler API. | 87 * Schedules uploading of all pending minidumps, using the JobScheduler API. |
| 88 */ | 88 */ |
| 89 @SuppressLint("NewApi") | 89 @SuppressLint("NewApi") |
| 90 public static void scheduleUploadJob() { | 90 public static void scheduleUploadJob(Context context) { |
| 91 assert shouldUseJobSchedulerForUploads(); | 91 assert shouldUseJobSchedulerForUploads(); |
| 92 | 92 |
| 93 CrashReportingPermissionManager permissionManager = PrivacyPreferencesMa
nager.getInstance(); | 93 CrashReportingPermissionManager permissionManager = PrivacyPreferencesMa
nager.getInstance(); |
| 94 PersistableBundle permissions = new PersistableBundle(); | 94 PersistableBundle permissions = new PersistableBundle(); |
| 95 permissions.putBoolean(ChromeMinidumpUploaderDelegate.IS_CLIENT_IN_METRI
CS_SAMPLE, | 95 permissions.putBoolean(ChromeMinidumpUploaderDelegate.IS_CLIENT_IN_METRI
CS_SAMPLE, |
| 96 permissionManager.isClientInMetricsSample()); | 96 permissionManager.isClientInMetricsSample()); |
| 97 permissions.putBoolean(ChromeMinidumpUploaderDelegate.IS_UPLOAD_ENABLED_
FOR_TESTS, | 97 permissions.putBoolean(ChromeMinidumpUploaderDelegate.IS_UPLOAD_ENABLED_
FOR_TESTS, |
| 98 permissionManager.isUploadEnabledForTests()); | 98 permissionManager.isUploadEnabledForTests()); |
| 99 | 99 |
| 100 JobInfo.Builder builder = | 100 JobInfo.Builder builder = |
| 101 new JobInfo | 101 new JobInfo |
| 102 .Builder(TaskIds.CHROME_MINIDUMP_UPLOADING_JOB_ID, | 102 .Builder(TaskIds.CHROME_MINIDUMP_UPLOADING_JOB_ID, |
| 103 new ComponentName(ContextUtils.getApplicationCon
text(), | 103 new ComponentName(context, ChromeMinidumpUploadJ
obService.class)) |
| 104 ChromeMinidumpUploadJobService.class)) | |
| 105 .setExtras(permissions); | 104 .setExtras(permissions); |
| 106 MinidumpUploadJobService.scheduleUpload(builder); | 105 MinidumpUploadJobService.scheduleUpload(context, builder); |
| 107 } | 106 } |
| 108 | 107 |
| 109 /** | 108 /** |
| 110 * Stores the successes and failures from uploading crash to UMA, | 109 * Stores the successes and failures from uploading crash to UMA, |
| 111 */ | 110 */ |
| 112 public static void storeBreakpadUploadStatsInUma(ChromePreferenceManager pre
f) { | 111 public static void storeBreakpadUploadStatsInUma(ChromePreferenceManager pre
f) { |
| 113 for (String type : TYPES) { | 112 for (String type : TYPES) { |
| 114 for (int success = pref.getCrashSuccessUploadCount(type); success >
0; success--) { | 113 for (int success = pref.getCrashSuccessUploadCount(type); success >
0; success--) { |
| 115 RecordHistogram.recordEnumeratedHistogram( | 114 RecordHistogram.recordEnumeratedHistogram( |
| 116 HISTOGRAM_NAME_PREFIX + type, SUCCESS, HISTOGRAM_MAX); | 115 HISTOGRAM_NAME_PREFIX + type, SUCCESS, HISTOGRAM_MAX); |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 285 return new MinidumpUploadCallable( | 284 return new MinidumpUploadCallable( |
| 286 minidumpFile, logfile, getCrashReportingPermissionManager()); | 285 minidumpFile, logfile, getCrashReportingPermissionManager()); |
| 287 } | 286 } |
| 288 | 287 |
| 289 /** | 288 /** |
| 290 * Attempts to upload the specified {@param minidumpFile}. | 289 * Attempts to upload the specified {@param minidumpFile}. |
| 291 * | 290 * |
| 292 * Note that this method is asynchronous. All that is guaranteed is that an
upload attempt will | 291 * Note that this method is asynchronous. All that is guaranteed is that an
upload attempt will |
| 293 * be enqueued. | 292 * be enqueued. |
| 294 * | 293 * |
| 295 * @throws SecurityException if the caller doesn't have permission to start
the upload | 294 * @param context The application context, in which to initiate the crash re
port upload. |
| 295 * @throws A security excpetion if the caller doesn't have permission to sta
rt the upload |
| 296 * service. This can only happen on KitKat and below, due to a frame
work bug. | 296 * service. This can only happen on KitKat and below, due to a frame
work bug. |
| 297 */ | 297 */ |
| 298 public static void tryUploadCrashDump(File minidumpFile) throws SecurityExce
ption { | 298 public static void tryUploadCrashDump(Context context, File minidumpFile) |
| 299 throws SecurityException { |
| 299 assert !shouldUseJobSchedulerForUploads(); | 300 assert !shouldUseJobSchedulerForUploads(); |
| 300 CrashFileManager fileManager = | 301 CrashFileManager fileManager = new CrashFileManager(context.getCacheDir(
)); |
| 301 new CrashFileManager(ContextUtils.getApplicationContext().getCac
heDir()); | 302 Intent intent = new Intent(context, MinidumpUploadService.class); |
| 302 Intent intent = | |
| 303 new Intent(ContextUtils.getApplicationContext(), MinidumpUploadS
ervice.class); | |
| 304 intent.setAction(ACTION_UPLOAD); | 303 intent.setAction(ACTION_UPLOAD); |
| 305 intent.putExtra(FILE_TO_UPLOAD_KEY, minidumpFile.getAbsolutePath()); | 304 intent.putExtra(FILE_TO_UPLOAD_KEY, minidumpFile.getAbsolutePath()); |
| 306 intent.putExtra(UPLOAD_LOG_KEY, fileManager.getCrashUploadLogFile().getA
bsolutePath()); | 305 intent.putExtra(UPLOAD_LOG_KEY, fileManager.getCrashUploadLogFile().getA
bsolutePath()); |
| 307 ContextUtils.getApplicationContext().startService(intent); | 306 context.startService(intent); |
| 308 } | 307 } |
| 309 | 308 |
| 310 /** | 309 /** |
| 311 * Attempts to upload all minidump files using the given {@link android.cont
ent.Context}. | 310 * Attempts to upload all minidump files using the given {@link android.cont
ent.Context}. |
| 312 * | 311 * |
| 313 * Note that this method is asynchronous. All that is guaranteed is that | 312 * Note that this method is asynchronous. All that is guaranteed is that |
| 314 * upload attempts will be enqueued. | 313 * upload attempts will be enqueued. |
| 315 * | 314 * |
| 316 * This method is safe to call from the UI thread. | 315 * This method is safe to call from the UI thread. |
| 317 * | 316 * |
| 317 * @param context Context of the application. |
| 318 */ | 318 */ |
| 319 public static void tryUploadAllCrashDumps() { | 319 public static void tryUploadAllCrashDumps(Context context) { |
| 320 assert !shouldUseJobSchedulerForUploads(); | 320 assert !shouldUseJobSchedulerForUploads(); |
| 321 CrashFileManager fileManager = | 321 CrashFileManager fileManager = new CrashFileManager(context.getCacheDir(
)); |
| 322 new CrashFileManager(ContextUtils.getApplicationContext().getCac
heDir()); | |
| 323 File[] minidumps = fileManager.getAllMinidumpFiles(MAX_TRIES_ALLOWED); | 322 File[] minidumps = fileManager.getAllMinidumpFiles(MAX_TRIES_ALLOWED); |
| 324 Log.i(TAG, "Attempting to upload accumulated crash dumps."); | 323 Log.i(TAG, "Attempting to upload accumulated crash dumps."); |
| 325 for (File minidump : minidumps) { | 324 for (File minidump : minidumps) { |
| 326 tryUploadCrashDump(minidump); | 325 tryUploadCrashDump(context, minidump); |
| 327 } | 326 } |
| 328 } | 327 } |
| 329 | 328 |
| 330 /** | 329 /** |
| 331 * Attempts to upload the crash report with the given local ID. | 330 * Attempts to upload the crash report with the given local ID. |
| 332 * | 331 * |
| 333 * Note that this method is asynchronous. All that is guaranteed is that | 332 * Note that this method is asynchronous. All that is guaranteed is that |
| 334 * upload attempts will be enqueued. | 333 * upload attempts will be enqueued. |
| 335 * | 334 * |
| 336 * This method is safe to call from the UI thread. | 335 * This method is safe to call from the UI thread. |
| 337 * | 336 * |
| 337 * @param context the context to use for the intent. |
| 338 * @param localId The local ID of the crash report. | 338 * @param localId The local ID of the crash report. |
| 339 */ | 339 */ |
| 340 @CalledByNative | 340 @CalledByNative |
| 341 public static void tryUploadCrashDumpWithLocalId(String localId) { | 341 public static void tryUploadCrashDumpWithLocalId(Context context, String loc
alId) { |
| 342 if (localId == null || localId.isEmpty()) { | 342 if (localId == null || localId.isEmpty()) { |
| 343 Log.w(TAG, "Cannot force crash upload since local crash id is absent
."); | 343 Log.w(TAG, "Cannot force crash upload since local crash id is absent
."); |
| 344 return; | 344 return; |
| 345 } | 345 } |
| 346 | 346 |
| 347 CrashFileManager fileManager = | 347 CrashFileManager fileManager = new CrashFileManager(context.getCacheDir(
)); |
| 348 new CrashFileManager(ContextUtils.getApplicationContext().getCac
heDir()); | |
| 349 File minidumpFile = fileManager.getCrashFileWithLocalId(localId); | 348 File minidumpFile = fileManager.getCrashFileWithLocalId(localId); |
| 350 if (minidumpFile == null) { | 349 if (minidumpFile == null) { |
| 351 Log.w(TAG, "Could not find a crash dump with local ID " + localId); | 350 Log.w(TAG, "Could not find a crash dump with local ID " + localId); |
| 352 return; | 351 return; |
| 353 } | 352 } |
| 354 File renamedMinidumpFile = CrashFileManager.trySetForcedUpload(minidumpF
ile); | 353 File renamedMinidumpFile = CrashFileManager.trySetForcedUpload(minidumpF
ile); |
| 355 if (renamedMinidumpFile == null) { | 354 if (renamedMinidumpFile == null) { |
| 356 Log.w(TAG, "Could not rename the file " + minidumpFile.getName() + "
for re-upload"); | 355 Log.w(TAG, "Could not rename the file " + minidumpFile.getName() + "
for re-upload"); |
| 357 return; | 356 return; |
| 358 } | 357 } |
| 359 | 358 |
| 360 if (shouldUseJobSchedulerForUploads()) { | 359 if (shouldUseJobSchedulerForUploads()) { |
| 361 scheduleUploadJob(); | 360 scheduleUploadJob(context); |
| 362 } else { | 361 } else { |
| 363 tryUploadCrashDump(renamedMinidumpFile); | 362 tryUploadCrashDump(context, renamedMinidumpFile); |
| 364 } | 363 } |
| 365 } | 364 } |
| 366 } | 365 } |
| OLD | NEW |