| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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.android_webview.crash; | 5 package org.chromium.android_webview.crash; |
| 6 | 6 |
| 7 import android.annotation.TargetApi; | 7 import android.annotation.TargetApi; |
| 8 import android.app.Service; | 8 import android.app.Service; |
| 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.Binder; | 13 import android.os.Binder; |
| 13 import android.os.Build; | 14 import android.os.Build; |
| 14 import android.os.IBinder; | 15 import android.os.IBinder; |
| 15 import android.os.ParcelFileDescriptor; | 16 import android.os.ParcelFileDescriptor; |
| 16 | 17 |
| 17 import org.chromium.base.ContextUtils; | |
| 18 import org.chromium.base.Log; | 18 import org.chromium.base.Log; |
| 19 import org.chromium.base.VisibleForTesting; | 19 import org.chromium.base.VisibleForTesting; |
| 20 import org.chromium.components.background_task_scheduler.TaskIds; | 20 import org.chromium.components.background_task_scheduler.TaskIds; |
| 21 import org.chromium.components.minidump_uploader.CrashFileManager; | 21 import org.chromium.components.minidump_uploader.CrashFileManager; |
| 22 import org.chromium.components.minidump_uploader.MinidumpUploadJobService; | 22 import org.chromium.components.minidump_uploader.MinidumpUploadJobService; |
| 23 | 23 |
| 24 import java.io.File; | 24 import java.io.File; |
| 25 import java.io.IOException; | 25 import java.io.IOException; |
| 26 | 26 |
| 27 /** | 27 /** |
| (...skipping 11 matching lines...) Expand all Loading... |
| 39 | 39 |
| 40 @Override | 40 @Override |
| 41 public void onCreate() { | 41 public void onCreate() { |
| 42 super.onCreate(); | 42 super.onCreate(); |
| 43 } | 43 } |
| 44 | 44 |
| 45 private final ICrashReceiverService.Stub mBinder = new ICrashReceiverService
.Stub() { | 45 private final ICrashReceiverService.Stub mBinder = new ICrashReceiverService
.Stub() { |
| 46 @Override | 46 @Override |
| 47 public void transmitCrashes(ParcelFileDescriptor[] fileDescriptors) { | 47 public void transmitCrashes(ParcelFileDescriptor[] fileDescriptors) { |
| 48 int uid = Binder.getCallingUid(); | 48 int uid = Binder.getCallingUid(); |
| 49 performMinidumpCopyingSerially(uid, fileDescriptors, true /* schedul
eUploads */); | 49 performMinidumpCopyingSerially( |
| 50 CrashReceiverService.this, uid, fileDescriptors, true /* sch
eduleUploads */); |
| 50 } | 51 } |
| 51 }; | 52 }; |
| 52 | 53 |
| 53 /** | 54 /** |
| 54 * Copies minidumps in a synchronized way, waiting for any already started c
opying operations to | 55 * Copies minidumps in a synchronized way, waiting for any already started c
opying operations to |
| 55 * finish before copying the current dumps. | 56 * finish before copying the current dumps. |
| 56 * @param scheduleUploads whether to ask JobScheduler to schedule an upload-
job (avoid this | 57 * @param scheduleUploads whether to ask JobScheduler to schedule an upload-
job (avoid this |
| 57 * during testing). | 58 * during testing). |
| 58 */ | 59 */ |
| 59 @VisibleForTesting | 60 @VisibleForTesting |
| 60 public void performMinidumpCopyingSerially( | 61 public void performMinidumpCopyingSerially(Context context, int uid, |
| 61 int uid, ParcelFileDescriptor[] fileDescriptors, boolean scheduleUpl
oads) { | 62 ParcelFileDescriptor[] fileDescriptors, boolean scheduleUploads) { |
| 62 if (!waitUntilWeCanCopy()) { | 63 if (!waitUntilWeCanCopy()) { |
| 63 Log.e(TAG, "something went wrong when waiting to copy minidumps, bai
ling!"); | 64 Log.e(TAG, "something went wrong when waiting to copy minidumps, bai
ling!"); |
| 64 return; | 65 return; |
| 65 } | 66 } |
| 66 | 67 |
| 67 try { | 68 try { |
| 68 boolean copySucceeded = copyMinidumps(uid, fileDescriptors); | 69 boolean copySucceeded = copyMinidumps(context, uid, fileDescriptors)
; |
| 69 if (copySucceeded && scheduleUploads) { | 70 if (copySucceeded && scheduleUploads) { |
| 70 // Only schedule a new job if there actually are any files to up
load. | 71 // Only schedule a new job if there actually are any files to up
load. |
| 71 scheduleNewJob(); | 72 scheduleNewJob(); |
| 72 } | 73 } |
| 73 } finally { | 74 } finally { |
| 74 synchronized (mCopyingLock) { | 75 synchronized (mCopyingLock) { |
| 75 mIsCopying = false; | 76 mIsCopying = false; |
| 76 mCopyingLock.notifyAll(); | 77 mCopyingLock.notifyAll(); |
| 77 } | 78 } |
| 78 } | 79 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 93 } | 94 } |
| 94 } | 95 } |
| 95 mIsCopying = true; | 96 mIsCopying = true; |
| 96 return true; | 97 return true; |
| 97 } | 98 } |
| 98 } | 99 } |
| 99 | 100 |
| 100 private void scheduleNewJob() { | 101 private void scheduleNewJob() { |
| 101 JobInfo.Builder builder = new JobInfo.Builder(TaskIds.WEBVIEW_MINIDUMP_U
PLOADING_JOB_ID, | 102 JobInfo.Builder builder = new JobInfo.Builder(TaskIds.WEBVIEW_MINIDUMP_U
PLOADING_JOB_ID, |
| 102 new ComponentName(this, AwMinidumpUploadJobService.class)); | 103 new ComponentName(this, AwMinidumpUploadJobService.class)); |
| 103 MinidumpUploadJobService.scheduleUpload(builder); | 104 MinidumpUploadJobService.scheduleUpload(this, builder); |
| 104 } | 105 } |
| 105 | 106 |
| 106 /** | 107 /** |
| 107 * Copy minidumps from the {@param fileDescriptors} to the directory where W
ebView stores its | 108 * Copy minidumps from the {@param fileDescriptors} to the directory where W
ebView stores its |
| 108 * minidump files. {@param context} is used to look up the directory in whic
h the files will be | 109 * minidump files. {@param context} is used to look up the directory in whic
h the files will be |
| 109 * saved. | 110 * saved. |
| 110 * @return whether any minidump was copied. | 111 * @return whether any minidump was copied. |
| 111 */ | 112 */ |
| 112 @VisibleForTesting | 113 @VisibleForTesting |
| 113 public static boolean copyMinidumps(int uid, ParcelFileDescriptor[] fileDesc
riptors) { | 114 public static boolean copyMinidumps( |
| 114 CrashFileManager crashFileManager = new CrashFileManager(getOrCreateWebV
iewCrashDir()); | 115 Context context, int uid, ParcelFileDescriptor[] fileDescriptors) { |
| 116 CrashFileManager crashFileManager = new CrashFileManager(createWebViewCr
ashDir(context)); |
| 115 boolean copiedAnything = false; | 117 boolean copiedAnything = false; |
| 116 if (fileDescriptors != null) { | 118 if (fileDescriptors != null) { |
| 117 for (ParcelFileDescriptor fd : fileDescriptors) { | 119 for (ParcelFileDescriptor fd : fileDescriptors) { |
| 118 if (fd == null) continue; | 120 if (fd == null) continue; |
| 119 try { | 121 try { |
| 120 File copiedFile = crashFileManager.copyMinidumpFromFD( | 122 File copiedFile = crashFileManager.copyMinidumpFromFD(fd.get
FileDescriptor(), |
| 121 fd.getFileDescriptor(), getWebViewTmpCrashDir(), uid
); | 123 getWebViewTmpCrashDir(context), uid); |
| 122 if (copiedFile == null) { | 124 if (copiedFile == null) { |
| 123 Log.w(TAG, "failed to copy minidump from " + fd.toString
()); | 125 Log.w(TAG, "failed to copy minidump from " + fd.toString
()); |
| 124 // TODO(gsennton): add UMA metric to ensure we aren't lo
sing too many | 126 // TODO(gsennton): add UMA metric to ensure we aren't lo
sing too many |
| 125 // minidumps here. | 127 // minidumps here. |
| 126 } else { | 128 } else { |
| 127 copiedAnything = true; | 129 copiedAnything = true; |
| 128 } | 130 } |
| 129 } catch (IOException e) { | 131 } catch (IOException e) { |
| 130 Log.w(TAG, "failed to copy minidump from " + fd.toString() +
": " | 132 Log.w(TAG, "failed to copy minidump from " + fd.toString() +
": " |
| 131 + e.getMessage()); | 133 + e.getMessage()); |
| 132 } finally { | 134 } finally { |
| 133 deleteFilesInWebViewTmpDirIfExists(); | 135 deleteFilesInWebViewTmpDirIfExists(context); |
| 134 } | 136 } |
| 135 } | 137 } |
| 136 } | 138 } |
| 137 return copiedAnything; | 139 return copiedAnything; |
| 138 } | 140 } |
| 139 | 141 |
| 140 /** | 142 /** |
| 141 * Delete all files in the directory where temporary files from this Service
are stored. | 143 * Delete all files in the directory where temporary files from this Service
are stored. |
| 142 */ | 144 */ |
| 143 @VisibleForTesting | 145 @VisibleForTesting |
| 144 public static void deleteFilesInWebViewTmpDirIfExists() { | 146 public static void deleteFilesInWebViewTmpDirIfExists(Context context) { |
| 145 deleteFilesInDirIfExists(getWebViewTmpCrashDir()); | 147 deleteFilesInDirIfExists(getWebViewTmpCrashDir(context)); |
| 146 } | 148 } |
| 147 | 149 |
| 148 private static void deleteFilesInDirIfExists(File directory) { | 150 private static void deleteFilesInDirIfExists(File directory) { |
| 149 if (directory.isDirectory()) { | 151 if (directory.isDirectory()) { |
| 150 File[] files = directory.listFiles(); | 152 File[] files = directory.listFiles(); |
| 151 if (files != null) { | 153 if (files != null) { |
| 152 for (File file : files) { | 154 for (File file : files) { |
| 153 if (!file.delete()) { | 155 if (!file.delete()) { |
| 154 Log.w(TAG, "Couldn't delete file " + file.getAbsolutePat
h()); | 156 Log.w(TAG, "Couldn't delete file " + file.getAbsolutePat
h()); |
| 155 } | 157 } |
| 156 } | 158 } |
| 157 } | 159 } |
| 158 } | 160 } |
| 159 } | 161 } |
| 160 | 162 |
| 161 /** | 163 /** |
| 162 * Create the directory in which WebView will store its minidumps. | 164 * Create the directory in which WebView will store its minidumps. |
| 163 * WebView needs a crash directory different from Chrome's to ensure Chrome'
s and WebView's | 165 * WebView needs a crash directory different from Chrome's to ensure Chrome'
s and WebView's |
| 164 * minidump handling won't clash in cases where both Chrome and WebView are
provided by the | 166 * minidump handling won't clash in cases where both Chrome and WebView are
provided by the |
| 165 * same app (Monochrome). | 167 * same app (Monochrome). |
| 168 * @param context Android Context used to find a cache-directory where minid
umps can be stored. |
| 166 * @return a reference to the created directory, or null if the creation fai
led. | 169 * @return a reference to the created directory, or null if the creation fai
led. |
| 167 */ | 170 */ |
| 168 @VisibleForTesting | 171 @VisibleForTesting |
| 169 public static File getOrCreateWebViewCrashDir() { | 172 public static File createWebViewCrashDir(Context context) { |
| 170 File dir = getWebViewCrashDir(); | 173 File dir = getWebViewCrashDir(context); |
| 171 // Call mkdir before isDirectory to ensure that if another thread create
d the directory | 174 // Call mkdir before isDirectory to ensure that if another thread create
d the directory |
| 172 // just before the call to mkdir, the current thread fails mkdir, but pa
sses isDirectory. | 175 // just before the call to mkdir, the current thread fails mkdir, but pa
sses isDirectory. |
| 173 if (dir.mkdir() || dir.isDirectory()) { | 176 if (dir.mkdir() || dir.isDirectory()) { |
| 174 return dir; | 177 return dir; |
| 175 } | 178 } |
| 176 return null; | 179 return null; |
| 177 } | 180 } |
| 178 | 181 |
| 179 /** | 182 /** |
| 180 * Fetch the crash directory where WebView stores its minidumps. | 183 * Fetch the crash directory where WebView stores its minidumps. |
| 184 * @param context Android Context used to find a cache-directory where minid
umps can be stored. |
| 181 * @return a File pointing to the crash directory. | 185 * @return a File pointing to the crash directory. |
| 182 */ | 186 */ |
| 183 @VisibleForTesting | 187 @VisibleForTesting |
| 184 public static File getWebViewCrashDir() { | 188 public static File getWebViewCrashDir(Context context) { |
| 185 return new File(ContextUtils.getApplicationContext().getCacheDir(), WEBV
IEW_CRASH_DIR); | 189 return new File(context.getCacheDir(), WEBVIEW_CRASH_DIR); |
| 186 } | 190 } |
| 187 | 191 |
| 188 /** | 192 /** |
| 189 * Directory where we store files temporarily when copying from an app proce
ss. | 193 * Directory where we store files temporarily when copying from an app proce
ss. |
| 194 * @param context Android Context used to find a cache-directory where minid
umps can be stored. |
| 190 */ | 195 */ |
| 191 @VisibleForTesting | 196 @VisibleForTesting |
| 192 public static File getWebViewTmpCrashDir() { | 197 public static File getWebViewTmpCrashDir(Context context) { |
| 193 return new File(ContextUtils.getApplicationContext().getCacheDir(), WEBV
IEW_TMP_CRASH_DIR); | 198 return new File(context.getCacheDir(), WEBVIEW_TMP_CRASH_DIR); |
| 194 } | 199 } |
| 195 | 200 |
| 196 @Override | 201 @Override |
| 197 public IBinder onBind(Intent intent) { | 202 public IBinder onBind(Intent intent) { |
| 198 return mBinder; | 203 return mBinder; |
| 199 } | 204 } |
| 200 } | 205 } |
| OLD | NEW |