improve logging in export backup service. closes #3672

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/services/ExportBackupService.java | 59 
1 file changed, 36 insertions(+), 23 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/services/ExportBackupService.java 🔗

@@ -14,6 +14,8 @@ import android.os.IBinder;
 import android.support.v4.app.NotificationCompat;
 import android.util.Log;
 
+import com.google.common.base.Strings;
+
 import java.io.DataOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
@@ -70,7 +72,7 @@ public class ExportBackupService extends Service {
         if (Compatibility.runsAndTargetsTwentyFour(context)) {
             openIntent.setType("resource/folder");
         } else {
-            openIntent.setDataAndType(Uri.parse("file://"+path),"resource/folder");
+            openIntent.setDataAndType(Uri.parse("file://" + path), "resource/folder");
         }
         openIntent.putExtra("org.openintents.extra.ABSOLUTE_PATH", path);
 
@@ -87,7 +89,7 @@ public class ExportBackupService extends Service {
 
     }
 
-    private static void accountExport(SQLiteDatabase db, String uuid, PrintWriter writer) {
+    private static void accountExport(final SQLiteDatabase db, final String uuid, final PrintWriter writer) {
         final StringBuilder builder = new StringBuilder();
         final Cursor accountCursor = db.query(Account.TABLENAME, null, Account.UUID + "=?", new String[]{uuid}, null, null, null);
         while (accountCursor != null && accountCursor.moveToNext()) {
@@ -136,27 +138,28 @@ public class ExportBackupService extends Service {
         }
     }
 
-    public static byte[] getKey(String password, byte[] salt) {
+    public static byte[] getKey(final String password, final byte[] salt) throws InvalidKeySpecException {
+        final SecretKeyFactory factory;
         try {
-            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
-            return factory.generateSecret(new PBEKeySpec(password.toCharArray(), salt, 1024, 128)).getEncoded();
-        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
-            throw new AssertionError(e);
+            factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
+        } catch (NoSuchAlgorithmException e) {
+            throw new IllegalStateException(e);
         }
+        return factory.generateSecret(new PBEKeySpec(password.toCharArray(), salt, 1024, 128)).getEncoded();
     }
 
-    private static String cursorToString(String tablename, Cursor cursor, int max) {
-        return cursorToString(tablename, cursor, max, false);
+    private static String cursorToString(final String table, final Cursor cursor, final int max) {
+        return cursorToString(table, cursor, max, false);
     }
 
-    private static String cursorToString(final String tablename, final Cursor cursor, int max, boolean ignore) {
-        final boolean identities = SQLiteAxolotlStore.IDENTITIES_TABLENAME.equals(tablename);
+    private static String cursorToString(final String table, final Cursor cursor, int max, boolean ignore) {
+        final boolean identities = SQLiteAxolotlStore.IDENTITIES_TABLENAME.equals(table);
         StringBuilder builder = new StringBuilder();
         builder.append("INSERT ");
         if (ignore) {
             builder.append("OR IGNORE ");
         }
-        builder.append("INTO ").append(tablename).append("(");
+        builder.append("INTO ").append(table).append("(");
         int skipColumn = -1;
         for (int i = 0; i < cursor.getColumnCount(); ++i) {
             final String name = cursor.getColumnName(i);
@@ -222,7 +225,8 @@ public class ExportBackupService extends Service {
                 try {
                     files = export();
                     success = true;
-                } catch (Exception e) {
+                } catch (final Exception e) {
+                    Log.d(Config.LOGTAG, "unable to create backup", e);
                     success = false;
                     files = Collections.emptyList();
                 }
@@ -234,6 +238,8 @@ public class ExportBackupService extends Service {
                 stopSelf();
             }).start();
             return START_STICKY;
+        } else {
+            Log.d(Config.LOGTAG, "ExportBackupService. ignoring start command because already running");
         }
         return START_NOT_STICKY;
     }
@@ -241,7 +247,7 @@ public class ExportBackupService extends Service {
     private void messageExport(SQLiteDatabase db, String uuid, PrintWriter writer, Progress progress) {
         Cursor cursor = db.rawQuery("select messages.* from messages join conversations on conversations.uuid=messages.conversationUuid where conversations.accountUuid=?", new String[]{uuid});
         int size = cursor != null ? cursor.getCount() : 0;
-        Log.d(Config.LOGTAG, "exporting " + size + " messages");
+        Log.d(Config.LOGTAG, "exporting " + size + " messages for account " + uuid);
         int i = 0;
         int p = 0;
         while (cursor != null && cursor.moveToNext()) {
@@ -272,7 +278,14 @@ public class ExportBackupService extends Service {
         final int max = this.mAccounts.size();
         final SecureRandom secureRandom = new SecureRandom();
         final List<File> files = new ArrayList<>();
-        for (Account account : this.mAccounts) {
+        Log.d(Config.LOGTAG, "starting backup for " + max + " accounts");
+        for (final Account account : this.mAccounts) {
+            final String password = account.getPassword();
+            if (Strings.nullToEmpty(password).trim().isEmpty()) {
+                Log.d(Config.LOGTAG, String.format("skipping backup for %s because password is empty. unable to encrypt", account.getJid().asBareJid()));
+                continue;
+            }
+            Log.d(Config.LOGTAG, String.format("exporting data for account %s (%s)", account.getJid().asBareJid(), account.getUuid()));
             final byte[] IV = new byte[12];
             final byte[] salt = new byte[16];
             secureRandom.nextBytes(IV);
@@ -281,8 +294,9 @@ public class ExportBackupService extends Service {
             final Progress progress = new Progress(mBuilder, max, count);
             final File file = new File(FileBackend.getBackupDirectory(this) + account.getJid().asBareJid().toEscapedString() + ".ceb");
             files.add(file);
-            if (file.getParentFile().mkdirs()) {
-                Log.d(Config.LOGTAG, "created backup directory " + file.getParentFile().getAbsolutePath());
+            final File directory = file.getParentFile();
+            if (directory != null && directory.mkdirs()) {
+                Log.d(Config.LOGTAG, "created backup directory " + directory.getAbsolutePath());
             }
             final FileOutputStream fileOutputStream = new FileOutputStream(file);
             final DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream);
@@ -290,8 +304,7 @@ public class ExportBackupService extends Service {
             dataOutputStream.flush();
 
             final Cipher cipher = Compatibility.twentyEight() ? Cipher.getInstance(CIPHERMODE) : Cipher.getInstance(CIPHERMODE, PROVIDER);
-            byte[] key = getKey(account.getPassword(), salt);
-            Log.d(Config.LOGTAG, backupFileHeader.toString());
+            final byte[] key = getKey(password, salt);
             SecretKeySpec keySpec = new SecretKeySpec(key, KEYTYPE);
             IvParameterSpec ivSpec = new IvParameterSpec(IV);
             cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
@@ -315,7 +328,7 @@ public class ExportBackupService extends Service {
         return files;
     }
 
-    private void notifySuccess(List<File> files) {
+    private void notifySuccess(final List<File> files) {
         final String path = FileBackend.getBackupDirectory(this);
 
         PendingIntent openFolderIntent = null;
@@ -331,14 +344,14 @@ public class ExportBackupService extends Service {
         if (files.size() > 0) {
             final Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
             ArrayList<Uri> uris = new ArrayList<>();
-            for(File file : files) {
+            for (File file : files) {
                 uris.add(FileBackend.getUriForFile(this, file));
             }
             intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
             intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
             intent.setType(MIME_TYPE);
             final Intent chooser = Intent.createChooser(intent, getString(R.string.share_backup_files));
-            shareFilesIntent = PendingIntent.getActivity(this,190, chooser, PendingIntent.FLAG_UPDATE_CURRENT);
+            shareFilesIntent = PendingIntent.getActivity(this, 190, chooser, PendingIntent.FLAG_UPDATE_CURRENT);
         }
 
         NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getBaseContext(), "backup");
@@ -361,7 +374,7 @@ public class ExportBackupService extends Service {
         return null;
     }
 
-    private class Progress {
+    private static class Progress {
         private final NotificationCompat.Builder builder;
         private final int max;
         private final int count;