CTS test for 'fullBackupOnly' manifest attribute

Uses 3 different versions of the same app that differ only by
'fullBackupOnly' value and the presence/absence of the backup agent.

Tests the following scenarios:

1. App that doesn't have fullBackupOnly (same as fullBackupOnly=false by
default) and has a backup agent will get key/value backup.
We check that key/value data was restored after reinstall and dolly data was not.

2. App that doesn't have fullBackupOnly (same as fullBackupOnly=false by
default) and has no backup agent will get Dolly backup.
We check that key/value data was not restored after reinstall and dolly data was.

3. App that has fullBackupOnly=true  and has a backup agent will only
get Dolly backup.
We check that key/value data was not restored after reinstall and dolly data was.

The flow of the tests is the following:
1. Install the app
2. Generate files in data folder of the app, including a file in
no_backup folder. The file in no_backup folder is used for key/value backup by
the backup agent of the app.
3. Run 'bmgr backupnow'. Depending on the manifest of the app we expect
either Dolly or Key/value backup to be performed.
4. Uninstall and reinstall the app.
5. Check that the correct files were restored depending on the manifest:
 - Files in the app's data folder for Dolly backup
 - Only file in no_backup folder for key/value.

Test: cts-tradefed run cts-dev -m CtsBackupHostTestCases -t android.cts.backup.FullBackupOnlyHostSideTest

Bug: 38108587

Change-Id: If29577a5209fc77cebebe23dc879c51ab4be5e65
diff --git a/hostsidetests/backup/FullBackupOnly/Android.mk b/hostsidetests/backup/FullBackupOnly/Android.mk
new file mode 100644
index 0000000..521ac4d
--- /dev/null
+++ b/hostsidetests/backup/FullBackupOnly/Android.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (C) 2017 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.
+#
+
+include $(call all-subdir-makefiles)
diff --git a/hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseNoAgentApp/Android.mk b/hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseNoAgentApp/Android.mk
new file mode 100644
index 0000000..5cce7a4
--- /dev/null
+++ b/hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseNoAgentApp/Android.mk
@@ -0,0 +1,39 @@
+# Copyright (C) 2017 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Don't include this package in any target
+LOCAL_MODULE_TAGS := tests
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
+LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
+
+# tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+LOCAL_PACKAGE_NAME := FullBackupOnlyFalseNoAgentApp
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
diff --git a/hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseNoAgentApp/AndroidManifest.xml b/hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseNoAgentApp/AndroidManifest.xml
new file mode 100644
index 0000000..c00671f
--- /dev/null
+++ b/hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseNoAgentApp/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 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
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.cts.backup.fullbackuponlyapp">
+
+    <application>
+
+        <uses-library android:name="android.test.runner" />
+
+    </application>
+
+    <instrumentation
+        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.cts.backup.fullbackuponlyapp" />
+
+</manifest>
diff --git a/hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseWithAgentApp/Android.mk b/hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseWithAgentApp/Android.mk
new file mode 100644
index 0000000..3224b98
--- /dev/null
+++ b/hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseWithAgentApp/Android.mk
@@ -0,0 +1,39 @@
+# Copyright (C) 2017 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Don't include this package in any target
+LOCAL_MODULE_TAGS := tests
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
+LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
+
+# tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+LOCAL_PACKAGE_NAME := FullBackupOnlyFalseWithAgentApp
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
diff --git a/hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseWithAgentApp/AndroidManifest.xml b/hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseWithAgentApp/AndroidManifest.xml
new file mode 100644
index 0000000..03555d4
--- /dev/null
+++ b/hostsidetests/backup/FullBackupOnly/FullBackupOnlyFalseWithAgentApp/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 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
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.cts.backup.fullbackuponlyapp">
+
+    <application
+        android:backupAgent=".FullBackupOnlyBackupAgent">
+
+        <uses-library android:name="android.test.runner" />
+
+    </application>
+
+    <instrumentation
+        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.cts.backup.fullbackuponlyapp" />
+
+</manifest>
diff --git a/hostsidetests/backup/FullBackupOnly/FullBackupOnlyTrueWithAgentApp/Android.mk b/hostsidetests/backup/FullBackupOnly/FullBackupOnlyTrueWithAgentApp/Android.mk
new file mode 100644
index 0000000..2f0eae8
--- /dev/null
+++ b/hostsidetests/backup/FullBackupOnly/FullBackupOnlyTrueWithAgentApp/Android.mk
@@ -0,0 +1,39 @@
+# Copyright (C) 2017 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Don't include this package in any target
+LOCAL_MODULE_TAGS := tests
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
+LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
+
+# tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+LOCAL_PACKAGE_NAME := FullBackupOnlyTrueWithAgentApp
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
diff --git a/hostsidetests/backup/FullBackupOnly/FullBackupOnlyTrueWithAgentApp/AndroidManifest.xml b/hostsidetests/backup/FullBackupOnly/FullBackupOnlyTrueWithAgentApp/AndroidManifest.xml
new file mode 100644
index 0000000..9b90592
--- /dev/null
+++ b/hostsidetests/backup/FullBackupOnly/FullBackupOnlyTrueWithAgentApp/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 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
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.cts.backup.fullbackuponlyapp">
+
+    <application
+        android:backupAgent=".FullBackupOnlyBackupAgent"
+        android:fullBackupOnly="true">
+
+        <uses-library android:name="android.test.runner" />
+
+    </application>
+
+    <instrumentation
+        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.cts.backup.fullbackuponlyapp" />
+
+</manifest>
diff --git a/hostsidetests/backup/FullBackupOnly/src/FullBackupOnlyBackupAgent.java b/hostsidetests/backup/FullBackupOnly/src/FullBackupOnlyBackupAgent.java
new file mode 100644
index 0000000..f14ce24
--- /dev/null
+++ b/hostsidetests/backup/FullBackupOnly/src/FullBackupOnlyBackupAgent.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2017 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.cts.backup.fullbackuponlyapp;
+
+import android.app.backup.BackupAgent;
+import android.app.backup.BackupDataInput;
+import android.app.backup.BackupDataOutput;
+
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * BackupAgent for test apps in {@link android.cts.backup.fullbackuponlyapp} package.
+ * Performs backup/restore of the file provided by {@link FullBackupOnlyTest}.
+ *
+ * Implementation of key/value backup methods is based on the examples from
+ * https://developer.android.com/guide/topics/data/keyvaluebackup.html
+ */
+public class FullBackupOnlyBackupAgent extends BackupAgent {
+    private static final String TAG = "FullBackupOnlyBA";
+
+    private static final String BACKUP_KEY = "full_backup_only_key";
+    private static final int DEFAULT_VALUE = -1;
+
+    /** Get the value saved in the shared preference and back it up. */
+    @Override
+    public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+            ParcelFileDescriptor newState) throws IOException {
+        Log.i(TAG, "onBackup");
+
+        File fileToBackup = FullBackupOnlyTest.getKeyValueBackupFile(this);
+        byte[] buffer = readFileToBytes(fileToBackup);
+
+        // Send the data to the Backup Manager via the BackupDataOutput
+        int len = buffer.length;
+        data.writeEntityHeader(BACKUP_KEY, len);
+        data.writeEntityData(buffer, len);
+    }
+
+    /** Get the value from backup and save it in the shared preference. */
+    @Override
+    public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
+            throws IOException {
+        Log.i(TAG, "onRestore");
+        int value = DEFAULT_VALUE;
+
+        // There should be only one entity, but the safest
+        // way to consume it is using a while loop
+        while (data.readNextHeader()) {
+            String key = data.getKey();
+            int dataSize = data.getDataSize();
+
+            // If the key is ours (for saving top score). Note this key was used when
+            // we wrote the backup entity header
+            if (BACKUP_KEY.equals(key)) {
+                // Copy data from BackupDataInput and write it into the file.
+                byte[] dataBuf = new byte[dataSize];
+                data.readEntityData(dataBuf, 0, dataSize);
+
+                File fileToRestore = FullBackupOnlyTest.getKeyValueBackupFile(this);
+
+                try (BufferedOutputStream bos = new BufferedOutputStream(
+                        new FileOutputStream(fileToRestore))) {
+                    bos.write(dataBuf, 0, dataBuf.length);
+                }
+            } else {
+                // We don't know this entity key. Shouldn't happen.
+                throw new RuntimeException("Unexpected key in the backup data");
+            }
+        }
+
+        // Finally, write to the state blob (newState) that describes the restored data
+        FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
+        DataOutputStream out = new DataOutputStream(outstream);
+        out.writeInt(value);
+    }
+
+
+    private byte[] readFileToBytes(File file) {
+        int size = (int) file.length();
+        byte[] bytes = new byte[size];
+        try {
+            BufferedInputStream buf = new BufferedInputStream(new FileInputStream(file));
+            buf.read(bytes, 0, bytes.length);
+            buf.close();
+        } catch (FileNotFoundException e) {
+            throw new RuntimeException("Key/value file not found", e);
+        } catch (IOException e) {
+            throw new RuntimeException("Error reading key/value file", e);
+        }
+        return bytes;
+    }
+}
diff --git a/hostsidetests/backup/FullBackupOnly/src/FullBackupOnlyTest.java b/hostsidetests/backup/FullBackupOnly/src/FullBackupOnlyTest.java
new file mode 100644
index 0000000..17a7e2c
--- /dev/null
+++ b/hostsidetests/backup/FullBackupOnly/src/FullBackupOnlyTest.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2017 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.cts.backup.fullbackuponlyapp;
+
+import static android.support.test.InstrumentationRegistry.getTargetContext;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Random;
+
+/**
+ * Device side routines to be invoked by the host side FullBackupOnlyHostSideTest. These
+ * are not designed to be called in any other way, as they rely on state set up by the host side
+ * test.
+ */
+@RunWith(AndroidJUnit4.class)
+public class FullBackupOnlyTest {
+    private static final String TAG = "FullBackupOnlyTest";
+
+    private static final int FILE_SIZE_BYTES = 1024 * 1024;
+
+    private File mKeyValueBackupFile;
+    private File mDoBackupFile;
+    private File mDoBackupFile2;
+
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        Log.i(TAG, "set up");
+        mContext = getTargetContext();
+        setupFiles();
+    }
+
+    private void setupFiles() {
+        mKeyValueBackupFile = getKeyValueBackupFile(mContext);
+
+        // Files to be backed up with Dolly
+        File filesDir = mContext.getFilesDir();
+        File normalFolder = new File(filesDir, "normal_folder");
+
+        mDoBackupFile = new File(filesDir, "file_to_backup");
+        mDoBackupFile2 = new File(normalFolder, "file_to_backup2");
+    }
+
+    @Test
+    public void createFiles() throws Exception {
+        // Make sure the data does not exist from before
+        deleteAllFiles();
+        assertNoFilesExist();
+
+        // Create test data
+        generateFiles();
+        assertAllFilesExist();
+
+        Log.d(TAG, "Test files created: \n"
+                + mKeyValueBackupFile.getAbsolutePath() + "\n"
+                + mDoBackupFile.getAbsolutePath() + "\n"
+                + mDoBackupFile2.getAbsolutePath());
+    }
+
+    @Test
+    public void checkKeyValueFileDoesntExist() throws Exception {
+        assertKeyValueFileDoesntExist();
+    }
+
+    @Test
+    public void checkKeyValueFileExists() throws Exception {
+        assertKeyValueFileExists();
+    }
+
+    @Test
+    public void checkDollyFilesExist() throws Exception {
+        assertDollyFilesExist();
+    }
+
+    @Test
+    public void checkDollyFilesDontExist() throws Exception {
+        assertDollyFilesDontExist();
+    }
+
+    protected static File getKeyValueBackupFile(Context context) {
+        // Files in the 'no_backup' directory are not backed up with Dolly.
+        // We're going to use it to store a file the contents of which are backed up via key/value.
+        File noBackupDir = context.getNoBackupFilesDir();
+        return new File(noBackupDir, "key_value_backup_file");
+    }
+
+    private void generateFiles() {
+        try {
+            // Add data to all the files we created
+            addData(mKeyValueBackupFile);
+            addData(mDoBackupFile);
+            addData(mDoBackupFile2);
+            Log.d(TAG, "Files generated!");
+        } catch (IOException e) {
+            Log.e(TAG, "Unable to generate files", e);
+        }
+    }
+
+    private void deleteAllFiles() {
+        mKeyValueBackupFile.delete();
+        mDoBackupFile.delete();
+        mDoBackupFile2.delete();
+        Log.d(TAG, "Files deleted!");
+    }
+
+    private void addData(File file) throws IOException {
+        file.getParentFile().mkdirs();
+        byte[] bytes = new byte[FILE_SIZE_BYTES];
+        new Random().nextBytes(bytes);
+
+        try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file))) {
+            bos.write(bytes, 0, bytes.length);
+        }
+    }
+
+    private void assertAllFilesExist() {
+        assertKeyValueFileExists();
+        assertDollyFilesExist();
+    }
+
+    private void assertNoFilesExist() {
+        assertKeyValueFileDoesntExist();
+        assertDollyFilesDontExist();
+    }
+
+    private void assertKeyValueFileExists() {
+        assertTrue("Key/value file did not exist!", mKeyValueBackupFile.exists());
+    }
+
+    private void assertKeyValueFileDoesntExist() {
+        assertFalse("Key/value file did exist!", mKeyValueBackupFile.exists());
+    }
+
+    private void assertDollyFilesExist() {
+        assertTrue("File in 'files' did not exist!", mDoBackupFile.exists());
+        assertTrue("File in folder inside 'files' did not exist!", mDoBackupFile2.exists());
+    }
+
+    private void assertDollyFilesDontExist() {
+        assertFalse("File in 'files' did exist!", mDoBackupFile.exists());
+        assertFalse("File in folder inside 'files' did exist!", mDoBackupFile2.exists());
+    }
+}
diff --git a/hostsidetests/backup/RestoreAnyVersion/src/RestoreAnyVersionTest.java b/hostsidetests/backup/RestoreAnyVersion/src/RestoreAnyVersionTest.java
index a364b0e..1dbdb05 100644
--- a/hostsidetests/backup/RestoreAnyVersion/src/RestoreAnyVersionTest.java
+++ b/hostsidetests/backup/RestoreAnyVersion/src/RestoreAnyVersionTest.java
@@ -56,15 +56,6 @@
     private static final int NEW_VERSION = 200;
 
     private Context mContext;
-    private CountDownLatch mLatch;
-
-    private final BroadcastReceiver mSharedPrefencesReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            Log.i(TAG, "received broadcast");
-            mLatch.countDown();
-        }
-    };
 
     @Before
     public void setUp() {
diff --git a/hostsidetests/backup/src/android/cts/backup/FullBackupOnlyHostSideTest.java b/hostsidetests/backup/src/android/cts/backup/FullBackupOnlyHostSideTest.java
new file mode 100644
index 0000000..7697dd2
--- /dev/null
+++ b/hostsidetests/backup/src/android/cts/backup/FullBackupOnlyHostSideTest.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2017 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.cts.backup;
+
+import static junit.framework.Assert.assertNull;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test checking that 'fullBackupOnly' manifest attribute is respected by backup manager.
+ *
+ * Uses 3 different versions of the same app that differ only by 'fullBackupOnly' value and the
+ * presence/absence of the backup agent.*
+ *
+ * Invokes device side tests provided by
+ * {@link android.cts.backup.fullbackupapp.FullBackupOnlyTest}.
+ *
+ * The flow of the tests is the following:
+ * 1. Install the app
+ * 2. Generate files in data folder of the app, including a file in no_backup folder. The file in
+ * no_backup folder is used for key/value backup by the backup agent of the app.
+ * 3. Run 'bmgr backupnow'. Depending on the manifest of the app we expect either Dolly or Key/value
+ * backup to be performed.
+ * 4. Uninstall and reinstall the app.
+ * 5. Check that the correct files were restored depending on the manifest:
+ * - Files in the app's data folder for Dolly backup
+ * - Only file in no_backup folder for key/value.
+ */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class FullBackupOnlyHostSideTest extends BaseBackupHostSideTest {
+
+    private static final String FULLBACKUPONLY_APP_PACKAGE = "android.cts.backup.fullbackuponlyapp";
+    private static final String FULLBACKUPONLY_DEVICE_TEST_CLASS_NAME =
+            FULLBACKUPONLY_APP_PACKAGE + ".FullBackupOnlyTest";
+
+    /**
+     * The name of the APK of the app that has a backup agent and fullBackupOnly=false in the
+     * manifest
+     */
+    private static final String FULLBACKUPONLY_FALSE_WITH_AGENT_APP_APK =
+            "FullBackupOnlyFalseWithAgentApp.apk";
+
+    /**
+     * The name of the APK of the app that has no backup agent and fullBackupOnly=false in the
+     * manifest
+     */
+    private static final String FULLBACKUPONLY_FALSE_NO_AGENT_APP_APK =
+            "FullBackupOnlyFalseNoAgentApp.apk";
+
+    /**
+     * The name of the APK of the app that has a backup agent and fullBackupOnly=true in the
+     * manifest
+     */
+    private static final String FULLBACKUPONLY_TRUE_WITH_AGENT_APP_APK =
+            "FullBackupOnlyTrueWithAgentApp.apk";
+
+
+    @After
+    public void tearDown() throws Exception {
+        super.tearDown();
+
+        // Clear backup data and uninstall the package (in that order!)
+        clearBackupDataInLocalTransport(FULLBACKUPONLY_APP_PACKAGE);
+        assertNull(uninstallPackage(FULLBACKUPONLY_APP_PACKAGE));
+    }
+
+    /**
+     * Tests that the app that doesn't have fullBackupOnly (same as fullBackupOnly=false by default)
+     * and has a backup agent will get key/value backup.
+     * We check that key/value data was restored after reinstall and dolly data was not.
+     */
+    @Test
+    public void testFullBackupOnlyFalse_WithAgent() throws Exception {
+        installPackage(FULLBACKUPONLY_FALSE_WITH_AGENT_APP_APK, "-d", "-r");
+
+        checkFullBackupOnlyDeviceTest("createFiles");
+
+        backupNowAndAssertSuccess(FULLBACKUPONLY_APP_PACKAGE);
+
+        assertNull(uninstallPackage(FULLBACKUPONLY_APP_PACKAGE));
+
+        installPackage(FULLBACKUPONLY_FALSE_WITH_AGENT_APP_APK, "-d", "-r");
+
+        checkFullBackupOnlyDeviceTest("checkKeyValueFileExists");
+        checkFullBackupOnlyDeviceTest("checkDollyFilesDontExist");
+    }
+
+    /**
+     * Tests that the app that doesn't have fullBackupOnly (same as fullBackupOnly=false by default)
+     * and has no backup agent will get Dolly backup.
+     * We check that key/value data was not restored after reinstall and dolly data was.
+     */
+    @Test
+    public void testFullBackupOnlyFalse_NoAgent() throws Exception {
+        installPackage(FULLBACKUPONLY_FALSE_NO_AGENT_APP_APK, "-d", "-r");
+
+        checkFullBackupOnlyDeviceTest("createFiles");
+
+        backupNowAndAssertSuccess(FULLBACKUPONLY_APP_PACKAGE);
+
+        assertNull(uninstallPackage(FULLBACKUPONLY_APP_PACKAGE));
+
+        installPackage(FULLBACKUPONLY_FALSE_NO_AGENT_APP_APK, "-d", "-r");
+
+        checkFullBackupOnlyDeviceTest("checkKeyValueFileDoesntExist");
+        checkFullBackupOnlyDeviceTest("checkDollyFilesExist");
+    }
+
+    /**
+     * Tests that the app that has fullBackupOnly=true  and has a backup agent will only get
+     * Dolly backup.
+     * We check that key/value data was not restored after reinstall and dolly data was.
+     */
+    @Test
+    public void testFullBackupOnlyTrue_WithAgent() throws Exception {
+        installPackage(FULLBACKUPONLY_TRUE_WITH_AGENT_APP_APK, "-d", "-r");
+
+        checkFullBackupOnlyDeviceTest("createFiles");
+
+        backupNowAndAssertSuccess(FULLBACKUPONLY_APP_PACKAGE);
+
+        assertNull(uninstallPackage(FULLBACKUPONLY_APP_PACKAGE));
+
+        installPackage(FULLBACKUPONLY_TRUE_WITH_AGENT_APP_APK, "-d", "-r");
+
+        checkFullBackupOnlyDeviceTest("checkKeyValueFileDoesntExist");
+        checkFullBackupOnlyDeviceTest("checkDollyFilesExist");
+    }
+
+
+    private void checkFullBackupOnlyDeviceTest(String methodName)
+            throws DeviceNotAvailableException {
+        checkDeviceTest(FULLBACKUPONLY_APP_PACKAGE, FULLBACKUPONLY_DEVICE_TEST_CLASS_NAME,
+                methodName);
+    }
+}