summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrett Chabot <brettchabot@android.com>2011-11-01 14:42:34 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2011-11-01 14:42:34 -0700
commit266440ef9b7aee437d971afb688a91b6a48e8cca (patch)
tree2239631dda2700068e755e03053e26094026753d
parentbe92a5c09f66660b78a109a650d1494df3939e12 (diff)
parent770358ebdbafa73653cced292f5f77cdccfbe2aa (diff)
downloadcts-ics-factoryrom-2-release.tar.gz
Merge "Support merging device info metrics." into ics-mr0android-4.0.1_r1.2android-4.0.1_r1.1android-4.0.1_r1ics-factoryrom-2-release
-rw-r--r--tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoConstants.java5
-rw-r--r--tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoInstrument.java4
-rw-r--r--tools/host/src/com/android/cts/TestDevice.java2
-rw-r--r--tools/tradefed-host/.classpath2
-rw-r--r--tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java218
-rw-r--r--tools/tradefed-host/src/com/android/cts/tradefed/result/DeviceInfoResult.java363
-rw-r--r--tools/tradefed-host/src/com/android/cts/tradefed/result/TestResults.java107
-rw-r--r--tools/tradefed-host/src/com/android/cts/tradefed/result/TestSummaryXml.java10
-rw-r--r--tools/tradefed-host/tests/src/com/android/cts/tradefed/result/CtsXmlResultReporterTest.java2
-rw-r--r--tools/tradefed-host/tests/src/com/android/cts/tradefed/result/DeviceInfoResultTest.java147
10 files changed, 625 insertions, 235 deletions
diff --git a/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoConstants.java b/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoConstants.java
index bfe5aaa5b52..57b0dad2ce7 100644
--- a/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoConstants.java
+++ b/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoConstants.java
@@ -40,8 +40,7 @@ public interface DeviceInfoConstants {
public static final String SCREEN_SIZE = "screen_size";
public static final String SCREEN_DENSITY_BUCKET = "screen_density_bucket";
public static final String SCREEN_DENSITY = "screen_density";
- public static final String SCREEN_HEIGHT = "screen_height";
- public static final String SCREEN_WIDTH = "screen_width";
+ public static final String RESOLUTION = "resolution";
public static final String VERSION_SDK = "androidPlatformVersion";
public static final String VERSION_RELEASE = "buildVersion";
public static final String BUILD_ABI = "build_abi";
@@ -57,5 +56,5 @@ public interface DeviceInfoConstants {
public static final String BUILD_ID = "buildID";
public static final String BUILD_VERSION = "buildVersion";
public static final String BUILD_TAGS = "build_tags";
- public static final String SERIAL_NUMBER = "serialNumber";
+ public static final String SERIAL_NUMBER = "deviceID";
}
diff --git a/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoInstrument.java b/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoInstrument.java
index 5ab063d0e19..1b705e7cd4a 100644
--- a/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoInstrument.java
+++ b/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoInstrument.java
@@ -68,6 +68,7 @@ public class DeviceInfoInstrument extends Instrumentation implements DeviceInfoC
addResult(BUILD_FINGERPRINT, Build.FINGERPRINT);
addResult(BUILD_ABI, Build.CPU_ABI);
addResult(BUILD_ABI2, Build.CPU_ABI2);
+ addResult(SERIAL_NUMBER, Build.SERIAL);
addResult(VERSION_RELEASE, Build.VERSION.RELEASE);
addResult(VERSION_SDK, Build.VERSION.SDK);
@@ -77,8 +78,7 @@ public class DeviceInfoInstrument extends Instrumentation implements DeviceInfoC
Context.WINDOW_SERVICE);
Display d = wm.getDefaultDisplay();
d.getMetrics(metrics);
- addResult(SCREEN_WIDTH, metrics.widthPixels);
- addResult(SCREEN_HEIGHT, metrics.heightPixels);
+ addResult(RESOLUTION, String.format("%sx%s", metrics.widthPixels, metrics.heightPixels));
addResult(SCREEN_DENSITY, metrics.density);
addResult(SCREEN_X_DENSITY, metrics.xdpi);
addResult(SCREEN_Y_DENSITY, metrics.ydpi);
diff --git a/tools/host/src/com/android/cts/TestDevice.java b/tools/host/src/com/android/cts/TestDevice.java
index a90f6f11468..dcedc0282c0 100644
--- a/tools/host/src/com/android/cts/TestDevice.java
+++ b/tools/host/src/com/android/cts/TestDevice.java
@@ -682,7 +682,7 @@ public class TestDevice implements DeviceObserver {
* @return The screen resolution.
*/
public String getScreenResolution() {
- return mInfoMap.get(SCREEN_WIDTH) + "x" + mInfoMap.get(SCREEN_HEIGHT);
+ return mInfoMap.get(RESOLUTION);
}
/**
diff --git a/tools/tradefed-host/.classpath b/tools/tradefed-host/.classpath
index 335f3c36a7f..197543c0012 100644
--- a/tools/tradefed-host/.classpath
+++ b/tools/tradefed-host/.classpath
@@ -7,6 +7,6 @@
<classpathentry combineaccessrules="false" kind="src" path="/ddmlib"/>
<classpathentry combineaccessrules="false" kind="src" path="/tradefederation"/>
<classpathentry combineaccessrules="false" kind="src" path="/hosttestlib"/>
- <classpathentry combineaccessrules="false" kind="src" path="/ctsdeviceinfolib"/>
+ <classpathentry combineaccessrules="false" exported="true" kind="src" path="/ctsdeviceinfolib"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
index 2893523741f..11b4b1cbd95 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
@@ -16,10 +16,7 @@
package com.android.cts.tradefed.result;
-import android.tests.getinfo.DeviceInfoConstants;
-
import com.android.cts.tradefed.build.CtsBuildHelper;
-import com.android.cts.tradefed.build.CtsBuildProvider;
import com.android.cts.tradefed.device.DeviceInfoCollector;
import com.android.cts.tradefed.testtype.CtsTest;
import com.android.ddmlib.Log;
@@ -46,9 +43,6 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.HashMap;
import java.util.Map;
/**
@@ -70,12 +64,6 @@ public class CtsXmlResultReporter implements ITestInvocationListener {
/** the XML namespace */
static final String ns = null;
- // XML constants
- static final String SUMMARY_TAG = "Summary";
- static final String PASS_ATTR = "pass";
- static final String TIMEOUT_ATTR = "timeout";
- static final String NOT_EXECUTED_ATTR = "notExecuted";
- static final String FAILED_ATTR = "failed";
static final String RESULT_TAG = "TestResult";
static final String PLAN_ATTR = "testPlan";
@@ -101,6 +89,7 @@ public class CtsXmlResultReporter implements ITestInvocationListener {
private String mDeviceSerial;
private TestResults mResults = new TestResults();
private TestPackageResult mCurrentPkgResult = null;
+ private boolean mIsDeviceInfoRun = false;
public void setReportDir(File reportDir) {
mReportDir = reportDir;
@@ -189,15 +178,18 @@ public class CtsXmlResultReporter implements ITestInvocationListener {
// display results from previous run
logCompleteRun(mCurrentPkgResult);
}
- if (name.equals(DeviceInfoCollector.APP_PACKAGE_NAME)) {
+ mIsDeviceInfoRun = name.equals(DeviceInfoCollector.APP_PACKAGE_NAME);
+ if (mIsDeviceInfoRun) {
logResult("Collecting device info");
- } else if (mCurrentPkgResult == null || !name.equals(
- mCurrentPkgResult.getAppPackageName())) {
- logResult("-----------------------------------------");
- logResult("Test package %s started", name);
- logResult("-----------------------------------------");
+ } else {
+ if (mCurrentPkgResult == null || !name.equals(mCurrentPkgResult.getAppPackageName())) {
+ logResult("-----------------------------------------");
+ logResult("Test package %s started", name);
+ logResult("-----------------------------------------");
+ }
+ mCurrentPkgResult = mResults.getOrCreatePackage(name);
}
- mCurrentPkgResult = mResults.getOrCreatePackage(name);
+
}
/**
@@ -233,7 +225,11 @@ public class CtsXmlResultReporter implements ITestInvocationListener {
*/
@Override
public void testRunEnded(long elapsedTime, Map<String, String> runMetrics) {
- mCurrentPkgResult.populateMetrics(runMetrics);
+ if (mIsDeviceInfoRun) {
+ mResults.populateDeviceInfoMetrics(runMetrics);
+ } else {
+ mCurrentPkgResult.populateMetrics(runMetrics);
+ }
}
/**
@@ -317,194 +313,12 @@ public class CtsXmlResultReporter implements ITestInvocationListener {
serializer.attribute(ns, "endtime", endTime);
serializer.attribute(ns, "version", CTS_RESULT_FILE_VERSION);
- serializeDeviceInfo(serializer);
- serializeHostInfo(serializer);
- serializeTestSummary(serializer);
mResults.serialize(serializer);
// TODO: not sure why, but the serializer doesn't like this statement
//serializer.endTag(ns, RESULT_TAG);
}
/**
- * Output the device info XML.
- *
- * @param serializer
- */
- private void serializeDeviceInfo(KXmlSerializer serializer) throws IOException {
- serializer.startTag(ns, "DeviceInfo");
-
- Map<String, String> deviceInfoMetrics = mResults.getDeviceInfoMetrics();
- if (deviceInfoMetrics == null || deviceInfoMetrics.isEmpty()) {
- // this might be expected, if device info collection was turned off
- CLog.d("Could not find device info");
- return;
- }
-
- // Extract metrics that need extra handling, and then dump the remainder into BuildInfo
- Map<String, String> metricsCopy = new HashMap<String, String>(
- deviceInfoMetrics);
- serializer.startTag(ns, "Screen");
- String screenWidth = metricsCopy.remove(DeviceInfoConstants.SCREEN_WIDTH);
- String screenHeight = metricsCopy.remove(DeviceInfoConstants.SCREEN_HEIGHT);
- serializer.attribute(ns, "resolution", String.format("%sx%s", screenWidth, screenHeight));
- serializer.attribute(ns, DeviceInfoConstants.SCREEN_DENSITY,
- metricsCopy.remove(DeviceInfoConstants.SCREEN_DENSITY));
- serializer.attribute(ns, DeviceInfoConstants.SCREEN_DENSITY_BUCKET,
- metricsCopy.remove(DeviceInfoConstants.SCREEN_DENSITY_BUCKET));
- serializer.attribute(ns, DeviceInfoConstants.SCREEN_SIZE,
- metricsCopy.remove(DeviceInfoConstants.SCREEN_SIZE));
- serializer.endTag(ns, "Screen");
-
- serializer.startTag(ns, "PhoneSubInfo");
- serializer.attribute(ns, "subscriberId", metricsCopy.remove(
- DeviceInfoConstants.PHONE_NUMBER));
- serializer.endTag(ns, "PhoneSubInfo");
-
- String featureData = metricsCopy.remove(DeviceInfoConstants.FEATURES);
- String processData = metricsCopy.remove(DeviceInfoConstants.PROCESSES);
-
- // dump the remaining metrics without translation
- serializer.startTag(ns, "BuildInfo");
- for (Map.Entry<String, String> metricEntry : metricsCopy.entrySet()) {
- serializer.attribute(ns, metricEntry.getKey(), metricEntry.getValue());
- }
- serializer.attribute(ns, "deviceID", mDeviceSerial);
- serializer.endTag(ns, "BuildInfo");
-
- serializeFeatureInfo(serializer, featureData);
- serializeProcessInfo(serializer, processData);
-
- serializer.endTag(ns, "DeviceInfo");
- }
-
- /**
- * Prints XML indicating what features are supported by the device. It parses a string from the
- * featureData argument that is in the form of "feature1:true;feature2:false;featuer3;true;"
- * with a trailing semi-colon.
- *
- * <pre>
- * <FeatureInfo>
- * <Feature name="android.name.of.feature" available="true" />
- * ...
- * </FeatureInfo>
- * </pre>
- *
- * @param serializer used to create XML
- * @param featureData raw unparsed feature data
- */
- private void serializeFeatureInfo(KXmlSerializer serializer, String featureData) throws IOException {
- serializer.startTag(ns, "FeatureInfo");
-
- if (featureData == null) {
- featureData = "";
- }
-
- String[] featurePairs = featureData.split(";");
- for (String featurePair : featurePairs) {
- String[] nameTypeAvailability = featurePair.split(":");
- if (nameTypeAvailability.length >= 3) {
- serializer.startTag(ns, "Feature");
- serializer.attribute(ns, "name", nameTypeAvailability[0]);
- serializer.attribute(ns, "type", nameTypeAvailability[1]);
- serializer.attribute(ns, "available", nameTypeAvailability[2]);
- serializer.endTag(ns, "Feature");
- }
- }
- serializer.endTag(ns, "FeatureInfo");
- }
-
- /**
- * Prints XML data indicating what particular processes of interest were running on the device.
- * It parses a string from the rootProcesses argument that is in the form of
- * "processName1;processName2;..." with a trailing semi-colon.
- *
- * <pre>
- * <ProcessInfo>
- * <Process name="long_cat_viewer" uid="0" />
- * ...
- * </ProcessInfo>
- * </pre>
- */
- private void serializeProcessInfo(KXmlSerializer serializer, String rootProcesses)
- throws IOException {
- serializer.startTag(ns, "ProcessInfo");
-
- if (rootProcesses == null) {
- rootProcesses = "";
- }
-
- String[] processNames = rootProcesses.split(";");
- for (String processName : processNames) {
- processName = processName.trim();
- if (processName.length() > 0) {
- serializer.startTag(ns, "Process");
- serializer.attribute(ns, "name", processName);
- serializer.attribute(ns, "uid", "0");
- serializer.endTag(ns, "Process");
- }
- }
- serializer.endTag(ns, "ProcessInfo");
- }
-
- /**
- * Output the host info XML.
- *
- * @param serializer
- */
- private void serializeHostInfo(KXmlSerializer serializer) throws IOException {
- serializer.startTag(ns, "HostInfo");
-
- String hostName = "";
- try {
- hostName = InetAddress.getLocalHost().getHostName();
- } catch (UnknownHostException ignored) {}
- serializer.attribute(ns, "name", hostName);
-
- serializer.startTag(ns, "Os");
- serializer.attribute(ns, "name", System.getProperty("os.name"));
- serializer.attribute(ns, "version", System.getProperty("os.version"));
- serializer.attribute(ns, "arch", System.getProperty("os.arch"));
- serializer.endTag(ns, "Os");
-
- serializer.startTag(ns, "Java");
- serializer.attribute(ns, "name", System.getProperty("java.vendor"));
- serializer.attribute(ns, "version", System.getProperty("java.version"));
- serializer.endTag(ns, "Java");
-
- serializer.startTag(ns, "Cts");
- serializer.attribute(ns, "version", CtsBuildProvider.CTS_BUILD_VERSION);
- // TODO: consider outputting other tradefed options here
- serializer.startTag(ns, "IntValue");
- serializer.attribute(ns, "name", "testStatusTimeoutMs");
- // TODO: create a constant variable for testStatusTimeoutMs value. Currently it cannot be
- // changed
- serializer.attribute(ns, "value", "600000");
- serializer.endTag(ns, "IntValue");
- serializer.endTag(ns, "Cts");
-
- serializer.endTag(ns, "HostInfo");
- }
-
- /**
- * Output the test summary XML containing summary totals for all tests.
- *
- * @param serializer
- * @throws IOException
- */
- private void serializeTestSummary(KXmlSerializer serializer) throws IOException {
- serializer.startTag(ns, SUMMARY_TAG);
- serializer.attribute(ns, FAILED_ATTR, Integer.toString(mResults.countTests(
- CtsTestStatus.FAIL)));
- serializer.attribute(ns, NOT_EXECUTED_ATTR, Integer.toString(mResults.countTests(
- CtsTestStatus.NOT_EXECUTED)));
- // ignore timeouts - these are reported as errors
- serializer.attribute(ns, TIMEOUT_ATTR, "0");
- serializer.attribute(ns, PASS_ATTR, Integer.toString(mResults.countTests(
- CtsTestStatus.PASS)));
- serializer.endTag(ns, SUMMARY_TAG);
- }
-
- /**
* Creates the output stream to use for test results. Exposed for mocking.
*/
OutputStream createOutputResultStream(File reportDir) throws IOException {
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/DeviceInfoResult.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/DeviceInfoResult.java
new file mode 100644
index 00000000000..102e99886f3
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/DeviceInfoResult.java
@@ -0,0 +1,363 @@
+/*
+ * Copyright (C) 2011 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.result;
+
+import android.tests.getinfo.DeviceInfoConstants;
+
+import com.android.tradefed.log.LogUtil.CLog;
+
+import org.kxml2.io.KXmlSerializer;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Data structure for the device info collected by CTS.
+ * <p/>
+ * Provides methods to serialize and deserialize from XML, as well as checks for consistency
+ * when multiple devices are used to generate the report.
+ */
+class DeviceInfoResult extends AbstractXmlPullParser {
+ static final String TAG = "DeviceInfo";
+ private static final String ns = CtsXmlResultReporter.ns;
+ private static final String BUILD_TAG = "BuildInfo";
+ private static final String PHONE_TAG = "PhoneSubInfo";
+ private static final String SCREEN_TAG = "Screen";
+ private static final String FEATURE_INFO_TAG = "FeatureInfo";
+ private static final String FEATURE_TAG = "Feature";
+ private static final String FEATURE_ATTR_DELIM = ":";
+ private static final String FEATURE_DELIM = ";";
+ private static final String PROCESS_INFO_TAG = "ProcessInfo";
+ private static final String PROCESS_TAG = "Process";
+ private static final String PROCESS_DELIM = ";";
+
+ private Map<String, String> mMetrics = new HashMap<String, String>();
+
+ /**
+ * Serialize this object and all its contents to XML.
+ *
+ * @param serializer
+ * @throws IOException
+ */
+ public void serialize(KXmlSerializer serializer) throws IOException {
+ serializer.startTag(ns, TAG);
+
+ if (!mMetrics.isEmpty()) {
+
+ // Extract metrics that need extra handling, and then dump the remainder into BuildInfo
+ Map<String, String> metricsCopy = new HashMap<String, String>(mMetrics);
+ serializer.startTag(ns, SCREEN_TAG);
+ serializer.attribute(ns, DeviceInfoConstants.RESOLUTION,
+ getMetric(metricsCopy, DeviceInfoConstants.RESOLUTION));
+ serializer.attribute(ns, DeviceInfoConstants.SCREEN_DENSITY,
+ getMetric(metricsCopy, DeviceInfoConstants.SCREEN_DENSITY));
+ serializer.attribute(ns, DeviceInfoConstants.SCREEN_DENSITY_BUCKET,
+ getMetric(metricsCopy, DeviceInfoConstants.SCREEN_DENSITY_BUCKET));
+ serializer.attribute(ns, DeviceInfoConstants.SCREEN_SIZE,
+ getMetric(metricsCopy, DeviceInfoConstants.SCREEN_SIZE));
+ serializer.endTag(ns, SCREEN_TAG);
+
+ serializer.startTag(ns, PHONE_TAG);
+ serializer.attribute(ns, DeviceInfoConstants.PHONE_NUMBER,
+ getMetric(metricsCopy, DeviceInfoConstants.PHONE_NUMBER));
+ serializer.endTag(ns, PHONE_TAG);
+
+ String featureData = getMetric(metricsCopy, DeviceInfoConstants.FEATURES);
+ String processData = getMetric(metricsCopy, DeviceInfoConstants.PROCESSES);
+
+ // dump the remaining metrics without translation
+ serializer.startTag(ns, BUILD_TAG);
+ for (Map.Entry<String, String> metricEntry : metricsCopy.entrySet()) {
+ serializer.attribute(ns, metricEntry.getKey(), metricEntry.getValue());
+ }
+ serializer.endTag(ns, BUILD_TAG);
+
+ serializeFeatureInfo(serializer, featureData);
+ serializeProcessInfo(serializer, processData);
+ } else {
+ // this might be expected, if device info collection was turned off
+ CLog.d("Could not find device info");
+ }
+ serializer.endTag(ns, TAG);
+ }
+
+ /**
+ * Fetch and remove given metric from hashmap.
+ *
+ * @return the metric value or empty string if it was not present in map.
+ */
+ private String getMetric(Map<String, String> metrics, String metricName ) {
+ String value = metrics.remove(metricName);
+ if (value == null) {
+ value = "";
+ }
+ return value;
+ }
+
+ /**
+ * Prints XML indicating what features are supported by the device. It parses a string from the
+ * featureData argument that is in the form of "feature1:true;feature2:false;featuer3;true;"
+ * with a trailing semi-colon.
+ *
+ * <pre>
+ * <FeatureInfo>
+ * <Feature name="android.name.of.feature" available="true" />
+ * ...
+ * </FeatureInfo>
+ * </pre>
+ *
+ * @param serializer used to create XML
+ * @param featureData raw unparsed feature data
+ */
+ private void serializeFeatureInfo(KXmlSerializer serializer, String featureData)
+ throws IOException {
+ serializer.startTag(ns, FEATURE_INFO_TAG);
+
+ if (featureData == null) {
+ featureData = "";
+ }
+
+ String[] featurePairs = featureData.split(FEATURE_DELIM);
+ for (String featurePair : featurePairs) {
+ String[] nameTypeAvailability = featurePair.split(FEATURE_ATTR_DELIM);
+ if (nameTypeAvailability.length >= 3) {
+ serializer.startTag(ns, FEATURE_TAG);
+ serializer.attribute(ns, "name", nameTypeAvailability[0]);
+ serializer.attribute(ns, "type", nameTypeAvailability[1]);
+ serializer.attribute(ns, "available", nameTypeAvailability[2]);
+ serializer.endTag(ns, FEATURE_TAG);
+ }
+ }
+ serializer.endTag(ns, FEATURE_INFO_TAG);
+ }
+
+ /**
+ * Prints XML data indicating what particular processes of interest were running on the device.
+ * It parses a string from the rootProcesses argument that is in the form of
+ * "processName1;processName2;..." with a trailing semi-colon.
+ *
+ * <pre>
+ * <ProcessInfo>
+ * <Process name="long_cat_viewer" uid="0" />
+ * ...
+ * </ProcessInfo>
+ * </pre>
+ */
+ private void serializeProcessInfo(KXmlSerializer serializer, String rootProcesses)
+ throws IOException {
+ serializer.startTag(ns, PROCESS_INFO_TAG);
+
+ if (rootProcesses == null) {
+ rootProcesses = "";
+ }
+
+ String[] processNames = rootProcesses.split(PROCESS_DELIM);
+ for (String processName : processNames) {
+ processName = processName.trim();
+ if (processName.length() > 0) {
+ serializer.startTag(ns, PROCESS_TAG);
+ serializer.attribute(ns, "name", processName);
+ serializer.attribute(ns, "uid", "0");
+ serializer.endTag(ns, PROCESS_TAG);
+ }
+ }
+ serializer.endTag(ns, PROCESS_INFO_TAG);
+ }
+
+ /**
+ * Populates this class with package result data parsed from XML.
+ *
+ * @param parser the {@link XmlPullParser}. Expected to be pointing at start
+ * of a {@link #TAG}
+ */
+ @Override
+ void parse(XmlPullParser parser) throws XmlPullParserException, IOException {
+ if (!parser.getName().equals(TAG)) {
+ throw new XmlPullParserException(String.format(
+ "invalid XML: Expected %s tag but received %s", TAG, parser.getName()));
+ }
+ int eventType = parser.getEventType();
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ if (eventType == XmlPullParser.START_TAG) {
+ if (parser.getName().equals(SCREEN_TAG) ||
+ parser.getName().equals(PHONE_TAG) ||
+ parser.getName().equals(BUILD_TAG)) {
+ addMetricsFromAttributes(parser);
+ } else if (parser.getName().equals(FEATURE_INFO_TAG)) {
+ // store features into metrics map, in the same format as when collected from
+ // device
+ mMetrics.put(DeviceInfoConstants.FEATURES, parseFeatures(parser));
+ } else if (parser.getName().equals(PROCESS_INFO_TAG)) {
+ // store processes into metrics map, in the same format as when collected from
+ // device
+ mMetrics.put(DeviceInfoConstants.PROCESSES, parseProcess(parser));
+ }
+ } else if (eventType == XmlPullParser.END_TAG && parser.getName().equals(TAG)) {
+ return;
+ }
+ eventType = parser.next();
+ }
+ }
+
+ /**
+ * Parse process XML, and return its contents as a delimited String
+ */
+ private String parseProcess(XmlPullParser parser) throws XmlPullParserException, IOException {
+ if (!parser.getName().equals(PROCESS_INFO_TAG)) {
+ throw new XmlPullParserException(String.format(
+ "invalid XML: Expected %s tag but received %s", PROCESS_INFO_TAG,
+ parser.getName()));
+ }
+ StringBuilder processString = new StringBuilder();
+ int eventType = parser.getEventType();
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ if (eventType == XmlPullParser.START_TAG && parser.getName().equals(PROCESS_TAG)) {
+ processString.append(getAttribute(parser, "name"));
+ processString.append(PROCESS_DELIM);
+ } else if (eventType == XmlPullParser.END_TAG && parser.getName().equals(
+ PROCESS_INFO_TAG)) {
+ return processString.toString();
+ }
+ eventType = parser.next();
+ }
+ return processString.toString();
+ }
+
+ /**
+ * Parse feature XML, and return its contents as a delimited String
+ */
+ private String parseFeatures(XmlPullParser parser) throws XmlPullParserException, IOException {
+ if (!parser.getName().equals(FEATURE_INFO_TAG)) {
+ throw new XmlPullParserException(String.format(
+ "invalid XML: Expected %s tag but received %s", FEATURE_INFO_TAG,
+ parser.getName()));
+ }
+ StringBuilder featureString = new StringBuilder();
+ int eventType = parser.getEventType();
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ if (eventType == XmlPullParser.START_TAG && parser.getName().equals(FEATURE_TAG)) {
+ featureString.append(getAttribute(parser, "name"));
+ featureString.append(FEATURE_ATTR_DELIM);
+ featureString.append(getAttribute(parser, "type"));
+ featureString.append(FEATURE_ATTR_DELIM);
+ featureString.append(getAttribute(parser, "available"));
+ featureString.append(FEATURE_DELIM);
+ } else if (eventType == XmlPullParser.END_TAG
+ && parser.getName().equals(FEATURE_INFO_TAG)) {
+ return featureString.toString();
+ }
+ eventType = parser.next();
+ }
+ return featureString.toString();
+
+ }
+
+ /**
+ * Adds all attributes from the current XML tag to metrics as name-value pairs
+ */
+ private void addMetricsFromAttributes(XmlPullParser parser) {
+ int attrCount = parser.getAttributeCount();
+ for (int i = 0; i < attrCount; i++) {
+ mMetrics.put(parser.getAttributeName(i), parser.getAttributeValue(i));
+ }
+ }
+
+ /**
+ * Populate the device info metrics with values collected from device.
+ * <p/>
+ * Check that the provided device info metrics are consistent with the currently stored metrics.
+ * If any inconsistencies occur, logs errors and stores error messages in the metrics map
+ *
+ * @param runResult
+ */
+ public void populateMetrics(Map<String, String> metrics) {
+ if (mMetrics.isEmpty()) {
+ // no special processing needed, no existing metrics
+ mMetrics.putAll(metrics);
+ return;
+ }
+ Map<String, String> metricsCopy = new HashMap<String, String>(
+ metrics);
+ // add values for metrics that might be different across runs
+ combineMetrics(metricsCopy, DeviceInfoConstants.PHONE_NUMBER, DeviceInfoConstants.IMSI,
+ DeviceInfoConstants.IMSI, DeviceInfoConstants.SERIAL_NUMBER);
+
+ // ensure all the metrics we expect to be identical actually are
+ checkMetrics(metricsCopy, DeviceInfoConstants.BUILD_FINGERPRINT,
+ DeviceInfoConstants.BUILD_MODEL, DeviceInfoConstants.BUILD_BRAND,
+ DeviceInfoConstants.BUILD_MANUFACTURER, DeviceInfoConstants.BUILD_BOARD,
+ DeviceInfoConstants.BUILD_DEVICE, DeviceInfoConstants.PRODUCT_NAME,
+ DeviceInfoConstants.BUILD_ABI, DeviceInfoConstants.BUILD_ABI2,
+ DeviceInfoConstants.SCREEN_SIZE);
+ }
+
+ private void combineMetrics(Map<String, String> metrics, String... keysToCombine) {
+ for (String combineKey : keysToCombine) {
+ String currentKeyValue = mMetrics.get(combineKey);
+ String valueToAdd = metrics.remove(combineKey);
+ if (valueToAdd != null) {
+ if (currentKeyValue == null) {
+ // strange - no existing value. Can occur during unit testing
+ mMetrics.put(combineKey, valueToAdd);
+ } else if (!currentKeyValue.equals(valueToAdd)) {
+ // new value! store a comma separated list
+ valueToAdd = String.format("%s,%s", currentKeyValue, valueToAdd);
+ mMetrics.put(combineKey, valueToAdd);
+ } else {
+ // ignore, current value is same as existing
+ }
+
+ } else {
+ CLog.d("Missing metric %s", combineKey);
+ }
+ }
+ }
+
+ private void checkMetrics(Map<String, String> metrics, String... keysToCheck) {
+ Set<String> keyCheckSet = new HashSet<String>();
+ Collections.addAll(keyCheckSet, keysToCheck);
+ for (Map.Entry<String, String> metricEntry : metrics.entrySet()) {
+ String currentValue = mMetrics.get(metricEntry.getKey());
+ if (keyCheckSet.contains(metricEntry.getKey()) && currentValue != null
+ && !metricEntry.getValue().equals(currentValue)) {
+ CLog.e("Inconsistent info collected from devices. "
+ + "Current result has %s='%s', Received '%s'. Are you sharding or " +
+ "resuming a test run across different devices and/or builds?",
+ metricEntry.getKey(), currentValue, metricEntry.getValue());
+ mMetrics.put(metricEntry.getKey(),
+ String.format("ERROR: Inconsistent results: %s, %s",
+ metricEntry.getValue(), currentValue));
+ } else {
+ mMetrics.put(metricEntry.getKey(), metricEntry.getValue());
+ }
+ }
+ }
+
+ /**
+ * Return the currently stored metrics.
+ * <p/>
+ * Exposed for unit testing.
+ */
+ Map<String, String> getMetrics() {
+ return mMetrics;
+ }
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/TestResults.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/TestResults.java
index a8742273a56..2f9eaddaa35 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/result/TestResults.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/TestResults.java
@@ -15,7 +15,7 @@
*/
package com.android.cts.tradefed.result;
-import com.android.cts.tradefed.device.DeviceInfoCollector;
+import com.android.cts.tradefed.build.CtsBuildProvider;
import com.android.tradefed.log.LogUtil.CLog;
import org.kxml2.io.KXmlSerializer;
@@ -23,6 +23,8 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -38,8 +40,18 @@ import java.util.Map;
*/
class TestResults extends AbstractXmlPullParser {
- private Map<String, TestPackageResult> mPackageMap = new LinkedHashMap<String, TestPackageResult>();
- private TestPackageResult mDeviceInfoPkg = new TestPackageResult();
+ private static final String ns = CtsXmlResultReporter.ns;
+
+ // XML constants
+ static final String SUMMARY_TAG = "Summary";
+ static final String PASS_ATTR = "pass";
+ static final String TIMEOUT_ATTR = "timeout";
+ static final String NOT_EXECUTED_ATTR = "notExecuted";
+ static final String FAILED_ATTR = "failed";
+
+ private Map<String, TestPackageResult> mPackageMap =
+ new LinkedHashMap<String, TestPackageResult>();
+ private DeviceInfoResult mDeviceInfo = new DeviceInfoResult();
/**
* {@inheritDoc}
@@ -49,6 +61,10 @@ class TestResults extends AbstractXmlPullParser {
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG && parser.getName().equals(
+ DeviceInfoResult.TAG)) {
+ mDeviceInfo.parse(parser);
+ }
+ if (eventType == XmlPullParser.START_TAG && parser.getName().equals(
TestPackageResult.TAG)) {
TestPackageResult pkg = new TestPackageResult();
pkg.parse(parser);
@@ -83,30 +99,77 @@ class TestResults extends AbstractXmlPullParser {
}
/**
- * @return
+ * Serialize the test results to XML.
+ *
+ * @param serializer
+ * @throws IOException
*/
- public Map<String, String> getDeviceInfoMetrics() {
- return mDeviceInfoPkg.getMetrics();
+ public void serialize(KXmlSerializer serializer) throws IOException {
+ mDeviceInfo.serialize(serializer);
+ serializeHostInfo(serializer);
+ serializeTestSummary(serializer);
+ // sort before serializing
+ List<TestPackageResult> pkgs = new ArrayList<TestPackageResult>(mPackageMap.values());
+ Collections.sort(pkgs, new PkgComparator());
+ for (TestPackageResult r : pkgs) {
+ r.serialize(serializer);
+ }
}
/**
- * @param mCurrentPkgResult
+ * Output the host info XML.
+ *
+ * @param serializer
*/
- public void addPackageResult(TestPackageResult pkgResult) {
- mPackageMap.put(pkgResult.getName(), pkgResult);
+ private void serializeHostInfo(KXmlSerializer serializer) throws IOException {
+ serializer.startTag(ns, "HostInfo");
+
+ String hostName = "";
+ try {
+ hostName = InetAddress.getLocalHost().getHostName();
+ } catch (UnknownHostException ignored) {}
+ serializer.attribute(ns, "name", hostName);
+
+ serializer.startTag(ns, "Os");
+ serializer.attribute(ns, "name", System.getProperty("os.name"));
+ serializer.attribute(ns, "version", System.getProperty("os.version"));
+ serializer.attribute(ns, "arch", System.getProperty("os.arch"));
+ serializer.endTag(ns, "Os");
+
+ serializer.startTag(ns, "Java");
+ serializer.attribute(ns, "name", System.getProperty("java.vendor"));
+ serializer.attribute(ns, "version", System.getProperty("java.version"));
+ serializer.endTag(ns, "Java");
+
+ serializer.startTag(ns, "Cts");
+ serializer.attribute(ns, "version", CtsBuildProvider.CTS_BUILD_VERSION);
+ // TODO: consider outputting other tradefed options here
+ serializer.startTag(ns, "IntValue");
+ serializer.attribute(ns, "name", "testStatusTimeoutMs");
+ // TODO: create a constant variable for testStatusTimeoutMs value. Currently it cannot be
+ // changed
+ serializer.attribute(ns, "value", "600000");
+ serializer.endTag(ns, "IntValue");
+ serializer.endTag(ns, "Cts");
+
+ serializer.endTag(ns, "HostInfo");
}
/**
+ * Output the test summary XML containing summary totals for all tests.
+ *
* @param serializer
* @throws IOException
*/
- public void serialize(KXmlSerializer serializer) throws IOException {
- // sort before serializing
- List<TestPackageResult> pkgs = new ArrayList<TestPackageResult>(mPackageMap.values());
- Collections.sort(pkgs, new PkgComparator());
- for (TestPackageResult r : pkgs) {
- r.serialize(serializer);
- }
+ private void serializeTestSummary(KXmlSerializer serializer) throws IOException {
+ serializer.startTag(ns, SUMMARY_TAG);
+ serializer.attribute(ns, FAILED_ATTR, Integer.toString(countTests(CtsTestStatus.FAIL)));
+ serializer.attribute(ns, NOT_EXECUTED_ATTR,
+ Integer.toString(countTests(CtsTestStatus.NOT_EXECUTED)));
+ // ignore timeouts - these are reported as errors
+ serializer.attribute(ns, TIMEOUT_ATTR, "0");
+ serializer.attribute(ns, PASS_ATTR, Integer.toString(countTests(CtsTestStatus.PASS)));
+ serializer.endTag(ns, SUMMARY_TAG);
}
private static class PkgComparator implements Comparator<TestPackageResult> {
@@ -127,10 +190,6 @@ class TestResults extends AbstractXmlPullParser {
* @return
*/
public TestPackageResult getOrCreatePackage(String appPackageName) {
- if (appPackageName.equals(DeviceInfoCollector.APP_PACKAGE_NAME)) {
- mDeviceInfoPkg.setAppPackageName(DeviceInfoCollector.APP_PACKAGE_NAME);
- return mDeviceInfoPkg ;
- }
TestPackageResult pkgResult = mPackageMap.get(appPackageName);
if (pkgResult == null) {
pkgResult = new TestPackageResult();
@@ -139,4 +198,12 @@ class TestResults extends AbstractXmlPullParser {
}
return pkgResult;
}
+
+ /**
+ * Populate the results with collected device info metrics.
+ * @param runMetrics
+ */
+ public void populateDeviceInfoMetrics(Map<String, String> runMetrics) {
+ mDeviceInfo.populateMetrics(runMetrics);
+ }
}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/TestSummaryXml.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/TestSummaryXml.java
index b91a391683a..4f0b59bff8e 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/result/TestSummaryXml.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/TestSummaryXml.java
@@ -103,11 +103,11 @@ public class TestSummaryXml extends AbstractXmlPullParser implements ITestSummar
CtsXmlResultReporter.RESULT_TAG)) {
mPlan = getAttribute(parser, CtsXmlResultReporter.PLAN_ATTR);
} else if (eventType == XmlPullParser.START_TAG && parser.getName().equals(
- CtsXmlResultReporter.SUMMARY_TAG)) {
- mNumFailed = parseIntAttr(parser, CtsXmlResultReporter.FAILED_ATTR) +
- parseIntAttr(parser, CtsXmlResultReporter.TIMEOUT_ATTR);
- mNumNotExecuted = parseIntAttr(parser, CtsXmlResultReporter.NOT_EXECUTED_ATTR);
- mNumPassed = parseIntAttr(parser, CtsXmlResultReporter.PASS_ATTR);
+ TestResults.SUMMARY_TAG)) {
+ mNumFailed = parseIntAttr(parser, TestResults.FAILED_ATTR) +
+ parseIntAttr(parser, TestResults.TIMEOUT_ATTR);
+ mNumNotExecuted = parseIntAttr(parser, TestResults.NOT_EXECUTED_ATTR);
+ mNumPassed = parseIntAttr(parser, TestResults.PASS_ATTR);
return;
}
eventType = parser.next();
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/result/CtsXmlResultReporterTest.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/result/CtsXmlResultReporterTest.java
index 7566fce9901..dcf013cb047 100644
--- a/tools/tradefed-host/tests/src/com/android/cts/tradefed/result/CtsXmlResultReporterTest.java
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/result/CtsXmlResultReporterTest.java
@@ -145,7 +145,7 @@ public class CtsXmlResultReporterTest extends TestCase {
assertTrue(output.contains(
"<Summary failed=\"1\" notExecuted=\"0\" timeout=\"0\" pass=\"0\" />"));
final String failureTag =
- "<FailedScene message=\"this is a trace\"> <StackTrace>this is a tracemore trace";
+ "<FailedScene message=\"this is a trace\"> <StackTrace>this is a tracemore trace";
assertTrue(output.contains(failureTag));
}
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/result/DeviceInfoResultTest.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/result/DeviceInfoResultTest.java
new file mode 100644
index 00000000000..a0388b2b32a
--- /dev/null
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/result/DeviceInfoResultTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2011 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.result;
+
+import android.tests.getinfo.DeviceInfoConstants;
+
+import junit.framework.TestCase;
+
+import org.kxml2.io.KXmlSerializer;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Unit tests for {@link DeviceInfoResult}
+ */
+public class DeviceInfoResultTest extends TestCase {
+
+ private DeviceInfoResult mDeserializingInfo;
+
+ @Override
+ protected void setUp() throws Exception {
+ mDeserializingInfo = new DeviceInfoResult() {
+ // override parent to advance xml parser to correct tag
+ @Override
+ void parse(XmlPullParser parser) throws XmlPullParserException, IOException {
+ int eventType = parser.getEventType();
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ if (eventType == XmlPullParser.START_TAG && parser.getName().equals(TAG)) {
+ super.parse(parser);
+ return;
+ }
+ eventType = parser.next();
+ }
+ throw new XmlPullParserException(String.format("Could not find tag %s", TAG));
+ }
+ };
+ }
+
+ /**
+ * Test the roundtrip setting of device process details, serializing and parsing from/to XML.
+ */
+ public void testProcess() throws Exception {
+ final String processString = "ueventd;netd;";
+ DeviceInfoResult serializedInfo = new DeviceInfoResult();
+ addMetric(DeviceInfoConstants.PROCESSES, processString, serializedInfo);
+ String serializedOutput = serialize(serializedInfo);
+ mDeserializingInfo.parse(new StringReader(serializedOutput));
+ assertEquals(processString, mDeserializingInfo.getMetrics().get(
+ DeviceInfoConstants.PROCESSES));
+ }
+
+ /**
+ * Test the roundtrip setting of device feature details, serializing and parsing from/to XML.
+ */
+ public void testFeature() throws Exception {
+ final String featureString =
+ "android.hardware.audio.low_latency:sdk:false;android.hardware.bluetooth:sdk:true;";
+ DeviceInfoResult serializedInfo = new DeviceInfoResult();
+ addMetric(DeviceInfoConstants.FEATURES, featureString, serializedInfo);
+ String serializedOutput = serialize(serializedInfo);
+ mDeserializingInfo.parse(new StringReader(serializedOutput));
+ assertEquals(featureString, mDeserializingInfo.getMetrics().get(
+ DeviceInfoConstants.FEATURES));
+ }
+
+ /**
+ * Test populating a combined metric like device serial
+ */
+ public void testPopulateMetrics_combinedSerial() throws Exception {
+ DeviceInfoResult info = new DeviceInfoResult();
+ // first add another metric to make hashmap non empty, so combined logic is triggered
+ addMetric(DeviceInfoConstants.PROCESSES, "proc", info);
+ addMetric(DeviceInfoConstants.SERIAL_NUMBER, "device1", info);
+ // ensure the stored serial number equals the value that was just set
+ assertEquals("device1", info.getMetrics().get(
+ DeviceInfoConstants.SERIAL_NUMBER));
+ // now add it again
+ addMetric(DeviceInfoConstants.SERIAL_NUMBER, "device1", info);
+ // should still equal same value
+ assertEquals("device1", info.getMetrics().get(
+ DeviceInfoConstants.SERIAL_NUMBER));
+ // now store different serial, and expect csv
+ addMetric(DeviceInfoConstants.SERIAL_NUMBER, "device2", info);
+ assertEquals("device1,device2", info.getMetrics().get(
+ DeviceInfoConstants.SERIAL_NUMBER));
+ }
+
+ /**
+ * Test populating a verified-to-be-identical metric like DeviceInfoConstants.BUILD_FINGERPRINT
+ */
+ public void testPopulateMetrics_verify() throws Exception {
+ DeviceInfoResult info = new DeviceInfoResult();
+ addMetric(DeviceInfoConstants.BUILD_FINGERPRINT, "fingerprint1", info);
+ // ensure the stored fingerprint equals the value that was just set
+ assertEquals("fingerprint1", info.getMetrics().get(
+ DeviceInfoConstants.BUILD_FINGERPRINT));
+ // now add it again
+ addMetric(DeviceInfoConstants.BUILD_FINGERPRINT, "fingerprint1", info);
+ // should still equal same value
+ assertEquals("fingerprint1", info.getMetrics().get(
+ DeviceInfoConstants.BUILD_FINGERPRINT));
+ // now store different serial, and expect error message
+ addMetric(DeviceInfoConstants.BUILD_FINGERPRINT, "fingerprint2", info);
+ assertTrue(info.getMetrics().get(
+ DeviceInfoConstants.BUILD_FINGERPRINT).contains("ERROR"));
+ }
+
+ /**
+ * Helper method to add given metric to the {@link DeviceInfoResult}
+ */
+ private void addMetric(String metricName, String metricValue, DeviceInfoResult serializedInfo) {
+ Map<String, String> collectedMetrics = new HashMap<String, String>();
+ collectedMetrics.put(metricName, metricValue);
+ serializedInfo.populateMetrics(collectedMetrics);
+ }
+
+ /**
+ * Helper method to serialize given object to XML
+ */
+ private String serialize(DeviceInfoResult serializedInfo)
+ throws IOException {
+ KXmlSerializer xmlSerializer = new KXmlSerializer();
+ StringWriter serializedOutput = new StringWriter();
+ xmlSerializer.setOutput(serializedOutput);
+ serializedInfo.serialize(xmlSerializer);
+ return serializedOutput.toString();
+ }
+}