Christopher Tate | 4a627c7 | 2011-04-01 14:43:32 -0700 | [diff] [blame] | 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" |
Christopher Tate | 11ae768 | 2015-03-24 18:48:10 -0700 | [diff] [blame] | 18 | #include <sys/stat.h> |
| 19 | |
Christopher Tate | 4a627c7 | 2011-04-01 14:43:32 -0700 | [diff] [blame] | 20 | #include <utils/Log.h> |
| 21 | #include <utils/String8.h> |
| 22 | |
Steven Moreland | 2279b25 | 2017-07-19 09:50:45 -0700 | [diff] [blame] | 23 | #include <nativehelper/JNIHelp.h> |
Christopher Tate | 4a627c7 | 2011-04-01 14:43:32 -0700 | [diff] [blame] | 24 | #include <android_runtime/AndroidRuntime.h> |
| 25 | |
Mathias Agopian | b13b9bd | 2012-02-17 18:27:36 -0800 | [diff] [blame] | 26 | #include <androidfw/BackupHelpers.h> |
Christopher Tate | 4a627c7 | 2011-04-01 14:43:32 -0700 | [diff] [blame] | 27 | |
Andreas Gampe | 987f79f | 2014-11-18 17:29:46 -0800 | [diff] [blame] | 28 | #include "core_jni_helpers.h" |
| 29 | |
Christopher Tate | 4a627c7 | 2011-04-01 14:43:32 -0700 | [diff] [blame] | 30 | #include <string.h> |
| 31 | |
| 32 | namespace android |
| 33 | { |
| 34 | |
Christopher Tate | 11ae768 | 2015-03-24 18:48:10 -0700 | [diff] [blame] | 35 | // android.app.backup.FullBackupDataOutput |
| 36 | static struct { |
| 37 | jfieldID mData; // type android.app.backup.BackupDataOutput |
| 38 | jmethodID addSize; |
| 39 | } sFullBackupDataOutput; |
| 40 | |
Christopher Tate | 4a627c7 | 2011-04-01 14:43:32 -0700 | [diff] [blame] | 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 |
Christopher Tate | 11ae768 | 2015-03-24 18:48:10 -0700 | [diff] [blame] | 81 | * dataOutput: the FullBackupDataOutput object that we're saving into |
Christopher Tate | 4a627c7 | 2011-04-01 14:43:32 -0700 | [diff] [blame] | 82 | */ |
Ashok Bhat | 58b8b24 | 2014-01-02 16:52:41 +0000 | [diff] [blame] | 83 | static jint backupToTar(JNIEnv* env, jobject clazz, jstring packageNameObj, |
Christopher Tate | 4a627c7 | 2011-04-01 14:43:32 -0700 | [diff] [blame] | 84 | jstring domainObj, jstring linkdomain, |
| 85 | jstring rootpathObj, jstring pathObj, jobject dataOutputObj) { |
Christopher Tate | 4a627c7 | 2011-04-01 14:43:32 -0700 | [diff] [blame] | 86 | // Extract the various strings, allowing for null object pointers |
Christopher Tate | ca1605e | 2011-09-23 13:12:49 -0700 | [diff] [blame] | 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; |
Christopher Tate | 4a627c7 | 2011-04-01 14:43:32 -0700 | [diff] [blame] | 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 | |
Christopher Tate | 11ae768 | 2015-03-24 18:48:10 -0700 | [diff] [blame] | 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; |
Christopher Tate | 4a627c7 | 2011-04-01 14:43:32 -0700 | [diff] [blame] | 107 | |
| 108 | if (path.length() < rootpath.length()) { |
Steve Block | 3762c31 | 2012-01-06 19:20:56 +0000 | [diff] [blame] | 109 | ALOGE("file path [%s] shorter than root path [%s]", |
Christopher Tate | 4a627c7 | 2011-04-01 14:43:32 -0700 | [diff] [blame] | 110 | path.string(), rootpath.string()); |
Ashok Bhat | 58b8b24 | 2014-01-02 16:52:41 +0000 | [diff] [blame] | 111 | return (jint) -1; |
Christopher Tate | 4a627c7 | 2011-04-01 14:43:32 -0700 | [diff] [blame] | 112 | } |
| 113 | |
Christopher Tate | 11ae768 | 2015-03-24 18:48:10 -0700 | [diff] [blame] | 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; |
Christopher Tate | 4a627c7 | 2011-04-01 14:43:32 -0700 | [diff] [blame] | 122 | } |
| 123 | |
| 124 | static const JNINativeMethod g_methods[] = { |
| 125 | { "backupToTar", |
Christopher Tate | 11ae768 | 2015-03-24 18:48:10 -0700 | [diff] [blame] | 126 | "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/app/backup/FullBackupDataOutput;)I", |
Christopher Tate | 4a627c7 | 2011-04-01 14:43:32 -0700 | [diff] [blame] | 127 | (void*)backupToTar }, |
| 128 | }; |
| 129 | |
| 130 | int register_android_app_backup_FullBackup(JNIEnv* env) |
| 131 | { |
Christopher Tate | 11ae768 | 2015-03-24 18:48:10 -0700 | [diff] [blame] | 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"); |
Christopher Tate | 4a627c7 | 2011-04-01 14:43:32 -0700 | [diff] [blame] | 135 | |
Christopher Tate | 11ae768 | 2015-03-24 18:48:10 -0700 | [diff] [blame] | 136 | jclass bdoClazz = FindClassOrDie(env, "android/app/backup/BackupDataOutput"); |
| 137 | sBackupDataOutput.mBackupWriter = GetFieldIDOrDie(env, bdoClazz, "mBackupWriter", "J"); |
Christopher Tate | 4a627c7 | 2011-04-01 14:43:32 -0700 | [diff] [blame] | 138 | |
Andreas Gampe | 987f79f | 2014-11-18 17:29:46 -0800 | [diff] [blame] | 139 | return RegisterMethodsOrDie(env, "android/app/backup/FullBackup", g_methods, NELEM(g_methods)); |
Christopher Tate | 4a627c7 | 2011-04-01 14:43:32 -0700 | [diff] [blame] | 140 | } |
| 141 | |
| 142 | } |