Cts Feature/Profile Annotations

Add annotations that allow CTS to be used for multiple device
profiles.

Example is shown in ProfileTest.java.

1. @SupportedProfiles - run the test only if the device's profile is
   the one passed via the "--profile" flag to CTS like:

   startcts --plan CTS --profile HANDHELD
   startcts --plan CTS --profile STB

2. @RequiredFeatures - run the test only if the device's
   PackageManager reports the features needed by the test. For
   instance tag wifi tests with this annotation's value set to
   the wifi feature to only run it on devices that declare the
   feature.

If not specified, the profile will be set to ALL, which means run all
the tests.

This creates an additional library for CTS test annotations, so this
will require a change to the build/core/cts.mk project too. A new
Makefile "CtsHostLibraryList.mk" can be used now to have the host
use additional libraries.

Change-Id: I69d76b65569160648020306fe14c94242d99efc1
diff --git a/CtsHostLibraryList.mk b/CtsHostLibraryList.mk
new file mode 100644
index 0000000..36291d5
--- /dev/null
+++ b/CtsHostLibraryList.mk
@@ -0,0 +1,16 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+CTS_HOST_LIBRARY_JARS := \
+	$(HOST_OUT_JAVA_LIBRARIES)/CtsTestAnnotationsHostLib.jar
diff --git a/development/ide/eclipse/.classpath b/development/ide/eclipse/.classpath
index e9fb45d..59c1521 100644
--- a/development/ide/eclipse/.classpath
+++ b/development/ide/eclipse/.classpath
@@ -2,6 +2,7 @@
 <classpath>
     <classpathentry kind="src" path="cts/apps/CtsVerifier/src"/>
     <classpathentry kind="src" path="cts/apps/CtsVerifier/tests/src"/>
+    <classpathentry kind="src" path="cts/libs/annotation/src"/>
     <classpathentry kind="src" path="cts/tests/ApiDemosReferenceTest/src"/>
     <classpathentry kind="src" path="cts/tests/ProcessTest/src"/>
     <classpathentry kind="src" path="cts/tests/ProcessTest/NoShareUidApp/src"/>
diff --git a/libs/Android.mk b/libs/Android.mk
new file mode 100644
index 0000000..4343259
--- /dev/null
+++ b/libs/Android.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include $(call all-subdir-makefiles)
diff --git a/libs/annotation/Android.mk b/libs/annotation/Android.mk
new file mode 100644
index 0000000..3a4dd82
--- /dev/null
+++ b/libs/annotation/Android.mk
@@ -0,0 +1,30 @@
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Build static Java library for APKs like the CTS tests. 
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_MODULE := CtsTestAnnotationsLib
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# Build the annotations for the host to use.
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_MODULE := CtsTestAnnotationsHostLib
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/libs/annotation/src/android/annotation/cts/Profile.java b/libs/annotation/src/android/annotation/cts/Profile.java
new file mode 100644
index 0000000..35769ad
--- /dev/null
+++ b/libs/annotation/src/android/annotation/cts/Profile.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.annotation.cts;
+
+/**
+ * Profile of the device being tested. Certain tests are applicable only to certain device profiles
+ * when annotated with the {@link SupportedProfiles} annotation and this enum.
+ */
+public enum Profile {
+    ALL,
+    HANDHELD,
+    STB,
+}
diff --git a/libs/annotation/src/android/annotation/cts/RequiredFeatures.java b/libs/annotation/src/android/annotation/cts/RequiredFeatures.java
new file mode 100644
index 0000000..8675b34
--- /dev/null
+++ b/libs/annotation/src/android/annotation/cts/RequiredFeatures.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.annotation.cts;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for specifying what features are needed to run a test. The device must have all the
+ * features specified by the annotation in order to be executed.
+ * <p>
+ * Examples:
+ * <pre>
+ * @RequiredFeatures(PackageManager.FEATURE_WIFI)
+ * @RequiredFeatures({PackageManager.FEATURE_TELEPHONY, PackageManager.FEATURE_TELEPHONY_CDMA})
+ * </pre>
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface RequiredFeatures {
+    String[] value();
+}
diff --git a/libs/annotation/src/android/annotation/cts/SupportedProfiles.java b/libs/annotation/src/android/annotation/cts/SupportedProfiles.java
new file mode 100644
index 0000000..24a9e21
--- /dev/null
+++ b/libs/annotation/src/android/annotation/cts/SupportedProfiles.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.annotation.cts;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for specifying what device profiles are supported by the test. The device's profile
+ * must match one of the profiles specified by the annotation. Not having the annotation means the
+ * test should be executed for all devices.
+ * <p>
+ * Examples:
+ * <pre>
+ * @SupportedProfiles(Profile.HANDHELD)
+ * @SupportedProfiles({Profile.HANDHELD, Profile.STB})
+ * </pre>
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface SupportedProfiles {
+    Profile[] value();
+}
diff --git a/tests/Android.mk b/tests/Android.mk
index 838d01d..bdd8b8a 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -23,6 +23,7 @@
               src/android/os/cts/IEmptyService.aidl
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := CtsTestAnnotationsLib
 
 LOCAL_JNI_SHARED_LIBRARIES := libcts_jni
 
diff --git a/tests/core/ctscore.mk b/tests/core/ctscore.mk
index 337b3f5..33fc6f3 100644
--- a/tests/core/ctscore.mk
+++ b/tests/core/ctscore.mk
@@ -18,6 +18,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 LOCAL_JAVA_LIBRARIES := android.test.runner bouncycastle
+LOCAL_STATIC_JAVA_LIBRARIES := CtsTestAnnotationsLib
 
 LOCAL_PROGUARD_ENABLED := disabled
 
diff --git a/tests/core/runner/Android.mk b/tests/core/runner/Android.mk
index f77bbc7..7658b7a 100644
--- a/tests/core/runner/Android.mk
+++ b/tests/core/runner/Android.mk
@@ -18,9 +18,6 @@
     $(error BUILD_CTSCORE_PACKAGE must be defined)
 endif
 
-#
-# Annotation Tests
-##########################################################
 include $(CLEAR_VARS)
 
 # include this package in the tests target for continuous testing
diff --git a/tests/core/runner/src/android/test/InstrumentationCtsTestRunner.java b/tests/core/runner/src/android/test/InstrumentationCtsTestRunner.java
index 4ca1cc2..660cb0b 100644
--- a/tests/core/runner/src/android/test/InstrumentationCtsTestRunner.java
+++ b/tests/core/runner/src/android/test/InstrumentationCtsTestRunner.java
@@ -22,8 +22,12 @@
 import dalvik.annotation.BrokenTest;
 import dalvik.annotation.SideEffect;
 
+import android.annotation.cts.Profile;
+import android.annotation.cts.RequiredFeatures;
+import android.annotation.cts.SupportedProfiles;
 import android.app.KeyguardManager;
 import android.content.Context;
+import android.content.pm.FeatureInfo;
 import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.test.suitebuilder.TestMethod;
@@ -33,7 +37,10 @@
 import java.io.File;
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 import java.util.TimeZone;
 
 import junit.framework.AssertionFailedError;
@@ -59,11 +66,16 @@
      */
     private static final String TAG = "InstrumentationCtsTestRunner";
 
+    private static final String ARGUMENT_PROFILE = "profile";
+
+    /** Profile of the device being tested or null to run all tests regardless of profile. */
+    private Profile mProfile;
+
     /**
      * True if (and only if) we are running in single-test mode (as opposed to
      * batch mode).
      */
-    private boolean singleTest = false;
+    private boolean mSingleTest = false;
 
     @Override
     public void onCreate(Bundle arguments) {
@@ -84,7 +96,16 @@
 
         if (arguments != null) {
             String classArg = arguments.getString(ARGUMENT_TEST_CLASS);
-            singleTest = classArg != null && classArg.contains("#");
+            mSingleTest = classArg != null && classArg.contains("#");
+
+            String profileArg = arguments.getString(ARGUMENT_PROFILE);
+            if (profileArg != null) {
+                mProfile = Profile.valueOf(profileArg.toUpperCase());
+            } else {
+                mProfile = Profile.ALL;
+            }
+        } else {
+            mProfile = Profile.ALL;
         }
 
         // attempt to disable keyguard,  if current test has permission to do so
@@ -219,14 +240,74 @@
     List<Predicate<TestMethod>> getBuilderRequirements() {
         List<Predicate<TestMethod>> builderRequirements =
                 super.getBuilderRequirements();
+
         Predicate<TestMethod> brokenTestPredicate =
                 Predicates.not(new HasAnnotation(BrokenTest.class));
         builderRequirements.add(brokenTestPredicate);
-        if (!singleTest) {
+
+        builderRequirements.add(getProfilePredicate(mProfile));
+        builderRequirements.add(getFeaturePredicate());
+
+        if (!mSingleTest) {
             Predicate<TestMethod> sideEffectPredicate =
                     Predicates.not(new HasAnnotation(SideEffect.class));
             builderRequirements.add(sideEffectPredicate);
         }
         return builderRequirements;
     }
+
+    private Predicate<TestMethod> getProfilePredicate(final Profile specifiedProfile) {
+        return new Predicate<TestMethod>() {
+            public boolean apply(TestMethod t) {
+                Set<Profile> profiles = new HashSet<Profile>();
+                add(profiles, t.getAnnotation(SupportedProfiles.class));
+                add(profiles, t.getEnclosingClass().getAnnotation(SupportedProfiles.class));
+
+                /*
+                 * Run the test if any of the following conditions are met:
+                 *
+                 * 1. No profile for the device was specified. This means run all tests.
+                 * 2. Specified profile is the ALL profile. This also means run all tests.
+                 * 3. The test does not require a specific type of profile.
+                 * 4. The test specifies that all profiles are supported by the test.
+                 * 5. The test requires a profile which matches the specified profile.
+                 */
+                return specifiedProfile == null
+                        || specifiedProfile == Profile.ALL
+                        || profiles.isEmpty()
+                        || profiles.contains(Profile.ALL)
+                        || profiles.contains(specifiedProfile);
+            }
+
+            private void add(Set<Profile> profiles, SupportedProfiles annotation) {
+                if (annotation != null) {
+                    Collections.addAll(profiles, annotation.value());
+                }
+            }
+        };
+    }
+
+    private Predicate<TestMethod> getFeaturePredicate() {
+        return new Predicate<TestMethod>() {
+            public boolean apply(TestMethod t) {
+                Set<String> features = new HashSet<String>();
+                add(features, t.getAnnotation(RequiredFeatures.class));
+                add(features, t.getEnclosingClass().getAnnotation(RequiredFeatures.class));
+
+                // Run the test only if the device supports all the features.
+                PackageManager packageManager = getContext().getPackageManager();
+                FeatureInfo[] featureInfos = packageManager.getSystemAvailableFeatures();
+                for (FeatureInfo featureInfo : featureInfos) {
+                    features.remove(featureInfo.name);
+                }
+                return features.isEmpty();
+            }
+
+            private void add(Set<String> features, RequiredFeatures annotation) {
+                if (annotation != null) {
+                    Collections.addAll(features, annotation.value());
+                }
+            }
+        };
+    }
 }
diff --git a/tests/tests/app/Android.mk b/tests/tests/app/Android.mk
index 4643b4c..46cd43b 100644
--- a/tests/tests/app/Android.mk
+++ b/tests/tests/app/Android.mk
@@ -22,6 +22,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := CtsTestAnnotationsLib
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
@@ -30,4 +31,3 @@
 LOCAL_INSTRUMENTATION_FOR := CtsTestStubs
 
 include $(BUILD_PACKAGE)
-
diff --git a/tests/tests/app/src/android/app/cts/ProfileFeaturesTest.java b/tests/tests/app/src/android/app/cts/ProfileFeaturesTest.java
new file mode 100644
index 0000000..328300f
--- /dev/null
+++ b/tests/tests/app/src/android/app/cts/ProfileFeaturesTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.cts;
+
+import android.annotation.cts.Profile;
+import android.annotation.cts.RequiredFeatures;
+import android.annotation.cts.SupportedProfiles;
+import android.content.pm.PackageManager;
+import android.test.AndroidTestCase;
+
+/**
+ * Test for checking that devices with different profiles report the correct combination of
+ * features mandated by the CDD.
+ * <p>
+ * It is also currently a demonstration of the {@link SupportedProfiles} and
+ * {@link RequiredFeatures} annotations.
+ */
+public class ProfileFeaturesTest extends AndroidTestCase {
+
+    @SupportedProfiles(Profile.HANDHELD)
+    public void testHandheldFeatures() {
+        // TODO: Add tests to check that this handheld reports a correct combination of features.
+    }
+
+    @SupportedProfiles(Profile.STB)
+    public void testStbFeatures() {
+        // TODO: Add tests to check that the STB reports a correct combination of features.
+    }
+
+    @RequiredFeatures(PackageManager.FEATURE_TELEPHONY_CDMA)
+    public void testRequiredFeatures() {
+        // This is just a demonstration and compilation test of the RequiredFeatures annotation
+        // that can be removed later when the annotation starts being used.
+    }
+}
diff --git a/tools/host/etc/cts b/tools/host/etc/cts
index 77bf822..c368db2 100755
--- a/tools/host/etc/cts
+++ b/tools/host/etc/cts
@@ -20,6 +20,7 @@
 DDMS_LIB=ddmlib.jar
 JUNIT_LIB=junit.jar
 HOSTTEST_LIB=hosttestlib.jar
+CTS_TEST_ANNOTATIONS_HOST_LIB=CtsTestAnnotationsHostLib.jar
 
 # Checking if "adb" is known by the system
 PATH=.:${PATH}
@@ -65,6 +66,7 @@
 ${ANDROID_ROOT}/${JAR_DIR}/${DDMS_LIB}:\
 ${ANDROID_ROOT}/${JAR_DIR}/${JUNIT_LIB}:\
 ${ANDROID_ROOT}/${JAR_DIR}/${HOSTTEST_LIB}:\
+${ANDROID_ROOT}/${JAR_DIR}/${CTS_TEST_ANNOTATIONS_HOST_LIB}:\
 ${ANDROID_ROOT}/${JAR_DIR}/${CTS_LIB}
 # Add path to CTS JAR file in the CTS archive
 CTS_LIBS=${CTS_LIBS}:${CTS_DIR}/${CTS_LIB}
@@ -85,5 +87,6 @@
 fi;
 
 JAVA_OPTS="-Xmx512M"
+JAVA_OPTS="${JAVA_OPTS} -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1337"
 
 java ${JAVA_OPTS} -cp ${CTS_LIBS} -DHOST_CONFIG=${CTS_HOST_CFG} com.android.cts.TestHost "$@"
diff --git a/tools/host/src/Android.mk b/tools/host/src/Android.mk
index 47a9cb8..5ad3998 100644
--- a/tools/host/src/Android.mk
+++ b/tools/host/src/Android.mk
@@ -21,7 +21,7 @@
 
 LOCAL_JAR_MANIFEST := ../etc/manifest.txt
 LOCAL_JAVA_LIBRARIES := \
-    ddmlib-prebuilt junit hosttestlib
+    ddmlib-prebuilt junit hosttestlib CtsTestAnnotationsHostLib
 
 LOCAL_MODULE := cts
 
diff --git a/tools/host/src/com/android/cts/CTSCommand.java b/tools/host/src/com/android/cts/CTSCommand.java
index 7755f5c..88604ff 100644
--- a/tools/host/src/com/android/cts/CTSCommand.java
+++ b/tools/host/src/com/android/cts/CTSCommand.java
@@ -45,4 +45,5 @@
     static final String OPTION_SESSION = "--session";
     static final String OPTION_CFG = "--config";
     static final String OPTION_DERIVED_PLAN = "--derivedplan";
+    static final String OPTION_PROFILE = "--profile";
 }
diff --git a/tools/host/src/com/android/cts/CommandParser.java b/tools/host/src/com/android/cts/CommandParser.java
index 74c3280..4c65317 100644
--- a/tools/host/src/com/android/cts/CommandParser.java
+++ b/tools/host/src/com/android/cts/CommandParser.java
@@ -54,7 +54,8 @@
     private static Set<String> sOptionsSet = new HashSet<String>(Arrays.asList(
             CTSCommand.OPTION_CFG, CTSCommand.OPTION_PACKAGE, CTSCommand.OPTION_PLAN,
             CTSCommand.OPTION_DEVICE, CTSCommand.OPTION_RESULT, CTSCommand.OPTION_E,
-            CTSCommand.OPTION_SESSION, CTSCommand.OPTION_TEST, CTSCommand.OPTION_DERIVED_PLAN));
+            CTSCommand.OPTION_SESSION, CTSCommand.OPTION_TEST, CTSCommand.OPTION_DERIVED_PLAN,
+            CTSCommand.OPTION_PROFILE));
     private static HashMap<String, String> sOptionMap = new HashMap<String, String>();
     static {
         final String[] keys = new String[] {
@@ -71,7 +72,8 @@
                 CTSCommand.OPTION_SESSION,
                 CTSCommand.OPTION_T,
                 CTSCommand.OPTION_TEST,
-                CTSCommand.OPTION_DERIVED_PLAN};
+                CTSCommand.OPTION_DERIVED_PLAN,
+                CTSCommand.OPTION_PROFILE};
 
         final String[] values = new String[] {
                 CTSCommand.OPTION_CFG,
@@ -87,7 +89,8 @@
                 CTSCommand.OPTION_SESSION,
                 CTSCommand.OPTION_TEST,
                 CTSCommand.OPTION_TEST,
-                CTSCommand.OPTION_DERIVED_PLAN};
+                CTSCommand.OPTION_DERIVED_PLAN,
+                CTSCommand.OPTION_PROFILE};
 
         for (int i = 0; i < keys.length; i++) {
             sOptionMap.put(keys[i], values[i]);
diff --git a/tools/host/src/com/android/cts/ConsoleUi.java b/tools/host/src/com/android/cts/ConsoleUi.java
index 951e3e9..702631d 100644
--- a/tools/host/src/com/android/cts/ConsoleUi.java
+++ b/tools/host/src/com/android/cts/ConsoleUi.java
@@ -21,6 +21,8 @@
 
 import org.xml.sax.SAXException;
 
+import android.annotation.cts.Profile;
+
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -253,24 +255,28 @@
         final String testStr = CTSCommand.OPTION_T + "/" + CTSCommand.OPTION_TEST;
         final String deviceStr = CTSCommand.OPTION_D + "/" + CTSCommand.OPTION_DEVICE;
         final String pkgStr = CTSCommand.OPTION_P + "/" + CTSCommand.OPTION_PACKAGE;
+        final String profileOptionStr = "[" + CTSCommand.OPTION_PROFILE + " profile_name]";
 
         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
-                + cmdStr + " test_plan_name: run a test plan");
+                + cmdStr + " test_plan_name " + profileOptionStr
+                + ": run a test plan");
         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
-                + cmdStr + " test_plan_name " + deviceStr + " device_ID: "
-                + "run a test plan using the specified device");
+                + cmdStr + " test_plan_name " + deviceStr + " device_ID " + profileOptionStr
+                +  ": run a test plan using the specified device");
         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
-            + cmdStr + " test_plan_name " + testStr + " test_name: run a specific test");
+                + cmdStr + " test_plan_name " + testStr + " test_name " + profileOptionStr
+                + ": run a specific test");
         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
-                + cmdStr + " test_plan_name " + pkgStr + " java_package_name: "
-                + "run a specific java package");
+                + cmdStr + " test_plan_name " + pkgStr + " java_package_name " + profileOptionStr
+                + ": run a specific java package");
         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
                 + cmdStr + " test_plan_name " + testStr + " test_name "
-                + deviceStr + " device_ID: run a specific test using the specified device");
+                + deviceStr + " device_ID " + profileOptionStr
+                + ": run a specific test using the specified device");
         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
                 + cmdStr + " test_plan_name " + pkgStr + " java_package_name "
-                + deviceStr + " device_ID: "
-                + "run a specific java package using the specified device");
+                + deviceStr + " device_ID " + profileOptionStr
+                + ": run a specific java package using the specified device");
     }
 
     /**
@@ -357,7 +363,7 @@
     private void processStartPackageCommand(CommandParser cp) {
         try {
             String pathName = cp.getValue(CTSCommand.OPTION_PACKAGE);
-            mHost.startZippedPackage(pathName);
+            mHost.startZippedPackage(pathName, getProfile(cp));
         } catch (DeviceDisconnectedException e) {
           Log.e("Device " + e.getMessage() + " disconnected", e);
         } catch (Exception e) {
@@ -387,6 +393,9 @@
         } else if (isValidCommandOption(cp, CTSCommand.START,
                 CTSCommand.OPTION_P)) {
             return true;
+        } else if (isValidCommandOption(cp, CTSCommand.START,
+                CTSCommand.OPTION_PROFILE)) {
+            return true;
         } else {
             return false;
         }
@@ -414,10 +423,12 @@
      *            start --plan plan-name
      *              [ --device device-id ]
      *              [ --test test-name ]
+     *              [ --profile profile-name ]
      *     <li> Syntax 2:
      *            start --plan plan-name
      *              [ --device device-id ]
      *              [ --package java-package-name ]
+     *              [ --profile profile-name ]
      * </ul>
      * @param cp container which contained start command options and values
      *           Process the list commands.
@@ -430,6 +441,8 @@
             return;
         }
 
+        Profile profile = getProfile(cp);
+
         String testPlanPath = null;
         String deviceId = null;
         String testName = null;
@@ -471,7 +484,7 @@
                 if ((testName == null) || (testName.length() == 0)) {
                     String mode = chooseMode(sessionList);
                     if (CREATE_SESSION.equals(mode)) {
-                        ts = TestHost.createSession(testPlanName);
+                        ts = TestHost.createSession(testPlanName, profile);
                     }
                 }
                 if (ts == null) {
@@ -509,8 +522,9 @@
             }
 
             if (ts == null) {
-                ts = TestHost.createSession(testPlanName);
+                ts = TestHost.createSession(testPlanName, profile);
             }
+
             mHost.startSession(ts, deviceId, testName, javaPkgName, actionType);
         } catch (IOException e) {
             Log.e("Can't create test session", e);
@@ -535,6 +549,15 @@
         }
     }
 
+    private Profile getProfile(CommandParser cp) {
+        String profileOption = cp.getValue(CTSCommand.OPTION_PROFILE);
+        if (profileOption != null) {
+            return Profile.valueOf(profileOption.toUpperCase());
+        } else {
+            return Profile.ALL;
+        }
+    }
+
     /**
      * Choose test session among the available test session list.
      *
@@ -1174,11 +1197,11 @@
     private void listResults() {
         Collection<TestSession> sessions = mHost.getSessions();
         if (sessions.isEmpty()) {
-            CUIOutputStream.println("There isn't any test result!");
+            CUIOutputStream.println("There aren't any test results!");
         } else {
             CUIOutputStream.println("List of all results: ");
-            CUIOutputStream.println(
-                    "Session\t\tTest result\t\t\t\tStart time\t\tEnd time\t\tTest plan name");
+            CUIOutputStream.println("Session\t\tTest result\t\t\t\tStart time\t\tEnd time\t"
+                    + "\tProfile\tTest plan name\t");
             CUIOutputStream.println("\t\tPass\tFail\tTimeout\tNotExecuted");
 
             for (TestSession session : sessions) {
@@ -1202,7 +1225,10 @@
                     HostUtils.getFormattedTimeString(log.getEndTime().getTime(), " ", ".", ":");
                 CUIOutputStream.println(Long.toString(session.getId()) + "\t\t"
                         + resStr + "\t\t" + startTimeStr
-                        + "\t" + endTimeStr + "\t" + log.getTestPlanName());
+                        + "\t" + endTimeStr
+                        + "\t" + log.getProfile().name()
+                        + "\t" + log.getTestPlanName());
+
             }
         }
     }
diff --git a/tools/host/src/com/android/cts/HostSideOnlyPackage.java b/tools/host/src/com/android/cts/HostSideOnlyPackage.java
index 0dab280..144be06 100644
--- a/tools/host/src/com/android/cts/HostSideOnlyPackage.java
+++ b/tools/host/src/com/android/cts/HostSideOnlyPackage.java
@@ -16,6 +16,8 @@
 
 package com.android.cts;
 
+import android.annotation.cts.Profile;
+
 import java.io.IOException;
 
 /**
@@ -47,12 +49,12 @@
 
     /** {@inheritDoc} */
     @Override
-    protected void runImpl(final String javaPkgName)
+    protected void runImpl(final String javaPkgName, Profile profile)
             throws IOException, DeviceDisconnectedException, ADBServerNeedRestartException {
         try {
             if (!mTestStop) {
                 Log.d("run in individual mode...");
-                runInIndividualMode(javaPkgName);
+                runInIndividualMode(javaPkgName, profile);
             }
         } catch (DeviceDisconnectedException e) {
             cleanUp();
@@ -62,12 +64,12 @@
 
     /** {@inheritDoc} */
     @Override
-    protected void runTestImpl(final Test test) throws DeviceDisconnectedException,
+    protected void runTestImpl(final Test test, Profile profile) throws DeviceDisconnectedException,
                 ADBServerNeedRestartException {
         try {
             if (!mTestStop) {
                 mCurrentTestSuite = test.getTestSuite();
-                mCurrentTestSuite.run(mDevice, test);
+                mCurrentTestSuite.run(mDevice, test, profile);
             }
         } catch (DeviceDisconnectedException e) {
             cleanUp();
diff --git a/tools/host/src/com/android/cts/HostSideOnlyTest.java b/tools/host/src/com/android/cts/HostSideOnlyTest.java
index 187fc53..5318834 100644
--- a/tools/host/src/com/android/cts/HostSideOnlyTest.java
+++ b/tools/host/src/com/android/cts/HostSideOnlyTest.java
@@ -16,6 +16,8 @@
 
 package com.android.cts;
 
+import android.annotation.cts.Profile;
+
 import java.io.IOException;
 
 import junit.framework.TestResult;
@@ -77,7 +79,7 @@
 
     /** {@inheritDoc} */
     @Override
-    protected void runImpl() {
+    protected void runImpl(Profile profile) {
         mHostSideTestRunner = new HostSideTestRunner(this);
         mHostSideTestRunner.start();
     }
diff --git a/tools/host/src/com/android/cts/ReferenceAppTestPackage.java b/tools/host/src/com/android/cts/ReferenceAppTestPackage.java
index 6b91ab4..d48708f 100644
--- a/tools/host/src/com/android/cts/ReferenceAppTestPackage.java
+++ b/tools/host/src/com/android/cts/ReferenceAppTestPackage.java
@@ -23,6 +23,8 @@
 import com.android.ddmlib.log.LogReceiver.ILogListener;
 import com.android.ddmlib.log.LogReceiver.LogEntry;
 
+import android.annotation.cts.Profile;
+
 import java.awt.image.BufferedImage;
 import java.io.File;
 import java.io.IOException;
@@ -79,8 +81,8 @@
      */
     @Override
     public void run(final TestDevice device, final String javaPkgName,
-                    TestSessionLog testSessionLog) throws DeviceDisconnectedException,
-                    InvalidApkPathException, InvalidNameSpaceException {
+            TestSessionLog testSessionLog) throws DeviceDisconnectedException,
+            InvalidApkPathException, InvalidNameSpaceException {
         Test test = getTests().iterator().next();
         if ((test != null) && (test.getResult().isNotExecuted())) {
             String appToTestApkPath =
diff --git a/tools/host/src/com/android/cts/SignatureCheckPackage.java b/tools/host/src/com/android/cts/SignatureCheckPackage.java
index e4bba3d..8692c9d 100644
--- a/tools/host/src/com/android/cts/SignatureCheckPackage.java
+++ b/tools/host/src/com/android/cts/SignatureCheckPackage.java
@@ -18,6 +18,8 @@
 
 import com.android.ddmlib.MultiLineReceiver;
 
+import android.annotation.cts.Profile;
+
 import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -73,9 +75,8 @@
      */
     @Override
     public void run(final TestDevice device, final String javaPkgName,
-            TestSessionLog testSesssionLog)
-            throws DeviceDisconnectedException, InvalidNameSpaceException,
-            InvalidApkPathException {
+            TestSessionLog testSesssionLog) throws DeviceDisconnectedException,
+            InvalidNameSpaceException, InvalidApkPathException {
         Test test = getTests().iterator().next();
         if ((test != null) && (test.getResult().isNotExecuted())) {
 
diff --git a/tools/host/src/com/android/cts/Test.java b/tools/host/src/com/android/cts/Test.java
index 9e3f0bd..00411a0 100644
--- a/tools/host/src/com/android/cts/Test.java
+++ b/tools/host/src/com/android/cts/Test.java
@@ -16,10 +16,12 @@
 
 package com.android.cts;
 
-import java.util.TimerTask;
-
 import com.android.cts.TestSession.ResultObserver;
 
+import android.annotation.cts.Profile;
+
+import java.util.TimerTask;
+
 /**
  * Correspond to junit's test method, provide functions on storing
  * and executing a test from CTS test harness.
@@ -316,8 +318,9 @@
      * Run the test over device given.
      *
      * @param device the device to run the test.
+     * @param profile The profile of the device being tested.
      */
-    public void run(final TestDevice device) throws DeviceDisconnectedException,
+    public void run(final TestDevice device, Profile profile) throws DeviceDisconnectedException,
             ADBServerNeedRestartException {
 
         if ((getName() == null) || (getName().length() == 0)) {
@@ -342,7 +345,7 @@
         String testFullName = getFullName();
         print(testFullName + "...");
 
-        runImpl();
+        runImpl(profile);
 
         synchronized (mTimeOutTimer) {
             if (!mTestStop) {
@@ -369,8 +372,8 @@
     /**
      * Implementation of running test.
      */
-    protected void runImpl() throws DeviceDisconnectedException {
-        mDevice.runTest(this);
+    protected void runImpl(Profile profile) throws DeviceDisconnectedException {
+        mDevice.runTest(this, profile);
     }
 
     /**
diff --git a/tools/host/src/com/android/cts/TestCase.java b/tools/host/src/com/android/cts/TestCase.java
index 799dc15..bc4f14b 100644
--- a/tools/host/src/com/android/cts/TestCase.java
+++ b/tools/host/src/com/android/cts/TestCase.java
@@ -16,6 +16,8 @@
 
 package com.android.cts;
 
+import android.annotation.cts.Profile;
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
@@ -190,15 +192,16 @@
      * Run the test case over device given.
      *
      * @param device The device to run the test case over.
+     * @param profile The profile of the device being tested.
      */
-    public void run(final TestDevice device) throws DeviceDisconnectedException,
+    public void run(final TestDevice device, Profile profile) throws DeviceDisconnectedException,
             ADBServerNeedRestartException {
         mTestStop = false;
         Iterator<Test> tests = getTests().iterator();
         while (tests.hasNext() && (!mTestStop)) {
             mCurrentTest = tests.next();
             if (mCurrentTest.getResult().isNotExecuted()) {
-                mCurrentTest.run(device);
+                mCurrentTest.run(device, profile);
             }
         }
     }
@@ -208,12 +211,13 @@
      *
      * @param device The device to run the test over.
      * @param test The specific test to be run.
+     * @param profile The profile of the device being tested.
      */
-    public void run(final TestDevice device, final Test test)
+    public void run(final TestDevice device, final Test test, Profile profile)
             throws DeviceDisconnectedException, ADBServerNeedRestartException {
         mTestStop = false;
         mCurrentTest = test;
-        mCurrentTest.run(device);
+        mCurrentTest.run(device, profile);
     }
 
     /** {@inheritDoc} */
diff --git a/tools/host/src/com/android/cts/TestDevice.java b/tools/host/src/com/android/cts/TestDevice.java
index 5fd00b4..3eb40fc 100644
--- a/tools/host/src/com/android/cts/TestDevice.java
+++ b/tools/host/src/com/android/cts/TestDevice.java
@@ -32,6 +32,8 @@
 import com.android.ddmlib.log.LogReceiver;
 import com.android.ddmlib.log.LogReceiver.ILogListener;
 
+import android.annotation.cts.Profile;
+
 import java.io.BufferedReader;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -844,7 +846,7 @@
      *
      * @param test The test to be run.
      */
-    public void runTest(Test test) throws DeviceDisconnectedException {
+    public void runTest(Test test, Profile profile) throws DeviceDisconnectedException {
 
         final String appNameSpace = test.getAppNameSpace();
         String runner = test.getInstrumentationRunner();
@@ -856,8 +858,8 @@
         // passed through two shells \\\$ -> \$ -> $
         final String testName = test.getFullName().replaceAll("\\$", "\\\\\\$");
 
-        final String commandStr = "am instrument -w -r -e class "
-                + testName + " " + appNameSpace + "/" + runner;
+        final String commandStr = "am instrument -w -r -e class " + testName
+                + " -e profile " + profile + " " + appNameSpace + "/" + runner;
         Log.d(commandStr);
         executeShellCommand(commandStr, new IndividualModeResultParser(test));
     }
@@ -869,7 +871,7 @@
      * @param javaPkgName The java package name. If null, run the whole test package;
      *              else, run the specified java package contained in the test package
      */
-    public void runInBatchMode(TestPackage testPackage, final String javaPkgName)
+    public void runInBatchMode(TestPackage testPackage, final String javaPkgName, Profile profile)
                 throws DeviceDisconnectedException {
         String appNameSpace = testPackage.getAppNameSpace();
         String runner = testPackage.getInstrumentationRunner();
@@ -882,7 +884,8 @@
             name = javaPkgName;
         }
 
-        String cmdHeader = "am instrument -w -r -e package " + name + " ";
+        String cmdHeader = "am instrument -w -r -e package " + name
+                + " -e profile " + profile + " ";
         final String commandStr = cmdHeader + appNameSpace + "/" + runner;
         Log.d(commandStr);
 
@@ -896,8 +899,8 @@
      * @param testPackage The testPackage to be run.
      * @param javaClassName The java class name.
      */
-    public void runTestCaseInBatchMode(TestPackage testPackage, final String javaClassName)
-                throws DeviceDisconnectedException {
+    public void runTestCaseInBatchMode(TestPackage testPackage, final String javaClassName,
+            String profile) throws DeviceDisconnectedException {
         if (javaClassName == null) {
             return;
         }
@@ -908,7 +911,8 @@
             runner = DEFAULT_TEST_RUNNER_NAME;
         }
 
-        String cmdHeader = "am instrument -w -r -e class " + javaClassName + " ";
+        String cmdHeader = "am instrument -w -r -e class " + javaClassName
+                + " -e profile " + profile + " ";
         final String commandStr = cmdHeader + appNameSpace + "/" + runner;
         Log.d(commandStr);
 
@@ -1242,7 +1246,7 @@
             mResultLines = new ArrayList<String>();
             mStackTrace = null;
             mFailedMsg = null;
-            mResultCode = CtsTestResult.CODE_PASS;
+            mResultCode = CtsTestResult.CODE_NOT_EXECUTED;
         }
 
         /** {@inheritDoc} */
diff --git a/tools/host/src/com/android/cts/TestHost.java b/tools/host/src/com/android/cts/TestHost.java
index 90dc97f..c721e4b 100644
--- a/tools/host/src/com/android/cts/TestHost.java
+++ b/tools/host/src/com/android/cts/TestHost.java
@@ -16,6 +16,14 @@
 
 package com.android.cts;
 
+import com.android.cts.HostConfig.CaseRepository;
+import com.android.cts.HostConfig.PlanRepository;
+import com.android.ddmlib.AndroidDebugBridge;
+
+import org.xml.sax.SAXException;
+
+import android.annotation.cts.Profile;
+
 import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -31,12 +39,6 @@
 import javax.xml.transform.TransformerException;
 import javax.xml.transform.TransformerFactoryConfigurationError;
 
-import org.xml.sax.SAXException;
-
-import com.android.cts.HostConfig.CaseRepository;
-import com.android.cts.HostConfig.PlanRepository;
-import com.android.ddmlib.AndroidDebugBridge;
-
 /**
  * Act as the host for the device connections, also provides management of
  * sessions.
@@ -135,8 +137,9 @@
      * Start zipped package.
      *
      * @param pathName  The path name of the zipped package.
+     * @param profile  The profile of the device being tested.
      */
-    public void startZippedPackage(final String pathName)
+    public void startZippedPackage(final String pathName, Profile profile)
                 throws FileNotFoundException,
                        IOException,
                        ParserConfigurationException,
@@ -168,7 +171,7 @@
 
         // step 3: start the plan
         TestSession ts = startSession(TEMP_PLAN_NAME, getFirstAvailableDevice().getSerialNumber(),
-                null);
+                null, profile);
 
         // step 4: copy the resulting zip file
         String resultName = pathName.substring(0, pathName.lastIndexOf("."))
@@ -445,8 +448,8 @@
      * @param type The action type to activate the test session.
      */
     static private void runTest(final TestSession ts, final String deviceId,
-            final String testFullName, final String javaPkgName, ActionType type) throws
-            DeviceNotAvailableException, TestNotFoundException, IllegalTestNameException,
+            final String testFullName, final String javaPkgName, ActionType type)
+            throws DeviceNotAvailableException, TestNotFoundException, IllegalTestNameException,
             DeviceDisconnectedException, InvalidNameSpaceException,
             InvalidApkPathException {
 
@@ -509,12 +512,12 @@
      * @param testPlanName the name of the specified test plan
      * @return a {@link TestSession}
      */
-    static public TestSession createSession(final String testPlanName)
+    static public TestSession createSession(final String testPlanName, Profile profile)
             throws IOException, TestNotFoundException, SAXException,
             ParserConfigurationException, TestPlanNotFoundException, NoSuchAlgorithmException {
 
         String testPlanPath = sConfig.getPlanRepository().getPlanPath(testPlanName);
-        TestSession ts = TestSessionBuilder.getInstance().build(testPlanPath);
+        TestSession ts = TestSessionBuilder.getInstance().build(testPlanPath, profile);
         sSessions.add(ts);
 
         return ts;
@@ -635,17 +638,18 @@
      *
      * @param testPlanName TestPlan config file name
      * @param deviceId Target device ID
+     * @param profile The profile of the device being tested.
      * @param javaPkgName The specific java package name to be run.
      */
     public TestSession startSession(final String testPlanName,
-            String deviceId, final String javaPkgName)
+            String deviceId, final String javaPkgName, Profile profile)
             throws IOException, DeviceNotAvailableException,
             TestNotFoundException, SAXException, ParserConfigurationException,
             TestPlanNotFoundException, IllegalTestNameException,
             DeviceDisconnectedException, NoSuchAlgorithmException,
             InvalidNameSpaceException, InvalidApkPathException {
 
-        TestSession ts = createSession(testPlanName);
+        TestSession ts = createSession(testPlanName, profile);
         if ((javaPkgName != null) && (javaPkgName.length() != 0)) {
             runTest(ts, deviceId, null, javaPkgName, ActionType.RUN_SINGLE_JAVA_PACKAGE);
         } else {
diff --git a/tools/host/src/com/android/cts/TestPackage.java b/tools/host/src/com/android/cts/TestPackage.java
index 3f21e56..db1e449 100644
--- a/tools/host/src/com/android/cts/TestPackage.java
+++ b/tools/host/src/com/android/cts/TestPackage.java
@@ -16,6 +16,10 @@
 
 package com.android.cts;
 
+import com.android.cts.TestSession.TestSessionThread;
+
+import android.annotation.cts.Profile;
+
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.security.MessageDigest;
@@ -26,8 +30,6 @@
 import java.util.List;
 import java.util.TimerTask;
 
-import com.android.cts.TestSession.TestSessionThread;
-
 /**
  * Correspond to an APK, provide functions on
  * representing and executing an APK from CTS test harness.
@@ -549,7 +551,7 @@
                 mCurrentTest = null;
             }
             // restart the timer even for unexpected tests
-            mTimeOutTimer.restart(new TimeOutTask(this), 
+            mTimeOutTimer.restart(new TimeOutTask(this),
                     HostConfig.Ints.testStatusTimeoutMs.value());
         }
     }
@@ -803,12 +805,12 @@
      */
     private boolean supportsBatchMode() {
         Collection<Test> tests = getTests();
-        
+
         // check whether the package is small enough for batch mode
         if (tests.size() > HostConfig.Ints.maxTestsInBatchMode.value()) {
             return false;
         }
-        
+
         for (Test test : tests) {
             if (!test.getResult().isNotExecuted()) {
                 // if any test has been run, use individual mode
@@ -850,8 +852,9 @@
      *
      * @param javaPkgName The java package name. If null, run the whole package;
      *              else, run the specified java package contained in this package
+     * @param profile The profile of the device being tested.
      */
-    private void runInBatchMode(final String javaPkgName)
+    private void runInBatchMode(final String javaPkgName, Profile profile)
             throws DeviceDisconnectedException {
         mTimeOutTimer = new HostTimer(new TimeOutTask(this),
                 HostConfig.Ints.batchStartTimeoutMs.value());
@@ -859,10 +862,10 @@
         mProgressObserver = new ProgressObserver();
 
         if ((javaPkgName != null) && (javaPkgName.length() > 0)) {
-            runInBatchModeImpl(javaPkgName);
+            runInBatchModeImpl(javaPkgName, profile);
         } else {
             for (String pkgName : getPackageNames()) {
-                runInBatchModeImpl(pkgName);
+                runInBatchModeImpl(pkgName, profile);
             }
         }
     }
@@ -871,9 +874,11 @@
      * Implementation of running in batch mode.
      *
      * @param javaPkgName The java package name.
+     * @param profile The profile of the device being tested.
      */
-    private void runInBatchModeImpl(String javaPkgName) throws DeviceDisconnectedException {
-        mDevice.runInBatchMode(this, javaPkgName);
+    private void runInBatchModeImpl(String javaPkgName, Profile profile)
+            throws DeviceDisconnectedException {
+        mDevice.runInBatchMode(this, javaPkgName, profile);
 
         synchronized (mTimeOutTimer) {
             if (!mTestStop) {
@@ -899,13 +904,14 @@
      * Run this package in individual mode.
      *
      * @param javaPkgName The java package name.
+     * @param profile The profile of the device being tested.
      */
-    protected void runInIndividualMode(final String javaPkgName) throws IOException,
+    protected void runInIndividualMode(final String javaPkgName, Profile profile) throws IOException,
                     DeviceDisconnectedException, ADBServerNeedRestartException {
         Iterator<TestSuite> suites = getTestSuites().iterator();
         while (suites.hasNext() && (!mTestStop)) {
             mCurrentTestSuite = suites.next();
-            mCurrentTestSuite.run(mDevice, javaPkgName);
+            mCurrentTestSuite.run(mDevice, javaPkgName, profile);
         }
     }
 
@@ -994,15 +1000,16 @@
         }
 
         setup(device, javaPkgName);
-        runImpl(javaPkgName);
+        runImpl(javaPkgName, sessionLog.getProfile());
     }
 
     /**
      * Implementation of running the test package.
      *
      * @param javaPkgName The JAVA package name.
+     * @param profile The profile of the device being tested.
      */
-    protected void runImpl(final String javaPkgName) throws IOException,
+    protected void runImpl(final String javaPkgName, Profile profile) throws IOException,
             DeviceDisconnectedException, ADBServerNeedRestartException, InvalidApkPathException,
             InvalidNameSpaceException {
         try {
@@ -1019,15 +1026,15 @@
                 if (supportsBatchMode()) {
                     mIsInBatchMode = true;
                     Log.d("run in batch mode...");
-                    runInBatchMode(javaPkgName);
+                    runInBatchMode(javaPkgName, profile);
                     if (!isAllTestsRun()) {
                         mIsInBatchMode = false;
                         Log.d("run in individual mode");
-                        runInIndividualMode(javaPkgName);
+                        runInIndividualMode(javaPkgName, profile);
                     }
                 } else {
                     Log.d("run in individual mode...");
-                    runInIndividualMode(javaPkgName);
+                    runInIndividualMode(javaPkgName, profile);
                 }
             }
 
@@ -1091,8 +1098,9 @@
      *
      * @param device The device to run the specific test.
      * @param test The specific test to be run.
+     * @param profile The profile of the device being tested.
      */
-    public void runTest(final TestDevice device, final Test test)
+    public void runTest(final TestDevice device, final Test test, Profile profile)
             throws DeviceDisconnectedException, ADBServerNeedRestartException,
             InvalidApkPathException, InvalidNameSpaceException {
 
@@ -1107,15 +1115,16 @@
         println("Test package: " + getAppPackageName());
         setTestDevice(device);
 
-        runTestImpl(test);
+        runTestImpl(test, profile);
     }
 
     /**
      * Implementation of running test.
      *
      * @param test The test to be run.
+     * @param profile The profile of the device being tested.
      */
-    protected void runTestImpl(final Test test) throws DeviceDisconnectedException,
+    protected void runTestImpl(final Test test, Profile profile) throws DeviceDisconnectedException,
             ADBServerNeedRestartException, InvalidApkPathException,
             InvalidNameSpaceException {
         try {
@@ -1126,7 +1135,7 @@
             if (!mTestStop) {
                 Log.d("install " + getAppPackageName() + " succeed!");
                 mCurrentTestSuite = test.getTestSuite();
-                mCurrentTestSuite.run(mDevice, test);
+                mCurrentTestSuite.run(mDevice, test, profile);
             }
 
             if (!mTestStop) {
diff --git a/tools/host/src/com/android/cts/TestSession.java b/tools/host/src/com/android/cts/TestSession.java
index 3a159e2..cbd2aba 100644
--- a/tools/host/src/com/android/cts/TestSession.java
+++ b/tools/host/src/com/android/cts/TestSession.java
@@ -16,6 +16,8 @@
 
 package com.android.cts;
 
+import android.annotation.cts.Profile;
+
 import java.io.IOException;
 import java.util.Collection;
 
@@ -396,7 +398,7 @@
                 if (mTest != null) {
                     TestPackage pkg = mTest.getTestPackage();
                     pkg.setSessionThread(this);
-                    pkg.runTest(mDevice, mTest);
+                    pkg.runTest(mDevice, mTest, mSessionLog.getProfile());
                 } else if (mTestPackage != null) {
                     mTestPackage.setSessionThread(this);
                     mTestPackage.run(mDevice, mJavaPackageName, mSessionLog);
diff --git a/tools/host/src/com/android/cts/TestSessionBuilder.java b/tools/host/src/com/android/cts/TestSessionBuilder.java
index b4e69f1..6ea996d 100644
--- a/tools/host/src/com/android/cts/TestSessionBuilder.java
+++ b/tools/host/src/com/android/cts/TestSessionBuilder.java
@@ -15,6 +15,13 @@
  */
 package com.android.cts;
 
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import android.annotation.cts.Profile;
+
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -29,11 +36,6 @@
 import javax.xml.transform.TransformerException;
 import javax.xml.transform.TransformerFactoryConfigurationError;
 
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
-
 /**
  * Builder of test plan and also provides serialization for a test plan.
  */
@@ -101,7 +103,7 @@
      * @param config TestPlan XML configuration file.
      * @return TestSession.
      */
-    public TestSession build(final String config) throws SAXException, IOException,
+    public TestSession build(final String config, Profile profile) throws SAXException, IOException,
             TestPlanNotFoundException, TestNotFoundException, NoSuchAlgorithmException {
         File file = new File(config);
         if (!file.exists()) {
@@ -133,7 +135,7 @@
             planName = planFileName;
         }
 
-        TestSessionLog sessionLog = new TestSessionLog(packages, planName);
+        TestSessionLog sessionLog = new TestSessionLog(packages, planName, profile);
         TestSession ts = new TestSession(sessionLog, numOfRequiredDevices);
         return ts;
     }
diff --git a/tools/host/src/com/android/cts/TestSessionLog.java b/tools/host/src/com/android/cts/TestSessionLog.java
index 6164a15..d3f836a 100644
--- a/tools/host/src/com/android/cts/TestSessionLog.java
+++ b/tools/host/src/com/android/cts/TestSessionLog.java
@@ -22,6 +22,8 @@
 import org.w3c.dom.Node;
 import org.w3c.dom.ProcessingInstruction;
 
+import android.annotation.cts.Profile;
+
 import java.io.File;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
@@ -46,11 +48,12 @@
     private static final String ATTRIBUTE_KNOWN_FAILURE = "KnownFailure";
 
     public static final String CTS_RESULT_FILE_NAME = "testResult.xml";
-    private static final String CTS_RESULT_FILE_VERSION = "1.5";
+    private static final String CTS_RESULT_FILE_VERSION = "1.6";
 
     static final String ATTRIBUTE_STARTTIME = "starttime";
     static final String ATTRIBUTE_ENDTIME = "endtime";
     static final String ATTRIBUTE_TESTPLAN = "testPlan";
+    static final String ATTRIBUTE_PROFILE = "profile";
     static final String ATTRIBUTE_RESOLUTION = "resolution";
     static final String ATTRIBUTE_SUBSCRIBER_ID = "subscriberId";
     static final String ATTRIBUTE_DEVICE_ID = "deviceID";
@@ -107,14 +110,17 @@
     private String mResultPath;
     private String mResultDir;
     private String mTestPlanName;
+    private Profile mProfile;
 
     private ArrayList<DeviceParameterCollector> mDeviceParameterBase;
 
-    public TestSessionLog(final Collection<TestPackage> packages, final String testPlanName) {
+    public TestSessionLog(final Collection<TestPackage> packages, final String testPlanName,
+            final Profile profile) {
         mTestPackages = packages;
 
         mDeviceParameterBase = new ArrayList<TestDevice.DeviceParameterCollector>();
         mTestPlanName = testPlanName;
+        mProfile = profile;
 
         mSessionStartTime = new Date();
         mSessionEndTime = new Date();
@@ -130,6 +136,15 @@
     }
 
     /**
+     * Get the profile.
+     *
+     * @return The profile
+     */
+    public Profile getProfile() {
+        return mProfile;
+    }
+
+    /**
      * Get all result of this session.
      *
      * @return All the tests with a result code of this session.
@@ -284,6 +299,7 @@
             setAttribute(doc, root, ATTRIBUTE_STARTTIME, HostUtils.dateToString(mSessionStartTime));
             setAttribute(doc, root, ATTRIBUTE_ENDTIME, HostUtils.dateToString(mSessionEndTime));
             setAttribute(doc, root, ATTRIBUTE_TESTPLAN, mTestPlanName);
+            setAttribute(doc, root, ATTRIBUTE_PROFILE, mProfile.name());
 
             // set device information
             for (int i = 0; i < mDeviceParameterBase.size(); i ++) {
diff --git a/tools/host/src/com/android/cts/TestSessionLogBuilder.java b/tools/host/src/com/android/cts/TestSessionLogBuilder.java
index c2285ee..68bab03 100644
--- a/tools/host/src/com/android/cts/TestSessionLogBuilder.java
+++ b/tools/host/src/com/android/cts/TestSessionLogBuilder.java
@@ -30,6 +30,8 @@
 import org.w3c.dom.NodeList;
 import org.xml.sax.SAXException;
 
+import android.annotation.cts.Profile;
+
 /**
  * Builder of test session from the test result XML file.
  */
@@ -90,7 +92,10 @@
         String start = getStringAttributeValue(resultNode, TestSessionLog.ATTRIBUTE_STARTTIME);
         String end = getStringAttributeValue(resultNode, TestSessionLog.ATTRIBUTE_ENDTIME);
         String planFilePath = HostConfig.getInstance().getPlanRepository().getPlanPath(planName);
-        TestSession sessionFromPlan = TestSessionBuilder.getInstance().build(planFilePath);
+        String profileOption = getStringAttributeValue(resultNode,
+                TestSessionLog.ATTRIBUTE_PROFILE);
+        Profile profile = Profile.valueOf(profileOption);
+        TestSession sessionFromPlan = TestSessionBuilder.getInstance().build(planFilePath, profile);
 
         NodeList pkgList = resultNode.getChildNodes();
         for (int i = 0; i < pkgList.getLength(); i++) {
@@ -124,7 +129,7 @@
             }
         }
 
-        TestSessionLog log = new TestSessionLog(pkgsFromPlan, planName);
+        TestSessionLog log = new TestSessionLog(pkgsFromPlan, planName, profile);
         try {
             log.setStartTime(HostUtils.dateFromString(start).getTime());
             log.setEndTime(HostUtils.dateFromString(end).getTime());
diff --git a/tools/host/src/com/android/cts/TestSuite.java b/tools/host/src/com/android/cts/TestSuite.java
index 136fc3f..f1efc60 100644
--- a/tools/host/src/com/android/cts/TestSuite.java
+++ b/tools/host/src/com/android/cts/TestSuite.java
@@ -16,6 +16,8 @@
 
 package com.android.cts;
 
+import android.annotation.cts.Profile;
+
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -267,8 +269,9 @@
      *
      * @param device The device to run the test over.
      * @param javaPkgName The java package name.
+     * @param profile The profile of the device being tested.
      */
-    public void run(final TestDevice device, final String javaPkgName)
+    public void run(final TestDevice device, final String javaPkgName, Profile profile)
             throws IOException, DeviceDisconnectedException, ADBServerNeedRestartException {
         Iterator<TestSuite> subSuites = getSubSuites().iterator();
         Iterator<TestCase> testCases = getTestCases().iterator();
@@ -279,7 +282,7 @@
 
         while (subSuites.hasNext() && (!mTestStop)) {
             mCurrentSubSuite = subSuites.next();
-            mCurrentSubSuite.run(device, javaPkgName);
+            mCurrentSubSuite.run(device, javaPkgName, profile);
         }
 
         while (testCases.hasNext() && (!mTestStop)) {
@@ -287,7 +290,7 @@
             String fullName = mFullName + "." + mCurrentTestCase.getName();
             if ((javaPkgName == null) || (javaPkgName.length() == 0)
                     || fullName.startsWith(javaPkgName)) {
-                mCurrentTestCase.run(device);
+                mCurrentTestCase.run(device, profile);
             }
         }
     }
@@ -297,15 +300,16 @@
      *
      * @param device The device to run the test over.
      * @param test The specific test to be run.
+     * @param profile The profile of the device being tested.
      */
-    public void run(final TestDevice device, final Test test)
+    public void run(final TestDevice device, final Test test, Profile profile)
             throws DeviceDisconnectedException, ADBServerNeedRestartException {
         mTestStop = false;
         mCurrentTestCase = null;
         mCurrentSubSuite = null;
 
         mCurrentTestCase = test.getTestCase();
-        mCurrentTestCase.run(device, test);
+        mCurrentTestCase.run(device, test, profile);
     }
 
     /** {@inheritDoc} */
diff --git a/tools/host/src/res/cts_result.xsl b/tools/host/src/res/cts_result.xsl
index 12e482a..bd99c8d 100644
--- a/tools/host/src/res/cts_result.xsl
+++ b/tools/host/src/res/cts_result.xsl
@@ -263,6 +263,12 @@
                                         </TD>
                                     </TR>
                                     <TR>
+                                        <TD class="rowtitle">Profile</TD>
+                                        <TD>
+                                            <xsl:value-of select="TestResult/@profile"/>
+                                        </TD>
+                                    </TR>
+                                    <TR>
                                         <TD class="rowtitle">Start time</TD>
                                         <TD>
                                             <xsl:value-of select="TestResult/@starttime"/>
diff --git a/tools/utils/buildCts.py b/tools/utils/buildCts.py
index 35a3a11..7d4b6e0 100755
--- a/tools/utils/buildCts.py
+++ b/tools/utils/buildCts.py
@@ -97,6 +97,7 @@
         'libcore/junit/src/main/java',          # junit classes
         'development/tools/hosttestlib/src',    # hosttestlib TestCase extensions
         'libcore/dalvik/src/main/java',         # test annotations
+        'cts/libs/annotation/src',              # cts annotations
         'cts/tests/src',                        # cts test stubs
         source_root                             # the source for this package
     ]
diff --git a/tools/utils/startcts b/tools/utils/startcts
index a4c97f8..c648125 100755
--- a/tools/utils/startcts
+++ b/tools/utils/startcts
@@ -53,6 +53,7 @@
 CTS_LIB=${CTS_ROOT}/tools/cts.jar
 JUNIT_LIB=${CTS_ROOT}/tools/junit.jar
 HOSTTEST_LIB=${CTS_ROOT}/tools/hosttestlib.jar
+CTS_TEST_ANNOTATIONS_HOST_LIB=${CTS_ROOT}/tools/CtsTestAnnotationsHostLib.jar
 ADB_PATH=${SDK_ROOT}/tools
 ADB_EXE=${ADB_PATH}/adb
 
@@ -62,7 +63,7 @@
 checkFile ${HOSTTEST_LIB}
 checkFile ${ADB_EXE}
 
-JARS=${CTS_LIB}:${DDM_LIB}:${JUNIT_LIB}:${HOSTTEST_LIB}
+JARS=${CTS_LIB}:${DDM_LIB}:${JUNIT_LIB}:${HOSTTEST_LIB}:${CTS_TEST_ANNOTATIONS_HOST_LIB}
 
 PATH=${ADB_PATH}:${PATH}