131 lines
5.6 KiB
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;
|
|
}
|
|
} |