diff options
author | 2013-09-19 13:03:53 -0400 | |
---|---|---|
committer | 2013-09-25 19:33:21 +0000 | |
commit | fd5f566db84722f9cf54085d8a378e9398ef260d (patch) | |
tree | 99a1785b8ad569fde85245570ebb0f9e7fac8ad9 | |
parent | 6885d577cbfe8dedcdb82fc066a4408ea762204f (diff) |
add a test for BackupData helpers.
Bug: 10821481
Change-Id: I3e28123d36927ae4a22d26378b8bf1cd4e87cfd2
-rw-r--r-- | core/tests/coretests/Android.mk | 1 | ||||
-rw-r--r-- | core/tests/coretests/assets/backup_mock.dat | bin | 0 -> 96 bytes | |||
-rw-r--r-- | core/tests/coretests/assets/backup_mock.gld | 4 | ||||
-rw-r--r-- | core/tests/coretests/assets/backup_real.dat | bin | 0 -> 248 bytes | |||
-rw-r--r-- | core/tests/coretests/assets/backup_real.gld | 3 | ||||
-rw-r--r-- | core/tests/coretests/src/android/app/backup/BackupDataTest.java | 291 | ||||
-rw-r--r-- | libs/androidfw/tests/Android.mk | 1 | ||||
-rw-r--r-- | libs/androidfw/tests/BackupData_test.cpp | 438 | ||||
-rw-r--r-- | services/java/com/android/server/BackupManagerService.java | 1 |
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 Binary files differnew file mode 100644 index 000000000000..f70b5735629e --- /dev/null +++ b/core/tests/coretests/assets/backup_mock.dat 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 Binary files differnew file mode 100644 index 000000000000..22625685aaea --- /dev/null +++ b/core/tests/coretests/assets/backup_real.dat 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; |