summaryrefslogtreecommitdiffstats
path: root/core/jni/android_app_backup_FullBackup.cpp
diff options
context:
space:
mode:
authorChristopher Tate <ctate@google.com>2015-03-24 18:48:10 -0700
committerChristopher Tate <ctate@google.com>2015-03-26 18:57:36 -0700
commit11ae768cf1b8348e761ad9c09e98788da1e591b1 (patch)
treefa4a4e9fffc83e61af98476d41df4252e3cd1323 /core/jni/android_app_backup_FullBackup.cpp
parente7f931c4505a6bd62e01bef5193dd724571a672b (diff)
downloadframeworks_base-11ae768cf1b8348e761ad9c09e98788da1e591b1.zip
frameworks_base-11ae768cf1b8348e761ad9c09e98788da1e591b1.tar.gz
frameworks_base-11ae768cf1b8348e761ad9c09e98788da1e591b1.tar.bz2
Add payload-size preflight stage to full transport backup
We now peform a total-size preflight pass before committing data to the wire. This is to eliminate the large superfluous network traffic that would otherwise happen if the transport enforces internal quotas: we now instead ask the transport up front whether it's prepared to accept a given payload size for the package. From the app's perspective this preflight operation is indistinguishable from a full-data backup pass. If the app has provided its own full-data handling in a subclassed backup agent, their usual file-providing code path will be executed. However, the files named for backup during this pass are not opened and read; just measured for their total size. As far as component lifecycles, this measurement pass is simply another call to the agent, immediately after it is bound, with identical timeout semantics to the existing full-data backup invocation. Once the app's file set has been measured the preflight operation invokes a new method on BackupTransport, called checkFullBackupSize(). This method is called after performFullBackup() (which applies any overall whitelist/blacklist policy) but before any data is delivered to the transport via sendBackupData(). The return code from checkFullBackupSize() is similar to the other transport methods: TRANSPORT_OK to permit the full backup to proceed; or TRANSPORT_REJECT_PACKAGE to indicate that the requested payload is unacceptable; or TRANSPORT_ERROR to report a more serious overall transport-level problem that prevents a full-data backup operation from occurring right now. The estimated payload currently does not include the size of the source-package metadata (technically, the manifest entry in its archive payload) or the size of any widget metadata associated with the package's install. In practice this means the preflighted size underestimates by 3 to 5 KB. In addition, the preflight API currently cannot distinguish between payload sizes larger than 2 gigabytes; any payload estimate larger than that is passed as Integer.MAX_VALUE to the checkFullBackupSize() query. Bug 19846750 Change-Id: I44498201e2d4b07482dcb3ca8fa6935dddc467ca
Diffstat (limited to 'core/jni/android_app_backup_FullBackup.cpp')
-rw-r--r--core/jni/android_app_backup_FullBackup.cpp42
1 files changed, 28 insertions, 14 deletions
diff --git a/core/jni/android_app_backup_FullBackup.cpp b/core/jni/android_app_backup_FullBackup.cpp
index 2c02b37..63b2e2a 100644
--- a/core/jni/android_app_backup_FullBackup.cpp
+++ b/core/jni/android_app_backup_FullBackup.cpp
@@ -15,6 +15,8 @@
*/
#define LOG_TAG "FullBackup_native"
+#include <sys/stat.h>
+
#include <utils/Log.h>
#include <utils/String8.h>
@@ -30,6 +32,12 @@
namespace android
{
+// android.app.backup.FullBackupDataOutput
+static struct {
+ jfieldID mData; // type android.app.backup.BackupDataOutput
+ jmethodID addSize;
+} sFullBackupDataOutput;
+
// android.app.backup.BackupDataOutput
static struct {
// This is actually a native pointer to the underlying BackupDataWriter instance
@@ -70,7 +78,7 @@ static struct {
* 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
+ * dataOutput: the FullBackupDataOutput object that we're saving into
*/
static jint backupToTar(JNIEnv* env, jobject clazz, jstring packageNameObj,
jstring domainObj, jstring linkdomain,
@@ -91,15 +99,11 @@ static jint backupToTar(JNIEnv* env, jobject clazz, jstring packageNameObj,
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;
- }
+ // Extract the data output fd. 'writer' ends up NULL in the measure-only case.
+ jobject bdo = env->GetObjectField(dataOutputObj, sFullBackupDataOutput.mData);
+ BackupDataWriter* writer = (bdo != NULL)
+ ? (BackupDataWriter*) env->GetLongField(bdo, sBackupDataOutput.mBackupWriter)
+ : NULL;
if (path.length() < rootpath.length()) {
ALOGE("file path [%s] shorter than root path [%s]",
@@ -107,20 +111,30 @@ static jint backupToTar(JNIEnv* env, jobject clazz, jstring packageNameObj,
return (jint) -1;
}
- return (jint) write_tarfile(packageName, domain, rootpath, path, writer);
+ off_t tarSize = 0;
+ jint err = write_tarfile(packageName, domain, rootpath, path, &tarSize, writer);
+ if (!err) {
+ //ALOGI("measured [%s] at %lld", path.string(), (long long) tarSize);
+ env->CallVoidMethod(dataOutputObj, sFullBackupDataOutput.addSize, (jlong) tarSize);
+ }
+
+ return err;
}
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",
+ "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/app/backup/FullBackupDataOutput;)I",
(void*)backupToTar },
};
int register_android_app_backup_FullBackup(JNIEnv* env)
{
- jclass clazz = FindClassOrDie(env, "android/app/backup/BackupDataOutput");
+ jclass fbdoClazz = FindClassOrDie(env, "android/app/backup/FullBackupDataOutput");
+ sFullBackupDataOutput.mData = GetFieldIDOrDie(env, fbdoClazz, "mData", "Landroid/app/backup/BackupDataOutput;");
+ sFullBackupDataOutput.addSize = GetMethodIDOrDie(env, fbdoClazz, "addSize", "(J)V");
- sBackupDataOutput.mBackupWriter = GetFieldIDOrDie(env, clazz, "mBackupWriter", "J");
+ jclass bdoClazz = FindClassOrDie(env, "android/app/backup/BackupDataOutput");
+ sBackupDataOutput.mBackupWriter = GetFieldIDOrDie(env, bdoClazz, "mBackupWriter", "J");
return RegisterMethodsOrDie(env, "android/app/backup/FullBackup", g_methods, NELEM(g_methods));
}