6

I'm implementing a backup/restore system in my android app.

An automatic backup occures every couple of minutes. I'm trying to restore my db backup file from my sd card, after my app was uninstalled and then installed again.

Backup works, but here's the problem:
Whenever the user installs my app again, there's a file not found exception, but, if the user closes the app, and then opens it again, the restore is just fine. Somehow, the restoring faces problem when the app is first launched.

The restore must happen on first time launch.

Note: the backupExists function returns true.

@Override
public void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if(backUpExists()){

        restoreDB();
      }
}
     private boolean backUpExists()
  {
    try{
        File sd = Environment.getExternalStorageDirectory();
        if (sd.canRead()){
            String backupDBPath = "myDB";
             File backupedDB = new File(sd, backupDBPath);
             if(backupedDB.exists()){
                 return true;
             }
        }
    } catch(Exception ex) {
         Toast.makeText(getBaseContext(), ex.toString(), Toast.LENGTH_LONG).show();
    }
        return false;
  }
  private void restoreDB()
  {
    try{
        File sd = Environment.getExternalStorageDirectory();
        File data = Environment.getDataDirectory();

        if (sd.canWrite()) {
            String restroredDBPath = "//data//myPackage//databases//myDB";
            String backupDBPath = "myDB";
            File restoredDB = new File(data, restroredDBPath);
            File backupedDB = new File(sd, backupDBPath);
                FileChannel src = new FileInputStream(backupedDB).getChannel();
                FileChannel dst = new FileOutputStream(restoredDB).getChannel();
                dst.transferFrom(src, 0, src.size());
                src.close();
                dst.close();
                Toast.makeText(getBaseContext(), restoredDB.toString(), Toast.LENGTH_LONG).show();

        }
    } catch (Exception e) {

        Toast.makeText(getBaseContext(), e.toString(), Toast.LENGTH_LONG).show();
    }
  }

Backtrace

09-09 22:49:50.931: I/Database(23206): sqlite returned: error code = 26, msg = statement aborts at 14: [SELECT COUNT(*) FROM Photos WHERE AlbumId=0] file is encrypted or is not a database
09-09 22:49:50.931: D/AndroidRuntime(23206): Shutting down VM
09-09 22:49:50.931: W/dalvikvm(23206): threadid=1: thread exiting with uncaught exception (group=0x4151c700)
09-09 22:49:50.931: E/AndroidRuntime(23206): FATAL EXCEPTION: main
09-09 22:49:50.931: E/AndroidRuntime(23206): net.sqlcipher.database.SQLiteException: file is encrypted or is not a database
09-09 22:49:50.931: E/AndroidRuntime(23206):    at     net.sqlcipher.database.SQLiteQuery.native_fill_window(Native Method)
09-09 22:49:50.931: E/AndroidRuntime(23206):    at net.sqlcipher.database.SQLiteQuery.fillWindow(SQLiteQuery.java:73)
09-09 22:49:50.931: E/AndroidRuntime(23206):    at net.sqlcipher.database.SQLiteCursor.fillWindow(SQLiteCursor.java:290)
[snipped]
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
idish
  • 3,190
  • 12
  • 53
  • 85
  • And where exactly does the exception happen? Remove the `try`/`catch` to get a proper stack trace. – CL. Sep 09 '13 at 11:33
  • I'm getting a "file is encrypted or is not a database" exception right when I try to query using the restored DB. Here's the full stacktrace: http://pastebin.com/j4tQU26K – idish Sep 09 '13 at 19:52
  • @CL. Forgot to tag :) – idish Sep 09 '13 at 19:53
  • In which class is this code? Is it possible that some code already has tried to open the database file? – CL. Sep 09 '13 at 20:30
  • @CL. Yes, it is possible. I'm using a singletone DatabaseHelper class, that is already instantiated before the restore operation. But, I tried to load the database libraries once again, and also set the instance of my database to null so it will re-create a new DatabaseHelper object. Though, I'm getting the same exception. – idish Sep 09 '13 at 20:39
  • Here's a relevant code of my DatabaseHelper class: http://pastebin.com/rLHV74hi I'm calling getInstance(...) function before the restore. and setDatabaseHelperNull() function after I restore. – idish Sep 09 '13 at 20:43
  • You must not use hardcoded path – Trikaldarshiii Sep 14 '13 at 01:46
  • @Hi-TechKitKatAndroid How can I make that path a device independent? – idish Sep 14 '13 at 14:20

3 Answers3

20

Please use this code it may help you... I have done the same with this way

For Backup

try {
    File sd = Environment.getExternalStorageDirectory();
    File data = Environment.getDataDirectory();

    if (sd.canWrite()) {
        String currentDBPath = "//data/package name/databases/database_name";
        String backupDBPath = "database_name";
        File currentDB = new File(data, currentDBPath);
        File backupDB = new File(sd, backupDBPath);

        if (currentDB.exists()) {
            FileChannel src = new FileInputStream(currentDB).getChannel();
            FileChannel dst = new FileOutputStream(backupDB).getChannel();
            dst.transferFrom(src, 0, src.size());
            src.close();
            dst.close();
            Toast.makeText(getApplicationContext(), "Backup is successful to SD card", Toast.LENGTH_SHORT).show();
        }
    }
} catch (Exception e) {
}

For Restore

try {
    File sd = Environment.getExternalStorageDirectory();
    File data = Environment.getDataDirectory();

    if (sd.canWrite()) {
    String currentDBPath = "//data/package name/databases/database_name";
        String backupDBPath = "database_name";
        File currentDB = new File(data, currentDBPath);
        File backupDB = new File(sd, backupDBPath);

        if (currentDB.exists()) {
            FileChannel src = new FileInputStream(backupDB).getChannel();
            FileChannel dst = new FileOutputStream(currentDB).getChannel();
            dst.transferFrom(src, 0, src.size());
            src.close();
            dst.close();
            Toast.makeText(getApplicationContext(), "Database Restored successfully", Toast.LENGTH_SHORT).show();
        }
    }
} catch (Exception e) {
}

A little dfference between both u can see in filechannel inside if condition.

Balvinder Singh
  • 580
  • 6
  • 19
  • Your answer hasn't solved my problem, but it made me look once again what really happens before the restore operation. I found out that I was using the new DB functions, so that caused all the problems. Thank you. – idish Sep 10 '13 at 13:21
  • 1
    It sometimes don't copy database file content in internal storage. If i pull database from device, it shows blank. Sometimes it does. Unable to recognize the problem. – Patriotic Jul 21 '18 at 14:20
  • @Patriotic it is may be because I make this post almost 5 years back. So after that so many changes made by google for data security. That may be the problem for such behaviour. – Balvinder Singh Dec 19 '18 at 06:36
3
try
{
    String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
    String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/CALC/Backup";
    //final 
    String inFileName = path+"/Calc_backup :"+date;
    File dbFile = new File(inFileName);
    FileInputStream fis = new FileInputStream(dbFile);


    /*File dir = new File(path);
    if(!dir.exists())
        dir.mkdirs();*/
    //Toast.makeText(getActivity(), "directory created @"+dir.getPath(), 2).show();

    // String outFileName = Environment.getExternalStorageDirectory()+"Calac/hems.txt";

    //String outFileName = path+"/"+date;
    String outFileName = "/data/data/com.special.ResideMenuDemo/databases/Calq";

    // Open the empty db as the output stream
    OutputStream output = new FileOutputStream(outFileName);

    // Transfer bytes from the inputfile to the outputfile
    byte[] buffer = new byte[1024];
    int length;

    while ((length = fis.read(buffer))>0)
    {
        output.write(buffer, 0, length);
    }

    Toast.makeText(getActivity(), "Restore Successfully", 2).show();
    // Close the streams
    output.flush();
    output.close();
    fis.close();

}
catch(Exception e)
{
    e.printStackTrace();
}
Devraj Gadhavi
  • 3,541
  • 3
  • 38
  • 67
0

The problem I feel is with reading the already existing db file. You actually are not reading it, the code is just creating a new one every time the app is installed. You will have to give the exact name of the db file you are referring to in order to read it in your getExternalEvironment function..

BenMorel
  • 34,448
  • 50
  • 182
  • 322
  • Ehm, the problem is already solved, the solution wasn't about the specified code, but there was another problem. Take a look at the comment in the answer above you, thanks :) – idish Sep 14 '13 at 15:07