summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Chris Wren <cwren@android.com> 2013-09-19 13:03:53 -0400
committer Chris Wren <cwren@android.com> 2013-09-25 19:33:21 +0000
commitfd5f566db84722f9cf54085d8a378e9398ef260d (patch)
tree99a1785b8ad569fde85245570ebb0f9e7fac8ad9
parent6885d577cbfe8dedcdb82fc066a4408ea762204f (diff)
add a test for BackupData helpers.
Bug: 10821481 Change-Id: I3e28123d36927ae4a22d26378b8bf1cd4e87cfd2
-rw-r--r--core/tests/coretests/Android.mk1
-rw-r--r--core/tests/coretests/assets/backup_mock.datbin0 -> 96 bytes
-rw-r--r--core/tests/coretests/assets/backup_mock.gld4
-rw-r--r--core/tests/coretests/assets/backup_real.datbin0 -> 248 bytes
-rw-r--r--core/tests/coretests/assets/backup_real.gld3
-rw-r--r--core/tests/coretests/src/android/app/backup/BackupDataTest.java291
-rw-r--r--libs/androidfw/tests/Android.mk1
-rw-r--r--libs/androidfw/tests/BackupData_test.cpp438
-rw-r--r--services/java/com/android/server/BackupManagerService.java1
9 files changed, 739 insertions, 0 deletions
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index be55444c63d6..73a53cb31b75 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -22,6 +22,7 @@ LOCAL_SRC_FILES := \
$(call all-java-files-under, EnabledTestApp/src)
LOCAL_DX_FLAGS := --core-library
+LOCAL_AAPT_FLAGS = -0 dat -0 gld
LOCAL_STATIC_JAVA_LIBRARIES := core-tests-support android-common frameworks-core-util-lib mockwebserver guava littlemock
LOCAL_JAVA_LIBRARIES := android.test.runner conscrypt telephony-common
LOCAL_PACKAGE_NAME := FrameworksCoreTests
diff --git a/core/tests/coretests/assets/backup_mock.dat b/core/tests/coretests/assets/backup_mock.dat
new file mode 100644
index 000000000000..f70b5735629e
--- /dev/null
+++ b/core/tests/coretests/assets/backup_mock.dat
Binary files differ
diff --git a/core/tests/coretests/assets/backup_mock.gld b/core/tests/coretests/assets/backup_mock.gld
new file mode 100644
index 000000000000..5197c2312c32
--- /dev/null
+++ b/core/tests/coretests/assets/backup_mock.gld
@@ -0,0 +1,4 @@
+key1:
+key2a:YWJjZGVmZw==
+key3bc:YWJjZGVmZ2g=
+key4dad:
diff --git a/core/tests/coretests/assets/backup_real.dat b/core/tests/coretests/assets/backup_real.dat
new file mode 100644
index 000000000000..22625685aaea
--- /dev/null
+++ b/core/tests/coretests/assets/backup_real.dat
Binary files differ
diff --git a/core/tests/coretests/assets/backup_real.gld b/core/tests/coretests/assets/backup_real.gld
new file mode 100644
index 000000000000..ef28f9bff4e2
--- /dev/null
+++ b/core/tests/coretests/assets/backup_real.gld
@@ -0,0 +1,3 @@
+CAEYLw:CC8QABoIR0VMIFN0dWIgnP//////////ASgBMAJAAUgBapgBI0ludGVudDthY3Rpb249YW5kcm9pZC5pbnRlbnQuYWN0aW9uLk1BSU47Y2F0ZWdvcnk9YW5kcm9pZC5pbnRlbnQuY2F0ZWdvcnkuTEFVTkNIRVI7bGF1bmNoRmxhZ3M9MHgxMDIwMDAwMDtjb21wb25lbnQ9Y29tLmdvb2dsZS5hbmRyb2lkLmdlbC8uU3R1YkFwcDtlbmQ=
+CAEYLQ:
+CAEYLA:
diff --git a/core/tests/coretests/src/android/app/backup/BackupDataTest.java b/core/tests/coretests/src/android/app/backup/BackupDataTest.java
new file mode 100644
index 000000000000..0c204e098405
--- /dev/null
+++ b/core/tests/coretests/src/android/app/backup/BackupDataTest.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.backup;
+
+import android.app.backup.BackupDataInput;
+import android.app.backup.BackupDataOutput;
+import android.content.res.AssetFileDescriptor;
+import android.content.res.AssetManager;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+import android.test.AndroidTestCase;
+import android.test.InstrumentationTestCase;
+import android.util.Base64;
+import android.util.Log;
+import org.json.JSONObject;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.Exception;
+import java.nio.ByteBuffer;
+
+public class BackupDataTest extends AndroidTestCase {
+ private static final String KEY1 = "key1";
+ private static final String KEY2 = "key2a";
+ private static final String KEY3 = "key3bc";
+ private static final String KEY4 = "key4dad"; // variable key lengths to test padding
+ private static final String[] KEYS = {KEY1, KEY2, KEY3, KEY4};
+
+ private static final String DATA1 = "abcdef";
+ private static final String DATA2 = "abcdefg";
+ private static final String DATA3 = "abcdefgh";
+ private static final String DATA4 = "abcdeffhi"; //variable data lengths to test padding
+ private static final String[] DATA = {DATA1, DATA2, DATA3, DATA4};
+ private static final String TAG = "BackupDataTest";
+
+ private File mFile;
+ private ParcelFileDescriptor mDataFile;
+ private File mDirectory;
+ private Bundle mStatusBundle;
+ private AssetManager mAssets;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mDirectory = new File(Environment.getExternalStorageDirectory(), "test_data");
+ mDirectory.mkdirs();
+ mAssets = mContext.getAssets();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ if (mDataFile != null) {
+ mDataFile.close();
+ }
+ }
+
+ public void testSingle() throws IOException {
+ mFile = new File(mDirectory, "backup_mixed_sinlge.dat");
+ openForWriting();
+ BackupDataOutput bdo = new BackupDataOutput(mDataFile.getFileDescriptor());
+
+ writeEntity(bdo, KEY1, DATA1.getBytes());
+
+ mDataFile.close();
+ openForReading();
+
+ BackupDataInput bdi = new BackupDataInput(mDataFile.getFileDescriptor());
+ int count = 0;
+ while (bdi.readNextHeader()) {
+ readAndVerifyEntity(bdi, KEY1, DATA1.getBytes());
+ count++;
+ }
+ assertEquals("only one entity in this stream", 1, count);
+ }
+
+ public void testMultiple() throws IOException {
+ mFile = new File(mDirectory, "backup_multiple_test.dat");
+ openForWriting();
+ BackupDataOutput bdo = new BackupDataOutput(mDataFile.getFileDescriptor());
+
+ for(int i = 0; i < KEYS.length; i++) {
+ writeEntity(bdo, KEYS[i], DATA[i].getBytes());
+ }
+
+ mDataFile.close();
+ openForReading();
+
+ BackupDataInput bdi = new BackupDataInput(mDataFile.getFileDescriptor());
+ int count = 0;
+ while (bdi.readNextHeader()) {
+ readAndVerifyEntity(bdi, KEYS[count], DATA[count].getBytes());
+ count++;
+ }
+ assertEquals("four entities in this stream", KEYS.length, count);
+ }
+
+ public void testDelete() throws IOException {
+ mFile = new File(mDirectory, "backup_delete_test.dat");
+ openForWriting();
+ BackupDataOutput bdo = new BackupDataOutput(mDataFile.getFileDescriptor());
+
+ for(int i = 0; i < KEYS.length; i++) {
+ deleteEntity(bdo, KEYS[i]);
+ }
+
+ mDataFile.close();
+ openForReading();
+
+ BackupDataInput bdi = new BackupDataInput(mDataFile.getFileDescriptor());
+ int count = 0;
+ while (bdi.readNextHeader()) {
+ readAndVerifyDeletedEntity(bdi, KEYS[count]);
+ count++;
+ }
+ assertEquals("four deletes in this stream", KEYS.length, count);
+ }
+
+ public void testMixed() throws IOException {
+ mFile = new File(mDirectory, "backup_mixed_test.dat");
+ openForWriting();
+
+ BackupDataOutput bdo = new BackupDataOutput(mDataFile.getFileDescriptor());
+
+ int i = 0;
+ deleteEntity(bdo, KEYS[i]); i++;
+ writeEntity(bdo, KEYS[i], DATA[i].getBytes()); i++;
+ writeEntity(bdo, KEYS[i], DATA[i].getBytes()); i++;
+ deleteEntity(bdo, KEYS[i]); i++;
+
+ mDataFile.close();
+ openForReading();
+
+ BackupDataInput bdi = new BackupDataInput(mDataFile.getFileDescriptor());
+ int out = 0;
+ assertTrue(bdi.readNextHeader());
+ readAndVerifyDeletedEntity(bdi, KEYS[out]); out++;
+ assertTrue(bdi.readNextHeader());
+ readAndVerifyEntity(bdi, KEYS[out], DATA[out].getBytes()); out++;
+ assertTrue(bdi.readNextHeader());
+ readAndVerifyEntity(bdi, KEYS[out], DATA[out].getBytes()); out++;
+ assertTrue(bdi.readNextHeader());
+ readAndVerifyDeletedEntity(bdi, KEYS[out]); out++;
+ assertFalse("four items in this stream",
+ bdi.readNextHeader());
+ }
+
+ public void testReadMockData() throws IOException {
+ copyAssetToFile("backup_mock.dat", "backup_read_mock_test.dat");
+
+ openForReading();
+ BackupDataInput bdi = new BackupDataInput(mDataFile.getFileDescriptor());
+ BufferedReader truth = new BufferedReader(new InputStreamReader(
+ mAssets.openFd("backup_mock.gld").createInputStream()));
+ while( bdi.readNextHeader()) {
+ String[] expected = truth.readLine().split(":");
+ byte[] expectedBytes = null;
+ if (expected.length > 1) {
+ expectedBytes = Base64.decode(expected[1], Base64.DEFAULT);
+ }
+ String key = bdi.getKey();
+ int dataSize = bdi.getDataSize();
+
+ assertEquals("wrong key", expected[0], key);
+ assertEquals("wrong length for key " + key,
+ (expectedBytes == null ? -1: expectedBytes.length), dataSize);
+ if (dataSize != -1) {
+ byte[] buffer = new byte[dataSize];
+ bdi.readEntityData(buffer, 0, dataSize);
+ assertEquals("wrong data for key " + key, expected[1],
+ Base64.encodeToString(buffer, 0, dataSize, Base64.NO_WRAP));
+ }
+ }
+ assertNull("there are unused entries in the golden file", truth.readLine());
+ }
+
+ public void testReadRealData() throws IOException {
+ copyAssetToFile("backup_real.dat", "backup_read_real_test.dat");
+
+ openForReading();
+ BackupDataInput bdi = new BackupDataInput(mDataFile.getFileDescriptor());
+ BufferedReader truth = new BufferedReader(new InputStreamReader(
+ mAssets.openFd("backup_real.gld").createInputStream()));
+
+ while(bdi.readNextHeader()) {
+ String[] expected = truth.readLine().split(":");
+ byte[] expectedBytes = null;
+ if (expected.length > 1) {
+ expectedBytes = Base64.decode(expected[1], Base64.DEFAULT);
+ }
+ String key = bdi.getKey();
+ int dataSize = bdi.getDataSize();
+
+ assertEquals("wrong key", expected[0], key);
+ assertEquals("wrong length for key " + key,
+ (expectedBytes == null ? -1: expectedBytes.length), dataSize);
+ if (dataSize != -1) {
+ byte[] buffer = new byte[dataSize];
+ bdi.readEntityData(buffer, 0, dataSize);
+ assertEquals("wrong data for key " + key, expected[1],
+ Base64.encodeToString(buffer, 0, dataSize, Base64.NO_WRAP));
+ }
+ }
+ assertNull("there are unused entries in the golden file", truth.readLine());
+ }
+
+ private void copyAssetToFile(String source, String destination) throws IOException {
+ mFile = new File(mDirectory, destination);
+ openForWriting();
+ FileInputStream fileInputStream = mAssets.openFd(source).createInputStream();
+ FileOutputStream fileOutputStream = new FileOutputStream(mDataFile.getFileDescriptor());
+ byte[] copybuffer = new byte[1024];
+ int numBytes = fileInputStream.read(copybuffer);
+ fileOutputStream.write(copybuffer, 0, numBytes);
+ fileOutputStream.close();
+ }
+
+ private void openForWriting() throws FileNotFoundException {
+ mDataFile = ParcelFileDescriptor.open(mFile,
+ ParcelFileDescriptor.MODE_WRITE_ONLY |
+ ParcelFileDescriptor.MODE_CREATE |
+ ParcelFileDescriptor.MODE_TRUNCATE); // Make an empty file if necessary
+ }
+
+ private void openForReading() throws FileNotFoundException {
+ mDataFile = ParcelFileDescriptor.open(mFile,
+ ParcelFileDescriptor.MODE_READ_ONLY |
+ ParcelFileDescriptor.MODE_CREATE); // Make an empty file if necessary
+ }
+
+ private void writeEntity(BackupDataOutput bdo, String key, byte[] data) throws IOException {
+ int status = bdo.writeEntityHeader(key, data.length);
+ // documentation says "number of bytes written" but that's not what we get:
+ assertEquals(0, status);
+
+ status = bdo.writeEntityData(data, data.length);
+ // documentation says "number of bytes written" but that's not what we get:
+ assertEquals(0, status);
+ }
+
+ private void deleteEntity(BackupDataOutput bdo, String key) throws IOException {
+ int status = bdo.writeEntityHeader(key, -1);
+ // documentation says "number of bytes written" but that's not what we get:
+ assertEquals(0, status);
+ }
+
+ private void readAndVerifyEntity(BackupDataInput bdi, String expectedKey, byte[] expectedData)
+ throws IOException {
+ assertEquals("Key mismatch",
+ expectedKey, bdi.getKey());
+ assertEquals("data size mismatch",
+ expectedData.length, bdi.getDataSize());
+ byte[] data = new byte[bdi.getDataSize()];
+ bdi.readEntityData(data, 0, bdi.getDataSize());
+ assertEquals("payload size is wrong",
+ expectedData.length, data.length);
+ for (int i = 0; i < data.length; i++) {
+ assertEquals("payload mismatch",
+ expectedData[i], data[i]);
+ }
+ }
+ private void readAndVerifyDeletedEntity(BackupDataInput bdi, String expectedKey)
+ throws IOException {
+ assertEquals("Key mismatch",
+ expectedKey, bdi.getKey());
+ assertEquals("deletion mis-reported",
+ -1, bdi.getDataSize());
+ }
+}
diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
index 05222128f3fc..c8e3f2bb16ee 100644
--- a/libs/androidfw/tests/Android.mk
+++ b/libs/androidfw/tests/Android.mk
@@ -4,6 +4,7 @@ include $(CLEAR_VARS)
# Build the unit tests.
test_src_files := \
+ BackupData_test.cpp \
ObbFile_test.cpp \
ZipFileRO_test.cpp
diff --git a/libs/androidfw/tests/BackupData_test.cpp b/libs/androidfw/tests/BackupData_test.cpp
new file mode 100644
index 000000000000..17f91ca9e4f0
--- /dev/null
+++ b/libs/androidfw/tests/BackupData_test.cpp
@@ -0,0 +1,438 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ObbFile_test"
+#include <androidfw/BackupHelpers.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include <gtest/gtest.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+
+namespace android {
+
+#define TEST_FILENAME "/test.bd"
+
+// keys of different lengths to test padding
+#define KEY1 "key1"
+#define KEY2 "key2a"
+#define KEY3 "key3bc"
+#define KEY4 "key4def"
+
+// payloads of different lengths to test padding
+#define DATA1 "abcdefg"
+#define DATA2 "hijklmnopq"
+#define DATA3 "rstuvwxyz"
+// KEY4 is only ever deleted
+
+class BackupDataTest : public testing::Test {
+protected:
+ char* m_external_storage;
+ char* m_filename;
+ String8 mKey1;
+ String8 mKey2;
+ String8 mKey3;
+ String8 mKey4;
+
+ virtual void SetUp() {
+ m_external_storage = getenv("EXTERNAL_STORAGE");
+
+ const int totalLen = strlen(m_external_storage) + strlen(TEST_FILENAME) + 1;
+ m_filename = new char[totalLen];
+ snprintf(m_filename, totalLen, "%s%s", m_external_storage, TEST_FILENAME);
+
+ ::unlink(m_filename);
+ int fd = ::open(m_filename, O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+ if (fd < 0) {
+ FAIL() << "Couldn't create " << m_filename << " for writing";
+ }
+ mKey1 = String8(KEY1);
+ mKey2 = String8(KEY2);
+ mKey3 = String8(KEY3);
+ mKey4 = String8(KEY4);
+ }
+
+ virtual void TearDown() {
+ }
+};
+
+TEST_F(BackupDataTest, WriteAndReadSingle) {
+ int fd = ::open(m_filename, O_WRONLY);
+ BackupDataWriter* writer = new BackupDataWriter(fd);
+
+ EXPECT_EQ(NO_ERROR, writer->WriteEntityHeader(mKey1, sizeof(DATA1)))
+ << "WriteEntityHeader returned an error";
+ EXPECT_EQ(NO_ERROR, writer->WriteEntityData(DATA1, sizeof(DATA1)))
+ << "WriteEntityData returned an error";
+
+ ::close(fd);
+ fd = ::open(m_filename, O_RDONLY);
+ BackupDataReader* reader = new BackupDataReader(fd);
+ EXPECT_EQ(NO_ERROR, reader->Status())
+ << "Reader ctor failed";
+
+ bool done;
+ int type;
+ reader->ReadNextHeader(&done, &type);
+ EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
+ << "wrong type from ReadNextHeader";
+
+ String8 key;
+ size_t dataSize;
+ EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
+ << "ReadEntityHeader returned an error";
+ EXPECT_EQ(mKey1, key)
+ << "wrong key from ReadEntityHeader";
+ EXPECT_EQ(sizeof(DATA1), dataSize)
+ << "wrong size from ReadEntityHeader";
+
+ char* dataBytes = new char[dataSize];
+ EXPECT_EQ((int) dataSize, reader->ReadEntityData(dataBytes, dataSize))
+ << "ReadEntityData returned an error";
+ for (unsigned int i = 0; i < sizeof(DATA1); i++) {
+ EXPECT_EQ(DATA1[i], dataBytes[i])
+ << "data character " << i << " should be equal";
+ }
+ delete dataBytes;
+ delete writer;
+ delete reader;
+}
+
+TEST_F(BackupDataTest, WriteAndReadMultiple) {
+ int fd = ::open(m_filename, O_WRONLY);
+ BackupDataWriter* writer = new BackupDataWriter(fd);
+ writer->WriteEntityHeader(mKey1, sizeof(DATA1));
+ writer->WriteEntityData(DATA1, sizeof(DATA1));
+ writer->WriteEntityHeader(mKey2, sizeof(DATA2));
+ writer->WriteEntityData(DATA2, sizeof(DATA2));
+
+ ::close(fd);
+ fd = ::open(m_filename, O_RDONLY);
+ BackupDataReader* reader = new BackupDataReader(fd);
+
+ bool done;
+ int type;
+ String8 key;
+ size_t dataSize;
+ char* dataBytes;
+ // read first entity
+ reader->ReadNextHeader(&done, &type);
+ reader->ReadEntityHeader(&key, &dataSize);
+ dataBytes = new char[dataSize];
+ reader->ReadEntityData(dataBytes, dataSize);
+ delete dataBytes;
+
+ // read and verify second entity
+ reader->ReadNextHeader(&done, &type);
+ EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
+ << "wrong type from ReadNextHeader";
+
+ EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
+ << "ReadEntityHeader returned an error on second entity";
+ EXPECT_EQ(mKey2, key)
+ << "wrong key from ReadEntityHeader on second entity";
+ EXPECT_EQ(sizeof(DATA2), dataSize)
+ << "wrong size from ReadEntityHeader on second entity";
+
+ dataBytes = new char[dataSize];
+ EXPECT_EQ((int)dataSize, reader->ReadEntityData(dataBytes, dataSize))
+ << "ReadEntityData returned an error on second entity";
+ for (unsigned int i = 0; i < sizeof(DATA2); i++) {
+ EXPECT_EQ(DATA2[i], dataBytes[i])
+ << "data character " << i << " should be equal";
+ }
+ delete dataBytes;
+ delete writer;
+ delete reader;
+}
+
+TEST_F(BackupDataTest, SkipEntity) {
+ int fd = ::open(m_filename, O_WRONLY);
+ BackupDataWriter* writer = new BackupDataWriter(fd);
+ writer->WriteEntityHeader(mKey1, sizeof(DATA1));
+ writer->WriteEntityData(DATA1, sizeof(DATA1));
+ writer->WriteEntityHeader(mKey2, sizeof(DATA2));
+ writer->WriteEntityData(DATA2, sizeof(DATA2));
+ writer->WriteEntityHeader(mKey3, sizeof(DATA3));
+ writer->WriteEntityData(DATA3, sizeof(DATA3));
+
+ ::close(fd);
+ fd = ::open(m_filename, O_RDONLY);
+ BackupDataReader* reader = new BackupDataReader(fd);
+
+ bool done;
+ int type;
+ String8 key;
+ size_t dataSize;
+ char* dataBytes;
+ // read first entity
+ reader->ReadNextHeader(&done, &type);
+ reader->ReadEntityHeader(&key, &dataSize);
+ dataBytes = new char[dataSize];
+ reader->ReadEntityData(dataBytes, dataSize);
+ delete dataBytes;
+
+ // skip second entity
+ reader->ReadNextHeader(&done, &type);
+ reader->ReadEntityHeader(&key, &dataSize);
+ reader->SkipEntityData();
+
+ // read and verify third entity
+ reader->ReadNextHeader(&done, &type);
+ EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
+ << "wrong type from ReadNextHeader after skip";
+
+ EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
+ << "ReadEntityHeader returned an error on third entity";
+ EXPECT_EQ(mKey3, key)
+ << "wrong key from ReadEntityHeader on third entity";
+ EXPECT_EQ(sizeof(DATA3), dataSize)
+ << "wrong size from ReadEntityHeader on third entity";
+
+ dataBytes = new char[dataSize];
+ EXPECT_EQ((int) dataSize, reader->ReadEntityData(dataBytes, dataSize))
+ << "ReadEntityData returned an error on third entity";
+ for (unsigned int i = 0; i < sizeof(DATA3); i++) {
+ EXPECT_EQ(DATA3[i], dataBytes[i])
+ << "data character " << i << " should be equal";
+ }
+ delete dataBytes;
+ delete writer;
+ delete reader;
+}
+
+TEST_F(BackupDataTest, DeleteEntity) {
+ int fd = ::open(m_filename, O_WRONLY);
+ BackupDataWriter* writer = new BackupDataWriter(fd);
+ writer->WriteEntityHeader(mKey1, sizeof(DATA1));
+ writer->WriteEntityData(DATA1, sizeof(DATA1));
+ writer->WriteEntityHeader(mKey2, -1);
+
+ ::close(fd);
+ fd = ::open(m_filename, O_RDONLY);
+ BackupDataReader* reader = new BackupDataReader(fd);
+
+ bool done;
+ int type;
+ String8 key;
+ size_t dataSize;
+ char* dataBytes;
+ // read first entity
+ reader->ReadNextHeader(&done, &type);
+ reader->ReadEntityHeader(&key, &dataSize);
+ dataBytes = new char[dataSize];
+ reader->ReadEntityData(dataBytes, dataSize);
+ delete dataBytes;
+
+ // read and verify deletion
+ reader->ReadNextHeader(&done, &type);
+ EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
+ << "wrong type from ReadNextHeader on deletion";
+
+ EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
+ << "ReadEntityHeader returned an error on second entity";
+ EXPECT_EQ(mKey2, key)
+ << "wrong key from ReadEntityHeader on second entity";
+ EXPECT_EQ(-1, (int) dataSize)
+ << "not recognizing deletion on second entity";
+
+ delete writer;
+ delete reader;
+}
+
+TEST_F(BackupDataTest, EneityAfterDelete) {
+ int fd = ::open(m_filename, O_WRONLY);
+ BackupDataWriter* writer = new BackupDataWriter(fd);
+ writer->WriteEntityHeader(mKey1, sizeof(DATA1));
+ writer->WriteEntityData(DATA1, sizeof(DATA1));
+ writer->WriteEntityHeader(mKey2, -1);
+ writer->WriteEntityHeader(mKey3, sizeof(DATA3));
+ writer->WriteEntityData(DATA3, sizeof(DATA3));
+
+ ::close(fd);
+ fd = ::open(m_filename, O_RDONLY);
+ BackupDataReader* reader = new BackupDataReader(fd);
+
+ bool done;
+ int type;
+ String8 key;
+ size_t dataSize;
+ char* dataBytes;
+ // read first entity
+ reader->ReadNextHeader(&done, &type);
+ reader->ReadEntityHeader(&key, &dataSize);
+ dataBytes = new char[dataSize];
+ reader->ReadEntityData(dataBytes, dataSize);
+ delete dataBytes;
+
+ // read and verify deletion
+ reader->ReadNextHeader(&done, &type);
+ EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
+ << "wrong type from ReadNextHeader on deletion";
+
+ EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
+ << "ReadEntityHeader returned an error on second entity";
+ EXPECT_EQ(mKey2, key)
+ << "wrong key from ReadEntityHeader on second entity";
+ EXPECT_EQ(-1, (int)dataSize)
+ << "not recognizing deletion on second entity";
+
+ // read and verify third entity
+ reader->ReadNextHeader(&done, &type);
+ EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
+ << "wrong type from ReadNextHeader after deletion";
+
+ EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
+ << "ReadEntityHeader returned an error on third entity";
+ EXPECT_EQ(mKey3, key)
+ << "wrong key from ReadEntityHeader on third entity";
+ EXPECT_EQ(sizeof(DATA3), dataSize)
+ << "wrong size from ReadEntityHeader on third entity";
+
+ dataBytes = new char[dataSize];
+ EXPECT_EQ((int) dataSize, reader->ReadEntityData(dataBytes, dataSize))
+ << "ReadEntityData returned an error on third entity";
+ for (unsigned int i = 0; i < sizeof(DATA3); i++) {
+ EXPECT_EQ(DATA3[i], dataBytes[i])
+ << "data character " << i << " should be equal";
+ }
+ delete dataBytes;
+ delete writer;
+ delete reader;
+}
+
+TEST_F(BackupDataTest, OnlyDeleteEntities) {
+ int fd = ::open(m_filename, O_WRONLY);
+ BackupDataWriter* writer = new BackupDataWriter(fd);
+ writer->WriteEntityHeader(mKey1, -1);
+ writer->WriteEntityHeader(mKey2, -1);
+ writer->WriteEntityHeader(mKey3, -1);
+ writer->WriteEntityHeader(mKey4, -1);
+
+ ::close(fd);
+ fd = ::open(m_filename, O_RDONLY);
+ BackupDataReader* reader = new BackupDataReader(fd);
+
+ bool done;
+ int type;
+ String8 key;
+ size_t dataSize;
+ // read and verify first deletion
+ reader->ReadNextHeader(&done, &type);
+ EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
+ << "wrong type from ReadNextHeader first deletion";
+
+ EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
+ << "ReadEntityHeader returned an error on first entity";
+ EXPECT_EQ(mKey1, key)
+ << "wrong key from ReadEntityHeader on first entity";
+ EXPECT_EQ(-1, (int) dataSize)
+ << "not recognizing deletion on first entity";
+
+ // read and verify second deletion
+ reader->ReadNextHeader(&done, &type);
+ EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
+ << "wrong type from ReadNextHeader second deletion";
+
+ EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
+ << "ReadEntityHeader returned an error on second entity";
+ EXPECT_EQ(mKey2, key)
+ << "wrong key from ReadEntityHeader on second entity";
+ EXPECT_EQ(-1, (int) dataSize)
+ << "not recognizing deletion on second entity";
+
+ // read and verify third deletion
+ reader->ReadNextHeader(&done, &type);
+ EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
+ << "wrong type from ReadNextHeader third deletion";
+
+ EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
+ << "ReadEntityHeader returned an error on third entity";
+ EXPECT_EQ(mKey3, key)
+ << "wrong key from ReadEntityHeader on third entity";
+ EXPECT_EQ(-1, (int) dataSize)
+ << "not recognizing deletion on third entity";
+
+ // read and verify fourth deletion
+ reader->ReadNextHeader(&done, &type);
+ EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
+ << "wrong type from ReadNextHeader fourth deletion";
+
+ EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
+ << "ReadEntityHeader returned an error on fourth entity";
+ EXPECT_EQ(mKey4, key)
+ << "wrong key from ReadEntityHeader on fourth entity";
+ EXPECT_EQ(-1, (int) dataSize)
+ << "not recognizing deletion on fourth entity";
+
+ delete writer;
+ delete reader;
+}
+
+TEST_F(BackupDataTest, ReadDeletedEntityData) {
+ int fd = ::open(m_filename, O_WRONLY);
+ BackupDataWriter* writer = new BackupDataWriter(fd);
+ writer->WriteEntityHeader(mKey1, -1);
+ writer->WriteEntityHeader(mKey2, -1);
+
+ ::close(fd);
+ fd = ::open(m_filename, O_RDONLY);
+ BackupDataReader* reader = new BackupDataReader(fd);
+
+ bool done;
+ int type;
+ String8 key;
+ size_t dataSize;
+ // read and verify first deletion
+ reader->ReadNextHeader(&done, &type);
+ EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
+ << "wrong type from ReadNextHeader first deletion";
+
+ EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
+ << "ReadEntityHeader returned an error on first entity";
+ EXPECT_EQ(mKey1, key)
+ << "wrong key from ReadEntityHeader on first entity";
+ EXPECT_EQ(-1, (int) dataSize)
+ << "not recognizing deletion on first entity";
+
+ // erroneously try to read first entity data
+ char* dataBytes = new char[10];
+ dataBytes[0] = 'A';
+ EXPECT_EQ(NO_ERROR, reader->ReadEntityData(dataBytes, dataSize));
+ // expect dataBytes to be unmodofied
+ EXPECT_EQ('A', dataBytes[0]);
+
+ // read and verify second deletion
+ reader->ReadNextHeader(&done, &type);
+ EXPECT_EQ(BACKUP_HEADER_ENTITY_V1, type)
+ << "wrong type from ReadNextHeader second deletion";
+
+ EXPECT_EQ(NO_ERROR, reader->ReadEntityHeader(&key, &dataSize))
+ << "ReadEntityHeader returned an error on second entity";
+ EXPECT_EQ(mKey2, key)
+ << "wrong key from ReadEntityHeader on second entity";
+ EXPECT_EQ(-1, (int) dataSize)
+ << "not recognizing deletion on second entity";
+
+ delete writer;
+ delete reader;
+}
+
+}
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index a04ee144da29..455d5e9d9f29 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -2117,6 +2117,7 @@ class BackupManagerService extends IBackupManager.Stub {
mSavedStateName = new File(mStateDir, packageName);
mBackupDataName = new File(mDataDir, packageName + ".data");
mNewStateName = new File(mStateDir, packageName + ".new");
+ if (MORE_DEBUG) Slog.d(TAG, "data file: " + mBackupDataName);
mSavedState = null;
mBackupData = null;