Merge changes Ic3a55909,I70462293

* changes:
  Always run asan ckati on the build servers
  Add exec.Cmd wrapper for logging / sandboxing
diff --git a/Android.bp b/Android.bp
index 61ef41e..d172fd5 100644
--- a/Android.bp
+++ b/Android.bp
@@ -72,6 +72,7 @@
         "android/expand_test.go",
         "android/paths_test.go",
         "android/prebuilt_test.go",
+        "android/variable_test.go",
     ],
 }
 
@@ -126,6 +127,7 @@
         "cc/prebuilt.go",
         "cc/proto.go",
         "cc/relocation_packer.go",
+        "cc/rs.go",
         "cc/sanitize.go",
         "cc/sabi.go",
         "cc/stl.go",
@@ -209,6 +211,25 @@
     pluginFor: ["soong_build"],
 }
 
+bootstrap_go_package {
+    name: "soong-python",
+    pkgPath: "android/soong/python",
+    deps: [
+        "blueprint",
+        "soong-android",
+    ],
+    srcs: [
+        "python/binary.go",
+        "python/builder.go",
+        "python/library.go",
+        "python/python.go",
+    ],
+    testSrcs: [
+        "python/python_test.go",
+    ],
+    pluginFor: ["soong_build"],
+}
+
 //
 // Defaults to enable various configurations of host bionic
 //
diff --git a/android/androidmk.go b/android/androidmk.go
index af6608f..b81cc2a 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -217,13 +217,22 @@
 	host := false
 	switch amod.Os().Class {
 	case Host:
-		fmt.Fprintln(w, "LOCAL_MODULE_HOST_ARCH :=", archStr)
+		// Make cannot identify LOCAL_MODULE_HOST_ARCH:= common.
+		if archStr != "common" {
+			fmt.Fprintln(w, "LOCAL_MODULE_HOST_ARCH :=", archStr)
+		}
 		host = true
 	case HostCross:
-		fmt.Fprintln(w, "LOCAL_MODULE_HOST_CROSS_ARCH :=", archStr)
+		// Make cannot identify LOCAL_MODULE_HOST_CROSS_ARCH:= common.
+		if archStr != "common" {
+			fmt.Fprintln(w, "LOCAL_MODULE_HOST_CROSS_ARCH :=", archStr)
+		}
 		host = true
 	case Device:
-		fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", archStr)
+		// Make cannot identify LOCAL_MODULE_TARGET_ARCH:= common.
+		if archStr != "common" {
+			fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", archStr)
+		}
 
 		if len(amod.commonProperties.Logtags) > 0 {
 			fmt.Fprintln(w, "LOCAL_LOGTAGS_FILES := ", strings.Join(amod.commonProperties.Logtags, " "))
diff --git a/android/arch.go b/android/arch.go
index e21a070..39477ad 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -189,7 +189,8 @@
 }()
 
 var (
-	osTypeList []OsType
+	osTypeList      []OsType
+	commonTargetMap = make(map[string]Target)
 
 	NoOsType    OsType
 	Linux       = NewOsType("linux", Host, false)
@@ -236,6 +237,13 @@
 		DefaultDisabled: defDisabled,
 	}
 	osTypeList = append(osTypeList, os)
+
+	if _, found := commonTargetMap[name]; found {
+		panic(fmt.Errorf("Found Os type duplicate during OsType registration: %q", name))
+	} else {
+		commonTargetMap[name] = Target{Os: os, Arch: Arch{ArchType: Common}}
+	}
+
 	return os
 }
 
@@ -249,15 +257,6 @@
 	return NoOsType
 }
 
-var (
-	commonTarget = Target{
-		Os: Android,
-		Arch: Arch{
-			ArchType: Common,
-		},
-	}
-)
-
 type Target struct {
 	Os   OsType
 	Arch Arch
@@ -989,6 +988,20 @@
 	return ret
 }
 
+func getCommonTargets(targets []Target) []Target {
+	var ret []Target
+	set := make(map[string]bool)
+
+	for _, t := range targets {
+		if _, found := set[t.Os.String()]; !found {
+			set[t.Os.String()] = true
+			ret = append(ret, commonTargetMap[t.Os.String()])
+		}
+	}
+
+	return ret
+}
+
 // Use the module multilib setting to select one or more targets from a target list
 func decodeMultilib(multilib string, targets []Target, prefer32 bool) ([]Target, error) {
 	buildTargets := []Target{}
@@ -1001,7 +1014,7 @@
 	}
 	switch multilib {
 	case "common":
-		buildTargets = append(buildTargets, commonTarget)
+		buildTargets = append(buildTargets, getCommonTargets(targets)...)
 	case "both":
 		if prefer32 {
 			buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib32")...)
diff --git a/android/module.go b/android/module.go
index a38c617..90d61e2 100644
--- a/android/module.go
+++ b/android/module.go
@@ -154,7 +154,7 @@
 	Init_rc []string
 
 	// names of other modules to install if this module is installed
-	Required []string
+	Required []string `android:"arch_variant"`
 
 	// Set by TargetMutator
 	CompileTarget  Target `blueprint:"mutated"`
diff --git a/android/mutator.go b/android/mutator.go
index 940b0ff..bb49487 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -81,8 +81,18 @@
 }
 
 func RegisterTestMutators(ctx *blueprint.Context) {
-	mutators := registerMutatorsContext{}
+	mutators := &registerMutatorsContext{}
+
+	register := func(funcs []RegisterMutatorFunc) {
+		for _, f := range funcs {
+			f(mutators)
+		}
+	}
+
+	register(testPreDeps)
 	mutators.BottomUp("deps", depsMutator).Parallel()
+	register(testPostDeps)
+
 	registerMutatorsToContext(ctx, mutators.mutators)
 }
 
@@ -97,7 +107,7 @@
 
 type RegisterMutatorFunc func(RegisterMutatorsContext)
 
-var preArch, preDeps, postDeps []RegisterMutatorFunc
+var preArch, preDeps, postDeps, testPreDeps, testPostDeps []RegisterMutatorFunc
 
 func PreArchMutators(f RegisterMutatorFunc) {
 	preArch = append(preArch, f)
@@ -111,6 +121,14 @@
 	postDeps = append(postDeps, f)
 }
 
+func TestPreDepsMutators(f RegisterMutatorFunc) {
+	testPreDeps = append(testPreDeps, f)
+}
+
+func TeststPostDepsMutators(f RegisterMutatorFunc) {
+	testPostDeps = append(testPostDeps, f)
+}
+
 type AndroidTopDownMutator func(TopDownMutatorContext)
 
 type TopDownMutatorContext interface {
diff --git a/android/variable.go b/android/variable.go
index 3d5e618..e692faf 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -62,6 +62,10 @@
 			Cflags []string
 		}
 
+		Override_rs_driver struct {
+			Cflags []string
+		}
+
 		// debuggable is true for eng and userdebug builds, and can be used to turn on additional
 		// debugging features that don't significantly impact runtime behavior.  userdebug builds
 		// are used for dogfooding and performance testing, and should be as similar to user builds
@@ -77,6 +81,10 @@
 			Cflags   []string
 			Cppflags []string
 		}
+
+		Pdk struct {
+			Enabled *bool
+		}
 	} `android:"arch_variant"`
 }
 
@@ -141,6 +149,8 @@
 	ArtUseReadBarrier *bool `json:",omitempty"`
 
 	BtConfigIncludeDir *string `json:",omitempty"`
+
+	Override_rs_driver *string `json:",omitempty"`
 }
 
 func boolPtr(v bool) *bool {
@@ -224,7 +234,7 @@
 func (a *ModuleBase) setVariableProperties(ctx BottomUpMutatorContext,
 	prefix string, productVariablePropertyValue reflect.Value, variableValue interface{}) {
 
-	printfIntoProperties(productVariablePropertyValue, variableValue)
+	printfIntoProperties(ctx, prefix, productVariablePropertyValue, variableValue)
 
 	err := proptools.AppendMatchingProperties(a.generalProperties,
 		productVariablePropertyValue.Addr().Interface(), nil)
@@ -237,7 +247,17 @@
 	}
 }
 
-func printfIntoProperties(productVariablePropertyValue reflect.Value, variableValue interface{}) {
+func printfIntoPropertiesError(ctx BottomUpMutatorContext, prefix string,
+	productVariablePropertyValue reflect.Value, i int, err error) {
+
+	field := productVariablePropertyValue.Type().Field(i).Name
+	property := prefix + "." + proptools.PropertyNameForField(field)
+	ctx.PropertyErrorf(property, "%s", err)
+}
+
+func printfIntoProperties(ctx BottomUpMutatorContext, prefix string,
+	productVariablePropertyValue reflect.Value, variableValue interface{}) {
+
 	for i := 0; i < productVariablePropertyValue.NumField(); i++ {
 		propertyValue := productVariablePropertyValue.Field(i)
 		kind := propertyValue.Kind()
@@ -249,36 +269,64 @@
 		}
 		switch propertyValue.Kind() {
 		case reflect.String:
-			printfIntoProperty(propertyValue, variableValue)
+			err := printfIntoProperty(propertyValue, variableValue)
+			if err != nil {
+				printfIntoPropertiesError(ctx, prefix, productVariablePropertyValue, i, err)
+			}
 		case reflect.Slice:
 			for j := 0; j < propertyValue.Len(); j++ {
-				printfIntoProperty(propertyValue.Index(j), variableValue)
+				err := printfIntoProperty(propertyValue.Index(j), variableValue)
+				if err != nil {
+					printfIntoPropertiesError(ctx, prefix, productVariablePropertyValue, i, err)
+				}
 			}
 		case reflect.Bool:
 			// Nothing
 		case reflect.Struct:
-			printfIntoProperties(propertyValue, variableValue)
+			printfIntoProperties(ctx, prefix, propertyValue, variableValue)
 		default:
 			panic(fmt.Errorf("unsupported field kind %q", propertyValue.Kind()))
 		}
 	}
 }
 
-func printfIntoProperty(propertyValue reflect.Value, variableValue interface{}) {
+func printfIntoProperty(propertyValue reflect.Value, variableValue interface{}) error {
 	s := propertyValue.String()
-	// For now, we only support int formats
-	var i int
+
+	count := strings.Count(s, "%")
+	if count == 0 {
+		return nil
+	}
+
+	if count > 1 {
+		return fmt.Errorf("product variable properties only support a single '%%'")
+	}
+
 	if strings.Contains(s, "%d") {
 		switch v := variableValue.(type) {
 		case int:
-			i = v
+			// Nothing
 		case bool:
 			if v {
-				i = 1
+				variableValue = 1
+			} else {
+				variableValue = 0
 			}
 		default:
-			panic(fmt.Errorf("unsupported type %T", variableValue))
+			return fmt.Errorf("unsupported type %T for %%d", variableValue)
 		}
-		propertyValue.Set(reflect.ValueOf(fmt.Sprintf(s, i)))
+	} else if strings.Contains(s, "%s") {
+		switch variableValue.(type) {
+		case string:
+			// Nothing
+		default:
+			return fmt.Errorf("unsupported type %T for %%s", variableValue)
+		}
+	} else {
+		return fmt.Errorf("unsupported %% in product variable property")
 	}
+
+	propertyValue.Set(reflect.ValueOf(fmt.Sprintf(s, variableValue)))
+
+	return nil
 }
diff --git a/android/variable_test.go b/android/variable_test.go
new file mode 100644
index 0000000..ce9ba54
--- /dev/null
+++ b/android/variable_test.go
@@ -0,0 +1,124 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// 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
+
+import (
+	"reflect"
+	"testing"
+)
+
+type printfIntoPropertyTestCase struct {
+	in  string
+	val interface{}
+	out string
+	err bool
+}
+
+var printfIntoPropertyTestCases = []printfIntoPropertyTestCase{
+	{
+		in:  "%d",
+		val: 0,
+		out: "0",
+	},
+	{
+		in:  "%d",
+		val: 1,
+		out: "1",
+	},
+	{
+		in:  "%d",
+		val: 2,
+		out: "2",
+	},
+	{
+		in:  "%d",
+		val: false,
+		out: "0",
+	},
+	{
+		in:  "%d",
+		val: true,
+		out: "1",
+	},
+	{
+		in:  "%d",
+		val: -1,
+		out: "-1",
+	},
+
+	{
+		in:  "-DA=%d",
+		val: 1,
+		out: "-DA=1",
+	},
+	{
+		in:  "-DA=%du",
+		val: 1,
+		out: "-DA=1u",
+	},
+	{
+		in:  "-DA=%s",
+		val: "abc",
+		out: "-DA=abc",
+	},
+	{
+		in:  `-DA="%s"`,
+		val: "abc",
+		out: `-DA="abc"`,
+	},
+
+	{
+		in:  "%%",
+		err: true,
+	},
+	{
+		in:  "%d%s",
+		err: true,
+	},
+	{
+		in:  "%d,%s",
+		err: true,
+	},
+	{
+		in:  "%d",
+		val: "",
+		err: true,
+	},
+	{
+		in:  "%d",
+		val: 1.5,
+		err: true,
+	},
+	{
+		in:  "%f",
+		val: 1.5,
+		err: true,
+	},
+}
+
+func TestPrintfIntoProperty(t *testing.T) {
+	for _, testCase := range printfIntoPropertyTestCases {
+		s := testCase.in
+		v := reflect.ValueOf(&s).Elem()
+		err := printfIntoProperty(v, testCase.val)
+		if err != nil && !testCase.err {
+			t.Errorf("unexpected error %s", err)
+		} else if err == nil && testCase.err {
+			t.Errorf("expected error")
+		} else if err == nil && v.String() != testCase.out {
+			t.Errorf("expected %q got %q", testCase.out, v.String())
+		}
+	}
+}
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index bd9d8ee..3c3e2a1 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -56,20 +56,21 @@
 func init() {
 	addStandardProperties(bpparser.StringType,
 		map[string]string{
-			"LOCAL_MODULE":               "name",
-			"LOCAL_CXX_STL":              "stl",
-			"LOCAL_STRIP_MODULE":         "strip",
-			"LOCAL_MULTILIB":             "compile_multilib",
-			"LOCAL_ARM_MODE_HACK":        "instruction_set",
-			"LOCAL_SDK_VERSION":          "sdk_version",
-			"LOCAL_NDK_STL_VARIANT":      "stl",
-			"LOCAL_JAR_MANIFEST":         "manifest",
-			"LOCAL_JARJAR_RULES":         "jarjar_rules",
-			"LOCAL_CERTIFICATE":          "certificate",
-			"LOCAL_PACKAGE_NAME":         "name",
-			"LOCAL_MODULE_RELATIVE_PATH": "relative_install_path",
-			"LOCAL_PROTOC_OPTIMIZE_TYPE": "proto.type",
-			"LOCAL_MODULE_OWNER":         "owner",
+			"LOCAL_MODULE":                  "name",
+			"LOCAL_CXX_STL":                 "stl",
+			"LOCAL_STRIP_MODULE":            "strip",
+			"LOCAL_MULTILIB":                "compile_multilib",
+			"LOCAL_ARM_MODE_HACK":           "instruction_set",
+			"LOCAL_SDK_VERSION":             "sdk_version",
+			"LOCAL_NDK_STL_VARIANT":         "stl",
+			"LOCAL_JAR_MANIFEST":            "manifest",
+			"LOCAL_JARJAR_RULES":            "jarjar_rules",
+			"LOCAL_CERTIFICATE":             "certificate",
+			"LOCAL_PACKAGE_NAME":            "name",
+			"LOCAL_MODULE_RELATIVE_PATH":    "relative_install_path",
+			"LOCAL_PROTOC_OPTIMIZE_TYPE":    "proto.type",
+			"LOCAL_MODULE_OWNER":            "owner",
+			"LOCAL_RENDERSCRIPT_TARGET_API": "renderscript.target_api",
 		})
 	addStandardProperties(bpparser.ListType,
 		map[string]string{
@@ -96,7 +97,9 @@
 			"LOCAL_INIT_RC":                       "init_rc",
 			"LOCAL_TIDY_FLAGS":                    "tidy_flags",
 			// TODO: This is comma-separated, not space-separated
-			"LOCAL_TIDY_CHECKS": "tidy_checks",
+			"LOCAL_TIDY_CHECKS":           "tidy_checks",
+			"LOCAL_RENDERSCRIPT_INCLUDES": "renderscript.include_dirs",
+			"LOCAL_RENDERSCRIPT_FLAGS":    "renderscript.flags",
 
 			"LOCAL_JAVA_RESOURCE_DIRS":    "java_resource_dirs",
 			"LOCAL_JAVACFLAGS":            "javacflags",
@@ -634,8 +637,11 @@
 		true:  "target.linux",
 		false: "target.not_linux"},
 	"(,$(TARGET_BUILD_APPS))": {
-		false: "product_variables.unbundled_build",
-	},
+		false: "product_variables.unbundled_build"},
+	"($(TARGET_BUILD_PDK),true)": {
+		true: "product_variables.pdk"},
+	"($(TARGET_BUILD_PDK), true)": {
+		true: "product_variables.pdk"},
 }
 
 func mydir(args []string) string {
diff --git a/cc/builder.go b/cc/builder.go
index 81ecd73..7144508 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -229,6 +229,7 @@
 	sAbiFlags   string
 	yasmFlags   string
 	aidlFlags   string
+	rsFlags     string
 	toolchain   config.Toolchain
 	clang       bool
 	tidy        bool
diff --git a/cc/cc.go b/cc/cc.go
index dd73504..28354a8 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -106,6 +106,7 @@
 	YaccFlags   []string // Flags that apply to Yacc source files
 	protoFlags  []string // Flags that apply to proto source files
 	aidlFlags   []string // Flags that apply to aidl source files
+	rsFlags     []string // Flags that apply to renderscript source files
 	LdFlags     []string // Flags that apply to linker command lines
 	libFlags    []string // Flags to add libraries early to the link order
 	TidyFlags   []string // Flags that apply to clang-tidy
diff --git a/cc/compiler.go b/cc/compiler.go
index f7e787c..cec527b 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -108,6 +108,17 @@
 		Local_include_dirs []string
 	}
 
+	Renderscript struct {
+		// list of directories that will be added to the llvm-rs-cc include paths
+		Include_dirs []string
+
+		// list of flags that will be passed to llvm-rs-cc
+		Flags []string
+
+		// Renderscript API level to target
+		Target_api *string
+	}
+
 	Debug, Release struct {
 		// list of module-specific flags that will be used for C and C++ compiles in debug or
 		// release builds
@@ -420,6 +431,10 @@
 			"-I"+android.PathForModuleGen(ctx, "aidl").String())
 	}
 
+	if compiler.hasSrcExt(".rs") || compiler.hasSrcExt(".fs") {
+		flags = rsFlags(ctx, flags, &compiler.Properties)
+	}
+
 	return flags
 }
 
diff --git a/cc/config/clang.go b/cc/config/clang.go
index 30ab1c6..3ff6b1b 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -105,6 +105,11 @@
 		// Bug: http://b/29823425 Disable -Wnull-dereference until the
 		// new instances detected by this warning are fixed.
 		"-Wno-null-dereference",
+
+		// Enable clang's thread-safety annotations in libcxx.
+		// Turn off -Wthread-safety-negative, to avoid breaking projects that use -Weverything.
+		"-D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS",
+		"-Wno-thread-safety-negative",
 	}, " "))
 
 	pctx.StaticVariable("ClangExtraTargetCflags", strings.Join([]string{
diff --git a/cc/config/global.go b/cc/config/global.go
index 8c24289..43ff975 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -151,6 +151,12 @@
 	pctx.StaticVariable("RSLLVMPrebuiltsPath", "${RSClangBase}/${HostPrebuiltTag}/${RSClangVersion}/bin")
 	pctx.StaticVariable("RSIncludePath", "${RSLLVMPrebuiltsPath}/../lib64/clang/${RSReleaseVersion}/include")
 
+	pctx.PrefixedPathsForOptionalSourceVariable("RsGlobalIncludes", "-I",
+		[]string{
+			"external/clang/lib/Headers",
+			"frameworks/rs/script_api/include",
+		})
+
 	pctx.VariableFunc("CcWrapper", func(config interface{}) (string, error) {
 		if override := config.(android.Config).Getenv("CC_WRAPPER"); override != "" {
 			return override + " ", nil
diff --git a/cc/gen.go b/cc/gen.go
index 808a681..353c43d 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -105,6 +105,8 @@
 
 	var deps android.Paths
 
+	var rsFiles android.Paths
+
 	for i, srcFile := range srcFiles {
 		switch srcFile.Ext() {
 		case ".y":
@@ -131,8 +133,16 @@
 			cppFile := android.GenPathWithExt(ctx, "aidl", srcFile, "cpp")
 			srcFiles[i] = cppFile
 			deps = append(deps, genAidl(ctx, srcFile, cppFile, buildFlags.aidlFlags)...)
+		case ".rs", ".fs":
+			cppFile := rsGeneratedCppFile(ctx, srcFile)
+			rsFiles = append(rsFiles, srcFiles[i])
+			srcFiles[i] = cppFile
 		}
 	}
 
+	if len(rsFiles) > 0 {
+		deps = append(deps, rsGenerateCpp(ctx, rsFiles, buildFlags.rsFlags)...)
+	}
+
 	return srcFiles, deps
 }
diff --git a/cc/makevars.go b/cc/makevars.go
index 22b9013..8bf034a 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -77,6 +77,8 @@
 
 	ctx.Strict("AIDL_CPP", "${aidlCmd}")
 
+	ctx.Strict("RS_GLOBAL_INCLUDES", "${config.RsGlobalIncludes}")
+
 	includeFlags, err := ctx.Eval("${config.CommonGlobalIncludes}")
 	if err != nil {
 		panic(err)
diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go
index f1bd3b5..15a9d28 100644
--- a/cc/ndk_prebuilt.go
+++ b/cc/ndk_prebuilt.go
@@ -190,7 +190,7 @@
 		ctx.ModuleErrorf("NDK prebuilts must have an ndk_lib prefixed name")
 	}
 
-	ndk.exportIncludes(ctx, "-I")
+	ndk.exportIncludes(ctx, "-isystem")
 
 	libName := strings.TrimPrefix(ctx.ModuleName(), "ndk_")
 	libExt := flags.Toolchain.ShlibSuffix()
diff --git a/cc/rs.go b/cc/rs.go
new file mode 100644
index 0000000..fda2469
--- /dev/null
+++ b/cc/rs.go
@@ -0,0 +1,114 @@
+// Copyright 2017 Google Inc. All rights reserved.
+//
+// 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 cc
+
+import (
+	"android/soong/android"
+	"strings"
+
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
+)
+
+func init() {
+	pctx.HostBinToolVariable("rsCmd", "llvm-rs-cc")
+}
+
+var rsCppCmdLine = strings.Replace(`
+${rsCmd} -o ${outDir} -d ${outDir} -a ${out} -MD -reflect-c++ ${rsFlags} $in &&
+(echo '${out}: \' && cat ${depFiles} | awk 'start { sub(/( \\)?$$/, " \\"); print } /:/ { start=1 }') > ${out}.d &&
+touch $out
+`, "\n", "", -1)
+
+var (
+	rsCpp = pctx.AndroidStaticRule("rsCpp",
+		blueprint.RuleParams{
+			Command:     rsCppCmdLine,
+			CommandDeps: []string{"$rsCmd"},
+			Depfile:     "${out}.d",
+			Deps:        blueprint.DepsGCC,
+			Description: "rsCpp $out",
+		},
+		"depFiles", "outDir", "rsFlags", "stampFile")
+)
+
+// Takes a path to a .rs or .fs file, and returns a path to a generated ScriptC_*.cpp file
+// This has to match the logic in llvm-rs-cc in DetermineOutputFile.
+func rsGeneratedCppFile(ctx android.ModuleContext, rsFile android.Path) android.WritablePath {
+	fileName := strings.TrimSuffix(rsFile.Base(), rsFile.Ext())
+	return android.PathForModuleGen(ctx, "rs", "ScriptC_"+fileName+".cpp")
+}
+
+func rsGeneratedDepFile(ctx android.ModuleContext, rsFile android.Path) android.WritablePath {
+	fileName := strings.TrimSuffix(rsFile.Base(), rsFile.Ext())
+	return android.PathForModuleGen(ctx, "rs", fileName+".d")
+}
+
+func rsGenerateCpp(ctx android.ModuleContext, rsFiles android.Paths, rsFlags string) android.Paths {
+	stampFile := android.PathForModuleGen(ctx, "rs", "rs.stamp")
+	depFiles := make(android.WritablePaths, len(rsFiles))
+	cppFiles := make(android.WritablePaths, len(rsFiles))
+	for i, rsFile := range rsFiles {
+		depFiles[i] = rsGeneratedDepFile(ctx, rsFile)
+		cppFiles[i] = rsGeneratedCppFile(ctx, rsFile)
+	}
+
+	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+		Rule:            rsCpp,
+		Output:          stampFile,
+		ImplicitOutputs: cppFiles,
+		Inputs:          rsFiles,
+		Args: map[string]string{
+			"rsFlags":  rsFlags,
+			"outDir":   android.PathForModuleGen(ctx, "rs").String(),
+			"depFiles": strings.Join(depFiles.Strings(), " "),
+		},
+	})
+
+	return android.Paths{stampFile}
+}
+
+func rsFlags(ctx ModuleContext, flags Flags, properties *BaseCompilerProperties) Flags {
+	targetApi := proptools.String(properties.Renderscript.Target_api)
+	if targetApi == "" && ctx.sdk() {
+		switch ctx.sdkVersion() {
+		case "current", "system_current", "test_current":
+			// Nothing
+		default:
+			targetApi = ctx.sdkVersion()
+		}
+	}
+
+	if targetApi != "" {
+		flags.rsFlags = append(flags.rsFlags, "-target-api "+targetApi)
+	}
+
+	flags.rsFlags = append(flags.rsFlags, "-Wall", "-Werror")
+	flags.rsFlags = append(flags.rsFlags, properties.Renderscript.Flags...)
+	if ctx.Arch().ArchType.Multilib == "lib64" {
+		flags.rsFlags = append(flags.rsFlags, "-m64")
+	} else {
+		flags.rsFlags = append(flags.rsFlags, "-m32")
+	}
+	flags.rsFlags = append(flags.rsFlags, "${config.RsGlobalIncludes}")
+
+	rootRsIncludeDirs := android.PathsForSource(ctx, properties.Renderscript.Include_dirs)
+	flags.rsFlags = append(flags.rsFlags, includeDirsToFlags(rootRsIncludeDirs))
+
+	flags.GlobalFlags = append(flags.GlobalFlags,
+		"-I"+android.PathForModuleGen(ctx, "rs").String())
+
+	return flags
+}
diff --git a/cc/util.go b/cc/util.go
index 18ad8a6..2febb57 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -96,6 +96,7 @@
 		yaccFlags:   strings.Join(in.YaccFlags, " "),
 		protoFlags:  strings.Join(in.protoFlags, " "),
 		aidlFlags:   strings.Join(in.aidlFlags, " "),
+		rsFlags:     strings.Join(in.rsFlags, " "),
 		ldFlags:     strings.Join(in.LdFlags, " "),
 		libFlags:    strings.Join(in.libFlags, " "),
 		tidyFlags:   strings.Join(in.TidyFlags, " "),
diff --git a/python/binary.go b/python/binary.go
new file mode 100644
index 0000000..4b4ccc2
--- /dev/null
+++ b/python/binary.go
@@ -0,0 +1,235 @@
+// Copyright 2017 Google Inc. All rights reserved.
+//
+// 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 python
+
+// This file contains the module types for building Python binary.
+
+import (
+	"fmt"
+	"io"
+	"path/filepath"
+	"strings"
+
+	"github.com/google/blueprint"
+
+	"android/soong/android"
+)
+
+func init() {
+	android.RegisterModuleType("python_binary_host", PythonBinaryHostFactory)
+}
+
+type PythonBinaryProperties struct {
+	// the name of the source file that is the main entry point of the program.
+	// this file must also be listed in srcs.
+	// If left unspecified, module name is used instead.
+	// If name doesn’t match any filename in srcs, main must be specified.
+	Main string
+
+	// set the name of the output binary.
+	Stem string
+
+	// append to the name of the output binary.
+	Suffix string
+}
+
+type PythonBinary struct {
+	pythonBaseModule
+
+	binaryProperties PythonBinaryProperties
+
+	// soong_zip arguments from all its dependencies.
+	depsParSpecs []parSpec
+
+	// Python runfiles paths from all its dependencies.
+	depsPyRunfiles []string
+
+	// the installation path for Python binary.
+	installPath android.OutputPath
+}
+
+var _ PythonSubModule = (*PythonBinary)(nil)
+
+var (
+	stubTemplateHost = "build/soong/python/scripts/stub_template_host.txt"
+)
+
+func PythonBinaryHostFactory() (blueprint.Module, []interface{}) {
+	module := &PythonBinary{}
+
+	return InitPythonBaseModule(&module.pythonBaseModule, module, android.HostSupportedNoCross,
+		&module.binaryProperties)
+}
+
+func (p *PythonBinary) GeneratePythonBuildActions(ctx android.ModuleContext) {
+	p.pythonBaseModule.GeneratePythonBuildActions(ctx)
+
+	// no Python source file for compiling par file.
+	if len(p.pythonBaseModule.srcsPathMappings) == 0 && len(p.depsPyRunfiles) == 0 {
+		return
+	}
+
+	// the runfiles packages needs to be populated with "__init__.py".
+	newPyPkgs := []string{}
+	// the set to de-duplicate the new Python packages above.
+	newPyPkgSet := make(map[string]bool)
+	// the runfiles dirs have been treated as packages.
+	existingPyPkgSet := make(map[string]bool)
+
+	wholePyRunfiles := []string{}
+	for _, path := range p.pythonBaseModule.srcsPathMappings {
+		wholePyRunfiles = append(wholePyRunfiles, path.dest)
+	}
+	wholePyRunfiles = append(wholePyRunfiles, p.depsPyRunfiles...)
+
+	// find all the runfiles dirs which have been treated as packages.
+	for _, path := range wholePyRunfiles {
+		if filepath.Base(path) != initFileName {
+			continue
+		}
+		existingPyPkg := PathBeforeLastSlash(path)
+		if _, found := existingPyPkgSet[existingPyPkg]; found {
+			panic(fmt.Errorf("found init file path duplicates: %q for module: %q.",
+				path, ctx.ModuleName()))
+		} else {
+			existingPyPkgSet[existingPyPkg] = true
+		}
+		parentPath := PathBeforeLastSlash(existingPyPkg)
+		populateNewPyPkgs(parentPath, existingPyPkgSet, newPyPkgSet, &newPyPkgs)
+	}
+
+	// create new packages under runfiles tree.
+	for _, path := range wholePyRunfiles {
+		if filepath.Base(path) == initFileName {
+			continue
+		}
+		parentPath := PathBeforeLastSlash(path)
+		populateNewPyPkgs(parentPath, existingPyPkgSet, newPyPkgSet, &newPyPkgs)
+	}
+
+	main := p.getPyMainFile(ctx)
+	if main == "" {
+		return
+	}
+	interp := p.getInterpreter(ctx)
+	if interp == "" {
+		return
+	}
+
+	// we need remove "runfiles/" suffix since stub script starts
+	// searching for main file in each sub-dir of "runfiles" directory tree.
+	binFile := registerBuildActionForParFile(ctx, p.getInterpreter(ctx),
+		strings.TrimPrefix(main, runFiles+"/"), p.getStem(ctx),
+		newPyPkgs, append(p.depsParSpecs, p.pythonBaseModule.parSpec))
+
+	// install par file.
+	p.installPath = ctx.InstallFile(
+		android.PathForModuleInstall(ctx, "bin"), binFile)
+}
+
+// get interpreter path.
+func (p *PythonBinary) getInterpreter(ctx android.ModuleContext) string {
+	var interp string
+	switch p.pythonBaseModule.properties.ActualVersion {
+	case pyVersion2:
+		interp = "python2"
+	case pyVersion3:
+		interp = "python3"
+	default:
+		panic(fmt.Errorf("unknown Python actualVersion: %q for module: %q.",
+			p.properties.ActualVersion, ctx.ModuleName()))
+	}
+
+	return interp
+}
+
+// find main program path within runfiles tree.
+func (p *PythonBinary) getPyMainFile(ctx android.ModuleContext) string {
+	var main string
+	if p.binaryProperties.Main == "" {
+		main = p.BaseModuleName() + pyExt
+	} else {
+		main = p.binaryProperties.Main
+	}
+
+	for _, path := range p.pythonBaseModule.srcsPathMappings {
+		if main == path.src.Rel() {
+			return path.dest
+		}
+	}
+	ctx.PropertyErrorf("main", "%q is not listed in srcs.", main)
+
+	return ""
+}
+
+func (p *PythonBinary) getStem(ctx android.ModuleContext) string {
+	stem := ctx.ModuleName()
+	if p.binaryProperties.Stem != "" {
+		stem = p.binaryProperties.Stem
+	}
+
+	return stem + p.binaryProperties.Suffix
+}
+
+// Sets the given directory and all its ancestor directories as Python packages.
+func populateNewPyPkgs(pkgPath string, existingPyPkgSet,
+	newPyPkgSet map[string]bool, newPyPkgs *[]string) {
+	for pkgPath != "" {
+		if _, found := existingPyPkgSet[pkgPath]; found {
+			break
+		}
+		if _, found := newPyPkgSet[pkgPath]; !found {
+			newPyPkgSet[pkgPath] = true
+			*newPyPkgs = append(*newPyPkgs, pkgPath)
+			// Gets its ancestor directory by trimming last slash.
+			pkgPath = PathBeforeLastSlash(pkgPath)
+		} else {
+			break
+		}
+	}
+}
+
+// filepath.Dir("abc") -> "." and filepath.Dir("/abc") -> "/". However,
+// the PathBeforeLastSlash() will return "" for both cases above.
+func PathBeforeLastSlash(path string) string {
+	if idx := strings.LastIndex(path, "/"); idx != -1 {
+		return path[:idx]
+	}
+	return ""
+}
+
+func (p *PythonBinary) GeneratePythonAndroidMk() (ret android.AndroidMkData, err error) {
+	// Soong installation is only supported for host modules. Have Make
+	// installation trigger Soong installation.
+	if p.pythonBaseModule.Target().Os.Class == android.Host {
+		ret.OutputFile = android.OptionalPathForPath(p.installPath)
+	}
+	ret.Class = "EXECUTABLES"
+
+	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) error {
+		path := p.installPath.RelPathString()
+		dir, file := filepath.Split(path)
+		stem := strings.TrimSuffix(file, filepath.Ext(file))
+
+		fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+filepath.Ext(file))
+		fmt.Fprintln(w, "LOCAL_MODULE_PATH := $(OUT_DIR)/"+filepath.Clean(dir))
+		fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
+
+		return nil
+	})
+
+	return
+
+}
diff --git a/python/builder.go b/python/builder.go
new file mode 100644
index 0000000..6223448
--- /dev/null
+++ b/python/builder.go
@@ -0,0 +1,146 @@
+// Copyright 2017 Google Inc. All rights reserved.
+//
+// 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 python
+
+// This file contains Ninja build actions for building Python program.
+
+import (
+	"strings"
+
+	"android/soong/android"
+
+	"github.com/google/blueprint"
+	_ "github.com/google/blueprint/bootstrap"
+)
+
+var (
+	pctx = android.NewPackageContext("android/soong/python")
+
+	par = pctx.AndroidStaticRule("par",
+		blueprint.RuleParams{
+			Command: `touch $initFile && ` +
+				`sed -e 's/%interpreter%/$interp/g' -e 's/%main%/$main/g' $template > $stub && ` +
+				`$parCmd -o $parFile $parArgs && echo '#!/usr/bin/env python' | cat - $parFile > $out && ` +
+				`chmod +x $out && (rm -f $initFile; rm -f $stub; rm -f $parFile)`,
+			CommandDeps: []string{"$parCmd", "$template"},
+			Description: "build par $out",
+		},
+		"initFile", "interp", "main", "template", "stub", "parCmd", "parFile", "parArgs")
+)
+
+func init() {
+	pctx.Import("github.com/google/blueprint/bootstrap")
+	pctx.Import("android/soong/common")
+
+	pctx.HostBinToolVariable("parCmd", "soong_zip")
+}
+
+type fileListSpec struct {
+	fileList     android.Path
+	relativeRoot string
+}
+
+type parSpec struct {
+	rootPrefix string
+
+	fileListSpecs []fileListSpec
+}
+
+func (p parSpec) soongParArgs() string {
+	ret := "-P " + p.rootPrefix
+
+	for _, spec := range p.fileListSpecs {
+		ret += " -C " + spec.relativeRoot + " -l " + spec.fileList.String()
+	}
+
+	return ret
+}
+
+func registerBuildActionForModuleFileList(ctx android.ModuleContext,
+	name string, files android.Paths) android.Path {
+	fileList := android.PathForModuleOut(ctx, name+".list")
+
+	content := []string{}
+	for _, file := range files {
+		content = append(content, file.String())
+	}
+
+	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+		Rule:      android.WriteFile,
+		Output:    fileList,
+		Implicits: files,
+		Args: map[string]string{
+			"content": strings.Join(content, "\n"),
+		},
+	})
+
+	return fileList
+}
+
+func registerBuildActionForParFile(ctx android.ModuleContext,
+	interpreter, main, binName string, newPyPkgs []string, parSpecs []parSpec) android.Path {
+
+	// intermediate output path for __init__.py
+	initFile := android.PathForModuleOut(ctx, initFileName).String()
+
+	// the path of stub_template_host.txt from source tree.
+	template := android.PathForSource(ctx, stubTemplateHost)
+
+	// intermediate output path for __main__.py
+	stub := android.PathForModuleOut(ctx, mainFileName).String()
+
+	// intermediate output path for par file.
+	parFile := android.PathForModuleOut(ctx, binName+parFileExt)
+
+	// intermediate output path for bin executable.
+	binFile := android.PathForModuleOut(ctx, binName)
+
+	// implicit dependency for parFile build action.
+	implicits := android.Paths{}
+	for _, p := range parSpecs {
+		for _, f := range p.fileListSpecs {
+			implicits = append(implicits, f.fileList)
+		}
+	}
+
+	parArgs := []string{}
+	parArgs = append(parArgs, "-C "+strings.TrimSuffix(stub, mainFileName)+" -f "+stub)
+	parArgs = append(parArgs, "-C "+strings.TrimSuffix(initFile, initFileName)+" -f "+initFile)
+	for _, pkg := range newPyPkgs {
+		parArgs = append(parArgs, "-P "+pkg+" -f "+initFile)
+	}
+	for _, p := range parSpecs {
+		parArgs = append(parArgs, p.soongParArgs())
+	}
+
+	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
+		Rule:      par,
+		Output:    binFile,
+		Implicits: implicits,
+		Args: map[string]string{
+			"initFile": initFile,
+			// the "\" isn't being interpreted by regex parser, it's being
+			// interpreted in the string literal.
+			"interp":   strings.Replace(interpreter, "/", `\/`, -1),
+			"main":     strings.Replace(main, "/", `\/`, -1),
+			"template": template.String(),
+			"stub":     stub,
+			"parFile":  parFile.String(),
+			"parArgs":  strings.Join(parArgs, " "),
+		},
+	})
+
+	return binFile
+}
diff --git a/python/library.go b/python/library.go
new file mode 100644
index 0000000..1deaeb8
--- /dev/null
+++ b/python/library.go
@@ -0,0 +1,43 @@
+// Copyright 2017 Google Inc. All rights reserved.
+//
+// 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 python
+
+// This file contains the module types for building Python library.
+
+import (
+	"github.com/google/blueprint"
+
+	"android/soong/android"
+)
+
+func init() {
+	android.RegisterModuleType("python_library_host", PythonLibraryHostFactory)
+}
+
+type PythonLibrary struct {
+	pythonBaseModule
+}
+
+var _ PythonSubModule = (*PythonLibrary)(nil)
+
+func PythonLibraryHostFactory() (blueprint.Module, []interface{}) {
+	module := &PythonLibrary{}
+
+	return InitPythonBaseModule(&module.pythonBaseModule, module, android.HostSupportedNoCross)
+}
+
+func (p *PythonLibrary) GeneratePythonAndroidMk() (ret android.AndroidMkData, err error) {
+	return
+}
diff --git a/python/python.go b/python/python.go
new file mode 100644
index 0000000..1c74c9a
--- /dev/null
+++ b/python/python.go
@@ -0,0 +1,448 @@
+// Copyright 2017 Google Inc. All rights reserved.
+//
+// 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 python
+
+// This file contains the "Base" module type for building Python program.
+
+import (
+	"fmt"
+	"path/filepath"
+	"regexp"
+	"sort"
+	"strings"
+
+	"github.com/google/blueprint"
+
+	"android/soong/android"
+)
+
+func init() {
+	android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.BottomUp("version_split", versionSplitMutator()).Parallel()
+	})
+}
+
+// the version properties that apply to python libraries and binaries.
+type PythonVersionProperties struct {
+	// true, if the module is required to be built with this version.
+	Enabled *bool
+
+	// if specified, common src files are converted to specific version with converter tool.
+	// Converter bool
+
+	// non-empty list of .py files under this strict Python version.
+	// srcs may reference the outputs of other modules that produce source files like genrule
+	// or filegroup using the syntax ":module".
+	Srcs []string
+
+	// list of the Python libraries under this Python version.
+	Libs []string
+}
+
+// properties that apply to python libraries and binaries.
+type PythonBaseModuleProperties struct {
+	// the package path prefix within the output artifact at which to place the source/data
+	// files of the current module.
+	// eg. Pkg_path = "a/b/c"; Other packages can reference this module by using
+	// (from a.b.c import ...) statement.
+	// if left unspecified, all the source/data files of current module are copied to
+	// "runfiles/" tree directory directly.
+	Pkg_path string
+
+	// list of source (.py) files compatible both with Python2 and Python3 used to compile the
+	// Python module.
+	// srcs may reference the outputs of other modules that produce source files like genrule
+	// or filegroup using the syntax ":module".
+	// Srcs has to be non-empty.
+	Srcs []string
+
+	// list of files or filegroup modules that provide data that should be installed alongside
+	// the test. the file extension can be arbitrary except for (.py).
+	Data []string
+
+	// list of the Python libraries compatible both with Python2 and Python3.
+	Libs []string
+
+	Version struct {
+		// all the "srcs" or Python dependencies that are to be used only for Python2.
+		Py2 PythonVersionProperties
+
+		// all the "srcs" or Python dependencies that are to be used only for Python3.
+		Py3 PythonVersionProperties
+	}
+
+	// the actual version each module uses after variations created.
+	// this property name is hidden from users' perspectives, and soong will populate it during
+	// runtime.
+	ActualVersion string `blueprint:"mutated"`
+}
+
+type pathMapping struct {
+	dest string
+	src  android.Path
+}
+
+type pythonBaseModule struct {
+	android.ModuleBase
+	subModule PythonSubModule
+
+	properties PythonBaseModuleProperties
+
+	// the Python files of current module after expanding source dependencies.
+	// pathMapping: <dest: runfile_path, src: source_path>
+	srcsPathMappings []pathMapping
+
+	// the data files of current module after expanding source dependencies.
+	// pathMapping: <dest: runfile_path, src: source_path>
+	dataPathMappings []pathMapping
+
+	// the soong_zip arguments for zipping current module source/data files.
+	parSpec parSpec
+}
+
+type PythonSubModule interface {
+	GeneratePythonBuildActions(ctx android.ModuleContext)
+	GeneratePythonAndroidMk() (ret android.AndroidMkData, err error)
+}
+
+type PythonDependency interface {
+	GetSrcsPathMappings() []pathMapping
+	GetDataPathMappings() []pathMapping
+	GetParSpec() parSpec
+}
+
+func (p *pythonBaseModule) GetSrcsPathMappings() []pathMapping {
+	return p.srcsPathMappings
+}
+
+func (p *pythonBaseModule) GetDataPathMappings() []pathMapping {
+	return p.dataPathMappings
+}
+
+func (p *pythonBaseModule) GetParSpec() parSpec {
+	return p.parSpec
+}
+
+var _ PythonDependency = (*pythonBaseModule)(nil)
+
+var _ android.AndroidMkDataProvider = (*pythonBaseModule)(nil)
+
+func InitPythonBaseModule(baseModule *pythonBaseModule, subModule PythonSubModule,
+	hod android.HostOrDeviceSupported,
+	props ...interface{}) (blueprint.Module, []interface{}) {
+
+	baseModule.subModule = subModule
+
+	props = append(props, &baseModule.properties)
+
+	return android.InitAndroidArchModule(baseModule, hod, android.MultilibCommon, props...)
+}
+
+// the tag used to mark dependencies within "py_libs" attribute.
+type pythonDependencyTag struct {
+	blueprint.BaseDependencyTag
+}
+
+var pyDependencyTag pythonDependencyTag
+
+var (
+	pyIdentifierRegexp = regexp.MustCompile(`^([a-z]|[A-Z]|_)([a-z]|[A-Z]|[0-9]|_)*$`)
+	pyExt              = ".py"
+	pyVersion2         = "PY2"
+	pyVersion3         = "PY3"
+	initFileName       = "__init__.py"
+	mainFileName       = "__main__.py"
+	parFileExt         = ".zip"
+	runFiles           = "runfiles"
+)
+
+// create version variants for modules.
+func versionSplitMutator() func(android.BottomUpMutatorContext) {
+	return func(mctx android.BottomUpMutatorContext) {
+		if base, ok := mctx.Module().(*pythonBaseModule); ok {
+			versionNames := []string{}
+			if base.properties.Version.Py2.Enabled != nil &&
+				*(base.properties.Version.Py2.Enabled) == true {
+				versionNames = append(versionNames, pyVersion2)
+			}
+			if !(base.properties.Version.Py3.Enabled != nil &&
+				*(base.properties.Version.Py3.Enabled) == false) {
+				versionNames = append(versionNames, pyVersion3)
+			}
+			modules := mctx.CreateVariations(versionNames...)
+			for i, v := range versionNames {
+				// set the actual version for Python module.
+				modules[i].(*pythonBaseModule).properties.ActualVersion = v
+			}
+		}
+	}
+}
+
+func (p *pythonBaseModule) DepsMutator(ctx android.BottomUpMutatorContext) {
+	// deps from "data".
+	android.ExtractSourcesDeps(ctx, p.properties.Data)
+	// deps from "srcs".
+	android.ExtractSourcesDeps(ctx, p.properties.Srcs)
+
+	switch p.properties.ActualVersion {
+	case pyVersion2:
+		// deps from "version.py2.srcs" property.
+		android.ExtractSourcesDeps(ctx, p.properties.Version.Py2.Srcs)
+
+		ctx.AddVariationDependencies(nil, pyDependencyTag,
+			uniqueLibs(ctx, p.properties.Libs, "version.py2.libs",
+				p.properties.Version.Py2.Libs)...)
+	case pyVersion3:
+		// deps from "version.py3.srcs" property.
+		android.ExtractSourcesDeps(ctx, p.properties.Version.Py3.Srcs)
+
+		ctx.AddVariationDependencies(nil, pyDependencyTag,
+			uniqueLibs(ctx, p.properties.Libs, "version.py3.libs",
+				p.properties.Version.Py3.Libs)...)
+	default:
+		panic(fmt.Errorf("unknown Python actualVersion: %q for module: %q.",
+			p.properties.ActualVersion, ctx.ModuleName()))
+	}
+}
+
+// check "libs" duplicates from current module dependencies.
+func uniqueLibs(ctx android.BottomUpMutatorContext,
+	commonLibs []string, versionProp string, versionLibs []string) []string {
+	set := make(map[string]string)
+	ret := []string{}
+
+	// deps from "libs" property.
+	for _, l := range commonLibs {
+		if _, found := set[l]; found {
+			ctx.PropertyErrorf("libs", "%q has duplicates within libs.", l)
+		} else {
+			set[l] = "libs"
+			ret = append(ret, l)
+		}
+	}
+	// deps from "version.pyX.libs" property.
+	for _, l := range versionLibs {
+		if _, found := set[l]; found {
+			ctx.PropertyErrorf(versionProp, "%q has duplicates within %q.", set[l])
+		} else {
+			set[l] = versionProp
+			ret = append(ret, l)
+		}
+	}
+
+	return ret
+}
+
+func (p *pythonBaseModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	p.subModule.GeneratePythonBuildActions(ctx)
+}
+
+func (p *pythonBaseModule) GeneratePythonBuildActions(ctx android.ModuleContext) {
+	// expand python files from "srcs" property.
+	srcs := p.properties.Srcs
+	switch p.properties.ActualVersion {
+	case pyVersion2:
+		srcs = append(srcs, p.properties.Version.Py2.Srcs...)
+	case pyVersion3:
+		srcs = append(srcs, p.properties.Version.Py3.Srcs...)
+	default:
+		panic(fmt.Errorf("unknown Python actualVersion: %q for module: %q.",
+			p.properties.ActualVersion, ctx.ModuleName()))
+	}
+	expandedSrcs := ctx.ExpandSources(srcs, nil)
+	if len(expandedSrcs) == 0 {
+		ctx.ModuleErrorf("doesn't have any source files!")
+	}
+
+	// expand data files from "data" property.
+	expandedData := ctx.ExpandSources(p.properties.Data, nil)
+
+	// sanitize pkg_path.
+	pkg_path := p.properties.Pkg_path
+	if pkg_path != "" {
+		pkg_path = filepath.Clean(p.properties.Pkg_path)
+		if pkg_path == ".." || strings.HasPrefix(pkg_path, "../") ||
+			strings.HasPrefix(pkg_path, "/") {
+			ctx.PropertyErrorf("pkg_path", "%q is not a valid format.",
+				p.properties.Pkg_path)
+			return
+		}
+		// pkg_path starts from "runfiles/" implicitly.
+		pkg_path = filepath.Join(runFiles, pkg_path)
+	} else {
+		// pkg_path starts from "runfiles/" implicitly.
+		pkg_path = runFiles
+	}
+
+	p.genModulePathMappings(ctx, pkg_path, expandedSrcs, expandedData)
+
+	p.parSpec = p.dumpFileList(ctx, pkg_path)
+
+	p.uniqWholeRunfilesTree(ctx)
+}
+
+// generate current module unique pathMappings: <dest: runfiles_path, src: source_path>
+// for python/data files.
+func (p *pythonBaseModule) genModulePathMappings(ctx android.ModuleContext, pkg_path string,
+	expandedSrcs, expandedData android.Paths) {
+	// fetch <runfiles_path, source_path> pairs from "src" and "data" properties to
+	// check duplicates.
+	destToPySrcs := make(map[string]string)
+	destToPyData := make(map[string]string)
+
+	for _, s := range expandedSrcs {
+		if s.Ext() != pyExt {
+			ctx.PropertyErrorf("srcs", "found non (.py) file: %q!", s.String())
+			continue
+		}
+		runfilesPath := filepath.Join(pkg_path, s.Rel())
+		identifiers := strings.Split(strings.TrimSuffix(runfilesPath, pyExt), "/")
+		for _, token := range identifiers {
+			if !pyIdentifierRegexp.MatchString(token) {
+				ctx.PropertyErrorf("srcs", "the path %q contains invalid token %q.",
+					runfilesPath, token)
+			}
+		}
+		if fillInMap(ctx, destToPySrcs, runfilesPath, s.String(), p.Name(), p.Name()) {
+			p.srcsPathMappings = append(p.srcsPathMappings,
+				pathMapping{dest: runfilesPath, src: s})
+		}
+	}
+
+	for _, d := range expandedData {
+		if d.Ext() == pyExt {
+			ctx.PropertyErrorf("data", "found (.py) file: %q!", d.String())
+			continue
+		}
+		runfilesPath := filepath.Join(pkg_path, d.Rel())
+		if fillInMap(ctx, destToPyData, runfilesPath, d.String(), p.Name(), p.Name()) {
+			p.dataPathMappings = append(p.dataPathMappings,
+				pathMapping{dest: runfilesPath, src: d})
+		}
+	}
+
+}
+
+// register build actions to dump filelist to disk.
+func (p *pythonBaseModule) dumpFileList(ctx android.ModuleContext, pkg_path string) parSpec {
+	relativeRootMap := make(map[string]android.Paths)
+	// the soong_zip params in order to pack current module's Python/data files.
+	ret := parSpec{rootPrefix: pkg_path}
+
+	pathMappings := append(p.srcsPathMappings, p.dataPathMappings...)
+
+	// "srcs" or "data" properties may have filegroup so it might happen that
+	// the relative root for each source path is different.
+	for _, path := range pathMappings {
+		relativeRoot := strings.TrimSuffix(path.src.String(), path.src.Rel())
+		if v, found := relativeRootMap[relativeRoot]; found {
+			relativeRootMap[relativeRoot] = append(v, path.src)
+		} else {
+			relativeRootMap[relativeRoot] = android.Paths{path.src}
+		}
+	}
+
+	var keys []string
+
+	// in order to keep stable order of soong_zip params, we sort the keys here.
+	for k := range relativeRootMap {
+		keys = append(keys, k)
+	}
+	sort.Strings(keys)
+
+	for _, k := range keys {
+		// use relative root as filelist name.
+		fileListPath := registerBuildActionForModuleFileList(
+			ctx, strings.Replace(k, "/", "_", -1), relativeRootMap[k])
+		ret.fileListSpecs = append(ret.fileListSpecs,
+			fileListSpec{fileList: fileListPath, relativeRoot: k})
+	}
+
+	return ret
+}
+
+// check Python/data files duplicates from current module and its whole dependencies.
+func (p *pythonBaseModule) uniqWholeRunfilesTree(ctx android.ModuleContext) {
+	// fetch <runfiles_path, source_path> pairs from "src" and "data" properties to
+	// check duplicates.
+	destToPySrcs := make(map[string]string)
+	destToPyData := make(map[string]string)
+
+	for _, path := range p.srcsPathMappings {
+		destToPySrcs[path.dest] = path.src.String()
+	}
+	for _, path := range p.dataPathMappings {
+		destToPyData[path.dest] = path.src.String()
+	}
+
+	// visit all its dependencies in depth first.
+	ctx.VisitDepsDepthFirst(func(module blueprint.Module) {
+		// module can only depend on Python library.
+		if base, ok := module.(*pythonBaseModule); ok {
+			if _, ok := base.subModule.(*PythonLibrary); !ok {
+				panic(fmt.Errorf(
+					"the dependency %q of module %q is not Python library!",
+					ctx.ModuleName(), ctx.OtherModuleName(module)))
+			}
+		} else {
+			return
+		}
+		if dep, ok := module.(PythonDependency); ok {
+			srcs := dep.GetSrcsPathMappings()
+			for _, path := range srcs {
+				if !fillInMap(ctx, destToPySrcs,
+					path.dest, path.src.String(), ctx.ModuleName(),
+					ctx.OtherModuleName(module)) {
+					continue
+				}
+				// binary needs the Python runfiles paths from all its
+				// dependencies to fill __init__.py in each runfiles dir.
+				if sub, ok := p.subModule.(*PythonBinary); ok {
+					sub.depsPyRunfiles = append(sub.depsPyRunfiles, path.dest)
+				}
+			}
+			data := dep.GetDataPathMappings()
+			for _, path := range data {
+				fillInMap(ctx, destToPyData,
+					path.dest, path.src.String(), ctx.ModuleName(),
+					ctx.OtherModuleName(module))
+			}
+			// binary needs the soong_zip arguments from all its
+			// dependencies to generate executable par file.
+			if sub, ok := p.subModule.(*PythonBinary); ok {
+				sub.depsParSpecs = append(sub.depsParSpecs, dep.GetParSpec())
+			}
+		}
+	})
+}
+
+func fillInMap(ctx android.ModuleContext, m map[string]string,
+	key, value, curModule, otherModule string) bool {
+	if oldValue, found := m[key]; found {
+		ctx.ModuleErrorf("found two files to be placed at the same runfiles location %q."+
+			" First file: in module %s at path %q."+
+			" Second file: in module %s at path %q.",
+			key, curModule, oldValue, otherModule, value)
+		return false
+	} else {
+		m[key] = value
+	}
+
+	return true
+}
+
+func (p *pythonBaseModule) AndroidMk() (ret android.AndroidMkData, err error) {
+	return p.subModule.GeneratePythonAndroidMk()
+}
diff --git a/python/python_test.go b/python/python_test.go
new file mode 100644
index 0000000..c6b8451
--- /dev/null
+++ b/python/python_test.go
@@ -0,0 +1,456 @@
+// Copyright 2017 Google Inc. All rights reserved.
+//
+// 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 python
+
+import (
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"reflect"
+	"sort"
+	"strings"
+	"testing"
+
+	"android/soong/android"
+
+	"github.com/google/blueprint"
+)
+
+type pyBinary struct {
+	name           string
+	actualVersion  string
+	pyRunfiles     []string
+	depsPyRunfiles []string
+	parSpec        string
+	depsParSpecs   []string
+}
+
+var (
+	buildNamePrefix          = "soong_python_test"
+	moduleVariantErrTemplate = "%s: module %q variant %q: "
+	pkgPathErrTemplate       = moduleVariantErrTemplate +
+		"pkg_path: %q is not a valid format."
+	badIdentifierErrTemplate = moduleVariantErrTemplate +
+		"srcs: the path %q contains invalid token %q."
+	dupRunfileErrTemplate = moduleVariantErrTemplate +
+		"found two files to be placed at the same runfiles location %q." +
+		" First file: in module %s at path %q." +
+		" Second file: in module %s at path %q."
+	noSrcFileErr      = moduleVariantErrTemplate + "doesn't have any source files!"
+	badSrcFileExtErr  = moduleVariantErrTemplate + "srcs: found non (.py) file: %q!"
+	badDataFileExtErr = moduleVariantErrTemplate + "data: found (.py) file: %q!"
+	bpFile            = "Blueprints"
+
+	data = []struct {
+		desc      string
+		mockFiles map[string][]byte
+
+		errors           []string
+		expectedBinaries []pyBinary
+	}{
+		{
+			desc: "module without any src files",
+			mockFiles: map[string][]byte{
+				bpFile: []byte(`subdirs = ["dir"]`),
+				filepath.Join("dir", bpFile): []byte(
+					`python_library_host {
+						name: "lib1",
+					}`,
+				),
+			},
+			errors: []string{
+				fmt.Sprintf(noSrcFileErr,
+					"dir/Blueprints:1:1", "lib1", "PY3"),
+			},
+		},
+		{
+			desc: "module with bad src file ext",
+			mockFiles: map[string][]byte{
+				bpFile: []byte(`subdirs = ["dir"]`),
+				filepath.Join("dir", bpFile): []byte(
+					`python_library_host {
+						name: "lib1",
+						srcs: [
+							"file1.exe",
+						],
+					}`,
+				),
+				"dir/file1.exe": nil,
+			},
+			errors: []string{
+				fmt.Sprintf(badSrcFileExtErr,
+					"dir/Blueprints:3:11", "lib1", "PY3", "dir/file1.exe"),
+			},
+		},
+		{
+			desc: "module with bad data file ext",
+			mockFiles: map[string][]byte{
+				bpFile: []byte(`subdirs = ["dir"]`),
+				filepath.Join("dir", bpFile): []byte(
+					`python_library_host {
+						name: "lib1",
+						srcs: [
+							"file1.py",
+						],
+						data: [
+							"file2.py",
+						],
+					}`,
+				),
+				"dir/file1.py": nil,
+				"dir/file2.py": nil,
+			},
+			errors: []string{
+				fmt.Sprintf(badDataFileExtErr,
+					"dir/Blueprints:6:11", "lib1", "PY3", "dir/file2.py"),
+			},
+		},
+		{
+			desc: "module with bad pkg_path format",
+			mockFiles: map[string][]byte{
+				bpFile: []byte(`subdirs = ["dir"]`),
+				filepath.Join("dir", bpFile): []byte(
+					`python_library_host {
+						name: "lib1",
+						pkg_path: "a/c/../../",
+						srcs: [
+							"file1.py",
+						],
+					}
+
+					python_library_host {
+						name: "lib2",
+						pkg_path: "a/c/../../../",
+						srcs: [
+							"file1.py",
+						],
+					}
+
+					python_library_host {
+						name: "lib3",
+						pkg_path: "/a/c/../../",
+						srcs: [
+							"file1.py",
+						],
+					}`,
+				),
+				"dir/file1.py": nil,
+			},
+			errors: []string{
+				fmt.Sprintf(pkgPathErrTemplate,
+					"dir/Blueprints:11:15", "lib2", "PY3", "a/c/../../../"),
+				fmt.Sprintf(pkgPathErrTemplate,
+					"dir/Blueprints:19:15", "lib3", "PY3", "/a/c/../../"),
+			},
+		},
+		{
+			desc: "module with bad runfile src path format",
+			mockFiles: map[string][]byte{
+				bpFile: []byte(`subdirs = ["dir"]`),
+				filepath.Join("dir", bpFile): []byte(
+					`python_library_host {
+						name: "lib1",
+						pkg_path: "a/b/c/",
+						srcs: [
+							".file1.py",
+							"123/file1.py",
+							"-e/f/file1.py",
+						],
+					}`,
+				),
+				"dir/.file1.py":     nil,
+				"dir/123/file1.py":  nil,
+				"dir/-e/f/file1.py": nil,
+			},
+			errors: []string{
+				fmt.Sprintf(badIdentifierErrTemplate, "dir/Blueprints:4:11",
+					"lib1", "PY3", "runfiles/a/b/c/-e/f/file1.py", "-e"),
+				fmt.Sprintf(badIdentifierErrTemplate, "dir/Blueprints:4:11",
+					"lib1", "PY3", "runfiles/a/b/c/.file1.py", ".file1"),
+				fmt.Sprintf(badIdentifierErrTemplate, "dir/Blueprints:4:11",
+					"lib1", "PY3", "runfiles/a/b/c/123/file1.py", "123"),
+			},
+		},
+		{
+			desc: "module with duplicate runfile path",
+			mockFiles: map[string][]byte{
+				bpFile: []byte(`subdirs = ["dir"]`),
+				filepath.Join("dir", bpFile): []byte(
+					`python_library_host {
+						name: "lib1",
+						pkg_path: "a/b/",
+						srcs: [
+							"c/file1.py",
+						],
+					}
+
+					python_library_host {
+						name: "lib2",
+						pkg_path: "a/b/c/",
+						srcs: [
+							"file1.py",
+						],
+						libs: [
+							"lib1",
+						],
+					}
+					`,
+				),
+				"dir/c/file1.py": nil,
+				"dir/file1.py":   nil,
+			},
+			errors: []string{
+				fmt.Sprintf(dupRunfileErrTemplate, "dir/Blueprints:9:6",
+					"lib2", "PY3", "runfiles/a/b/c/file1.py", "lib2", "dir/file1.py",
+					"lib1", "dir/c/file1.py"),
+			},
+		},
+		{
+			desc: "module for testing dependencies",
+			mockFiles: map[string][]byte{
+				bpFile: []byte(`subdirs = ["dir"]`),
+				filepath.Join("dir", bpFile): []byte(
+					`python_library_host {
+						name: "lib5",
+						pkg_path: "a/b/",
+						srcs: [
+							"file1.py",
+						],
+						version: {
+							py2: {
+								enabled: true,
+							},
+							py3: {
+								enabled: true,
+							},
+						},
+					}
+
+					python_library_host {
+						name: "lib6",
+						pkg_path: "c/d/",
+						srcs: [
+							"file2.py",
+						],
+						libs: [
+							"lib5",
+						],
+					}
+
+					python_binary_host {
+						name: "bin",
+						pkg_path: "e/",
+						srcs: [
+							"bin.py",
+						],
+						libs: [
+							"lib5",
+						],
+						version: {
+							py3: {
+								enabled: true,
+								srcs: [
+									"file4.py",
+								],
+								libs: [
+									"lib6",
+								],
+							},
+						},
+					}`,
+				),
+				filepath.Join("dir", "file1.py"): nil,
+				filepath.Join("dir", "file2.py"): nil,
+				filepath.Join("dir", "bin.py"):   nil,
+				filepath.Join("dir", "file4.py"): nil,
+				stubTemplateHost: []byte(`PYTHON_BINARY = '%interpreter%'
+				MAIN_FILE = '%main%'`),
+			},
+			expectedBinaries: []pyBinary{
+				{
+					name:          "bin",
+					actualVersion: "PY3",
+					pyRunfiles: []string{
+						"runfiles/e/bin.py",
+						"runfiles/e/file4.py",
+					},
+					depsPyRunfiles: []string{
+						"runfiles/a/b/file1.py",
+						"runfiles/c/d/file2.py",
+					},
+					parSpec: "-P runfiles/e -C dir/ -l @prefix@/.intermediates/dir/bin/PY3/dir_.list",
+					depsParSpecs: []string{
+						"-P runfiles/a/b -C dir/ -l @prefix@/.intermediates/dir/lib5/PY3/dir_.list",
+						"-P runfiles/c/d -C dir/ -l @prefix@/.intermediates/dir/lib6/PY3/dir_.list",
+					},
+				},
+			},
+		},
+	}
+)
+
+func TestPythonModule(t *testing.T) {
+	config, buildDir := setupBuildEnv(t)
+	defer tearDownBuildEnv()
+	android.TestPreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.BottomUp("version_split", versionSplitMutator()).Parallel()
+	})
+	for _, d := range data {
+		t.Run(d.desc, func(t *testing.T) {
+			ctx := blueprint.NewContext()
+			android.RegisterTestMutators(ctx)
+			ctx.RegisterModuleType("python_library_host", PythonLibraryHostFactory)
+			ctx.RegisterModuleType("python_binary_host", PythonBinaryHostFactory)
+			ctx.MockFileSystem(d.mockFiles)
+			_, testErrs := ctx.ParseBlueprintsFiles(bpFile)
+			fail(t, testErrs)
+			_, actErrs := ctx.PrepareBuildActions(config)
+			if len(actErrs) > 0 {
+				testErrs = append(testErrs, expectErrors(t, actErrs, d.errors)...)
+			} else {
+				for _, e := range d.expectedBinaries {
+					testErrs = append(testErrs,
+						expectModule(t, ctx, buildDir, e.name,
+							e.actualVersion,
+							e.pyRunfiles, e.depsPyRunfiles,
+							e.parSpec, e.depsParSpecs)...)
+				}
+			}
+			fail(t, testErrs)
+		})
+	}
+}
+
+func expectErrors(t *testing.T, actErrs []error, expErrs []string) (testErrs []error) {
+	actErrStrs := []string{}
+	for _, v := range actErrs {
+		actErrStrs = append(actErrStrs, v.Error())
+	}
+	sort.Strings(actErrStrs)
+	if len(actErrStrs) != len(expErrs) {
+		t.Errorf("got (%d) errors, expected (%d) errors!", len(actErrStrs), len(expErrs))
+		for _, v := range actErrStrs {
+			testErrs = append(testErrs, errors.New(v))
+		}
+	} else {
+		sort.Strings(expErrs)
+		for i, v := range actErrStrs {
+			if v != expErrs[i] {
+				testErrs = append(testErrs, errors.New(v))
+			}
+		}
+	}
+
+	return
+}
+
+func expectModule(t *testing.T, ctx *blueprint.Context, buildDir, name, variant string,
+	expPyRunfiles, expDepsPyRunfiles []string,
+	expParSpec string, expDepsParSpecs []string) (testErrs []error) {
+	module := findModule(ctx, name, variant)
+	if module == nil {
+		t.Fatalf("failed to find module %s!", name)
+	}
+
+	base, baseOk := module.(*pythonBaseModule)
+	if !baseOk {
+		t.Fatalf("%s is not Python module!", name)
+	}
+	sub, subOk := base.subModule.(*PythonBinary)
+	if !subOk {
+		t.Fatalf("%s is not Python binary!", name)
+	}
+
+	actPyRunfiles := []string{}
+	for _, path := range base.srcsPathMappings {
+		actPyRunfiles = append(actPyRunfiles, path.dest)
+	}
+
+	if !reflect.DeepEqual(actPyRunfiles, expPyRunfiles) {
+		testErrs = append(testErrs, errors.New(fmt.Sprintf(
+			`binary "%s" variant "%s" has unexpected pyRunfiles: %q!`,
+			base.Name(),
+			base.properties.ActualVersion,
+			actPyRunfiles)))
+	}
+
+	if !reflect.DeepEqual(sub.depsPyRunfiles, expDepsPyRunfiles) {
+		testErrs = append(testErrs, errors.New(fmt.Sprintf(
+			`binary "%s" variant "%s" has unexpected depsPyRunfiles: %q!`,
+			base.Name(),
+			base.properties.ActualVersion,
+			sub.depsPyRunfiles)))
+	}
+
+	if base.parSpec.soongParArgs() != strings.Replace(expParSpec, "@prefix@", buildDir, 1) {
+		testErrs = append(testErrs, errors.New(fmt.Sprintf(
+			`binary "%s" variant "%s" has unexpected parSpec: %q!`,
+			base.Name(),
+			base.properties.ActualVersion,
+			base.parSpec.soongParArgs())))
+	}
+
+	actDepsParSpecs := []string{}
+	for i, p := range sub.depsParSpecs {
+		actDepsParSpecs = append(actDepsParSpecs, p.soongParArgs())
+		expDepsParSpecs[i] = strings.Replace(expDepsParSpecs[i], "@prefix@", buildDir, 1)
+	}
+
+	if !reflect.DeepEqual(actDepsParSpecs, expDepsParSpecs) {
+		testErrs = append(testErrs, errors.New(fmt.Sprintf(
+			`binary "%s" variant "%s" has unexpected depsParSpecs: %q!`,
+			base.Name(),
+			base.properties.ActualVersion,
+			actDepsParSpecs)))
+	}
+
+	return
+}
+
+func setupBuildEnv(t *testing.T) (config android.Config, buildDir string) {
+	buildDir, err := ioutil.TempDir("", buildNamePrefix)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	config = android.TestConfig(buildDir)
+
+	return
+}
+
+func tearDownBuildEnv() {
+	os.RemoveAll(buildNamePrefix)
+}
+
+func findModule(ctx *blueprint.Context, name, variant string) blueprint.Module {
+	var ret blueprint.Module
+	ctx.VisitAllModules(func(m blueprint.Module) {
+		if ctx.ModuleName(m) == name && ctx.ModuleSubDir(m) == variant {
+			ret = m
+		}
+	})
+	return ret
+}
+
+func fail(t *testing.T, errs []error) {
+	if len(errs) > 0 {
+		for _, err := range errs {
+			t.Error(err)
+		}
+		t.FailNow()
+	}
+}
diff --git a/python/scripts/stub_template_host.txt b/python/scripts/stub_template_host.txt
new file mode 100644
index 0000000..b90a28b
--- /dev/null
+++ b/python/scripts/stub_template_host.txt
@@ -0,0 +1,91 @@
+#!/usr/bin/env python
+
+import os
+import re
+import tempfile
+import shutil
+import sys
+import subprocess
+import zipfile
+
+PYTHON_BINARY = '%interpreter%'
+MAIN_FILE = '%main%'
+PYTHON_PATH = 'PYTHONPATH'
+ZIP_RUNFILES_DIRECTORY_NAME = 'runfiles'
+
+def SearchPathEnv(name):
+  search_path = os.getenv('PATH', os.defpath).split(os.pathsep)
+  for directory in search_path:
+    if directory == '': continue
+    path = os.path.join(directory, name)
+    if os.path.islink(path):
+      path = os.path.realpath(path)
+    # Check if path is actual executable file.
+    if os.path.isfile(path) and os.access(path, os.X_OK):
+      return path
+  return None
+
+def FindPythonBinary():
+  if PYTHON_BINARY.startswith('/'):
+    # Case 1: Python interpreter is directly provided with absolute path.
+    return PYTHON_BINARY
+  else:
+    # Case 2: Find Python interpreter through environment variable: PATH.
+    return SearchPathEnv(PYTHON_BINARY)
+
+# Create the runfiles tree by extracting the zip file
+def ExtractRunfiles():
+  temp_dir = tempfile.mkdtemp("", "Soong.python_")
+  zf = zipfile.ZipFile(os.path.dirname(__file__))
+  zf.extractall(temp_dir)
+  return os.path.join(temp_dir, ZIP_RUNFILES_DIRECTORY_NAME)
+
+def Main():
+  args = sys.argv[1:]
+
+  new_env = {}
+
+  try:
+    runfiles_path = ExtractRunfiles()
+
+    # Add runfiles path to PYTHONPATH.
+    python_path_entries = [runfiles_path]
+
+    # Add top dirs within runfiles path to PYTHONPATH.
+    top_entries = [os.path.join(runfiles_path, i) for i in os.listdir(runfiles_path)]
+    top_pkg_dirs = [i for i in top_entries if os.path.isdir(i)]
+    python_path_entries += top_pkg_dirs
+
+    old_python_path = os.environ.get(PYTHON_PATH)
+    separator = ':'
+    new_python_path = separator.join(python_path_entries)
+
+    # Copy old PYTHONPATH.
+    if old_python_path:
+      new_python_path += separator + old_python_path
+    new_env[PYTHON_PATH] = new_python_path
+
+    # Now look for main python source file.
+    main_filepath = os.path.join(runfiles_path, MAIN_FILE)
+    assert os.path.exists(main_filepath), \
+           'Cannot exec() %r: file not found.' % main_filepath
+    assert os.access(main_filepath, os.R_OK), \
+           'Cannot exec() %r: file not readable.' % main_filepath
+
+    python_program = FindPythonBinary()
+    if python_program is None:
+      raise AssertionError('Could not find python binary: ' + PYTHON_BINARY)
+    args = [python_program, main_filepath] + args
+
+    os.environ.update(new_env)
+
+    sys.stdout.flush()
+    retCode = subprocess.call(args)
+    exit(retCode)
+  except:
+    raise
+  finally:
+    shutil.rmtree(os.path.dirname(runfiles_path), True)
+
+if __name__ == '__main__':
+  Main()