Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/build/build/soong/java/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 33 kB image not shown  

Quelle  droiddoc.go   Sprache: unbekannt

 
Spracherkennung für: .go vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

// 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 (
 "fmt"
 "path/filepath"
 "strings"

 "github.com/google/blueprint"
 "github.com/google/blueprint/proptools"

 "android/soong/android"
 "android/soong/java/config"
)

//go:generate go run ../../blueprint/gobtools/codegen

func init() {
 RegisterDocsBuildComponents(android.InitRegistrationContext)
}

func RegisterDocsBuildComponents(ctx android.RegistrationContext) {
 ctx.RegisterModuleType("doc_defaults", DocDefaultsFactory)

 ctx.RegisterModuleType("droiddoc", DroiddocFactory)
 ctx.RegisterModuleType("droiddoc_host", DroiddocHostFactory)
 ctx.RegisterModuleType("droiddoc_exported_dir", ExportedDroiddocDirFactory)
 ctx.RegisterModuleType("javadoc", JavadocFactory)
 ctx.RegisterModuleType("javadoc_host", JavadocHostFactory)
}

type JavadocProperties struct {
 // list of source files used to compile the Java module.  May be .java, .logtags, .proto,
 // or .aidl files.
 Srcs proptools.Configurable[[]string] `android:"path,arch_variant"`

 // list of source files that should not be used to build the Java module.
 // This is most useful in the arch/multilib variants to remove non-common files
 // filegroup or genrule can be included within this property.
 Exclude_srcs []string `android:"path,arch_variant"`

 // list of package names that should actually be used. If this property is left unspecified,
 // all the sources from the srcs property is used.
 Filter_packages []string

 // list of java libraries that will be in the classpath.
 Libs proptools.Configurable[[]string] `android:"arch_variant"`

 // If set to false, don't allow this module(-docs.zip) to be exported. Defaults to true.
 Installable *bool

 // if not blank, set to the version of the sdk to compile against.
 // Defaults to compiling against the current platform.
 Sdk_version *string `android:"arch_variant"`

 // When targeting 1.9 and above, override the modules to use with --system,
 // otherwise provides defaults libraries to add to the bootclasspath.
 // Defaults to "none"
 System_modules *string

 Aidl struct {
  // Top level directories to pass to aidl tool
  Include_dirs []string

  // Directories rooted at the Android.bp file to pass to aidl tool
  Local_include_dirs []string
 }

 // If not blank, set the java version passed to javadoc as -source
 Java_version *string

 // local files that are used within user customized droiddoc options.
 Arg_files []string `android:"path"`

 // user customized droiddoc args. Deprecated, use flags instead.
 // Available variables for substitution:
 //
 //  $(location <label>): the path to the arg_files with name <label>
 //  $$: a literal $
 Args *string

 // user customized droiddoc args. Not compatible with property args.
 // Available variables for substitution:
 //
 //  $(location <label>): the path to the arg_files with name <label>
 //  $$: a literal $
 Flags []string

 // names of the output files used in args that will be generated
 Out []string
}

type ApiToCheck struct {
 // If set to `false` this will prevent `api_file` and `removed_api_file` from
 // being used in compatibility checks, but they will continue to provide the
 // previously released API to which flagged APIs can be reverted.
 Enabled *bool

 // path to the API txt file that the new API extracted from source code is checked
 // against. The path can be local to the module or from other module (via :module syntax).
 Api_file *string `android:"path"`

 // path to the API txt file that the new @removed API extractd from source code is
 // checked against. The path can be local to the module or from other module (via
 // :module syntax).
 Removed_api_file *string `android:"path"`

 // If not blank, path to the baseline txt file for approved API check violations.
 Baseline_file *string `android:"path"`

 // Arguments to the apicheck tool.
 Args *string

 // If true, checkapi will run by default when building `droid` for this module.
 Default_in_droid *bool
}

type DroiddocProperties struct {
 // directory relative to top of the source tree that contains doc templates files.
 Custom_template *string

 // directories under current module source which contains html/jd files.
 Html_dirs []string

 // set a value in the Clearsilver hdf namespace.
 Hdf []string

 // proofread file contains all of the text content of the javadocs concatenated into one file,
 // suitable for spell-checking and other goodness.
 Proofread_file *string

 // a todo file lists the program elements that are missing documentation.
 // At some point, this might be improved to show more warnings.
 Todo_file *string `android:"path"`

 // A file containing a baseline for allowed lint errors.
 Lint_baseline *string `android:"path"`

 // directory under current module source that provide additional resources (images).
 Resourcesdir *string

 // resources output directory under out/soong/.intermediates.
 Resourcesoutdir *string

 // index.html under current module will be copied to docs out dir, if not null.
 Static_doc_index_redirect *string `android:"path"`

 // source.properties under current module will be copied to docs out dir, if not null.
 Static_doc_properties *string `android:"path"`

 // a list of files under current module source dir which contains known tags in Java sources.
 // filegroup or genrule can be included within this property.
 Knowntags []string `android:"path"`

 // if set to true, generate docs through Dokka instead of Doclava.
 Dokka_enabled *bool

 // Compat config XML. Generates compat change documentation if set.
 Compat_config *string `android:"path"`
}

// Common flags passed down to build rule
type droiddocBuilderFlags struct {
 bootClasspathArgs  string
 classpathArgs      string
 sourcepathArgs     string
 dokkaClasspathArgs string
 aidlFlags          string
 aidlDeps           android.Paths

 doclavaStubsFlags string
 doclavaDocsFlags  string
 postDoclavaCmds   string
}

func InitDroiddocModule(module android.DefaultableModule, hod android.HostOrDeviceSupported) {
 android.InitAndroidArchModule(module, hod, android.MultilibCommon)
 android.InitDefaultableModule(module)
}

func apiCheckEnabled(ctx android.ModuleContext, apiToCheck ApiToCheck, apiVersionTag string) bool {
 if ctx.Config().IsEnvTrue("WITHOUT_CHECK_API") {
  if ctx.Config().BuildFromTextStub() {
   ctx.ModuleErrorf("Generating stubs from api signature files is not available " +
    "with WITHOUT_CHECK_API=true, as sync between the source Java files and the " +
    "api signature files is not guaranteed.\n" +
    "In order to utilize WITHOUT_CHECK_API, generate stubs from the source Java " +
    "files with BUILD_FROM_SOURCE_STUB=true.\n" +
    "However, the usage of WITHOUT_CHECK_API is not preferred as the incremental " +
    "build is slower when generating stubs from the source Java files.\n" +
    "Consider updating the api signature files and generating the stubs from " +
    "them instead.")
  }
  return false
 } else if String(apiToCheck.Api_file) != "" && String(apiToCheck.Removed_api_file) != "" {
  return true
 } else if String(apiToCheck.Api_file) != "" {
  panic("for " + apiVersionTag + " removed_api_file has to be non-empty!")
 } else if String(apiToCheck.Removed_api_file) != "" {
  panic("for " + apiVersionTag + " api_file has to be non-empty!")
 }

 return false
}

// Javadoc
type Javadoc struct {
 android.ModuleBase
 android.DefaultableModuleBase

 properties JavadocProperties

 srcJars     android.Paths
 srcFiles    android.Paths
 sourcepaths android.Paths
 implicits   android.Paths

 docZip      android.WritablePath
 stubsSrcJar android.WritablePath

 exportableStubsSrcJar android.WritablePath
}

// javadoc converts .java source files to documentation using javadoc.
func JavadocFactory() android.Module {
 module := &Javadoc{}

 module.AddProperties(&module.properties)

 InitDroiddocModule(module, android.HostAndDeviceSupported)
 return module
}

// javadoc_host converts .java source files to documentation using javadoc.
func JavadocHostFactory() android.Module {
 module := &Javadoc{}

 module.AddProperties(&module.properties)

 InitDroiddocModule(module, android.HostSupported)
 return module
}

func (j *Javadoc) SdkVersion(ctx android.ConfigContext) android.SdkSpec {
 return android.SdkSpecFrom(ctx, String(j.properties.Sdk_version))
}

func (j *Javadoc) SystemModules() string {
 return proptools.String(j.properties.System_modules)
}

func (j *Javadoc) MinSdkVersion(ctx android.MinSdkVersionFromValueContext) android.ApiLevel {
 return j.SdkVersion(ctx).ApiLevel
}

func (j *Javadoc) ReplaceMaxSdkVersionPlaceholder(ctx android.EarlyModuleContext) android.ApiLevel {
 return j.SdkVersion(ctx).ApiLevel
}

func (j *Javadoc) TargetSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
 return j.SdkVersion(ctx).ApiLevel
}

func (j *Javadoc) addDeps(ctx android.BottomUpMutatorContext) {
 if ctx.Device() {
  sdkDep := decodeSdkDep(ctx, android.SdkContext(j))
  if sdkDep.useModule {
   ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...)
   ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules)
   ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...)
   ctx.AddVariationDependencies(nil, sdkLibTag, sdkDep.classpath...)
  }
 }

 ctx.AddVariationDependencies(nil, libTag, j.properties.Libs.GetOrDefault(ctx, nil)...)
}

func (j *Javadoc) collectAidlFlags(ctx android.ModuleContext, deps deps) droiddocBuilderFlags {
 var flags droiddocBuilderFlags

 flags.aidlFlags, flags.aidlDeps = j.aidlFlags(ctx, deps.aidlPreprocess, deps.aidlIncludeDirs)

 return flags
}

func (j *Javadoc) aidlFlags(ctx android.ModuleContext, aidlPreprocess android.OptionalPath,
 aidlIncludeDirs android.Paths) (string, android.Paths) {

 aidlIncludes := android.PathsForModuleSrc(ctx, j.properties.Aidl.Local_include_dirs)
 aidlIncludes = append(aidlIncludes, android.PathsForSource(ctx, j.properties.Aidl.Include_dirs)...)

 var flags []string
 var deps android.Paths

 if aidlPreprocess.Valid() {
  flags = append(flags, "-p"+aidlPreprocess.String())
  deps = append(deps, aidlPreprocess.Path())
 } else {
  flags = append(flags, android.JoinWithPrefix(aidlIncludeDirs.Strings(), "-I"))
 }

 flags = append(flags, android.JoinWithPrefix(aidlIncludes.Strings(), "-I"))
 flags = append(flags, "-I"+ctx.ModuleDir())
 if src := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "src"); src.Valid() {
  flags = append(flags, "-I"+src.String())
 }

 minSdkVersion := j.MinSdkVersion(ctx).FinalOrFutureInt()
 flags = append(flags, fmt.Sprintf("--min_sdk_version=%v", minSdkVersion))

 return strings.Join(flags, " "), deps
}

// TODO: remove the duplication between this and the one in gen.go
func (j *Javadoc) genSources(ctx android.ModuleContext, srcFiles android.Paths,
 flags droiddocBuilderFlags) android.Paths {

 outSrcFiles := make(android.Paths, 0, len(srcFiles))
 var aidlSrcs android.Paths

 aidlIncludeFlags := genAidlIncludeFlags(ctx, srcFiles, android.Paths{})

 for _, srcFile := range srcFiles {
  switch srcFile.Ext() {
  case ".aidl":
   aidlSrcs = append(aidlSrcs, srcFile)
  case ".logtags":
   javaFile := genLogtags(ctx, srcFile)
   outSrcFiles = append(outSrcFiles, javaFile)
  default:
   outSrcFiles = append(outSrcFiles, srcFile)
  }
 }

 // Process all aidl files together to support sharding them into one or more rules that produce srcjars.
 if len(aidlSrcs) > 0 {
  srcJarFiles := genAidl(ctx, aidlSrcs, flags.aidlFlags+aidlIncludeFlags, nil, flags.aidlDeps)
  outSrcFiles = append(outSrcFiles, srcJarFiles...)
 }

 return outSrcFiles
}

func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps {
 var deps deps

 sdkDep := decodeSdkDep(ctx, android.SdkContext(j))
 if sdkDep.invalidVersion {
  ctx.AddMissingDependencies(sdkDep.bootclasspath)
  ctx.AddMissingDependencies(sdkDep.java9Classpath)
 } else if sdkDep.useFiles {
  deps.bootClasspath = append(deps.bootClasspath, sdkDep.jars...)
  deps.aidlPreprocess = sdkDep.aidl
 } else {
  deps.aidlPreprocess = sdkDep.aidl
 }

 ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) {
  otherName := ctx.OtherModuleName(module)
  tag := ctx.OtherModuleDependencyTag(module)

  switch tag {
  case bootClasspathTag:
   if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
    deps.bootClasspath = append(deps.bootClasspath, dep.ImplementationJars...)
   } else if sm, ok := android.OtherModuleProvider(ctx, module, SystemModulesProvider); ok {
    // A system modules dependency has been added to the bootclasspath
    // so add its libs to the bootclasspath.
    deps.bootClasspath = append(deps.bootClasspath, sm.HeaderJars...)
   } else {
    panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
   }
  case libTag, sdkLibTag:
   if sdkInfo, ok := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider); ok {
    generatingLibsString := android.PrettyConcat(
     getGeneratingLibs(ctx, j.SdkVersion(ctx), module.Name(), sdkInfo), true, "or")
    ctx.ModuleErrorf("cannot depend directly on java_sdk_library %q; try depending on %s instead", module.Name(), generatingLibsString)
   } else if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
    deps.classpath = append(deps.classpath, dep.HeaderJars...)
    deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...)
    deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.AconfigIntermediateCacheOutputPaths...)
   } else if commonInfo, ok := android.OtherModuleProvider(ctx, module, android.CommonModuleInfoProvider); ok && commonInfo.SourceFiles != nil {
    dep := commonInfo.SourceFiles
    checkProducesJars(ctx, *dep, module)
    deps.classpath = append(deps.classpath, dep.Srcs...)
   } else {
    ctx.ModuleErrorf("depends on non-java module %q", otherName)
   }

  case java9LibTag:
   if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
    deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars...)
   } else {
    ctx.ModuleErrorf("depends on non-java module %q", otherName)
   }
  case systemModulesTag:
   if deps.systemModules != nil {
    panic("Found two system module dependencies")
   }
   if sm, ok := android.OtherModuleProvider(ctx, module, SystemModulesProvider); ok {
    deps.systemModules = &systemModules{sm.OutputDir, sm.OutputDirDeps}
   } else {
    ctx.PropertyErrorf("boot classpath dependency %q does not provide SystemModulesProvider",
     ctx.OtherModuleName(module))
   }
  case aconfigDeclarationTag:
   if dep, ok := android.OtherModuleProvider(ctx, module, android.AconfigDeclarationsProviderKey); ok {
    deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.IntermediateCacheOutputPath)
   } else if dep, ok := android.OtherModuleProvider(ctx, module, android.CodegenInfoProvider); ok {
    deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.IntermediateCacheOutputPaths...)
   } else {
    ctx.ModuleErrorf("Only aconfig_declarations and aconfig_declarations_group "+
     "module type is allowed for flags_packages property, but %s is neither "+
     "of these supported module types",
     module.Name(),
    )
   }
  }
 })
 // do not pass exclude_srcs directly when expanding srcFiles since exclude_srcs
 // may contain filegroup or genrule.
 srcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Srcs.GetOrDefault(ctx, nil), j.properties.Exclude_srcs)
 j.implicits = append(j.implicits, srcFiles...)

 // Module can depend on a java_aconfig_library module using the ":module_name{.tag}" syntax.
 // Find the corresponding aconfig_declarations module name for such case.
 for _, src := range j.properties.Srcs.GetOrDefault(ctx, nil) {
  if moduleName, tag := android.SrcIsModuleWithTag(src); moduleName != "" {
   otherModule := android.GetModuleProxyFromPathDep(ctx, moduleName, tag)
   if !otherModule.IsNil() {
    if dep, ok := android.OtherModuleProvider(ctx, otherModule, android.CodegenInfoProvider); ok {
     deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.IntermediateCacheOutputPaths...)
    }
   }
  }
 }

 filterByPackage := func(srcs []android.Path, filterPackages []string) []android.Path {
  if filterPackages == nil {
   return srcs
  }
  filtered := []android.Path{}
  for _, src := range srcs {
   if src.Ext() != ".java" {
    // Don't filter-out non-Java (=generated sources) by package names. This is not ideal,
    // but otherwise metalava emits stub sources having references to the generated AIDL classes
    // in filtered-out pacages (e.g. com.android.internal.*).
    // TODO(b/141149570) We need to fix this by introducing default private constructors or
    // fixing metalava to not emit constructors having references to unknown classes.
    filtered = append(filtered, src)
    continue
   }
   packageName := strings.ReplaceAll(filepath.Dir(src.Rel()), "/", ".")
   if android.HasAnyPrefix(packageName, filterPackages) {
    filtered = append(filtered, src)
   }
  }
  return filtered
 }
 srcFiles = filterByPackage(srcFiles, j.properties.Filter_packages)

 aidlFlags := j.collectAidlFlags(ctx, deps)
 srcFiles = j.genSources(ctx, srcFiles, aidlFlags)

 // srcs may depend on some genrule output.
 j.srcJars = srcFiles.FilterByExt(".srcjar")
 j.srcJars = append(j.srcJars, deps.srcJars...)

 j.srcFiles = srcFiles.FilterOutByExt(".srcjar")
 j.srcFiles = append(j.srcFiles, deps.srcs...)

 if len(j.srcFiles) > 0 {
  j.sourcepaths = android.PathsForModuleSrc(ctx, []string{"."})
 }

 return deps
}

func (j *Javadoc) expandArgs(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
 var argFiles android.Paths
 argFilesMap := map[string]string{}
 argFileLabels := []string{}

 for _, label := range j.properties.Arg_files {
  var paths = android.PathsForModuleSrc(ctx, []string{label})
  if _, exists := argFilesMap[label]; !exists {
   argFilesMap[label] = strings.Join(cmd.PathsForInputs(paths), " ")
   argFileLabels = append(argFileLabels, label)
   argFiles = append(argFiles, paths...)
  } else {
   ctx.ModuleErrorf("multiple arg_files for %q, %q and %q",
    label, argFilesMap[label], paths)
  }
 }

 var argsPropertyName string
 flags := make([]string, 0)
 if j.properties.Args != nil && j.properties.Flags != nil {
  ctx.PropertyErrorf("args", "flags is set. Cannot set args")
 } else if args := proptools.String(j.properties.Args); args != "" {
  flags = append(flags, args)
  argsPropertyName = "args"
 } else {
  flags = append(flags, j.properties.Flags...)
  argsPropertyName = "flags"
 }

 for _, flag := range flags {
  expanded, err := android.Expand(flag, func(name string) (string, error) {
   if strings.HasPrefix(name, "location ") {
    label := strings.TrimSpace(strings.TrimPrefix(name, "location "))
    if paths, ok := argFilesMap[label]; ok {
     return paths, nil
    } else {
     return "", fmt.Errorf("unknown location label %q, expecting one of %q",
      label, strings.Join(argFileLabels, ", "))
    }
   } else if name == "genDir" {
    return android.PathForModuleGen(ctx).String(), nil
   }
   return "", fmt.Errorf("unknown variable '$(%s)'", name)
  })

  if err != nil {
   ctx.PropertyErrorf(argsPropertyName, "%s", err.Error())
  }
  cmd.Flag(expanded)
 }

 cmd.Implicits(argFiles)
}

func (j *Javadoc) DepsMutator(ctx android.BottomUpMutatorContext) {
 j.addDeps(ctx)
}

func (j *Javadoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 deps := j.collectDeps(ctx)

 j.docZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"docs.zip")

 outDir := android.PathForModuleOut(ctx, "out")
 srcJarDir := android.PathForModuleOut(ctx, "srcjars")

 j.stubsSrcJar = nil

 rule := android.NewRuleBuilder(pctx, ctx).SandboxDisabled()

 rule.Command().Text("rm -rf").Text(outDir.String())
 rule.Command().Text("mkdir -p").Text(outDir.String())

 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, j.srcJars)

 javaVersion := getJavaVersion(ctx, String(j.properties.Java_version), android.SdkContext(j))

 cmd := javadocSystemModulesCmd(ctx, rule, j.srcFiles, outDir, srcJarDir, srcJarList,
  deps.systemModules, deps.classpath, j.sourcepaths)

 cmd.FlagWithArg("-source ", javaVersion.String()).
  Flag("-J-Xmx1024m").
  Flag("-XDignore.symbol.file").
  Flag("-Xdoclint:none")

 j.expandArgs(ctx, cmd)

 rule.Command().
  BuiltTool("soong_zip").
  Flag("-write_if_changed").
  Flag("-d").
  FlagWithOutput("-o ", j.docZip).
  FlagWithArg("-C ", outDir.String()).
  FlagWithArg("-D ", outDir.String())

 rule.Restat()

 zipSyncCleanupCmd(rule, srcJarDir)

 rule.Build("javadoc", "javadoc")

 ctx.SetOutputFiles(android.Paths{j.docZip}, ".docs.zip")
}

// Droiddoc
type Droiddoc struct {
 Javadoc

 properties DroiddocProperties
}

// droiddoc converts .java source files to documentation using doclava or dokka.
func DroiddocFactory() android.Module {
 module := &Droiddoc{}

 module.AddProperties(&module.properties,
  &module.Javadoc.properties)

 InitDroiddocModule(module, android.HostAndDeviceSupported)
 return module
}

// droiddoc_host converts .java source files to documentation using doclava or dokka.
func DroiddocHostFactory() android.Module {
 module := &Droiddoc{}

 module.AddProperties(&module.properties,
  &module.Javadoc.properties)

 InitDroiddocModule(module, android.HostSupported)
 return module
}

func (d *Droiddoc) DepsMutator(ctx android.BottomUpMutatorContext) {
 d.Javadoc.addDeps(ctx)

 if String(d.properties.Custom_template) != "" {
  ctx.AddDependency(ctx.Module(), droiddocTemplateTag, String(d.properties.Custom_template))
 }
}

func (d *Droiddoc) doclavaDocsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, docletPath classpath) {
 buildNumberFile := ctx.Config().BuildNumberFile(ctx)
 buildDateFile := ctx.Config().BuildDateFile(ctx)
 // Droiddoc always gets "-source 1.8" because it doesn't support 1.9 sources.  For modules with 1.9
 // sources, droiddoc will get sources produced by metalava which will have already stripped out the
 // 1.9 language features.
 cmd.FlagWithArg("-source ", getStubsJavaVersion().String()).
  Flag("-J-Xmx1600m").
  Flag("-J-XX:-OmitStackTraceInFastThrow").
  Flag("-XDignore.symbol.file").
  Flag("--ignore-source-errors").
  FlagWithArg("-doclet ", "com.google.doclava.Doclava").
  FlagWithInputList("-docletpath ", docletPath.Paths(), ":").
  FlagWithArg("-Xmaxerrs ", "10").
  FlagWithArg("-Xmaxwarns ", "10").
  Flag("-J--add-exports=jdk.javadoc/jdk.javadoc.internal.doclets.formats.html=ALL-UNNAMED").
  Flag("-J--add-exports=jdk.javadoc/jdk.javadoc.internal.tool=ALL-UNNAMED").
  Flag("-J--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED").
  Flag("-J--add-exports=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED").
  Flag("-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED").
  Flag("-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED").
  Flag("-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED").
  FlagWithArg("-hdf page.build ", ctx.Config().BuildId()+"-$(cat "+buildNumberFile.String()+")").OrderOnly(buildNumberFile).
  FlagWithArg("-hdf page.now ", `"$(date -d @$(cat `+buildDateFile.String()+`) "+%d %b %Y %k:%M")" `).OrderOnly(buildDateFile)

 if String(d.properties.Custom_template) == "" {
  // TODO: This is almost always droiddoc-templates-sdk
  ctx.PropertyErrorf("custom_template", "must specify a template")
 }

 ctx.VisitDirectDepsProxyWithTag(droiddocTemplateTag, func(m android.ModuleProxy) {
  if t, ok := android.OtherModuleProvider(ctx, m, ExportedDroiddocDirInfoProvider); ok {
   cmd.FlagWithArg("-templatedir ", t.Dir.String()).Implicits(t.Deps)
  } else {
   ctx.PropertyErrorf("custom_template", "module %q is not a droiddoc_exported_dir", ctx.OtherModuleName(m))
  }
 })

 if len(d.properties.Html_dirs) > 0 {
  htmlDir := android.PathForModuleSrc(ctx, d.properties.Html_dirs[0])
  cmd.FlagWithArg("-htmldir ", htmlDir.String()).
   Implicits(android.PathsForModuleSrc(ctx, []string{filepath.Join(d.properties.Html_dirs[0], "**/*")}))
 }

 if len(d.properties.Html_dirs) > 1 {
  htmlDir2 := android.PathForModuleSrc(ctx, d.properties.Html_dirs[1])
  cmd.FlagWithArg("-htmldir2 ", htmlDir2.String()).
   Implicits(android.PathsForModuleSrc(ctx, []string{filepath.Join(d.properties.Html_dirs[1], "**/*")}))
 }

 if len(d.properties.Html_dirs) > 2 {
  ctx.PropertyErrorf("html_dirs", "Droiddoc only supports up to 2 html dirs")
 }

 knownTags := android.PathsForModuleSrc(ctx, d.properties.Knowntags)
 cmd.FlagForEachInput("-knowntags ", knownTags)

 cmd.FlagForEachArg("-hdf ", d.properties.Hdf)

 if String(d.properties.Proofread_file) != "" {
  proofreadFile := android.PathForModuleOut(ctx, String(d.properties.Proofread_file))
  cmd.FlagWithOutput("-proofread ", proofreadFile)
 }

 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".
  cmd.FlagWithArg("-todo ", String(d.properties.Todo_file)).
   ImplicitOutput(android.PathForModuleOut(ctx, String(d.properties.Todo_file)))
 }

 if String(d.properties.Lint_baseline) != "" {
  cmd.FlagWithInput("-lintbaseline ", android.PathForModuleSrc(ctx, String(d.properties.Lint_baseline)))
 }

 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))
  cmd.FlagWithArg("-resourcesdir ", resourcesDir.String())
 }

 if String(d.properties.Resourcesoutdir) != "" {
  // TODO: it seems -resourceoutdir reference/android/images/ didn't get generated anywhere.
  cmd.FlagWithArg("-resourcesoutdir ", String(d.properties.Resourcesoutdir))
 }
}

func (d *Droiddoc) postDoclavaCmds(ctx android.ModuleContext, rule *android.RuleBuilder) {
 if String(d.properties.Static_doc_index_redirect) != "" {
  staticDocIndexRedirect := android.PathForModuleSrc(ctx, String(d.properties.Static_doc_index_redirect))
  rule.Command().Text("cp").
   Input(staticDocIndexRedirect).
   Output(android.PathForModuleOut(ctx, "out", "index.html"))
 }

 if String(d.properties.Static_doc_properties) != "" {
  staticDocProperties := android.PathForModuleSrc(ctx, String(d.properties.Static_doc_properties))
  rule.Command().Text("cp").
   Input(staticDocProperties).
   Output(android.PathForModuleOut(ctx, "out", "source.properties"))
 }
}

func javadocCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs android.Paths,
 outDir, srcJarDir, srcJarList android.Path, sourcepaths android.Paths) *android.RuleBuilderCommand {

 cmd := rule.Command().
  BuiltTool("soong_javac_wrapper").Tool(config.JavadocCmd(ctx)).
  Flag(config.JavacVmFlags).
  FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, "javadoc.rsp"), srcs).
  FlagWithInput("@", srcJarList)

 // TODO(ccross): Remove this if- statement once we finish migration for all Doclava
 // based stubs generation.
 // In the future, all the docs generation depends on Metalava stubs (droidstubs) srcjar
 // dir. We need add the srcjar dir to -sourcepath arg, so that Javadoc can figure out
 // the correct package name base path.
 if len(sourcepaths) > 0 {
  cmd.FlagWithList("-sourcepath ", sourcepaths.Strings(), ":")
 } else {
  cmd.FlagWithArg("-sourcepath ", srcJarDir.String())
 }

 cmd.FlagWithArg("-d ", outDir.String()).
  Flag("-quiet")

 return cmd
}

func javadocSystemModulesCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs android.Paths,
 outDir, srcJarDir, srcJarList android.Path, systemModules *systemModules,
 classpath classpath, sourcepaths android.Paths) *android.RuleBuilderCommand {

 cmd := javadocCmd(ctx, rule, srcs, outDir, srcJarDir, srcJarList, sourcepaths)

 flag, deps := systemModules.FormJavaSystemModulesPath(ctx.Device())
 cmd.Flag(flag).Implicits(deps)

 cmd.FlagWithArg("--patch-module ", "java.base=.")

 if len(classpath) > 0 {
  cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":")
 }

 return cmd
}

func javadocBootclasspathCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs android.Paths,
 outDir, srcJarDir, srcJarList android.Path, bootclasspath, classpath classpath,
 sourcepaths android.Paths) *android.RuleBuilderCommand {

 cmd := javadocCmd(ctx, rule, srcs, outDir, srcJarDir, srcJarList, sourcepaths)

 if len(bootclasspath) == 0 && ctx.Device() {
  // explicitly specify -bootclasspath "" if the bootclasspath is empty to
  // ensure java does not fall back to the default bootclasspath.
  cmd.FlagWithArg("-bootclasspath ", `""`)
 } else if len(bootclasspath) > 0 {
  cmd.FlagWithInputList("-bootclasspath ", bootclasspath.Paths(), ":")
 }

 if len(classpath) > 0 {
  cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":")
 }

 return cmd
}

func dokkaCmd(ctx android.ModuleContext, rule *android.RuleBuilder,
 outDir, srcJarDir android.Path, bootclasspath, classpath classpath) *android.RuleBuilderCommand {

 // Dokka doesn't support bootClasspath, so combine these two classpath vars for Dokka.
 dokkaClasspath := append(bootclasspath.Paths(), classpath.Paths()...)

 return rule.Command().
  BuiltTool("dokka").
  Flag(config.JavacVmFlags).
  Flag("-J--add-opens=java.base/java.lang=ALL-UNNAMED").
  Flag(srcJarDir.String()).
  FlagWithInputList("-classpath ", dokkaClasspath, ":").
  FlagWithArg("-format ", "dac").
  FlagWithArg("-dacRoot ", "/reference/kotlin").
  FlagWithArg("-output ", outDir.String())
}

func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 deps := d.Javadoc.collectDeps(ctx)

 d.Javadoc.docZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"docs.zip")

 jsilver := ctx.Config().HostJavaToolPath(ctx, "jsilver.jar")
 doclava := ctx.Config().HostJavaToolPath(ctx, "doclava.jar")

 outDir := android.PathForModuleOut(ctx, "out")
 srcJarDir := android.PathForModuleOut(ctx, "srcjars")

 rule := android.NewRuleBuilder(pctx, ctx).SandboxDisabled()

 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)

 var cmd *android.RuleBuilderCommand
 if Bool(d.properties.Dokka_enabled) {
  cmd = dokkaCmd(ctx, rule, outDir, srcJarDir, deps.bootClasspath, deps.classpath)
 } else {
  cmd = javadocBootclasspathCmd(ctx, rule, d.Javadoc.srcFiles, outDir, srcJarDir, srcJarList,
   deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths)
 }

 d.expandArgs(ctx, cmd)

 if d.properties.Compat_config != nil {
  compatConfig := android.PathForModuleSrc(ctx, String(d.properties.Compat_config))
  cmd.FlagWithInput("-compatconfig ", compatConfig)
 }

 var desc string
 if Bool(d.properties.Dokka_enabled) {
  desc = "dokka"
 } else {
  d.doclavaDocsFlags(ctx, cmd, classpath{jsilver, doclava})

  for _, o := range d.Javadoc.properties.Out {
   cmd.ImplicitOutput(android.PathForModuleGen(ctx, o))
  }

  d.postDoclavaCmds(ctx, rule)
  desc = "doclava"
 }

 rule.Command().
  BuiltTool("soong_zip").
  Flag("-write_if_changed").
  Flag("-d").
  FlagWithOutput("-o ", d.docZip).
  FlagWithArg("-C ", outDir.String()).
  FlagWithArg("-D ", outDir.String())

 rule.Restat()

 zipSyncCleanupCmd(rule, srcJarDir)

 rule.Build("javadoc", desc)

 ctx.SetOutputFiles(android.Paths{d.Javadoc.docZip}, "")
 ctx.SetOutputFiles(android.Paths{d.Javadoc.docZip}, ".docs.zip")
}

// Exported Droiddoc Directory
var droiddocTemplateTag = dependencyTag{name: "droiddoc-template"}

type ExportedDroiddocDirProperties struct {
 // path to the directory containing Droiddoc related files.
 Path *string
}

// @auto-generate: gob
type ExportedDroiddocDirInfo struct {
 Deps android.Paths
 Dir  android.Path
}

var ExportedDroiddocDirInfoProvider = blueprint.NewProvider[ExportedDroiddocDirInfo]()

type ExportedDroiddocDir struct {
 android.ModuleBase

 properties ExportedDroiddocDirProperties

 deps android.Paths
 dir  android.Path
}

// droiddoc_exported_dir exports a directory of html templates or nullability annotations for use by doclava.
func ExportedDroiddocDirFactory() android.Module {
 module := &ExportedDroiddocDir{}
 module.AddProperties(&module.properties)
 android.InitAndroidModule(module)
 return module
}

func (d *ExportedDroiddocDir) DepsMutator(android.BottomUpMutatorContext) {}

func (d *ExportedDroiddocDir) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 path := String(d.properties.Path)
 d.dir = android.PathForModuleSrc(ctx, path)
 d.deps = android.PathsForModuleSrc(ctx, []string{filepath.Join(path, "**/*")})

 android.SetProvider(ctx, ExportedDroiddocDirInfoProvider, ExportedDroiddocDirInfo{
  Dir:  d.dir,
  Deps: d.deps,
 })
}

// Defaults
type DocDefaults struct {
 android.ModuleBase
 android.DefaultsModuleBase
}

func DocDefaultsFactory() android.Module {
 module := &DocDefaults{}

 module.AddProperties(
  &JavadocProperties{},
  &DroiddocProperties{},
 )

 android.InitDefaultsModule(module)

 return module
}

func zipSyncCmd(ctx android.ModuleContext, rule *android.RuleBuilder,
 srcJarDir android.ModuleOutPath, srcJars android.Paths) android.OutputPath {

 cmd := rule.Command()
 cmd.Text("rm -rf").Text(cmd.PathForOutput(srcJarDir))
 cmd = rule.Command()
 cmd.Text("mkdir -p").Text(cmd.PathForOutput(srcJarDir))
 srcJarList := srcJarDir.Join(ctx, "list")

 rule.Temporary(srcJarList)

 cmd = rule.Command()
 cmd.BuiltTool("zipsync").
  FlagWithArg("-d ", cmd.PathForOutput(srcJarDir)).
  FlagWithOutput("-l ", srcJarList).
  FlagWithArg("-f ", `"*.java"`).
  Inputs(srcJars)

 return srcJarList
}

func zipSyncCleanupCmd(rule *android.RuleBuilder, srcJarDir android.ModuleOutPath) {
 rule.Command().Text("rm -rf").Text(srcJarDir.String())
}

[Dauer der Verarbeitung: 0.43 Sekunden, vorverarbeitet 2026-06-28]