Merge changes from topic "sts-sdk" into main

* changes:
  Add placeholders necessary for translation
  Add task descriptions
  Add STS SDK run configurations
  Properly config AppTests
  Add NDK test and ABI-specific support
  Remove old STS SDK
  Initial STS SDK example
  Initial STS SDK plugin
diff --git a/libraries/sts-common-util/sts-sdk/Android.bp b/libraries/sts-common-util/sts-sdk/Android.bp
deleted file mode 100644
index 0d56bc9..0000000
--- a/libraries/sts-common-util/sts-sdk/Android.bp
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright (C) 2024 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 {
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-filegroup {
-    name: "sts-sdk-samples-srcs",
-    srcs: [
-        "package/**/*",
-    ],
-    exclude_srcs: [
-        "package/**/.*",
-    ],
-}
-
-genrule {
-    name: "sts-sdk-samples.zip-gen",
-    srcs: [
-        ":sts-sdk-samples-srcs",
-    ],
-    out: ["sts-sdk-samples.zip"],
-    tools: [
-        "soong_zip",
-    ],
-    product_variables: {
-        platform_sdk_version: {
-            cmd: "mkdir -p $(genDir)/tmp/ " +
-                "&& cp -rf platform_testing/libraries/sts-common-util/sts-sdk/package/* $(genDir)/tmp/" +
-                "&& mv $(genDir)/tmp/dotidea $(genDir)/tmp/.idea && " +
-                "for tmplfile in $$(find $(genDir)/tmp/ -type f -iname *.template); do " +
-                "  echo $${tmplfile}; " +
-                "  sed -i 's~{{PLATFORM_SDK_VERSION}}~%d~g' $${tmplfile}; " +
-                "  mv $${tmplfile} $${tmplfile/.template/}; " +
-                "done && " +
-                "$(location soong_zip) -o $(out) -C $(genDir)/tmp -D $(genDir)/tmp -D $(genDir)/tmp/.idea",
-        },
-    },
-}
-
-prebuilt_etc {
-    name: "sts-sdk-samples.zip",
-    src: ":sts-sdk-samples.zip-gen",
-}
diff --git a/libraries/sts-common-util/sts-sdk/example/.gitignore b/libraries/sts-common-util/sts-sdk/example/.gitignore
new file mode 100644
index 0000000..1ffc05a
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/example/.gitignore
@@ -0,0 +1,14 @@
+# Ignore Gradle project-specific cache directory
+.gradle
+
+# Ignore Gradle build output directory
+build
+
+# Ignore Gradle local properties
+local.properties
+
+# Ignore Idea workspace files
+.idea
+
+# ignore cmake builds
+*.cxx
diff --git a/libraries/sts-common-util/sts-sdk/package/dotidea/runConfigurations/assemble_STS_arm.xml b/libraries/sts-common-util/sts-sdk/example/.run/assembleStsSdkSubmissionZip.run.xml
similarity index 70%
rename from libraries/sts-common-util/sts-sdk/package/dotidea/runConfigurations/assemble_STS_arm.xml
rename to libraries/sts-common-util/sts-sdk/example/.run/assembleStsSdkSubmissionZip.run.xml
index c79a3b0..7885f4a 100644
--- a/libraries/sts-common-util/sts-sdk/package/dotidea/runConfigurations/assemble_STS_arm.xml
+++ b/libraries/sts-common-util/sts-sdk/example/.run/assembleStsSdkSubmissionZip.run.xml
@@ -1,8 +1,8 @@
 <component name="ProjectRunConfigurationManager">
-  <configuration default="false" name="assembleStsArm" type="GradleRunConfiguration" factoryName="Gradle">
+  <configuration default="false" name="assembleStsSdkSubmissionZip" type="GradleRunConfiguration" factoryName="Gradle">
     <ExternalSystemSettings>
       <option name="executionName" />
-      <option name="externalProjectPath" value="$PROJECT_DIR$" />
+      <option name="externalProjectPath" value="$PROJECT_DIR$/submission" />
       <option name="externalSystemIdString" value="GRADLE" />
       <option name="scriptParameters" value="" />
       <option name="taskDescriptions">
@@ -10,7 +10,7 @@
       </option>
       <option name="taskNames">
         <list>
-          <option value="assembleStsARM" />
+          <option value="assembleStsSdkSubmissionZip" />
         </list>
       </option>
       <option name="vmOptions" />
@@ -18,6 +18,7 @@
     <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
     <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
     <DebugAllEnabled>false</DebugAllEnabled>
+    <RunAsTest>false</RunAsTest>
     <method v="2" />
   </configuration>
-</component>
+</component>
\ No newline at end of file
diff --git a/libraries/sts-common-util/sts-sdk/package/dotidea/runConfigurations/assemble_STS_arm.xml b/libraries/sts-common-util/sts-sdk/example/.run/assembleSubmissionSources.run.xml
similarity index 70%
copy from libraries/sts-common-util/sts-sdk/package/dotidea/runConfigurations/assemble_STS_arm.xml
copy to libraries/sts-common-util/sts-sdk/example/.run/assembleSubmissionSources.run.xml
index c79a3b0..471d1af 100644
--- a/libraries/sts-common-util/sts-sdk/package/dotidea/runConfigurations/assemble_STS_arm.xml
+++ b/libraries/sts-common-util/sts-sdk/example/.run/assembleSubmissionSources.run.xml
@@ -1,8 +1,8 @@
 <component name="ProjectRunConfigurationManager">
-  <configuration default="false" name="assembleStsArm" type="GradleRunConfiguration" factoryName="Gradle">
+  <configuration default="false" name="assembleSubmissionSources" type="GradleRunConfiguration" factoryName="Gradle">
     <ExternalSystemSettings>
       <option name="executionName" />
-      <option name="externalProjectPath" value="$PROJECT_DIR$" />
+      <option name="externalProjectPath" value="$PROJECT_DIR$/submission" />
       <option name="externalSystemIdString" value="GRADLE" />
       <option name="scriptParameters" value="" />
       <option name="taskDescriptions">
@@ -10,7 +10,7 @@
       </option>
       <option name="taskNames">
         <list>
-          <option value="assembleStsARM" />
+          <option value="assembStsSdkSubmissionSources" />
         </list>
       </option>
       <option name="vmOptions" />
@@ -18,6 +18,7 @@
     <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
     <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
     <DebugAllEnabled>false</DebugAllEnabled>
+    <RunAsTest>false</RunAsTest>
     <method v="2" />
   </configuration>
-</component>
+</component>
\ No newline at end of file
diff --git a/libraries/sts-common-util/sts-sdk/package/dotidea/runConfigurations/assemble_STS_arm.xml b/libraries/sts-common-util/sts-sdk/example/.run/copyInvocationResultsToSubmission.run.xml
similarity index 69%
copy from libraries/sts-common-util/sts-sdk/package/dotidea/runConfigurations/assemble_STS_arm.xml
copy to libraries/sts-common-util/sts-sdk/example/.run/copyInvocationResultsToSubmission.run.xml
index c79a3b0..45ee95c 100644
--- a/libraries/sts-common-util/sts-sdk/package/dotidea/runConfigurations/assemble_STS_arm.xml
+++ b/libraries/sts-common-util/sts-sdk/example/.run/copyInvocationResultsToSubmission.run.xml
@@ -1,8 +1,8 @@
 <component name="ProjectRunConfigurationManager">
-  <configuration default="false" name="assembleStsArm" type="GradleRunConfiguration" factoryName="Gradle">
+  <configuration default="false" name="copyInvocationResultsToSubmission" type="GradleRunConfiguration" factoryName="Gradle">
     <ExternalSystemSettings>
       <option name="executionName" />
-      <option name="externalProjectPath" value="$PROJECT_DIR$" />
+      <option name="externalProjectPath" value="$PROJECT_DIR$/submission" />
       <option name="externalSystemIdString" value="GRADLE" />
       <option name="scriptParameters" value="" />
       <option name="taskDescriptions">
@@ -10,7 +10,7 @@
       </option>
       <option name="taskNames">
         <list>
-          <option value="assembleStsARM" />
+          <option value="copyInvocationResultsToSubmission" />
         </list>
       </option>
       <option name="vmOptions" />
@@ -18,6 +18,7 @@
     <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
     <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
     <DebugAllEnabled>false</DebugAllEnabled>
+    <RunAsTest>false</RunAsTest>
     <method v="2" />
   </configuration>
-</component>
+</component>
\ No newline at end of file
diff --git a/libraries/sts-common-util/sts-sdk/example/.run/sts-tradefed_linux_nonroot_arm64.run.xml b/libraries/sts-common-util/sts-sdk/example/.run/sts-tradefed_linux_nonroot_arm64.run.xml
new file mode 100644
index 0000000..201d016
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/example/.run/sts-tradefed_linux_nonroot_arm64.run.xml
@@ -0,0 +1,19 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="sts-tradefed_linux_nonroot_arm64" type="ShConfigurationType">
+    <option name="SCRIPT_TEXT" value="" />
+    <option name="INDEPENDENT_SCRIPT_PATH" value="true" />
+    <option name="SCRIPT_PATH" value="$PROJECT_DIR$/submission/build/test_suites_arm64/android-sts/tools/sts-tradefed" />
+    <option name="SCRIPT_OPTIONS" value="run commandAndExit sts-sdk-nonroot --log-level debug --log-level-display debug" />
+    <option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
+    <option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
+    <option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
+    <option name="INTERPRETER_PATH" value="/bin/bash" />
+    <option name="INTERPRETER_OPTIONS" value="" />
+    <option name="EXECUTE_IN_TERMINAL" value="true" />
+    <option name="EXECUTE_SCRIPT_FILE" value="true" />
+    <envs />
+    <method v="2">
+      <option name="Gradle.BeforeRunTask" enabled="false" tasks="assembleStsSdkTradefed-test_suites_arm64" externalProjectPath="$PROJECT_DIR$/submission" vmOptions="" scriptParameters="" />
+    </method>
+  </configuration>
+</component>
\ No newline at end of file
diff --git a/libraries/sts-common-util/sts-sdk/example/.run/sts-tradefed_linux_nonroot_x86_64.run.xml b/libraries/sts-common-util/sts-sdk/example/.run/sts-tradefed_linux_nonroot_x86_64.run.xml
new file mode 100644
index 0000000..ba31166
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/example/.run/sts-tradefed_linux_nonroot_x86_64.run.xml
@@ -0,0 +1,19 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="sts-tradefed_linux_nonroot_x86_64" type="ShConfigurationType">
+    <option name="SCRIPT_TEXT" value="" />
+    <option name="INDEPENDENT_SCRIPT_PATH" value="true" />
+    <option name="SCRIPT_PATH" value="$PROJECT_DIR$/submission/build/test_suites_x86_64/android-sts/tools/sts-tradefed" />
+    <option name="SCRIPT_OPTIONS" value="run commandAndExit sts-sdk-nonroot --log-level debug --log-level-display debug" />
+    <option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
+    <option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
+    <option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
+    <option name="INTERPRETER_PATH" value="/bin/bash" />
+    <option name="INTERPRETER_OPTIONS" value="" />
+    <option name="EXECUTE_IN_TERMINAL" value="true" />
+    <option name="EXECUTE_SCRIPT_FILE" value="true" />
+    <envs />
+    <method v="2">
+      <option name="Gradle.BeforeRunTask" enabled="false" tasks="assembleStsSdkTradefed-test_suites_x86_64" externalProjectPath="$PROJECT_DIR$/submission" vmOptions="" scriptParameters="" />
+    </method>
+  </configuration>
+</component>
\ No newline at end of file
diff --git a/libraries/sts-common-util/sts-sdk/example/.run/sts-tradefed_linux_root_arm64.run.xml b/libraries/sts-common-util/sts-sdk/example/.run/sts-tradefed_linux_root_arm64.run.xml
new file mode 100644
index 0000000..3b7e642
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/example/.run/sts-tradefed_linux_root_arm64.run.xml
@@ -0,0 +1,19 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="sts-tradefed_linux_root_arm64" type="ShConfigurationType">
+    <option name="SCRIPT_TEXT" value="" />
+    <option name="INDEPENDENT_SCRIPT_PATH" value="true" />
+    <option name="SCRIPT_PATH" value="$PROJECT_DIR$/submission/build/test_suites_arm64/android-sts/tools/sts-tradefed" />
+    <option name="SCRIPT_OPTIONS" value="run commandAndExit sts-sdk-root --log-level debug --log-level-display debug" />
+    <option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
+    <option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
+    <option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
+    <option name="INTERPRETER_PATH" value="/bin/bash" />
+    <option name="INTERPRETER_OPTIONS" value="" />
+    <option name="EXECUTE_IN_TERMINAL" value="true" />
+    <option name="EXECUTE_SCRIPT_FILE" value="true" />
+    <envs />
+    <method v="2">
+      <option name="Gradle.BeforeRunTask" enabled="true" tasks="assembleStsSdkTradefed-test_suites_arm64" externalProjectPath="$PROJECT_DIR$/submission" vmOptions="" scriptParameters="" />
+    </method>
+  </configuration>
+</component>
\ No newline at end of file
diff --git a/libraries/sts-common-util/sts-sdk/example/.run/sts-tradefed_linux_root_x86_64.run.xml b/libraries/sts-common-util/sts-sdk/example/.run/sts-tradefed_linux_root_x86_64.run.xml
new file mode 100644
index 0000000..9c2a0cd
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/example/.run/sts-tradefed_linux_root_x86_64.run.xml
@@ -0,0 +1,19 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="sts-tradefed_linux_root_x86_64" type="ShConfigurationType">
+    <option name="SCRIPT_TEXT" value="" />
+    <option name="INDEPENDENT_SCRIPT_PATH" value="true" />
+    <option name="SCRIPT_PATH" value="$PROJECT_DIR$/submission/build/test_suites_x86_64/android-sts/tools/sts-tradefed" />
+    <option name="SCRIPT_OPTIONS" value="run commandAndExit sts-sdk-root --log-level debug --log-level-display debug" />
+    <option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
+    <option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
+    <option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
+    <option name="INTERPRETER_PATH" value="/bin/bash" />
+    <option name="INTERPRETER_OPTIONS" value="" />
+    <option name="EXECUTE_IN_TERMINAL" value="true" />
+    <option name="EXECUTE_SCRIPT_FILE" value="true" />
+    <envs />
+    <method v="2">
+      <option name="Gradle.BeforeRunTask" enabled="true" tasks="assembleStsSdkTradefed-test_suites_x86_64" externalProjectPath="$PROJECT_DIR$/submission" vmOptions="" scriptParameters="" />
+    </method>
+  </configuration>
+</component>
\ No newline at end of file
diff --git a/libraries/sts-common-util/sts-sdk/example/gradle.properties b/libraries/sts-common-util/sts-sdk/example/gradle.properties
new file mode 100644
index 0000000..cc18a0c
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/example/gradle.properties
@@ -0,0 +1,3 @@
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+android.useAndroidX=true
+android.enableJetifier=true
diff --git a/libraries/sts-common-util/sts-sdk/example/gradle/wrapper/gradle-wrapper.jar b/libraries/sts-common-util/sts-sdk/example/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..033e24c
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/example/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/libraries/sts-common-util/sts-sdk/package/gradle/wrapper/gradle-wrapper.properties b/libraries/sts-common-util/sts-sdk/example/gradle/wrapper/gradle-wrapper.properties
similarity index 74%
copy from libraries/sts-common-util/sts-sdk/package/gradle/wrapper/gradle-wrapper.properties
copy to libraries/sts-common-util/sts-sdk/example/gradle/wrapper/gradle-wrapper.properties
index 48c8d88..62f495d 100644
--- a/libraries/sts-common-util/sts-sdk/package/gradle/wrapper/gradle-wrapper.properties
+++ b/libraries/sts-common-util/sts-sdk/example/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,7 @@
-#Wed Jun 29 11:41:03 PDT 2022
 distributionBase=GRADLE_USER_HOME
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
 distributionPath=wrapper/dists
-zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
 zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/libraries/sts-common-util/sts-sdk/example/gradlew b/libraries/sts-common-util/sts-sdk/example/gradlew
new file mode 100755
index 0000000..fcb6fca
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/example/gradlew
@@ -0,0 +1,248 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# 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
+#
+#      https://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.
+#
+
+##############################################################################
+#
+#   Gradle start up script for POSIX generated by Gradle.
+#
+#   Important for running:
+#
+#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+#       noncompliant, but you have some other compliant shell such as ksh or
+#       bash, then to run this script, type that shell name before the whole
+#       command line, like:
+#
+#           ksh Gradle
+#
+#       Busybox and similar reduced shells will NOT work, because this script
+#       requires all of these POSIX shell features:
+#         * functions;
+#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+#         * compound commands having a testable exit status, especially «case»;
+#         * various built-in commands including «command», «set», and «ulimit».
+#
+#   Important for patching:
+#
+#   (2) This script targets any POSIX shell, so it avoids extensions provided
+#       by Bash, Ksh, etc; in particular arrays are avoided.
+#
+#       The "traditional" practice of packing multiple parameters into a
+#       space-separated string is a well documented source of bugs and security
+#       problems, so this is (mostly) avoided, by progressively accumulating
+#       options in "$@", and eventually passing that to Java.
+#
+#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+#       see the in-line comments for details.
+#
+#       There are tweaks for specific operating systems such as AIX, CygWin,
+#       Darwin, MinGW, and NonStop.
+#
+#   (3) This script is generated from the Groovy template
+#       https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+#       within the Gradle project.
+#
+#       You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+    APP_HOME=${app_path%"${app_path##*/}"}  # leaves a trailing /; empty if no leading path
+    [ -h "$app_path" ]
+do
+    ls=$( ls -ld "$app_path" )
+    link=${ls#*' -> '}
+    case $link in             #(
+      /*)   app_path=$link ;; #(
+      *)    app_path=$APP_HOME$link ;;
+    esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+    echo "$*"
+} >&2
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in                #(
+  CYGWIN* )         cygwin=true  ;; #(
+  Darwin* )         darwin=true  ;; #(
+  MSYS* | MINGW* )  msys=true    ;; #(
+  NONSTOP* )        nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD=$JAVA_HOME/jre/sh/java
+    else
+        JAVACMD=$JAVA_HOME/bin/java
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD=java
+    if ! command -v java >/dev/null 2>&1
+    then
+        die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+    case $MAX_FD in #(
+      max*)
+        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+        # shellcheck disable=SC3045
+        MAX_FD=$( ulimit -H -n ) ||
+            warn "Could not query maximum file descriptor limit"
+    esac
+    case $MAX_FD in  #(
+      '' | soft) :;; #(
+      *)
+        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+        # shellcheck disable=SC3045
+        ulimit -n "$MAX_FD" ||
+            warn "Could not set maximum file descriptor limit to $MAX_FD"
+    esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+#   * args from the command line
+#   * the main class name
+#   * -classpath
+#   * -D...appname settings
+#   * --module-path (only if needed)
+#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+    APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+    CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+    JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    for arg do
+        if
+            case $arg in                                #(
+              -*)   false ;;                            # don't mess with options #(
+              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath
+                    [ -e "$t" ] ;;                      #(
+              *)    false ;;
+            esac
+        then
+            arg=$( cygpath --path --ignore --mixed "$arg" )
+        fi
+        # Roll the args list around exactly as many times as the number of
+        # args, so each arg winds up back in the position where it started, but
+        # possibly modified.
+        #
+        # NB: a `for` loop captures its iteration list before it begins, so
+        # changing the positional parameters here affects neither the number of
+        # iterations, nor the values presented in `arg`.
+        shift                   # remove old arg
+        set -- "$@" "$arg"      # push replacement arg
+    done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command;
+#   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+#     shell script including quotes and variable substitutions, so put them in
+#     double quotes to make sure that they get re-expanded; and
+#   * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+        "-Dorg.gradle.appname=$APP_BASE_NAME" \
+        -classpath "$CLASSPATH" \
+        org.gradle.wrapper.GradleWrapperMain \
+        "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+    die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+#   readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+#   set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+        printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+        xargs -n1 |
+        sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+        tr '\n' ' '
+    )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/libraries/sts-common-util/sts-sdk/example/gradlew.bat b/libraries/sts-common-util/sts-sdk/example/gradlew.bat
new file mode 100644
index 0000000..6689b85
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/example/gradlew.bat
@@ -0,0 +1,92 @@
+@rem

+@rem Copyright 2015 the original author or authors.

+@rem

+@rem Licensed under the Apache License, Version 2.0 (the "License");

+@rem you may not use this file except in compliance with the License.

+@rem You may obtain a copy of the License at

+@rem

+@rem      https://www.apache.org/licenses/LICENSE-2.0

+@rem

+@rem Unless required by applicable law or agreed to in writing, software

+@rem distributed under the License is distributed on an "AS IS" BASIS,

+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+@rem See the License for the specific language governing permissions and

+@rem limitations under the License.

+@rem

+

+@if "%DEBUG%"=="" @echo off

+@rem ##########################################################################

+@rem

+@rem  Gradle startup script for Windows

+@rem

+@rem ##########################################################################

+

+@rem Set local scope for the variables with windows NT shell

+if "%OS%"=="Windows_NT" setlocal

+

+set DIRNAME=%~dp0

+if "%DIRNAME%"=="" set DIRNAME=.

+@rem This is normally unused

+set APP_BASE_NAME=%~n0

+set APP_HOME=%DIRNAME%

+

+@rem Resolve any "." and ".." in APP_HOME to make it shorter.

+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi

+

+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.

+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"

+

+@rem Find java.exe

+if defined JAVA_HOME goto findJavaFromJavaHome

+

+set JAVA_EXE=java.exe

+%JAVA_EXE% -version >NUL 2>&1

+if %ERRORLEVEL% equ 0 goto execute

+

+echo.

+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

+echo.

+echo Please set the JAVA_HOME variable in your environment to match the

+echo location of your Java installation.

+

+goto fail

+

+:findJavaFromJavaHome

+set JAVA_HOME=%JAVA_HOME:"=%

+set JAVA_EXE=%JAVA_HOME%/bin/java.exe

+

+if exist "%JAVA_EXE%" goto execute

+

+echo.

+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%

+echo.

+echo Please set the JAVA_HOME variable in your environment to match the

+echo location of your Java installation.

+

+goto fail

+

+:execute

+@rem Setup the command line

+

+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

+

+

+@rem Execute Gradle

+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*

+

+:end

+@rem End local scope for the variables with windows NT shell

+if %ERRORLEVEL% equ 0 goto mainEnd

+

+:fail

+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of

+rem the _cmd.exe /c_ return code!

+set EXIT_CODE=%ERRORLEVEL%

+if %EXIT_CODE% equ 0 set EXIT_CODE=1

+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%

+exit /b %EXIT_CODE%

+

+:mainEnd

+if "%OS%"=="Windows_NT" endlocal

+

+:omega

diff --git a/libraries/sts-common-util/sts-sdk/example/settings.gradle.kts b/libraries/sts-common-util/sts-sdk/example/settings.gradle.kts
new file mode 100644
index 0000000..6cca284
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/example/settings.gradle.kts
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2024 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.
+ */
+
+// repositories of plugins
+pluginManagement {
+    repositories {
+        mavenLocal()
+        gradlePluginPortal()
+        google()
+        mavenCentral()
+    }
+}
+
+// repositories of project dependencies
+dependencyResolutionManagement {
+    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+    repositories {
+        google()
+        mavenCentral()
+    }
+}
+
+plugins {
+    // Apply the foojay-resolver plugin to allow automatic download of JDKs
+    id("org.gradle.toolchains.foojay-resolver-convention") version "0.4.0"
+    id("com.android.sts.sdk.submission") version "1.0.0" apply false
+    id("com.android.sts.sdk.apptest") version "1.0.0" apply false
+    id("com.android.sts.sdk.javahosttest") version "1.0.0" apply false
+}
+
+rootProject.name = "sts-sdk-example"
+
+// glob and include gradle projects
+fileTree(rootDir) {
+        // only include subprojects of ":submission"
+        include("submission/**/build.gradle*")
+        // don't include subprojects from build directories
+        exclude("**/build")
+    }
+    .forEach {
+        val path = rootDir.toPath().relativize(it.toPath().getParent())
+        val gradlePath = path.toString().replace('/', ':')
+        include(gradlePath)
+    }
diff --git a/libraries/sts-common-util/sts-sdk/example/submission/appTest/build.gradle.kts b/libraries/sts-common-util/sts-sdk/example/submission/appTest/build.gradle.kts
new file mode 100644
index 0000000..8589e25
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/example/submission/appTest/build.gradle.kts
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2024 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.
+ */
+plugins { id("com.android.sts.sdk.apptest") }
+
+// Note: the Gradle package name is appended to the namespace "android.security.sts"
+appTest {}
diff --git a/libraries/sts-common-util/sts-sdk/package/test-app/src/main/AndroidManifest.xml b/libraries/sts-common-util/sts-sdk/example/submission/appTest/src/main/AndroidManifest.xml
similarity index 86%
rename from libraries/sts-common-util/sts-sdk/package/test-app/src/main/AndroidManifest.xml
rename to libraries/sts-common-util/sts-sdk/example/submission/appTest/src/main/AndroidManifest.xml
index a16eccb..13807ea 100644
--- a/libraries/sts-common-util/sts-sdk/package/test-app/src/main/AndroidManifest.xml
+++ b/libraries/sts-common-util/sts-sdk/example/submission/appTest/src/main/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright 2022 The Android Open Source Project
+  Copyright 2024 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.
@@ -16,12 +16,11 @@
   -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.security.sts.sts_test_app_package"
     android:versionCode="1"
     android:versionName="1.0">
     <instrumentation
         android:name="androidx.test.runner.AndroidJUnitRunner"
-        android:targetPackage="android.security.sts.sts_test_app_package" />
+        android:targetPackage="${applicationId}" />
     <application
         android:supportsRtl="true">
         <activity
diff --git a/libraries/sts-common-util/sts-sdk/package/test-app/src/main/java/android/security/sts/sts_test_app_package/DeviceTest.java b/libraries/sts-common-util/sts-sdk/example/submission/appTest/src/main/java/android/security/sts/DeviceTest.java
similarity index 93%
rename from libraries/sts-common-util/sts-sdk/package/test-app/src/main/java/android/security/sts/sts_test_app_package/DeviceTest.java
rename to libraries/sts-common-util/sts-sdk/example/submission/appTest/src/main/java/android/security/sts/DeviceTest.java
index a218e81..6993204 100644
--- a/libraries/sts-common-util/sts-sdk/package/test-app/src/main/java/android/security/sts/sts_test_app_package/DeviceTest.java
+++ b/libraries/sts-common-util/sts-sdk/example/submission/appTest/src/main/java/android/security/sts/DeviceTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.security.sts.sts_test_app_package;
+package android.security.sts;
 
 import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
@@ -48,6 +48,7 @@
 
     /** Test broadcast action */
     public static final String ACTION_BROADCAST = "action_security_test_broadcast";
+
     /** Broadcast intent extra name for artifacts */
     public static final String INTENT_ARTIFACT = "artifact";
 
@@ -77,9 +78,9 @@
                         }
                     }
                 };
-        IntentFilter filter = new IntentFilter(); // see if there's a shorthand
-        filter.addAction(ACTION_BROADCAST); // what does this return?
-        mContext.registerReceiver(broadcastReceiver, filter);
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(ACTION_BROADCAST);
+        mContext.registerReceiver(broadcastReceiver, filter, Context.RECEIVER_EXPORTED);
 
         // start the target app
         try {
diff --git a/libraries/sts-common-util/sts-sdk/package/test-app/src/main/java/android/security/sts/sts_test_app_package/PocActivity.java b/libraries/sts-common-util/sts-sdk/example/submission/appTest/src/main/java/android/security/sts/PocActivity.java
similarity index 93%
rename from libraries/sts-common-util/sts-sdk/package/test-app/src/main/java/android/security/sts/sts_test_app_package/PocActivity.java
rename to libraries/sts-common-util/sts-sdk/example/submission/appTest/src/main/java/android/security/sts/PocActivity.java
index daeb76c..9adb2b5 100644
--- a/libraries/sts-common-util/sts-sdk/package/test-app/src/main/java/android/security/sts/sts_test_app_package/PocActivity.java
+++ b/libraries/sts-common-util/sts-sdk/example/submission/appTest/src/main/java/android/security/sts/PocActivity.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright 2022 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.
@@ -13,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.sts.sts_test_app_package;
+package android.security.sts;
 
 import android.app.Activity;
 import android.content.Intent;
diff --git a/libraries/sts-common-util/sts-sdk/package/test-app/src/main/res/layout/activity_main.xml b/libraries/sts-common-util/sts-sdk/example/submission/appTest/src/main/res/layout/activity_main.xml
similarity index 94%
rename from libraries/sts-common-util/sts-sdk/package/test-app/src/main/res/layout/activity_main.xml
rename to libraries/sts-common-util/sts-sdk/example/submission/appTest/src/main/res/layout/activity_main.xml
index f14c7ce..0edbaae 100644
--- a/libraries/sts-common-util/sts-sdk/package/test-app/src/main/res/layout/activity_main.xml
+++ b/libraries/sts-common-util/sts-sdk/example/submission/appTest/src/main/res/layout/activity_main.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright 2022 The Android Open Source Project
+  Copyright 2024 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.
@@ -24,3 +24,4 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"/>
 </LinearLayout>
+
diff --git a/libraries/sts-common-util/sts-sdk/example/submission/appTest2/build.gradle.kts b/libraries/sts-common-util/sts-sdk/example/submission/appTest2/build.gradle.kts
new file mode 100644
index 0000000..455cc61
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/example/submission/appTest2/build.gradle.kts
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2024 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.
+ */
+plugins { id("com.android.sts.sdk.apptest") }
+
+appTest {}
diff --git a/libraries/sts-common-util/sts-sdk/package/test-app/src/main/AndroidManifest.xml b/libraries/sts-common-util/sts-sdk/example/submission/appTest2/src/main/AndroidManifest.xml
similarity index 86%
copy from libraries/sts-common-util/sts-sdk/package/test-app/src/main/AndroidManifest.xml
copy to libraries/sts-common-util/sts-sdk/example/submission/appTest2/src/main/AndroidManifest.xml
index a16eccb..13807ea 100644
--- a/libraries/sts-common-util/sts-sdk/package/test-app/src/main/AndroidManifest.xml
+++ b/libraries/sts-common-util/sts-sdk/example/submission/appTest2/src/main/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright 2022 The Android Open Source Project
+  Copyright 2024 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.
@@ -16,12 +16,11 @@
   -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.security.sts.sts_test_app_package"
     android:versionCode="1"
     android:versionName="1.0">
     <instrumentation
         android:name="androidx.test.runner.AndroidJUnitRunner"
-        android:targetPackage="android.security.sts.sts_test_app_package" />
+        android:targetPackage="${applicationId}" />
     <application
         android:supportsRtl="true">
         <activity
diff --git a/libraries/sts-common-util/sts-sdk/example/submission/appTest2/src/main/java/android/security/sts/PocActivity.java b/libraries/sts-common-util/sts-sdk/example/submission/appTest2/src/main/java/android/security/sts/PocActivity.java
new file mode 100644
index 0000000..effa606
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/example/submission/appTest2/src/main/java/android/security/sts/PocActivity.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2022 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.security.sts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+
+public class PocActivity extends Activity {
+    private static final String TAG = PocActivity.class.getSimpleName();
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+        Log.d(TAG, "poc activity started");
+    }
+}
diff --git a/libraries/sts-common-util/sts-sdk/package/test-app/src/main/res/layout/activity_main.xml b/libraries/sts-common-util/sts-sdk/example/submission/appTest2/src/main/res/layout/activity_main.xml
similarity index 94%
copy from libraries/sts-common-util/sts-sdk/package/test-app/src/main/res/layout/activity_main.xml
copy to libraries/sts-common-util/sts-sdk/example/submission/appTest2/src/main/res/layout/activity_main.xml
index f14c7ce..0edbaae 100644
--- a/libraries/sts-common-util/sts-sdk/package/test-app/src/main/res/layout/activity_main.xml
+++ b/libraries/sts-common-util/sts-sdk/example/submission/appTest2/src/main/res/layout/activity_main.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright 2022 The Android Open Source Project
+  Copyright 2024 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.
@@ -24,3 +24,4 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"/>
 </LinearLayout>
+
diff --git a/libraries/sts-common-util/sts-sdk/example/submission/build.gradle.kts b/libraries/sts-common-util/sts-sdk/example/submission/build.gradle.kts
new file mode 100644
index 0000000..be2a8ea
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/example/submission/build.gradle.kts
@@ -0,0 +1,26 @@
+plugins { id("com.android.sts.sdk.submission") }
+
+fun getSubprojects(): List<Project> {
+    // glob for gradle direct subprojects
+    return fileTree(projectDir) { include("*/build.gradle*") }
+        .map {
+            val path = projectDir.toPath().relativize(it.toPath().getParent())
+            val gradlePath = path.toString().replace('/', ':')
+            gradlePath
+        }
+        .filter({
+            // filter out self build.gradle*
+            !it.isEmpty()
+        })
+        .map { project(it) }
+}
+
+// NOTE! all STS SDK dependencies must be subprojects
+dependencies {
+    // Automatically add each subproject as an STS SDK Test Resource
+    getSubprojects().forEach { stsSdkTestResource(it) }
+}
+
+stsSdkSubmission {
+    // Please configure your submission attributes here
+}
diff --git a/libraries/sts-common-util/sts-sdk/example/submission/hostTest/build.gradle.kts b/libraries/sts-common-util/sts-sdk/example/submission/hostTest/build.gradle.kts
new file mode 100644
index 0000000..a14c18a
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/example/submission/hostTest/build.gradle.kts
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2024 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.
+ */
+plugins { id("com.android.sts.sdk.javahosttest") }
diff --git a/libraries/sts-common-util/sts-sdk/package/sts-test/src/main/java/android/security/sts/StsHostSideTestCase.java b/libraries/sts-common-util/sts-sdk/example/submission/hostTest/src/main/java/android/security/sts/sts_sdk_placeholder/HostsideTest.java
similarity index 86%
rename from libraries/sts-common-util/sts-sdk/package/sts-test/src/main/java/android/security/sts/StsHostSideTestCase.java
rename to libraries/sts-common-util/sts-sdk/example/submission/hostTest/src/main/java/android/security/sts/sts_sdk_placeholder/HostsideTest.java
index dbc55e2..697202d 100644
--- a/libraries/sts-common-util/sts-sdk/package/sts-test/src/main/java/android/security/sts/StsHostSideTestCase.java
+++ b/libraries/sts-common-util/sts-sdk/example/submission/hostTest/src/main/java/android/security/sts/sts_sdk_placeholder/HostsideTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright 2022 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.
@@ -13,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-package android.security.sts;
+package android.security.sts.sts_sdk_placeholder;
 
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
@@ -41,11 +40,14 @@
 import java.util.regex.Pattern;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class StsHostSideTestCase extends NonRootSecurityTestCase {
+public class HostsideTest extends NonRootSecurityTestCase {
 
-    static final String TEST_APP = "sts_test_app_package.apk";
-    static final String TEST_PKG = "android.security.sts.sts_test_app_package";
-    static final String TEST_CLASS = TEST_PKG + "." + "DeviceTest";
+    // Set from the Gradle project for the AppTest plugins.
+    static final String TEST_APP = "appTest_StsSdkPlaceholder.apk";
+    // The Gradle project name is appended to the namespace "android.security.sts".
+    static final String TEST_PKG = "android.security.sts.appTest_StsSdkPlaceholder";
+    // The class name will be different from the application ID but will match the source code.
+    static final String TEST_CLASS = "android.security.sts.DeviceTest";
 
     /** An app test, which uses this host Java test to launch an Android instrumented test */
     @Test
@@ -68,9 +70,9 @@
     public void testWithNativePoc() throws Exception {
         NativePoc.builder()
                 // the name of the PoC
-                .pocName("native-poc")
+                .pocName("ndkTest_StsSdkPlaceholder")
                 // extra files pushed to the device
-                .resources("res.txt")
+                .resources("StsSdkPlaceholder/res.txt")
                 // command-line arguments for the PoC
                 .args("res.txt", "vulnerable")
                 // other options allow different linker paths for library shims
@@ -97,13 +99,13 @@
                 MallocDebug.withLibcMallocDebugOnNewProcess(
                         getDevice(),
                         "backtrace guard", // malloc debug options
-                        "native-poc" // process name
+                        "ndkTest_StsSdkPlaceholder" // process name
                         )) {
             assumeTrue("could not disable root", getDevice().disableAdbRoot());
 
             // run a native PoC
             NativePoc.builder()
-                    .pocName("native-poc")
+                    .pocName("ndkTest_StsSdkPlaceholder")
                     .args("memory_corrupt")
                     .build() // add more as needed
                     .run(this);
@@ -137,7 +139,7 @@
 
         // attack the service
         NativePoc.builder()
-                .pocName("native-poc")
+                .pocName("ndkTest_StsSdkPlaceholder")
                 // pass the library path to the PoC
                 .args(libFileEntry.get().getFullPath())
                 .assumePocExitSuccess(false) // example returns EXIT_FAILURE if not enough args
@@ -146,7 +148,8 @@
                                 new TombstoneUtils.Config()
                                         // Because the vulnerability is in the shared library, the
                                         // process crash is the PoC.
-                                        .setProcessPatterns(Pattern.compile("native-poc"))))
+                                        .setProcessPatterns(
+                                                Pattern.compile("ndkTest_StsSdkPlaceholder"))))
                 .build()
                 .run(this);
     }
@@ -158,7 +161,7 @@
 
         // attack the device, which can be native poc, echo to socket, send intent, app, etc
         NativePoc.builder()
-                .pocName("native-poc")
+                .pocName("ndkTest_StsSdkPlaceholder")
                 .assumePocExitSuccess(false) // example returns EXIT_FAILURE if no args
                 .build() // add more as needed
                 .run(this);
diff --git a/libraries/sts-common-util/sts-sdk/package/sts-test/src/main/resources/res.txt b/libraries/sts-common-util/sts-sdk/example/submission/hostTest/src/main/resources/StsSdkPlaceholder/res.txt
similarity index 100%
rename from libraries/sts-common-util/sts-sdk/package/sts-test/src/main/resources/res.txt
rename to libraries/sts-common-util/sts-sdk/example/submission/hostTest/src/main/resources/StsSdkPlaceholder/res.txt
diff --git a/libraries/sts-common-util/sts-sdk/example/submission/ndkTest/CMakeLists.txt b/libraries/sts-common-util/sts-sdk/example/submission/ndkTest/CMakeLists.txt
new file mode 100644
index 0000000..0f84092
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/example/submission/ndkTest/CMakeLists.txt
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 3.22.1)
+
+project("ndkTest")
+
+add_executable(
+        ndkTest
+        src/native-sample.cpp
+)
+
+find_library( # Sets the name of the path variable.
+        log-lib
+        log)
diff --git a/libraries/sts-common-util/sts-sdk/example/submission/ndkTest/build.gradle.kts b/libraries/sts-common-util/sts-sdk/example/submission/ndkTest/build.gradle.kts
new file mode 100644
index 0000000..6950c64
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/example/submission/ndkTest/build.gradle.kts
@@ -0,0 +1,10 @@
+plugins {
+    // my sts sdk plugin
+    id("com.android.sts.sdk.ndktest")
+}
+
+nativeTest {
+    minSdk = 11
+    targetSdk = 33
+    compileSdk = 33
+}
diff --git a/libraries/sts-common-util/sts-sdk/package/native-poc/src/native-sample.cpp b/libraries/sts-common-util/sts-sdk/example/submission/ndkTest/src/native-sample.cpp
similarity index 100%
rename from libraries/sts-common-util/sts-sdk/package/native-poc/src/native-sample.cpp
rename to libraries/sts-common-util/sts-sdk/example/submission/ndkTest/src/native-sample.cpp
diff --git a/libraries/sts-common-util/sts-sdk/package/README.md b/libraries/sts-common-util/sts-sdk/package/README.md
deleted file mode 100644
index 41b399a..0000000
--- a/libraries/sts-common-util/sts-sdk/package/README.md
+++ /dev/null
@@ -1,2 +0,0 @@
-See https://source.android.com/docs/security/test/sts-sdk for instructions and
-documentation.
diff --git a/libraries/sts-common-util/sts-sdk/package/build.gradle b/libraries/sts-common-util/sts-sdk/package/build.gradle
deleted file mode 100644
index d08dd5e..0000000
--- a/libraries/sts-common-util/sts-sdk/package/build.gradle
+++ /dev/null
@@ -1,101 +0,0 @@
-plugins {
-    id 'com.android.application' version '7.2.1' apply false
-    id 'com.android.library' version '7.2.1' apply false
-}
-
-task clean(type: Delete) {
-    delete layout.buildDirectory
-    if (findProject('native-poc') != null) {
-        delete project('native-poc').layout.projectDirectory.dir('.cxx')
-    }
-}
-
-ext.copyArtifacts = { nativeDir ->
-    copy {
-        from project('sts-test').layout.buildDirectory.file('testcases')
-
-        if (findProject('native-poc') != null) {
-            from project('native-poc').layout.buildDirectory.file(nativeDir)
-        }
-
-        into layout.buildDirectory.dir('android-sts/testcases')
-    }
-
-    // TODO: figure out variants
-    if (findProject('test-app') != null) {
-        copy {
-            from project('test-app').layout.buildDirectory.file('outputs/apk/debug')
-            rename '(.*).apk', 'sts_test_app_package.apk'
-            include '**/*.apk'
-            into layout.buildDirectory.dir('android-sts/testcases')
-        }
-    }
-
-    // To add another Android apk to the test, copy the block above and rename
-    // the project name to your submodule as well as the APK output filename.
-    // Remember to use that APK file name in your `sts-test`.
-
-    copy {
-        from project('sts-test').layout.projectDirectory.file('libs')
-        into layout.buildDirectory.dir('android-sts/tools')
-    }
-    copy {
-        from project('sts-test').layout.projectDirectory.dir('jdk')
-        into layout.buildDirectory.dir('android-sts/jdk')
-    }
-}
-
-task assembleStsARM {
-    dependsOn ':sts-test:copyHostSideTest'
-
-    if (findProject('native-poc') != null) {
-        dependsOn ':native-poc:copyarmeabi-v7a'
-        dependsOn ':native-poc:copyarm64-v8a'
-    }
-
-    if (findProject('test-app') != null) {
-        dependsOn ':test-app:assemble'
-    }
-
-    // To add another Android apk to the test, copy the block above and rename
-    // the project name to your new submodule
-
-    doLast {
-        copyArtifacts('testcases_arm')
-    }
-}
-
-task assembleStsx86 {
-    dependsOn ':sts-test:copyHostSideTest'
-
-    if (findProject('native-poc') != null) {
-        dependsOn ':native-poc:copyx86'
-        dependsOn ':native-poc:copyx86_64'
-    }
-
-    if (findProject('test-app') != null) {
-        dependsOn ':test-app:assemble'
-    }
-
-    // To add another Android apk to the test, copy the block above and rename
-    // the project name to your new submodule
-
-    doLast {
-        copyArtifacts('testcases_x86')
-    }
-}
-
-task zipForSubmission(type: Zip) {
-    from('.') {
-        exclude "**/build"
-        exclude '.gradle'
-        exclude 'test-app/libs'
-        exclude 'sts-test/libs'
-        exclude 'sts-test/jdk'
-        exclude 'sts-test/utils'
-        exclude "**/.cxx"
-    }
-    from project('sts-test').layout.projectDirectory.file('libs/version.txt')
-    archiveFileName.set("codesubmission.zip")
-    destinationDirectory.set(layout.buildDirectory)
-}
diff --git a/libraries/sts-common-util/sts-sdk/package/dotidea/runConfigurations/assemble_STS_x86.xml b/libraries/sts-common-util/sts-sdk/package/dotidea/runConfigurations/assemble_STS_x86.xml
deleted file mode 100644
index 790e427..0000000
--- a/libraries/sts-common-util/sts-sdk/package/dotidea/runConfigurations/assemble_STS_x86.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<component name="ProjectRunConfigurationManager">
-  <configuration default="false" name="assembleStsx86" type="GradleRunConfiguration" factoryName="Gradle">
-    <ExternalSystemSettings>
-      <option name="executionName" />
-      <option name="externalProjectPath" value="$PROJECT_DIR$" />
-      <option name="externalSystemIdString" value="GRADLE" />
-      <option name="scriptParameters" value="" />
-      <option name="taskDescriptions">
-        <list />
-      </option>
-      <option name="taskNames">
-        <list>
-          <option value="assembleStsx86" />
-        </list>
-      </option>
-      <option name="vmOptions" />
-    </ExternalSystemSettings>
-    <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
-    <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
-    <DebugAllEnabled>false</DebugAllEnabled>
-    <method v="2" />
-  </configuration>
-</component>
diff --git a/libraries/sts-common-util/sts-sdk/package/dotidea/runConfigurations/clean.xml b/libraries/sts-common-util/sts-sdk/package/dotidea/runConfigurations/clean.xml
deleted file mode 100644
index 9480f95..0000000
--- a/libraries/sts-common-util/sts-sdk/package/dotidea/runConfigurations/clean.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<component name="ProjectRunConfigurationManager">
-  <configuration default="false" name="clean" type="GradleRunConfiguration" factoryName="Gradle">
-    <ExternalSystemSettings>
-      <option name="executionName" />
-      <option name="externalProjectPath" value="$PROJECT_DIR$" />
-      <option name="externalSystemIdString" value="GRADLE" />
-      <option name="scriptParameters" value="" />
-      <option name="taskDescriptions">
-        <list />
-      </option>
-      <option name="taskNames">
-        <list>
-          <option value="clean" />
-        </list>
-      </option>
-      <option name="vmOptions" />
-    </ExternalSystemSettings>
-    <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
-    <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
-    <DebugAllEnabled>false</DebugAllEnabled>
-    <method v="2" />
-  </configuration>
-</component>
diff --git a/libraries/sts-common-util/sts-sdk/package/dotidea/runConfigurations/create_zip.xml b/libraries/sts-common-util/sts-sdk/package/dotidea/runConfigurations/create_zip.xml
deleted file mode 100644
index 50d26e2..0000000
--- a/libraries/sts-common-util/sts-sdk/package/dotidea/runConfigurations/create_zip.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<component name="ProjectRunConfigurationManager">
-  <configuration default="false" name="zipForSubmission" type="GradleRunConfiguration" factoryName="Gradle">
-    <ExternalSystemSettings>
-      <option name="executionName" />
-      <option name="externalProjectPath" value="$PROJECT_DIR$" />
-      <option name="externalSystemIdString" value="GRADLE" />
-      <option name="scriptParameters" value="" />
-      <option name="taskDescriptions">
-        <list />
-      </option>
-      <option name="taskNames">
-        <list>
-          <option value="zipForSubmission" />
-        </list>
-      </option>
-      <option name="vmOptions" />
-    </ExternalSystemSettings>
-    <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
-    <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
-    <DebugAllEnabled>false</DebugAllEnabled>
-    <method v="2" />
-  </configuration>
-</component>
-
diff --git a/libraries/sts-common-util/sts-sdk/package/dotidea/runConfigurations/run_STS_nonroot.xml b/libraries/sts-common-util/sts-sdk/package/dotidea/runConfigurations/run_STS_nonroot.xml
deleted file mode 100644
index a8e0ca6..0000000
--- a/libraries/sts-common-util/sts-sdk/package/dotidea/runConfigurations/run_STS_nonroot.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<component name="ProjectRunConfigurationManager">
-  <configuration default="false" name="run STS on device without root" type="ShConfigurationType">
-    <option name="SCRIPT_TEXT" value="./sts-tradefed run commandAndExit sts-sdk-nonroot --log-level debug --log-level-display debug -m hostsidetest" />
-    <option name="INDEPENDENT_SCRIPT_PATH" value="true" />
-    <option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
-    <option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$/build/android-sts/tools" />
-    <option name="EXECUTE_IN_TERMINAL" value="false" />
-    <option name="EXECUTE_SCRIPT_FILE" value="false" />
-    <envs />
-    <method v="2" />
-  </configuration>
-</component>
diff --git a/libraries/sts-common-util/sts-sdk/package/dotidea/runConfigurations/run_STS_root.xml b/libraries/sts-common-util/sts-sdk/package/dotidea/runConfigurations/run_STS_root.xml
deleted file mode 100644
index 053744b..0000000
--- a/libraries/sts-common-util/sts-sdk/package/dotidea/runConfigurations/run_STS_root.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<component name="ProjectRunConfigurationManager">
-  <configuration default="false" name="run STS on device with root" type="ShConfigurationType">
-    <option name="SCRIPT_TEXT" value="./sts-tradefed run commandAndExit sts-sdk-root --log-level debug --log-level-display debug -m hostsidetest" />
-    <option name="INDEPENDENT_SCRIPT_PATH" value="true" />
-    <option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
-    <option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$/build/android-sts/tools" />
-    <option name="EXECUTE_IN_TERMINAL" value="false" />
-    <option name="EXECUTE_SCRIPT_FILE" value="false" />
-    <envs />
-    <method v="2" />
-  </configuration>
-</component>
diff --git a/libraries/sts-common-util/sts-sdk/package/gradle.properties b/libraries/sts-common-util/sts-sdk/package/gradle.properties
deleted file mode 100644
index 0b36154..0000000
--- a/libraries/sts-common-util/sts-sdk/package/gradle.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
-android.useAndroidX=true
-android.nonTransitiveRClass=true
-gradle=build -x lint -x lintVitalRelease
\ No newline at end of file
diff --git a/libraries/sts-common-util/sts-sdk/package/gradle/wrapper/gradle-wrapper.jar b/libraries/sts-common-util/sts-sdk/package/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index 1948b90..0000000
--- a/libraries/sts-common-util/sts-sdk/package/gradle/wrapper/gradle-wrapper.jar
+++ /dev/null
Binary files differ
diff --git a/libraries/sts-common-util/sts-sdk/package/gradlew b/libraries/sts-common-util/sts-sdk/package/gradlew
deleted file mode 100755
index cccdd3d..0000000
--- a/libraries/sts-common-util/sts-sdk/package/gradlew
+++ /dev/null
@@ -1,172 +0,0 @@
-#!/usr/bin/env sh
-
-##############################################################################
-##
-##  Gradle start up script for UN*X
-##
-##############################################################################
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
-    ls=`ls -ld "$PRG"`
-    link=`expr "$ls" : '.*-> \(.*\)$'`
-    if expr "$link" : '/.*' > /dev/null; then
-        PRG="$link"
-    else
-        PRG=`dirname "$PRG"`"/$link"
-    fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
-
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
-
-warn () {
-    echo "$*"
-}
-
-die () {
-    echo
-    echo "$*"
-    echo
-    exit 1
-}
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false
-msys=false
-darwin=false
-nonstop=false
-case "`uname`" in
-  CYGWIN* )
-    cygwin=true
-    ;;
-  Darwin* )
-    darwin=true
-    ;;
-  MINGW* )
-    msys=true
-    ;;
-  NONSTOP* )
-    nonstop=true
-    ;;
-esac
-
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
-
-# Determine the Java command to use to start the JVM.
-if [ -n "$JAVA_HOME" ] ; then
-    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
-        # IBM's JDK on AIX uses strange locations for the executables
-        JAVACMD="$JAVA_HOME/jre/sh/java"
-    else
-        JAVACMD="$JAVA_HOME/bin/java"
-    fi
-    if [ ! -x "$JAVACMD" ] ; then
-        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-    fi
-else
-    JAVACMD="java"
-    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-fi
-
-# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
-    MAX_FD_LIMIT=`ulimit -H -n`
-    if [ $? -eq 0 ] ; then
-        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
-            MAX_FD="$MAX_FD_LIMIT"
-        fi
-        ulimit -n $MAX_FD
-        if [ $? -ne 0 ] ; then
-            warn "Could not set maximum file descriptor limit: $MAX_FD"
-        fi
-    else
-        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
-    fi
-fi
-
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
-    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
-
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
-    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
-    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-    JAVACMD=`cygpath --unix "$JAVACMD"`
-
-    # We build the pattern for arguments to be converted via cygpath
-    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
-    SEP=""
-    for dir in $ROOTDIRSRAW ; do
-        ROOTDIRS="$ROOTDIRS$SEP$dir"
-        SEP="|"
-    done
-    OURCYGPATTERN="(^($ROOTDIRS))"
-    # Add a user-defined pattern to the cygpath arguments
-    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
-        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
-    fi
-    # Now convert the arguments - kludge to limit ourselves to /bin/sh
-    i=0
-    for arg in "$@" ; do
-        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
-        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
-
-        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
-            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
-        else
-            eval `echo args$i`="\"$arg\""
-        fi
-        i=$((i+1))
-    done
-    case $i in
-        (0) set -- ;;
-        (1) set -- "$args0" ;;
-        (2) set -- "$args0" "$args1" ;;
-        (3) set -- "$args0" "$args1" "$args2" ;;
-        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
-        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
-        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
-        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
-        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
-        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
-    esac
-fi
-
-# Escape application args
-save () {
-    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
-    echo " "
-}
-APP_ARGS=$(save "$@")
-
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
-
-# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
-if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
-  cd "$(dirname "$0")"
-fi
-
-exec "$JAVACMD" "$@"
diff --git a/libraries/sts-common-util/sts-sdk/package/native-poc/build.gradle.template b/libraries/sts-common-util/sts-sdk/package/native-poc/build.gradle.template
deleted file mode 100644
index 08b4333..0000000
--- a/libraries/sts-common-util/sts-sdk/package/native-poc/build.gradle.template
+++ /dev/null
@@ -1,32 +0,0 @@
-plugins {
-    id 'com.android.library'
-}
-
-android {
-    compileSdk {{PLATFORM_SDK_VERSION}}
-    externalNativeBuild {
-        cmake {
-            path file('src/CMakeLists.txt')
-            version '3.18.1'
-        }
-    }
-    defaultConfig {
-        targetSdk {{PLATFORM_SDK_VERSION}}
-        minSdk 29
-    }
-}
-
-ext.copyArtifact = { arch, suffix, outputDir ->
-    tasks.register("copy${arch}", Copy) {
-        dependsOn 'externalNativeBuildDebug'
-        from layout.buildDirectory.file("intermediates/cmake/debug/obj/${arch}/nativepoc")
-        rename ('nativepoc', "${project.name.replaceFirst(/-native/, '')}${suffix}")
-        into layout.buildDirectory.dir(outputDir)
-    }
-}
-
-copyArtifact('armeabi-v7a', '_sts32', 'testcases_arm')
-copyArtifact('arm64-v8a', '_sts64', 'testcases_arm')
-copyArtifact('x86', '_sts32', 'testcases_x86')
-copyArtifact('x86_64', '_sts64', 'testcases_x86')
-
diff --git a/libraries/sts-common-util/sts-sdk/package/native-poc/src/CMakeLists.txt b/libraries/sts-common-util/sts-sdk/package/native-poc/src/CMakeLists.txt
deleted file mode 100644
index cda521d..0000000
--- a/libraries/sts-common-util/sts-sdk/package/native-poc/src/CMakeLists.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-cmake_minimum_required(VERSION 3.18.1)
-
-project("nativepoc")
-
-add_executable(
-        nativepoc
-        native-sample.cpp
-)
-
-find_library( # Sets the name of the path variable.
-        log-lib
-        log)
diff --git a/libraries/sts-common-util/sts-sdk/package/native-poc/src/main/AndroidManifest.xml b/libraries/sts-common-util/sts-sdk/package/native-poc/src/main/AndroidManifest.xml
deleted file mode 100644
index cf2ccb7..0000000
--- a/libraries/sts-common-util/sts-sdk/package/native-poc/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    package="com.android.sts">
-</manifest>
\ No newline at end of file
diff --git a/libraries/sts-common-util/sts-sdk/package/settings.gradle b/libraries/sts-common-util/sts-sdk/package/settings.gradle
deleted file mode 100644
index c73df1c..0000000
--- a/libraries/sts-common-util/sts-sdk/package/settings.gradle
+++ /dev/null
@@ -1,27 +0,0 @@
-pluginManagement {
-    repositories {
-        gradlePluginPortal()
-        google()
-        mavenCentral()
-    }
-}
-
-dependencyResolutionManagement {
-    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
-    repositories {
-        google()
-        mavenCentral()
-    }
-}
-
-rootProject.name = 'STS test'
-
-if (new File('native-poc').isDirectory()) {
-    include ':native-poc'
-}
-
-if (new File('test-app').isDirectory()) {
-    include ':test-app'
-}
-
-include ':sts-test'
diff --git a/libraries/sts-common-util/sts-sdk/package/sts-test/build.gradle b/libraries/sts-common-util/sts-sdk/package/sts-test/build.gradle
deleted file mode 100644
index f5f4a15..0000000
--- a/libraries/sts-common-util/sts-sdk/package/sts-test/build.gradle
+++ /dev/null
@@ -1,31 +0,0 @@
-plugins {
-    id 'java-library'
-}
-
-task copyConfig(type: Copy) {
-    from layout.projectDirectory.file('src/hostsidetest.config.tmpl')
-    rename 'hostsidetest.config.tmpl', 'hostsidetest.config'
-    filter { l -> l.replaceAll('@@jarname@@', jar.outputs.getFiles().getSingleFile().getName()) }
-    into layout.buildDirectory.dir('config')
-}
-
-task copyHostSideTest(type: Copy) {
-    from jar
-    from copyConfig
-    into layout.buildDirectory.dir('testcases')
-}
-
-dependencies {
-    implementation files('libs/sts-tradefed.jar')
-    implementation files('libs/tradefed.jar')
-    implementation files('libs/compatibility-host-util.jar')
-    implementation files('libs/sts-host-util.jar')
-
-    implementation 'androidx.annotation:annotation:1.4.0'
-    implementation files('libs/hamcrest-library.jar')
-}
-
-java {
-    sourceCompatibility = JavaVersion.VERSION_1_8
-    targetCompatibility = JavaVersion.VERSION_1_8
-}
diff --git a/libraries/sts-common-util/sts-sdk/package/sts-test/src/main/AndroidManifest.xml b/libraries/sts-common-util/sts-sdk/package/sts-test/src/main/AndroidManifest.xml
deleted file mode 100644
index c94d4eb..0000000
--- a/libraries/sts-common-util/sts-sdk/package/sts-test/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.security.sts">
-
-</manifest>
\ No newline at end of file
diff --git a/libraries/sts-common-util/sts-sdk/package/test-app/build.gradle b/libraries/sts-common-util/sts-sdk/package/test-app/build.gradle
deleted file mode 100644
index 17881cc..0000000
--- a/libraries/sts-common-util/sts-sdk/package/test-app/build.gradle
+++ /dev/null
@@ -1,40 +0,0 @@
-plugins {
-    id 'com.android.application'
-}
-
-android {
-    compileSdk 31
-
-    defaultConfig {
-        applicationId "android.security.sts.sts_test_app_package"
-        minSdk 29
-        targetSdk 31
-        versionCode 1
-        versionName "1.0"
-    }
-
-    buildTypes {
-        release {
-            minifyEnabled false
-        }
-    }
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_8
-        targetCompatibility JavaVersion.VERSION_1_8
-    }
-
-    lintOptions {
-        checkReleaseBuilds false
-        abortOnError false
-    }
-}
-
-dependencies {
-
-    implementation 'androidx.appcompat:appcompat:1.4.2'
-    implementation 'com.google.android.material:material:1.6.1'
-    implementation 'junit:junit:4.13.2'
-    implementation 'androidx.test.ext:junit:1.1.3'
-    implementation 'androidx.test.espresso:espresso-core:3.4.0'
-    implementation 'androidx.test.uiautomator:uiautomator:2.2.0'
-}
diff --git a/libraries/sts-common-util/sts-sdk/plugin/.gitignore b/libraries/sts-common-util/sts-sdk/plugin/.gitignore
new file mode 100644
index 0000000..0959319
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/plugin/.gitignore
@@ -0,0 +1,8 @@
+# Ignore Gradle project-specific cache directory
+.gradle
+
+# Ignore Gradle build output directory
+build
+
+# Ignore idea
+.idea
diff --git a/libraries/sts-common-util/sts-sdk/plugin/Android.bp b/libraries/sts-common-util/sts-sdk/plugin/Android.bp
new file mode 100644
index 0000000..2d1d3c7
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/plugin/Android.bp
@@ -0,0 +1,52 @@
+// Copyright (C) 2024 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+filegroup {
+    name: "sts-sdk-skel-srcs",
+    srcs: [
+        "**/*",
+    ],
+    exclude_srcs: [
+        "**/.*",
+        "Android.bp",
+    ],
+}
+
+genrule {
+    name: "sts-sdk-plugin-skel.zip-gen",
+    srcs: [
+        ":sts-sdk-skel-srcs",
+    ],
+    out: ["sts-sdk-plugin-skel.zip"],
+    tools: [
+        "soong_zip",
+    ],
+    product_variables: {
+        platform_sdk_version: {
+            cmd: "files=($(in)) " +
+                "&& mkdir -p $(genDir)/tmp/ " +
+                "&& echo $(in) > $(genDir)/tmp/sts-sdk-plugin-skel.zip.list " +
+                "&& $(location soong_zip) -o $(out) -C $$(dirname $${files[0]}) -l $(genDir)/tmp/sts-sdk-plugin-skel.zip.list",
+        },
+    },
+}
+
+prebuilt_etc {
+    name: "sts-sdk-plugin-skel.zip",
+    src: ":sts-sdk-plugin-skel.zip-gen",
+}
diff --git a/libraries/sts-common-util/sts-sdk/plugin/extract-and-gradle.sh b/libraries/sts-common-util/sts-sdk/plugin/extract-and-gradle.sh
new file mode 100755
index 0000000..6e2743b
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/plugin/extract-and-gradle.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+# Because the build environment is not passed to this script, please `m sts-sdk`.
+
+# usage:
+# $ m sts-sdk && ./extract-and-gradle.sh *commands*
+
+# publish to local; useful for testing examples:
+# $ m sts-sdk && ./extract-and-gradle.sh publishToMavenLocal
+
+# build only:
+# $ m sts-sdk && ./extract-and-gradle.sh assemble
+
+# build and test:
+# $ m sts-sdk && ./extract-and-gradle.sh build
+
+# Exit on error
+set -e
+
+if [ -z "${ANDROID_HOST_OUT}" ]; then
+  echo "ANDROID_HOST_OUT is not set. Did you source and lunch?"
+  exit 1
+fi
+
+STS_SDK_OUT=/tmp/sts-sdk
+
+# Remove output directory.
+# This breaks incremental compile but in practice the difference is negligible.
+rm -rf $STS_SDK_OUT
+
+# -q quiet
+# -o overwrite without prompting
+# -d output directory
+unzip -q -o $ANDROID_HOST_OUT/sts-sdk/sts-sdk.zip -d $STS_SDK_OUT
+
+cd $STS_SDK_OUT
+./gradlew $@
diff --git a/libraries/sts-common-util/sts-sdk/plugin/gradle/libs.versions.toml b/libraries/sts-common-util/sts-sdk/plugin/gradle/libs.versions.toml
new file mode 100644
index 0000000..b4d4e5b
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/plugin/gradle/libs.versions.toml
@@ -0,0 +1,20 @@
+# Copyright 2024 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.
+
+# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format
+
+[plugins]
+androidApp = { id = "com.android.application", version = "8.2.2" }
+androidLib = { id = "com.android.library", version = "8.2.2" }
+jvm = { id = "org.jetbrains.kotlin.jvm", version = "1.9.20" }
diff --git a/libraries/sts-common-util/sts-sdk/plugin/gradle/wrapper/gradle-wrapper.jar b/libraries/sts-common-util/sts-sdk/plugin/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..d64cd49
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/plugin/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/libraries/sts-common-util/sts-sdk/package/gradle/wrapper/gradle-wrapper.properties b/libraries/sts-common-util/sts-sdk/plugin/gradle/wrapper/gradle-wrapper.properties
similarity index 74%
rename from libraries/sts-common-util/sts-sdk/package/gradle/wrapper/gradle-wrapper.properties
rename to libraries/sts-common-util/sts-sdk/plugin/gradle/wrapper/gradle-wrapper.properties
index 48c8d88..a80b22c 100644
--- a/libraries/sts-common-util/sts-sdk/package/gradle/wrapper/gradle-wrapper.properties
+++ b/libraries/sts-common-util/sts-sdk/plugin/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,7 @@
-#Wed Jun 29 11:41:03 PDT 2022
 distributionBase=GRADLE_USER_HOME
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
 distributionPath=wrapper/dists
-zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
 zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/libraries/sts-common-util/sts-sdk/plugin/gradlew b/libraries/sts-common-util/sts-sdk/plugin/gradlew
new file mode 100755
index 0000000..1aa94a4
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/plugin/gradlew
@@ -0,0 +1,249 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# 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
+#
+#      https://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.
+#
+
+##############################################################################
+#
+#   Gradle start up script for POSIX generated by Gradle.
+#
+#   Important for running:
+#
+#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+#       noncompliant, but you have some other compliant shell such as ksh or
+#       bash, then to run this script, type that shell name before the whole
+#       command line, like:
+#
+#           ksh Gradle
+#
+#       Busybox and similar reduced shells will NOT work, because this script
+#       requires all of these POSIX shell features:
+#         * functions;
+#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+#         * compound commands having a testable exit status, especially «case»;
+#         * various built-in commands including «command», «set», and «ulimit».
+#
+#   Important for patching:
+#
+#   (2) This script targets any POSIX shell, so it avoids extensions provided
+#       by Bash, Ksh, etc; in particular arrays are avoided.
+#
+#       The "traditional" practice of packing multiple parameters into a
+#       space-separated string is a well documented source of bugs and security
+#       problems, so this is (mostly) avoided, by progressively accumulating
+#       options in "$@", and eventually passing that to Java.
+#
+#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+#       see the in-line comments for details.
+#
+#       There are tweaks for specific operating systems such as AIX, CygWin,
+#       Darwin, MinGW, and NonStop.
+#
+#   (3) This script is generated from the Groovy template
+#       https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+#       within the Gradle project.
+#
+#       You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+    APP_HOME=${app_path%"${app_path##*/}"}  # leaves a trailing /; empty if no leading path
+    [ -h "$app_path" ]
+do
+    ls=$( ls -ld "$app_path" )
+    link=${ls#*' -> '}
+    case $link in             #(
+      /*)   app_path=$link ;; #(
+      *)    app_path=$APP_HOME$link ;;
+    esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+    echo "$*"
+} >&2
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in                #(
+  CYGWIN* )         cygwin=true  ;; #(
+  Darwin* )         darwin=true  ;; #(
+  MSYS* | MINGW* )  msys=true    ;; #(
+  NONSTOP* )        nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD=$JAVA_HOME/jre/sh/java
+    else
+        JAVACMD=$JAVA_HOME/bin/java
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD=java
+    if ! command -v java >/dev/null 2>&1
+    then
+        die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+    case $MAX_FD in #(
+      max*)
+        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+        # shellcheck disable=SC2039,SC3045
+        MAX_FD=$( ulimit -H -n ) ||
+            warn "Could not query maximum file descriptor limit"
+    esac
+    case $MAX_FD in  #(
+      '' | soft) :;; #(
+      *)
+        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+        # shellcheck disable=SC2039,SC3045
+        ulimit -n "$MAX_FD" ||
+            warn "Could not set maximum file descriptor limit to $MAX_FD"
+    esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+#   * args from the command line
+#   * the main class name
+#   * -classpath
+#   * -D...appname settings
+#   * --module-path (only if needed)
+#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+    APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+    CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+    JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    for arg do
+        if
+            case $arg in                                #(
+              -*)   false ;;                            # don't mess with options #(
+              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath
+                    [ -e "$t" ] ;;                      #(
+              *)    false ;;
+            esac
+        then
+            arg=$( cygpath --path --ignore --mixed "$arg" )
+        fi
+        # Roll the args list around exactly as many times as the number of
+        # args, so each arg winds up back in the position where it started, but
+        # possibly modified.
+        #
+        # NB: a `for` loop captures its iteration list before it begins, so
+        # changing the positional parameters here affects neither the number of
+        # iterations, nor the values presented in `arg`.
+        shift                   # remove old arg
+        set -- "$@" "$arg"      # push replacement arg
+    done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+#   * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+#     and any embedded shellness will be escaped.
+#   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+#     treated as '${Hostname}' itself on the command line.
+
+set -- \
+        "-Dorg.gradle.appname=$APP_BASE_NAME" \
+        -classpath "$CLASSPATH" \
+        org.gradle.wrapper.GradleWrapperMain \
+        "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+    die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+#   readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+#   set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+        printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+        xargs -n1 |
+        sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+        tr '\n' ' '
+    )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/libraries/sts-common-util/sts-sdk/plugin/plugin/build.gradle.kts b/libraries/sts-common-util/sts-sdk/plugin/plugin/build.gradle.kts
new file mode 100644
index 0000000..44bf5ac
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/plugin/plugin/build.gradle.kts
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2024 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.
+ */
+
+plugins {
+    // Apply the Java Gradle plugin development plugin to add support for developing Gradle plugins
+    `java-gradle-plugin`
+
+    // Apply the Kotlin JVM plugin to add support for Kotlin.
+    alias(libs.plugins.jvm)
+
+    `maven-publish`
+
+    alias(libs.plugins.androidApp) apply false
+    alias(libs.plugins.androidLib) apply false
+}
+
+dependencies {
+    implementation("com.android.tools.build:gradle:8.2.2")
+
+    // Use the Kotlin JUnit 5 integration.
+    testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
+
+    testRuntimeOnly("org.junit.platform:junit-platform-launcher")
+
+    // https://mvnrepository.com/artifact/com.google.code.gson/gson
+    implementation("com.google.code.gson:gson:2.10")
+}
+
+java {
+    toolchain {
+        // The Android Gradle Plugin is currently only compatible with Java 17
+        languageVersion = JavaLanguageVersion.of(17)
+    }
+}
+
+// Define the overall plugin
+group = "com.android.sts.sdk"
+
+version = "1.0.0"
+
+// Define the individual sub-plugins
+gradlePlugin {
+    plugins {
+        create("stsSdkBasePlugin") {
+            id = "com.android.sts.sdk.base"
+            implementationClass = "com.android.sts.StsSdkBasePlugin"
+        }
+        create("stsSdkSubmissionPlugin") {
+            id = "com.android.sts.sdk.submission"
+            implementationClass = "com.android.sts.StsSdkSubmissionPlugin"
+        }
+        create("StsSdkJavaHostTestPlugin") {
+            id = "com.android.sts.sdk.javahosttest"
+            implementationClass = "com.android.sts.StsSdkJavaHostTestPlugin"
+        }
+        create("StsSdkAppTestPlugin") {
+            id = "com.android.sts.sdk.apptest"
+            implementationClass = "com.android.sts.StsSdkAppTestPlugin"
+        }
+        create("StsSdkNdkTestPlugin") {
+            id = "com.android.sts.sdk.ndktest"
+            implementationClass = "com.android.sts.StsSdkNdkTestPlugin"
+        }
+    }
+}
diff --git a/libraries/sts-common-util/sts-sdk/plugin/plugin/src/main/kotlin/com/android/sts/StsSdkAppTestPlugin.kt b/libraries/sts-common-util/sts-sdk/plugin/plugin/src/main/kotlin/com/android/sts/StsSdkAppTestPlugin.kt
new file mode 100644
index 0000000..75b0971
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/plugin/plugin/src/main/kotlin/com/android/sts/StsSdkAppTestPlugin.kt
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2024 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.sts
+
+import com.android.build.api.artifact.SingleArtifact
+import com.android.build.api.variant.ApplicationAndroidComponentsExtension
+import com.android.build.gradle.internal.dsl.BaseAppModuleExtension
+import com.google.gson.Gson
+import java.io.BufferedWriter
+import org.gradle.api.GradleException
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.api.tasks.Copy
+
+// This is a restricted version of the "android" extension block provided by the AGP
+// The interface is restricted to simplify the translation between AGP and the Android Build System
+// More fields can be added here in response to needs that arise
+// All fields must be JSON serializable for inclusion in the submission zip
+// https://developer.android.com/guide/app-bundle/configure-base
+// See "android_test_helper_app" at the "Soong reference files"
+// https://ci.android.com/builds/latest/branches/aosp-build-tools/targets/linux/view/soong_build.html
+open class AppTestExtension {
+    var minSdk: Int = 31 // oldest security-supported
+    var targetSdk: Int = 34 // newest security-supported
+    var compileSdk: Int = 34 // compile = target
+}
+
+class StsSdkAppTestPlugin : Plugin<Project> {
+    override fun apply(project: Project) {
+        val namespace = "android.security.sts"
+        val appTest = project.extensions.create("appTest", AppTestExtension::class.java)
+
+        // The APK artifact will be published to the "stsSdkTestResource" configuration
+        project.plugins.apply("com.android.sts.sdk.base")
+
+        val writeManifestTask =
+            project.tasks.register("writeManifestTask") { task ->
+                task.outputs.file(
+                    project.layout.buildDirectory.file("sts-sdk/sts-sdk-manifest.json")
+                )
+                task.doLast {
+                    val writer = BufferedWriter(task.outputs.files.singleFile.writer())
+                    val moduleManifest =
+                        StsSdkBasePlugin.ModuleManifest<AppTestExtension>(
+                            project,
+                            "AppTest",
+                            appTest
+                        )
+                    writer.use { out -> out.write(Gson().toJson(moduleManifest)) }
+                }
+            }
+
+        // Perform this work in the "afterEvaluate" callback because the extensions are not
+        // initialized yet.
+        project.afterEvaluate {
+            project.plugins.apply("com.android.application")
+
+            // https://developer.android.com/build/configure-app-module
+            // "All characters must be alphanumeric or an underscore [a-zA-Z0-9_]."
+            val nameRegex = """[a-zA-Z0-9_]+""".toRegex()
+            if (!project.name.matches(nameRegex)) {
+                throw GradleException("Project name doesn't match $nameRegex: ${project.name}")
+            }
+
+            // Because every module must be unique, append a placeholder to find/replace on import.
+            // https://source.android.com/docs/setup/reference/androidbp
+            // "every module must have a name property, and the value must be unique"
+            val rename = project.name + "_StsSdkPlaceholder"
+
+            // Copy our restricted-scope AppTestExtension into the normal Android extension
+            // BaseAppModuleExtension is internal to the AGP, but is widely used by similar
+            // extensions and unlikely to break
+            project.extensions.configure<BaseAppModuleExtension>("android") {
+                // Base on the Gradle project name so each APK is guaranteed to have unique id
+                it.defaultConfig.applicationId = "$namespace.$rename"
+                // Set the namespace to reduce refactoring requirements for STS integration
+                // https://developer.android.com/build/configure-app-module#set-namespace
+                it.namespace = namespace
+                it.compileSdk = appTest.compileSdk
+                it.defaultConfig.minSdk = appTest.minSdk
+                it.defaultConfig.targetSdk = appTest.targetSdk
+            }
+
+            val implementationConfiguration = project.configurations.getByName("implementation")
+            // TODO: https://github.com/gradle/gradle/issues/16634 - Can't use version catalog
+            // because the extension is not registered by subproject or root project
+            listOf(
+                    "androidx.appcompat:appcompat:1.6.1",
+                    "androidx.core:core:1.13.1",
+                    "com.google.android.material:material:1.12.0",
+                    "junit:junit:4.13.2",
+                    "androidx.test.ext:junit:1.1.5",
+                    "androidx.test.espresso:espresso-core:3.5.1",
+                    "androidx.test.uiautomator:uiautomator:2.3.0",
+                    "org.jetbrains.kotlin:kotlin-stdlib:1.8.22"
+                )
+                .forEach { dependencyString ->
+                    implementationConfiguration.dependencies.add(
+                        project.dependencies.create(dependencyString)
+                    )
+                }
+
+            // Register callbacks for "onVariants" so that we can attach the APK to the
+            // stsSdkTestResource configuration.
+            // This is the technique used by the "gradle-play-publisher" plugin
+            // https://developer.android.com/reference/tools/gradle-api/8.3/com/android/build/api/variant/AndroidComponentsExtension
+            // The order of this task is sensitive because the callbacks must be registered before
+            // they are called internally.
+            // The best time to register the callbacks is immediately when applying the plugin.
+            val androidComponentsExtension =
+                project.extensions.getByType(ApplicationAndroidComponentsExtension::class.java)
+            androidComponentsExtension.onVariants(androidComponentsExtension.selector().all()) {
+                variant ->
+                // We only care about the debug variant for now; release APKs don't have any
+                // features needed for STS.
+                // If necessary, add a field to AppTestExtension to control this
+                val variantName = variant.name
+                if (variantName == "debug") {
+                    // This is the same as the "outgoing variant" for "*RuntimeElement" secondary
+                    // variant "apk"
+                    // It's the dir containing the APK; typically "build/outputs/apk/debug"
+                    val apkDir = variant.artifacts.get(SingleArtifact.APK)
+                    val copyAppTestcaseResourceTask =
+                        project.tasks.register<Copy>(
+                            "copyAppTestcaseResource-$variantName",
+                            Copy::class.java
+                        ) { task ->
+                            task.from(apkDir) {
+                                // Rename to expected Soong module name
+                                it.rename(".*\\.apk", rename + ".apk")
+                                // Only include apks (glob, not regex)
+                                it.include("*.apk")
+                            }
+                            task.into(project.layout.buildDirectory.dir("sts-sdk/testcases/"))
+                        }
+
+                    val copyAppTestcaseResourceTasks =
+                        StsSdkBasePlugin.Abi.entries.map { abi ->
+                            Pair(abi, copyAppTestcaseResourceTask)
+                        }
+                    StsSdkBasePlugin.applyConfiguration(
+                        project = project,
+                        sourceDirectoryArtifact = project.layout.projectDirectory.dir("src/main"),
+                        manifestArtifact = writeManifestTask,
+                        resourceArtifacts = copyAppTestcaseResourceTasks
+                    )
+                }
+            }
+        }
+    }
+}
diff --git a/libraries/sts-common-util/sts-sdk/plugin/plugin/src/main/kotlin/com/android/sts/StsSdkBasePlugin.kt b/libraries/sts-common-util/sts-sdk/plugin/plugin/src/main/kotlin/com/android/sts/StsSdkBasePlugin.kt
new file mode 100644
index 0000000..a764224
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/plugin/plugin/src/main/kotlin/com/android/sts/StsSdkBasePlugin.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2024 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.sts
+
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.api.attributes.Attribute
+
+class StsSdkBasePlugin : Plugin<Project> {
+    class AbiAttributes(name: String, bitness: Int) {
+        val name = name
+        val bitness = bitness
+    }
+
+    // https://developer.android.com/ndk/guides/abis#sa
+    enum class Abi(val attr: AbiAttributes) {
+        ABI_ARMEABI_V7A(AbiAttributes("armeabi-v7a", 32)),
+        ABI_ARM64_V8A(AbiAttributes("arm64-v8a", 64)),
+        ABI_X86(AbiAttributes("x86", 32)),
+        ABI_X86_64(AbiAttributes("x86_64", 64)),
+    }
+
+    companion object {
+        val STS_SDK_TESTCASES_RESOURCE_CONFIGURATION_NAME = "stsSdkTestResource"
+
+        fun applyConfiguration(
+            project: Project,
+            sourceDirectoryArtifact: Any,
+            manifestArtifact: Any,
+            resourceArtifacts: List<Pair<Abi, Any>>,
+        ) {
+            val stsSdkTestResourceConfiguration =
+                project.configurations.getByName(STS_SDK_TESTCASES_RESOURCE_CONFIGURATION_NAME)
+            val abiAttribute = Attribute.of("com.android.sts.sdk.abi", Abi::class.java)
+            stsSdkTestResourceConfiguration.outgoing { configurationPublications ->
+                configurationPublications.artifact(sourceDirectoryArtifact) {
+                    configurePublishArtifact ->
+                    configurePublishArtifact.setType("source")
+                }
+                configurationPublications.artifact(manifestArtifact) { configurePublishArtifact ->
+                    configurePublishArtifact.setType("manifest")
+                }
+                configurationPublications.variants { namedDomainObjectContainer ->
+                    resourceArtifacts.forEach { resourceArtifact ->
+                        val (abi, artifact) = resourceArtifact
+                        val abiName = abi.attr.name
+                        namedDomainObjectContainer.create("abi-$abiName") { configurationVariant ->
+                            configurationVariant.attributes { attributeContainer ->
+                                attributeContainer.attribute(abiAttribute, abi)
+                            }
+                            configurationVariant.artifact(artifact) { configurablePublishArtifact ->
+                                configurablePublishArtifact.setType("resource")
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    override fun apply(project: Project) {
+        // Export a configuration for users to add dependencies.
+        // "stsSdkTestResource" represents Soong modules for the Tradefed testcases/ directory.
+        // See "android_test_helper_app" and "cc_test" Soong modules.
+        // Dependencies should map 1:1 to tradefed Android.bp files for easy reconstruction.
+        project.configurations.create(STS_SDK_TESTCASES_RESOURCE_CONFIGURATION_NAME) { configuration
+            ->
+            configuration.isCanBeConsumed = true
+            configuration.isCanBeResolved = false
+        }
+    }
+
+    class ModuleManifest<T>(project: Project, type: String, resource: T) {
+        val name: String = project.name
+        val type: String = type
+        val resource: T = resource
+    }
+}
diff --git a/libraries/sts-common-util/sts-sdk/plugin/plugin/src/main/kotlin/com/android/sts/StsSdkJavaHostTestPlugin.kt b/libraries/sts-common-util/sts-sdk/plugin/plugin/src/main/kotlin/com/android/sts/StsSdkJavaHostTestPlugin.kt
new file mode 100644
index 0000000..3963972
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/plugin/plugin/src/main/kotlin/com/android/sts/StsSdkJavaHostTestPlugin.kt
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2024 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.sts
+
+import com.google.gson.Gson
+import java.io.BufferedWriter
+import java.util.regex.Pattern
+import org.gradle.api.GradleException
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.api.tasks.Copy
+import org.gradle.api.tasks.SourceSetContainer
+
+class StsSdkJavaHostTestPlugin : Plugin<Project> {
+    override fun apply(project: Project) {
+        val pluginJarUrl = this.javaClass.getProtectionDomain().getCodeSource().getLocation()
+
+        project.plugins.apply("java-library")
+        val compileOnlyConfiguration = project.configurations.getByName("compileOnly")
+        val dependencies =
+            project.dependencies.create(
+                project.zipTree(pluginJarUrl).matching { filter ->
+                    filter.include(
+                        listOf(
+                            "sts-tradefed-tools/sts-tradefed.jar",
+                            "sts-tradefed-tools/tradefed.jar",
+                            "sts-tradefed-tools/compatibility-host-util.jar",
+                            "sts-tradefed-tools/sts-host-util.jar",
+                            "sts-tradefed-tools/hamcrest-library.jar",
+                        )
+                    )
+                }
+            )
+        compileOnlyConfiguration.dependencies.add(dependencies)
+
+        val writeManifestTask =
+            project.tasks.register("writeManifestTask") { task ->
+                task.outputs.file(
+                    project.layout.buildDirectory.file("sts-sdk/sts-sdk-manifest.json")
+                )
+                task.doLast {
+                    val writer = BufferedWriter(task.outputs.files.singleFile.writer())
+                    // Note: this module has no extension so using Kotlin Unit as void/null
+                    val moduleManifest =
+                        StsSdkBasePlugin.ModuleManifest<Unit>(project, "JavaHostTest", Unit)
+                    writer.use { out -> out.write(Gson().toJson(moduleManifest)) }
+                }
+            }
+
+        val copyTestcasesResourcesTask =
+            project.tasks.register<Copy>("copyTestcasesResourcesJar", Copy::class.java) { task ->
+                task.from(project.tasks.getByName("jar")) { copySpec ->
+                    copySpec.rename(".*", "HostsideTest.jar")
+                }
+                task.from(project.zipTree(pluginJarUrl)) { copySpec ->
+                    // only include the single file instead of all jar contents
+                    copySpec.include("HostsideTest.config")
+                }
+                task.into(project.layout.buildDirectory.dir("android-sts/testcases"))
+            }
+        val copyTestcasesResourcesTasks =
+            StsSdkBasePlugin.Abi.entries.map { abi -> Pair(abi, copyTestcasesResourcesTask) }
+
+        project.plugins.apply("com.android.sts.sdk.base")
+        StsSdkBasePlugin.applyConfiguration(
+            project = project,
+            sourceDirectoryArtifact = project.layout.projectDirectory.dir("src/main"),
+            manifestArtifact = writeManifestTask,
+            resourceArtifacts = copyTestcasesResourcesTasks
+        )
+
+        val verifyPackageNamesTask =
+            project.tasks.register("verifyPackageNames") { task ->
+                task.doLast {
+                    val sourceSets = project.extensions.getByType(SourceSetContainer::class.java)
+                    sourceSets.getByName("main").java.forEach { file ->
+                        val expectedPackagePrefix = "android.security.sts.sts_sdk_placeholder"
+                        val fileText = file.readText()
+                        // Extract the package from the Java file
+                        val packageRegex = """^package\s+(?<package>[\w.]+);?$"""
+                        val packageMatcher =
+                            Pattern.compile(packageRegex, Pattern.MULTILINE).matcher(fileText)
+                        if (!packageMatcher.find()) {
+                            throw GradleException("Could not find package pattern in file: $file")
+                        }
+                        val packageName = packageMatcher.group("package")
+                        if (packageName == null) {
+                            throw GradleException("Could not find package name in file: $file")
+                        }
+                        if (!packageName.startsWith(expectedPackagePrefix)) {
+                            throw GradleException(
+                                "Package name doesn't start with \"$expectedPackagePrefix\" in " +
+                                    "file: $file"
+                            )
+                        }
+                    }
+                }
+            }
+
+        val verifyResourcesTask =
+            project.tasks.register("verifyResources") { task ->
+                task.doLast {
+                    val sourceSets = project.extensions.getByType(SourceSetContainer::class.java)
+                    val resourcesSourceSet = sourceSets.getByName("main").resources
+                    val expectedResourceDirectory = "StsSdkPlaceholder"
+
+                    val invalidPrefixResourceIterator =
+                        resourcesSourceSet.asFileTree
+                            .matching { patternFilterable ->
+                                patternFilterable.exclude(expectedResourceDirectory)
+                            }
+                            .iterator()
+                    if (invalidPrefixResourceIterator.hasNext()) {
+                        val invalidPrefixResources =
+                            invalidPrefixResourceIterator.asSequence().toList()
+                        throw GradleException(
+                            "All resource files need to be contained within " +
+                                "$expectedResourceDirectory/ in the resources directory: " +
+                                "$invalidPrefixResources"
+                        )
+                    }
+                }
+            }
+
+        // Perform verification when classes are being compiled.
+        project.tasks.named("classes").configure { task ->
+            task.dependsOn(verifyPackageNamesTask, verifyResourcesTask)
+        }
+    }
+}
diff --git a/libraries/sts-common-util/sts-sdk/plugin/plugin/src/main/kotlin/com/android/sts/StsSdkNdkTestPlugin.kt b/libraries/sts-common-util/sts-sdk/plugin/plugin/src/main/kotlin/com/android/sts/StsSdkNdkTestPlugin.kt
new file mode 100644
index 0000000..7e8df4a
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/plugin/plugin/src/main/kotlin/com/android/sts/StsSdkNdkTestPlugin.kt
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2024 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.sts
+
+import com.android.build.api.artifact.SingleArtifact
+import com.android.build.api.variant.LibraryAndroidComponentsExtension
+import com.android.build.gradle.LibraryExtension
+import com.google.gson.Gson
+import java.io.BufferedWriter
+import java.io.File
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.api.file.RelativePath
+import org.gradle.api.tasks.Copy
+
+open class NdkTestExtension {
+    var minSdk: Int = 31 // oldest security-supported
+    var targetSdk: Int = 34 // newest security-supported
+    var compileSdk: Int = 34 // compile = target
+}
+
+class StsSdkNdkTestPlugin : Plugin<Project> {
+    override fun apply(project: Project) {
+        val nativeTest = project.extensions.create("nativeTest", NdkTestExtension::class.java)
+
+        project.plugins.apply("com.android.sts.sdk.base")
+        val ndkTest = project.extensions.create("appTest", NdkTestExtension::class.java)
+
+        val writeManifestTask =
+            project.tasks.register("writeManifestTask") { task ->
+                task.outputs.file(
+                    project.layout.buildDirectory.file("sts-sdk/sts-sdk-manifest.json")
+                )
+                task.doLast {
+                    val writer = BufferedWriter(task.outputs.files.singleFile.writer())
+                    val moduleManifest =
+                        StsSdkBasePlugin.ModuleManifest<NdkTestExtension>(
+                            project,
+                            "NdkTest",
+                            ndkTest
+                        )
+                    writer.use { out -> out.write(Gson().toJson(moduleManifest)) }
+                }
+            }
+
+        project.afterEvaluate {
+            val rename = project.name + "_StsSdkPlaceholder"
+
+            project.plugins.apply("com.android.library")
+            project.extensions.configure<LibraryExtension>("android") {
+                it.namespace = "com.android.sts"
+                it.compileSdk = nativeTest.compileSdk
+                it.externalNativeBuild.cmake.path = File("CMakeLists.txt")
+                // externalNativeBuild.cmake.version will be automatically set
+                it.defaultConfig.targetSdk = nativeTest.targetSdk
+                it.defaultConfig.minSdk = nativeTest.minSdk
+
+                // publish the pocs to the .aar artifact
+                // https://developer.android.com/build/native-dependencies?agpversion=4.1#publish-native-libs-in-aars
+                it.buildFeatures.prefabPublishing = true
+                it.prefab.create(project.name)
+            }
+
+            val androidComponentsExtension =
+                project.extensions.getByType(LibraryAndroidComponentsExtension::class.java)
+            androidComponentsExtension.onVariants { variant ->
+                val projectName = project.name
+                val variantName = variant.name
+                // Only select the "debug" variant
+                if (variantName == "debug") {
+                    val aarDir = variant.artifacts.get(SingleArtifact.AAR)
+                    val copyNdkTestcaseResourceTasks =
+                        StsSdkBasePlugin.Abi.entries.map { abi ->
+                            val abiName = abi.attr.name
+                            val aarPrefabPath =
+                                "prefab/modules/$projectName/libs/android.$abiName/$projectName"
+                            val copyNdkTestcaseResourceTask =
+                                project.tasks.register<Copy>(
+                                    "copyNdkTestcaseResource-$variantName-$abiName",
+                                    Copy::class.java
+                                ) { task ->
+                                    task.from(project.zipTree(aarDir)) { copySpec ->
+                                        copySpec.include(aarPrefabPath)
+                                        copySpec.rename(".*", "${rename}_sts${abi.attr.bitness}")
+                                        copySpec.eachFile { fileCopyDetails ->
+                                            // drop the path prefix
+                                            fileCopyDetails.relativePath =
+                                                RelativePath(
+                                                    true /* endsWithFile */,
+                                                    fileCopyDetails.relativePath.lastName
+                                                )
+                                        }
+                                        copySpec.includeEmptyDirs = false
+                                    }
+                                    task.into(
+                                        project.layout.buildDirectory.dir(
+                                            "sts-sdk/resources/$abiName"
+                                        )
+                                    )
+                                }
+                            Pair(abi, copyNdkTestcaseResourceTask)
+                        }
+                    StsSdkBasePlugin.applyConfiguration(
+                        project = project,
+                        sourceDirectoryArtifact = project.layout.projectDirectory.dir("src"),
+                        manifestArtifact = writeManifestTask,
+                        resourceArtifacts = copyNdkTestcaseResourceTasks
+                    )
+                }
+            }
+        }
+    }
+}
diff --git a/libraries/sts-common-util/sts-sdk/plugin/plugin/src/main/kotlin/com/android/sts/StsSdkSubmissionPlugin.kt b/libraries/sts-common-util/sts-sdk/plugin/plugin/src/main/kotlin/com/android/sts/StsSdkSubmissionPlugin.kt
new file mode 100644
index 0000000..ad76c7a
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/plugin/plugin/src/main/kotlin/com/android/sts/StsSdkSubmissionPlugin.kt
@@ -0,0 +1,365 @@
+/*
+ * Copyright 2024 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.sts
+
+import com.google.gson.Gson
+import com.google.gson.GsonBuilder
+import com.google.gson.JsonArray
+import com.google.gson.JsonObject
+import com.google.gson.JsonParser
+import java.nio.file.Files
+import org.gradle.api.Action
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.api.artifacts.Configuration
+import org.gradle.api.artifacts.ProjectDependency
+import org.gradle.api.attributes.Attribute
+import org.gradle.api.file.RelativePath
+import org.gradle.api.tasks.Copy
+import org.gradle.api.tasks.bundling.Zip
+
+open class StsSdkSubmissionExtension {
+    var deviceType: String? = null // phone, tv, wear, etc. enum?
+    var isRootRequired: Boolean = false
+    var isExternalHardwareRequired: Boolean = false // string?
+    var isPersistentExploit: Boolean = false
+}
+
+class StsSdkSubmissionPlugin : Plugin<Project> {
+    val taskGroup = "STS SDK"
+    val stsSdkSubmissionSourcesDir = "sts-sdk-submission"
+    val stsSdkTradefedDir = "android-sts"
+
+    // get plugin jar path from current class; plugin jar has resources
+    val pluginJarUrl = this.javaClass.getProtectionDomain().getCodeSource().getLocation()
+
+    val abiAttribute = Attribute.of("com.android.sts.sdk.abi", StsSdkBasePlugin.Abi::class.java)
+    var stsSdkTestResourceConfiguration: Configuration? = null
+
+    fun dependencyProjectConfiguration(
+        project: Project,
+        configuration: Configuration,
+        action: Action<Pair<Project, Configuration>>,
+    ) {
+        // By default, Gradle considers "evaluation" of the "configure" lifecycle to be done before
+        // the subprojects/dependencies are "configured/evaluated".
+        // This means that we can't process the subproject's configurations or artifacts unless this
+        // is set.
+        // Note: This likely only works for subprojects instead of all dependencies. I don't see
+        // another way because dependencies aren't available until afterEvaluate.
+        project.evaluationDependsOnChildren()
+
+        // Need to perform this work in the "afterEvaluate" callback because the extensions,
+        // dependencies, and dependency artifacts are not initialized yet.
+        project.afterEvaluate {
+            configuration.dependencies.forEach { dependency ->
+                if (dependency is ProjectDependency) {
+                    val dependencyProject = dependency.dependencyProject
+                    val dependencyConfiguration =
+                        dependencyProject.configurations.getByName(configuration.name)
+                    action.execute(Pair(dependencyProject, dependencyConfiguration))
+                }
+            }
+        }
+    }
+
+    fun registerAssembleStsSdkTradefedTask(
+        project: Project,
+        target: String,
+        abis: Set<StsSdkBasePlugin.Abi>,
+    ) {
+        val copyStsSdkTradefedToolsTask =
+            project.tasks.register<Copy>("copyStsSdkTradefedTools-$target", Copy::class.java) { task
+                ->
+                // use ziptree to copy the zip contents instead of the jar itself
+                task.from(project.zipTree(pluginJarUrl)) { copySpec ->
+                    // only include the "sts-tradefed-tools" path instead of all jar contents
+                    copySpec.include("sts-tradefed-tools/**")
+                    copySpec.eachFile { fileCopyDetails ->
+                        // drop the "sts-tradefed-tools" path prefix
+                        fileCopyDetails.relativePath =
+                            RelativePath(
+                                true /* endsWithFile */,
+                                *fileCopyDetails.relativePath.segments.drop(1).toTypedArray()
+                            )
+                    }
+                    // don't include the "sts-tradefed-tools" dir itself
+                    copySpec.includeEmptyDirs = false
+                }
+                task.into(project.layout.buildDirectory.dir("$target/$stsSdkTradefedDir/tools"))
+            }
+
+        val copyTradefedJdkTask =
+            project.tasks.register<Copy>("copyTradefedJdk-$target", Copy::class.java) { task ->
+                task.from(project.zipTree(pluginJarUrl)) { copySpec -> copySpec.include("jdk/**") }
+                task.into(project.layout.buildDirectory.dir("$target/$stsSdkTradefedDir"))
+            }
+
+        val assembleStsSdkTradefedTask =
+            project.tasks.register("assembleStsSdkTradefed-$target") { task ->
+                task.description =
+                    "Assemble the STS SDK Tradefed executable test suite for $target."
+                task.group = taskGroup
+                task.dependsOn(
+                    copyStsSdkTradefedToolsTask,
+                    copyTradefedJdkTask,
+                )
+            }
+
+        abis.forEach { abi ->
+            dependencyProjectConfiguration(project, stsSdkTestResourceConfiguration!!) {
+                dependencyProjectConfigurationPair ->
+                val (dependencyProject, dependencyConfiguration) =
+                    dependencyProjectConfigurationPair
+                val projectName = dependencyProject.name
+                dependencyConfiguration.outgoing { configurationPublications ->
+                    configurationPublications.variants { namedDomainObjectContainer ->
+                        namedDomainObjectContainer
+                            .filter { configurationVariant ->
+                                configurationVariant.attributes.getAttribute(abiAttribute) == abi
+                            }
+                            .forEach { configurationVariant ->
+                                val abiName = abi.attr.name
+                                configurationVariant.artifacts
+                                    .filter { publishArtifact ->
+                                        publishArtifact.type == "resource"
+                                    }
+                                    .forEach { publishArtifact ->
+                                        val copyTestcaseResourceTaskName =
+                                            "copyTestcaseResource-$target-$projectName-$abiName"
+                                        val copyTestcaseResourceTask =
+                                            project.tasks.register<Copy>(
+                                                copyTestcaseResourceTaskName,
+                                                Copy::class.java
+                                            ) { task ->
+                                                // Don't copy until entire task done
+                                                task.dependsOn(publishArtifact)
+                                                // TODO:
+                                                // https://github.com/gradle/gradle/issues/25587 -
+                                                // use publishArtifact directly
+                                                task.from(publishArtifact.file)
+                                                task.into(
+                                                    project.layout.buildDirectory.dir(
+                                                        "$target/$stsSdkTradefedDir/testcases"
+                                                    )
+                                                )
+                                            }
+                                        assembleStsSdkTradefedTask.configure { task ->
+                                            task.dependsOn(copyTestcaseResourceTask)
+                                        }
+                                    }
+                            }
+                    }
+                }
+            }
+        }
+
+        // Build STS SDK Tradefed tasks on assemble
+        project.tasks.named("assemble").configure { task ->
+            task.dependsOn(assembleStsSdkTradefedTask)
+        }
+    }
+
+    override fun apply(project: Project) {
+        val stsSdkSubmissionExtension =
+            project.extensions.create("stsSdkSubmission", StsSdkSubmissionExtension::class.java)
+
+        stsSdkTestResourceConfiguration =
+            project.configurations.create("stsSdkTestResource") { configuration ->
+                configuration.isCanBeConsumed = false
+                configuration.isCanBeResolved = true
+            }
+
+        // The standard lifecycle tasks including `assemble` are defined in `base`
+        // By applying the plugin, we essentially export it
+        // Without it, users will hit an error that "assemble" isn't found
+        project.plugins.apply("base")
+
+        val mergeManifestsTask =
+            project.tasks.register("mergeManifests") { task ->
+                task.outputs.file(
+                    // project.layout.buildDirectory.file("sts-sdk-submission/manifest.json")
+                    project.layout.buildDirectory.dir("$stsSdkSubmissionSourcesDir/manifest.json")
+                )
+                task.doLast {
+                    val submissionJson = JsonObject()
+                    val resources = JsonArray()
+                    task.inputs.files.forEach {
+                        val resourcesJsonString = Files.readString(it.toPath())
+                        resources.add(JsonParser.parseString(resourcesJsonString))
+                    }
+                    submissionJson.add("resources", resources)
+                    submissionJson.add("submission", Gson().toJsonTree(stsSdkSubmissionExtension))
+                    val gson = GsonBuilder().setPrettyPrinting().create()
+                    val jsonOutput = gson.toJson(submissionJson)
+                    task.outputs.files.singleFile.writeText(jsonOutput)
+                }
+            }
+
+        val copyRootProjectTask =
+            project.tasks.register<Copy>("copyRootProject", Copy::class.java) { task ->
+                val rootProjectDir = project.rootProject.layout.projectDirectory
+                task.from(rootProjectDir) { copySpec ->
+                    // Ignore system-specific files
+                    copySpec.exclude("local.properties")
+
+                    // Ignore gradle build
+                    project.rootProject.subprojects.forEach { subproject ->
+                        // exclude must be a String pattern relative to the copySpec "from"
+                        val subprojectBuildDirFile = subproject.layout.buildDirectory.asFile.get()
+                        copySpec.exclude(
+                            subprojectBuildDirFile.relativeTo(rootProjectDir.asFile).toString()
+                        )
+                    }
+                    // Ignore Gradle work dir and executable files
+                    copySpec.exclude(".gradle")
+                    copySpec.exclude("gradle")
+                    copySpec.exclude("gradlew")
+                    copySpec.exclude("gradlew.bat")
+
+                    // Ignore git
+                    copySpec.exclude(".git*")
+
+                    // Ignore Idea workspace files
+                    copySpec.exclude(".idea")
+
+                    // Ignore native build directories
+                    copySpec.exclude("**/.cxx")
+                }
+                task.into(project.layout.buildDirectory.dir("$stsSdkSubmissionSourcesDir/project"))
+            }
+
+        val assembleStsSdkSubmissionSourcesTask =
+            project.tasks.register("assembleStsSdkSubmissionSources") { task ->
+                task.description = "Assemble the source files for the submission zip."
+                task.group = taskGroup
+                task.dependsOn(mergeManifestsTask)
+                task.dependsOn(copyRootProjectTask)
+                task.outputs.file(project.layout.buildDirectory.dir(stsSdkSubmissionSourcesDir))
+            }
+
+        val assembleStsSdkSubmissionZipTask =
+            project.tasks.register<Zip>("assembleStsSdkSubmissionZip", Zip::class.java) { task ->
+                task.description = "Assemble the submission zip for upload."
+                task.group = taskGroup
+                task.from(assembleStsSdkSubmissionSourcesTask)
+                task.archiveFileName.set("sts-sdk-submission.zip")
+                task.destinationDirectory.set(project.layout.buildDirectory)
+            }
+
+        // matching Android Build configs
+        val targetToMultiAbiSets =
+            mapOf(
+                "test_suites_arm64" to
+                    setOf(StsSdkBasePlugin.Abi.ABI_ARMEABI_V7A, StsSdkBasePlugin.Abi.ABI_ARM64_V8A),
+                "test_suites_x86_64" to
+                    setOf(StsSdkBasePlugin.Abi.ABI_X86, StsSdkBasePlugin.Abi.ABI_X86_64),
+            )
+        targetToMultiAbiSets.entries.forEach { mapEntry ->
+            val (target, abis) = mapEntry
+            registerAssembleStsSdkTradefedTask(project, target, abis)
+        }
+
+        // By default, Gradle considers "evaluation" of the "configure" lifecycle to be done before
+        // the subprojects/dependencies are "configured/evaluated".
+        // This means that we can't process the subproject's configurations or artifacts unless this
+        // is set.
+        // Note: This likely only works for subprojects instead of all dependencies. I don't see
+        // another way because dependencies aren't available until afterEvaluate.
+        project.evaluationDependsOnChildren()
+
+        // Need to perform this work in the "afterEvaluate" callback because the extensions,
+        // dependencies, and dependency artifacts are not initialized yet.
+        project.afterEvaluate {
+            stsSdkTestResourceConfiguration!!.dependencies.forEach { dependency ->
+                if (dependency is ProjectDependency) {
+                    val dependencyProject = dependency.dependencyProject
+                    val configuration =
+                        dependencyProject.configurations.getByName(
+                            stsSdkTestResourceConfiguration!!.name
+                        )
+                    val projectName = dependencyProject.name
+
+                    configuration.artifacts.forEach { publishArtifact ->
+                        when (publishArtifact.type) {
+                            "manifest" -> {
+                                mergeManifestsTask.configure { task ->
+                                    task.dependsOn(dependencyProject.tasks.getByName("assemble"))
+                                    task.inputs.file(publishArtifact.file)
+                                }
+                            }
+                            "source" -> {
+                                val copyStsSdkTestcaseResourceSourceTask =
+                                    project.tasks.register<Copy>(
+                                        "copyStsSdkTestcaseResourceSource-$projectName",
+                                        Copy::class.java
+                                    ) { task ->
+                                        // TODO: https://github.com/gradle/gradle/issues/25587 - use
+                                        // publishArtifact directly
+                                        task.from(publishArtifact.file)
+                                        task.into(
+                                            project.layout.buildDirectory.dir(
+                                                "$stsSdkSubmissionSourcesDir/source/$projectName/"
+                                            )
+                                        )
+                                    }
+                                assembleStsSdkSubmissionSourcesTask.configure { task ->
+                                    task.dependsOn(copyStsSdkTestcaseResourceSourceTask)
+                                }
+                            }
+                            else -> {
+                                throw IllegalStateException(
+                                    "A resource added to the ${configuration.name} configuration " +
+                                        "has an unknown type. name: ${publishArtifact.name}, " +
+                                        "type: ${publishArtifact.type}"
+                                )
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        val copyInvocationResultsResultsToSubmissionTask =
+            project.tasks.register("copyInvocationResultsToSubmission") { task ->
+                task.description =
+                    "Copy the results from previous Tradefed invocations into the STS SDK " +
+                        "submission sources directory to assist with the review process. Note " +
+                        "that this contains logs from both the host and device; please review " +
+                        "the contents before or after running this."
+                task.group = taskGroup
+            }
+        targetToMultiAbiSets.entries.forEach { mapEntry ->
+            val (target, _) = mapEntry
+            val targetTask =
+                project.tasks.register<Copy>(
+                    "copyInvocationResultsToSubmission-$target",
+                    Copy::class.java
+                ) { task ->
+                    task.dependsOn(assembleStsSdkSubmissionZipTask)
+                    task.from(project.layout.buildDirectory.dir("$target/$stsSdkTradefedDir")) {
+                        copySpec ->
+                        copySpec.include("logs/**")
+                        copySpec.include("results/**")
+                    }
+                    task.into(project.layout.buildDirectory.dir(stsSdkSubmissionSourcesDir))
+                }
+            copyInvocationResultsResultsToSubmissionTask.configure { task ->
+                task.dependsOn(targetTask)
+            }
+        }
+    }
+}
diff --git a/libraries/sts-common-util/sts-sdk/package/sts-test/src/hostsidetest.config.tmpl b/libraries/sts-common-util/sts-sdk/plugin/plugin/src/main/resources/HostsideTest.config
similarity index 76%
rename from libraries/sts-common-util/sts-sdk/package/sts-test/src/hostsidetest.config.tmpl
rename to libraries/sts-common-util/sts-sdk/plugin/plugin/src/main/resources/HostsideTest.config
index 39e3867..ed95e86 100644
--- a/libraries/sts-common-util/sts-sdk/package/sts-test/src/hostsidetest.config.tmpl
+++ b/libraries/sts-common-util/sts-sdk/plugin/plugin/src/main/resources/HostsideTest.config
@@ -2,6 +2,6 @@
 
 <configuration description="Runs host-side STS tests">
     <test class="com.android.tradefed.testtype.HostTest" >
-        <option name="jar" value="@@jarname@@" />
+        <option name="jar" value="HostsideTest.jar" />
     </test>
 </configuration>
diff --git a/libraries/sts-common-util/sts-sdk/plugin/settings.gradle.kts b/libraries/sts-common-util/sts-sdk/plugin/settings.gradle.kts
new file mode 100644
index 0000000..2cea965
--- /dev/null
+++ b/libraries/sts-common-util/sts-sdk/plugin/settings.gradle.kts
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2024 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.
+ */
+
+pluginManagement {
+    repositories {
+        gradlePluginPortal()
+        google()
+        mavenCentral()
+    }
+}
+
+dependencyResolutionManagement {
+    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+    repositories {
+        google()
+        mavenCentral()
+    }
+}
+
+rootProject.name = "sts-sdk"
+
+include("plugin")