1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.backup; 18 19import android.content.Context; 20import android.os.ParcelFileDescriptor; 21import android.util.Log; 22 23import java.io.InputStream; 24import java.io.File; 25import java.io.FileDescriptor; 26import java.io.FileOutputStream; 27 28class FileBackupHelperBase { 29 private static final String TAG = "RestoreHelperBase"; 30 31 int mPtr; 32 Context mContext; 33 boolean mExceptionLogged; 34 35 FileBackupHelperBase(Context context) { 36 mPtr = ctor(); 37 mContext = context; 38 } 39 40 protected void finalize() throws Throwable { 41 try { 42 dtor(mPtr); 43 } finally { 44 super.finalize(); 45 } 46 } 47 48 /** 49 * Check the parameters so the native code doens't have to throw all the exceptions 50 * since it's easier to do that from java. 51 */ 52 static void performBackup_checked(ParcelFileDescriptor oldState, BackupDataOutput data, 53 ParcelFileDescriptor newState, String[] files, String[] keys) { 54 if (files.length == 0) { 55 return; 56 } 57 // files must be all absolute paths 58 for (String f: files) { 59 if (f.charAt(0) != '/') { 60 throw new RuntimeException("files must have all absolute paths: " + f); 61 } 62 } 63 // the length of files and keys must be the same 64 if (files.length != keys.length) { 65 throw new RuntimeException("files.length=" + files.length 66 + " keys.length=" + keys.length); 67 } 68 // oldStateFd can be null 69 FileDescriptor oldStateFd = oldState != null ? oldState.getFileDescriptor() : null; 70 FileDescriptor newStateFd = newState.getFileDescriptor(); 71 if (newStateFd == null) { 72 throw new NullPointerException(); 73 } 74 75 int err = performBackup_native(oldStateFd, data.mBackupWriter, newStateFd, files, keys); 76 77 if (err != 0) { 78 // TODO: more here 79 throw new RuntimeException("Backup failed 0x" + Integer.toHexString(err)); 80 } 81 } 82 83 void writeFile(File f, InputStream in) { 84 if (!(in instanceof BackupDataInputStream)) { 85 throw new IllegalStateException("input stream must be a BackupDataInputStream"); 86 } 87 int result = -1; 88 89 // Create the enclosing directory. 90 File parent = f.getParentFile(); 91 parent.mkdirs(); 92 93 result = writeFile_native(mPtr, f.getAbsolutePath(), 94 ((BackupDataInputStream)in).mData.mBackupReader); 95 if (result != 0) { 96 // Bail on this entity. Only log one failure per helper object. 97 if (!mExceptionLogged) { 98 Log.e(TAG, "Failed restoring file '" + f + "' for app '" 99 + mContext.getPackageName() + "\' result=0x" 100 + Integer.toHexString(result)); 101 mExceptionLogged = true; 102 } 103 } 104 } 105 106 public void writeRestoreSnapshot(ParcelFileDescriptor fd) { 107 int result = writeSnapshot_native(mPtr, fd.getFileDescriptor()); 108 // TODO: Do something with the error. 109 } 110 111 boolean isKeyInList(String key, String[] list) { 112 for (String s: list) { 113 if (s.equals(key)) { 114 return true; 115 } 116 } 117 return false; 118 } 119 120 private static native int ctor(); 121 private static native void dtor(int ptr); 122 123 native private static int performBackup_native(FileDescriptor oldState, 124 int data, FileDescriptor newState, String[] files, String[] keys); 125 126 private static native int writeFile_native(int ptr, String filename, int backupReader); 127 private static native int writeSnapshot_native(int ptr, FileDescriptor fd); 128} 129 130 131