Merge "Allow disabling LTO on eng"
diff --git a/Android.bp b/Android.bp
index 2daa958..26aeac2 100644
--- a/Android.bp
+++ b/Android.bp
@@ -221,6 +221,7 @@
     srcs: [
         "java/aapt2.go",
         "java/aar.go",
+        "java/android_manifest.go",
         "java/android_resources.go",
         "java/androidmk.go",
         "java/app_builder.go",
diff --git a/android/makevars.go b/android/makevars.go
index 3094a48..accc4d3 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -20,6 +20,7 @@
 	"io/ioutil"
 	"os"
 	"strconv"
+	"strings"
 
 	"github.com/google/blueprint/proptools"
 )
@@ -240,8 +241,16 @@
 	return c.ctx
 }
 
+var ninjaDescaper = strings.NewReplacer("$$", "$")
+
 func (c *makeVarsContext) Eval(ninjaStr string) (string, error) {
-	return c.ctx.Eval(c.pctx, ninjaStr)
+	s, err := c.ctx.Eval(c.pctx, ninjaStr)
+	if err != nil {
+		return "", err
+	}
+	// SingletonContext.Eval returns an exapnded string that is valid for a ninja file, de-escape $$ to $ for use
+	// in a Makefile
+	return ninjaDescaper.Replace(s), nil
 }
 
 func (c *makeVarsContext) addVariableRaw(name, value string, strict, sort bool) {
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index e3eb82a..29c7365 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -747,8 +747,8 @@
 	"BUILD_NATIVE_BENCHMARK":      "cc_benchmark",
 	"BUILD_HOST_NATIVE_BENCHMARK": "cc_benchmark_host",
 
-	"BUILD_JAVA_LIBRARY":             "java_library",
-	"BUILD_STATIC_JAVA_LIBRARY":      "java_library_static",
+	"BUILD_JAVA_LIBRARY":             "java_library_installable", // will be rewritten to java_library by bpfix
+	"BUILD_STATIC_JAVA_LIBRARY":      "java_library",
 	"BUILD_HOST_JAVA_LIBRARY":        "java_library_host",
 	"BUILD_HOST_DALVIK_JAVA_LIBRARY": "java_library_host_dalvik",
 	"BUILD_PACKAGE":                  "android_app",
diff --git a/androidmk/cmd/androidmk/androidmk_test.go b/androidmk/cmd/androidmk/androidmk_test.go
index ed5ae02..80e7a75 100644
--- a/androidmk/cmd/androidmk/androidmk_test.go
+++ b/androidmk/cmd/androidmk/androidmk_test.go
@@ -512,7 +512,7 @@
 			LOCAL_PROGUARD_ENABLED := obfuscation optimization
 			# Custom
 			LOCAL_PROGUARD_ENABLED := custom
-			include $(BUILD_JAVA_LIBRARY)
+			include $(BUILD_STATIC_JAVA_LIBRARY)
 		`,
 		expected: `
 			java_library {
@@ -535,11 +535,53 @@
 		`,
 	},
 	{
+		desc: "java library",
+		in: `
+			include $(CLEAR_VARS)
+			LOCAL_SRC_FILES := a.java
+			include $(BUILD_STATIC_JAVA_LIBRARY)
+
+			include $(CLEAR_VARS)
+			LOCAL_SRC_FILES := b.java
+			include $(BUILD_JAVA_LIBRARY)
+
+			include $(CLEAR_VARS)
+			LOCAL_SRC_FILES := c.java
+			LOCAL_UNINSTALLABLE_MODULE := true
+			include $(BUILD_JAVA_LIBRARY)
+
+			include $(CLEAR_VARS)
+			LOCAL_SRC_FILES := d.java
+			LOCAL_UNINSTALLABLE_MODULE := false
+			include $(BUILD_JAVA_LIBRARY)
+		`,
+		expected: `
+			java_library {
+				srcs: ["a.java"],
+			}
+
+			java_library {
+				installable: true,
+				srcs: ["b.java"],
+			}
+
+			java_library {
+				installable: false,
+				srcs: ["c.java"],
+			}
+
+			java_library {
+				installable: true,
+				srcs: ["d.java"],
+			}
+		`,
+	},
+	{
 		desc: "errorprone options for java library",
 		in: `
 			include $(CLEAR_VARS)
 			LOCAL_ERROR_PRONE_FLAGS := -Xep:AsyncCallableReturnsNull:ERROR -Xep:AsyncFunctionReturnsNull:ERROR
-			include $(BUILD_JAVA_LIBRARY)
+			include $(BUILD_STATIC_JAVA_LIBRARY)
 		`,
 		expected: `
 			java_library {
@@ -631,7 +673,7 @@
 				],
 			}
 
-			java_library_static {
+			java_library {
 				srcs: ["test.java"],
 				static_libs: [],
 			}
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index 05be3bd..056a01b 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -71,6 +71,14 @@
 		fix:  rewriteTestModuleTypes,
 	},
 	{
+		name: "rewriteAndroidmkJavaLibs",
+		fix:  rewriteAndroidmkJavaLibs,
+	},
+	{
+		name: "rewriteJavaStaticLibs",
+		fix:  rewriteJavaStaticLibs,
+	},
+	{
 		name: "mergeMatchingModuleProperties",
 		fix:  runPatchListMod(mergeMatchingModuleProperties),
 	},
@@ -241,7 +249,7 @@
 		hasResourceDirs := hasNonEmptyLiteralListProperty(mod, "resource_dirs")
 
 		if hasAndroidLibraries || hasStaticAndroidLibraries || hasResourceDirs {
-			if mod.Type == "java_library_static" {
+			if mod.Type == "java_library_static" || mod.Type == "java_library" {
 				mod.Type = "android_library"
 			}
 		}
@@ -289,7 +297,7 @@
 			switch mod.Type {
 			case "android_app":
 				mod.Type = "android_test"
-			case "java_library":
+			case "java_library", "java_library_installable":
 				mod.Type = "java_test"
 			case "java_library_host":
 				mod.Type = "java_test_host"
@@ -300,6 +308,51 @@
 	return nil
 }
 
+// rewriteJavaStaticLibs rewrites java_library_static into java_library
+func rewriteJavaStaticLibs(f *Fixer) error {
+	for _, def := range f.tree.Defs {
+		mod, ok := def.(*parser.Module)
+		if !ok {
+			continue
+		}
+
+		if mod.Type == "java_library_static" {
+			mod.Type = "java_library"
+		}
+	}
+
+	return nil
+}
+
+// rewriteAndroidmkJavaLibs rewrites java_library_installable into java_library plus installable: true
+func rewriteAndroidmkJavaLibs(f *Fixer) error {
+	for _, def := range f.tree.Defs {
+		mod, ok := def.(*parser.Module)
+		if !ok {
+			continue
+		}
+
+		if mod.Type != "java_library_installable" {
+			continue
+		}
+
+		mod.Type = "java_library"
+
+		_, hasInstallable := mod.GetProperty("installable")
+		if !hasInstallable {
+			prop := &parser.Property{
+				Name: "installable",
+				Value: &parser.Bool{
+					Value: true,
+				},
+			}
+			mod.Properties = append(mod.Properties, prop)
+		}
+	}
+
+	return nil
+}
+
 func runPatchListMod(modFunc func(mod *parser.Module, buf []byte, patchlist *parser.PatchList) error) func(*Fixer) error {
 	return func(f *Fixer) error {
 		// Make sure all the offsets are accurate
@@ -346,6 +399,7 @@
 	"defaults",
 	"device_supported",
 	"host_supported",
+	"installable",
 }
 
 func reorderCommonProperties(mod *parser.Module, buf []byte, patchlist *parser.PatchList) error {
diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go
index 6ba93f6..16dfce0 100644
--- a/bpfix/bpfix/bpfix_test.go
+++ b/bpfix/bpfix/bpfix_test.go
@@ -497,3 +497,61 @@
 		})
 	}
 }
+
+func TestReplaceJavaStaticLibs(t *testing.T) {
+	tests := []struct {
+		name string
+		in   string
+		out  string
+	}{
+		{
+			name: "static lib",
+			in: `
+				java_library_static {
+					name: "foo",
+				}
+			`,
+			out: `
+				java_library {
+					name: "foo",
+				}
+			`,
+		},
+		{
+			name: "java lib",
+			in: `
+				java_library {
+					name: "foo",
+				}
+			`,
+			out: `
+				java_library {
+					name: "foo",
+				}
+			`,
+		},
+		{
+			name: "java installable lib",
+			in: `
+				java_library {
+					name: "foo",
+					installable: true,
+				}
+			`,
+			out: `
+				java_library {
+					name: "foo",
+					installable: true,
+				}
+			`,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			runPass(t, test.in, test.out, func(fixer *Fixer) error {
+				return rewriteJavaStaticLibs(fixer)
+			})
+		})
+	}
+}
diff --git a/java/aar.go b/java/aar.go
index a4069bb..0cfc585 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -27,6 +27,7 @@
 	ExportPackage() android.Path
 	ExportedProguardFlagFiles() android.Paths
 	ExportedStaticPackages() android.Paths
+	ExportedManifest() android.Path
 }
 
 func init() {
@@ -74,8 +75,8 @@
 	return a.exportPackage
 }
 
-func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext sdkContext) (flags []string, deps android.Paths,
-	resDirs, overlayDirs []globbedResourceDir, overlayFiles, rroDirs android.Paths, manifestPath android.Path) {
+func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext sdkContext, manifestPath android.Path) (flags []string,
+	deps android.Paths, resDirs, overlayDirs []globbedResourceDir, rroDirs android.Paths) {
 
 	hasVersionCode := false
 	hasVersionName := false
@@ -116,21 +117,12 @@
 		assetFiles = append(assetFiles, androidResourceGlob(ctx, dir)...)
 	}
 
-	// App manifest file
-	manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
-	manifestPath = android.PathForModuleSrc(ctx, manifestFile)
 	linkFlags = append(linkFlags, "--manifest "+manifestPath.String())
 	linkDeps = append(linkDeps, manifestPath)
 
 	linkFlags = append(linkFlags, android.JoinWithPrefix(assetDirs.Strings(), "-A "))
 	linkDeps = append(linkDeps, assetFiles...)
 
-	transitiveStaticLibs, libDeps, libFlags := aaptLibs(ctx, sdkContext)
-
-	overlayFiles = append(overlayFiles, transitiveStaticLibs...)
-	linkDeps = append(linkDeps, libDeps...)
-	linkFlags = append(linkFlags, libFlags...)
-
 	// SDK version flags
 	minSdkVersion := sdkVersionOrDefault(ctx, sdkContext.minSdkVersion())
 
@@ -156,7 +148,7 @@
 		linkFlags = append(linkFlags, "--version-name ", versionName)
 	}
 
-	return linkFlags, linkDeps, resDirs, overlayDirs, overlayFiles, rroDirs, manifestPath
+	return linkFlags, linkDeps, resDirs, overlayDirs, rroDirs
 }
 
 func (a *aapt) deps(ctx android.BottomUpMutatorContext, sdkContext sdkContext) {
@@ -169,8 +161,18 @@
 }
 
 func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext sdkContext, extraLinkFlags ...string) {
-	linkFlags, linkDeps, resDirs, overlayDirs, overlayFiles, rroDirs, manifestPath := a.aapt2Flags(ctx, sdkContext)
+	transitiveStaticLibs, staticLibManifests, libDeps, libFlags := aaptLibs(ctx, sdkContext)
 
+	// App manifest file
+	manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
+	manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
+
+	manifestPath := manifestMerger(ctx, manifestSrcPath, sdkContext, staticLibManifests)
+
+	linkFlags, linkDeps, resDirs, overlayDirs, rroDirs := a.aapt2Flags(ctx, sdkContext, manifestPath)
+
+	linkFlags = append(linkFlags, libFlags...)
+	linkDeps = append(linkDeps, libDeps...)
 	linkFlags = append(linkFlags, extraLinkFlags...)
 
 	packageRes := android.PathForModuleOut(ctx, "package-res.apk")
@@ -188,7 +190,7 @@
 		compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files).Paths()...)
 	}
 
-	compiledOverlay = append(compiledOverlay, overlayFiles...)
+	compiledOverlay = append(compiledOverlay, transitiveStaticLibs...)
 
 	aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt, extraPackages,
 		linkFlags, linkDeps, compiledRes, compiledOverlay)
@@ -203,8 +205,8 @@
 }
 
 // aaptLibs collects libraries from dependencies and sdk_version and converts them into paths
-func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStaticLibs, deps android.Paths,
-	flags []string) {
+func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStaticLibs, staticLibManifests,
+	deps android.Paths, flags []string) {
 
 	var sharedLibs android.Paths
 
@@ -229,6 +231,7 @@
 			if exportPackage != nil {
 				transitiveStaticLibs = append(transitiveStaticLibs, exportPackage)
 				transitiveStaticLibs = append(transitiveStaticLibs, aarDep.ExportedStaticPackages()...)
+				staticLibManifests = append(staticLibManifests, aarDep.ExportedManifest())
 			}
 		}
 	})
@@ -246,7 +249,7 @@
 
 	transitiveStaticLibs = android.FirstUniquePaths(transitiveStaticLibs)
 
-	return transitiveStaticLibs, deps, flags
+	return transitiveStaticLibs, staticLibManifests, deps, flags
 }
 
 type AndroidLibrary struct {
@@ -269,6 +272,10 @@
 	return a.exportedStaticPackages
 }
 
+func (a *AndroidLibrary) ExportedManifest() android.Path {
+	return a.manifestPath
+}
+
 var _ AndroidLibraryDependency = (*AndroidLibrary)(nil)
 
 func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -323,7 +330,6 @@
 		&module.androidLibraryProperties)
 
 	module.androidLibraryProperties.BuildAAR = true
-	module.properties.Installable = proptools.BoolPtr(false)
 
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	return module
@@ -383,6 +389,10 @@
 	return a.exportedStaticPackages
 }
 
+func (a *AARImport) ExportedManifest() android.Path {
+	return a.manifest
+}
+
 func (a *AARImport) Prebuilt() *android.Prebuilt {
 	return &a.prebuilt
 }
@@ -460,7 +470,9 @@
 	linkFlags = append(linkFlags, "--manifest "+a.manifest.String())
 	linkDeps = append(linkDeps, a.manifest)
 
-	transitiveStaticLibs, libDeps, libFlags := aaptLibs(ctx, sdkContext(a))
+	transitiveStaticLibs, staticLibManifests, libDeps, libFlags := aaptLibs(ctx, sdkContext(a))
+
+	_ = staticLibManifests
 
 	linkDeps = append(linkDeps, libDeps...)
 	linkFlags = append(linkFlags, libFlags...)
diff --git a/java/android_manifest.go b/java/android_manifest.go
new file mode 100644
index 0000000..8fcdcba
--- /dev/null
+++ b/java/android_manifest.go
@@ -0,0 +1,71 @@
+// Copyright 2018 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 java
+
+import (
+	"android/soong/java/config"
+
+	"github.com/google/blueprint"
+
+	"android/soong/android"
+)
+
+var manifestFixerRule = pctx.AndroidStaticRule("manifestFixer",
+	blueprint.RuleParams{
+		Command:     `${config.ManifestFixerCmd} --minSdkVersion ${minSdkVersion} $usesLibraries $in $out`,
+		CommandDeps: []string{"${config.ManifestFixerCmd}"},
+	},
+	"minSdkVersion", "usesLibraries")
+
+var manifestMergerRule = pctx.AndroidStaticRule("manifestMerger",
+	blueprint.RuleParams{
+		Command: `${config.JavaCmd} -classpath ${config.ManifestMergerClasspath} com.android.manifmerger.Merger ` +
+			`--main $in $libs --out $out`,
+		CommandDeps: config.ManifestMergerClasspath,
+	},
+	"libs")
+
+func manifestMerger(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext,
+	staticLibManifests android.Paths) android.Path {
+
+	// Inject minSdkVersion into the manifest
+	fixedManifest := android.PathForModuleOut(ctx, "manifest_fixer", "AndroidManifest.xml")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   manifestFixerRule,
+		Input:  manifest,
+		Output: fixedManifest,
+		Args: map[string]string{
+			"minSdkVersion": sdkVersionOrDefault(ctx, sdkContext.minSdkVersion()),
+		},
+	})
+	manifest = fixedManifest
+
+	// Merge static aar dependency manifests if necessary
+	if len(staticLibManifests) > 0 {
+		mergedManifest := android.PathForModuleOut(ctx, "manifest_merger", "AndroidManifest.xml")
+		ctx.Build(pctx, android.BuildParams{
+			Rule:      manifestMergerRule,
+			Input:     manifest,
+			Implicits: staticLibManifests,
+			Output:    mergedManifest,
+			Args: map[string]string{
+				"libs": android.JoinWithPrefix(staticLibManifests.Strings(), "--uses-library "),
+			},
+		})
+		manifest = mergedManifest
+	}
+
+	return manifest
+}
diff --git a/java/androidmk.go b/java/androidmk.go
index 79cf317..5740eca 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -37,7 +37,7 @@
 					fmt.Fprintln(w, "LOCAL_LOGTAGS_FILES :=", strings.Join(logtags, " "))
 				}
 
-				if library.properties.Installable != nil && *library.properties.Installable == false {
+				if library.installFile == nil {
 					fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
 				}
 				if library.dexJarFile != nil {
@@ -85,7 +85,7 @@
 				fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true")
 				fmt.Fprintln(w, "LOCAL_MODULE_CLASS := JAVA_LIBRARIES")
 				fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", library.implementationJarFile.String())
-				if library.properties.Installable != nil && *library.properties.Installable == false {
+				if library.installFile == nil {
 					fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
 				}
 				if library.dexJarFile != nil {
diff --git a/java/app.go b/java/app.go
index f4de419..7ad525d 100644
--- a/java/app.go
+++ b/java/app.go
@@ -72,6 +72,10 @@
 	return nil
 }
 
+func (a *AndroidApp) ExportedManifest() android.Path {
+	return a.manifestPath
+}
+
 var _ AndroidLibraryDependency = (*AndroidApp)(nil)
 
 type certificate struct {
@@ -187,6 +191,7 @@
 	module.Module.deviceProperties.Optimize.Shrink = proptools.BoolPtr(true)
 
 	module.Module.properties.Instrument = true
+	module.Module.properties.Installable = proptools.BoolPtr(true)
 
 	module.AddProperties(
 		&module.Module.properties,
@@ -225,6 +230,7 @@
 	module := &AndroidTest{}
 
 	module.Module.deviceProperties.Optimize.Enabled = proptools.BoolPtr(true)
+	module.Module.properties.Installable = proptools.BoolPtr(true)
 
 	module.AddProperties(
 		&module.Module.properties,
diff --git a/java/app_test.go b/java/app_test.go
index 6770119..c7c94ec 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -71,7 +71,10 @@
 
 			foo := ctx.ModuleForTests("foo", "android_common")
 
-			expectedLinkImplicits := []string{"AndroidManifest.xml"}
+			var expectedLinkImplicits []string
+
+			manifestFixer := foo.Output("manifest_fixer/AndroidManifest.xml")
+			expectedLinkImplicits = append(expectedLinkImplicits, manifestFixer.Output.String())
 
 			frameworkRes := ctx.ModuleForTests("framework-res", "android_common")
 			expectedLinkImplicits = append(expectedLinkImplicits,
diff --git a/java/config/config.go b/java/config/config.go
index 2fa48cb..ae497a6 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -42,6 +42,16 @@
 		"android.car",
 		"android.car7",
 	}
+
+	ManifestMergerClasspath = []string{
+		"prebuilts/gradle-plugin/com/android/tools/build/manifest-merger/26.1.0/manifest-merger-26.1.0.jar",
+		"prebuilts/gradle-plugin/com/android/tools/common/26.1.0/common-26.1.0.jar",
+		"prebuilts/gradle-plugin/com/android/tools/sdk-common/26.1.0/sdk-common-26.1.0.jar",
+		"prebuilts/gradle-plugin/com/android/tools/sdklib/26.1.0/sdklib-26.1.0.jar",
+		"prebuilts/gradle-plugin/org/jetbrains/kotlin/kotlin-runtime/1.0.5/kotlin-runtime-1.0.5.jar",
+		"prebuilts/gradle-plugin/org/jetbrains/kotlin/kotlin-stdlib/1.1.3/kotlin-stdlib-1.1.3.jar",
+		"prebuilts/misc/common/guava/guava-21.0.jar",
+	}
 )
 
 func init() {
@@ -134,4 +144,7 @@
 	hostBinToolVariableWithPrebuilt("Aapt2Cmd", "prebuilts/sdk/tools", "aapt2")
 
 	pctx.SourcePathVariable("ManifestFixerCmd", "build/soong/scripts/manifest_fixer.py")
+
+	pctx.SourcePathsVariable("ManifestMergerJars", " ", ManifestMergerClasspath...)
+	pctx.SourcePathsVariable("ManifestMergerClasspath", ":", ManifestMergerClasspath...)
 }
diff --git a/java/config/makevars.go b/java/config/makevars.go
index d378877..275f496 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -73,4 +73,8 @@
 	ctx.Strict("EXTRACT_JAR_PACKAGES", "${ExtractJarPackagesCmd}")
 
 	ctx.Strict("MANIFEST_FIXER", "${ManifestFixerCmd}")
+
+	ctx.Strict("ANDROID_MANIFEST_MERGER_DEPS", "${ManifestMergerJars}")
+	ctx.Strict("ANDROID_MANIFEST_MERGER",
+		"${JavaCmd} -classpath ${ManifestMergerClasspath} com.android.manifmerger.Merger")
 }
diff --git a/java/java.go b/java/java.go
index 5d75b1f..9ae05f3 100644
--- a/java/java.go
+++ b/java/java.go
@@ -34,8 +34,8 @@
 func init() {
 	android.RegisterModuleType("java_defaults", defaultsFactory)
 
-	android.RegisterModuleType("java_library", LibraryFactory(true))
-	android.RegisterModuleType("java_library_static", LibraryFactory(false))
+	android.RegisterModuleType("java_library", LibraryFactory)
+	android.RegisterModuleType("java_library_static", LibraryFactory)
 	android.RegisterModuleType("java_library_host", LibraryHostFactory)
 	android.RegisterModuleType("java_binary", BinaryFactory)
 	android.RegisterModuleType("java_binary_host", BinaryHostFactory)
@@ -107,7 +107,8 @@
 	// If not blank, set the java version passed to javac as -source and -target
 	Java_version *string
 
-	// If set to false, don't allow this module to be installed.  Defaults to true.
+	// If set to true, allow this module to be dexed and installed on devices.  Has no
+	// effect on host modules, which are always considered installable.
 	Installable *bool
 
 	// If set to true, include sources used to compile the module in to the final jar
@@ -1182,13 +1183,13 @@
 		outputFile = j.instrument(ctx, flags, outputFile, jarName)
 	}
 
-	if ctx.Device() && j.createDexRule() {
+	if ctx.Device() && (Bool(j.properties.Installable) || Bool(j.deviceProperties.Compile_dex)) {
 		var dexOutputFile android.Path
 		dexOutputFile = j.compileDex(ctx, flags, outputFile, jarName)
 		if ctx.Failed() {
 			return
 		}
-		if j.installable() {
+		if Bool(j.properties.Installable) {
 			outputFile = dexOutputFile
 		}
 	}
@@ -1250,14 +1251,6 @@
 	return instrumentedJar
 }
 
-func (j *Module) installable() bool {
-	return BoolDefault(j.properties.Installable, true)
-}
-
-func (j *Module) createDexRule() bool {
-	return Bool(j.deviceProperties.Compile_dex) || j.installable()
-}
-
 var _ Dependency = (*Library)(nil)
 
 func (j *Module) HeaderJars() android.Paths {
@@ -1293,7 +1286,7 @@
 func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	j.compile(ctx)
 
-	if j.installable() {
+	if Bool(j.properties.Installable) || ctx.Host() {
 		j.installFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
 			ctx.ModuleName()+".jar", j.outputFile)
 	}
@@ -1303,22 +1296,16 @@
 	j.deps(ctx)
 }
 
-func LibraryFactory(installable bool) func() android.Module {
-	return func() android.Module {
-		module := &Library{}
+func LibraryFactory() android.Module {
+	module := &Library{}
 
-		if !installable {
-			module.properties.Installable = proptools.BoolPtr(false)
-		}
+	module.AddProperties(
+		&module.Module.properties,
+		&module.Module.deviceProperties,
+		&module.Module.protoProperties)
 
-		module.AddProperties(
-			&module.Module.properties,
-			&module.Module.deviceProperties,
-			&module.Module.protoProperties)
-
-		InitJavaModule(module, android.HostAndDeviceSupported)
-		return module
-	}
+	InitJavaModule(module, android.HostAndDeviceSupported)
+	return module
 }
 
 func LibraryHostFactory() android.Module {
@@ -1328,6 +1315,8 @@
 		&module.Module.properties,
 		&module.Module.protoProperties)
 
+	module.Module.properties.Installable = proptools.BoolPtr(true)
+
 	InitJavaModule(module, android.HostSupported)
 	return module
 }
@@ -1367,6 +1356,8 @@
 		&module.Module.protoProperties,
 		&module.testProperties)
 
+	module.Module.properties.Installable = proptools.BoolPtr(true)
+
 	InitJavaModule(module, android.HostAndDeviceSupported)
 	android.InitDefaultableModule(module)
 	return module
@@ -1380,6 +1371,8 @@
 		&module.Module.protoProperties,
 		&module.testProperties)
 
+	module.Module.properties.Installable = proptools.BoolPtr(true)
+
 	InitJavaModule(module, android.HostSupported)
 	android.InitDefaultableModule(module)
 	return module
@@ -1449,6 +1442,8 @@
 		&module.Module.protoProperties,
 		&module.binaryProperties)
 
+	module.Module.properties.Installable = proptools.BoolPtr(true)
+
 	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommonFirst)
 	android.InitDefaultableModule(module)
 	return module
@@ -1462,6 +1457,8 @@
 		&module.Module.protoProperties,
 		&module.binaryProperties)
 
+	module.Module.properties.Installable = proptools.BoolPtr(true)
+
 	android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommonFirst)
 	android.InitDefaultableModule(module)
 	return module
diff --git a/java/java_test.go b/java/java_test.go
index 572db2f..537bdb9 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -74,7 +74,7 @@
 	ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(AndroidAppFactory))
 	ctx.RegisterModuleType("android_library", android.ModuleFactoryAdaptor(AndroidLibraryFactory))
 	ctx.RegisterModuleType("java_binary_host", android.ModuleFactoryAdaptor(BinaryHostFactory))
-	ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(LibraryFactory(true)))
+	ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(LibraryFactory))
 	ctx.RegisterModuleType("java_library_host", android.ModuleFactoryAdaptor(LibraryHostFactory))
 	ctx.RegisterModuleType("java_import", android.ModuleFactoryAdaptor(ImportFactory))
 	ctx.RegisterModuleType("java_defaults", android.ModuleFactoryAdaptor(defaultsFactory))
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 5dfc32f..e4cfd41 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -331,7 +331,7 @@
 		props.Product_specific = proptools.BoolPtr(true)
 	}
 
-	mctx.CreateModule(android.ModuleFactoryAdaptor(LibraryFactory(false)), &props)
+	mctx.CreateModule(android.ModuleFactoryAdaptor(LibraryFactory), &props)
 }
 
 // Creates a droiddoc module that creates stubs source files from the given full source
@@ -453,6 +453,7 @@
 		Soc_specific     *bool
 		Device_specific  *bool
 		Product_specific *bool
+		Installable      *bool
 		Required         []string
 		Errorprone       struct {
 			Javacflags []string
@@ -463,6 +464,7 @@
 	props.Srcs = module.properties.Srcs
 	props.Libs = module.properties.Libs
 	props.Static_libs = module.properties.Static_libs
+	props.Installable = proptools.BoolPtr(true)
 	// XML file is installed along with the impl lib
 	props.Required = []string{module.xmlFileName()}
 	props.Errorprone.Javacflags = module.properties.Errorprone.Javacflags
@@ -475,7 +477,7 @@
 		props.Product_specific = proptools.BoolPtr(true)
 	}
 
-	mctx.CreateModule(android.ModuleFactoryAdaptor(LibraryFactory(true)), &props, &module.deviceProperties)
+	mctx.CreateModule(android.ModuleFactoryAdaptor(LibraryFactory), &props, &module.deviceProperties)
 }
 
 // Creates the xml file that publicizes the runtime library