From c7a6f5cbcfca07c4298b7c4dbc369171637aef74 Mon Sep 17 00:00:00 2001 From: vince-bourgmayer Date: Sat, 23 Nov 2019 16:23:05 +0100 Subject: [PATCH 01/20] add ServiceExceptionHandler --- .../e/drive/utils/AppConstants.java | 3 - .../drive/utils/ServiceExceptionHandler.java | 73 +++++++++++++++++++ 2 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java diff --git a/app/src/main/java/foundation/e/drive/utils/AppConstants.java b/app/src/main/java/foundation/e/drive/utils/AppConstants.java index 1694eedd..50d57cec 100644 --- a/app/src/main/java/foundation/e/drive/utils/AppConstants.java +++ b/app/src/main/java/foundation/e/drive/utils/AppConstants.java @@ -27,7 +27,4 @@ public abstract class AppConstants { public static final String[] MEDIA_SYNCABLE_CATEGORIES = new String[]{"Images", "Movies", "Music", "Ringtones", "Documents", "Podcasts"}; public static final String[] SETTINGS_SYNCABLE_CATEGORIES = new String[] {"Rom settings"}; - - - } diff --git a/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java new file mode 100644 index 00000000..1b8f68b4 --- /dev/null +++ b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java @@ -0,0 +1,73 @@ +/* + * Copyright © Vincent Bourgmayer (/e/ foundation). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v3.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/gpl.html + */ +package foundation.e.drive.utils; +import android.os.Environment; +import android.util.Log; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.Thread.UncaughtExceptionHandler; + +/** + * @author Vincent Bourgmayer + */ +public class ServiceExceptionHandler implements UncaughtExceptionHandler{ + @Override + public void uncaughtException(Thread t, Throwable e) { + e.printStackTrace(); + + if(isExternalStorageAvailable() && !isExternalStorageReadOnly()){ + //Get TimeStamp + Long timestamp = System.currentTimeMillis(); + + //Create a new file that user can sent to us + String fileName = "eDrive-crash-"+timestamp+".log"; + File downloadDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath()); + File logFile = new File(downloadDir, fileName); + try { + FileOutputStream fos = new FileOutputStream(logFile); + fos.write(getStackTraceAsString(e).getBytes()); + fos.close(); + } catch (IOException exception) { + exception.printStackTrace(); + } + } + } + + //source: https://www.journaldev.com/9400/android-external-storage-read-write-save-file + private static boolean isExternalStorageAvailable() { + String extStorageState = Environment.getExternalStorageState(); + if (Environment.MEDIA_MOUNTED.equals(extStorageState)) { + return true; + } + return false; + } + //source: https://www.journaldev.com/9400/android-external-storage-read-write-save-file + private static boolean isExternalStorageReadOnly() { + String extStorageState = Environment.getExternalStorageState(); + if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(extStorageState)) { + return true; + } + return false; + } + + /** + * Return the stackTrace of the exception as a String + * @param e the exception + * @return the Stacktrace as a string + */ + private String getStackTraceAsString(Throwable e){ + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + e.printStackTrace(pw); + return sw.toString(); + } +} -- GitLab From d82cad7b1a8ece8bb11a3b02b53e78990eaae8a8 Mon Sep 17 00:00:00 2001 From: vince-bourgmayer Date: Sat, 23 Nov 2019 16:28:40 +0100 Subject: [PATCH 02/20] use ServiceExceptionHandler in Observer, OMS & Initializer --- .../e/drive/services/InitializerService.java | 5 +++++ .../foundation/e/drive/services/ObserverService.java | 9 +++------ .../e/drive/services/OperationManagerService.java | 2 ++ .../e/drive/utils/ServiceExceptionHandler.java | 10 +++++++++- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/services/InitializerService.java b/app/src/main/java/foundation/e/drive/services/InitializerService.java index ee3f8b26..a53cebd2 100644 --- a/app/src/main/java/foundation/e/drive/services/InitializerService.java +++ b/app/src/main/java/foundation/e/drive/services/InitializerService.java @@ -34,6 +34,8 @@ import foundation.e.drive.receivers.ScreenOffReceiver; import foundation.e.drive.utils.AppConstants; import foundation.e.drive.utils.CommonUtils; import foundation.e.drive.utils.JobUtils; +import foundation.e.drive.utils.ServiceExceptionHandler; + import static com.owncloud.android.lib.resources.files.FileUtils.PATH_SEPARATOR; import static foundation.e.drive.utils.AppConstants.INITIALFOLDERS_NUMBER; import static foundation.e.drive.utils.AppConstants.MEDIA_SYNCABLE_CATEGORIES; @@ -63,6 +65,9 @@ public class InitializerService extends Service implements OnRemoteOperationList @Override public int onStartCommand( Intent intent, int flags, int startId ) { Log.i(TAG, "onStartCommand(...)"); + + Thread.setDefaultUncaughtExceptionHandler(new ServiceExceptionHandler(this)); + //Get account SharedPreferences prefs = this.getSharedPreferences( AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE ); diff --git a/app/src/main/java/foundation/e/drive/services/ObserverService.java b/app/src/main/java/foundation/e/drive/services/ObserverService.java index 0514e328..0a51eba7 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -51,6 +51,7 @@ import static com.owncloud.android.lib.resources.files.FileUtils.PATH_SEPARATOR; import static foundation.e.drive.utils.AppConstants.INITIALIZATION_HAS_BEEN_DONE; import foundation.e.drive.utils.DavClientProvider; import foundation.e.drive.utils.JobUtils; +import foundation.e.drive.utils.ServiceExceptionHandler; /** * @author Vincent Bourgmayer @@ -75,16 +76,12 @@ public class ObserverService extends Service implements OnRemoteOperationListene this.mSyncedFolders = null; } - @Override - public void onCreate() { - Log.i(TAG, "onCreate()"); - super.onCreate(); - } - @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "onStartCommand("+startId+")"); + Thread.setDefaultUncaughtExceptionHandler(new ServiceExceptionHandler(this)); + SharedPreferences prefs = this.getSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE); String accountName = prefs.getString(AccountManager.KEY_ACCOUNT_NAME, ""); String accountType = prefs.getString(AccountManager.KEY_ACCOUNT_TYPE, ""); diff --git a/app/src/main/java/foundation/e/drive/services/OperationManagerService.java b/app/src/main/java/foundation/e/drive/services/OperationManagerService.java index 4e59a83a..e25f0836 100644 --- a/app/src/main/java/foundation/e/drive/services/OperationManagerService.java +++ b/app/src/main/java/foundation/e/drive/services/OperationManagerService.java @@ -40,6 +40,7 @@ import foundation.e.drive.operations.UploadFileOperation; import foundation.e.drive.utils.AppConstants; import foundation.e.drive.utils.CommonUtils; import foundation.e.drive.utils.DavClientProvider; +import foundation.e.drive.utils.ServiceExceptionHandler; /** * @author Vincent Bourgmayer @@ -239,6 +240,7 @@ public class OperationManagerService extends Service implements OnRemoteOperatio @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "onStartCommand()"); + Thread.setDefaultUncaughtExceptionHandler(new ServiceExceptionHandler(this)); Bundle extras = intent.getExtras(); Log.d(TAG, "OperationManagerService recieved "+(extras == null ? "null extras": extras.size()+" operations to perform") ); diff --git a/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java index 1b8f68b4..7ad84ee0 100644 --- a/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java +++ b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java @@ -6,8 +6,8 @@ * http://www.gnu.org/licenses/gpl.html */ package foundation.e.drive.utils; +import android.app.Service; import android.os.Environment; -import android.util.Log; import java.io.File; import java.io.FileOutputStream; @@ -20,6 +20,14 @@ import java.lang.Thread.UncaughtExceptionHandler; * @author Vincent Bourgmayer */ public class ServiceExceptionHandler implements UncaughtExceptionHandler{ + private UncaughtExceptionHandler defaultUEH; + + Service service; + + public ServiceExceptionHandler(Service service) { + this.service = service; + } + @Override public void uncaughtException(Thread t, Throwable e) { e.printStackTrace(); -- GitLab From 58ddae83bf8f805038e861e085db46ced7f0572a Mon Sep 17 00:00:00 2001 From: vince-bourgmayer Date: Tue, 10 Dec 2019 16:44:50 +0100 Subject: [PATCH 03/20] correctly end UncaughtExceptionHandler --- .idea/codeStyles/Project.xml | 116 ++++++++++++++++++ .../drive/utils/ServiceExceptionHandler.java | 12 +- 2 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 .idea/codeStyles/Project.xml diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 00000000..681f41ae --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,116 @@ + + + + + + + +
+ + + + xmlns:android + + ^$ + + + +
+
+ + + + xmlns:.* + + ^$ + + + BY_NAME + +
+
+ + + + .*:id + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + .*:name + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + name + + ^$ + + + +
+
+ + + + style + + ^$ + + + +
+
+ + + + .* + + ^$ + + + BY_NAME + +
+
+ + + + .* + + http://schemas.android.com/apk/res/android + + + ANDROID_ATTRIBUTE_ORDER + +
+
+ + + + .* + + .* + + + BY_NAME + +
+
+
+
+
+
\ No newline at end of file diff --git a/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java index 7ad84ee0..a1c57909 100644 --- a/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java +++ b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java @@ -8,6 +8,7 @@ package foundation.e.drive.utils; import android.app.Service; import android.os.Environment; +import android.util.Log; import java.io.File; import java.io.FileOutputStream; @@ -26,11 +27,11 @@ public class ServiceExceptionHandler implements UncaughtExceptionHandler{ public ServiceExceptionHandler(Service service) { this.service = service; + defaultUEH = Thread.getDefaultUncaughtExceptionHandler(); } @Override public void uncaughtException(Thread t, Throwable e) { - e.printStackTrace(); if(isExternalStorageAvailable() && !isExternalStorageReadOnly()){ //Get TimeStamp @@ -48,6 +49,14 @@ public class ServiceExceptionHandler implements UncaughtExceptionHandler{ exception.printStackTrace(); } } + + //source: https://stackoverflow.com/questions/9050962/rethrow-uncaughtexceptionhandler-exception-after-logging-it/9050990#9050990 + if(defaultUEH != null){ + defaultUEH.uncaughtException(t, e); + }else{ + Log.d("ServiceExceptionHandler", "/e/ Drive has crashed and there is no ExceptionHandler"); + System.exit(1); //Kill /e/ Drive... + } } //source: https://www.journaldev.com/9400/android-external-storage-read-write-save-file @@ -58,6 +67,7 @@ public class ServiceExceptionHandler implements UncaughtExceptionHandler{ } return false; } + //source: https://www.journaldev.com/9400/android-external-storage-read-write-save-file private static boolean isExternalStorageReadOnly() { String extStorageState = Environment.getExternalStorageState(); -- GitLab From deac7849b06e72c45f7dd35bc9c23e19e824e604 Mon Sep 17 00:00:00 2001 From: vince-bourgmayer Date: Wed, 11 Dec 2019 15:42:51 +0100 Subject: [PATCH 04/20] fix generation of multiple file --- .../e/drive/services/InitializerService.java | 7 +++++-- .../e/drive/services/ObserverService.java | 11 ++++++---- .../services/OperationManagerService.java | 20 +++++-------------- 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/services/InitializerService.java b/app/src/main/java/foundation/e/drive/services/InitializerService.java index a53cebd2..1f9cde01 100644 --- a/app/src/main/java/foundation/e/drive/services/InitializerService.java +++ b/app/src/main/java/foundation/e/drive/services/InitializerService.java @@ -66,8 +66,11 @@ public class InitializerService extends Service implements OnRemoteOperationList public int onStartCommand( Intent intent, int flags, int startId ) { Log.i(TAG, "onStartCommand(...)"); - Thread.setDefaultUncaughtExceptionHandler(new ServiceExceptionHandler(this)); - + if(Thread.getDefaultUncaughtExceptionHandler().getClass().getSimpleName().equals(ServiceExceptionHandler.class.getSimpleName())){ + Log.d("ObserverService", "ServiceExceptionHandler already set!"); + }else{ + Thread.setDefaultUncaughtExceptionHandler(new ServiceExceptionHandler(this)); + } //Get account SharedPreferences prefs = this.getSharedPreferences( AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE ); diff --git a/app/src/main/java/foundation/e/drive/services/ObserverService.java b/app/src/main/java/foundation/e/drive/services/ObserverService.java index 0a51eba7..413dad2e 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -80,8 +80,11 @@ public class ObserverService extends Service implements OnRemoteOperationListene public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "onStartCommand("+startId+")"); - Thread.setDefaultUncaughtExceptionHandler(new ServiceExceptionHandler(this)); - + if(Thread.getDefaultUncaughtExceptionHandler().getClass().getSimpleName().equals(ServiceExceptionHandler.class.getSimpleName())){ + Log.d("ObserverService", "ServiceExceptionHandler already set!"); + }else{ + Thread.setDefaultUncaughtExceptionHandler(new ServiceExceptionHandler(this)); + } SharedPreferences prefs = this.getSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE); String accountName = prefs.getString(AccountManager.KEY_ACCOUNT_NAME, ""); String accountType = prefs.getString(AccountManager.KEY_ACCOUNT_TYPE, ""); @@ -142,7 +145,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene return super.onStartCommand( intent, flags, startId ); } - /* Common methods */ + //Common methods /** * Start to bind this service to OperationManagerService or start scan if binding is already set. * Method to factorise code that is called from different place @@ -198,7 +201,6 @@ public class ObserverService extends Service implements OnRemoteOperationListene } Log.d(TAG, logFolderList.toString()); - if (remote) { OwnCloudClient client = DavClientProvider.getInstance().getClientInstance(mAccount, getApplicationContext()); if (client != null) { @@ -246,6 +248,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene @Override public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result ) { Log.i( TAG, "onRemoteOperationFinish()" ); + if( operation instanceof ListFileRemoteOperation){ if( result.isSuccess() ){ List resultDatas = result.getData(); diff --git a/app/src/main/java/foundation/e/drive/services/OperationManagerService.java b/app/src/main/java/foundation/e/drive/services/OperationManagerService.java index e25f0836..c21ef3a5 100644 --- a/app/src/main/java/foundation/e/drive/services/OperationManagerService.java +++ b/app/src/main/java/foundation/e/drive/services/OperationManagerService.java @@ -13,13 +13,11 @@ import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Parcelable; -import android.preference.Preference; import android.support.annotation.Nullable; import android.util.Log; import com.owncloud.android.lib.common.OwnCloudClient; @@ -27,7 +25,6 @@ import com.owncloud.android.lib.common.operations.OnRemoteOperationListener; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; -import org.apache.commons.httpclient.util.DateUtil; import java.lang.ref.WeakReference; import java.util.Hashtable; @@ -61,16 +58,6 @@ public class OperationManagerService extends Service implements OnRemoteOperatio @Override public void onDestroy() { Log.i(TAG, "onDestroy()"); - - /*this.mOperationsQueue.clear(); - for(int i =-1, size = mThreadPool.length;++i < size;){ - try{ - if(mThreadPool[i] != null) - mThreadPool[i].interrupt();} - catch(Exception e){ - Log.e(TAG, e.toString()); - } - }*/ super.onDestroy(); } @@ -240,8 +227,11 @@ public class OperationManagerService extends Service implements OnRemoteOperatio @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "onStartCommand()"); - Thread.setDefaultUncaughtExceptionHandler(new ServiceExceptionHandler(this)); - + if(Thread.getDefaultUncaughtExceptionHandler().getClass().getSimpleName().equals(ServiceExceptionHandler.class.getSimpleName())){ + Log.d("ObserverService", "ServiceExceptionHandler already set!"); + }else{ + Thread.setDefaultUncaughtExceptionHandler(new ServiceExceptionHandler(this)); + } Bundle extras = intent.getExtras(); Log.d(TAG, "OperationManagerService recieved "+(extras == null ? "null extras": extras.size()+" operations to perform") ); -- GitLab From 50eda9894b5b49efd2a54bbbc37f32b597824e73 Mon Sep 17 00:00:00 2001 From: vince-bourgmayer Date: Thu, 12 Dec 2019 15:51:40 +0100 Subject: [PATCH 05/20] make file readable by user --- .../e/drive/utils/ServiceExceptionHandler.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java index a1c57909..ef4cf52d 100644 --- a/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java +++ b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java @@ -21,6 +21,7 @@ import java.lang.Thread.UncaughtExceptionHandler; * @author Vincent Bourgmayer */ public class ServiceExceptionHandler implements UncaughtExceptionHandler{ + private final static String TAG = ServiceExceptionHandler.class.getSimpleName(); private UncaughtExceptionHandler defaultUEH; Service service; @@ -39,12 +40,19 @@ public class ServiceExceptionHandler implements UncaughtExceptionHandler{ //Create a new file that user can sent to us String fileName = "eDrive-crash-"+timestamp+".log"; - File downloadDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath()); + + File downloadDir = service.getApplication().getExternalFilesDir("Logs"); + //File downloadDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath()); File logFile = new File(downloadDir, fileName); try { + FileOutputStream fos = new FileOutputStream(logFile); fos.write(getStackTraceAsString(e).getBytes()); fos.close(); + logFile.setReadable(true, false); + + //DID NOT WORKS: CommonUtils.doActionMediaScannerConnexionScanFile(service, logFile.getCanonicalPath()); + } catch (IOException exception) { exception.printStackTrace(); } -- GitLab From dbcfd22f38221aecc09fbd5c68cce33df2230457 Mon Sep 17 00:00:00 2001 From: vince-bourgmayer Date: Thu, 12 Dec 2019 17:35:26 +0100 Subject: [PATCH 06/20] add method to setUEH for thread --- .../foundation/e/drive/utils/CommonUtils.java | 20 ++++++++++++++ .../drive/utils/ServiceExceptionHandler.java | 26 +++++++++++++++---- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/utils/CommonUtils.java b/app/src/main/java/foundation/e/drive/utils/CommonUtils.java index 523e4556..9dc2630b 100644 --- a/app/src/main/java/foundation/e/drive/utils/CommonUtils.java +++ b/app/src/main/java/foundation/e/drive/utils/CommonUtils.java @@ -13,6 +13,7 @@ import android.accounts.Account; import android.accounts.AccountManager; import android.app.NotificationManager; import android.app.PendingIntent; +import android.app.Service; import android.content.ContentResolver; import android.content.Context; import android.media.MediaScannerConnection; @@ -40,6 +41,25 @@ import static foundation.e.drive.utils.AppConstants.SETTINGSYNC_PROVIDER_AUTHORI public abstract class CommonUtils { final private static String TAG = CommonUtils.class.getSimpleName(); + + /** + * Set ServiceUncaughtExceptionHandler to be the MainThread Exception Handler + * Or update the service which use it + * @param service current service + */ + public static void setServiceUnCaughtExceptionHandler(Service service){ + + Thread.UncaughtExceptionHandler defaultUEH = Thread.getDefaultUncaughtExceptionHandler(); + if(defaultUEH.getClass().getSimpleName().equals(ServiceExceptionHandler.class.getSimpleName())){ + Log.d("ObserverService", "ServiceExceptionHandler already set!"); + ((ServiceExceptionHandler) defaultUEH).setService(service); + }else{ + Thread.setDefaultUncaughtExceptionHandler(new ServiceExceptionHandler(service)); + } + } + + + /** * Unregister from screeOffReceiver component * @param context app context diff --git a/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java index ef4cf52d..96248dc6 100644 --- a/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java +++ b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java @@ -7,6 +7,8 @@ */ package foundation.e.drive.utils; import android.app.Service; +import android.content.Context; +import android.content.SharedPreferences; import android.os.Environment; import android.util.Log; @@ -17,14 +19,23 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.lang.Thread.UncaughtExceptionHandler; +import foundation.e.drive.services.OperationManagerService; + /** * @author Vincent Bourgmayer */ public class ServiceExceptionHandler implements UncaughtExceptionHandler{ private final static String TAG = ServiceExceptionHandler.class.getSimpleName(); private UncaughtExceptionHandler defaultUEH; + private Service service; - Service service; + /** + * Change the service that could trigger an UncaughtException + * @param service service instance + */ + public void setService(Service service){ + this.service = service; + } public ServiceExceptionHandler(Service service) { this.service = service; @@ -33,6 +44,14 @@ public class ServiceExceptionHandler implements UncaughtExceptionHandler{ @Override public void uncaughtException(Thread t, Throwable e) { + Log.d(TAG, "Service class: "+service.getClass().getSimpleName()); + //IF OMS is crashing, set settings that it runs to false; + if(service.getClass().getSimpleName().equals(OperationManagerService.class.getSimpleName())){ + service.getSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE) + .edit() + .putBoolean(AppConstants.KEY_OMS_IS_WORKING, false) + .apply(); + } if(isExternalStorageAvailable() && !isExternalStorageReadOnly()){ //Get TimeStamp @@ -42,22 +61,19 @@ public class ServiceExceptionHandler implements UncaughtExceptionHandler{ String fileName = "eDrive-crash-"+timestamp+".log"; File downloadDir = service.getApplication().getExternalFilesDir("Logs"); - //File downloadDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath()); File logFile = new File(downloadDir, fileName); try { FileOutputStream fos = new FileOutputStream(logFile); + fos.write(service.getClass().getSimpleName().getBytes()); fos.write(getStackTraceAsString(e).getBytes()); fos.close(); logFile.setReadable(true, false); - //DID NOT WORKS: CommonUtils.doActionMediaScannerConnexionScanFile(service, logFile.getCanonicalPath()); - } catch (IOException exception) { exception.printStackTrace(); } } - //source: https://stackoverflow.com/questions/9050962/rethrow-uncaughtexceptionhandler-exception-after-logging-it/9050990#9050990 if(defaultUEH != null){ defaultUEH.uncaughtException(t, e); -- GitLab From 1f10d3ff116c1e593a679e196c73e581c2a99703 Mon Sep 17 00:00:00 2001 From: vince-bourgmayer Date: Thu, 12 Dec 2019 17:36:09 +0100 Subject: [PATCH 07/20] use method from commonUtils to set the UEH --- .../e/drive/services/InitializerService.java | 6 +----- .../foundation/e/drive/services/ObserverService.java | 7 ++----- .../e/drive/services/OperationManagerService.java | 10 +++------- 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/services/InitializerService.java b/app/src/main/java/foundation/e/drive/services/InitializerService.java index 1f9cde01..29c6d0da 100644 --- a/app/src/main/java/foundation/e/drive/services/InitializerService.java +++ b/app/src/main/java/foundation/e/drive/services/InitializerService.java @@ -66,11 +66,7 @@ public class InitializerService extends Service implements OnRemoteOperationList public int onStartCommand( Intent intent, int flags, int startId ) { Log.i(TAG, "onStartCommand(...)"); - if(Thread.getDefaultUncaughtExceptionHandler().getClass().getSimpleName().equals(ServiceExceptionHandler.class.getSimpleName())){ - Log.d("ObserverService", "ServiceExceptionHandler already set!"); - }else{ - Thread.setDefaultUncaughtExceptionHandler(new ServiceExceptionHandler(this)); - } + CommonUtils.setServiceUnCaughtExceptionHandler(this); //Get account SharedPreferences prefs = this.getSharedPreferences( AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE ); diff --git a/app/src/main/java/foundation/e/drive/services/ObserverService.java b/app/src/main/java/foundation/e/drive/services/ObserverService.java index 413dad2e..d46364a6 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -80,11 +80,8 @@ public class ObserverService extends Service implements OnRemoteOperationListene public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "onStartCommand("+startId+")"); - if(Thread.getDefaultUncaughtExceptionHandler().getClass().getSimpleName().equals(ServiceExceptionHandler.class.getSimpleName())){ - Log.d("ObserverService", "ServiceExceptionHandler already set!"); - }else{ - Thread.setDefaultUncaughtExceptionHandler(new ServiceExceptionHandler(this)); - } + CommonUtils.setServiceUnCaughtExceptionHandler(this); + SharedPreferences prefs = this.getSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE); String accountName = prefs.getString(AccountManager.KEY_ACCOUNT_NAME, ""); String accountType = prefs.getString(AccountManager.KEY_ACCOUNT_TYPE, ""); diff --git a/app/src/main/java/foundation/e/drive/services/OperationManagerService.java b/app/src/main/java/foundation/e/drive/services/OperationManagerService.java index c21ef3a5..24bb14be 100644 --- a/app/src/main/java/foundation/e/drive/services/OperationManagerService.java +++ b/app/src/main/java/foundation/e/drive/services/OperationManagerService.java @@ -227,11 +227,9 @@ public class OperationManagerService extends Service implements OnRemoteOperatio @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "onStartCommand()"); - if(Thread.getDefaultUncaughtExceptionHandler().getClass().getSimpleName().equals(ServiceExceptionHandler.class.getSimpleName())){ - Log.d("ObserverService", "ServiceExceptionHandler already set!"); - }else{ - Thread.setDefaultUncaughtExceptionHandler(new ServiceExceptionHandler(this)); - } + + CommonUtils.setServiceUnCaughtExceptionHandler(this); + Bundle extras = intent.getExtras(); Log.d(TAG, "OperationManagerService recieved "+(extras == null ? "null extras": extras.size()+" operations to perform") ); @@ -284,11 +282,9 @@ public class OperationManagerService extends Service implements OnRemoteOperatio }else{ Log.w(TAG, "Intent's extras is null."); } - return super.onStartCommand(intent, flags, startId); } - @Nullable @Override public IBinder onBind(Intent intent) { -- GitLab From 3c5f995346a4cf35da4bb5839570567d526b60c2 Mon Sep 17 00:00:00 2001 From: vince-bourgmayer Date: Fri, 13 Dec 2019 10:42:18 +0100 Subject: [PATCH 08/20] replace title in Logcat by TAG field --- .../java/foundation/e/drive/utils/ServiceExceptionHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java index 96248dc6..98830444 100644 --- a/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java +++ b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java @@ -78,7 +78,7 @@ public class ServiceExceptionHandler implements UncaughtExceptionHandler{ if(defaultUEH != null){ defaultUEH.uncaughtException(t, e); }else{ - Log.d("ServiceExceptionHandler", "/e/ Drive has crashed and there is no ExceptionHandler"); + Log.d(TAG, "there is no ExceptionHandler"); System.exit(1); //Kill /e/ Drive... } } -- GitLab From 6359bc442953f215de8e5b7d327400bd59f73d75 Mon Sep 17 00:00:00 2001 From: vince-bourgmayer Date: Sat, 14 Dec 2019 15:10:08 +0100 Subject: [PATCH 09/20] add method to remove oldestCrashlogs. add CrashlogsFileFilter with unitTest class. --- .../fileFilters/CrashlogsFileFilter.java | 42 ++++++++++++++++ .../e/drive/services/ObserverService.java | 28 +++++++++++ .../drive/utils/ServiceExceptionHandler.java | 7 ++- .../CrashlogFileFilterTest.java | 48 +++++++++++++++++++ 4 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/foundation/e/drive/fileFilters/CrashlogsFileFilter.java create mode 100644 app/src/test/java/foundation/e/drive/Test/FileFilterTest/CrashlogFileFilterTest.java diff --git a/app/src/main/java/foundation/e/drive/fileFilters/CrashlogsFileFilter.java b/app/src/main/java/foundation/e/drive/fileFilters/CrashlogsFileFilter.java new file mode 100644 index 00000000..3c902cb7 --- /dev/null +++ b/app/src/main/java/foundation/e/drive/fileFilters/CrashlogsFileFilter.java @@ -0,0 +1,42 @@ +package foundation.e.drive.fileFilters; + +import java.io.File; +import java.io.FileFilter; + +import foundation.e.drive.utils.ServiceExceptionHandler; + +public class CrashlogsFileFilter implements FileFilter { + private final static long max_timestamp_delta = 864000000; //10 days in ms (240*3600*1000) + + @Override + public boolean accept(File pathname) { + String fileTimestamp = extractTimestamp(pathname.getName(), + ServiceExceptionHandler.LOG_FILE_NAME_PREFIX, + ServiceExceptionHandler.LOG_FILE_EXTENSION); + + long timestamp; + try { + timestamp = Long.parseLong(fileTimestamp); + }catch (NumberFormatException e){ + //Can't parse the extracted timestamp + //This file has not the expected name. It must be removed + return true; + } + + //if current Date - file date >= max deta allowed + return ((System.currentTimeMillis() - timestamp ) >= max_timestamp_delta); + } + + /** + * Extract the timestamp from the name of the file + * UnitTested! + * @param fileName Filename + * @param prefix prefix to ignore + * @param extension extension to ignore + * @return the timestamp extracted from the name + */ + private String extractTimestamp(String fileName, String prefix, String extension){ + return fileName.substring(prefix.length(), (fileName.length() - extension.length())); + } + +} diff --git a/app/src/main/java/foundation/e/drive/services/ObserverService.java b/app/src/main/java/foundation/e/drive/services/ObserverService.java index d46364a6..54a352f3 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -30,13 +30,17 @@ import com.owncloud.android.lib.resources.files.model.RemoteFile; import java.io.File; import java.io.FileFilter; import java.io.FileOutputStream; +import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.ListIterator; import java.util.Map; +import java.util.stream.Stream; import foundation.e.drive.database.DbHelper; +import foundation.e.drive.fileFilters.CrashlogsFileFilter; import foundation.e.drive.fileFilters.FileFilterFactory; import foundation.e.drive.fileFilters.OnlyFileFilter; import foundation.e.drive.models.SyncedFolder; @@ -151,12 +155,36 @@ public class ObserverService extends Service implements OnRemoteOperationListene Log.i(TAG, "begin()"); this.isWorking = true; clearCachedFile(); + deleteOldestCrashlogs(); startScan(true); } + /** + * This method remove all the crash-logs file + * in external dir that are 10 days or more old. + */ + private void deleteOldestCrashlogs(){ + Log.i(TAG, "deleteOldestCrashLogs()"); + File[] fileToRemove = getExternalFilesDir(ServiceExceptionHandler.CRASH_LOG_FOLDER) + .listFiles(new CrashlogsFileFilter()); + + int counter = 0; + for (File file : fileToRemove) { + try { + file.delete(); + ++counter; + }catch (SecurityException e){ + e.printStackTrace(); + } + } + Log.d(TAG, counter+" old crashlogs file.s deleted"); + } + + /** * Clear cached file unused: * remove each cached file which isn't in OperationManagerService.lockedSyncedFileState(); + * @TODO rewrite this method! */ private void clearCachedFile(){ Log.i(TAG, "clearCachedFile()"); diff --git a/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java index 98830444..0833f3e3 100644 --- a/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java +++ b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java @@ -26,6 +26,9 @@ import foundation.e.drive.services.OperationManagerService; */ public class ServiceExceptionHandler implements UncaughtExceptionHandler{ private final static String TAG = ServiceExceptionHandler.class.getSimpleName(); + public final static String CRASH_LOG_FOLDER = "crash-logs"; + public final static String LOG_FILE_NAME_PREFIX = "eDrive-crash-"; + public final static String LOG_FILE_EXTENSION = ".log"; private UncaughtExceptionHandler defaultUEH; private Service service; @@ -58,9 +61,9 @@ public class ServiceExceptionHandler implements UncaughtExceptionHandler{ Long timestamp = System.currentTimeMillis(); //Create a new file that user can sent to us - String fileName = "eDrive-crash-"+timestamp+".log"; + String fileName = LOG_FILE_NAME_PREFIX+timestamp+LOG_FILE_EXTENSION; - File downloadDir = service.getApplication().getExternalFilesDir("Logs"); + File downloadDir = service.getApplication().getExternalFilesDir(CRASH_LOG_FOLDER); File logFile = new File(downloadDir, fileName); try { diff --git a/app/src/test/java/foundation/e/drive/Test/FileFilterTest/CrashlogFileFilterTest.java b/app/src/test/java/foundation/e/drive/Test/FileFilterTest/CrashlogFileFilterTest.java new file mode 100644 index 00000000..d10b6435 --- /dev/null +++ b/app/src/test/java/foundation/e/drive/Test/FileFilterTest/CrashlogFileFilterTest.java @@ -0,0 +1,48 @@ +package foundation.e.drive.Test.FileFilterTest; + +import org.junit.Assert; +import org.junit.Test; + +public class CrashlogFileFilterTest { + + private String mockFileName(String target, String prefix, String extension){ + return prefix+target+extension; + } + + private String extractTimestamp(String fileName, String prefix, String extension){ + return fileName.substring(prefix.length(), (fileName.length() - extension.length())); + } + + @Test + public void extractTimeStampFromFileNameTest(){ + String prefix = "edrive-"; + String extension = ".log"; + String target = ""; + //Case 1 Empty Target + String base = mockFileName(target, prefix, extension); + Assert.assertEquals("Base length is incorrect", prefix.length()+extension.length(), base.length()); + + String fileTimestamp = extractTimestamp(base, prefix, extension); + Assert.assertEquals("result is not empty String", "", fileTimestamp); + + //Case 2: Prefix is empty + prefix = ""; + target = "1234"; + base = mockFileName(target, prefix, extension); + Assert.assertEquals("Base length is incorrect", prefix.length()+target.length()+extension.length(), base.length()); + + fileTimestamp = extractTimestamp(base, prefix, extension); + Assert.assertEquals("result is not empty String", target, fileTimestamp); + + //Case 3: extension is empty + + prefix = "edrive-"; + extension = ""; + + base = mockFileName(target, prefix, extension); + Assert.assertEquals("Base length is incorrect", prefix.length()+target.length(), base.length()); + + fileTimestamp = extractTimestamp(base, prefix, extension); + Assert.assertEquals("result is not empty String", target, fileTimestamp); + } +} -- GitLab From 2216c64de6865b734ecd85314a6f4f85d1daa337 Mon Sep 17 00:00:00 2001 From: vince-bourgmayer Date: Sat, 14 Dec 2019 15:29:20 +0100 Subject: [PATCH 10/20] remove useless import in ObserverService --- .../main/java/foundation/e/drive/services/ObserverService.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/services/ObserverService.java b/app/src/main/java/foundation/e/drive/services/ObserverService.java index 54a352f3..6cf06395 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -30,14 +30,11 @@ import com.owncloud.android.lib.resources.files.model.RemoteFile; import java.io.File; import java.io.FileFilter; import java.io.FileOutputStream; -import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.ListIterator; import java.util.Map; -import java.util.stream.Stream; import foundation.e.drive.database.DbHelper; import foundation.e.drive.fileFilters.CrashlogsFileFilter; -- GitLab From 4f395d9469f14919b3569a23bd855fb3988a31f8 Mon Sep 17 00:00:00 2001 From: vince-bourgmayer Date: Sat, 23 Nov 2019 16:23:05 +0100 Subject: [PATCH 11/20] add ServiceExceptionHandler --- .../e/drive/utils/AppConstants.java | 3 - .../drive/utils/ServiceExceptionHandler.java | 73 +++++++++++++++++++ 2 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java diff --git a/app/src/main/java/foundation/e/drive/utils/AppConstants.java b/app/src/main/java/foundation/e/drive/utils/AppConstants.java index 1694eedd..50d57cec 100644 --- a/app/src/main/java/foundation/e/drive/utils/AppConstants.java +++ b/app/src/main/java/foundation/e/drive/utils/AppConstants.java @@ -27,7 +27,4 @@ public abstract class AppConstants { public static final String[] MEDIA_SYNCABLE_CATEGORIES = new String[]{"Images", "Movies", "Music", "Ringtones", "Documents", "Podcasts"}; public static final String[] SETTINGS_SYNCABLE_CATEGORIES = new String[] {"Rom settings"}; - - - } diff --git a/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java new file mode 100644 index 00000000..1b8f68b4 --- /dev/null +++ b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java @@ -0,0 +1,73 @@ +/* + * Copyright © Vincent Bourgmayer (/e/ foundation). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v3.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/gpl.html + */ +package foundation.e.drive.utils; +import android.os.Environment; +import android.util.Log; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.Thread.UncaughtExceptionHandler; + +/** + * @author Vincent Bourgmayer + */ +public class ServiceExceptionHandler implements UncaughtExceptionHandler{ + @Override + public void uncaughtException(Thread t, Throwable e) { + e.printStackTrace(); + + if(isExternalStorageAvailable() && !isExternalStorageReadOnly()){ + //Get TimeStamp + Long timestamp = System.currentTimeMillis(); + + //Create a new file that user can sent to us + String fileName = "eDrive-crash-"+timestamp+".log"; + File downloadDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath()); + File logFile = new File(downloadDir, fileName); + try { + FileOutputStream fos = new FileOutputStream(logFile); + fos.write(getStackTraceAsString(e).getBytes()); + fos.close(); + } catch (IOException exception) { + exception.printStackTrace(); + } + } + } + + //source: https://www.journaldev.com/9400/android-external-storage-read-write-save-file + private static boolean isExternalStorageAvailable() { + String extStorageState = Environment.getExternalStorageState(); + if (Environment.MEDIA_MOUNTED.equals(extStorageState)) { + return true; + } + return false; + } + //source: https://www.journaldev.com/9400/android-external-storage-read-write-save-file + private static boolean isExternalStorageReadOnly() { + String extStorageState = Environment.getExternalStorageState(); + if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(extStorageState)) { + return true; + } + return false; + } + + /** + * Return the stackTrace of the exception as a String + * @param e the exception + * @return the Stacktrace as a string + */ + private String getStackTraceAsString(Throwable e){ + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + e.printStackTrace(pw); + return sw.toString(); + } +} -- GitLab From 14b66f686d2366e83ce8fd21f9625aba98f306a0 Mon Sep 17 00:00:00 2001 From: vince-bourgmayer Date: Sat, 23 Nov 2019 16:28:40 +0100 Subject: [PATCH 12/20] use ServiceExceptionHandler in Observer, OMS & Initializer --- .../e/drive/services/InitializerService.java | 5 +++++ .../foundation/e/drive/services/ObserverService.java | 9 +++------ .../e/drive/services/OperationManagerService.java | 2 ++ .../e/drive/utils/ServiceExceptionHandler.java | 10 +++++++++- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/services/InitializerService.java b/app/src/main/java/foundation/e/drive/services/InitializerService.java index ee3f8b26..a53cebd2 100644 --- a/app/src/main/java/foundation/e/drive/services/InitializerService.java +++ b/app/src/main/java/foundation/e/drive/services/InitializerService.java @@ -34,6 +34,8 @@ import foundation.e.drive.receivers.ScreenOffReceiver; import foundation.e.drive.utils.AppConstants; import foundation.e.drive.utils.CommonUtils; import foundation.e.drive.utils.JobUtils; +import foundation.e.drive.utils.ServiceExceptionHandler; + import static com.owncloud.android.lib.resources.files.FileUtils.PATH_SEPARATOR; import static foundation.e.drive.utils.AppConstants.INITIALFOLDERS_NUMBER; import static foundation.e.drive.utils.AppConstants.MEDIA_SYNCABLE_CATEGORIES; @@ -63,6 +65,9 @@ public class InitializerService extends Service implements OnRemoteOperationList @Override public int onStartCommand( Intent intent, int flags, int startId ) { Log.i(TAG, "onStartCommand(...)"); + + Thread.setDefaultUncaughtExceptionHandler(new ServiceExceptionHandler(this)); + //Get account SharedPreferences prefs = this.getSharedPreferences( AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE ); diff --git a/app/src/main/java/foundation/e/drive/services/ObserverService.java b/app/src/main/java/foundation/e/drive/services/ObserverService.java index 0514e328..0a51eba7 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -51,6 +51,7 @@ import static com.owncloud.android.lib.resources.files.FileUtils.PATH_SEPARATOR; import static foundation.e.drive.utils.AppConstants.INITIALIZATION_HAS_BEEN_DONE; import foundation.e.drive.utils.DavClientProvider; import foundation.e.drive.utils.JobUtils; +import foundation.e.drive.utils.ServiceExceptionHandler; /** * @author Vincent Bourgmayer @@ -75,16 +76,12 @@ public class ObserverService extends Service implements OnRemoteOperationListene this.mSyncedFolders = null; } - @Override - public void onCreate() { - Log.i(TAG, "onCreate()"); - super.onCreate(); - } - @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "onStartCommand("+startId+")"); + Thread.setDefaultUncaughtExceptionHandler(new ServiceExceptionHandler(this)); + SharedPreferences prefs = this.getSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE); String accountName = prefs.getString(AccountManager.KEY_ACCOUNT_NAME, ""); String accountType = prefs.getString(AccountManager.KEY_ACCOUNT_TYPE, ""); diff --git a/app/src/main/java/foundation/e/drive/services/OperationManagerService.java b/app/src/main/java/foundation/e/drive/services/OperationManagerService.java index 4e59a83a..e25f0836 100644 --- a/app/src/main/java/foundation/e/drive/services/OperationManagerService.java +++ b/app/src/main/java/foundation/e/drive/services/OperationManagerService.java @@ -40,6 +40,7 @@ import foundation.e.drive.operations.UploadFileOperation; import foundation.e.drive.utils.AppConstants; import foundation.e.drive.utils.CommonUtils; import foundation.e.drive.utils.DavClientProvider; +import foundation.e.drive.utils.ServiceExceptionHandler; /** * @author Vincent Bourgmayer @@ -239,6 +240,7 @@ public class OperationManagerService extends Service implements OnRemoteOperatio @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "onStartCommand()"); + Thread.setDefaultUncaughtExceptionHandler(new ServiceExceptionHandler(this)); Bundle extras = intent.getExtras(); Log.d(TAG, "OperationManagerService recieved "+(extras == null ? "null extras": extras.size()+" operations to perform") ); diff --git a/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java index 1b8f68b4..7ad84ee0 100644 --- a/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java +++ b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java @@ -6,8 +6,8 @@ * http://www.gnu.org/licenses/gpl.html */ package foundation.e.drive.utils; +import android.app.Service; import android.os.Environment; -import android.util.Log; import java.io.File; import java.io.FileOutputStream; @@ -20,6 +20,14 @@ import java.lang.Thread.UncaughtExceptionHandler; * @author Vincent Bourgmayer */ public class ServiceExceptionHandler implements UncaughtExceptionHandler{ + private UncaughtExceptionHandler defaultUEH; + + Service service; + + public ServiceExceptionHandler(Service service) { + this.service = service; + } + @Override public void uncaughtException(Thread t, Throwable e) { e.printStackTrace(); -- GitLab From 55960ca1c002385549fe2813d6a098b29a1f3e64 Mon Sep 17 00:00:00 2001 From: vince-bourgmayer Date: Tue, 10 Dec 2019 16:44:50 +0100 Subject: [PATCH 13/20] correctly end UncaughtExceptionHandler --- .idea/codeStyles/Project.xml | 116 ++++++++++++++++++ .../drive/utils/ServiceExceptionHandler.java | 12 +- 2 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 .idea/codeStyles/Project.xml diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 00000000..681f41ae --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,116 @@ + + + + + + + +
+ + + + xmlns:android + + ^$ + + + +
+
+ + + + xmlns:.* + + ^$ + + + BY_NAME + +
+
+ + + + .*:id + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + .*:name + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + name + + ^$ + + + +
+
+ + + + style + + ^$ + + + +
+
+ + + + .* + + ^$ + + + BY_NAME + +
+
+ + + + .* + + http://schemas.android.com/apk/res/android + + + ANDROID_ATTRIBUTE_ORDER + +
+
+ + + + .* + + .* + + + BY_NAME + +
+
+
+
+
+
\ No newline at end of file diff --git a/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java index 7ad84ee0..a1c57909 100644 --- a/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java +++ b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java @@ -8,6 +8,7 @@ package foundation.e.drive.utils; import android.app.Service; import android.os.Environment; +import android.util.Log; import java.io.File; import java.io.FileOutputStream; @@ -26,11 +27,11 @@ public class ServiceExceptionHandler implements UncaughtExceptionHandler{ public ServiceExceptionHandler(Service service) { this.service = service; + defaultUEH = Thread.getDefaultUncaughtExceptionHandler(); } @Override public void uncaughtException(Thread t, Throwable e) { - e.printStackTrace(); if(isExternalStorageAvailable() && !isExternalStorageReadOnly()){ //Get TimeStamp @@ -48,6 +49,14 @@ public class ServiceExceptionHandler implements UncaughtExceptionHandler{ exception.printStackTrace(); } } + + //source: https://stackoverflow.com/questions/9050962/rethrow-uncaughtexceptionhandler-exception-after-logging-it/9050990#9050990 + if(defaultUEH != null){ + defaultUEH.uncaughtException(t, e); + }else{ + Log.d("ServiceExceptionHandler", "/e/ Drive has crashed and there is no ExceptionHandler"); + System.exit(1); //Kill /e/ Drive... + } } //source: https://www.journaldev.com/9400/android-external-storage-read-write-save-file @@ -58,6 +67,7 @@ public class ServiceExceptionHandler implements UncaughtExceptionHandler{ } return false; } + //source: https://www.journaldev.com/9400/android-external-storage-read-write-save-file private static boolean isExternalStorageReadOnly() { String extStorageState = Environment.getExternalStorageState(); -- GitLab From ca9870edbedd4a79152d21ecc3912afc611c42bc Mon Sep 17 00:00:00 2001 From: vince-bourgmayer Date: Wed, 11 Dec 2019 15:42:51 +0100 Subject: [PATCH 14/20] fix generation of multiple file --- .../e/drive/services/InitializerService.java | 7 +++++-- .../e/drive/services/ObserverService.java | 11 ++++++---- .../services/OperationManagerService.java | 20 +++++-------------- 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/services/InitializerService.java b/app/src/main/java/foundation/e/drive/services/InitializerService.java index a53cebd2..1f9cde01 100644 --- a/app/src/main/java/foundation/e/drive/services/InitializerService.java +++ b/app/src/main/java/foundation/e/drive/services/InitializerService.java @@ -66,8 +66,11 @@ public class InitializerService extends Service implements OnRemoteOperationList public int onStartCommand( Intent intent, int flags, int startId ) { Log.i(TAG, "onStartCommand(...)"); - Thread.setDefaultUncaughtExceptionHandler(new ServiceExceptionHandler(this)); - + if(Thread.getDefaultUncaughtExceptionHandler().getClass().getSimpleName().equals(ServiceExceptionHandler.class.getSimpleName())){ + Log.d("ObserverService", "ServiceExceptionHandler already set!"); + }else{ + Thread.setDefaultUncaughtExceptionHandler(new ServiceExceptionHandler(this)); + } //Get account SharedPreferences prefs = this.getSharedPreferences( AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE ); diff --git a/app/src/main/java/foundation/e/drive/services/ObserverService.java b/app/src/main/java/foundation/e/drive/services/ObserverService.java index 0a51eba7..413dad2e 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -80,8 +80,11 @@ public class ObserverService extends Service implements OnRemoteOperationListene public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "onStartCommand("+startId+")"); - Thread.setDefaultUncaughtExceptionHandler(new ServiceExceptionHandler(this)); - + if(Thread.getDefaultUncaughtExceptionHandler().getClass().getSimpleName().equals(ServiceExceptionHandler.class.getSimpleName())){ + Log.d("ObserverService", "ServiceExceptionHandler already set!"); + }else{ + Thread.setDefaultUncaughtExceptionHandler(new ServiceExceptionHandler(this)); + } SharedPreferences prefs = this.getSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE); String accountName = prefs.getString(AccountManager.KEY_ACCOUNT_NAME, ""); String accountType = prefs.getString(AccountManager.KEY_ACCOUNT_TYPE, ""); @@ -142,7 +145,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene return super.onStartCommand( intent, flags, startId ); } - /* Common methods */ + //Common methods /** * Start to bind this service to OperationManagerService or start scan if binding is already set. * Method to factorise code that is called from different place @@ -198,7 +201,6 @@ public class ObserverService extends Service implements OnRemoteOperationListene } Log.d(TAG, logFolderList.toString()); - if (remote) { OwnCloudClient client = DavClientProvider.getInstance().getClientInstance(mAccount, getApplicationContext()); if (client != null) { @@ -246,6 +248,7 @@ public class ObserverService extends Service implements OnRemoteOperationListene @Override public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result ) { Log.i( TAG, "onRemoteOperationFinish()" ); + if( operation instanceof ListFileRemoteOperation){ if( result.isSuccess() ){ List resultDatas = result.getData(); diff --git a/app/src/main/java/foundation/e/drive/services/OperationManagerService.java b/app/src/main/java/foundation/e/drive/services/OperationManagerService.java index e25f0836..c21ef3a5 100644 --- a/app/src/main/java/foundation/e/drive/services/OperationManagerService.java +++ b/app/src/main/java/foundation/e/drive/services/OperationManagerService.java @@ -13,13 +13,11 @@ import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Parcelable; -import android.preference.Preference; import android.support.annotation.Nullable; import android.util.Log; import com.owncloud.android.lib.common.OwnCloudClient; @@ -27,7 +25,6 @@ import com.owncloud.android.lib.common.operations.OnRemoteOperationListener; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; -import org.apache.commons.httpclient.util.DateUtil; import java.lang.ref.WeakReference; import java.util.Hashtable; @@ -61,16 +58,6 @@ public class OperationManagerService extends Service implements OnRemoteOperatio @Override public void onDestroy() { Log.i(TAG, "onDestroy()"); - - /*this.mOperationsQueue.clear(); - for(int i =-1, size = mThreadPool.length;++i < size;){ - try{ - if(mThreadPool[i] != null) - mThreadPool[i].interrupt();} - catch(Exception e){ - Log.e(TAG, e.toString()); - } - }*/ super.onDestroy(); } @@ -240,8 +227,11 @@ public class OperationManagerService extends Service implements OnRemoteOperatio @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "onStartCommand()"); - Thread.setDefaultUncaughtExceptionHandler(new ServiceExceptionHandler(this)); - + if(Thread.getDefaultUncaughtExceptionHandler().getClass().getSimpleName().equals(ServiceExceptionHandler.class.getSimpleName())){ + Log.d("ObserverService", "ServiceExceptionHandler already set!"); + }else{ + Thread.setDefaultUncaughtExceptionHandler(new ServiceExceptionHandler(this)); + } Bundle extras = intent.getExtras(); Log.d(TAG, "OperationManagerService recieved "+(extras == null ? "null extras": extras.size()+" operations to perform") ); -- GitLab From d1e9faa3b0e1f7545ffccfe35a3f9e620be54712 Mon Sep 17 00:00:00 2001 From: vince-bourgmayer Date: Thu, 12 Dec 2019 15:51:40 +0100 Subject: [PATCH 15/20] make file readable by user --- .../e/drive/utils/ServiceExceptionHandler.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java index a1c57909..ef4cf52d 100644 --- a/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java +++ b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java @@ -21,6 +21,7 @@ import java.lang.Thread.UncaughtExceptionHandler; * @author Vincent Bourgmayer */ public class ServiceExceptionHandler implements UncaughtExceptionHandler{ + private final static String TAG = ServiceExceptionHandler.class.getSimpleName(); private UncaughtExceptionHandler defaultUEH; Service service; @@ -39,12 +40,19 @@ public class ServiceExceptionHandler implements UncaughtExceptionHandler{ //Create a new file that user can sent to us String fileName = "eDrive-crash-"+timestamp+".log"; - File downloadDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath()); + + File downloadDir = service.getApplication().getExternalFilesDir("Logs"); + //File downloadDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath()); File logFile = new File(downloadDir, fileName); try { + FileOutputStream fos = new FileOutputStream(logFile); fos.write(getStackTraceAsString(e).getBytes()); fos.close(); + logFile.setReadable(true, false); + + //DID NOT WORKS: CommonUtils.doActionMediaScannerConnexionScanFile(service, logFile.getCanonicalPath()); + } catch (IOException exception) { exception.printStackTrace(); } -- GitLab From 6af28da31c583675d6ea146b7fb3e0a06c63758c Mon Sep 17 00:00:00 2001 From: vince-bourgmayer Date: Thu, 12 Dec 2019 17:35:26 +0100 Subject: [PATCH 16/20] add method to setUEH for thread --- .../foundation/e/drive/utils/CommonUtils.java | 20 ++++++++++++++ .../drive/utils/ServiceExceptionHandler.java | 26 +++++++++++++++---- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/utils/CommonUtils.java b/app/src/main/java/foundation/e/drive/utils/CommonUtils.java index 523e4556..9dc2630b 100644 --- a/app/src/main/java/foundation/e/drive/utils/CommonUtils.java +++ b/app/src/main/java/foundation/e/drive/utils/CommonUtils.java @@ -13,6 +13,7 @@ import android.accounts.Account; import android.accounts.AccountManager; import android.app.NotificationManager; import android.app.PendingIntent; +import android.app.Service; import android.content.ContentResolver; import android.content.Context; import android.media.MediaScannerConnection; @@ -40,6 +41,25 @@ import static foundation.e.drive.utils.AppConstants.SETTINGSYNC_PROVIDER_AUTHORI public abstract class CommonUtils { final private static String TAG = CommonUtils.class.getSimpleName(); + + /** + * Set ServiceUncaughtExceptionHandler to be the MainThread Exception Handler + * Or update the service which use it + * @param service current service + */ + public static void setServiceUnCaughtExceptionHandler(Service service){ + + Thread.UncaughtExceptionHandler defaultUEH = Thread.getDefaultUncaughtExceptionHandler(); + if(defaultUEH.getClass().getSimpleName().equals(ServiceExceptionHandler.class.getSimpleName())){ + Log.d("ObserverService", "ServiceExceptionHandler already set!"); + ((ServiceExceptionHandler) defaultUEH).setService(service); + }else{ + Thread.setDefaultUncaughtExceptionHandler(new ServiceExceptionHandler(service)); + } + } + + + /** * Unregister from screeOffReceiver component * @param context app context diff --git a/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java index ef4cf52d..96248dc6 100644 --- a/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java +++ b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java @@ -7,6 +7,8 @@ */ package foundation.e.drive.utils; import android.app.Service; +import android.content.Context; +import android.content.SharedPreferences; import android.os.Environment; import android.util.Log; @@ -17,14 +19,23 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.lang.Thread.UncaughtExceptionHandler; +import foundation.e.drive.services.OperationManagerService; + /** * @author Vincent Bourgmayer */ public class ServiceExceptionHandler implements UncaughtExceptionHandler{ private final static String TAG = ServiceExceptionHandler.class.getSimpleName(); private UncaughtExceptionHandler defaultUEH; + private Service service; - Service service; + /** + * Change the service that could trigger an UncaughtException + * @param service service instance + */ + public void setService(Service service){ + this.service = service; + } public ServiceExceptionHandler(Service service) { this.service = service; @@ -33,6 +44,14 @@ public class ServiceExceptionHandler implements UncaughtExceptionHandler{ @Override public void uncaughtException(Thread t, Throwable e) { + Log.d(TAG, "Service class: "+service.getClass().getSimpleName()); + //IF OMS is crashing, set settings that it runs to false; + if(service.getClass().getSimpleName().equals(OperationManagerService.class.getSimpleName())){ + service.getSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE) + .edit() + .putBoolean(AppConstants.KEY_OMS_IS_WORKING, false) + .apply(); + } if(isExternalStorageAvailable() && !isExternalStorageReadOnly()){ //Get TimeStamp @@ -42,22 +61,19 @@ public class ServiceExceptionHandler implements UncaughtExceptionHandler{ String fileName = "eDrive-crash-"+timestamp+".log"; File downloadDir = service.getApplication().getExternalFilesDir("Logs"); - //File downloadDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath()); File logFile = new File(downloadDir, fileName); try { FileOutputStream fos = new FileOutputStream(logFile); + fos.write(service.getClass().getSimpleName().getBytes()); fos.write(getStackTraceAsString(e).getBytes()); fos.close(); logFile.setReadable(true, false); - //DID NOT WORKS: CommonUtils.doActionMediaScannerConnexionScanFile(service, logFile.getCanonicalPath()); - } catch (IOException exception) { exception.printStackTrace(); } } - //source: https://stackoverflow.com/questions/9050962/rethrow-uncaughtexceptionhandler-exception-after-logging-it/9050990#9050990 if(defaultUEH != null){ defaultUEH.uncaughtException(t, e); -- GitLab From d8719a63455ba10867054ff58a747a2854db161c Mon Sep 17 00:00:00 2001 From: vince-bourgmayer Date: Thu, 12 Dec 2019 17:36:09 +0100 Subject: [PATCH 17/20] use method from commonUtils to set the UEH --- .../e/drive/services/InitializerService.java | 6 +----- .../foundation/e/drive/services/ObserverService.java | 7 ++----- .../e/drive/services/OperationManagerService.java | 10 +++------- 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/services/InitializerService.java b/app/src/main/java/foundation/e/drive/services/InitializerService.java index 1f9cde01..29c6d0da 100644 --- a/app/src/main/java/foundation/e/drive/services/InitializerService.java +++ b/app/src/main/java/foundation/e/drive/services/InitializerService.java @@ -66,11 +66,7 @@ public class InitializerService extends Service implements OnRemoteOperationList public int onStartCommand( Intent intent, int flags, int startId ) { Log.i(TAG, "onStartCommand(...)"); - if(Thread.getDefaultUncaughtExceptionHandler().getClass().getSimpleName().equals(ServiceExceptionHandler.class.getSimpleName())){ - Log.d("ObserverService", "ServiceExceptionHandler already set!"); - }else{ - Thread.setDefaultUncaughtExceptionHandler(new ServiceExceptionHandler(this)); - } + CommonUtils.setServiceUnCaughtExceptionHandler(this); //Get account SharedPreferences prefs = this.getSharedPreferences( AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE ); diff --git a/app/src/main/java/foundation/e/drive/services/ObserverService.java b/app/src/main/java/foundation/e/drive/services/ObserverService.java index 413dad2e..d46364a6 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -80,11 +80,8 @@ public class ObserverService extends Service implements OnRemoteOperationListene public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "onStartCommand("+startId+")"); - if(Thread.getDefaultUncaughtExceptionHandler().getClass().getSimpleName().equals(ServiceExceptionHandler.class.getSimpleName())){ - Log.d("ObserverService", "ServiceExceptionHandler already set!"); - }else{ - Thread.setDefaultUncaughtExceptionHandler(new ServiceExceptionHandler(this)); - } + CommonUtils.setServiceUnCaughtExceptionHandler(this); + SharedPreferences prefs = this.getSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE); String accountName = prefs.getString(AccountManager.KEY_ACCOUNT_NAME, ""); String accountType = prefs.getString(AccountManager.KEY_ACCOUNT_TYPE, ""); diff --git a/app/src/main/java/foundation/e/drive/services/OperationManagerService.java b/app/src/main/java/foundation/e/drive/services/OperationManagerService.java index c21ef3a5..24bb14be 100644 --- a/app/src/main/java/foundation/e/drive/services/OperationManagerService.java +++ b/app/src/main/java/foundation/e/drive/services/OperationManagerService.java @@ -227,11 +227,9 @@ public class OperationManagerService extends Service implements OnRemoteOperatio @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "onStartCommand()"); - if(Thread.getDefaultUncaughtExceptionHandler().getClass().getSimpleName().equals(ServiceExceptionHandler.class.getSimpleName())){ - Log.d("ObserverService", "ServiceExceptionHandler already set!"); - }else{ - Thread.setDefaultUncaughtExceptionHandler(new ServiceExceptionHandler(this)); - } + + CommonUtils.setServiceUnCaughtExceptionHandler(this); + Bundle extras = intent.getExtras(); Log.d(TAG, "OperationManagerService recieved "+(extras == null ? "null extras": extras.size()+" operations to perform") ); @@ -284,11 +282,9 @@ public class OperationManagerService extends Service implements OnRemoteOperatio }else{ Log.w(TAG, "Intent's extras is null."); } - return super.onStartCommand(intent, flags, startId); } - @Nullable @Override public IBinder onBind(Intent intent) { -- GitLab From 3b0f8008ac8b5eb46de15a934174f84ed131c2da Mon Sep 17 00:00:00 2001 From: vince-bourgmayer Date: Fri, 13 Dec 2019 10:42:18 +0100 Subject: [PATCH 18/20] replace title in Logcat by TAG field --- .../java/foundation/e/drive/utils/ServiceExceptionHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java index 96248dc6..98830444 100644 --- a/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java +++ b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java @@ -78,7 +78,7 @@ public class ServiceExceptionHandler implements UncaughtExceptionHandler{ if(defaultUEH != null){ defaultUEH.uncaughtException(t, e); }else{ - Log.d("ServiceExceptionHandler", "/e/ Drive has crashed and there is no ExceptionHandler"); + Log.d(TAG, "there is no ExceptionHandler"); System.exit(1); //Kill /e/ Drive... } } -- GitLab From 3d2bc383c7fb7d29eef051675f3cec7f5a746fcf Mon Sep 17 00:00:00 2001 From: vince-bourgmayer Date: Sat, 14 Dec 2019 15:10:08 +0100 Subject: [PATCH 19/20] add method to remove oldestCrashlogs. add CrashlogsFileFilter with unitTest class. --- .../fileFilters/CrashlogsFileFilter.java | 42 ++++++++++++++++ .../e/drive/services/ObserverService.java | 28 +++++++++++ .../drive/utils/ServiceExceptionHandler.java | 7 ++- .../CrashlogFileFilterTest.java | 48 +++++++++++++++++++ 4 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/foundation/e/drive/fileFilters/CrashlogsFileFilter.java create mode 100644 app/src/test/java/foundation/e/drive/Test/FileFilterTest/CrashlogFileFilterTest.java diff --git a/app/src/main/java/foundation/e/drive/fileFilters/CrashlogsFileFilter.java b/app/src/main/java/foundation/e/drive/fileFilters/CrashlogsFileFilter.java new file mode 100644 index 00000000..3c902cb7 --- /dev/null +++ b/app/src/main/java/foundation/e/drive/fileFilters/CrashlogsFileFilter.java @@ -0,0 +1,42 @@ +package foundation.e.drive.fileFilters; + +import java.io.File; +import java.io.FileFilter; + +import foundation.e.drive.utils.ServiceExceptionHandler; + +public class CrashlogsFileFilter implements FileFilter { + private final static long max_timestamp_delta = 864000000; //10 days in ms (240*3600*1000) + + @Override + public boolean accept(File pathname) { + String fileTimestamp = extractTimestamp(pathname.getName(), + ServiceExceptionHandler.LOG_FILE_NAME_PREFIX, + ServiceExceptionHandler.LOG_FILE_EXTENSION); + + long timestamp; + try { + timestamp = Long.parseLong(fileTimestamp); + }catch (NumberFormatException e){ + //Can't parse the extracted timestamp + //This file has not the expected name. It must be removed + return true; + } + + //if current Date - file date >= max deta allowed + return ((System.currentTimeMillis() - timestamp ) >= max_timestamp_delta); + } + + /** + * Extract the timestamp from the name of the file + * UnitTested! + * @param fileName Filename + * @param prefix prefix to ignore + * @param extension extension to ignore + * @return the timestamp extracted from the name + */ + private String extractTimestamp(String fileName, String prefix, String extension){ + return fileName.substring(prefix.length(), (fileName.length() - extension.length())); + } + +} diff --git a/app/src/main/java/foundation/e/drive/services/ObserverService.java b/app/src/main/java/foundation/e/drive/services/ObserverService.java index d46364a6..54a352f3 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -30,13 +30,17 @@ import com.owncloud.android.lib.resources.files.model.RemoteFile; import java.io.File; import java.io.FileFilter; import java.io.FileOutputStream; +import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.ListIterator; import java.util.Map; +import java.util.stream.Stream; import foundation.e.drive.database.DbHelper; +import foundation.e.drive.fileFilters.CrashlogsFileFilter; import foundation.e.drive.fileFilters.FileFilterFactory; import foundation.e.drive.fileFilters.OnlyFileFilter; import foundation.e.drive.models.SyncedFolder; @@ -151,12 +155,36 @@ public class ObserverService extends Service implements OnRemoteOperationListene Log.i(TAG, "begin()"); this.isWorking = true; clearCachedFile(); + deleteOldestCrashlogs(); startScan(true); } + /** + * This method remove all the crash-logs file + * in external dir that are 10 days or more old. + */ + private void deleteOldestCrashlogs(){ + Log.i(TAG, "deleteOldestCrashLogs()"); + File[] fileToRemove = getExternalFilesDir(ServiceExceptionHandler.CRASH_LOG_FOLDER) + .listFiles(new CrashlogsFileFilter()); + + int counter = 0; + for (File file : fileToRemove) { + try { + file.delete(); + ++counter; + }catch (SecurityException e){ + e.printStackTrace(); + } + } + Log.d(TAG, counter+" old crashlogs file.s deleted"); + } + + /** * Clear cached file unused: * remove each cached file which isn't in OperationManagerService.lockedSyncedFileState(); + * @TODO rewrite this method! */ private void clearCachedFile(){ Log.i(TAG, "clearCachedFile()"); diff --git a/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java index 98830444..0833f3e3 100644 --- a/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java +++ b/app/src/main/java/foundation/e/drive/utils/ServiceExceptionHandler.java @@ -26,6 +26,9 @@ import foundation.e.drive.services.OperationManagerService; */ public class ServiceExceptionHandler implements UncaughtExceptionHandler{ private final static String TAG = ServiceExceptionHandler.class.getSimpleName(); + public final static String CRASH_LOG_FOLDER = "crash-logs"; + public final static String LOG_FILE_NAME_PREFIX = "eDrive-crash-"; + public final static String LOG_FILE_EXTENSION = ".log"; private UncaughtExceptionHandler defaultUEH; private Service service; @@ -58,9 +61,9 @@ public class ServiceExceptionHandler implements UncaughtExceptionHandler{ Long timestamp = System.currentTimeMillis(); //Create a new file that user can sent to us - String fileName = "eDrive-crash-"+timestamp+".log"; + String fileName = LOG_FILE_NAME_PREFIX+timestamp+LOG_FILE_EXTENSION; - File downloadDir = service.getApplication().getExternalFilesDir("Logs"); + File downloadDir = service.getApplication().getExternalFilesDir(CRASH_LOG_FOLDER); File logFile = new File(downloadDir, fileName); try { diff --git a/app/src/test/java/foundation/e/drive/Test/FileFilterTest/CrashlogFileFilterTest.java b/app/src/test/java/foundation/e/drive/Test/FileFilterTest/CrashlogFileFilterTest.java new file mode 100644 index 00000000..d10b6435 --- /dev/null +++ b/app/src/test/java/foundation/e/drive/Test/FileFilterTest/CrashlogFileFilterTest.java @@ -0,0 +1,48 @@ +package foundation.e.drive.Test.FileFilterTest; + +import org.junit.Assert; +import org.junit.Test; + +public class CrashlogFileFilterTest { + + private String mockFileName(String target, String prefix, String extension){ + return prefix+target+extension; + } + + private String extractTimestamp(String fileName, String prefix, String extension){ + return fileName.substring(prefix.length(), (fileName.length() - extension.length())); + } + + @Test + public void extractTimeStampFromFileNameTest(){ + String prefix = "edrive-"; + String extension = ".log"; + String target = ""; + //Case 1 Empty Target + String base = mockFileName(target, prefix, extension); + Assert.assertEquals("Base length is incorrect", prefix.length()+extension.length(), base.length()); + + String fileTimestamp = extractTimestamp(base, prefix, extension); + Assert.assertEquals("result is not empty String", "", fileTimestamp); + + //Case 2: Prefix is empty + prefix = ""; + target = "1234"; + base = mockFileName(target, prefix, extension); + Assert.assertEquals("Base length is incorrect", prefix.length()+target.length()+extension.length(), base.length()); + + fileTimestamp = extractTimestamp(base, prefix, extension); + Assert.assertEquals("result is not empty String", target, fileTimestamp); + + //Case 3: extension is empty + + prefix = "edrive-"; + extension = ""; + + base = mockFileName(target, prefix, extension); + Assert.assertEquals("Base length is incorrect", prefix.length()+target.length(), base.length()); + + fileTimestamp = extractTimestamp(base, prefix, extension); + Assert.assertEquals("result is not empty String", target, fileTimestamp); + } +} -- GitLab From cda9afd5bbba1f942c5f9d49fb42849f2c3c80d0 Mon Sep 17 00:00:00 2001 From: vince-bourgmayer Date: Sat, 14 Dec 2019 15:29:20 +0100 Subject: [PATCH 20/20] remove useless import in ObserverService --- .../main/java/foundation/e/drive/services/ObserverService.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/src/main/java/foundation/e/drive/services/ObserverService.java b/app/src/main/java/foundation/e/drive/services/ObserverService.java index 54a352f3..6cf06395 100644 --- a/app/src/main/java/foundation/e/drive/services/ObserverService.java +++ b/app/src/main/java/foundation/e/drive/services/ObserverService.java @@ -30,14 +30,11 @@ import com.owncloud.android.lib.resources.files.model.RemoteFile; import java.io.File; import java.io.FileFilter; import java.io.FileOutputStream; -import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.ListIterator; import java.util.Map; -import java.util.stream.Stream; import foundation.e.drive.database.DbHelper; import foundation.e.drive.fileFilters.CrashlogsFileFilter; -- GitLab