Conversations/src/main/java/eu/siacs/conversations/services/BackupService.java

131 lines
5.6 KiB
Java

package eu.siacs.conversations.services;
import android.app.AlarmManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import android.preference.PreferenceManager;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Calendar;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.crypto.NoSuchPaddingException;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.persistance.DatabaseBackend;
import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.utils.EncryptDecryptFile;
public class BackupService extends Service {
private static final int NOTIFICATION_ID = 1;
private static AtomicBoolean running = new AtomicBoolean(false);
private AlarmManager alarmMgr;
private PendingIntent alarmIntent;
@Override
public void onCreate() {
/*
alarmIntent = PendingIntent.getService(this, 0, new Intent(this, BackupService.class), 0);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 4);
// With setInexactRepeating(), you have to use one of the AlarmManager interval
// constants--in this case, AlarmManager.INTERVAL_DAY.
alarmMgr = (AlarmManager)(this.getSystemService(Context.ALARM_SERVICE));
alarmMgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, alarmIntent);
*/
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (running.compareAndSet(false, true)) {
new Thread(() -> {
export();
stopForeground(true);
running.set(false);
stopSelf();
}).start();
}
return START_NOT_STICKY;
}
private void export() {
try {
NotificationManager mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getBaseContext(), "backup");
mBuilder.setContentTitle(getString(R.string.notification_backup_create))
.setSmallIcon(R.drawable.ic_import_export_white_24dp);
startForeground(NOTIFICATION_ID, mBuilder.build());
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
String encryptionKey = prefs.getString("backup_password", null);
if (encryptionKey == null || encryptionKey.length() < 3) {
Log.d(Config.LOGTAG, "BackupService: failed to write encryted backup to sdcard because of missing password");
return;
}
Log.d(Config.LOGTAG, "BackupService: start creating backup");
// Get hold of the db:
FileInputStream inputFile = new FileInputStream(this.getDatabasePath(DatabaseBackend.DATABASE_NAME));
// Set the output folder on the SDcard
File directory = new File(FileBackend.getBackupDirectory());
// Create the folder if it doesn't exist:
if (!directory.exists()) {
boolean directory_created = directory.mkdirs();
Log.d(Config.LOGTAG, "BackupService: backup directory created " + directory_created);
}
//Delete old database export file
File tempDBFile = new File(directory + "/database.bak");
if (tempDBFile.exists()) {
Log.d(Config.LOGTAG, "BackupService: Delete temp database backup file from " + tempDBFile.toString());
boolean temp_db_file_deleted = tempDBFile.delete();
Log.d(Config.LOGTAG, "BackupService: old backup file deleted " + temp_db_file_deleted);
}
// Set the output file stream up:
FileOutputStream outputFile = new FileOutputStream(directory.getPath() + "/database.db.crypt");
// encrypt database from the input file to the output file
try {
EncryptDecryptFile.encrypt(inputFile, outputFile, encryptionKey);
Log.d(Config.LOGTAG, "BackupService: starting encrypted output to " + outputFile.toString());
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
Log.d(Config.LOGTAG, "BackupService: Database exporter: encryption failed with " + e);
e.printStackTrace();
} catch (InvalidKeyException e) {
Log.d(Config.LOGTAG, "BackupService: Database exporter: encryption failed (invalid key) with " + e);
e.printStackTrace();
} catch (IOException e) {
Log.d(Config.LOGTAG, "BackupService: Database exporter: encryption failed (IO) with " + e);
e.printStackTrace();
} finally {
Log.d(Config.LOGTAG, "BackupService: backup job finished");
}
mNotifyManager.notify(NOTIFICATION_ID, mBuilder.build());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}