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