| 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 | 
|---|