diff options
| author | Joe Onorato <joeo@android.com> | 2009-06-18 13:11:18 -0700 | 
|---|---|---|
| committer | Joe Onorato <joeo@android.com> | 2009-06-18 18:41:11 -0700 | 
| commit | d2d9ceb7305d593c1b767bbb05de0082a9af4109 (patch) | |
| tree | 1ba39c3c5901d65a18855286e240f177820a6ec6 | |
| parent | abce4e8714bed26a2b37b20ad3f02cf619d71c9a (diff) | |
| download | frameworks_base-d2d9ceb7305d593c1b767bbb05de0082a9af4109.zip frameworks_base-d2d9ceb7305d593c1b767bbb05de0082a9af4109.tar.gz frameworks_base-d2d9ceb7305d593c1b767bbb05de0082a9af4109.tar.bz2 | |
Make RestoreHelper and friends also write out the snapshot state.
| -rw-r--r-- | core/java/android/backup/RestoreHelper.java | 3 | ||||
| -rw-r--r-- | core/java/android/backup/RestoreHelperBase.java | 71 | ||||
| -rw-r--r-- | core/java/android/backup/RestoreHelperDispatcher.java | 16 | ||||
| -rw-r--r-- | core/jni/Android.mk | 3 | ||||
| -rw-r--r-- | core/jni/AndroidRuntime.cpp | 2 | ||||
| -rw-r--r-- | core/jni/android_backup_RestoreHelperBase.cpp | 94 | ||||
| -rw-r--r-- | include/utils/BackupHelpers.h | 35 | ||||
| -rw-r--r-- | libs/utils/BackupHelpers.cpp | 115 | ||||
| -rw-r--r-- | tests/backup/src/com/android/backuptest/BackupTestActivity.java | 7 | ||||
| -rw-r--r-- | tests/backup/src/com/android/backuptest/BackupTestAgent.java | 2 | 
10 files changed, 278 insertions, 70 deletions
| diff --git a/core/java/android/backup/RestoreHelper.java b/core/java/android/backup/RestoreHelper.java index ac7d8ee..e47869c 100644 --- a/core/java/android/backup/RestoreHelper.java +++ b/core/java/android/backup/RestoreHelper.java @@ -16,6 +16,8 @@  package android.backup; +import android.os.ParcelFileDescriptor; +  import java.io.InputStream;  /** @hide */ @@ -27,5 +29,6 @@ public interface RestoreHelper {       * <code>dataSize</code> bytes from <code>data</code>.       */      public void restoreEntity(BackupDataInputStream data); +    public void writeSnapshot(ParcelFileDescriptor fd);  } diff --git a/core/java/android/backup/RestoreHelperBase.java b/core/java/android/backup/RestoreHelperBase.java index 894c9af..93a8fef 100644 --- a/core/java/android/backup/RestoreHelperBase.java +++ b/core/java/android/backup/RestoreHelperBase.java @@ -17,69 +17,66 @@  package android.backup;  import android.content.Context; +import android.os.ParcelFileDescriptor;  import android.util.Log;  import java.io.InputStream;  import java.io.File; +import java.io.FileDescriptor;  import java.io.FileOutputStream; -import java.io.IOException;  class RestoreHelperBase {      private static final String TAG = "RestoreHelperBase"; -    private static final int BUF_SIZE = 8 * 1024; +    int mPtr;      Context mContext; -    byte[] mBuf = new byte[BUF_SIZE];      boolean mExceptionLogged;      RestoreHelperBase(Context context) { +        mPtr = ctor();          mContext = context;      } -    void writeFile(File f, InputStream in) { -        boolean success = false; -        FileOutputStream out = null; +    protected void finalize() throws Throwable {          try { -            // Create the enclosing directory. -            File parent = f.getParentFile(); -            parent.mkdirs(); +            dtor(mPtr); +        } finally { +            super.finalize(); +        } +    } -            // Copy the file. -            int sum = 0; -            out = new FileOutputStream(f); -            byte[] buf = mBuf; -            int amt; -            while ((amt = in.read(buf)) > 0) { -                out.write(buf, 0, amt); -                sum += amt; -            } +    void writeFile(File f, InputStream in) { +        if (!(in instanceof BackupDataInputStream)) { +            throw new IllegalStateException("input stream must be a BackupDataInputStream"); +        } +        int result = -1; -            // TODO: Set the permissions of the file. +        // Create the enclosing directory. +        File parent = f.getParentFile(); +        parent.mkdirs(); -            // We're done -            success = true; -            out = null; -        } catch (IOException ex) { -            // Bail on this entity.  Only log one exception per helper object. +        result = writeFile_native(mPtr, f.getAbsolutePath(), +                ((BackupDataInputStream)in).mData.mBackupReader); +        if (result != 0) { +            // Bail on this entity.  Only log one failure per helper object.              if (!mExceptionLogged) {                  Log.e(TAG, "Failed restoring file '" + f + "' for app '" -                    + mContext.getPackageName() + '\'', ex); +                        + mContext.getPackageName() + "\' result=0x" +                        + Integer.toHexString(result));                  mExceptionLogged = true;              }          } -        finally { -            if (out != null) { -                try { -                    out.close(); -                } catch (IOException ex) { -                } -            } -            if (!success) { -                // Something didn't work out, delete the file -                f.delete(); -            } -        }      } + +    public void writeSnapshot(ParcelFileDescriptor fd) { +        int result = writeSnapshot_native(mPtr, fd.getFileDescriptor()); +        // TODO: Do something with the error. +    } + +    private static native int ctor(); +    private static native void dtor(int ptr); +    private static native int writeFile_native(int ptr, String filename, int backupReader); +    private static native int writeSnapshot_native(int ptr, FileDescriptor fd);  } diff --git a/core/java/android/backup/RestoreHelperDispatcher.java b/core/java/android/backup/RestoreHelperDispatcher.java index 5928914..4861775 100644 --- a/core/java/android/backup/RestoreHelperDispatcher.java +++ b/core/java/android/backup/RestoreHelperDispatcher.java @@ -16,10 +16,12 @@  package android.backup; +import android.os.ParcelFileDescriptor;  import android.util.Log;  import java.io.IOException;  import java.util.HashMap; +import java.util.Map;  /** @hide */  public class RestoreHelperDispatcher { @@ -31,7 +33,7 @@ public class RestoreHelperDispatcher {          mHelpers.put(keyPrefix, helper);      } -    public void dispatch(BackupDataInput input) throws IOException { +    public void dispatch(BackupDataInput input, ParcelFileDescriptor newState) throws IOException {          boolean alreadyComplained = false;          BackupDataInputStream stream = new BackupDataInputStream(input); @@ -60,5 +62,17 @@ public class RestoreHelperDispatcher {              }              input.skipEntityData(); // In case they didn't consume the data.          } + +        if (mHelpers.size() > 1) { +            throw new RuntimeException("RestoreHelperDispatcher won't get your your" +                    + " data in the right order yet."); +        } +         +        // Write out the state files +        for (RestoreHelper helper: mHelpers.values()) { +            // TODO: Write a header for the state +            helper.writeSnapshot(newState); +        }      }  } + diff --git a/core/jni/Android.mk b/core/jni/Android.mk index fee8396..faa04f7 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -119,7 +119,8 @@ LOCAL_SRC_FILES:= \  	com_android_internal_graphics_NativeUtils.cpp \  	android_backup_BackupDataInput.cpp \  	android_backup_BackupDataOutput.cpp \ -	android_backup_FileBackupHelper.cpp +	android_backup_FileBackupHelper.cpp \ +	android_backup_RestoreHelperBase.cpp  LOCAL_C_INCLUDES += \  	$(JNI_H_INCLUDE) \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 6d829fc..18f6d5f9 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -158,6 +158,7 @@ extern int register_android_location_GpsLocationProvider(JNIEnv* env);  extern int register_android_backup_BackupDataInput(JNIEnv *env);  extern int register_android_backup_BackupDataOutput(JNIEnv *env);  extern int register_android_backup_FileBackupHelper(JNIEnv *env); +extern int register_android_backup_RestoreHelperBase(JNIEnv *env);  static AndroidRuntime* gCurRuntime = NULL; @@ -1131,6 +1132,7 @@ static const RegJNIRec gRegJNI[] = {      REG_JNI(register_android_backup_BackupDataInput),      REG_JNI(register_android_backup_BackupDataOutput),      REG_JNI(register_android_backup_FileBackupHelper), +    REG_JNI(register_android_backup_RestoreHelperBase),  };  /* diff --git a/core/jni/android_backup_RestoreHelperBase.cpp b/core/jni/android_backup_RestoreHelperBase.cpp new file mode 100644 index 0000000..3173420 --- /dev/null +++ b/core/jni/android_backup_RestoreHelperBase.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "FileBackupHelper_native" +#include <utils/Log.h> + +#include "JNIHelp.h" +#include <android_runtime/AndroidRuntime.h> + +#include <utils/BackupHelpers.h> + +namespace android +{ + +// java.io.FileDescriptor +static jfieldID s_descriptorField = 0; + +static int +ctor(JNIEnv* env, jobject clazz) +{ +    return (int)new RestoreHelperBase(); +} + +static void +dtor(JNIEnv* env, jobject clazz, jint ptr) +{ +    delete (RestoreHelperBase*)ptr; +} + +static int +writeFile_native(JNIEnv* env, jobject clazz, jint ptr, jstring filenameObj, int backupReaderPtr) +{ +    int err; +    RestoreHelperBase* restore = (RestoreHelperBase*)ptr; +    BackupDataReader* reader = (BackupDataReader*)backupReaderPtr; +    char const* filename; + +    filename = env->GetStringUTFChars(filenameObj, NULL); + +    err = restore->WriteFile(String8(filename), reader); + +    env->ReleaseStringUTFChars(filenameObj, filename); + +    return err; +} + +static int +writeSnapshot_native(JNIEnv* env, jobject clazz, jint ptr, jobject fileDescriptor) +{ +    int err; + +    RestoreHelperBase* restore = (RestoreHelperBase*)ptr; +    int fd = env->GetIntField(fileDescriptor, s_descriptorField); + +    err = restore->WriteSnapshot(fd); + +    return err; +} + +static const JNINativeMethod g_methods[] = { +    { "ctor", "()I", (void*)ctor }, +    { "dtor", "(I)V", (void*)dtor }, +    { "writeFile_native", "(ILjava/lang/String;I)I", (void*)writeFile_native }, +    { "writeSnapshot_native", "(ILjava/io/FileDescriptor;)I", (void*)writeSnapshot_native }, +}; + +int register_android_backup_RestoreHelperBase(JNIEnv* env) +{ +    jclass clazz; + +    clazz = env->FindClass("java/io/FileDescriptor"); +    LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor"); +    s_descriptorField = env->GetFieldID(clazz, "descriptor", "I"); +    LOG_FATAL_IF(s_descriptorField == NULL, +            "Unable to find descriptor field in java.io.FileDescriptor"); +     +    return AndroidRuntime::registerNativeMethods(env, "android/backup/RestoreHelperBase", +            g_methods, NELEM(g_methods)); +} + +} diff --git a/include/utils/BackupHelpers.h b/include/utils/BackupHelpers.h index fa7f8d5..fc701fd 100644 --- a/include/utils/BackupHelpers.h +++ b/include/utils/BackupHelpers.h @@ -19,6 +19,7 @@  #include <utils/Errors.h>  #include <utils/String8.h> +#include <utils/KeyedVector.h>  namespace android { @@ -32,6 +33,27 @@ typedef struct {      int dataSize; // size of the data, not including the padding, -1 means delete  } entity_header_v1; +struct SnapshotHeader { +    int magic0; +    int fileCount; +    int magic1; +    int totalSize; +}; + +struct FileState { +    int modTime_sec; +    int modTime_nsec; +    int size; +    int crc32; +    int nameLen; +}; + +struct FileRec { +    String8 file; +    bool deleted; +    FileState s; +}; +  /**   * Writes the data. @@ -99,6 +121,19 @@ private:  int back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,          char const* const* files, char const* const *keys, int fileCount); +class RestoreHelperBase +{ +public: +    RestoreHelperBase(); +    ~RestoreHelperBase(); + +    status_t WriteFile(const String8& filename, BackupDataReader* in); +    status_t WriteSnapshot(int fd); + +private: +    void* m_buf; +    KeyedVector<String8,FileRec> m_files; +};  #define TEST_BACKUP_HELPERS 1 diff --git a/libs/utils/BackupHelpers.cpp b/libs/utils/BackupHelpers.cpp index c1d5404..99687bc 100644 --- a/libs/utils/BackupHelpers.cpp +++ b/libs/utils/BackupHelpers.cpp @@ -47,27 +47,6 @@ namespace android {  #define LOGP(x...) LOGD(x)  #endif -struct SnapshotHeader { -    int magic0; -    int fileCount; -    int magic1; -    int totalSize; -}; - -struct FileState { -    int modTime_sec; -    int modTime_nsec; -    int size; -    int crc32; -    int nameLen; -}; - -struct FileRec { -    char const* file; // this object does not own this string -    bool deleted; -    FileState s; -}; -  const static int ROUND_UP[4] = { 0, 3, 2, 1 };  static inline int @@ -310,7 +289,8 @@ back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD      for (int i=0; i<fileCount; i++) {          String8 key(keys[i]);          FileRec r; -        char const* file = r.file = files[i]; +        char const* file = files[i]; +        r.file = file;          struct stat st;          err = stat(file, &st); @@ -351,20 +331,20 @@ back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD          }          else if (cmp > 0) {              // file added -            LOGP("file added: %s", g.file); -            write_update_file(dataStream, q, g.file); +            LOGP("file added: %s", g.file.string()); +            write_update_file(dataStream, q, g.file.string());              m++;          }          else {              // both files exist, check them              const FileState& f = oldSnapshot.valueAt(n); -            int fd = open(g.file, O_RDONLY); +            int fd = open(g.file.string(), O_RDONLY);              if (fd < 0) {                  // We can't open the file.  Don't report it as a delete either.  Let the                  // server keep the old version.  Maybe they'll be able to deal with it                  // on restore. -                LOGP("Unable to open file %s - skipping", g.file); +                LOGP("Unable to open file %s - skipping", g.file.string());              } else {                  g.s.crc32 = compute_crc32(fd); @@ -375,7 +355,7 @@ back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD                          g.s.modTime_sec, g.s.modTime_nsec, g.s.size, g.s.crc32);                  if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec                          || f.size != g.s.size || f.crc32 != g.s.crc32) { -                    write_update_file(dataStream, fd, p, g.file); +                    write_update_file(dataStream, fd, p, g.file.string());                  }                  close(fd); @@ -395,7 +375,7 @@ back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD      while (m<fileCount) {          const String8& q = newSnapshot.keyAt(m);          FileRec& g = newSnapshot.editValueAt(m); -        write_update_file(dataStream, q, g.file); +        write_update_file(dataStream, q, g.file.string());          m++;      } @@ -404,6 +384,84 @@ back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD      return 0;  } +#define RESTORE_BUF_SIZE (8*1024) + +RestoreHelperBase::RestoreHelperBase() +{ +    m_buf = malloc(RESTORE_BUF_SIZE); +} + +RestoreHelperBase::~RestoreHelperBase() +{ +    free(m_buf); +} + +status_t +RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in) +{ +    ssize_t err; +    size_t dataSize; +    String8 key; +    int fd; +    void* buf = m_buf; +    ssize_t amt; +    int mode; +    int crc; +    struct stat st; +    FileRec r; + +    err = in->ReadEntityHeader(&key, &dataSize); +    if (err != NO_ERROR) { +        return err; +    } +     +    // TODO: World readable/writable for now. +    mode = 0666; + +    // Write the file and compute the crc +    crc = crc32(0L, Z_NULL, 0); +    fd = open(filename.string(), O_CREAT|O_RDWR, mode); +    if (fd != -1) { +        return errno; +    } +     +    while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) { +        err = write(fd, buf, amt); +        if (err != amt) { +            close(fd); +            return errno; +        } +        crc = crc32(crc, (Bytef*)buf, amt); +    } + +    close(fd); + +    // Record for the snapshot +    err = stat(filename.string(), &st); +    if (err != 0) { +        LOGW("Error stating file that we just created %s", filename.string()); +        return errno; +    } + +    r.file = filename; +    r.deleted = false; +    r.s.modTime_sec = st.st_mtime; +    r.s.modTime_nsec = 0; // workaround sim breakage +    //r.s.modTime_nsec = st.st_mtime_nsec; +    r.s.size = st.st_size; +    r.s.crc32 = crc; + +    m_files.add(key, r); + +    return NO_ERROR; +} + +status_t +RestoreHelperBase::WriteSnapshot(int fd) +{ +    return write_snapshot_file(fd, m_files);; +} +  #if TEST_BACKUP_HELPERS  #define SCRATCH_DIR "/data/backup_helper_test/" @@ -560,7 +618,6 @@ backup_helper_test_four()      FileState states[4];      FileRec r;      r.deleted = false; -    r.file = NULL;      states[0].modTime_sec = 0xfedcba98;      states[0].modTime_nsec = 0xdeadbeef; diff --git a/tests/backup/src/com/android/backuptest/BackupTestActivity.java b/tests/backup/src/com/android/backuptest/BackupTestActivity.java index d87e85c..f0c3f93 100644 --- a/tests/backup/src/com/android/backuptest/BackupTestActivity.java +++ b/tests/backup/src/com/android/backuptest/BackupTestActivity.java @@ -161,8 +161,13 @@ public class BackupTestActivity extends ListActivity                              new FileRestoreHelper(BackupTestActivity.this));                      FileInputStream dataFile = openFileInput("backup_test");                      BackupDataInput data = new BackupDataInput(dataFile.getFD()); -                    dispatch.dispatch(data); +                    ParcelFileDescriptor state = ParcelFileDescriptor.open( +                            new File(getFilesDir(), "restore_state"), +                            ParcelFileDescriptor.MODE_READ_WRITE|ParcelFileDescriptor.MODE_CREATE| +                            ParcelFileDescriptor.MODE_TRUNCATE); +                    dispatch.dispatch(data, state);                      dataFile.close(); +                    state.close();                  } catch (IOException ex) {                      throw new RuntimeException(ex);                  } diff --git a/tests/backup/src/com/android/backuptest/BackupTestAgent.java b/tests/backup/src/com/android/backuptest/BackupTestAgent.java index e3566ec..0da4151 100644 --- a/tests/backup/src/com/android/backuptest/BackupTestAgent.java +++ b/tests/backup/src/com/android/backuptest/BackupTestAgent.java @@ -55,7 +55,7 @@ public class BackupTestAgent extends BackupAgent          // dispatch.addHelper(SHARED_PREFS, new SharedPrefsRestoreHelper(this));          dispatch.addHelper(DATA_FILES, new FileRestoreHelper(this)); -        dispatch.dispatch(data); +        dispatch.dispatch(data, newState);      }  } | 
