android_backup_BackupHelperDispatcher.cpp revision 5baa3a62a97544669fba6d65a11c07f252e654dd
1cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber/* 2cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * Copyright (C) 2009 The Android Open Source Project 3cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * 4cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License"); 5cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * you may not use this file except in compliance with the License. 6cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * You may obtain a copy of the License at 7cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * 8cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * http://www.apache.org/licenses/LICENSE-2.0 9cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * 10cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * Unless required by applicable law or agreed to in writing, software 11cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS, 12cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * See the License for the specific language governing permissions and 14cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * limitations under the License. 15cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber */ 16cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber 17cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber#define LOG_TAG "BackupHelperDispatcher_native" 18cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber#include <utils/Log.h> 19cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber 20cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber#include "JNIHelp.h" 21cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber#include <android_runtime/AndroidRuntime.h> 22cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber 23cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber#include <sys/types.h> 24cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber#include <sys/uio.h> 25cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber#include <unistd.h> 26cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber 27cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber 28cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber#define VERSION_1_HEADER 0x01706c48 // 'Hlp'1 little endian 29cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber 30cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Hubernamespace android 31cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber{ 32cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber 33cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberstruct chunk_header_v1 { 34cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber int headerSize; 35cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber int version; 36cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber int dataSize; // corresponds to Header.chunkSize 37cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber int nameLength; // not including the NULL terminator, which is not written to the file 38cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber}; 39cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber 40cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberstatic jfieldID s_chunkSizeField = 0; 41cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberstatic jfieldID s_keyPrefixField = 0; 42cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber 43cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberstatic int 44cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas HuberreadHeader_native(JNIEnv* env, jobject clazz, jobject headerObj, jobject fdObj) 45cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber{ 46cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber chunk_header_v1 flattenedHeader; 47cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber ssize_t amt; 48cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber String8 keyPrefix; 49cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber char* buf; 50cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber 51cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber int fd = jniGetFDFromFileDescriptor(env, fdObj); 52cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber 53cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber amt = read(fd, &flattenedHeader.headerSize, sizeof(flattenedHeader.headerSize)); 54 if (amt != sizeof(flattenedHeader.headerSize)) { 55 return -1; 56 } 57 58 int remainingHeader = flattenedHeader.headerSize - sizeof(flattenedHeader.headerSize); 59 60 if (flattenedHeader.headerSize < (int)sizeof(chunk_header_v1)) { 61 LOGW("Skipping unknown header: %d bytes", flattenedHeader.headerSize); 62 if (remainingHeader > 0) { 63 lseek(fd, remainingHeader, SEEK_CUR); 64 // >0 means skip this chunk 65 return 1; 66 } 67 } 68 69 amt = read(fd, &flattenedHeader.version, 70 sizeof(chunk_header_v1)-sizeof(flattenedHeader.headerSize)); 71 if (amt <= 0) { 72 LOGW("Failed reading chunk header"); 73 return -1; 74 } 75 remainingHeader -= sizeof(chunk_header_v1)-sizeof(flattenedHeader.headerSize); 76 77 if (flattenedHeader.version != VERSION_1_HEADER) { 78 LOGW("Skipping unknown header version: 0x%08x, %d bytes", flattenedHeader.version, 79 flattenedHeader.headerSize); 80 if (remainingHeader > 0) { 81 lseek(fd, remainingHeader, SEEK_CUR); 82 // >0 means skip this chunk 83 return 1; 84 } 85 } 86 87#if 0 88 ALOGD("chunk header:"); 89 ALOGD(" headerSize=%d", flattenedHeader.headerSize); 90 ALOGD(" version=0x%08x", flattenedHeader.version); 91 ALOGD(" dataSize=%d", flattenedHeader.dataSize); 92 ALOGD(" nameLength=%d", flattenedHeader.nameLength); 93#endif 94 95 if (flattenedHeader.dataSize < 0 || flattenedHeader.nameLength < 0 || 96 remainingHeader < flattenedHeader.nameLength) { 97 LOGW("Malformed V1 header remainingHeader=%d dataSize=%d nameLength=%d", remainingHeader, 98 flattenedHeader.dataSize, flattenedHeader.nameLength); 99 return -1; 100 } 101 102 buf = keyPrefix.lockBuffer(flattenedHeader.nameLength); 103 if (buf == NULL) { 104 LOGW("unable to allocate %d bytes", flattenedHeader.nameLength); 105 return -1; 106 } 107 108 amt = read(fd, buf, flattenedHeader.nameLength); 109 buf[flattenedHeader.nameLength] = 0; 110 111 keyPrefix.unlockBuffer(flattenedHeader.nameLength); 112 113 remainingHeader -= flattenedHeader.nameLength; 114 115 if (remainingHeader > 0) { 116 lseek(fd, remainingHeader, SEEK_CUR); 117 } 118 119 env->SetIntField(headerObj, s_chunkSizeField, flattenedHeader.dataSize); 120 env->SetObjectField(headerObj, s_keyPrefixField, env->NewStringUTF(keyPrefix.string())); 121 122 return 0; 123} 124 125static int 126skipChunk_native(JNIEnv* env, jobject clazz, jobject fdObj, jint bytesToSkip) 127{ 128 int fd = jniGetFDFromFileDescriptor(env, fdObj); 129 130 lseek(fd, bytesToSkip, SEEK_CUR); 131 132 return 0; 133} 134 135static int 136padding_len(int len) 137{ 138 len = len % 4; 139 return len == 0 ? len : 4 - len; 140} 141 142static int 143allocateHeader_native(JNIEnv* env, jobject clazz, jobject headerObj, jobject fdObj) 144{ 145 int pos; 146 jstring nameObj; 147 int nameLength; 148 int namePadding; 149 int headerSize; 150 151 int fd = jniGetFDFromFileDescriptor(env, fdObj); 152 153 nameObj = (jstring)env->GetObjectField(headerObj, s_keyPrefixField); 154 155 nameLength = env->GetStringUTFLength(nameObj); 156 namePadding = padding_len(nameLength); 157 158 headerSize = sizeof(chunk_header_v1) + nameLength + namePadding; 159 160 pos = lseek(fd, 0, SEEK_CUR); 161 162 lseek(fd, headerSize, SEEK_CUR); 163 164 return pos; 165} 166 167static int 168writeHeader_native(JNIEnv* env, jobject clazz, jobject headerObj, jobject fdObj, jint pos) 169{ 170 int err; 171 chunk_header_v1 header; 172 int namePadding; 173 int prevPos; 174 jstring nameObj; 175 const char* buf; 176 177 int fd = jniGetFDFromFileDescriptor(env, fdObj); 178 prevPos = lseek(fd, 0, SEEK_CUR); 179 180 nameObj = (jstring)env->GetObjectField(headerObj, s_keyPrefixField); 181 header.nameLength = env->GetStringUTFLength(nameObj); 182 namePadding = padding_len(header.nameLength); 183 184 header.headerSize = sizeof(chunk_header_v1) + header.nameLength + namePadding; 185 header.version = VERSION_1_HEADER; 186 header.dataSize = prevPos - (pos + header.headerSize); 187 188 lseek(fd, pos, SEEK_SET); 189 err = write(fd, &header, sizeof(chunk_header_v1)); 190 if (err != sizeof(chunk_header_v1)) { 191 return errno; 192 } 193 194 buf = env->GetStringUTFChars(nameObj, NULL); 195 err = write(fd, buf, header.nameLength); 196 env->ReleaseStringUTFChars(nameObj, buf); 197 if (err != header.nameLength) { 198 return errno; 199 } 200 201 if (namePadding != 0) { 202 int zero = 0; 203 err = write(fd, &zero, namePadding); 204 if (err != namePadding) { 205 return errno; 206 } 207 } 208 209 lseek(fd, prevPos, SEEK_SET); 210 return 0; 211} 212 213static const JNINativeMethod g_methods[] = { 214 { "readHeader_native", 215 "(Landroid/app/backup/BackupHelperDispatcher$Header;Ljava/io/FileDescriptor;)I", 216 (void*)readHeader_native }, 217 { "skipChunk_native", 218 "(Ljava/io/FileDescriptor;I)I", 219 (void*)skipChunk_native }, 220 { "allocateHeader_native", 221 "(Landroid/app/backup/BackupHelperDispatcher$Header;Ljava/io/FileDescriptor;)I", 222 (void*)allocateHeader_native }, 223 { "writeHeader_native", 224 "(Landroid/app/backup/BackupHelperDispatcher$Header;Ljava/io/FileDescriptor;I)I", 225 (void*)writeHeader_native }, 226}; 227 228int register_android_backup_BackupHelperDispatcher(JNIEnv* env) 229{ 230 jclass clazz = env->FindClass("android/app/backup/BackupHelperDispatcher$Header"); 231 LOG_FATAL_IF(clazz == NULL, 232 "Unable to find class android.app.backup.BackupHelperDispatcher.Header"); 233 s_chunkSizeField = env->GetFieldID(clazz, "chunkSize", "I"); 234 LOG_FATAL_IF(s_chunkSizeField == NULL, 235 "Unable to find chunkSize field in android.app.backup.BackupHelperDispatcher.Header"); 236 s_keyPrefixField = env->GetFieldID(clazz, "keyPrefix", "Ljava/lang/String;"); 237 LOG_FATAL_IF(s_keyPrefixField == NULL, 238 "Unable to find keyPrefix field in android.app.backup.BackupHelperDispatcher.Header"); 239 240 return AndroidRuntime::registerNativeMethods(env, "android/app/backup/BackupHelperDispatcher", 241 g_methods, NELEM(g_methods)); 242} 243 244} 245