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