14a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate/* 24a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * Copyright (C) 2011 The Android Open Source Project 34a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * 44a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * Licensed under the Apache License, Version 2.0 (the "License"); 54a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * you may not use this file except in compliance with the License. 64a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * You may obtain a copy of the License at 74a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * 84a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * http://www.apache.org/licenses/LICENSE-2.0 94a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * 104a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * Unless required by applicable law or agreed to in writing, software 114a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * distributed under the License is distributed on an "AS IS" BASIS, 124a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * See the License for the specific language governing permissions and 144a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * limitations under the License. 154a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate */ 164a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate 174a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate#define LOG_TAG "FullBackup_native" 184a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate#include <utils/Log.h> 194a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate#include <utils/String8.h> 204a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate 214a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate#include "JNIHelp.h" 224a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate#include <android_runtime/AndroidRuntime.h> 234a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate 24b13b9bdad2baf6ad1ec2e56b6b7598fa20f55fc4Mathias Agopian#include <androidfw/BackupHelpers.h> 254a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate 264a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate#include <string.h> 274a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate 284a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tatenamespace android 294a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate{ 304a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate 314a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate// android.app.backup.BackupDataOutput 324a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tatestatic struct { 334a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate // This is actually a native pointer to the underlying BackupDataWriter instance 344a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate jfieldID mBackupWriter; 354a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate} sBackupDataOutput; 364a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate 374a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate/* 384a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * Write files to the given output. This implementation does *not* create 394a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * a standalone archive suitable for restore on its own. In particular, the identification of 404a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * the application's name etc is not in-band here; it's assumed that the calling code has 414a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * taken care of supplying that information previously in the output stream. 424a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * 434a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * The file format is 'tar's, with special semantics applied by use of a "fake" directory 444a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * hierarchy within the tar stream: 454a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * 464a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * apps/packagename/a/Filename.apk - this is an actual application binary, which will be 474a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * installed on the target device at restore time. These need to appear first in the tar 484a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * stream. 494a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * apps/packagename/obb/[relpath] - OBB containers belonging the app 504a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * apps/packagename/r/[relpath] - these are files at the root of the app's data tree 514a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * apps/packagename/f/[relpath] - this is a file within the app's getFilesDir() tree, stored 524a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * at [relpath] relative to the top of that tree. 534a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * apps/packagename/db/[relpath] - as with "files" but for the getDatabasePath() tree 544a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * apps/packagename/sp/[relpath] - as with "files" but for the getSharedPrefsFile() tree 554a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * apps/packagename/c/[relpath] - as with "files" but for the getCacheDir() tree 564a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * 574a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * and for the shared storage hierarchy: 584a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * 594a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * shared/[relpaths] - files belonging in the device's shared storage location. This will 604a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * *not* include .obb files; those are saved with their owning apps. 614a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * 624a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * This method writes one file data block. 'domain' is the name of the appropriate pseudo- 634a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * directory to be applied for this file; 'linkdomain' is the pseudo-dir for a relative 644a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * symlink's antecedent. 654a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * 664a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * packagename: the package name to use as the top level directory tag 674a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * domain: which semantic name the file is to be stored under (a, r, f, db, etc) 684a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * linkdomain: where a symlink points for purposes of rewriting; current unused 694a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * rootpath: prefix to be snipped from full path when encoding in tar 704a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * path: absolute path to the file to be saved 714a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * dataOutput: the BackupDataOutput object that we're saving into 724a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate */ 7358b8b24256bdc2b613b7fda9151845ed9898a4c7Ashok Bhatstatic jint backupToTar(JNIEnv* env, jobject clazz, jstring packageNameObj, 744a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate jstring domainObj, jstring linkdomain, 754a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate jstring rootpathObj, jstring pathObj, jobject dataOutputObj) { 76b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate int ret; 77b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate 784a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate // Extract the various strings, allowing for null object pointers 79ca1605e6e342a8e17859daf03bd23fdad1ad83a0Christopher Tate const char* packagenamechars = (packageNameObj) ? env->GetStringUTFChars(packageNameObj, NULL) : NULL; 80ca1605e6e342a8e17859daf03bd23fdad1ad83a0Christopher Tate const char* rootchars = (rootpathObj) ? env->GetStringUTFChars(rootpathObj, NULL) : NULL; 81ca1605e6e342a8e17859daf03bd23fdad1ad83a0Christopher Tate const char* pathchars = (pathObj) ? env->GetStringUTFChars(pathObj, NULL) : NULL; 82ca1605e6e342a8e17859daf03bd23fdad1ad83a0Christopher Tate const char* domainchars = (domainObj) ? env->GetStringUTFChars(domainObj, NULL) : NULL; 834a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate 844a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate String8 packageName(packagenamechars ? packagenamechars : ""); 854a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate String8 rootpath(rootchars ? rootchars : ""); 864a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate String8 path(pathchars ? pathchars : ""); 874a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate String8 domain(domainchars ? domainchars : ""); 884a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate 894a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate if (domainchars) env->ReleaseStringUTFChars(domainObj, domainchars); 904a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate if (pathchars) env->ReleaseStringUTFChars(pathObj, pathchars); 914a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate if (rootchars) env->ReleaseStringUTFChars(rootpathObj, rootchars); 924a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate if (packagenamechars) env->ReleaseStringUTFChars(packageNameObj, packagenamechars); 934a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate 944a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate // Extract the data output fd 9558b8b24256bdc2b613b7fda9151845ed9898a4c7Ashok Bhat BackupDataWriter* writer = (BackupDataWriter*) env->GetLongField(dataOutputObj, 964a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate sBackupDataOutput.mBackupWriter); 974a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate 984a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate // Validate 994a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate if (!writer) { 1003762c311729fe9f3af085c14c5c1fb471d994c03Steve Block ALOGE("No output stream provided [%s]", path.string()); 10158b8b24256bdc2b613b7fda9151845ed9898a4c7Ashok Bhat return (jint) -1; 1024a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate } 1034a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate 1044a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate if (path.length() < rootpath.length()) { 1053762c311729fe9f3af085c14c5c1fb471d994c03Steve Block ALOGE("file path [%s] shorter than root path [%s]", 1064a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate path.string(), rootpath.string()); 10758b8b24256bdc2b613b7fda9151845ed9898a4c7Ashok Bhat return (jint) -1; 1084a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate } 1094a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate 11058b8b24256bdc2b613b7fda9151845ed9898a4c7Ashok Bhat return (jint) write_tarfile(packageName, domain, rootpath, path, writer); 1114a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate} 1124a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate 1134a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tatestatic const JNINativeMethod g_methods[] = { 1144a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate { "backupToTar", 1154a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/app/backup/BackupDataOutput;)I", 1164a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate (void*)backupToTar }, 1174a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate}; 1184a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate 1194a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tateint register_android_app_backup_FullBackup(JNIEnv* env) 1204a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate{ 1214a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate jclass clazz = env->FindClass("android/app/backup/BackupDataOutput"); 1224a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate LOG_FATAL_IF(clazz == NULL, "Unable to find class android.app.backup.BackupDataOutput"); 1234a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate 12458b8b24256bdc2b613b7fda9151845ed9898a4c7Ashok Bhat sBackupDataOutput.mBackupWriter = env->GetFieldID(clazz, "mBackupWriter", "J"); 1254a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate LOG_FATAL_IF(sBackupDataOutput.mBackupwriter == NULL, 1264a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate "Unable to find mBackupWriter field in android.app.backup.BackupDataOutput"); 1274a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate 1284a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate return AndroidRuntime::registerNativeMethods(env, "android/app/backup/FullBackup", 1294a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate g_methods, NELEM(g_methods)); 1304a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate} 1314a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate 1324a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate} 133