| /* |
| * Copyright (C) 2011 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 "FullBackup_native" |
| #include <utils/Log.h> |
| #include <utils/String8.h> |
| |
| #include "JNIHelp.h" |
| #include <android_runtime/AndroidRuntime.h> |
| |
| #include <androidfw/BackupHelpers.h> |
| |
| #include <string.h> |
| |
| namespace android |
| { |
| |
| // android.app.backup.BackupDataOutput |
| static struct { |
| // This is actually a native pointer to the underlying BackupDataWriter instance |
| jfieldID mBackupWriter; |
| } sBackupDataOutput; |
| |
| /* |
| * Write files to the given output. This implementation does *not* create |
| * a standalone archive suitable for restore on its own. In particular, the identification of |
| * the application's name etc is not in-band here; it's assumed that the calling code has |
| * taken care of supplying that information previously in the output stream. |
| * |
| * The file format is 'tar's, with special semantics applied by use of a "fake" directory |
| * hierarchy within the tar stream: |
| * |
| * apps/packagename/a/Filename.apk - this is an actual application binary, which will be |
| * installed on the target device at restore time. These need to appear first in the tar |
| * stream. |
| * apps/packagename/obb/[relpath] - OBB containers belonging the app |
| * apps/packagename/r/[relpath] - these are files at the root of the app's data tree |
| * apps/packagename/f/[relpath] - this is a file within the app's getFilesDir() tree, stored |
| * at [relpath] relative to the top of that tree. |
| * apps/packagename/db/[relpath] - as with "files" but for the getDatabasePath() tree |
| * apps/packagename/sp/[relpath] - as with "files" but for the getSharedPrefsFile() tree |
| * apps/packagename/c/[relpath] - as with "files" but for the getCacheDir() tree |
| * |
| * and for the shared storage hierarchy: |
| * |
| * shared/[relpaths] - files belonging in the device's shared storage location. This will |
| * *not* include .obb files; those are saved with their owning apps. |
| * |
| * This method writes one file data block. 'domain' is the name of the appropriate pseudo- |
| * directory to be applied for this file; 'linkdomain' is the pseudo-dir for a relative |
| * symlink's antecedent. |
| * |
| * packagename: the package name to use as the top level directory tag |
| * domain: which semantic name the file is to be stored under (a, r, f, db, etc) |
| * linkdomain: where a symlink points for purposes of rewriting; current unused |
| * rootpath: prefix to be snipped from full path when encoding in tar |
| * path: absolute path to the file to be saved |
| * dataOutput: the BackupDataOutput object that we're saving into |
| */ |
| static jint backupToTar(JNIEnv* env, jobject clazz, jstring packageNameObj, |
| jstring domainObj, jstring linkdomain, |
| jstring rootpathObj, jstring pathObj, jobject dataOutputObj) { |
| // Extract the various strings, allowing for null object pointers |
| const char* packagenamechars = (packageNameObj) ? env->GetStringUTFChars(packageNameObj, NULL) : NULL; |
| const char* rootchars = (rootpathObj) ? env->GetStringUTFChars(rootpathObj, NULL) : NULL; |
| const char* pathchars = (pathObj) ? env->GetStringUTFChars(pathObj, NULL) : NULL; |
| const char* domainchars = (domainObj) ? env->GetStringUTFChars(domainObj, NULL) : NULL; |
| |
| String8 packageName(packagenamechars ? packagenamechars : ""); |
| String8 rootpath(rootchars ? rootchars : ""); |
| String8 path(pathchars ? pathchars : ""); |
| String8 domain(domainchars ? domainchars : ""); |
| |
| if (domainchars) env->ReleaseStringUTFChars(domainObj, domainchars); |
| if (pathchars) env->ReleaseStringUTFChars(pathObj, pathchars); |
| if (rootchars) env->ReleaseStringUTFChars(rootpathObj, rootchars); |
| if (packagenamechars) env->ReleaseStringUTFChars(packageNameObj, packagenamechars); |
| |
| // Extract the data output fd |
| BackupDataWriter* writer = (BackupDataWriter*) env->GetLongField(dataOutputObj, |
| sBackupDataOutput.mBackupWriter); |
| |
| // Validate |
| if (!writer) { |
| ALOGE("No output stream provided [%s]", path.string()); |
| return (jint) -1; |
| } |
| |
| if (path.length() < rootpath.length()) { |
| ALOGE("file path [%s] shorter than root path [%s]", |
| path.string(), rootpath.string()); |
| return (jint) -1; |
| } |
| |
| return (jint) write_tarfile(packageName, domain, rootpath, path, writer); |
| } |
| |
| static const JNINativeMethod g_methods[] = { |
| { "backupToTar", |
| "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/app/backup/BackupDataOutput;)I", |
| (void*)backupToTar }, |
| }; |
| |
| int register_android_app_backup_FullBackup(JNIEnv* env) |
| { |
| jclass clazz = env->FindClass("android/app/backup/BackupDataOutput"); |
| LOG_FATAL_IF(clazz == NULL, "Unable to find class android.app.backup.BackupDataOutput"); |
| |
| sBackupDataOutput.mBackupWriter = env->GetFieldID(clazz, "mBackupWriter", "J"); |
| LOG_FATAL_IF(sBackupDataOutput.mBackupwriter == NULL, |
| "Unable to find mBackupWriter field in android.app.backup.BackupDataOutput"); |
| |
| return AndroidRuntime::registerNativeMethods(env, "android/app/backup/FullBackup", |
| g_methods, NELEM(g_methods)); |
| } |
| |
| } |