Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  droidstubs.go   Sprache: unbekannt

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

// Copyright 2021 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"
 "regexp"
 "slices"
 "strings"

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

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

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

// @auto-generate: gob
type StubsInfo struct {
 ApiVersionsXml android.Path
 AnnotationsZip android.Path
 ApiFile        android.Path
 RemovedApiFile android.Path
}

// @auto-generate: gob
type DroidStubsInfo struct {
 CheckedInApiFile        android.Path
 CheckedInRemovedApiFile android.Path
 AconfigProtoFiles       android.Paths
 CurrentApiTimestamp     android.Path
 EverythingStubsInfo     StubsInfo
 ExportableStubsInfo     StubsInfo
}

var DroidStubsInfoProvider = blueprint.NewProvider[DroidStubsInfo]()

// @auto-generate: gob
type StubsSrcInfo struct {
 EverythingStubsSrcJar android.Path
 ExportableStubsSrcJar android.Path
}

var StubsSrcInfoProvider = blueprint.NewProvider[StubsSrcInfo]()

// Marker provider that indicates this module has files to update on an `m update-api`.
// @auto-generate: gob
type UpdateApiInfo struct {
 Name                 string
 SourceApiFile        android.Path
 GeneratedApiFile     android.Path
 SourceRemovedFile    android.Path
 GeneratedRemovedFile android.Path
}

var UpdateApiProvider = blueprint.NewProvider[UpdateApiInfo]()

// The values allowed for Droidstubs' Api_levels_sdk_type
var allowedApiLevelSdkTypes = []string{"public", "system", "module-lib", "system-server"}

type StubsType int

const (
 Everything StubsType = iota
 Exportable
)

func (s StubsType) String() string {
 switch s {
 case Everything:
  return "everything"
 case Exportable:
  return "exportable"
 default:
  panic("Unsupported StubsType for String")
 }
}

func (s StubsType) OutputTagPrefix() string {
 switch s {
 case Everything:
  return ""
 case Exportable:
  return ".exportable"
 default:
  panic("Unsupported StubsType for OutputTagPrefix")
 }
}

var validStubsType = []StubsType{Everything, Exportable}

func StringToStubsType(s string) (StubsType, error) {
 switch strings.ToLower(s) {
 case Everything.String():
  return Everything, nil
 case Exportable.String():
  return Exportable, nil
 default:
  return Everything, fmt.Errorf("%s is not a valid stubs type, must be one of %s", s, validStubsType)
 }
}

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

func RegisterStubsBuildComponents(ctx android.RegistrationContext) {
 ctx.RegisterModuleType("stubs_defaults", StubsDefaultsFactory)

 ctx.RegisterModuleType("droidstubs", DroidstubsFactory)
 ctx.RegisterModuleType("droidstubs_host", DroidstubsHostFactory)

 ctx.RegisterModuleType("prebuilt_stubs_sources", PrebuiltStubsSourcesFactory)

 ctx.RegisterParallelSingletonType("update_api_singleton", UpdateApiSingletonFactory)
}

type stubsArtifacts struct {
 nullabilityWarningsFile android.WritablePath
 annotationsZip          android.WritablePath
 apiVersionsXml          android.WritablePath
 metadataZip             android.WritablePath
 metadataDir             android.WritablePath
}

// Droidstubs
type Droidstubs struct {
 Javadoc
 embeddableInModuleAndImport

 properties     DroidstubsProperties
 apiFile        android.Path
 removedApiFile android.Path

 checkCurrentApiTimestamp      android.WritablePath
 checkLastReleasedApiTimestamp android.WritablePath
 apiLintTimestamp              android.WritablePath
 apiLintReport                 android.WritablePath

 checkNullabilityWarningsTimestamp android.WritablePath

 everythingArtifacts stubsArtifacts
 exportableArtifacts stubsArtifacts

 exportableApiFile        android.WritablePath
 exportableRemovedApiFile android.WritablePath
}

type DroidstubsProperties struct {
 // The generated public API filename by Metalava, defaults to <module>_api.txt
 Api_filename *string

 // The generated removed API filename by Metalava, defaults to <module>_removed.txt
 Removed_api_filename *string

 Check_api struct {
  Last_released ApiToCheck

  Current ApiToCheck

  Api_lint struct {
   Enabled *bool

   // If set, performs api_lint on any new APIs not found in the given signature file
   New_since *string `android:"path"`

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

 // User can specify the version of previous released API file in order to do compatibility check.
 Previous_api *string `android:"path"`

 // If set to true, Metalava will allow framework SDK to contain annotations.
 Annotations_enabled *bool

 // A list of top-level directories containing files to merge qualifier annotations (i.e. those intended to be included in the stubs written) from.
 Merge_annotations_dirs []string

 // A list of top-level directories containing Java stub files to merge show/hide annotations from.
 Merge_inclusion_annotations_dirs []string

 // A file containing a list of classes to do nullability validation for.
 Validate_nullability_from_list *string

 // A file containing expected warnings produced by validation of nullability annotations.
 Check_nullability_warnings *string

 // If set to true, allow Metalava to generate doc_stubs source files. Defaults to false.
 Create_doc_stubs *bool

 // If set to true, cause Metalava to output Javadoc comments in the stubs source files. Defaults to false.
 // Has no effect if create_doc_stubs: true.
 Output_javadoc_comments *bool

 // If set to false then do not write out stubs. Defaults to true.
 //
 // TODO(b/146727827): Remove capability when we do not need to generate stubs and API separately.
 Generate_stubs *bool

 // If set to true, provides a hint to the build system that this rule uses a lot of memory,
 // which can be used for scheduling purposes
 High_mem *bool

 // If set to true, Metalava will allow framework SDK to contain API levels annotations.
 Api_levels_annotations_enabled *bool

 // Apply the api levels database created by this module rather than generating one in this droidstubs.
 Api_levels_module *string

 // The dirs which Metalava extracts API levels annotations from.
 Api_levels_annotations_dirs []string

 // The sdk kind which Metalava extracts API levels annotations from. Supports 'public', 'system', 'module-lib' and 'system-server'; defaults to public.
 Api_levels_sdk_type *string

 // The filename which Metalava extracts API levels annotations from. Defaults to android.jar.
 Api_levels_jar_filename *string

 // If set to true, collect the values used by the Dev tools and
 // write them in files packaged with the SDK. Defaults to false.
 Write_sdk_values *bool

 // Path or filegroup to file defining extension an SDK name <-> numerical ID mapping and
 // what APIs exist in which SDKs; passed to metalava via --sdk-extensions-info
 Extensions_info_file *string `android:"path"`

 // API surface of this module. If set, the module contributes to an API surface.
 // For the full list of available API surfaces, refer to soong/android/sdk_version.go
 Api_surface *string

 // A list of aconfig_declarations module names that the stubs generated in this module
 // depend on.
 Aconfig_declarations []string

 // List of hard coded filegroups containing Metalava config files that are passed to every
 // Metalava invocation that this module performs. See addMetalavaConfigFilesToCmd.
 ConfigFiles []string `android:"path" blueprint:"mutated"`
}

// Used by xsd_config
type ApiFilePath interface {
 ApiFilePath(StubsType) (android.Path, error)
}

type ApiStubsSrcProvider interface {
 StubsSrcJar(StubsType) (android.Path, error)
}

// Provider of information about API stubs, used by java_sdk_library.
type ApiStubsProvider interface {
 AnnotationsZip(StubsType) (android.Path, error)
 ApiFilePath
 RemovedApiFilePath(StubsType) (android.Path, error)

 ApiStubsSrcProvider
}

type annotationFlagsParams struct {
 migratingNullability    bool
 validatingNullability   bool
 nullabilityWarningsFile android.WritablePath
 annotationsZip          android.WritablePath
}
type stubsCommandParams struct {
 srcJarDir               android.ModuleOutPath
 stubsDir                android.OptionalPath
 stubsSrcJar             android.WritablePath
 metadataZip             android.WritablePath
 metadataDir             android.WritablePath
 apiVersionsXml          android.WritablePath
 nullabilityWarningsFile android.WritablePath
 annotationsZip          android.WritablePath
 stubConfig              stubsCommandConfigParams
}
type stubsCommandConfigParams struct {
 stubsType             StubsType
 javaVersion           javaVersion
 deps                  deps
 checkApi              bool
 generateStubs         bool
 doApiLint             bool
 doCheckReleased       bool
 writeSdkValues        bool
 migratingNullability  bool
 validatingNullability bool
}

// droidstubs passes sources files through Metalava to generate stub .java files that only contain the API to be
// documented, filtering out hidden classes and methods.  The resulting .java files are intended to be passed to
// a droiddoc module to generate documentation.
func DroidstubsFactory() android.Module {
 module := &Droidstubs{}

 module.AddProperties(&module.properties,
  &module.Javadoc.properties)
 module.properties.ConfigFiles = getMetalavaConfigFilegroupReference()
 module.initModuleAndImport(module)

 InitDroiddocModule(module, android.HostAndDeviceSupported)

 module.SetDefaultableHook(func(ctx android.DefaultableHookContext) {
  module.createApiContribution(ctx)
 })
 return module
}

// droidstubs_host passes sources files through Metalava to generate stub .java files that only contain the API
// to be documented, filtering out hidden classes and methods.  The resulting .java files are intended to be
// passed to a droiddoc_host module to generate documentation.  Use a droidstubs_host instead of a droidstubs
// module when symbols needed by the source files are provided by java_library_host modules.
func DroidstubsHostFactory() android.Module {
 module := &Droidstubs{}

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

 module.properties.ConfigFiles = getMetalavaConfigFilegroupReference()
 InitDroiddocModule(module, android.HostSupported)
 return module
}

func (d *Droidstubs) AnnotationsZip(stubsType StubsType) (ret android.Path, err error) {
 switch stubsType {
 case Everything:
  ret, err = d.everythingArtifacts.annotationsZip, nil
 case Exportable:
  ret, err = d.exportableArtifacts.annotationsZip, nil
 default:
  ret, err = nil, fmt.Errorf("annotations zip not supported for the stub type %s", stubsType.String())
 }
 return ret, err
}

func (d *Droidstubs) ApiFilePath(stubsType StubsType) (ret android.Path, err error) {
 switch stubsType {
 case Everything:
  ret, err = d.apiFile, nil
 case Exportable:
  ret, err = d.exportableApiFile, nil
 default:
  ret, err = nil, fmt.Errorf("api file path not supported for the stub type %s", stubsType.String())
 }
 if ret == nil && err == nil {
  err = fmt.Errorf("api file is null for the stub type %s", stubsType.String())
 }
 return ret, err
}

func (d *Droidstubs) ApiVersionsXmlFilePath(stubsType StubsType) (ret android.Path, err error) {
 switch stubsType {
 case Everything:
  ret, err = d.everythingArtifacts.apiVersionsXml, nil
 case Exportable:
  ret, err = d.exportableArtifacts.apiVersionsXml, nil
 default:
  ret, err = nil, fmt.Errorf("api versions xml file path not supported for the stub type %s", stubsType.String())
 }
 if ret == nil && err == nil {
  err = fmt.Errorf("api versions xml file is null for the stub type %s", stubsType.String())
 }
 return ret, err
}

func (d *Droidstubs) DocZip(stubsType StubsType) (ret android.Path, err error) {
 switch stubsType {
 case Everything:
  ret, err = d.docZip, nil
 default:
  ret, err = nil, fmt.Errorf("docs zip not supported for the stub type %s", stubsType.String())
 }
 if ret == nil && err == nil {
  err = fmt.Errorf("docs zip is null for the stub type %s", stubsType.String())
 }
 return ret, err
}

func (d *Droidstubs) MetadataZip(stubsType StubsType) (ret android.Path, err error) {
 switch stubsType {
 case Everything:
  ret, err = d.everythingArtifacts.metadataZip, nil
 case Exportable:
  ret, err = d.exportableArtifacts.metadataZip, nil
 default:
  ret, err = nil, fmt.Errorf("metadata zip not supported for the stub type %s", stubsType.String())
 }
 if ret == nil && err == nil {
  err = fmt.Errorf("metadata zip is null for the stub type %s", stubsType.String())
 }
 return ret, err
}

func (d *Droidstubs) RemovedApiFilePath(stubsType StubsType) (ret android.Path, err error) {
 switch stubsType {
 case Everything:
  ret, err = d.removedApiFile, nil
 case Exportable:
  ret, err = d.exportableRemovedApiFile, nil
 default:
  ret, err = nil, fmt.Errorf("removed api file path not supported for the stub type %s", stubsType.String())
 }
 if ret == nil && err == nil {
  err = fmt.Errorf("removed api file is null for the stub type %s", stubsType.String())
 }
 return ret, err
}

func (d *Droidstubs) StubsSrcJar(stubsType StubsType) (ret android.Path, err error) {
 switch stubsType {
 case Everything:
  ret, err = d.stubsSrcJar, nil
 case Exportable:
  ret, err = d.exportableStubsSrcJar, nil
 default:
  ret, err = nil, fmt.Errorf("stubs srcjar not supported for the stub type %s", stubsType.String())
 }
 if ret == nil && err == nil {
  err = fmt.Errorf("stubs srcjar is null for the stub type %s", stubsType.String())
 }
 return ret, err
}

func (d *Droidstubs) CurrentApiTimestamp() android.Path {
 return d.checkCurrentApiTimestamp
}

var metalavaMergeAnnotationsDirTag = dependencyTag{name: "metalava-merge-annotations-dir"}
var metalavaMergeInclusionAnnotationsDirTag = dependencyTag{name: "metalava-merge-inclusion-annotations-dir"}
var metalavaAPILevelsAnnotationsDirTag = dependencyTag{name: "metalava-api-levels-annotations-dir"}
var metalavaAPILevelsModuleTag = dependencyTag{name: "metalava-api-levels-module-tag"}
var metalavaCurrentApiTimestampTag = dependencyTag{name: "metalava-current-api-timestamp-tag"}

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

 if len(d.properties.Merge_annotations_dirs) != 0 {
  for _, mergeAnnotationsDir := range d.properties.Merge_annotations_dirs {
   ctx.AddDependency(ctx.Module(), metalavaMergeAnnotationsDirTag, mergeAnnotationsDir)
  }
 }

 if len(d.properties.Merge_inclusion_annotations_dirs) != 0 {
  for _, mergeInclusionAnnotationsDir := range d.properties.Merge_inclusion_annotations_dirs {
   ctx.AddDependency(ctx.Module(), metalavaMergeInclusionAnnotationsDirTag, mergeInclusionAnnotationsDir)
  }
 }

 if len(d.properties.Api_levels_annotations_dirs) != 0 {
  for _, apiLevelsAnnotationsDir := range d.properties.Api_levels_annotations_dirs {
   ctx.AddDependency(ctx.Module(), metalavaAPILevelsAnnotationsDirTag, apiLevelsAnnotationsDir)
  }
 }

 if len(d.properties.Aconfig_declarations) != 0 {
  for _, aconfigDeclarationModuleName := range d.properties.Aconfig_declarations {
   ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfigDeclarationModuleName)
  }
 }

 if d.properties.Api_levels_module != nil {
  ctx.AddDependency(ctx.Module(), metalavaAPILevelsModuleTag, proptools.String(d.properties.Api_levels_module))
 }

 d.EmbeddableSdkLibraryComponent.setComponentDependencyInfoProvider(ctx)
}

func (d *Droidstubs) sdkValuesFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, metadataDir android.WritablePath) {
 cmd.FlagWithArg("--sdk-values ", metadataDir.String())
}

func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.OptionalPath, stubsType StubsType, checkApi bool) {

 apiFileName := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt")
 uncheckedApiFile := android.PathForModuleOut(ctx, stubsType.String(), apiFileName)
 cmd.FlagWithOutput("--api ", uncheckedApiFile)
 if checkApi || String(d.properties.Api_filename) != "" {
  if stubsType == Everything {
   d.apiFile = uncheckedApiFile
  } else if stubsType == Exportable {
   d.exportableApiFile = uncheckedApiFile
  }
 } else if sourceApiFile := proptools.String(d.properties.Check_api.Current.Api_file); sourceApiFile != "" {
  if stubsType == Everything {
   // If check api is disabled then make the source file available for export.
   d.apiFile = android.PathForModuleSrc(ctx, sourceApiFile)
  } else if stubsType == Exportable {
   d.exportableApiFile = uncheckedApiFile
  }
 }

 removedApiFileName := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_removed.txt")
 uncheckedRemovedFile := android.PathForModuleOut(ctx, stubsType.String(), removedApiFileName)
 cmd.FlagWithOutput("--removed-api ", uncheckedRemovedFile)
 if checkApi || String(d.properties.Removed_api_filename) != "" {
  if stubsType == Everything {
   d.removedApiFile = uncheckedRemovedFile
  } else if stubsType == Exportable {
   d.exportableRemovedApiFile = uncheckedRemovedFile
  }
 } else if sourceRemovedApiFile := proptools.String(d.properties.Check_api.Current.Removed_api_file); sourceRemovedApiFile != "" {
  if stubsType == Everything {
   // If check api is disabled then make the source removed api file available for export.
   d.removedApiFile = android.PathForModuleSrc(ctx, sourceRemovedApiFile)
  } else if stubsType == Exportable {
   d.exportableRemovedApiFile = uncheckedRemovedFile
  }
 }

 if stubsDir.Valid() {
  if Bool(d.properties.Create_doc_stubs) {
   cmd.FlagWithArg("--doc-stubs ", stubsDir.String())
  } else {
   cmd.FlagWithArg("--stubs ", stubsDir.String())
   if !Bool(d.properties.Output_javadoc_comments) {
    cmd.Flag("--exclude-documentation-from-stubs")
   }
  }
 }
}

func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, params annotationFlagsParams) {
 if Bool(d.properties.Annotations_enabled) {
  cmd.Flag(config.MetalavaAnnotationsFlags)

  if params.migratingNullability {
   previousApiFiles := android.PathsForModuleSrc(ctx, []string{String(d.properties.Previous_api)})
   cmd.FlagForEachInput("--migrate-nullness ", previousApiFiles)
  }

  if s := String(d.properties.Validate_nullability_from_list); s != "" {
   cmd.FlagWithInput("--validate-nullability-from-list ", android.PathForModuleSrc(ctx, s))
  }

  if params.validatingNullability {
   cmd.FlagWithOutput("--nullability-warnings-txt ", params.nullabilityWarningsFile)
  }

  cmd.FlagWithOutput("--extract-annotations ", params.annotationsZip)

  if len(d.properties.Merge_annotations_dirs) != 0 {
   d.mergeAnnoDirFlags(ctx, cmd)
  }

  cmd.Flag(config.MetalavaAnnotationsWarningsFlags)
 }
}

func (d *Droidstubs) mergeAnnoDirFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
 ctx.VisitDirectDepsProxyWithTag(metalavaMergeAnnotationsDirTag, func(m android.ModuleProxy) {
  if t, ok := android.OtherModuleProvider(ctx, m, ExportedDroiddocDirInfoProvider); ok {
   cmd.FlagWithArg("--merge-qualifier-annotations ", t.Dir.String()).Implicits(t.Deps)
  } else {
   ctx.PropertyErrorf("merge_annotations_dirs",
    "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
  }
 })
}

func (d *Droidstubs) inclusionAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
 ctx.VisitDirectDepsProxyWithTag(metalavaMergeInclusionAnnotationsDirTag, func(m android.ModuleProxy) {
  if t, ok := android.OtherModuleProvider(ctx, m, ExportedDroiddocDirInfoProvider); ok {
   cmd.FlagWithArg("--merge-inclusion-annotations ", t.Dir.String()).Implicits(t.Deps)
  } else {
   ctx.PropertyErrorf("merge_inclusion_annotations_dirs",
    "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m))
  }
 })
}

// Magic value that signalas that an api is still in development. Lint
// understands this value and will not emit NewAPi warnings IFF it sees 10000
// AND the FlaggedApi linter is enabled. This value is also used as placeholder
// value when generating documentation. It is first put into the
// api-versions.xml file and then later on when metalava generates the
// documentation it is give a map of sdk values and codenames and it
// creates @apisince tages where the given sdk values are replaced by their
// codename counterparts.
const sdk_development = "10000"

func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsType StubsType, apiVersionsXml android.WritablePath) {
 var apiVersions android.Path
 if proptools.Bool(d.properties.Api_levels_annotations_enabled) {
  d.apiLevelsGenerationFlags(ctx, cmd, stubsType, apiVersionsXml)
  apiVersions = apiVersionsXml
 } else {
  ctx.VisitDirectDepsProxyWithTag(metalavaAPILevelsModuleTag, func(m android.ModuleProxy) {
   if s, ok := android.OtherModuleProvider(ctx, m, DroidStubsInfoProvider); ok {
    if stubsType == Everything {
     apiVersions = s.EverythingStubsInfo.ApiVersionsXml
    } else if stubsType == Exportable {
     apiVersions = s.ExportableStubsInfo.ApiVersionsXml
    } else {
     ctx.ModuleErrorf("%s stubs type does not generate api-versions.xml file", stubsType.String())
    }
   } else {
    ctx.PropertyErrorf("api_levels_module",
     "module %q is not a droidstubs module", ctx.OtherModuleName(m))
   }
  })
 }
 if apiVersions != nil {
  cmd.FlagWithInput("--apply-api-levels ", apiVersions)
  if prospectiveFullSdkVersion := ctx.Config().PlatformProspectiveSdkVersionFull(); prospectiveFullSdkVersion == sdk_development {
   // This tells metalava to replace  <prospectiveFullSdkVersion> with
   // <PlatformSdkCodename> when generating documentation. This is only done
   // if prospectiveFullSdkVersion is set to 10_000 which is the magic
   // constant for non finalized Apis.
   apiVersionLabel := fmt.Sprintf("%s:%s", prospectiveFullSdkVersion, ctx.Config().PlatformSdkCodename())
   cmd.FlagWithArg("--api-version-label ", apiVersionLabel)
  }
 }
}

// AndroidPlusUpdatableJar is the name of some extra jars added into `module-lib` and
// `system-server` directories that contain all the APIs provided by the platform and updatable
// modules because the `android.jar` files do not. See b/337836752.
const AndroidPlusUpdatableJar = "android-plus-updatable.jar"

func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsType StubsType, apiVersionsXml android.WritablePath) {
 if len(d.properties.Api_levels_annotations_dirs) == 0 {
  ctx.PropertyErrorf("api_levels_annotations_dirs",
   "has to be non-empty if api levels annotations was enabled!")
 }

 cmd.FlagWithOutput("--generate-api-levels ", apiVersionsXml)

 // This limits the range of versions that metalava uses when computing the historic api.
 apiVersionRange := fmt.Sprintf("1:%s", ctx.Config().PlatformSdkVersionFull())
 cmd.FlagWithArg("--api-version-range ", apiVersionRange)

 // If prospectiveFullSdkVersion is set, pass it to metalava to let metava know
 // that sources should be included and that they should be consdered this api
 // version. If prospectiveFullSdkVersion is not set metalava will only
 // consider the historic apis when generating api-versions.xml
 if prospectiveFullSdkVersion := ctx.Config().PlatformProspectiveSdkVersionFull(); len(prospectiveFullSdkVersion) > 0 {
  cmd.FlagWithArg("--api-version-for-sources ", prospectiveFullSdkVersion)
 }

 filename := proptools.StringDefault(d.properties.Api_levels_jar_filename, "android.jar")

 // If generating the android API then include android.test.*.jars in the set
 // of files passed to Metalava.
 filenames := []string{filename}
 if filename == "android.jar" {
  filenames = append(
   filenames,
   "android.test.base.jar",
   "android.test.mock.jar",
   "android.test.runner.jar",
  )
 }

 // TODO: Avoid the duplication of API surfaces, reuse apiScope.
 // Add all relevant --android-jar-pattern patterns for Metalava.
 // When parsing a stub jar for a specific version, Metalava picks the first pattern that defines
 // an actual file present on disk (in the order the patterns were passed). For system APIs for
 // privileged apps that are only defined since API level 21 (Lollipop), fallback to public stubs
 // for older releases. Similarly, module-lib falls back to system API.
 var sdkDirs []string
 apiLevelsSdkType := proptools.StringDefault(d.properties.Api_levels_sdk_type, "public")
 switch apiLevelsSdkType {
 case "system-server":
  sdkDirs = []string{"system-server", "module-lib", "system", "public"}
 case "module-lib":
  sdkDirs = []string{"module-lib", "system", "public"}
 case "system":
  sdkDirs = []string{"system", "public"}
 case "public":
  sdkDirs = []string{"public"}
 default:
  ctx.PropertyErrorf("api_levels_sdk_type", "needs to be one of %v", allowedApiLevelSdkTypes)
  return
 }

 // Construct a pattern to match the appropriate extensions that should be included in the
 // generated api-versions.xml file.
 //
 // Use the first item in the sdkDirs array as that is the sdk type for the target API levels
 // being generated but has the advantage over `Api_levels_sdk_type` as it has been validated.
 // The exception is for system-server which needs to include module-lib and system-server. That
 // is because while system-server extends module-lib the system-server extension directory only
 // contains service-* modules which provide system-server APIs it does not list the modules which
 // only provide a module-lib, so they have to be included separately.
 extensionSurfacesPattern := sdkDirs[0]
 if apiLevelsSdkType == "system-server" {
  // Take the first two items in sdkDirs, which are system-server and module-lib, and construct
  // a pattern that will match either.
  extensionSurfacesPattern = strings.Join(sdkDirs[0:2], "|")
 }
 extensionsPattern := fmt.Sprintf(`/extensions/[0-9]+/(%s)/.*\.jar`, extensionSurfacesPattern)

 var dirs []string
 var extensions_dir string
 ctx.VisitDirectDepsProxyWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.ModuleProxy) {
  if t, ok := android.OtherModuleProvider(ctx, m, ExportedDroiddocDirInfoProvider); ok {
   extRegex := regexp.MustCompile(t.Dir.String() + extensionsPattern)

   // Grab the first extensions_dir and we find while scanning ExportedDroiddocDir.deps;
   // ideally this should be read from prebuiltApis.properties.Extensions_*
   for _, dep := range t.Deps {
    // Check to see if it matches an extension first.
    depBase := dep.Base()
    if extRegex.MatchString(dep.String()) && d.properties.Extensions_info_file != nil {
     if extensions_dir == "" {
      extensions_dir = t.Dir.String() + "/extensions"
     }
     cmd.Implicit(dep)
    } else if slices.Contains(filenames, depBase) {
     // Check to see if it matches a dessert release for an SDK, e.g. Android, Car, Wear, etc..
     cmd.Implicit(dep)
    } else if depBase == AndroidPlusUpdatableJar && d.properties.Extensions_info_file != nil {
     // The output api-versions.xml has been requested to include information on SDK
     // extensions, i.e. updatable Apis. That means it also needs to include the history of
     // those updatable APIs. Usually, they would be included in the `android.jar` file but
     // unfortunately, the `module-lib` and `system-server` cannot as it would lead to build
     // cycles. So, the module-lib and system-server directories contain an
     // `android-plus-updatable.jar` that should be used instead of `android.jar`. See
     // AndroidPlusUpdatableJar for more information.
     cmd.Implicit(dep)
    }
   }

   dirs = append(dirs, t.Dir.String())
  } else {
   ctx.PropertyErrorf("api_levels_annotations_dirs",
    "module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m))
  }
 })

 // Generate the list of --android-jar-pattern options. The order matters so the first one which
 // matches will be the one that is used for a specific api level.
 for _, sdkDir := range sdkDirs {
  for _, dir := range dirs {
   addPattern := func(jarFilename string) {
    cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/{version:major.minor?}/%s/%s", dir, sdkDir, jarFilename))
   }

   if sdkDir == "module-lib" || sdkDir == "system-server" {
    // The module-lib and system-server android.jars do not include the updatable modules (as
    // doing so in the source would introduce dependency cycles and the prebuilts have to
    // match the sources). So, instead an additional `android-plus-updatable.jar` will be used
    // that does include the updatable modules and this pattern will match that. This pattern
    // is added in addition to the following pattern to decouple this change from the change
    // to add the `android-plus-updatable.jar`.
    addPattern(AndroidPlusUpdatableJar)
   }

   // Always add the main jar, e.g. android.jar. This will be overridden by
   // android-plus-updatable.jar if a pattern for it was added as that comes
   // first and neither has a library placeholder.
   addPattern(filename)

   // If additional file names were added then they are assumed to be
   // libraries so match them using a {library} placeholder.
   if len(filenames) > 1 {
    addPattern("{library}.jar")
   }
  }

  if extensions_dir != "" {
   cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/{version:extension}/%s/{module}.jar", extensions_dir, sdkDir))
  }
 }

 if d.properties.Extensions_info_file != nil {
  if extensions_dir == "" {
   ctx.ModuleErrorf("extensions_info_file set, but no SDK extension dirs found")
  }
  info_file := android.PathForModuleSrc(ctx, *d.properties.Extensions_info_file)
  cmd.Implicit(info_file)
  cmd.FlagWithArg("--sdk-extensions-info ", info_file.String())
  // Limit the range of which extensions should be included. There are
  // scenarios where a releaseconfiguration need to build without "seeing"
  // the latest extensions.
  sdkExtensionVersionRange := fmt.Sprintf("1:%d", ctx.Config().PlatformSdkExtensionVersion())
  cmd.FlagWithArg("--sdk-extension-version-range ", sdkExtensionVersionRange)
  // Magic constant to use when writing since="XYZ" in api-versions.xml for
  // apis that only exists in an extension.
  cmd.FlagWithArg("--api-version-for-sdk-extension ", sdk_development)
 }
}

func (d *Droidstubs) apiCompatibilityFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsType StubsType) {
 if len(d.Javadoc.properties.Out) > 0 {
  ctx.PropertyErrorf("out", "out property may not be combined with check_api")
 }

 // Disable compatibility checks if required.
 if !BoolDefault(d.properties.Check_api.Last_released.Enabled, true) {
  cmd.Flag("--check-compatibility disabled")
 }

 apiFiles := android.PathsForModuleSrc(ctx, []string{String(d.properties.Check_api.Last_released.Api_file)})
 removedApiFiles := android.PathsForModuleSrc(ctx, []string{String(d.properties.Check_api.Last_released.Removed_api_file)})

 cmd.FlagForEachInput("--check-compatibility:api:released ", apiFiles)
 cmd.FlagForEachInput("--check-compatibility:removed:released ", removedApiFiles)

 baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Last_released.Baseline_file)
 if baselineFile.Valid() {
  cmd.FlagWithInput("--baseline:compatibility:released ", baselineFile.Path())
 }
}

func metalavaUseRewrapper(ctx android.ModuleContext) bool {
 return ctx.Config().UseREWrapper() && ctx.Config().IsEnvTrue("RBE_METALAVA")
}

func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs android.Paths,
 srcJarList android.Path, homeDir android.WritablePath, params stubsCommandConfigParams,
 configFiles android.Paths, apiSurface *string) *android.RuleBuilderCommand {
 rule.Command().Text("rm -rf").Flag(homeDir.String())
 rule.Command().Text("mkdir -p").Flag(homeDir.String())

 cmd := rule.Command()
 cmd.FlagWithArg("ANDROID_PREFS_ROOT=", homeDir.String())
 rule.ToolchainPaths(filepath.Dir(config.JavaCmd(ctx).String()))

 if metalavaUseRewrapper(ctx) {
  rule.Remoteable(android.RemoteRuleSupports{RBE: true})
  execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
  compare := ctx.Config().IsEnvTrue("RBE_METALAVA_COMPARE")
  remoteUpdateCache := !ctx.Config().IsEnvFalse("RBE_METALAVA_REMOTE_UPDATE_CACHE")
  labels := map[string]string{"type": "tool", "name": "metalava"}
  // TODO: metalava pool rejects these jobs
  pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "java16")
  rule.Rewrapper(&remoteexec.REParams{
   Labels:              labels,
   ExecStrategy:        execStrategy,
   ToolchainInputs:     []string{config.JavaCmd(ctx).String()},
   Platform:            map[string]string{remoteexec.PoolKey: pool},
   Compare:             compare,
   NumLocalRuns:        1,
   NumRemoteRuns:       1,
   NoRemoteUpdateCache: !remoteUpdateCache,
  })
 }

 cmd.BuiltTool("metalava").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "metalava.jar")).
  Flag(config.JavacVmFlags).
  Flag(config.MetalavaVmFlags).
  Flag(config.MetalavaAddOpens).
  FlagWithArg("--java-source ", params.javaVersion.String()).
  FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, fmt.Sprintf("%s.metalava.rsp", params.stubsType.String())), srcs).
  FlagWithInput("@", srcJarList)

 // If this is for the host then pass the --jdk-home option to Metalava and
 // make sure the files necessary to access the JDK class files are available.
 if ctx.Host() {
  homeDir := ctx.Config().Getenv("ANDROID_JAVA_HOME")
  cmd.FlagWithArg("--jdk-home ", homeDir)
  cmd.Implicits(ctx.GlobFilesOutsideModuleDir(filepath.Join(homeDir, "**/*"), nil))
 }

 // Metalava does not differentiate between bootclasspath and classpath and has not done so for
 // years, so it is unlikely to change any time soon.
 combinedPaths := append(([]android.Path)(nil), params.deps.bootClasspath.Paths()...)
 combinedPaths = append(combinedPaths, params.deps.classpath.Paths()...)
 if len(combinedPaths) > 0 {
  cmd.FlagWithInputList("--classpath ", combinedPaths, ":")
 }

 cmd.Flag(config.MetalavaFlags)

 providerName := ctx.Config().GetenvWithDefault("SOONG_METALAVA_SOURCE_MODEL_PROVIDER", "psi")
 cmd.FlagWithArg("--source-model-provider ", providerName)

 addMetalavaConfigFilesToCmd(cmd, configFiles)

 addOptionalApiSurfaceToCmd(cmd, apiSurface)

 // Support using @android.annotation.Hide instead of @hide
 cmd.Flag("--hide-annotation").Flag("android.annotation.Hide")

 return cmd
}

// MetalavaConfigFilegroup is the name of the filegroup in build/soong/java/metalava that lists
// the configuration files to pass to Metalava.
const MetalavaConfigFilegroup = "metalava-config-files"

// Get a reference to the MetalavaConfigFilegroup suitable for use in a property.
func getMetalavaConfigFilegroupReference() []string {
 return []string{":" + MetalavaConfigFilegroup}
}

// addMetalavaConfigFilesToCmd adds --config-file options to use the config files list in the
// MetalavaConfigFilegroup filegroup.
func addMetalavaConfigFilesToCmd(cmd *android.RuleBuilderCommand, configFiles android.Paths) {
 cmd.FlagForEachInput("--config-file ", configFiles)
}

// addOptionalApiSurfaceToCmd adds --api-surface option is apiSurface is not `nil`.
func addOptionalApiSurfaceToCmd(cmd *android.RuleBuilderCommand, apiSurface *string) {
 if apiSurface != nil {
  cmd.Flag("--api-surface")
  cmd.Flag(*apiSurface)
 }
}

// Pass aconfig flags to Metalava. Filters the flags in aconfigFlagsPaths for
// the stubsType and then transforms them into a Metalava config file.
//
// If no flags are passed to Metalava then it will assume all flags are kept.
// This is needed for StubsType.Everything which is used to generate the checked
// in signature files and the stub libraries against which the platform is
// built.
//
// Any `*/READ_WRITE` flags that are passed to Metalava will keep the API as the
// API may be available (depending on the state of the flag) at runtime. In that
// case it is the caller's responsibility to check that the flag is enabled. The
// associated `@FlaggedApi` annotations are kept as Android Lint will use them
// to enforce that the caller checks the state of the flag before calling.
func generateMetalavaFlagConfigArgs(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsType StubsType, aconfigFlagsPaths android.Paths) {
 var filterArgs string
 var overrideArgs string
 switch stubsType {
 // No flagged apis specific flags need to be passed to metalava when generating
 // everything stubs
 case Everything:
  overrideArgs = "--override-flag-state=ENABLED --override-flag-permission=READ_WRITE"

 case Exportable:
  // When the build flag RELEASE_EXPORT_RUNTIME_APIS is set to true, apis marked with
  // the flagged apis that have read_write permissions are exposed on top of the enabled
  // and read_only apis. This is to support local override of flag values at runtime.
  if ctx.Config().ReleaseExportRuntimeApis() {
   filterArgs = "--filter='state:ENABLED+permission:READ_ONLY' --filter='permission:READ_WRITE'"
  } else {
   filterArgs = "--filter='state:ENABLED+permission:READ_ONLY'"
  }
 }

 // If aconfigFlagsPaths is empty then it is still important to generate the
 // Metalava flags config file, albeit with an empty set of flags, so that all
 // flagged APIs will be reverted.

 releasedFlagsFile := android.PathForModuleOut(ctx, fmt.Sprintf("released-flags-%s.pb", stubsType.String()))
 metalavaFlagsConfigFile := android.PathForModuleOut(ctx, fmt.Sprintf("flags-config-%s.xml", stubsType.String()))

 ctx.Build(pctx, android.BuildParams{
  Rule:        gatherReleasedFlaggedApisRule,
  Inputs:      aconfigFlagsPaths,
  Output:      releasedFlagsFile,
  Description: fmt.Sprintf("%s gather aconfig flags", stubsType),
  Args: map[string]string{
   "flags_path":  android.JoinPathsWithPrefix(aconfigFlagsPaths, "--cache "),
   "filter_args": filterArgs,
  },
 })

 ctx.Build(pctx, android.BuildParams{
  Rule:        generateMetalavaFlagConfigRule,
  Input:       releasedFlagsFile,
  Output:      metalavaFlagsConfigFile,
  Description: fmt.Sprintf("%s metalava flags config", stubsType),
  Args: map[string]string{
   "args": overrideArgs,
  },
 })

 cmd.FlagWithInput("--config-file ", metalavaFlagsConfigFile)
}

func (d *Droidstubs) commonMetalavaStubCmd(ctx android.ModuleContext, rule *android.RuleBuilder,
 params stubsCommandParams) *android.RuleBuilderCommand {
 if BoolDefault(d.properties.High_mem, false) {
  // This metalava run uses lots of memory, restrict the number of metalava jobs that can run in parallel.
  rule.HighMem()
 }

 if params.stubConfig.generateStubs {
  rule.Command().Text("rm -rf").Text(params.stubsDir.String())
  rule.Command().Text("mkdir -p").Text(params.stubsDir.String())
 }

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

 homeDir := android.PathForModuleOut(ctx, params.stubConfig.stubsType.String(), "home")

 configFiles := android.PathsForModuleSrc(ctx, d.properties.ConfigFiles)

 cmd := metalavaCmd(ctx, rule, d.Javadoc.srcFiles, srcJarList, homeDir, params.stubConfig,
  configFiles, d.properties.Api_surface)
 cmd.Implicits(d.Javadoc.implicits)

 d.stubsFlags(ctx, cmd, params.stubsDir, params.stubConfig.stubsType, params.stubConfig.checkApi)

 if params.stubConfig.writeSdkValues {
  d.sdkValuesFlags(ctx, cmd, params.metadataDir)
 }

 annotationParams := annotationFlagsParams{
  migratingNullability:    params.stubConfig.migratingNullability,
  validatingNullability:   params.stubConfig.validatingNullability,
  nullabilityWarningsFile: params.nullabilityWarningsFile,
  annotationsZip:          params.annotationsZip,
 }

 d.annotationsFlags(ctx, cmd, annotationParams)
 d.inclusionAnnotationsFlags(ctx, cmd)
 d.apiLevelsAnnotationsFlags(ctx, cmd, params.stubConfig.stubsType, params.apiVersionsXml)

 if params.stubConfig.doCheckReleased {
  d.apiCompatibilityFlags(ctx, cmd, params.stubConfig.stubsType)
 }

 d.expandArgs(ctx, cmd)

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

 generateMetalavaFlagConfigArgs(ctx, cmd, params.stubConfig.stubsType, params.stubConfig.deps.aconfigProtoFiles)

 return cmd
}

// Sandbox rule for generating the everything stubs and other artifacts
func (d *Droidstubs) everythingStubCmd(ctx android.ModuleContext, params stubsCommandConfigParams) *android.RuleBuilderCommand {
 srcJarDir := android.PathForModuleOut(ctx, Everything.String(), "srcjars")
 rule := android.NewRuleBuilder(pctx, ctx).SandboxDisabled()
 rule.Sbox(android.PathForModuleOut(ctx, Everything.String()),
  android.PathForModuleOut(ctx, "metalava.sbox.textproto"))

 var stubsDir android.OptionalPath
 if params.generateStubs {
  stubsDir = android.OptionalPathForPath(android.PathForModuleOut(ctx, Everything.String(), "stubsDir"))
  d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, Everything.String(), ctx.ModuleName()+"-"+"stubs.srcjar")
 }

 if params.writeSdkValues {
  d.everythingArtifacts.metadataDir = android.PathForModuleOut(ctx, Everything.String(), "metadata")
  d.everythingArtifacts.metadataZip = android.PathForModuleOut(ctx, Everything.String(), ctx.ModuleName()+"-metadata.zip")
 }

 if Bool(d.properties.Annotations_enabled) {
  if params.validatingNullability {
   d.everythingArtifacts.nullabilityWarningsFile = android.PathForModuleOut(ctx, Everything.String(), ctx.ModuleName()+"_nullability_warnings.txt")
  }
  d.everythingArtifacts.annotationsZip = android.PathForModuleOut(ctx, Everything.String(), ctx.ModuleName()+"_annotations.zip")
 }
 if Bool(d.properties.Api_levels_annotations_enabled) {
  d.everythingArtifacts.apiVersionsXml = android.PathForModuleOut(ctx, Everything.String(), "api-versions.xml")
 }

 commonCmdParams := stubsCommandParams{
  srcJarDir:               srcJarDir,
  stubsDir:                stubsDir,
  stubsSrcJar:             d.Javadoc.stubsSrcJar,
  metadataDir:             d.everythingArtifacts.metadataDir,
  apiVersionsXml:          d.everythingArtifacts.apiVersionsXml,
  nullabilityWarningsFile: d.everythingArtifacts.nullabilityWarningsFile,
  annotationsZip:          d.everythingArtifacts.annotationsZip,
  stubConfig:              params,
 }

 cmd := d.commonMetalavaStubCmd(ctx, rule, commonCmdParams)

 // Add the default Metalava format flags used for producing the signature files that are checked
 // in and the stub files against which Android itself builds.
 cmd.Flag(config.DefaultMetalavaEverythingFormatFlags)

 d.everythingOptionalCmd(ctx, cmd, params.doApiLint, params.doCheckReleased)

 var everythingStubsCmd *android.RuleBuilderCommand

 if params.generateStubs {
  everythingStubsCmd = rule.Command()
  everythingStubsCmd.
   BuiltTool("soong_zip").
   Flag("-write_if_changed").
   Flag("-jar").
   FlagWithOutput("-o ", d.Javadoc.stubsSrcJar).
   FlagWithArg("-C ", stubsDir.String()).
   FlagWithArg("-D ", stubsDir.String())
 }

 if params.writeSdkValues {
  rule.Command().
   BuiltTool("soong_zip").
   Flag("-write_if_changed").
   Flag("-d").
   FlagWithOutput("-o ", d.everythingArtifacts.metadataZip).
   FlagWithArg("-C ", d.everythingArtifacts.metadataDir.String()).
   FlagWithArg("-D ", d.everythingArtifacts.metadataDir.String())
 }

 // TODO: We don't really need two separate API files, but this is a reminiscence of how
 // we used to run metalava separately for API lint and the "last_released" check. Unify them.
 if params.doApiLint {
  rule.Command().Text("touch").Output(d.apiLintTimestamp)
 }
 if params.doCheckReleased {
  rule.Command().Text("touch").Output(d.checkLastReleasedApiTimestamp)
 }

 // TODO(b/183630617): rewrapper doesn't support restat rules
 if !metalavaUseRewrapper(ctx) {
  rule.Restat()
 }

 zipSyncCleanupCmd(rule, srcJarDir)

 rule.Build("metalava", "metalava merged")

 return everythingStubsCmd
}

// Sandbox rule for generating the everything artifacts that are not run by
// default but only run based on the module configurations
func (d *Droidstubs) everythingOptionalCmd(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, doApiLint bool, doCheckReleased bool) {

 // Add API lint options.
 treatDocumentationIssuesAsErrors := false
 if doApiLint {
  var newSince android.Paths
  if d.properties.Check_api.Api_lint.New_since != nil {
   newSince = android.PathsForModuleSrc(ctx, []string{proptools.String(d.properties.Check_api.Api_lint.New_since)})
  }
  cmd.Flag("--api-lint")
  cmd.FlagForEachInput("--api-lint-previous-api ", newSince)
  d.apiLintReport = android.PathForModuleOut(ctx, Everything.String(), "api_lint_report.txt")
  cmd.FlagWithOutput("--report-even-if-suppressed ", d.apiLintReport) // TODO:  Change to ":api-lint"

  // If UnflaggedApi issues have not already been configured then make sure that existing
  // UnflaggedApi issues are reported as warnings but issues in new/changed code are treated as
  // errors by the Build Warnings Aye Aye Analyzer in Gerrit.
  // Once existing issues have been fixed this will be changed to error.
  // TODO(b/362771529): Switch to --error
  if !strings.Contains(cmd.String(), " UnflaggedApi ") {
   cmd.Flag("--error-when-new UnflaggedApi")
  }

  // TODO(b/154317059): Clean up this allowlist by baselining and/or checking in last-released.
  if d.Name() != "android.car-system-stubs-docs" &&
   d.Name() != "android.car-stubs-docs" {
   treatDocumentationIssuesAsErrors = true
   cmd.Flag("--treat-as-error").Flag("warning") // Most lints are actually warnings.
  }

  baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.Baseline_file)
  updatedBaselineOutput := android.PathForModuleOut(ctx, Everything.String(), "api_lint_baseline.txt")
  d.apiLintTimestamp = android.PathForModuleOut(ctx, Everything.String(), "api_lint.timestamp")

  // Note this string includes a special shell quote $' ... ', which decodes the "\n"s.
  //
  // TODO: metalava also has a slightly different message hardcoded. Should we unify this
  // message and metalava's one?
  msg := `$'` + // Enclose with $' ... '
   `************************************************************\n` +
   `Your API changes are triggering API Lint warnings or errors.\n` +
   `\n` +
   `To make the failures go away:\n` +
   `\n` +
   `1. REQUIRED: Read the messages carefully and address them by` +
   `   fixing the API if appropriate.\n` +
   `2. If the failure is a false positive, you can suppress it with:\n` +
   `        @SuppressLint("<id>")\n` +
   `   where the <id> is given in brackets in the error message above.\n`

  if baselineFile.Valid() {
   cmd.FlagWithInput("--baseline:api-lint ", baselineFile.Path())
   cmd.FlagWithOutput("--update-baseline:api-lint ", updatedBaselineOutput)

   msg += fmt.Sprintf(``+
    `3. FOR LSC ONLY: You can update the baseline by executing\n`+
    `   the following command:\n`+
    `       (cd $ANDROID_BUILD_TOP && cp \\\n`+
    `       "%s" \\\n`+
    `       "%s")\n`+
    `   To submit the revised baseline.txt to the main Android\n`+
    `   repository, you will need approval.\n`, updatedBaselineOutput, baselineFile.Path())
  } else {
   msg += fmt.Sprintf(``+
    `3. FOR LSC ONLY: You can add a baseline file of existing lint failures\n`+
    `   to the build rule of %s.\n`, d.Name())
  }
  // Note the message ends with a ' (single quote), to close the $' ... ' .
  msg += `************************************************************\n'`

  cmd.FlagWithArg("--error-message:api-lint ", msg)
 }

 if !treatDocumentationIssuesAsErrors {
  treatDocumentationIssuesAsWarningErrorWhenNew(cmd)
 }

 // Add "check released" options. (Detect incompatible API changes from the last public release)
 if doCheckReleased {
  baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Last_released.Baseline_file)
  d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, Everything.String(), "check_last_released_api.timestamp")
  if baselineFile.Valid() {
   updatedBaselineOutput := android.PathForModuleOut(ctx, Everything.String(), "last_released_baseline.txt")
   cmd.FlagWithOutput("--update-baseline:compatibility:released ", updatedBaselineOutput)
  }
  // Note this string includes quote ($' ... '), which decodes the "\n"s.
  msg := `$'\n******************************\n` +
   `You have tried to change the API from what has been previously released in\n` +
   `an SDK.  Please fix the errors listed above.\n` +
   `******************************\n'`

  cmd.FlagWithArg("--error-message:compatibility:released ", msg)
 }

 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
  // Pass the current API file into metalava so it can use it as the basis for determining how to
  // generate the output signature files (both api and removed).
  currentApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
  cmd.FlagWithInput("--use-same-format-as ", currentApiFile)
 }
}

// HIDDEN_DOCUMENTATION_ISSUES is the set of documentation related issues that should always be
// hidden as they are very noisy and provide little value.
var HIDDEN_DOCUMENTATION_ISSUES = []string{
 "Deprecated",
 "IntDef",
 "Nullable",
}

func treatDocumentationIssuesAsWarningErrorWhenNew(cmd *android.RuleBuilderCommand) {
 // Treat documentation issues as warnings, but error when new.
 cmd.Flag("--error-when-new-category").Flag("Documentation")

 // Hide some documentation issues that generated a lot of noise for little benefit.
 cmd.FlagForEachArg("--hide ", HIDDEN_DOCUMENTATION_ISSUES)
}

// Sandbox rule for generating exportable stubs and other artifacts
func (d *Droidstubs) exportableStubCmd(ctx android.ModuleContext, params stubsCommandConfigParams) {
 optionalCmdParams := stubsCommandParams{
  stubConfig: params,
 }

 if params.generateStubs {
  d.Javadoc.exportableStubsSrcJar = android.PathForModuleOut(ctx, params.stubsType.String(), ctx.ModuleName()+"-"+"stubs.srcjar")
  optionalCmdParams.stubsSrcJar = d.Javadoc.exportableStubsSrcJar
 }

 if params.writeSdkValues {
  d.exportableArtifacts.metadataZip = android.PathForModuleOut(ctx, params.stubsType.String(), ctx.ModuleName()+"-metadata.zip")
  d.exportableArtifacts.metadataDir = android.PathForModuleOut(ctx, params.stubsType.String(), "metadata")
  optionalCmdParams.metadataZip = d.exportableArtifacts.metadataZip
  optionalCmdParams.metadataDir = d.exportableArtifacts.metadataDir
 }

 if Bool(d.properties.Annotations_enabled) {
  if params.validatingNullability {
   d.exportableArtifacts.nullabilityWarningsFile = android.PathForModuleOut(ctx, params.stubsType.String(), ctx.ModuleName()+"_nullability_warnings.txt")
   optionalCmdParams.nullabilityWarningsFile = d.exportableArtifacts.nullabilityWarningsFile
  }
  d.exportableArtifacts.annotationsZip = android.PathForModuleOut(ctx, params.stubsType.String(), ctx.ModuleName()+"_annotations.zip")
  optionalCmdParams.annotationsZip = d.exportableArtifacts.annotationsZip
 }
 if Bool(d.properties.Api_levels_annotations_enabled) {
  d.exportableArtifacts.apiVersionsXml = android.PathForModuleOut(ctx, params.stubsType.String(), "api-versions.xml")
  optionalCmdParams.apiVersionsXml = d.exportableArtifacts.apiVersionsXml
 }

 if params.checkApi || String(d.properties.Api_filename) != "" {
  filename := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt")
  d.exportableApiFile = android.PathForModuleOut(ctx, params.stubsType.String(), filename)
 }

 if params.checkApi || String(d.properties.Removed_api_filename) != "" {
  filename := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_api.txt")
  d.exportableRemovedApiFile = android.PathForModuleOut(ctx, params.stubsType.String(), filename)
 }

 d.optionalStubCmd(ctx, optionalCmdParams)
}

func (d *Droidstubs) optionalStubCmd(ctx android.ModuleContext, params stubsCommandParams) {

 params.srcJarDir = android.PathForModuleOut(ctx, params.stubConfig.stubsType.String(), "srcjars")
 rule := android.NewRuleBuilder(pctx, ctx).SandboxDisabled()
 rule.Sbox(android.PathForModuleOut(ctx, params.stubConfig.stubsType.String()),
  android.PathForModuleOut(ctx, fmt.Sprintf("metalava_%s.sbox.textproto", params.stubConfig.stubsType.String())))

 if params.stubConfig.generateStubs {
  params.stubsDir = android.OptionalPathForPath(android.PathForModuleOut(ctx, params.stubConfig.stubsType.String(), "stubsDir"))
 }

 cmd := d.commonMetalavaStubCmd(ctx, rule, params)

 // Add the Metalava format specifier used for producing the signature files and stubs that are
 // finalized and end up in the Android SDK and mainline module drops.
 formatSpecifier := ctx.Config().GetenvWithDefault(
  "SOONG_SDK_SNAPSHOT_SIGNATURE_FORMAT_SPECIFIER",
  config.DefaultMetalavaExportableFormatSpecifier,
 )
 cmd.FlagWithArg("--format ", formatSpecifier)

 if params.stubConfig.doApiLint {
  // Pass the lint baseline file as an input to resolve the lint errors.
  // The exportable stubs generation does not update the lint baseline file.
  // Lint baseline file update is handled by the everything stubs
  baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.Baseline_file)
  if baselineFile.Valid() {
   cmd.FlagWithInput("--baseline:api-lint ", baselineFile.Path())
  }
 }

 // Treat documentation issues as warnings, but error when new.
 treatDocumentationIssuesAsWarningErrorWhenNew(cmd)

 if params.stubConfig.generateStubs {
  rule.Command().
   BuiltTool("soong_zip").
   Flag("-write_if_changed").
   Flag("-jar").
   FlagWithOutput("-o ", params.stubsSrcJar).
   FlagWithArg("-C ", params.stubsDir.String()).
   FlagWithArg("-D ", params.stubsDir.String())
 }

 if params.stubConfig.writeSdkValues {
  rule.Command().
   BuiltTool("soong_zip").
   Flag("-write_if_changed").
   Flag("-d").
   FlagWithOutput("-o ", params.metadataZip).
   FlagWithArg("-C ", params.metadataDir.String()).
   FlagWithArg("-D ", params.metadataDir.String())
 }

 // TODO(b/183630617): rewrapper doesn't support restat rules
 if !metalavaUseRewrapper(ctx) {
  rule.Restat()
 }

 zipSyncCleanupCmd(rule, params.srcJarDir)

 rule.Build(fmt.Sprintf("metalava_%s", params.stubConfig.stubsType.String()), "metalava merged")
}

func (d *Droidstubs) setPhonyRules(ctx android.ModuleContext) {
 if d.apiFile != nil {
  ctx.Phony(d.Name(), d.apiFile)
  ctx.Phony(fmt.Sprintf("%s.txt", d.Name()), d.apiFile)
 }
 if d.removedApiFile != nil {
  ctx.Phony(d.Name(), d.removedApiFile)
  ctx.Phony(fmt.Sprintf("%s.txt", d.Name()), d.removedApiFile)
 }
 if d.checkCurrentApiTimestamp != nil {
  ctx.Phony(fmt.Sprintf("%s-check-current-api", d.Name()), d.checkCurrentApiTimestamp)
  ctx.Phony("checkapi", d.checkCurrentApiTimestamp)
  if proptools.BoolDefault(d.properties.Check_api.Current.Default_in_droid, false) {
   ctx.Phony("droidcore", d.checkCurrentApiTimestamp)
  }
 }
 if d.checkLastReleasedApiTimestamp != nil {
  ctx.Phony(fmt.Sprintf("%s-check-last-released-api", d.Name()), d.checkLastReleasedApiTimestamp)
 }
 if d.apiLintTimestamp != nil {
  ctx.Phony(fmt.Sprintf("%s-api-lint", d.Name()), d.apiLintTimestamp)
 }
 if d.checkNullabilityWarningsTimestamp != nil {
  ctx.Phony(fmt.Sprintf("%s-check-nullability-warnings", d.Name()), d.checkNullabilityWarningsTimestamp)
 }
}

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

 javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), android.SdkContext(d))
 generateStubs := BoolDefault(d.properties.Generate_stubs, true)

 // Add options for the other optional tasks: API-lint and check-released.
 // We generate separate timestamp files for them.
 doApiLint := BoolDefault(d.properties.Check_api.Api_lint.Enabled, false)
 doCheckReleased := apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released")

 writeSdkValues := Bool(d.properties.Write_sdk_values)

 annotationsEnabled := Bool(d.properties.Annotations_enabled)

 migratingNullability := annotationsEnabled && String(d.properties.Previous_api) != ""
 validatingNullability := annotationsEnabled && (strings.Contains(String(d.Javadoc.properties.Args), "--validate-nullability-from-merged-stubs") ||
  String(d.properties.Validate_nullability_from_list) != "")

 checkApi := apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
  apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released")

 stubCmdParams := stubsCommandConfigParams{
  javaVersion:           javaVersion,
  deps:                  deps,
  checkApi:              checkApi,
  generateStubs:         generateStubs,
  doApiLint:             doApiLint,
  doCheckReleased:       doCheckReleased,
  writeSdkValues:        writeSdkValues,
  migratingNullability:  migratingNullability,
  validatingNullability: validatingNullability,
 }
 stubCmdParams.stubsType = Everything
 // Create default (i.e. "everything" stubs) rule for metalava
 d.everythingStubCmd(ctx, stubCmdParams)

 // The module generates "exportable" (and "runtime" eventually) stubs regardless of whether
 // aconfig_declarations property is defined or not. If the property is not defined, the module simply
 // strips all flagged apis to generate the "exportable" stubs
 stubCmdParams.stubsType = Exportable
 d.exportableStubCmd(ctx, stubCmdParams)

 if String(d.properties.Check_nullability_warnings) != "" {
  if d.everythingArtifacts.nullabilityWarningsFile == nil {
   ctx.PropertyErrorf("check_nullability_warnings",
    "Cannot specify check_nullability_warnings unless validating nullability")
  }

  checkNullabilityWarningsPath := android.PathForModuleSrc(ctx, String(d.properties.Check_nullability_warnings))

  d.checkNullabilityWarningsTimestamp = android.PathForModuleOut(ctx, Everything.String(), "check_nullability_warnings.timestamp")

  msg := fmt.Sprintf(`\n******************************\n`+
   `The warnings encountered during nullability annotation validation did\n`+
   `not match the checked in file of expected warnings. The diffs are shown\n`+
   `above. You have two options:\n`+
   `   1. Resolve the differences by editing the nullability annotations.\n`+
   `   2. Update the file of expected warnings by running:\n`+
   `         cp %s %s\n`+
   `       and submitting the updated file as part of your change.`,
   d.everythingArtifacts.nullabilityWarningsFile, checkNullabilityWarningsPath)

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

  rule.Command().
   Text("(").
   Text("diff").Input(checkNullabilityWarningsPath).Input(d.everythingArtifacts.nullabilityWarningsFile).
   Text("&&").
   Text("touch").Output(d.checkNullabilityWarningsTimestamp).
   Text(") || (").
   Text("echo").Flag("-e").Flag(`"` + msg + `"`).
   Text("; exit 38").
   Text(")")

  rule.Build("nullabilityWarningsCheck", "nullability warnings check")
 }

 var apiFile, removedApiFile android.Path

 if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {

  if len(d.Javadoc.properties.Out) > 0 {
   ctx.PropertyErrorf("out", "out property may not be combined with check_api")
  }

  apiFile = android.PathForModuleSrc(ctx, proptools.String(d.properties.Check_api.Current.Api_file))
  removedApiFile = android.PathForModuleSrc(ctx, proptools.String(d.properties.Check_api.Current.Removed_api_file))
  baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Current.Baseline_file)

  if baselineFile.Valid() {
   ctx.PropertyErrorf("baseline_file", "current API check can't have a baseline file. (module %s)", ctx.ModuleName())
  }

  d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, Everything.String(), "check_current_api.timestamp")

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

  // Diff command line.
  // -F matches the closest "opening" line, such as "package android {"
  // and "  public class Intent {".
  diff := `diff -u -F '{ *$'`

  rule.Command().Text("( true")
  rule.Command().
   Text(diff).
   Input(apiFile).Input(d.apiFile)

  rule.Command().
   Text(diff).
   Input(removedApiFile).Input(d.removedApiFile)

  msg := fmt.Sprintf(`\n******************************\n`+
   `You have tried to change the API from what has been previously approved.\n\n`+
   `To make these errors go away, you have two choices:\n`+
   `   1. You can add '@hide' javadoc comments (and remove @SystemApi/@TestApi/etc)\n`+
   `      to the new methods, etc. shown in the above diff.\n\n`+
   `   2. You can update current.txt and/or removed.txt by executing the following command:\n`+
   `         m %s-update-current-api\n\n`+
   `      To submit the revised current.txt to the main Android repository,\n`+
   `      you will need approval.\n`+
   `If your build failed due to stub validation, you can resolve the errors with\n`+
   `either of the two choices above and try re-building the target.\n`+
   `If the mismatch between the stubs and the current.txt is intended,\n`+
   `you can try re-building the target by executing the following command:\n`+
   `m DISABLE_STUB_VALIDATION=true <your build target>.\n`+
   `Note that DISABLE_STUB_VALIDATION=true does not bypass checkapi.\n`+
   `******************************\n`, ctx.ModuleName())

  cmd := rule.Command().
   Text("touch").Output(d.checkCurrentApiTimestamp).
   Text(") || (").
   Text("echo").Flag("-e").Flag(`"` + msg + `"`).
   Text("; exit 38").
   Text(")")

  if d.apiLintTimestamp != nil {
   cmd.Validation(d.apiLintTimestamp)
  }
  if d.checkLastReleasedApiTimestamp != nil {
   cmd.Validation(d.checkLastReleasedApiTimestamp)
  }
  if d.checkNullabilityWarningsTimestamp != nil {
   cmd.Validation(d.checkNullabilityWarningsTimestamp)
  }
  rule.Build("metalavaCurrentApiCheck", "check current API")

  ctx.CheckbuildFile(d.checkCurrentApiTimestamp)

  android.SetProvider(ctx, UpdateApiProvider, UpdateApiInfo{
   Name:                 d.Name(),
   SourceApiFile:        apiFile,
   GeneratedApiFile:     d.apiFile,
   SourceRemovedFile:    removedApiFile,
   GeneratedRemovedFile: d.removedApiFile,
  })
 }

 droidInfo := DroidStubsInfo{
  AconfigProtoFiles:   deps.aconfigProtoFiles,
  CurrentApiTimestamp: d.CurrentApiTimestamp(),
  EverythingStubsInfo: StubsInfo{},
  ExportableStubsInfo: StubsInfo{},
 }

 if apiFile != nil {
  droidInfo.CheckedInApiFile = apiFile
 }
 if removedApiFile != nil {
  droidInfo.CheckedInRemovedApiFile = removedApiFile
 }

 setDroidInfo(ctx, d, &droidInfo.EverythingStubsInfo, Everything)
 setDroidInfo(ctx, d, &droidInfo.ExportableStubsInfo, Exportable)
 android.SetProvider(ctx, DroidStubsInfoProvider, droidInfo)

 android.SetProvider(ctx, StubsSrcInfoProvider, StubsSrcInfo{
  EverythingStubsSrcJar: d.stubsSrcJar,
  ExportableStubsSrcJar: d.exportableStubsSrcJar,
 })

 d.setOutputFiles(ctx)

 d.setPhonyRules(ctx)

 if d.apiLintTimestamp != nil {
  if d.apiLintReport != nil {
   ctx.DistForGoalsWithFilename(
    []string{fmt.Sprintf("%s-api-lint", d.Name()), "droidcore"},
    d.apiLintReport,
    fmt.Sprintf("apilint/%s-lint-report.txt", d.Name()),
   )
  }
 }
}

func setDroidInfo(ctx android.ModuleContext, d *Droidstubs, info *StubsInfo, typ StubsType) {
 if typ == Everything {
  info.ApiFile = d.apiFile
  info.RemovedApiFile = d.removedApiFile
  info.AnnotationsZip = d.everythingArtifacts.annotationsZip
  info.ApiVersionsXml = d.everythingArtifacts.apiVersionsXml
 } else if typ == Exportable {
  info.ApiFile = d.exportableApiFile
  info.RemovedApiFile = d.exportableRemovedApiFile
  info.AnnotationsZip = d.exportableArtifacts.annotationsZip
  info.ApiVersionsXml = d.exportableArtifacts.apiVersionsXml
 } else {
  ctx.ModuleErrorf("failed to set ApiVersionsXml, stubs type not supported: %d", typ)
 }
}

// This method sets the outputFiles property, which is used to set the
// OutputFilesProvider later.
// Droidstubs' tag supports specifying with the stubs type.
// While supporting the pre-existing tags, it also supports tags with
// the stubs type prefix. Some examples are shown below:
// {.annotations.zip} - pre-existing behavior. Returns the path to the
// annotation zip.
// {.exportable} - Returns the path to the exportable stubs src jar.
// {.exportable.annotations.zip} - Returns the path to the exportable
// annotations zip file.
// {.runtime.api_versions.xml} - Runtime stubs does not generate api versions
// xml file. For unsupported combinations, the default everything output file
// is returned.
func (d *Droidstubs) setOutputFiles(ctx android.ModuleContext) {
 addOutputFilesForStubType := func(tag string, getter func(StubsType) (android.Path, error), stubType StubsType) {
  outputFile, err := getter(stubType)
  if err == nil && outputFile != nil {
   ctx.SetOutputFiles(android.Paths{outputFile}, stubType.OutputTagPrefix()+tag)
  }
 }
 addOutputFiles := func(tag string, getter func(StubsType) (android.Path, error)) {
  addOutputFilesForStubType(tag, getter, Everything)
  addOutputFilesForStubType(tag, getter, Exportable)
 }

 addOutputFiles("", d.StubsSrcJar)
 addOutputFiles(".docs.zip", d.DocZip)
 addOutputFiles(".api.txt", d.ApiFilePath)
 addOutputFiles(android.DefaultDistTag, d.ApiFilePath)
 addOutputFiles(".removed-api.txt", d.RemovedApiFilePath)
 addOutputFiles(".annotations.zip", d.AnnotationsZip)
 addOutputFiles(".api_versions.xml", d.ApiVersionsXmlFilePath)
 addOutputFiles(".metadata.zip", d.MetadataZip)
}

func (d *Droidstubs) createApiContribution(ctx android.DefaultableHookContext) {
 api_file := d.properties.Check_api.Current.Api_file
 api_surface := d.properties.Api_surface

 props := struct {
  Name        *string
  Api_surface *string
  Api_file    *string
  Visibility  []string
 }{}

 props.Name = proptools.StringPtr(d.Name() + ".api.contribution")
 props.Api_surface = api_surface
 props.Api_file = api_file
 props.Visibility = []string{"//visibility:override", "//visibility:public"}

 ctx.CreateModule(ApiContributionFactory, &props)
}

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

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

 android.InitDefaultsModule(module)

 return module
}

var _ android.PrebuiltInterface = (*PrebuiltStubsSources)(nil)

type PrebuiltStubsSourcesProperties struct {
 Srcs []string `android:"path"`

 // Name of the source soong module that gets shadowed by this prebuilt
 // If unspecified, follows the naming convention that the source module of
 // the prebuilt is Name() without "prebuilt_" prefix
 Source_module_name *string

 // Non-nil if this prebuilt stub srcs  module was dynamically created by a java_sdk_library_import
 // The name is the undecorated name of the java_sdk_library as it appears in the blueprint file
 // (without any prebuilt_ prefix)
 Created_by_java_sdk_library_name *string `blueprint:"mutated"`
}

func (j *PrebuiltStubsSources) BaseModuleName() string {
 return proptools.StringDefault(j.properties.Source_module_name, j.ModuleBase.Name())
}

func (j *PrebuiltStubsSources) CreatedByJavaSdkLibraryName() *string {
 return j.properties.Created_by_java_sdk_library_name
}

type PrebuiltStubsSources struct {
 android.ModuleBase
 android.DefaultableModuleBase
 embeddableInModuleAndImport

 prebuilt android.Prebuilt

 properties PrebuiltStubsSourcesProperties

 stubsSrcJar android.Path
}

func (d *PrebuiltStubsSources) StubsSrcJar(_ StubsType) (android.Path, error) {
 return d.stubsSrcJar, nil
}

func (p *PrebuiltStubsSources) DepsMutator(ctx android.BottomUpMutatorContext) {
 p.EmbeddableSdkLibraryComponent.setComponentDependencyInfoProvider(ctx)
}

func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 if len(p.properties.Srcs) != 1 {
  ctx.PropertyErrorf("srcs", "must only specify one directory path or srcjar, contains %d paths", len(p.properties.Srcs))
  return
 }

 src := p.properties.Srcs[0]
 if filepath.Ext(src) == ".srcjar" {
  // This is a srcjar. We can use it directly.
  p.stubsSrcJar = android.PathForModuleSrc(ctx, src)
 } else {
  outPath := android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")

  // This is a directory. Glob the contents just in case the directory does not exist.
  srcGlob := src + "/**/*"
  srcPaths := android.PathsForModuleSrc(ctx, []string{srcGlob})

  // Although PathForModuleSrc can return nil if either the path doesn't exist or
  // the path components are invalid it won't in this case because no components
  // are specified and the module directory must exist in order to get this far.
  srcDir := android.PathForModuleSrc(ctx).(android.SourcePath).Join(ctx, src)

  rule := android.NewRuleBuilder(pctx, ctx).SandboxDisabled()
  rule.Command().
   BuiltTool("soong_zip").
   Flag("-write_if_changed").
   Flag("-jar").
   FlagWithOutput("-o ", outPath).
   FlagWithArg("-C ", srcDir.String()).
   FlagWithRspFileInputList("-r ", outPath.ReplaceExtension(ctx, "rsp"), srcPaths)
  rule.Restat()
  rule.Build("zip src", "Create srcjar from prebuilt source")
  p.stubsSrcJar = outPath
 }

 android.SetProvider(ctx, StubsSrcInfoProvider, StubsSrcInfo{
  EverythingStubsSrcJar: p.stubsSrcJar,
  ExportableStubsSrcJar: p.stubsSrcJar,
 })

 ctx.SetOutputFiles(android.Paths{p.stubsSrcJar}, "")
 // prebuilt droidstubs does not output "exportable" stubs.
 // Output the "everything" stubs srcjar file if the tag is ".exportable".
 ctx.SetOutputFiles(android.Paths{p.stubsSrcJar}, ".exportable")
}

func (p *PrebuiltStubsSources) Prebuilt() *android.Prebuilt {
 return &p.prebuilt
}

func (p *PrebuiltStubsSources) Name() string {
 return p.prebuilt.Name(p.ModuleBase.Name())
}

// prebuilt_stubs_sources imports a set of java source files as if they were
// generated by droidstubs.
//
// By default, a prebuilt_stubs_sources has a single variant that expects a
// set of `.java` files generated by droidstubs.
//
// Specifying `host_supported: true` will produce two variants, one for use as a dependency of device modules and one
// for host modules.
//
// Intended only for use by sdk snapshots.
func PrebuiltStubsSourcesFactory() android.Module {
 module := &PrebuiltStubsSources{}

 module.AddProperties(&module.properties)
 module.initModuleAndImport(module)

 android.InitPrebuiltModule(module, &module.properties.Srcs)
 InitDroiddocModule(module, android.HostAndDeviceSupported)
 return module
}

func UpdateApiSingletonFactory() android.Singleton {
 return &updateApiSingleton{}
}

type updateApiSingleton struct{}

func (u *updateApiSingleton) GenerateBuildActions(ctx android.SingletonContext) {
 updateApiModulesFile := android.PathForOutput(ctx, "update_api.txt")

 // Write an update_api.txt file that has essentially the value of all the UpdateApiInfos.
 // Soong_ui will read this file after the build finishes and copy the generated api files
 // to the source tree, as the source tree is read-only during the build.
 var modulesFileBuilder strings.Builder
 ctx.VisitAllModuleProxies(func(m android.ModuleProxy) {
  if info, ok := android.OtherModuleProvider(ctx, m, UpdateApiProvider); ok {
   ctx.Phony(fmt.Sprintf("%s-update-current-api", info.Name), info.GeneratedApiFile, info.GeneratedRemovedFile, updateApiModulesFile)
   ctx.Phony("update-api", info.GeneratedApiFile, info.GeneratedRemovedFile)
   modulesFileBuilder.WriteString(info.Name)
   modulesFileBuilder.WriteString("\n")
   modulesFileBuilder.WriteString(info.GeneratedApiFile.String())
   modulesFileBuilder.WriteString("\n")
   modulesFileBuilder.WriteString(info.SourceApiFile.String())
   modulesFileBuilder.WriteString("\n")
   modulesFileBuilder.WriteString(info.GeneratedRemovedFile.String())
   modulesFileBuilder.WriteString("\n")
   modulesFileBuilder.WriteString(info.SourceRemovedFile.String())
   modulesFileBuilder.WriteString("\n")
  }
 })

 android.WriteFileRuleVerbatim(ctx, updateApiModulesFile, modulesFileBuilder.String())
 ctx.Phony("update-api", updateApiModulesFile)
}

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

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik