Allow to skip dumping deprecated options

In some compatibility situation, avoiding deprecated
option is useful to avoid hard mismatch betwee two version
of Tradefed.

Test: unit tests
https://sponge.corp.google.com/invocation?id=e1c54832-4e8e-46fa-8485-be32aca58171&searchFor=user%3Ajdesprez
Bug: 122830609

Change-Id: I1fb5a468fadb6450ad588fd928c4ba070f0b5cea
diff --git a/src/com/android/tradefed/config/Configuration.java b/src/com/android/tradefed/config/Configuration.java
index fa0d183..93ec09d 100644
--- a/src/com/android/tradefed/config/Configuration.java
+++ b/src/com/android/tradefed/config/Configuration.java
@@ -1315,6 +1315,14 @@
     /** {@inheritDoc} */
     @Override
     public void dumpXml(PrintWriter output, List<String> excludeFilters) throws IOException {
+        dumpXml(output, excludeFilters, true);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void dumpXml(
+            PrintWriter output, List<String> excludeFilters, boolean printDeprecatedOptions)
+            throws IOException {
         KXmlSerializer serializer = new KXmlSerializer();
         serializer.setOutput(output);
         serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
@@ -1326,12 +1334,17 @@
                     serializer,
                     MULTI_PRE_TARGET_PREPARER_TYPE_NAME,
                     multiPreTargerPrep,
-                    excludeFilters);
+                    excludeFilters,
+                    printDeprecatedOptions);
         }
 
         for (IMultiTargetPreparer multipreparer : getMultiTargetPreparers()) {
             ConfigurationUtil.dumpClassToXml(
-                    serializer, MULTI_PREPARER_TYPE_NAME, multipreparer, excludeFilters);
+                    serializer,
+                    MULTI_PREPARER_TYPE_NAME,
+                    multipreparer,
+                    excludeFilters,
+                    printDeprecatedOptions);
         }
 
         if (getDeviceConfig().size() > 1) {
@@ -1346,80 +1359,132 @@
                         serializer,
                         BUILD_PROVIDER_TYPE_NAME,
                         deviceConfig.getBuildProvider(),
-                        excludeFilters);
+                        excludeFilters,
+                        printDeprecatedOptions);
                 for (ITargetPreparer preparer : deviceConfig.getTargetPreparers()) {
                     ConfigurationUtil.dumpClassToXml(
-                            serializer, TARGET_PREPARER_TYPE_NAME, preparer, excludeFilters);
+                            serializer,
+                            TARGET_PREPARER_TYPE_NAME,
+                            preparer,
+                            excludeFilters,
+                            printDeprecatedOptions);
                 }
                 ConfigurationUtil.dumpClassToXml(
                         serializer,
                         DEVICE_RECOVERY_TYPE_NAME,
                         deviceConfig.getDeviceRecovery(),
-                        excludeFilters);
+                        excludeFilters,
+                        printDeprecatedOptions);
                 ConfigurationUtil.dumpClassToXml(
                         serializer,
                         DEVICE_REQUIREMENTS_TYPE_NAME,
                         deviceConfig.getDeviceRequirements(),
-                        excludeFilters);
+                        excludeFilters,
+                        printDeprecatedOptions);
                 ConfigurationUtil.dumpClassToXml(
                         serializer,
                         DEVICE_OPTIONS_TYPE_NAME,
                         deviceConfig.getDeviceOptions(),
-                        excludeFilters);
+                        excludeFilters,
+                        printDeprecatedOptions);
                 serializer.endTag(null, Configuration.DEVICE_NAME);
             }
         } else {
             // Put single device tags
             ConfigurationUtil.dumpClassToXml(
-                    serializer, BUILD_PROVIDER_TYPE_NAME, getBuildProvider(), excludeFilters);
+                    serializer,
+                    BUILD_PROVIDER_TYPE_NAME,
+                    getBuildProvider(),
+                    excludeFilters,
+                    printDeprecatedOptions);
             for (ITargetPreparer preparer : getTargetPreparers()) {
                 ConfigurationUtil.dumpClassToXml(
-                        serializer, TARGET_PREPARER_TYPE_NAME, preparer, excludeFilters);
+                        serializer,
+                        TARGET_PREPARER_TYPE_NAME,
+                        preparer,
+                        excludeFilters,
+                        printDeprecatedOptions);
             }
             ConfigurationUtil.dumpClassToXml(
-                    serializer, DEVICE_RECOVERY_TYPE_NAME, getDeviceRecovery(), excludeFilters);
+                    serializer,
+                    DEVICE_RECOVERY_TYPE_NAME,
+                    getDeviceRecovery(),
+                    excludeFilters,
+                    printDeprecatedOptions);
             ConfigurationUtil.dumpClassToXml(
                     serializer,
                     DEVICE_REQUIREMENTS_TYPE_NAME,
                     getDeviceRequirements(),
-                    excludeFilters);
+                    excludeFilters,
+                    printDeprecatedOptions);
             ConfigurationUtil.dumpClassToXml(
-                    serializer, DEVICE_OPTIONS_TYPE_NAME, getDeviceOptions(), excludeFilters);
+                    serializer,
+                    DEVICE_OPTIONS_TYPE_NAME,
+                    getDeviceOptions(),
+                    excludeFilters,
+                    printDeprecatedOptions);
         }
         for (IRemoteTest test : getTests()) {
-            ConfigurationUtil.dumpClassToXml(serializer, TEST_TYPE_NAME, test, excludeFilters);
+            ConfigurationUtil.dumpClassToXml(
+                    serializer, TEST_TYPE_NAME, test, excludeFilters, printDeprecatedOptions);
         }
         ConfigurationUtil.dumpClassToXml(
                 serializer,
                 CONFIGURATION_DESCRIPTION_TYPE_NAME,
                 getConfigurationDescription(),
-                excludeFilters);
+                excludeFilters,
+                printDeprecatedOptions);
         ConfigurationUtil.dumpClassToXml(
-                serializer, LOGGER_TYPE_NAME, getLogOutput(), excludeFilters);
+                serializer,
+                LOGGER_TYPE_NAME,
+                getLogOutput(),
+                excludeFilters,
+                printDeprecatedOptions);
         ConfigurationUtil.dumpClassToXml(
-                serializer, LOG_SAVER_TYPE_NAME, getLogSaver(), excludeFilters);
+                serializer,
+                LOG_SAVER_TYPE_NAME,
+                getLogSaver(),
+                excludeFilters,
+                printDeprecatedOptions);
         for (ITestInvocationListener listener : getTestInvocationListeners()) {
             ConfigurationUtil.dumpClassToXml(
-                    serializer, RESULT_REPORTER_TYPE_NAME, listener, excludeFilters);
+                    serializer,
+                    RESULT_REPORTER_TYPE_NAME,
+                    listener,
+                    excludeFilters,
+                    printDeprecatedOptions);
         }
         ConfigurationUtil.dumpClassToXml(
-                serializer, CMD_OPTIONS_TYPE_NAME, getCommandOptions(), excludeFilters);
+                serializer,
+                CMD_OPTIONS_TYPE_NAME,
+                getCommandOptions(),
+                excludeFilters,
+                printDeprecatedOptions);
 
         for (IMetricCollector collector : getMetricCollectors()) {
             ConfigurationUtil.dumpClassToXml(
-                    serializer, DEVICE_METRICS_COLLECTOR_TYPE_NAME, collector, excludeFilters);
+                    serializer,
+                    DEVICE_METRICS_COLLECTOR_TYPE_NAME,
+                    collector,
+                    excludeFilters,
+                    printDeprecatedOptions);
         }
 
         for (ISystemStatusChecker checker : getSystemStatusCheckers()) {
             ConfigurationUtil.dumpClassToXml(
-                    serializer, SYSTEM_STATUS_CHECKER_TYPE_NAME, checker, excludeFilters);
+                    serializer,
+                    SYSTEM_STATUS_CHECKER_TYPE_NAME,
+                    checker,
+                    excludeFilters,
+                    printDeprecatedOptions);
         }
 
         ConfigurationUtil.dumpClassToXml(
                 serializer,
                 SANBOX_OPTIONS_TYPE_NAME,
                 getConfigurationObject(SANBOX_OPTIONS_TYPE_NAME),
-                excludeFilters);
+                excludeFilters,
+                printDeprecatedOptions);
 
         serializer.endTag(null, ConfigurationUtil.CONFIGURATION_NAME);
         serializer.endDocument();
diff --git a/src/com/android/tradefed/config/ConfigurationUtil.java b/src/com/android/tradefed/config/ConfigurationUtil.java
index c6038f0..f162181 100644
--- a/src/com/android/tradefed/config/ConfigurationUtil.java
+++ b/src/com/android/tradefed/config/ConfigurationUtil.java
@@ -71,14 +71,17 @@
      * @param excludeClassFilter list of object configuration type or fully qualified class names to
      *     be excluded from the dump. for example: {@link Configuration#TARGET_PREPARER_TYPE_NAME}.
      *     com.android.tradefed.testtype.StubTest
+     * @param printDeprecatedOptions whether or not to print deprecated options
      */
     static void dumpClassToXml(
             KXmlSerializer serializer,
             String classTypeName,
             Object obj,
-            List<String> excludeClassFilter)
+            List<String> excludeClassFilter,
+            boolean printDeprecatedOptions)
             throws IOException {
-        dumpClassToXml(serializer, classTypeName, obj, false, excludeClassFilter);
+        dumpClassToXml(
+                serializer, classTypeName, obj, false, excludeClassFilter, printDeprecatedOptions);
     }
 
     /**
@@ -91,13 +94,15 @@
      * @param excludeClassFilter list of object configuration type or fully qualified class names to
      *     be excluded from the dump. for example: {@link Configuration#TARGET_PREPARER_TYPE_NAME}.
      *     com.android.tradefed.testtype.StubTest
+     * @param printDeprecatedOptions whether or not to print deprecated options
      */
     static void dumpClassToXml(
             KXmlSerializer serializer,
             String classTypeName,
             Object obj,
             boolean isGenericObject,
-            List<String> excludeClassFilter)
+            List<String> excludeClassFilter,
+            boolean printDeprecatedOptions)
             throws IOException {
         if (excludeClassFilter.contains(classTypeName)) {
             return;
@@ -109,12 +114,12 @@
             serializer.startTag(null, "object");
             serializer.attribute(null, "type", classTypeName);
             serializer.attribute(null, CLASS_NAME, obj.getClass().getName());
-            dumpOptionsToXml(serializer, obj);
+            dumpOptionsToXml(serializer, obj, printDeprecatedOptions);
             serializer.endTag(null, "object");
         } else {
             serializer.startTag(null, classTypeName);
             serializer.attribute(null, CLASS_NAME, obj.getClass().getName());
-            dumpOptionsToXml(serializer, obj);
+            dumpOptionsToXml(serializer, obj, printDeprecatedOptions);
             serializer.endTag(null, classTypeName);
         }
     }
@@ -124,11 +129,19 @@
      *
      * @param serializer a {@link KXmlSerializer} to create the XML dump
      * @param obj {@link Object} to be added to the XML dump
+     * @param printDeprecatedOptions whether or not to skip the deprecated options
      */
     @SuppressWarnings({"rawtypes", "unchecked"})
-    private static void dumpOptionsToXml(KXmlSerializer serializer, Object obj) throws IOException {
+    private static void dumpOptionsToXml(
+            KXmlSerializer serializer, Object obj, boolean printDeprecatedOptions)
+            throws IOException {
         for (Field field : OptionSetter.getOptionFieldsForClass(obj.getClass())) {
             Option option = field.getAnnotation(Option.class);
+            Deprecated deprecatedAnnotation = field.getAnnotation(Deprecated.class);
+            // If enabled, skip @Deprecated options
+            if (!printDeprecatedOptions && deprecatedAnnotation != null) {
+                continue;
+            }
             Object fieldVal = OptionSetter.getFieldValue(field, obj);
             if (fieldVal == null) {
                 continue;
diff --git a/src/com/android/tradefed/config/GlobalConfiguration.java b/src/com/android/tradefed/config/GlobalConfiguration.java
index aac2394..daf6ebc 100644
--- a/src/com/android/tradefed/config/GlobalConfiguration.java
+++ b/src/com/android/tradefed/config/GlobalConfiguration.java
@@ -802,7 +802,7 @@
                 isGenericObject = true;
             }
             ConfigurationUtil.dumpClassToXml(
-                    serializer, config, configObj, isGenericObject, new ArrayList<>());
+                    serializer, config, configObj, isGenericObject, new ArrayList<>(), true);
         }
         serializer.endTag(null, ConfigurationUtil.CONFIGURATION_NAME);
         serializer.endDocument();
diff --git a/src/com/android/tradefed/config/IConfiguration.java b/src/com/android/tradefed/config/IConfiguration.java
index d33127f..a22c7dd 100644
--- a/src/com/android/tradefed/config/IConfiguration.java
+++ b/src/com/android/tradefed/config/IConfiguration.java
@@ -581,4 +581,19 @@
      * @throws IOException
      */
     public void dumpXml(PrintWriter output, List<String> excludeFilters) throws IOException;
+
+    /**
+     * Gets the expanded XML file for the config with all options shown for this {@link
+     * IConfiguration} minus the objects filters by their key name.
+     *
+     * <p>Filter example: {@link Configuration#TARGET_PREPARER_TYPE_NAME}.
+     *
+     * @param output the writer to print the xml to.
+     * @param excludeFilters the list of object type that should not be dumped.
+     * @param printDeprecatedOptions Whether or not to print options marked as deprecated
+     * @throws IOException
+     */
+    public void dumpXml(
+            PrintWriter output, List<String> excludeFilters, boolean printDeprecatedOptions)
+            throws IOException;
 }
diff --git a/src/com/android/tradefed/sandbox/TradefedSandbox.java b/src/com/android/tradefed/sandbox/TradefedSandbox.java
index 0f69ab9..adc1242 100644
--- a/src/com/android/tradefed/sandbox/TradefedSandbox.java
+++ b/src/com/android/tradefed/sandbox/TradefedSandbox.java
@@ -398,7 +398,8 @@
             File tmpParentConfig =
                     FileUtil.createTempFile("parent-config", ".xml", mSandboxTmpFolder);
             PrintWriter pw = new PrintWriter(tmpParentConfig);
-            parentConfig.dumpXml(pw);
+            // Do not print deprecated options to avoid compatibility issues
+            parentConfig.dumpXml(pw, new ArrayList<>(), false);
             return tmpParentConfig;
         } catch (ConfigurationException | IOException e) {
             CLog.e("Parent doesn't understand the command either:");
diff --git a/tests/src/com/android/tradefed/config/ConfigurationUtilTest.java b/tests/src/com/android/tradefed/config/ConfigurationUtilTest.java
index e978ad3..75535e4 100644
--- a/tests/src/com/android/tradefed/config/ConfigurationUtilTest.java
+++ b/tests/src/com/android/tradefed/config/ConfigurationUtilTest.java
@@ -20,8 +20,14 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.command.CommandScheduler;
 import com.android.tradefed.device.DeviceManager;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.targetprep.BuildError;
+import com.android.tradefed.targetprep.ITargetPreparer;
+import com.android.tradefed.targetprep.TargetSetupError;
 import com.android.tradefed.util.FileUtil;
 
 import org.junit.Test;
@@ -41,8 +47,8 @@
     private static final String DEVICE_MANAGER_TYPE_NAME = "device_manager";
 
     /**
-     * Test {@link ConfigurationUtil#dumpClassToXml(KXmlSerializer, String, Object, List)} to create
-     * a dump of a configuration.
+     * Test {@link ConfigurationUtil#dumpClassToXml(KXmlSerializer, String, Object, List, boolean)}
+     * to create a dump of a configuration.
      */
     @Test
     public void testDumpClassToXml() throws Throwable {
@@ -57,7 +63,11 @@
 
             DeviceManager deviceManager = new DeviceManager();
             ConfigurationUtil.dumpClassToXml(
-                    serializer, DEVICE_MANAGER_TYPE_NAME, deviceManager, new ArrayList<String>());
+                    serializer,
+                    DEVICE_MANAGER_TYPE_NAME,
+                    deviceManager,
+                    new ArrayList<String>(),
+                    true);
 
             serializer.endTag(null, ConfigurationUtil.CONFIGURATION_NAME);
             serializer.endDocument();
@@ -77,8 +87,8 @@
     }
 
     /**
-     * Test {@link ConfigurationUtil#dumpClassToXml(KXmlSerializer, String, Object, List)} to create
-     * a dump of a configuration with filters
+     * Test {@link ConfigurationUtil#dumpClassToXml(KXmlSerializer, String, Object, List, boolean)}
+     * to create a dump of a configuration with filters
      */
     @Test
     public void testDumpClassToXml_filtered() throws Throwable {
@@ -96,12 +106,14 @@
                     serializer,
                     GlobalConfiguration.DEVICE_MANAGER_TYPE_NAME,
                     deviceManager,
-                    Arrays.asList("com.android.tradefed.device.DeviceManager"));
+                    Arrays.asList("com.android.tradefed.device.DeviceManager"),
+                    true);
             ConfigurationUtil.dumpClassToXml(
                     serializer,
                     GlobalConfiguration.SCHEDULER_TYPE_NAME,
                     new CommandScheduler(),
-                    Arrays.asList("com.android.tradefed.device.DeviceManager"));
+                    Arrays.asList("com.android.tradefed.device.DeviceManager"),
+                    true);
 
             serializer.endTag(null, ConfigurationUtil.CONFIGURATION_NAME);
             serializer.endDocument();
@@ -236,4 +248,60 @@
             FileUtil.recursiveDelete(tmpDir);
         }
     }
+
+    private class TestTargetPreparer implements ITargetPreparer {
+
+        @Option(name = "real-option")
+        private boolean mReal;
+
+        @Deprecated
+        @Option(name = "deprecated-option")
+        private boolean mDeprecated;
+
+        @Override
+        public void setUp(ITestDevice device, IBuildInfo buildInfo)
+                throws TargetSetupError, BuildError, DeviceNotAvailableException {
+            // Should never be called
+            assertTrue(false);
+        }
+    }
+
+    /** Test that an option annotated with deprecated is properly filtered. */
+    @Test
+    public void testDumpClassToXml_filterDeprecated() throws Throwable {
+        File tmpXml = FileUtil.createTempFile("global_config", ".xml");
+        try {
+            PrintWriter output = new PrintWriter(tmpXml);
+            KXmlSerializer serializer = new KXmlSerializer();
+            serializer.setOutput(output);
+            serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+            serializer.startDocument("UTF-8", null);
+            serializer.startTag(null, ConfigurationUtil.CONFIGURATION_NAME);
+
+            ITargetPreparer preparer = new TestTargetPreparer();
+            ConfigurationUtil.dumpClassToXml(
+                    serializer,
+                    Configuration.TARGET_PREPARER_TYPE_NAME,
+                    preparer,
+                    new ArrayList<String>(),
+                    false);
+
+            serializer.endTag(null, ConfigurationUtil.CONFIGURATION_NAME);
+            serializer.endDocument();
+
+            // Read the dump XML file, make sure configurations can be loaded.
+            String content = FileUtil.readStringFromFile(tmpXml);
+            assertTrue(content.length() > 100);
+            assertTrue(content.contains("<configuration>"));
+            assertTrue(content.contains("<option name=\"real-option\" value=\"false\" />"));
+            // Does not contain any trace of the deprecated option
+            assertFalse(content.contains("deprecated-option"));
+            assertTrue(
+                    content.contains(
+                            "<target_preparer class=\"com.android.tradefed.config."
+                                    + "ConfigurationUtilTest$TestTargetPreparer\">"));
+        } finally {
+            FileUtil.deleteFile(tmpXml);
+        }
+    }
 }
diff --git a/tests/src/com/android/tradefed/config/OptionSetterTest.java b/tests/src/com/android/tradefed/config/OptionSetterTest.java
index 78f73ee..255eb7a 100644
--- a/tests/src/com/android/tradefed/config/OptionSetterTest.java
+++ b/tests/src/com/android/tradefed/config/OptionSetterTest.java
@@ -266,14 +266,6 @@
         private final String mFinal= "foo";
     }
 
-    private static class RemoteFileOption {
-        @Option(name = "remote-file")
-        public File remoteFile = null;
-
-        @Option(name = "remote-file-list")
-        public Collection<File> remoteFileList = new ArrayList<>();
-    }
-
     /**
      * Test creating an {@link OptionSetter} for a source with invalid option type.
      */