support package scope prepare/teardown

* introduced concept of module test config as AndroidTest.xml;
  for now target preparers can be defined in it to complete tasks
  before and after (CTS) package scope test execution
* modified CtsTest to invoke the preparers around package scope
  test execution
* modified related makefiles to "install" the module test config
  into CTS repository/testcases
* default common test config that included the commonly useful
  preparers
* modified accessibility tests to adopt module test config

Bug: 19442125

Change-Id: I1c694997c96c37150399395de2fbc464264c2aba
diff --git a/build/config.mk b/build/config.mk
index 20f6001..ffc71ba 100644
--- a/build/config.mk
+++ b/build/config.mk
@@ -34,6 +34,9 @@
 # Holds the target architecture to build for.
 CTS_TARGET_ARCH := $(TARGET_ARCH)
 
+# default module config filename
+CTS_MODULE_TEST_CONFIG := AndroidTest.xml
+
 # CTS build rules
 BUILD_CTS_EXECUTABLE := cts/build/test_executable.mk
 BUILD_CTS_PACKAGE := cts/build/test_package.mk
@@ -43,3 +46,4 @@
 BUILD_CTS_UI_JAVA_LIBRARY := cts/build/test_uiautomator.mk
 BUILD_CTS_DEQP_PACKAGE := cts/build/test_deqp_package.mk
 BUILD_CTS_SUPPORT_PACKAGE := cts/build/support_package.mk
+BUILD_CTS_MODULE_TEST_CONFIG := cts/build/module_test_config.mk
diff --git a/build/module_test_config.mk b/build/module_test_config.mk
new file mode 100644
index 0000000..5cbaf0d
--- /dev/null
+++ b/build/module_test_config.mk
@@ -0,0 +1,21 @@
+# Copyright (C) 2015 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.
+
+cts_module_test_config := $(if $(wildcard \
+	$(LOCAL_PATH)/$(CTS_MODULE_TEST_CONFIG)), \
+	$(CTS_TESTCASES_OUT)/$(LOCAL_PACKAGE_NAME).config)
+ifneq ($(cts_module_test_config),)
+$(cts_module_test_config): $(LOCAL_PATH)/$(CTS_MODULE_TEST_CONFIG)
+	$(call copy-file-to-target)
+endif
diff --git a/build/test_package.mk b/build/test_package.mk
index b2bf2c6..0e8d37b 100644
--- a/build/test_package.mk
+++ b/build/test_package.mk
@@ -24,6 +24,7 @@
 LOCAL_PROGUARD_ENABLED := disabled
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
+include $(BUILD_CTS_MODULE_TEST_CONFIG)
 
 cts_src_dirs := $(LOCAL_PATH)
 cts_src_dirs += $(sort $(dir $(LOCAL_GENERATED_SOURCES)))
@@ -41,6 +42,7 @@
 $(cts_package_xml): PRIVATE_TEST_PACKAGE := $(PRIVATE_CTS_TEST_PACKAGE_NAME_)
 $(cts_package_xml): PRIVATE_MANIFEST := $(LOCAL_PATH)/AndroidManifest.xml
 $(cts_package_xml): PRIVATE_TEST_TYPE := $(if $(LOCAL_CTS_TEST_RUNNER),$(LOCAL_CTS_TEST_RUNNER),'')
+$(cts_package_xml): $(cts_module_test_config)
 $(cts_package_xml): $(CTS_EXPECTATIONS) $(CTS_UNSUPPORTED_ABIS) $(CTS_JAVA_TEST_SCANNER_DOCLET) $(CTS_JAVA_TEST_SCANNER) $(CTS_XML_GENERATOR)
 	$(hide) echo Generating test description for java package $(PRIVATE_PACKAGE)
 	$(hide) mkdir -p $(CTS_TESTCASES_OUT)
@@ -57,6 +59,5 @@
 						-b $(CTS_UNSUPPORTED_ABIS) \
 						-a $(CTS_TARGET_ARCH) \
 						-o $@
-
 # Have the module name depend on the cts files; so the cts files get generated when you run mm/mmm/mma/mmma.
-$(my_register_name) : $(cts_package_xml)
+$(my_register_name) : $(cts_package_xml) $(cts_module_test_config)
diff --git a/tests/tests/accessibility/Android.mk b/tests/tests/accessibility/Android.mk
index 9f98b16..bb943ee 100644
--- a/tests/tests/accessibility/Android.mk
+++ b/tests/tests/accessibility/Android.mk
@@ -26,7 +26,4 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
 
-# This test runner sets up/cleans up the device before/after running the tests.
-LOCAL_CTS_TEST_RUNNER := com.android.cts.tradefed.testtype.AccessibilityTestRunner
-
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/accessibility/AndroidTest.xml b/tests/tests/accessibility/AndroidTest.xml
new file mode 100644
index 0000000..df90914
--- /dev/null
+++ b/tests/tests/accessibility/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+<configuration description="Base config for CTS package preparer">
+    <include name="common-config" />
+    <option name="run-command:run-command" value="settings put secure enabled_accessibility_services android.view.accessibility.services/.SpeakingAccessibilityService,android.view.accessibility.services/.VibratingAccessibilityService" />
+    <option name="run-command:run-command" value="settings put secure touch_exploration_granted_accessibility_services android.view.accessibility.services/.SpeakingAccessibilityService,android.view.accessibility.services/.VibratingAccessibilityService" />
+    <option name="run-command:run-command" value="settings put secure accessibility_enabled 1" />
+    <option name="run-command:teardown-command" value="settings put secure enabled_accessibility_services ''" />
+    <option name="run-command:teardown-command" value="settings put secure touch_exploration_granted_accessibility_services ''" />
+    <option name="run-command:teardown-command" value="settings put secure accessibility_enabled 0" />
+    <option name="cts-apk-installer:test-file-name" value="CtsSomeAccessibilityServices.apk" />
+</configuration>
diff --git a/tools/tradefed-host/res/config/common-config.xml b/tools/tradefed-host/res/config/common-config.xml
new file mode 100644
index 0000000..e1ac66d
--- /dev/null
+++ b/tools/tradefed-host/res/config/common-config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+<configuration description="Common base configuration for CTS module">
+    <!--
+      This common base configuration contains some commonly used preparers
+      -->
+    <target_preparer class="com.android.cts.tradefed.targetprep.CtsFilePusher">
+        <option name="cleanup" value="true" />
+    </target_preparer>
+    <target_preparer class="com.android.cts.tradefed.targetprep.CtsApkInstaller">
+        <option name="cleanup-apks" value="true" />
+    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer" />
+</configuration>
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/targetprep/CtsApkInstaller.java b/tools/tradefed-host/src/com/android/cts/tradefed/targetprep/CtsApkInstaller.java
new file mode 100644
index 0000000..08061b1
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/targetprep/CtsApkInstaller.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2015 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 com.android.cts.tradefed.targetprep;
+
+import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.targetprep.TargetSetupError;
+import com.android.tradefed.targetprep.TestAppInstallSetup;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+/**
+ * Installs specified apks from CTS test case repository
+ */
+@OptionClass(alias="cts-apk-installer")
+public class CtsApkInstaller extends TestAppInstallSetup {
+
+    private CtsBuildHelper mBuildHelper = null;
+
+    protected CtsBuildHelper getCtsBuildHelper(IBuildInfo buildInfo) {
+        if (mBuildHelper == null) {
+            mBuildHelper = CtsBuildHelper.createBuildHelper(buildInfo);
+        }
+        return mBuildHelper;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected File getLocalPathForFilename(IBuildInfo buildInfo, String apkFileName)
+            throws TargetSetupError {
+        try {
+            return getCtsBuildHelper(buildInfo).getTestApp(apkFileName);
+        } catch (FileNotFoundException e) {
+            throw new TargetSetupError(String.format("apk not found: %s", apkFileName), e);
+        }
+    }
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/targetprep/CtsFilePusher.java b/tools/tradefed-host/src/com/android/cts/tradefed/targetprep/CtsFilePusher.java
new file mode 100644
index 0000000..c6ae2e1
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/targetprep/CtsFilePusher.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 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 com.android.cts.tradefed.targetprep;
+
+import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.targetprep.PushFilePreparer;
+
+import java.io.File;
+
+/**
+ * Pushes specified testing artifacts from CTS test case repository
+ */
+@OptionClass(alias="cts-file-pusher")
+public class CtsFilePusher extends PushFilePreparer {
+
+    private CtsBuildHelper mBuildHelper;
+
+    protected CtsBuildHelper getCtsBuildHelper(IBuildInfo buildInfo) {
+        if (mBuildHelper == null) {
+            mBuildHelper = CtsBuildHelper.createBuildHelper(buildInfo);
+        }
+        return mBuildHelper;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public File resolveRelativeFilePath(IBuildInfo buildInfo, String fileName) {
+        return new File(getCtsBuildHelper(buildInfo).getTestCasesDir(), fileName);
+    }
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/AccessibilityServiceTestRunner.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/AccessibilityServiceTestRunner.java
deleted file mode 100644
index eafd608..0000000
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/AccessibilityServiceTestRunner.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2012 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 com.android.cts.tradefed.testtype;
-
-import com.android.cts.util.AbiUtils;
-import com.android.ddmlib.Log;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.result.ITestInvocationListener;
-import com.android.tradefed.util.FileUtil;
-
-import junit.framework.TestCase;
-
-import java.io.File;
-
-/**
- * Running the accessibility tests requires modification of secure
- * settings. Secure settings cannot be changed from device CTS tests
- * since system signature permission is required. Such settings can
- * be modified by the shell user, so a host side test is used for
- * installing a package with a delegating accessibility service, enabling
- * this service, running these tests, disabling the service, and removing
- * the delegating accessibility service package.
- *
- * @deprecated This class is not required in current CTS builds. Still
- * maintained so cts-tradefed can run against older CTS builds that still
- * require this class.
- */
-@Deprecated
-public class AccessibilityServiceTestRunner extends CtsInstrumentationApkTest {
-
-    private static final String LOG_TAG = AccessibilityServiceTestRunner.class.getSimpleName();
-
-    private static final String DELEGATING_ACCESSIBLITY_SERVICE_PACKAGE_NAME =
-        "android.accessibilityservice.delegate";
-
-    private static final String DELEGATING_ACCESSIBLITY_SERVICE_NAME =
-        "android.accessibilityservice.delegate.DelegatingAccessibilityService";
-
-    private static final String DELEGATING_ACCESSIBLITY_SERVICE_APK =
-        "CtsDelegatingAccessibilityService.apk";
-
-    @Override
-    public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
-        beforeTest();
-        super.run(listener);
-        afterTest();
-    }
-
-    private void beforeTest() throws DeviceNotAvailableException {
-        installApkAndAssert(DELEGATING_ACCESSIBLITY_SERVICE_APK);
-        enableAccessibilityAndDelegatingService();
-    }
-
-    private void afterTest() throws DeviceNotAvailableException {
-        AccessibilityTestRunner.disableAccessibilityAndServices(getDevice());
-        uninstallAndAssert(DELEGATING_ACCESSIBLITY_SERVICE_PACKAGE_NAME);
-    }
-
-    private void installApkAndAssert(String apkName) throws DeviceNotAvailableException {
-        File file = FileUtil.getFileForPath(mCtsBuild.getTestCasesDir(), apkName);
-        String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
-        String errorMessage = getDevice().installPackage(file, true, options);
-        TestCase.assertNull("Error installing: " + apkName, errorMessage);
-    }
-
-    private void uninstallAndAssert(String packageName) throws DeviceNotAvailableException {
-        String errorMessage = getDevice().uninstallPackage(packageName);
-        TestCase.assertNull("Error uninstalling: " + packageName, errorMessage);
-    }
-
-    private void enableAccessibilityAndDelegatingService() throws DeviceNotAvailableException {
-        String componentName = DELEGATING_ACCESSIBLITY_SERVICE_PACKAGE_NAME + "/"
-            + DELEGATING_ACCESSIBLITY_SERVICE_NAME;
-        AccessibilityTestRunner.enableAccessibilityAndServices(getDevice(),
-                componentName);
-    }
-}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/AccessibilityTestRunner.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/AccessibilityTestRunner.java
deleted file mode 100644
index 9ba4109..0000000
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/AccessibilityTestRunner.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2012 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 com.android.cts.tradefed.testtype;
-
-import com.android.cts.tradefed.targetprep.SettingsToggler;
-import com.android.cts.util.AbiUtils;
-import com.android.ddmlib.Log;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.result.ITestInvocationListener;
-import com.android.tradefed.util.FileUtil;
-
-import junit.framework.TestCase;
-
-import java.io.File;
-
-/**
- * Running the accessibility tests requires modification of secure
- * settings. Secure settings cannot be changed from device CTS tests
- * since system signature permission is required. Such settings can
- * be modified by the shell user, so a host side test is used for
- * installing a package with some accessibility services, enabling
- * these services, running the tests, disabling the services, and removing
- * the accessibility services package.
- */
-public class AccessibilityTestRunner extends CtsInstrumentationApkTest {
-
-    private static final String LOG_TAG = AccessibilityTestRunner.class.getSimpleName();
-
-    private static final String SOME_ACCESSIBLITY_SERVICES_PACKAGE_NAME =
-        "android.view.accessibility.services";
-
-    private static final String SPEAKING_ACCESSIBLITY_SERVICE_NAME =
-        "android.view.accessibility.services.SpeakingAccessibilityService";
-
-    private static final String VIBRATING_ACCESSIBLITY_SERVICE_NAME =
-        "android.view.accessibility.services.VibratingAccessibilityService";
-
-    private static final String SOME_ACCESSIBLITY_SERVICES_APK =
-        "CtsSomeAccessibilityServices.apk";
-
-    @Override
-    public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
-        beforeTest();
-        super.run(listener);
-        afterTest();
-    }
-
-    private void beforeTest() throws DeviceNotAvailableException {
-        installApkAndAssert(SOME_ACCESSIBLITY_SERVICES_APK);
-        enableAccessibilityAndServices();
-    }
-
-    private void afterTest() throws DeviceNotAvailableException {
-        disableAccessibilityAndServices(getDevice());
-        uninstallAndAssert(SOME_ACCESSIBLITY_SERVICES_PACKAGE_NAME);
-    }
-
-    private void installApkAndAssert(String apkName) throws DeviceNotAvailableException {
-        File file = FileUtil.getFileForPath(mCtsBuild.getTestCasesDir(), apkName);
-        String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
-        String errorMessage = getDevice().installPackage(file, true, options);
-        TestCase.assertNull("Error installing: " + apkName, errorMessage);
-    }
-
-    private void uninstallAndAssert(String packageName) throws DeviceNotAvailableException {
-        String errorMessage = getDevice().uninstallPackage(packageName);
-        TestCase.assertNull("Error uninstalling: " + packageName, errorMessage);
-    }
-
-    private void enableAccessibilityAndServices() throws DeviceNotAvailableException {
-        String enabledServicesValue =
-              SOME_ACCESSIBLITY_SERVICES_PACKAGE_NAME + "/" + SPEAKING_ACCESSIBLITY_SERVICE_NAME
-            + ":"
-            + SOME_ACCESSIBLITY_SERVICES_PACKAGE_NAME + "/" + VIBRATING_ACCESSIBLITY_SERVICE_NAME;
-        enableAccessibilityAndServices(getDevice(), enabledServicesValue);
-    }
-
-    static void enableAccessibilityAndServices(ITestDevice device, String value)
-            throws DeviceNotAvailableException {
-        SettingsToggler.setSecureString(device, "enabled_accessibility_services", value);
-        SettingsToggler.setSecureString(device,
-                "touch_exploration_granted_accessibility_services", value);
-        SettingsToggler.setSecureInt(device, "accessibility_enabled", 1);
-    }
-
-    static void disableAccessibilityAndServices(ITestDevice device)
-            throws DeviceNotAvailableException {
-        SettingsToggler.updateSecureString(device, "enabled_accessibility_services", "");
-        SettingsToggler.updateSecureString(device,
-                "touch_exploration_granted_accessibility_services", "");
-        SettingsToggler.updateSecureInt(device, "accessibility_enabled", 0);
-    }
-}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
index 3c5888f..c241ddb 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
@@ -37,7 +37,12 @@
 import com.android.tradefed.result.InputStreamSource;
 import com.android.tradefed.result.LogDataType;
 import com.android.tradefed.result.ResultForwarder;
+import com.android.tradefed.targetprep.BuildError;
+import com.android.tradefed.targetprep.ITargetCleaner;
+import com.android.tradefed.targetprep.ITargetPreparer;
+import com.android.tradefed.targetprep.TargetSetupError;
 import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
 import com.android.tradefed.testtype.IBuildReceiver;
 import com.android.tradefed.testtype.IDeviceTest;
 import com.android.tradefed.testtype.IRemoteTest;
@@ -64,6 +69,7 @@
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Map;
 import java.util.Set;
 
@@ -557,7 +563,9 @@
                 }
 
                 forwardPackageDetails(testPackage.getPackageDef(), listener);
+                performPackagePrepareSetup(testPackage.getPackageDef());
                 test.run(filterMap.get(testPackage.getPackageDef().getId()));
+                performPackagePreparerTearDown(testPackage.getPackageDef());
                 if (i < mTestPackageList.size() - 1) {
                     TestPackage nextPackage = mTestPackageList.get(i + 1);
                     rebootIfNecessary(testPackage, nextPackage);
@@ -592,6 +600,54 @@
     }
 
     /**
+     * Invokes {@link ITargetPreparer}s configured for the test package. {@link TargetSetupError}s
+     * thrown by any preparer will be rethrown as {@link RuntimeException} so that the entire test
+     * package will be skipped for execution. Note that preparers will be invoked in the same order
+     * as they are defined in the module test config.
+     * @param packageDef definition for the test package
+     * @throws DeviceNotAvailableException
+     */
+    private void performPackagePrepareSetup(ITestPackageDef packageDef)
+            throws DeviceNotAvailableException {
+        for (ITargetPreparer preparer : packageDef.getPackagePreparers()) {
+            if (preparer instanceof IAbiReceiver) {
+                ((IAbiReceiver)preparer).setAbi(packageDef.getAbi());
+            }
+            try {
+                preparer.setUp(getDevice(), mBuildInfo);
+            } catch (BuildError e) {
+                // This should only happen for flashing new build
+                CLog.e("Unexpected BuildError from preparer: %s",
+                        preparer.getClass().getCanonicalName());
+            } catch (TargetSetupError e) {
+                // log preparer class then rethrow & let caller handle
+                CLog.e("TargetSetupError in preparer: %s",
+                        preparer.getClass().getCanonicalName());
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    /**
+     * Invokes clean up step for {@link ITargetCleaner}s configured for the test package. Note that
+     * the cleaners will be invoked in the reverse order as they are defined in module test config.
+     * @param packageDef definition for the test package
+     * @throws DeviceNotAvailableException
+     */
+    private void performPackagePreparerTearDown(ITestPackageDef packageDef)
+            throws DeviceNotAvailableException {
+        List<ITargetPreparer> preparers = packageDef.getPackagePreparers();
+        ListIterator<ITargetPreparer> itr = preparers.listIterator(preparers.size());
+        // do teardown in reverse order
+        while (itr.hasPrevious()) {
+            ITargetPreparer preparer = itr.previous();
+            if (preparer instanceof ITargetCleaner) {
+                ((ITargetCleaner) preparer).tearDown(getDevice(), mBuildInfo, null);
+            }
+        }
+    }
+
+    /**
      * Helper method to join strings. Exposed for unit tests
      * @param input
      * @param conjunction
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPackageDef.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPackageDef.java
index 8a5c822..13f3572 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPackageDef.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPackageDef.java
@@ -17,11 +17,13 @@
 package com.android.cts.tradefed.testtype;
 
 import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.tradefed.targetprep.ITargetPreparer;
 import com.android.tradefed.testtype.IAbi;
 import com.android.tradefed.testtype.IRemoteTest;
 
 import java.io.File;
 import java.util.Collection;
+import java.util.List;
 
 /**
  * Container for CTS test info.
@@ -98,4 +100,9 @@
      */
     public String getTargetPackageName();
 
+    /**
+     * Return a list of preparers used for setup or teardown of test cases in this package
+     * @return
+     */
+    public List<ITargetPreparer> getPackagePreparers();
 }
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
index 59dee04..c6affba 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
@@ -20,6 +20,7 @@
 import com.android.ddmlib.Log.LogLevel;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.targetprep.ITargetPreparer;
 import com.android.tradefed.testtype.IAbi;
 import com.android.tradefed.testtype.IRemoteTest;
 import com.android.tradefed.testtype.InstrumentationTest;
@@ -53,10 +54,6 @@
     public static final String WRAPPED_NATIVE_TEST = "wrappednative";
     public static final String VM_HOST_TEST = "vmHostTest";
     public static final String DEQP_TEST = "deqpTest";
-    public static final String ACCESSIBILITY_TEST =
-            "com.android.cts.tradefed.testtype.AccessibilityTestRunner";
-    public static final String ACCESSIBILITY_SERVICE_TEST =
-            "com.android.cts.tradefed.testtype.AccessibilityServiceTestRunner";
     public static final String DISPLAY_TEST =
             "com.android.cts.tradefed.testtype.DisplayTestRunner";
     public static final String UIAUTOMATOR_TEST = "uiAutomator";
@@ -72,6 +69,7 @@
     private String mTestPackageName = null;
     private String mDigest = null;
     private IAbi mAbi = null;
+    private List<ITargetPreparer> mPreparers = null;
 
     // use a LinkedHashSet for predictable iteration insertion-order, and fast
     // lookups
@@ -215,6 +213,22 @@
     }
 
     /**
+     * Setter for injecting a list of {@link ITargetPreparer}s as configured in module test config.
+     * @param preparers
+     */
+    void setPackagePreparers(List<ITargetPreparer> preparers) {
+        mPreparers = preparers;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<ITargetPreparer> getPackagePreparers() {
+        return mPreparers;
+    }
+
+    /**
      * {@inheritDoc}
      */
     @Override
@@ -258,13 +272,6 @@
             WrappedGTest wrappedGeeTest = new WrappedGTest(mAppNameSpace, mAppPackageName, mName, mRunner);
             wrappedGeeTest.setAbi(mAbi);
             return wrappedGeeTest;
-        } else if (ACCESSIBILITY_TEST.equals(mTestType)) {
-            AccessibilityTestRunner test = new AccessibilityTestRunner();
-            return setInstrumentationTest(test, testCaseDir);
-        } else if (ACCESSIBILITY_SERVICE_TEST.equals(mTestType)) {
-            @SuppressWarnings("deprecation")
-            AccessibilityServiceTestRunner test = new AccessibilityServiceTestRunner();
-            return setInstrumentationTest(test, testCaseDir);
         } else if (DISPLAY_TEST.equals(mTestType)) {
             DisplayTestRunner test = new DisplayTestRunner();
             return setInstrumentationTest(test, testCaseDir);
@@ -437,8 +444,8 @@
         } catch (IOException e) {
             CLog.e(e);
         } finally {
-            StreamUtil.closeStream(d);
-            StreamUtil.closeStream(fileStream);
+            StreamUtil.close(d);
+            StreamUtil.close(fileStream);
         }
         return "failed to generate digest";
     }
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageRepo.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageRepo.java
index aea6613..7e16170 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageRepo.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageRepo.java
@@ -17,6 +17,9 @@
 
 import com.android.cts.util.AbiUtils;
 import com.android.ddmlib.Log;
+import com.android.tradefed.config.ConfigurationException;
+import com.android.tradefed.config.ConfigurationFactory;
+import com.android.tradefed.config.IConfiguration;
 import com.android.tradefed.util.xml.AbstractXmlParser.ParseException;
 
 import java.io.BufferedInputStream;
@@ -27,8 +30,8 @@
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -63,22 +66,68 @@
     private void parse(File dir) {
         File[] xmlFiles = dir.listFiles(new XmlFilter());
         for (File xmlFile : xmlFiles) {
-            parseTestFromXml(xmlFile);
+            parseModuleTestConfigs(xmlFile);
         }
     }
 
-    private void parseTestFromXml(File xmlFile)  {
+    /**
+     * Infer package preparer config from package XML definition file and return if exists
+     * @param pkgXml {@link File} instance referencing the package XML definition
+     * @return the matching package preparer if exists, <code>null</code> otherwise
+     */
+    private File getPreparerDefForPackage(File pkgXml) {
+        String fullPath = pkgXml.getAbsolutePath();
+        int lastDot = fullPath.lastIndexOf('.');
+        if (lastDot == -1) {
+            // huh?
+            return null;
+        }
+        File preparer = new File(fullPath.substring(0, lastDot) + ".config");
+        if (preparer.exists()) {
+            return preparer;
+        }
+        return null;
+    }
+
+    /**
+     * Processes test module definition XML file, and stores parsed data structure in class member
+     * variable. Parsed config objects will be associated with each applicable ABI type so multiple
+     * {@link TestPackageDef}s will be generated accordingly. In addition, based on
+     * &lt;module name&gt;.config file naming convention, this method also looks for the optional
+     * module test config, and attaches defined configuration objects to the {@link TestPackageDef}
+     * representing the module accordingly.
+     * @param xmlFile the module definition XML
+     */
+    private void parseModuleTestConfigs(File xmlFile)  {
         TestPackageXmlParser parser = new TestPackageXmlParser(mIncludeKnownFailures);
         try {
             parser.parse(createStreamFromFile(xmlFile));
+            // based on test module XML file path, and the <module name>.config naming convention,
+            // infers the module test config file, and parses it
+            File preparer = getPreparerDefForPackage(xmlFile);
+            IConfiguration config = null;
+            if (preparer != null) {
+                try {
+                    // invokes parser to process the test module config file
+                    config = ConfigurationFactory.getInstance().createConfigurationFromArgs(
+                            new String[]{preparer.getAbsolutePath()});
+                } catch (ConfigurationException e) {
+                    throw new RuntimeException(
+                            String.format("error parsing config file: %s", xmlFile.getName()), e);
+                }
+            }
             Set<TestPackageDef> defs = parser.getTestPackageDefs();
             if (defs.isEmpty()) {
                 Log.w(LOG_TAG, String.format("Could not find test package info in xml file %s",
                         xmlFile.getAbsolutePath()));
             }
+            // loops over multiple package defs defined for each ABI type
             for (TestPackageDef def : defs) {
                 String name = def.getAppPackageName();
                 String abi = def.getAbi().getName();
+                if (config != null) {
+                    def.setPackagePreparers(config.getTargetPreparers());
+                }
                 if (!mTestMap.containsKey(abi)) {
                     mTestMap.put(abi, new HashMap<String, TestPackageDef>());
                 }