1 /* 2 * Copyright (C) 2011 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 17 #define LOG_TAG "FullBackup_native" 18 #include <sys/stat.h> 19 20 #include <utils/Log.h> 21 #include <utils/String8.h> 22 23 #include "JNIHelp.h" 24 #include <android_runtime/AndroidRuntime.h> 25 26 #include <androidfw/BackupHelpers.h> 27 28 #include "core_jni_helpers.h" 29 30 #include <string.h> 31 32 namespace android 33 { 34 35 // android.app.backup.FullBackupDataOutput 36 static struct { 37 jfieldID mData; // type android.app.backup.BackupDataOutput 38 jmethodID addSize; 39 } sFullBackupDataOutput; 40 41 // android.app.backup.BackupDataOutput 42 static struct { 43 // This is actually a native pointer to the underlying BackupDataWriter instance 44 jfieldID mBackupWriter; 45 } sBackupDataOutput; 46 47 /* 48 * Write files to the given output. This implementation does *not* create 49 * a standalone archive suitable for restore on its own. In particular, the identification of 50 * the application's name etc is not in-band here; it's assumed that the calling code has 51 * taken care of supplying that information previously in the output stream. 52 * 53 * The file format is 'tar's, with special semantics applied by use of a "fake" directory 54 * hierarchy within the tar stream: 55 * 56 * apps/packagename/a/Filename.apk - this is an actual application binary, which will be 57 * installed on the target device at restore time. These need to appear first in the tar 58 * stream. 59 * apps/packagename/obb/[relpath] - OBB containers belonging the app 60 * apps/packagename/r/[relpath] - these are files at the root of the app's data tree 61 * apps/packagename/f/[relpath] - this is a file within the app's getFilesDir() tree, stored 62 * at [relpath] relative to the top of that tree. 63 * apps/packagename/db/[relpath] - as with "files" but for the getDatabasePath() tree 64 * apps/packagename/sp/[relpath] - as with "files" but for the getSharedPrefsFile() tree 65 * apps/packagename/c/[relpath] - as with "files" but for the getCacheDir() tree 66 * 67 * and for the shared storage hierarchy: 68 * 69 * shared/[relpaths] - files belonging in the device's shared storage location. This will 70 * *not* include .obb files; those are saved with their owning apps. 71 * 72 * This method writes one file data block. 'domain' is the name of the appropriate pseudo- 73 * directory to be applied for this file; 'linkdomain' is the pseudo-dir for a relative 74 * symlink's antecedent. 75 * 76 * packagename: the package name to use as the top level directory tag 77 * domain: which semantic name the file is to be stored under (a, r, f, db, etc) 78 * linkdomain: where a symlink points for purposes of rewriting; current unused 79 * rootpath: prefix to be snipped from full path when encoding in tar 80 * path: absolute path to the file to be saved 81 * dataOutput: the FullBackupDataOutput object that we're saving into 82 */ 83 static jint backupToTar(JNIEnv* env, jobject clazz, jstring packageNameObj, 84 jstring domainObj, jstring linkdomain, 85 jstring rootpathObj, jstring pathObj, jobject dataOutputObj) { 86 // Extract the various strings, allowing for null object pointers 87 const char* packagenamechars = (packageNameObj) ? env->GetStringUTFChars(packageNameObj, NULL) : NULL; 88 const char* rootchars = (rootpathObj) ? env->GetStringUTFChars(rootpathObj, NULL) : NULL; 89 const char* pathchars = (pathObj) ? env->GetStringUTFChars(pathObj, NULL) : NULL; 90 const char* domainchars = (domainObj) ? env->GetStringUTFChars(domainObj, NULL) : NULL; 91 92 String8 packageName(packagenamechars ? packagenamechars : ""); 93 String8 rootpath(rootchars ? rootchars : ""); 94 String8 path(pathchars ? pathchars : ""); 95 String8 domain(domainchars ? domainchars : ""); 96 97 if (domainchars) env->ReleaseStringUTFChars(domainObj, domainchars); 98 if (pathchars) env->ReleaseStringUTFChars(pathObj, pathchars); 99 if (rootchars) env->ReleaseStringUTFChars(rootpathObj, rootchars); 100 if (packagenamechars) env->ReleaseStringUTFChars(packageNameObj, packagenamechars); 101 102 // Extract the data output fd. 'writer' ends up NULL in the measure-only case. 103 jobject bdo = env->GetObjectField(dataOutputObj, sFullBackupDataOutput.mData); 104 BackupDataWriter* writer = (bdo != NULL) 105 ? (BackupDataWriter*) env->GetLongField(bdo, sBackupDataOutput.mBackupWriter) 106 : NULL; 107 108 if (path.length() < rootpath.length()) { 109 ALOGE("file path [%s] shorter than root path [%s]", 110 path.string(), rootpath.string()); 111 return (jint) -1; 112 } 113 114 off_t tarSize = 0; 115 jint err = write_tarfile(packageName, domain, rootpath, path, &tarSize, writer); 116 if (!err) { 117 //ALOGI("measured [%s] at %lld", path.string(), (long long) tarSize); 118 env->CallVoidMethod(dataOutputObj, sFullBackupDataOutput.addSize, (jlong) tarSize); 119 } 120 121 return err; 122 } 123 124 static const JNINativeMethod g_methods[] = { 125 { "backupToTar", 126 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/app/backup/FullBackupDataOutput;)I", 127 (void*)backupToTar }, 128 }; 129 130 int register_android_app_backup_FullBackup(JNIEnv* env) 131 { 132 jclass fbdoClazz = FindClassOrDie(env, "android/app/backup/FullBackupDataOutput"); 133 sFullBackupDataOutput.mData = GetFieldIDOrDie(env, fbdoClazz, "mData", "Landroid/app/backup/BackupDataOutput;"); 134 sFullBackupDataOutput.addSize = GetMethodIDOrDie(env, fbdoClazz, "addSize", "(J)V"); 135 136 jclass bdoClazz = FindClassOrDie(env, "android/app/backup/BackupDataOutput"); 137 sBackupDataOutput.mBackupWriter = GetFieldIDOrDie(env, bdoClazz, "mBackupWriter", "J"); 138 139 return RegisterMethodsOrDie(env, "android/app/backup/FullBackup", g_methods, NELEM(g_methods)); 140 } 141 142 } 143