Merge "Fix parsing of dangling dep check"
diff --git a/android/api_levels.go b/android/api_levels.go
index 64d3d5d..1b56625 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -67,6 +67,8 @@
 			"N":     24,
 			"N-MR1": 25,
 			"O":     26,
+			"O-MR1": 27,
+			"P":     28,
 		}
 		for i, codename := range config.PlatformVersionCombinedCodenames() {
 			apiLevelsMap[codename] = baseApiLevel + i
diff --git a/android/variable.go b/android/variable.go
index d97fc0b..b4ed1b7 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -104,6 +104,19 @@
 		Uml struct {
 			Cppflags []string
 		}
+
+		Use_lmkd_stats_log struct {
+			Cflags []string
+		}
+
+		Arc struct {
+			Cflags       []string
+			Exclude_srcs []string
+			Include_dirs []string
+			Shared_libs  []string
+			Static_libs  []string
+			Srcs         []string
+		}
 	} `android:"arch_variant"`
 }
 
@@ -174,6 +187,8 @@
 	Enforce_vintf_manifest     *bool `json:",omitempty"`
 	Pdk                        *bool `json:",omitempty"`
 	Uml                        *bool `json:",omitempty"`
+	Use_lmkd_stats_log         *bool `json:",omitempty"`
+	Arc                        *bool `json:",omitempty"`
 	MinimizeJavaDebugInfo      *bool `json:",omitempty"`
 
 	IntegerOverflowExcludePaths *[]string `json:",omitempty"`
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index 172784a..f412583 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -174,7 +174,6 @@
 	toolchain64Bit
 
 	ldflags              string
-	lldflags             string
 	toolchainCflags      string
 	toolchainClangCflags string
 }
@@ -232,7 +231,7 @@
 }
 
 func (t *toolchainArm64) ClangLldflags() string {
-	return t.lldflags
+	return "${config.Arm64Lldflags}"
 }
 
 func (t *toolchainArm64) ToolchainClangCflags() string {
@@ -270,10 +269,6 @@
 			"${config.Arm64Ldflags}",
 			extraLdflags,
 		}, " "),
-		lldflags: strings.Join([]string{
-			"${config.Arm64Lldflags}",
-			extraLdflags,
-		}, " "),
 		toolchainCflags:      variantOrDefault(arm64CpuVariantCflagsVar, arch.CpuVariant),
 		toolchainClangCflags: strings.Join(toolchainClangCflags, " "),
 	}
diff --git a/cc/config/global.go b/cc/config/global.go
index dee7640..a49e509 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -192,7 +192,7 @@
 	// This is used by non-NDK modules to get jni.h. export_include_dirs doesn't help
 	// with this, since there is no associated library.
 	pctx.PrefixedExistentPathsForSourcesVariable("CommonNativehelperInclude", "-I",
-		[]string{"libnativehelper/include_deprecated"})
+		[]string{"libnativehelper/include_jni"})
 
 	pctx.SourcePathVariable("ClangDefaultBase", ClangDefaultBase)
 	pctx.VariableFunc("ClangBase", func(ctx android.PackageVarContext) string {
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 4c8a611..1037181 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -236,8 +236,8 @@
 		}
 	}
 
-	// Enable CFI for all components in the include paths
-	if s.Cfi == nil && ctx.Config().CFIEnabledForPath(ctx.ModuleDir()) {
+	// Enable CFI for all components in the include paths (for Aarch64 only)
+	if s.Cfi == nil && ctx.Config().CFIEnabledForPath(ctx.ModuleDir()) && ctx.Arch().ArchType == android.Arm64 {
 		s.Cfi = boolPtr(true)
 		if inList("cfi", ctx.Config().SanitizeDeviceDiag()) {
 			s.Diag.Cfi = boolPtr(true)
@@ -272,6 +272,12 @@
 		s.Integer_overflow = nil
 	}
 
+	// Also disable CFI for VNDK variants of components
+	if ctx.isVndk() && ctx.useVndk() {
+		s.Cfi = nil
+		s.Diag.Cfi = nil
+	}
+
 	if ctx.staticBinary() {
 		s.Address = nil
 		s.Coverage = nil
diff --git a/java/config/config.go b/java/config/config.go
index ae497a6..4863fec 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -41,6 +41,8 @@
 		"services",
 		"android.car",
 		"android.car7",
+		"core-oj",
+		"core-libart",
 	}
 
 	ManifestMergerClasspath = []string{
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 6a5758b..137eaaf 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -94,7 +94,7 @@
 
 	android.RegisterModuleType("droiddoc", DroiddocFactory)
 	android.RegisterModuleType("droiddoc_host", DroiddocHostFactory)
-	android.RegisterModuleType("droiddoc_template", DroiddocTemplateFactory)
+	android.RegisterModuleType("droiddoc_exported_dir", ExportedDroiddocDirFactory)
 	android.RegisterModuleType("javadoc", JavadocFactory)
 	android.RegisterModuleType("javadoc_host", JavadocHostFactory)
 }
@@ -169,7 +169,7 @@
 	// directory relative to top of the source tree that contains doc templates files.
 	Custom_template *string
 
-	// directories relative to top of the source tree which contains html/jd files.
+	// directories under current module source which contains html/jd files.
 	Html_dirs []string
 
 	// set a value in the Clearsilver hdf namespace.
@@ -266,6 +266,34 @@
 	Metalava_merge_annotations_dirs []string
 }
 
+//
+// Common flags passed down to build rule
+//
+type droiddocBuilderFlags struct {
+	args              string
+	bootClasspathArgs string
+	classpathArgs     string
+	aidlFlags         string
+
+	doclavaDocsFlags  string
+	doclavaStubsFlags string
+	postDoclavaCmds   string
+
+	metalavaAnnotationsFlags string
+	metalavaDocsFlags        string
+	metalavaStubsFlags       string
+
+	dokkaFlags string
+}
+
+func InitDroiddocModule(module android.DefaultableModule, hod android.HostOrDeviceSupported) {
+	android.InitAndroidArchModule(module, hod, android.MultilibCommon)
+	android.InitDefaultableModule(module)
+}
+
+//
+// Javadoc
+//
 type Javadoc struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
@@ -284,39 +312,6 @@
 	return android.Paths{j.stubsSrcJar}
 }
 
-var _ android.SourceFileProducer = (*Javadoc)(nil)
-
-type Droiddoc struct {
-	Javadoc
-
-	properties        DroiddocProperties
-	apiFile           android.WritablePath
-	dexApiFile        android.WritablePath
-	privateApiFile    android.WritablePath
-	privateDexApiFile android.WritablePath
-	removedApiFile    android.WritablePath
-	removedDexApiFile android.WritablePath
-	exactApiFile      android.WritablePath
-	apiMappingFile    android.WritablePath
-
-	checkCurrentApiTimestamp      android.WritablePath
-	updateCurrentApiTimestamp     android.WritablePath
-	checkLastReleasedApiTimestamp android.WritablePath
-
-	annotationsZip android.WritablePath
-
-	apiFilePath android.Path
-}
-
-type ApiFilePath interface {
-	ApiFilePath() android.Path
-}
-
-func InitDroiddocModule(module android.DefaultableModule, hod android.HostOrDeviceSupported) {
-	android.InitAndroidArchModule(module, hod, android.MultilibCommon)
-	android.InitDefaultableModule(module)
-}
-
 func JavadocFactory() android.Module {
 	module := &Javadoc{}
 
@@ -335,25 +330,7 @@
 	return module
 }
 
-func DroiddocFactory() android.Module {
-	module := &Droiddoc{}
-
-	module.AddProperties(&module.properties,
-		&module.Javadoc.properties)
-
-	InitDroiddocModule(module, android.HostAndDeviceSupported)
-	return module
-}
-
-func DroiddocHostFactory() android.Module {
-	module := &Droiddoc{}
-
-	module.AddProperties(&module.properties,
-		&module.Javadoc.properties)
-
-	InitDroiddocModule(module, android.HostSupported)
-	return module
-}
+var _ android.SourceFileProducer = (*Javadoc)(nil)
 
 func (j *Javadoc) sdkVersion() string {
 	return String(j.properties.Sdk_version)
@@ -372,7 +349,7 @@
 				ctx.AddDependency(ctx.Module(), systemModulesTag, config.DefaultSystemModules)
 			}
 			if !Bool(j.properties.No_framework_libs) {
-				ctx.AddDependency(ctx.Module(), libTag, []string{"ext", "framework"}...)
+				ctx.AddDependency(ctx.Module(), libTag, config.DefaultLibraries...)
 			}
 		} else if sdkDep.useModule {
 			if ctx.Config().TargetOpenJDK9() {
@@ -406,8 +383,8 @@
 	}
 }
 
-func (j *Javadoc) collectBuilderFlags(ctx android.ModuleContext, deps deps) javaBuilderFlags {
-	var flags javaBuilderFlags
+func (j *Javadoc) collectAidlFlags(ctx android.ModuleContext, deps deps) droiddocBuilderFlags {
+	var flags droiddocBuilderFlags
 
 	// aidl flags.
 	aidlFlags := j.aidlFlags(ctx, deps.aidlPreprocess, deps.aidlIncludeDirs)
@@ -443,7 +420,7 @@
 }
 
 func (j *Javadoc) genSources(ctx android.ModuleContext, srcFiles android.Paths,
-	flags javaBuilderFlags) android.Paths {
+	flags droiddocBuilderFlags) android.Paths {
 
 	outSrcFiles := make(android.Paths, 0, len(srcFiles))
 
@@ -536,7 +513,7 @@
 	// do not pass exclude_srcs directly when expanding srcFiles since exclude_srcs
 	// may contain filegroup or genrule.
 	srcFiles := ctx.ExpandSources(j.properties.Srcs, j.properties.Exclude_srcs)
-	flags := j.collectBuilderFlags(ctx, deps)
+	flags := j.collectAidlFlags(ctx, deps)
 	srcFiles = j.genSources(ctx, srcFiles, flags)
 
 	// srcs may depend on some genrule output.
@@ -608,6 +585,59 @@
 	})
 }
 
+//
+// Droiddoc
+//
+type Droiddoc struct {
+	Javadoc
+
+	properties        DroiddocProperties
+	apiFile           android.WritablePath
+	dexApiFile        android.WritablePath
+	privateApiFile    android.WritablePath
+	privateDexApiFile android.WritablePath
+	removedApiFile    android.WritablePath
+	removedDexApiFile android.WritablePath
+	exactApiFile      android.WritablePath
+	apiMappingFile    android.WritablePath
+
+	checkCurrentApiTimestamp      android.WritablePath
+	updateCurrentApiTimestamp     android.WritablePath
+	checkLastReleasedApiTimestamp android.WritablePath
+
+	annotationsZip android.WritablePath
+
+	apiFilePath android.Path
+}
+
+type ApiFilePath interface {
+	ApiFilePath() android.Path
+}
+
+func DroiddocFactory() android.Module {
+	module := &Droiddoc{}
+
+	module.AddProperties(&module.properties,
+		&module.Javadoc.properties)
+
+	InitDroiddocModule(module, android.HostAndDeviceSupported)
+	return module
+}
+
+func DroiddocHostFactory() android.Module {
+	module := &Droiddoc{}
+
+	module.AddProperties(&module.properties,
+		&module.Javadoc.properties)
+
+	InitDroiddocModule(module, android.HostSupported)
+	return module
+}
+
+func (d *Droiddoc) ApiFilePath() android.Path {
+	return d.apiFilePath
+}
+
 func (d *Droiddoc) checkCurrentApi() bool {
 	if String(d.properties.Check_api.Current.Api_file) != "" &&
 		String(d.properties.Check_api.Current.Removed_api_file) != "" {
@@ -641,7 +671,7 @@
 		ctx.AddDependency(ctx.Module(), droiddocTemplateTag, String(d.properties.Custom_template))
 	}
 
-	// extra_arg_files may contains filegroup or genrule.
+	// arg_files may contains filegroup or genrule.
 	android.ExtractSourcesDeps(ctx, d.properties.Arg_files)
 
 	// knowntags may contain filegroup or genrule.
@@ -668,36 +698,33 @@
 	if String(d.properties.Metalava_previous_api) != "" {
 		android.ExtractSourceDeps(ctx, d.properties.Metalava_previous_api)
 	}
+
+	if len(d.properties.Metalava_merge_annotations_dirs) != 0 {
+		for _, mergeAnnotationsDir := range d.properties.Metalava_merge_annotations_dirs {
+			ctx.AddDependency(ctx.Module(), metalavaMergeAnnotationsDirTag, mergeAnnotationsDir)
+		}
+	}
 }
 
-func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	deps := d.Javadoc.collectDeps(ctx)
+func (d *Droiddoc) initBuilderFlags(ctx android.ModuleContext, implicits *android.Paths, deps deps) (droiddocBuilderFlags, error) {
+	var flags droiddocBuilderFlags
 
-	var implicits android.Paths
-	implicits = append(implicits, deps.bootClasspath...)
-	implicits = append(implicits, deps.classpath...)
+	*implicits = append(*implicits, deps.bootClasspath...)
+	*implicits = append(*implicits, deps.classpath...)
 
-	var bootClasspathArgs string
-	javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), sdkContext(d))
-	// Doclava has problem with "-source 1.9", so override javaVersion when Doclava
-	// is running with EXPERIMENTAL_USE_OPENJDK9=true. And eventually Doclava will be
-	// replaced by Metalava.
-	if !Bool(d.properties.Metalava_enabled) {
-		javaVersion = "1.8"
-	}
 	// continue to use -bootclasspath even if Metalava under -source 1.9 is enabled
 	// since it doesn't support system modules yet.
 	if len(deps.bootClasspath.Strings()) > 0 {
 		// For OpenJDK 8 we can use -bootclasspath to define the core libraries code.
-		bootClasspathArgs = deps.bootClasspath.FormJavaClassPath("-bootclasspath")
+		flags.bootClasspathArgs = deps.bootClasspath.FormJavaClassPath("-bootclasspath")
 	}
-	classpathArgs := deps.classpath.FormJavaClassPath("-classpath")
+	flags.classpathArgs = deps.classpath.FormJavaClassPath("-classpath")
 
 	argFiles := ctx.ExpandSources(d.properties.Arg_files, nil)
 	argFilesMap := map[string]android.Path{}
 
 	for _, f := range argFiles {
-		implicits = append(implicits, f)
+		*implicits = append(*implicits, f)
 		if _, exists := argFilesMap[f.Rel()]; !exists {
 			argFilesMap[f.Rel()] = f
 		} else {
@@ -706,7 +733,8 @@
 		}
 	}
 
-	args, err := android.Expand(String(d.properties.Args), func(name string) (string, error) {
+	var err error
+	flags.args, err = android.Expand(String(d.properties.Args), func(name string) (string, error) {
 		if strings.HasPrefix(name, "location ") {
 			label := strings.TrimSpace(strings.TrimPrefix(name, "location "))
 			if f, ok := argFilesMap[label]; ok {
@@ -722,163 +750,16 @@
 
 	if err != nil {
 		ctx.PropertyErrorf("args", "%s", err.Error())
-		return
+		return droiddocBuilderFlags{}, err
 	}
+	return flags, nil
+}
 
-	genDocsForMetalava := false
-	var metalavaArgs string
-	if Bool(d.properties.Metalava_enabled) {
-		if strings.Contains(args, "--generate-documentation") {
-			if !strings.Contains(args, "-nodocs") {
-				genDocsForMetalava = true
-			}
-			// TODO(nanzhang): Add a Soong property to handle documentation args.
-			metalavaArgs = strings.Split(args, "--generate-documentation")[0]
-		} else {
-			metalavaArgs = args
-		}
-	}
+func (d *Droiddoc) collectDoclavaDocsFlags(ctx android.ModuleContext, implicits *android.Paths,
+	javaVersion string, jsilver, doclava android.Path) string {
 
-	var templateDir, htmlDirArgs, htmlDir2Args string
-	if !Bool(d.properties.Metalava_enabled) || genDocsForMetalava {
-		if String(d.properties.Custom_template) == "" {
-			// TODO: This is almost always droiddoc-templates-sdk
-			ctx.PropertyErrorf("custom_template", "must specify a template")
-		}
-
-		ctx.VisitDirectDepsWithTag(droiddocTemplateTag, func(m android.Module) {
-			if t, ok := m.(*DroiddocTemplate); ok {
-				implicits = append(implicits, t.deps...)
-				templateDir = t.dir.String()
-			} else {
-				ctx.PropertyErrorf("custom_template", "module %q is not a droiddoc_template", ctx.OtherModuleName(m))
-			}
-		})
-
-		if len(d.properties.Html_dirs) > 0 {
-			htmlDir := android.PathForModuleSrc(ctx, d.properties.Html_dirs[0])
-			implicits = append(implicits, ctx.Glob(htmlDir.Join(ctx, "**/*").String(), nil)...)
-			htmlDirArgs = "-htmldir " + htmlDir.String()
-		}
-
-		if len(d.properties.Html_dirs) > 1 {
-			htmlDir2 := android.PathForModuleSrc(ctx, d.properties.Html_dirs[1])
-			implicits = append(implicits, ctx.Glob(htmlDir2.Join(ctx, "**/*").String(), nil)...)
-			htmlDir2Args = "-htmldir2 " + htmlDir2.String()
-		}
-
-		if len(d.properties.Html_dirs) > 2 {
-			ctx.PropertyErrorf("html_dirs", "Droiddoc only supports up to 2 html dirs")
-		}
-
-		knownTags := ctx.ExpandSources(d.properties.Knowntags, nil)
-		implicits = append(implicits, knownTags...)
-
-		for _, kt := range knownTags {
-			args = args + " -knowntags " + kt.String()
-		}
-
-		for _, hdf := range d.properties.Hdf {
-			args = args + " -hdf " + hdf
-		}
-
-		if String(d.properties.Proofread_file) != "" {
-			proofreadFile := android.PathForModuleOut(ctx, String(d.properties.Proofread_file))
-			args = args + " -proofread " + proofreadFile.String()
-		}
-
-		if String(d.properties.Todo_file) != "" {
-			// tricky part:
-			// we should not compute full path for todo_file through PathForModuleOut().
-			// the non-standard doclet will get the full path relative to "-o".
-			args = args + " -todo " + String(d.properties.Todo_file)
-		}
-
-		if String(d.properties.Resourcesdir) != "" {
-			// TODO: should we add files under resourcesDir to the implicits? It seems that
-			// resourcesDir is one sub dir of htmlDir
-			resourcesDir := android.PathForModuleSrc(ctx, String(d.properties.Resourcesdir))
-			args = args + " -resourcesdir " + resourcesDir.String()
-		}
-
-		if String(d.properties.Resourcesoutdir) != "" {
-			// TODO: it seems -resourceoutdir reference/android/images/ didn't get generated anywhere.
-			args = args + " -resourcesoutdir " + String(d.properties.Resourcesoutdir)
-		}
-	}
-
-	var docArgsForMetalava string
-	if Bool(d.properties.Metalava_enabled) && genDocsForMetalava {
-		docArgsForMetalava = strings.Split(args, "--generate-documentation")[1]
-	}
-
-	var implicitOutputs android.WritablePaths
-
-	if d.checkCurrentApi() || d.checkLastReleasedApi() || String(d.properties.Api_filename) != "" {
-		d.apiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.txt")
-		args = args + " -api " + d.apiFile.String()
-		metalavaArgs = metalavaArgs + " --api " + d.apiFile.String()
-		implicitOutputs = append(implicitOutputs, d.apiFile)
-		d.apiFilePath = d.apiFile
-	}
-
-	if d.checkCurrentApi() || d.checkLastReleasedApi() || String(d.properties.Removed_api_filename) != "" {
-		d.removedApiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_removed.txt")
-		args = args + " -removedApi " + d.removedApiFile.String()
-		metalavaArgs = metalavaArgs + " --removed-api " + d.removedApiFile.String()
-		implicitOutputs = append(implicitOutputs, d.removedApiFile)
-	}
-
-	if String(d.properties.Private_api_filename) != "" {
-		d.privateApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_api_filename))
-		args = args + " -privateApi " + d.privateApiFile.String()
-		metalavaArgs = metalavaArgs + " --private-api " + d.privateApiFile.String()
-		implicitOutputs = append(implicitOutputs, d.privateApiFile)
-	}
-
-	if String(d.properties.Dex_api_filename) != "" {
-		d.dexApiFile = android.PathForModuleOut(ctx, String(d.properties.Dex_api_filename))
-		args = args + " -dexApi " + d.dexApiFile.String()
-		implicitOutputs = append(implicitOutputs, d.dexApiFile)
-	}
-
-	if String(d.properties.Private_dex_api_filename) != "" {
-		d.privateDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_dex_api_filename))
-		args = args + " -privateDexApi " + d.privateDexApiFile.String()
-		metalavaArgs = metalavaArgs + " --private-dex-api " + d.privateDexApiFile.String()
-		implicitOutputs = append(implicitOutputs, d.privateDexApiFile)
-	}
-
-	if String(d.properties.Removed_dex_api_filename) != "" {
-		d.removedDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Removed_dex_api_filename))
-		args = args + " -removedDexApi " + d.removedDexApiFile.String()
-		metalavaArgs = metalavaArgs + " --removed-dex-api " + d.removedDexApiFile.String()
-		implicitOutputs = append(implicitOutputs, d.removedDexApiFile)
-	}
-
-	if String(d.properties.Exact_api_filename) != "" {
-		d.exactApiFile = android.PathForModuleOut(ctx, String(d.properties.Exact_api_filename))
-		args = args + " -exactApi " + d.exactApiFile.String()
-		metalavaArgs = metalavaArgs + " --exact-api " + d.exactApiFile.String()
-		implicitOutputs = append(implicitOutputs, d.exactApiFile)
-	}
-
-	if String(d.properties.Dex_mapping_filename) != "" {
-		d.apiMappingFile = android.PathForModuleOut(ctx, String(d.properties.Dex_mapping_filename))
-		args = args + " -apiMapping " + d.apiMappingFile.String()
-		// Omitted: metalava support
-		implicitOutputs = append(implicitOutputs, d.apiMappingFile)
-	}
-
-	implicits = append(implicits, d.Javadoc.srcJars...)
-
-	implicitOutputs = append(implicitOutputs, d.Javadoc.docZip)
-	for _, o := range d.properties.Out {
-		implicitOutputs = append(implicitOutputs, android.PathForModuleGen(ctx, o))
-	}
-
-	jsilver := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "jsilver.jar")
-	doclava := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "doclava.jar")
+	*implicits = append(*implicits, jsilver)
+	*implicits = append(*implicits, doclava)
 
 	var date string
 	if runtime.GOOS == "darwin" {
@@ -887,43 +768,285 @@
 		date = `date -d`
 	}
 
-	doclavaOpts := "-source " + javaVersion + " -J-Xmx1600m -J-XX:-OmitStackTraceInFastThrow -XDignore.symbol.file " +
+	args := " -source " + javaVersion + " -J-Xmx1600m -J-XX:-OmitStackTraceInFastThrow -XDignore.symbol.file " +
 		"-doclet com.google.doclava.Doclava -docletpath " + jsilver.String() + ":" + doclava.String() + " " +
-		"-templatedir " + templateDir + " " + htmlDirArgs + " " + htmlDir2Args + " " +
 		"-hdf page.build " + ctx.Config().BuildId() + "-" + ctx.Config().BuildNumberFromFile() + " " +
 		`-hdf page.now "$$(` + date + ` @$$(cat ` + ctx.Config().Getenv("BUILD_DATETIME_FILE") + `) "+%d %b %Y %k:%M")" `
 
+	if String(d.properties.Custom_template) == "" {
+		// TODO: This is almost always droiddoc-templates-sdk
+		ctx.PropertyErrorf("custom_template", "must specify a template")
+	}
+
+	ctx.VisitDirectDepsWithTag(droiddocTemplateTag, func(m android.Module) {
+		if t, ok := m.(*ExportedDroiddocDir); ok {
+			*implicits = append(*implicits, t.deps...)
+			args = args + " -templatedir " + t.dir.String()
+		} else {
+			ctx.PropertyErrorf("custom_template", "module %q is not a droiddoc_template", ctx.OtherModuleName(m))
+		}
+	})
+
+	if len(d.properties.Html_dirs) > 0 {
+		htmlDir := android.PathForModuleSrc(ctx, d.properties.Html_dirs[0])
+		*implicits = append(*implicits, ctx.Glob(htmlDir.Join(ctx, "**/*").String(), nil)...)
+		args = args + " -htmldir " + htmlDir.String()
+	}
+
+	if len(d.properties.Html_dirs) > 1 {
+		htmlDir2 := android.PathForModuleSrc(ctx, d.properties.Html_dirs[1])
+		*implicits = append(*implicits, ctx.Glob(htmlDir2.Join(ctx, "**/*").String(), nil)...)
+		args = args + " -htmldir2 " + htmlDir2.String()
+	}
+
+	if len(d.properties.Html_dirs) > 2 {
+		ctx.PropertyErrorf("html_dirs", "Droiddoc only supports up to 2 html dirs")
+	}
+
+	knownTags := ctx.ExpandSources(d.properties.Knowntags, nil)
+	*implicits = append(*implicits, knownTags...)
+
+	for _, kt := range knownTags {
+		args = args + " -knowntags " + kt.String()
+	}
+
+	for _, hdf := range d.properties.Hdf {
+		args = args + " -hdf " + hdf
+	}
+
+	if String(d.properties.Proofread_file) != "" {
+		proofreadFile := android.PathForModuleOut(ctx, String(d.properties.Proofread_file))
+		args = args + " -proofread " + proofreadFile.String()
+	}
+
+	if String(d.properties.Todo_file) != "" {
+		// tricky part:
+		// we should not compute full path for todo_file through PathForModuleOut().
+		// the non-standard doclet will get the full path relative to "-o".
+		args = args + " -todo " + String(d.properties.Todo_file)
+	}
+
+	if String(d.properties.Resourcesdir) != "" {
+		// TODO: should we add files under resourcesDir to the implicits? It seems that
+		// resourcesDir is one sub dir of htmlDir
+		resourcesDir := android.PathForModuleSrc(ctx, String(d.properties.Resourcesdir))
+		args = args + " -resourcesdir " + resourcesDir.String()
+	}
+
+	if String(d.properties.Resourcesoutdir) != "" {
+		// TODO: it seems -resourceoutdir reference/android/images/ didn't get generated anywhere.
+		args = args + " -resourcesoutdir " + String(d.properties.Resourcesoutdir)
+	}
+	return args
+}
+
+func (d *Droiddoc) collectStubsFlags(ctx android.ModuleContext, implicitOutputs *android.WritablePaths) (string, string) {
+	var doclavaFlags, MetalavaFlags string
+	if d.checkCurrentApi() || d.checkLastReleasedApi() || String(d.properties.Api_filename) != "" {
+		d.apiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.txt")
+		doclavaFlags += " -api " + d.apiFile.String()
+		MetalavaFlags = MetalavaFlags + " --api " + d.apiFile.String()
+		*implicitOutputs = append(*implicitOutputs, d.apiFile)
+		d.apiFilePath = d.apiFile
+	}
+
+	if d.checkCurrentApi() || d.checkLastReleasedApi() || String(d.properties.Removed_api_filename) != "" {
+		d.removedApiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_removed.txt")
+		doclavaFlags += " -removedApi " + d.removedApiFile.String()
+		MetalavaFlags = MetalavaFlags + " --removed-api " + d.removedApiFile.String()
+		*implicitOutputs = append(*implicitOutputs, d.removedApiFile)
+	}
+
+	if String(d.properties.Private_api_filename) != "" {
+		d.privateApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_api_filename))
+		doclavaFlags += " -privateApi " + d.privateApiFile.String()
+		MetalavaFlags = MetalavaFlags + " --private-api " + d.privateApiFile.String()
+		*implicitOutputs = append(*implicitOutputs, d.privateApiFile)
+	}
+
+	if String(d.properties.Dex_api_filename) != "" {
+		d.dexApiFile = android.PathForModuleOut(ctx, String(d.properties.Dex_api_filename))
+		doclavaFlags += " -dexApi " + d.dexApiFile.String()
+		*implicitOutputs = append(*implicitOutputs, d.dexApiFile)
+	}
+
+	if String(d.properties.Private_dex_api_filename) != "" {
+		d.privateDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Private_dex_api_filename))
+		doclavaFlags += " -privateDexApi " + d.privateDexApiFile.String()
+		MetalavaFlags = MetalavaFlags + " --private-dex-api " + d.privateDexApiFile.String()
+		*implicitOutputs = append(*implicitOutputs, d.privateDexApiFile)
+	}
+
+	if String(d.properties.Removed_dex_api_filename) != "" {
+		d.removedDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Removed_dex_api_filename))
+		doclavaFlags += " -removedDexApi " + d.removedDexApiFile.String()
+		MetalavaFlags = MetalavaFlags + " --removed-dex-api " + d.removedDexApiFile.String()
+		*implicitOutputs = append(*implicitOutputs, d.removedDexApiFile)
+	}
+
+	if String(d.properties.Exact_api_filename) != "" {
+		d.exactApiFile = android.PathForModuleOut(ctx, String(d.properties.Exact_api_filename))
+		doclavaFlags += " -exactApi " + d.exactApiFile.String()
+		MetalavaFlags = MetalavaFlags + " --exact-api " + d.exactApiFile.String()
+		*implicitOutputs = append(*implicitOutputs, d.exactApiFile)
+	}
+
+	if String(d.properties.Dex_mapping_filename) != "" {
+		d.apiMappingFile = android.PathForModuleOut(ctx, String(d.properties.Dex_mapping_filename))
+		doclavaFlags += " -apiMapping " + d.apiMappingFile.String()
+		// Omitted: metalava support
+		*implicitOutputs = append(*implicitOutputs, d.apiMappingFile)
+	}
+
+	if BoolDefault(d.properties.Create_stubs, true) {
+		doclavaFlags += " -stubs " + android.PathForModuleOut(ctx, "docs", "stubsDir").String()
+	}
+
+	if Bool(d.properties.Write_sdk_values) {
+		doclavaFlags += " -sdkvalues " + android.PathForModuleOut(ctx, "docs", "out").String()
+	}
+	return doclavaFlags, MetalavaFlags
+}
+
+func (d *Droiddoc) getPostDoclavaCmds(ctx android.ModuleContext, implicits *android.Paths) string {
+	var cmds string
+	if String(d.properties.Static_doc_index_redirect) != "" {
+		static_doc_index_redirect := ctx.ExpandSource(String(d.properties.Static_doc_index_redirect),
+			"static_doc_index_redirect")
+		*implicits = append(*implicits, static_doc_index_redirect)
+		cmds = cmds + " && cp " + static_doc_index_redirect.String() + " " +
+			android.PathForModuleOut(ctx, "docs", "out", "index.html").String()
+	}
+
+	if String(d.properties.Static_doc_properties) != "" {
+		static_doc_properties := ctx.ExpandSource(String(d.properties.Static_doc_properties),
+			"static_doc_properties")
+		*implicits = append(*implicits, static_doc_properties)
+		cmds = cmds + " && cp " + static_doc_properties.String() + " " +
+			android.PathForModuleOut(ctx, "docs", "out", "source.properties").String()
+	}
+	return cmds
+}
+
+func (d *Droiddoc) collectMetalavaAnnotationsFlags(
+	ctx android.ModuleContext, implicits *android.Paths, implicitOutputs *android.WritablePaths) string {
+	var flags string
+	if String(d.properties.Metalava_previous_api) != "" {
+		previousApi := ctx.ExpandSource(String(d.properties.Metalava_previous_api),
+			"metalava_previous_api")
+		flags += " --previous-api " + previousApi.String()
+		*implicits = append(*implicits, previousApi)
+	}
+
+	if Bool(d.properties.Metalava_annotations_enabled) {
+		if String(d.properties.Metalava_previous_api) == "" {
+			ctx.PropertyErrorf("metalava_previous_api",
+				"has to be non-empty if annotations was enabled!")
+		}
+		flags += " --include-annotations --migrate-nullness"
+
+		d.annotationsZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"_annotations.zip")
+		*implicitOutputs = append(*implicitOutputs, d.annotationsZip)
+
+		flags += " --extract-annotations " + d.annotationsZip.String()
+
+		if len(d.properties.Metalava_merge_annotations_dirs) == 0 {
+			ctx.PropertyErrorf("metalava_merge_annotations_dirs",
+				"has to be non-empty if annotations was enabled!")
+		}
+		ctx.VisitDirectDepsWithTag(metalavaMergeAnnotationsDirTag, func(m android.Module) {
+			if t, ok := m.(*ExportedDroiddocDir); ok {
+				*implicits = append(*implicits, t.deps...)
+				flags += " --merge-annotations " + t.dir.String()
+			} else {
+				ctx.PropertyErrorf("metalava_merge_annotations_dirs",
+					"module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
+			}
+		})
+		// TODO(tnorbye): find owners to fix these warnings when annotation was enabled.
+		flags += " --hide HiddenTypedefConstant --hide SuperfluousPrefix --hide AnnotationExtraction "
+	}
+
+	return flags
+}
+
+func (d *Droiddoc) collectMetalavaDocsFlags(ctx android.ModuleContext,
+	bootClasspathArgs, classpathArgs string) string {
+	return " --doc-stubs " + android.PathForModuleOut(ctx, "docs", "docStubsDir").String() +
+		" --write-doc-stubs-source-list $outDir/doc_stubs_src_list " +
+		" --generate-documentation ${config.JavadocCmd} -encoding UTF-8 DOC_STUBS_SOURCE_LIST " +
+		bootClasspathArgs + " " + classpathArgs + " " + " -sourcepath " +
+		android.PathForModuleOut(ctx, "docs", "docStubsDir").String() + " -quiet -d $outDir "
+}
+
+func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	deps := d.Javadoc.collectDeps(ctx)
+
+	javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), sdkContext(d))
+	// Doclava has problem with "-source 1.9", so override javaVersion when Doclava
+	// is running with EXPERIMENTAL_USE_OPENJDK9=true. And eventually Doclava will be
+	// replaced by Metalava.
 	if !Bool(d.properties.Metalava_enabled) {
-		opts := doclavaOpts + args
+		javaVersion = "1.8"
+	}
 
-		implicits = append(implicits, jsilver)
-		implicits = append(implicits, doclava)
+	jsilver := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "jsilver.jar")
+	doclava := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "doclava.jar")
+	java8Home := ctx.Config().Getenv("ANDROID_JAVA8_HOME")
+	checkApiClasspath := classpath{jsilver, doclava, android.PathForSource(ctx, java8Home, "lib/tools.jar")}
 
-		if BoolDefault(d.properties.Create_stubs, true) {
-			opts += " -stubs " + android.PathForModuleOut(ctx, "docs", "stubsDir").String()
+	var implicits android.Paths
+	implicits = append(implicits, d.Javadoc.srcJars...)
+
+	var implicitOutputs android.WritablePaths
+	implicitOutputs = append(implicitOutputs, d.Javadoc.docZip)
+	for _, o := range d.properties.Out {
+		implicitOutputs = append(implicitOutputs, android.PathForModuleGen(ctx, o))
+	}
+
+	flags, err := d.initBuilderFlags(ctx, &implicits, deps)
+	if err != nil {
+		return
+	}
+
+	flags.doclavaStubsFlags, flags.metalavaStubsFlags = d.collectStubsFlags(ctx, &implicitOutputs)
+	if Bool(d.properties.Metalava_enabled) {
+		opts := flags.metalavaStubsFlags
+		flags.metalavaAnnotationsFlags = d.collectMetalavaAnnotationsFlags(ctx, &implicits, &implicitOutputs)
+		opts += flags.metalavaAnnotationsFlags
+		if strings.Contains(flags.args, "--generate-documentation") {
+			// TODO(nanzhang): Add a Soong property to handle documentation args.
+			flags.doclavaDocsFlags = d.collectDoclavaDocsFlags(ctx, &implicits, javaVersion, jsilver, doclava)
+			flags.metalavaDocsFlags = d.collectMetalavaDocsFlags(ctx, flags.bootClasspathArgs, flags.classpathArgs)
+			opts += " " + strings.Split(flags.args, "--generate-documentation")[0] + " " +
+				flags.metalavaDocsFlags + flags.doclavaDocsFlags +
+				" " + strings.Split(flags.args, "--generate-documentation")[1]
+		} else {
+			opts += " " + flags.args
 		}
-
-		if Bool(d.properties.Write_sdk_values) {
-			opts += " -sdkvalues " + android.PathForModuleOut(ctx, "docs", "out").String()
-		}
-
-		var postDoclavaCmds string
-		if String(d.properties.Static_doc_index_redirect) != "" {
-			static_doc_index_redirect := ctx.ExpandSource(String(d.properties.Static_doc_index_redirect),
-				"static_doc_index_redirect")
-			implicits = append(implicits, static_doc_index_redirect)
-			postDoclavaCmds += " && cp " + static_doc_index_redirect.String() + " " +
-				android.PathForModuleOut(ctx, "docs", "out", "index.html").String()
-		}
-
-		if String(d.properties.Static_doc_properties) != "" {
-			static_doc_properties := ctx.ExpandSource(String(d.properties.Static_doc_properties),
-				"static_doc_properties")
-			implicits = append(implicits, static_doc_properties)
-			postDoclavaCmds += " && cp " + static_doc_properties.String() + " " +
-				android.PathForModuleOut(ctx, "docs", "out", "source.properties").String()
-		}
-
+		ctx.Build(pctx, android.BuildParams{
+			Rule:            metalava,
+			Description:     "Metalava",
+			Output:          d.Javadoc.stubsSrcJar,
+			Inputs:          d.Javadoc.srcFiles,
+			Implicits:       implicits,
+			ImplicitOutputs: implicitOutputs,
+			Args: map[string]string{
+				"outDir":            android.PathForModuleOut(ctx, "docs", "out").String(),
+				"srcJarDir":         android.PathForModuleOut(ctx, "docs", "srcjars").String(),
+				"stubsDir":          android.PathForModuleOut(ctx, "docs", "stubsDir").String(),
+				"srcJars":           strings.Join(d.Javadoc.srcJars.Strings(), " "),
+				"javaVersion":       javaVersion,
+				"bootclasspathArgs": flags.bootClasspathArgs,
+				"classpathArgs":     flags.classpathArgs,
+				"sourcepath":        strings.Join(d.Javadoc.sourcepaths.Strings(), ":"),
+				"docZip":            d.Javadoc.docZip.String(),
+				"opts":              opts,
+			},
+		})
+	} else {
+		flags.doclavaDocsFlags = d.collectDoclavaDocsFlags(ctx, &implicits, javaVersion, jsilver, doclava)
+		flags.postDoclavaCmds = d.getPostDoclavaCmds(ctx, &implicits)
 		ctx.Build(pctx, android.BuildParams{
 			Rule:            javadoc,
 			Description:     "Droiddoc",
@@ -936,87 +1059,16 @@
 				"srcJarDir":         android.PathForModuleOut(ctx, "docs", "srcjars").String(),
 				"stubsDir":          android.PathForModuleOut(ctx, "docs", "stubsDir").String(),
 				"srcJars":           strings.Join(d.Javadoc.srcJars.Strings(), " "),
-				"opts":              opts,
-				"bootclasspathArgs": bootClasspathArgs,
-				"classpathArgs":     classpathArgs,
+				"opts":              flags.doclavaDocsFlags + flags.doclavaStubsFlags + " " + flags.args,
+				"bootclasspathArgs": flags.bootClasspathArgs,
+				"classpathArgs":     flags.classpathArgs,
 				"sourcepath":        strings.Join(d.Javadoc.sourcepaths.Strings(), ":"),
 				"docZip":            d.Javadoc.docZip.String(),
-				"postDoclavaCmds":   postDoclavaCmds,
+				"postDoclavaCmds":   flags.postDoclavaCmds,
 			},
 		})
-	} else {
-		opts := metalavaArgs
-
-		buildArgs := map[string]string{
-			"outDir":            android.PathForModuleOut(ctx, "docs", "out").String(),
-			"srcJarDir":         android.PathForModuleOut(ctx, "docs", "srcjars").String(),
-			"stubsDir":          android.PathForModuleOut(ctx, "docs", "stubsDir").String(),
-			"srcJars":           strings.Join(d.Javadoc.srcJars.Strings(), " "),
-			"javaVersion":       javaVersion,
-			"bootclasspathArgs": bootClasspathArgs,
-			"classpathArgs":     classpathArgs,
-			"sourcepath":        strings.Join(d.Javadoc.sourcepaths.Strings(), ":"),
-			"docZip":            d.Javadoc.docZip.String(),
-		}
-
-		var previousApi android.Path
-		if String(d.properties.Metalava_previous_api) != "" {
-			previousApi = ctx.ExpandSource(String(d.properties.Metalava_previous_api),
-				"metalava_previous_api")
-			opts += " --previous-api " + previousApi.String()
-			implicits = append(implicits, previousApi)
-		}
-
-		if Bool(d.properties.Metalava_annotations_enabled) {
-			if String(d.properties.Metalava_previous_api) == "" {
-				ctx.PropertyErrorf("metalava_previous_api",
-					"has to be non-empty if annotations was enabled!")
-			}
-			opts += " --include-annotations --migrate-nullness"
-
-			d.annotationsZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"_annotations.zip")
-			implicitOutputs = append(implicitOutputs, d.annotationsZip)
-
-			if len(d.properties.Metalava_merge_annotations_dirs) == 0 {
-				ctx.PropertyErrorf("metalava_merge_annotations_dirs",
-					"has to be non-empty if annotations was enabled!")
-			}
-			mergeAnnotationsDirs := android.PathsForSource(ctx, d.properties.Metalava_merge_annotations_dirs)
-
-			opts += " --extract-annotations " + d.annotationsZip.String()
-			for _, mergeAnnotationsDir := range mergeAnnotationsDirs {
-				opts += " --merge-annotations " + mergeAnnotationsDir.String()
-			}
-			// TODO(tnorbye): find owners to fix these warnings when annotation was enabled.
-			opts += " --hide HiddenTypedefConstant --hide SuperfluousPrefix --hide AnnotationExtraction"
-		}
-
-		if genDocsForMetalava {
-			opts += " --doc-stubs " + android.PathForModuleOut(ctx, "docs", "docStubsDir").String() +
-				" --write-doc-stubs-source-list $outDir/doc_stubs_src_list " +
-				" --generate-documentation ${config.JavadocCmd} -encoding UTF-8 DOC_STUBS_SOURCE_LIST " +
-				doclavaOpts + docArgsForMetalava + bootClasspathArgs + " " + classpathArgs + " " + " -sourcepath " +
-				android.PathForModuleOut(ctx, "docs", "docStubsDir").String() + " -quiet -d $outDir "
-			implicits = append(implicits, jsilver)
-			implicits = append(implicits, doclava)
-		}
-
-		buildArgs["opts"] = opts
-		ctx.Build(pctx, android.BuildParams{
-			Rule:            metalava,
-			Description:     "Metalava",
-			Output:          d.Javadoc.stubsSrcJar,
-			Inputs:          d.Javadoc.srcFiles,
-			Implicits:       implicits,
-			ImplicitOutputs: implicitOutputs,
-			Args:            buildArgs,
-		})
 	}
 
-	java8Home := ctx.Config().Getenv("ANDROID_JAVA8_HOME")
-
-	checkApiClasspath := classpath{jsilver, doclava, android.PathForSource(ctx, java8Home, "lib/tools.jar")}
-
 	if d.checkCurrentApi() && !ctx.Config().IsPdkBuild() {
 		d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "check_current_api.timestamp")
 
@@ -1053,7 +1105,6 @@
 		})
 
 		d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "update_current_api.timestamp")
-
 		ctx.Build(pctx, android.BuildParams{
 			Rule:        updateApi,
 			Description: "update current API",
@@ -1067,6 +1118,7 @@
 			},
 		})
 	}
+
 	if d.checkLastReleasedApi() && !ctx.Config().IsPdkBuild() {
 		d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "check_last_released_api.timestamp")
 
@@ -1098,36 +1150,36 @@
 	}
 }
 
-func (d *Droiddoc) ApiFilePath() android.Path {
-	return d.apiFilePath
-}
-
+//
+// Exported Droiddoc Directory
+//
 var droiddocTemplateTag = dependencyTag{name: "droiddoc-template"}
+var metalavaMergeAnnotationsDirTag = dependencyTag{name: "metalava-merge-annotations-dir"}
 
-type DroiddocTemplateProperties struct {
-	// path to the directory containing the droiddoc templates.
+type ExportedDroiddocDirProperties struct {
+	// path to the directory containing Droiddoc related files.
 	Path *string
 }
 
-type DroiddocTemplate struct {
+type ExportedDroiddocDir struct {
 	android.ModuleBase
 
-	properties DroiddocTemplateProperties
+	properties ExportedDroiddocDirProperties
 
 	deps android.Paths
 	dir  android.Path
 }
 
-func DroiddocTemplateFactory() android.Module {
-	module := &DroiddocTemplate{}
+func ExportedDroiddocDirFactory() android.Module {
+	module := &ExportedDroiddocDir{}
 	module.AddProperties(&module.properties)
 	android.InitAndroidModule(module)
 	return module
 }
 
-func (d *DroiddocTemplate) DepsMutator(android.BottomUpMutatorContext) {}
+func (d *ExportedDroiddocDir) DepsMutator(android.BottomUpMutatorContext) {}
 
-func (d *DroiddocTemplate) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+func (d *ExportedDroiddocDir) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	path := android.PathForModuleSrc(ctx, String(d.properties.Path))
 	d.dir = path
 	d.deps = ctx.Glob(path.Join(ctx, "**/*").String(), nil)
diff --git a/java/java_test.go b/java/java_test.go
index 6bba29b..434bcc7 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -84,7 +84,7 @@
 	ctx.RegisterModuleType("genrule", android.ModuleFactoryAdaptor(genrule.GenRuleFactory))
 	ctx.RegisterModuleType("droiddoc", android.ModuleFactoryAdaptor(DroiddocFactory))
 	ctx.RegisterModuleType("droiddoc_host", android.ModuleFactoryAdaptor(DroiddocHostFactory))
-	ctx.RegisterModuleType("droiddoc_template", android.ModuleFactoryAdaptor(DroiddocTemplateFactory))
+	ctx.RegisterModuleType("droiddoc_template", android.ModuleFactoryAdaptor(ExportedDroiddocDirFactory))
 	ctx.RegisterModuleType("java_sdk_library", android.ModuleFactoryAdaptor(sdkLibraryFactory))
 	ctx.RegisterModuleType("prebuilt_apis", android.ModuleFactoryAdaptor(prebuiltApisFactory))
 	ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators)
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 57a0c3a..525652a 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -117,6 +117,17 @@
 		Javacflags []string
 	}
 
+	// Additional droiddoc options
+	Droiddoc_options []string
+
+	// If set to true, compile dex regardless of installable.  Defaults to false.
+	// This applies to the stubs lib.
+	Compile_dex *bool
+
+	// the sub dirs under srcs_lib_whitelist_dirs will be scanned for java srcs.
+	// Defaults to "android.annotation".
+	Srcs_lib_whitelist_pkgs []string
+
 	// TODO: determines whether to create HTML doc or not
 	//Html_doc *bool
 }
@@ -359,6 +370,7 @@
 		Soc_specific      *bool
 		Device_specific   *bool
 		Product_specific  *bool
+		Compile_dex       *bool
 		Product_variables struct {
 			Unbundled_build struct {
 				Enabled *bool
@@ -377,6 +389,9 @@
 	// Unbundled apps will use the prebult one from /prebuilts/sdk
 	props.Product_variables.Unbundled_build.Enabled = proptools.BoolPtr(false)
 	props.Product_variables.Pdk.Enabled = proptools.BoolPtr(false)
+	if module.properties.Compile_dex != nil {
+		props.Compile_dex = module.properties.Compile_dex
+	}
 
 	if module.SocSpecific() {
 		props.Soc_specific = proptools.BoolPtr(true)
@@ -430,7 +445,7 @@
 	droiddocArgs := " -hide 110 -hide 111 -hide 113 -hide 121 -hide 125 -hide 126 -hide 127 -hide 128" +
 		" -stubpackages " + strings.Join(module.properties.Api_packages, ":") +
 		" " + android.JoinWithPrefix(module.properties.Hidden_api_packages, "-hidePackage ") +
-		" -nodocs"
+		" " + android.JoinWithPrefix(module.properties.Droiddoc_options, "-") + " -nodocs"
 	switch apiScope {
 	case apiScopeSystem:
 		droiddocArgs = droiddocArgs + " -showAnnotation android.annotation.SystemApi"
@@ -488,7 +503,11 @@
 	props.Srcs_lib_whitelist_dirs = []string{"core/java"}
 	// Add android.annotation package to give access to the framework-defined
 	// annotations such as SystemApi, NonNull, etc.
-	props.Srcs_lib_whitelist_pkgs = []string{"android.annotation"}
+	if module.properties.Srcs_lib_whitelist_pkgs != nil {
+		props.Srcs_lib_whitelist_pkgs = module.properties.Srcs_lib_whitelist_pkgs
+	} else {
+		props.Srcs_lib_whitelist_pkgs = []string{"android.annotation"}
+	}
 	// These libs are required by doclava to parse the framework sources add via
 	// Src_lib and Src_lib_whitelist_* properties just above.
 	// If we don't add them to the classpath, errors messages are generated by doclava,