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