Merge changes I3323d993,I01cea895 into main am: 349ef87505
am: 2c5f3c7fc1
Original change: https://android-review.googlesource.com/c/platform/build/soong/+/2876754 Change-Id: Ib096242d10e90818fcf1e37e17ac98190a9922c2 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -15,6 +15,7 @@
|
|||||||
package android
|
package android
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/google/blueprint"
|
"github.com/google/blueprint"
|
||||||
@@ -146,10 +147,16 @@ type RequiresFilesFromPrebuiltApexTag interface {
|
|||||||
|
|
||||||
// FindDeapexerProviderForModule searches through the direct dependencies of the current context
|
// FindDeapexerProviderForModule searches through the direct dependencies of the current context
|
||||||
// module for a DeapexerTag dependency and returns its DeapexerInfo. If a single nonambiguous
|
// module for a DeapexerTag dependency and returns its DeapexerInfo. If a single nonambiguous
|
||||||
// deapexer module isn't found then errors are reported with ctx.ModuleErrorf and nil is returned.
|
// deapexer module isn't found then it returns it an error
|
||||||
func FindDeapexerProviderForModule(ctx ModuleContext) *DeapexerInfo {
|
// clients should check the value of error and call ctx.ModuleErrof if a non nil error is received
|
||||||
|
func FindDeapexerProviderForModule(ctx ModuleContext) (*DeapexerInfo, error) {
|
||||||
var di *DeapexerInfo
|
var di *DeapexerInfo
|
||||||
|
var err error
|
||||||
ctx.VisitDirectDepsWithTag(DeapexerTag, func(m Module) {
|
ctx.VisitDirectDepsWithTag(DeapexerTag, func(m Module) {
|
||||||
|
if err != nil {
|
||||||
|
// An err has been found. Do not visit further.
|
||||||
|
return
|
||||||
|
}
|
||||||
c, _ := OtherModuleProvider(ctx, m, DeapexerProvider)
|
c, _ := OtherModuleProvider(ctx, m, DeapexerProvider)
|
||||||
p := &c
|
p := &c
|
||||||
if di != nil {
|
if di != nil {
|
||||||
@@ -159,17 +166,18 @@ func FindDeapexerProviderForModule(ctx ModuleContext) *DeapexerInfo {
|
|||||||
di = selected
|
di = selected
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.ModuleErrorf("Multiple installable prebuilt APEXes provide ambiguous deapexers: %s and %s",
|
err = fmt.Errorf("Multiple installable prebuilt APEXes provide ambiguous deapexers: %s and %s", di.ApexModuleName(), p.ApexModuleName())
|
||||||
di.ApexModuleName(), p.ApexModuleName())
|
|
||||||
}
|
}
|
||||||
di = p
|
di = p
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if di != nil {
|
if di != nil {
|
||||||
return di
|
return di, nil
|
||||||
}
|
}
|
||||||
ai, _ := ModuleProvider(ctx, ApexInfoProvider)
|
ai, _ := ModuleProvider(ctx, ApexInfoProvider)
|
||||||
ctx.ModuleErrorf("No prebuilt APEX provides a deapexer module for APEX variant %s", ai.ApexVariationName)
|
return nil, fmt.Errorf("No prebuilt APEX provides a deapexer module for APEX variant %s", ai.ApexVariationName)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// removeCompressedApexSuffix removes the _compressed suffix from the name if present.
|
// removeCompressedApexSuffix removes the _compressed suffix from the name if present.
|
||||||
|
@@ -3725,7 +3725,7 @@ func ensureExactContents(t *testing.T, ctx *android.TestContext, moduleName, var
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ensureExactDeapexedContents(t *testing.T, ctx *android.TestContext, moduleName string, variant string, files []string) {
|
func ensureExactDeapexedContents(t *testing.T, ctx *android.TestContext, moduleName string, variant string, files []string) {
|
||||||
deapexer := ctx.ModuleForTests(moduleName+".deapexer", variant).Rule("deapexer")
|
deapexer := ctx.ModuleForTests(moduleName+".deapexer", variant).Description("deapex")
|
||||||
outputs := make([]string, 0, len(deapexer.ImplicitOutputs)+1)
|
outputs := make([]string, 0, len(deapexer.ImplicitOutputs)+1)
|
||||||
if deapexer.Output != nil {
|
if deapexer.Output != nil {
|
||||||
outputs = append(outputs, deapexer.Output.String())
|
outputs = append(outputs, deapexer.Output.String())
|
||||||
@@ -8432,6 +8432,13 @@ func TestDuplicateDeapexersFromPrebuiltApexes(t *testing.T) {
|
|||||||
prebuilt_bootclasspath_fragment {
|
prebuilt_bootclasspath_fragment {
|
||||||
name: "my-bootclasspath-fragment",
|
name: "my-bootclasspath-fragment",
|
||||||
apex_available: ["com.android.myapex"],
|
apex_available: ["com.android.myapex"],
|
||||||
|
hidden_api: {
|
||||||
|
annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
|
||||||
|
metadata: "my-bootclasspath-fragment/metadata.csv",
|
||||||
|
index: "my-bootclasspath-fragment/index.csv",
|
||||||
|
stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
|
||||||
|
all_flags: "my-bootclasspath-fragment/all-flags.csv",
|
||||||
|
},
|
||||||
%s
|
%s
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
@@ -8453,6 +8460,7 @@ func TestDuplicateDeapexersFromPrebuiltApexes(t *testing.T) {
|
|||||||
public: {
|
public: {
|
||||||
jars: ["libbar.jar"],
|
jars: ["libbar.jar"],
|
||||||
},
|
},
|
||||||
|
shared_library: false,
|
||||||
apex_available: ["com.android.myapex"],
|
apex_available: ["com.android.myapex"],
|
||||||
}
|
}
|
||||||
`)
|
`)
|
||||||
@@ -8468,6 +8476,7 @@ func TestDuplicateDeapexersFromPrebuiltApexes(t *testing.T) {
|
|||||||
public: {
|
public: {
|
||||||
jars: ["libbar.jar"],
|
jars: ["libbar.jar"],
|
||||||
},
|
},
|
||||||
|
shared_library: false,
|
||||||
apex_available: ["com.android.myapex"],
|
apex_available: ["com.android.myapex"],
|
||||||
}
|
}
|
||||||
`)
|
`)
|
||||||
|
@@ -530,6 +530,8 @@ func TestBootclasspathFragmentInPrebuiltArtApex(t *testing.T) {
|
|||||||
|
|
||||||
java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{
|
java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{
|
||||||
`com.android.art.apex.selector`,
|
`com.android.art.apex.selector`,
|
||||||
|
`com.android.art.deapexer`,
|
||||||
|
`dex2oatd`,
|
||||||
`prebuilt_art-bootclasspath-fragment`,
|
`prebuilt_art-bootclasspath-fragment`,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@@ -22,6 +22,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"android/soong/android"
|
"android/soong/android"
|
||||||
|
"android/soong/dexpreopt"
|
||||||
"android/soong/java"
|
"android/soong/java"
|
||||||
"android/soong/provenance"
|
"android/soong/provenance"
|
||||||
|
|
||||||
@@ -50,6 +51,7 @@ type prebuilt interface {
|
|||||||
|
|
||||||
type prebuiltCommon struct {
|
type prebuiltCommon struct {
|
||||||
android.ModuleBase
|
android.ModuleBase
|
||||||
|
java.Dexpreopter
|
||||||
prebuilt android.Prebuilt
|
prebuilt android.Prebuilt
|
||||||
|
|
||||||
// Properties common to both prebuilt_apex and apex_set.
|
// Properties common to both prebuilt_apex and apex_set.
|
||||||
@@ -170,50 +172,42 @@ func (p *prebuiltCommon) installable() bool {
|
|||||||
return proptools.BoolDefault(p.prebuiltCommonProperties.Installable, true)
|
return proptools.BoolDefault(p.prebuiltCommonProperties.Installable, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// initApexFilesForAndroidMk initializes the prebuiltCommon.apexFilesForAndroidMk field from the
|
// To satisfy java.DexpreopterInterface
|
||||||
// modules that this depends upon.
|
func (p *prebuiltCommon) IsInstallable() bool {
|
||||||
|
return p.installable()
|
||||||
|
}
|
||||||
|
|
||||||
|
// initApexFilesForAndroidMk initializes the prebuiltCommon.requiredModuleNames field with the install only deps of the prebuilt apex
|
||||||
func (p *prebuiltCommon) initApexFilesForAndroidMk(ctx android.ModuleContext) {
|
func (p *prebuiltCommon) initApexFilesForAndroidMk(ctx android.ModuleContext) {
|
||||||
// Walk the dependencies of this module looking for the java modules that it exports.
|
// If this apex contains a system server jar, then the dexpreopt artifacts should be added as required
|
||||||
ctx.WalkDeps(func(child, parent android.Module) bool {
|
for _, install := range p.Dexpreopter.DexpreoptBuiltInstalledForApex() {
|
||||||
tag := ctx.OtherModuleDependencyTag(child)
|
p.requiredModuleNames = append(p.requiredModuleNames, install.FullModuleName())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
name := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(child))
|
// If this prebuilt has system server jar, create the rules to dexpreopt it and install it alongside the prebuilt apex
|
||||||
if java.IsBootclasspathFragmentContentDepTag(tag) ||
|
func (p *prebuiltCommon) dexpreoptSystemServerJars(ctx android.ModuleContext) {
|
||||||
java.IsSystemServerClasspathFragmentContentDepTag(tag) || tag == exportedJavaLibTag {
|
// If this apex does not export anything, return
|
||||||
// If the exported java module provides a dex jar path then add it to the list of apexFiles.
|
if !p.hasExportedDeps() {
|
||||||
path := child.(interface {
|
return
|
||||||
DexJarBuildPath() java.OptionalDexJarPath
|
}
|
||||||
}).DexJarBuildPath()
|
// Use apex_name to determine the api domain of this prebuilt apex
|
||||||
if path.IsSet() {
|
apexName := p.ApexVariationName()
|
||||||
af := apexFile{
|
di, err := android.FindDeapexerProviderForModule(ctx)
|
||||||
module: child,
|
if err != nil {
|
||||||
moduleDir: ctx.OtherModuleDir(child),
|
ctx.ModuleErrorf(err.Error())
|
||||||
androidMkModuleName: name,
|
}
|
||||||
builtFile: path.Path(),
|
dc := dexpreopt.GetGlobalConfig(ctx)
|
||||||
class: javaSharedLib,
|
systemServerJarList := dc.AllApexSystemServerJars(ctx)
|
||||||
}
|
|
||||||
if module, ok := child.(java.DexpreopterInterface); ok {
|
for i := 0; i < systemServerJarList.Len(); i++ {
|
||||||
for _, install := range module.DexpreoptBuiltInstalledForApex() {
|
sscpApex := systemServerJarList.Apex(i)
|
||||||
af.requiredModuleNames = append(af.requiredModuleNames, install.FullModuleName())
|
sscpJar := systemServerJarList.Jar(i)
|
||||||
}
|
if apexName != sscpApex {
|
||||||
}
|
continue
|
||||||
p.apexFilesForAndroidMk = append(p.apexFilesForAndroidMk, af)
|
|
||||||
}
|
|
||||||
} else if tag == exportedBootclasspathFragmentTag {
|
|
||||||
_, ok := child.(*java.PrebuiltBootclasspathFragmentModule)
|
|
||||||
if !ok {
|
|
||||||
ctx.PropertyErrorf("exported_bootclasspath_fragments", "%q is not a prebuilt_bootclasspath_fragment module", name)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// Visit the children of the bootclasspath_fragment.
|
|
||||||
return true
|
|
||||||
} else if tag == exportedSystemserverclasspathFragmentTag {
|
|
||||||
// Visit the children of the systemserver_fragment.
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
p.Dexpreopter.DexpreoptPrebuiltApexSystemServerJars(ctx, sscpJar, di)
|
||||||
return false
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *prebuiltCommon) addRequiredModules(entries *android.AndroidMkEntries) {
|
func (p *prebuiltCommon) addRequiredModules(entries *android.AndroidMkEntries) {
|
||||||
@@ -248,6 +242,11 @@ func (p *prebuiltCommon) AndroidMkEntries() []android.AndroidMkEntries {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add the dexpreopt artifacts to androidmk
|
||||||
|
for _, install := range p.Dexpreopter.DexpreoptBuiltInstalledForApex() {
|
||||||
|
entriesList = append(entriesList, install.ToMakeEntries())
|
||||||
|
}
|
||||||
|
|
||||||
// Iterate over the apexFilesForAndroidMk list and create an AndroidMkEntries struct for each
|
// Iterate over the apexFilesForAndroidMk list and create an AndroidMkEntries struct for each
|
||||||
// file. This provides similar behavior to that provided in apexBundle.AndroidMk() as it makes the
|
// file. This provides similar behavior to that provided in apexBundle.AndroidMk() as it makes the
|
||||||
// apex specific variants of the exported java modules available for use from within make.
|
// apex specific variants of the exported java modules available for use from within make.
|
||||||
@@ -756,6 +755,14 @@ func (p *Prebuilt) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
|
|||||||
p.prebuiltApexContentsDeps(ctx)
|
p.prebuiltApexContentsDeps(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *prebuiltCommon) DepsMutator(ctx android.BottomUpMutatorContext) {
|
||||||
|
if p.hasExportedDeps() {
|
||||||
|
// Create a dependency from the prebuilt apex (prebuilt_apex/apex_set) to the internal deapexer module
|
||||||
|
// The deapexer will return a provider that will be bubbled up to the rdeps of apexes (e.g. dex_bootjars)
|
||||||
|
ctx.AddDependency(ctx.Module(), android.DeapexerTag, deapexerModuleName(p.BaseModuleName()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var _ ApexInfoMutator = (*Prebuilt)(nil)
|
var _ ApexInfoMutator = (*Prebuilt)(nil)
|
||||||
|
|
||||||
func (p *Prebuilt) ApexInfoMutator(mctx android.TopDownMutatorContext) {
|
func (p *Prebuilt) ApexInfoMutator(mctx android.TopDownMutatorContext) {
|
||||||
@@ -783,6 +790,9 @@ func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dexpreopt any system server jars if present
|
||||||
|
p.dexpreoptSystemServerJars(ctx)
|
||||||
|
|
||||||
// Save the files that need to be made available to Make.
|
// Save the files that need to be made available to Make.
|
||||||
p.initApexFilesForAndroidMk(ctx)
|
p.initApexFilesForAndroidMk(ctx)
|
||||||
|
|
||||||
@@ -999,6 +1009,9 @@ func (a *ApexSet) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dexpreopt any system server jars if present
|
||||||
|
a.dexpreoptSystemServerJars(ctx)
|
||||||
|
|
||||||
// Save the files that need to be made available to Make.
|
// Save the files that need to be made available to Make.
|
||||||
a.initApexFilesForAndroidMk(ctx)
|
a.initApexFilesForAndroidMk(ctx)
|
||||||
|
|
||||||
|
@@ -272,7 +272,9 @@ func TestPrebuiltSystemserverclasspathFragmentContents(t *testing.T) {
|
|||||||
ctx := result.TestContext
|
ctx := result.TestContext
|
||||||
|
|
||||||
java.CheckModuleDependencies(t, ctx, "myapex", "android_common_myapex", []string{
|
java.CheckModuleDependencies(t, ctx, "myapex", "android_common_myapex", []string{
|
||||||
|
`dex2oatd`,
|
||||||
`myapex.apex.selector`,
|
`myapex.apex.selector`,
|
||||||
|
`myapex.deapexer`,
|
||||||
`prebuilt_mysystemserverclasspathfragment`,
|
`prebuilt_mysystemserverclasspathfragment`,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@@ -207,11 +207,7 @@ func (j *TestHelperLibrary) AndroidMkEntries() []android.AndroidMkEntries {
|
|||||||
|
|
||||||
func (prebuilt *Import) AndroidMkEntries() []android.AndroidMkEntries {
|
func (prebuilt *Import) AndroidMkEntries() []android.AndroidMkEntries {
|
||||||
if prebuilt.hideApexVariantFromMake {
|
if prebuilt.hideApexVariantFromMake {
|
||||||
// For a library imported from a prebuilt APEX, we don't need a Make module for itself, as we
|
return []android.AndroidMkEntries{}
|
||||||
// don't need to install it. However, we need to add its dexpreopt outputs as sub-modules, if it
|
|
||||||
// is preopted.
|
|
||||||
dexpreoptEntries := prebuilt.dexpreopter.AndroidMkEntriesForApex()
|
|
||||||
return append(dexpreoptEntries, android.AndroidMkEntries{Disabled: true})
|
|
||||||
}
|
}
|
||||||
return []android.AndroidMkEntries{android.AndroidMkEntries{
|
return []android.AndroidMkEntries{android.AndroidMkEntries{
|
||||||
Class: "JAVA_LIBRARIES",
|
Class: "JAVA_LIBRARIES",
|
||||||
|
@@ -40,8 +40,8 @@ func TestAndroidAppImport(t *testing.T) {
|
|||||||
variant := ctx.ModuleForTests("foo", "android_common")
|
variant := ctx.ModuleForTests("foo", "android_common")
|
||||||
|
|
||||||
// Check dexpreopt outputs.
|
// Check dexpreopt outputs.
|
||||||
if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule == nil ||
|
if variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.vdex").Rule == nil ||
|
||||||
variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule == nil {
|
variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.odex").Rule == nil {
|
||||||
t.Errorf("can't find dexpreopt outputs")
|
t.Errorf("can't find dexpreopt outputs")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,8 +74,8 @@ func TestAndroidAppImport_NoDexPreopt(t *testing.T) {
|
|||||||
variant := ctx.ModuleForTests("foo", "android_common")
|
variant := ctx.ModuleForTests("foo", "android_common")
|
||||||
|
|
||||||
// Check dexpreopt outputs. They shouldn't exist.
|
// Check dexpreopt outputs. They shouldn't exist.
|
||||||
if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule != nil ||
|
if variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.vdex").Rule != nil ||
|
||||||
variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule != nil {
|
variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.odex").Rule != nil {
|
||||||
t.Errorf("dexpreopt shouldn't have run.")
|
t.Errorf("dexpreopt shouldn't have run.")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,8 +101,8 @@ func TestAndroidAppImport_Presigned(t *testing.T) {
|
|||||||
variant := ctx.ModuleForTests("foo", "android_common")
|
variant := ctx.ModuleForTests("foo", "android_common")
|
||||||
|
|
||||||
// Check dexpreopt outputs.
|
// Check dexpreopt outputs.
|
||||||
if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule == nil ||
|
if variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.vdex").Rule == nil ||
|
||||||
variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule == nil {
|
variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.odex").Rule == nil {
|
||||||
t.Errorf("can't find dexpreopt outputs")
|
t.Errorf("can't find dexpreopt outputs")
|
||||||
}
|
}
|
||||||
// Make sure signing was skipped and aligning was done.
|
// Make sure signing was skipped and aligning was done.
|
||||||
@@ -210,8 +210,8 @@ func TestAndroidAppImport_DefaultDevCert(t *testing.T) {
|
|||||||
variant := ctx.ModuleForTests("foo", "android_common")
|
variant := ctx.ModuleForTests("foo", "android_common")
|
||||||
|
|
||||||
// Check dexpreopt outputs.
|
// Check dexpreopt outputs.
|
||||||
if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule == nil ||
|
if variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.vdex").Rule == nil ||
|
||||||
variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule == nil {
|
variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.odex").Rule == nil {
|
||||||
t.Errorf("can't find dexpreopt outputs")
|
t.Errorf("can't find dexpreopt outputs")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3357,7 +3357,7 @@ func TestUsesLibraries(t *testing.T) {
|
|||||||
cmd := app.Rule("dexpreopt").RuleParams.Command
|
cmd := app.Rule("dexpreopt").RuleParams.Command
|
||||||
android.AssertStringDoesContain(t, "dexpreopt app cmd context", cmd, "--context-json=")
|
android.AssertStringDoesContain(t, "dexpreopt app cmd context", cmd, "--context-json=")
|
||||||
android.AssertStringDoesContain(t, "dexpreopt app cmd product_packages", cmd,
|
android.AssertStringDoesContain(t, "dexpreopt app cmd product_packages", cmd,
|
||||||
"--product-packages=out/soong/.intermediates/app/android_common/dexpreopt/product_packages.txt")
|
"--product-packages=out/soong/.intermediates/app/android_common/dexpreopt/app/product_packages.txt")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDexpreoptBcp(t *testing.T) {
|
func TestDexpreoptBcp(t *testing.T) {
|
||||||
|
@@ -240,7 +240,8 @@ type BootclasspathFragmentModule struct {
|
|||||||
sourceOnlyProperties SourceOnlyBootclasspathProperties
|
sourceOnlyProperties SourceOnlyBootclasspathProperties
|
||||||
|
|
||||||
// Path to the boot image profile.
|
// Path to the boot image profile.
|
||||||
profilePath android.WritablePath
|
profilePath android.WritablePath
|
||||||
|
profilePathErr error
|
||||||
}
|
}
|
||||||
|
|
||||||
// commonBootclasspathFragment defines the methods that are implemented by both source and prebuilt
|
// commonBootclasspathFragment defines the methods that are implemented by both source and prebuilt
|
||||||
@@ -1065,8 +1066,11 @@ func (module *PrebuiltBootclasspathFragmentModule) produceBootImageProfile(ctx a
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
di := android.FindDeapexerProviderForModule(ctx)
|
di, err := android.FindDeapexerProviderForModule(ctx)
|
||||||
if di == nil {
|
if err != nil {
|
||||||
|
// An error was found, possibly due to multiple apexes in the tree that export this library
|
||||||
|
// Defer the error till a client tries to call getProfilePath
|
||||||
|
module.profilePathErr = err
|
||||||
return nil // An error has been reported by FindDeapexerProviderForModule.
|
return nil // An error has been reported by FindDeapexerProviderForModule.
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1074,6 +1078,9 @@ func (module *PrebuiltBootclasspathFragmentModule) produceBootImageProfile(ctx a
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *PrebuiltBootclasspathFragmentModule) getProfilePath() android.Path {
|
func (b *PrebuiltBootclasspathFragmentModule) getProfilePath() android.Path {
|
||||||
|
if b.profilePathErr != nil {
|
||||||
|
panic(b.profilePathErr.Error())
|
||||||
|
}
|
||||||
return b.profilePath
|
return b.profilePath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -79,18 +79,25 @@ func (install *dexpreopterInstall) SubModuleName() string {
|
|||||||
func (install dexpreopterInstall) ToMakeEntries() android.AndroidMkEntries {
|
func (install dexpreopterInstall) ToMakeEntries() android.AndroidMkEntries {
|
||||||
return android.AndroidMkEntries{
|
return android.AndroidMkEntries{
|
||||||
Class: "ETC",
|
Class: "ETC",
|
||||||
SubName: install.SubModuleName(),
|
|
||||||
OutputFile: android.OptionalPathForPath(install.outputPathOnHost),
|
OutputFile: android.OptionalPathForPath(install.outputPathOnHost),
|
||||||
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
|
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
|
||||||
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
|
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
|
||||||
|
entries.SetString("LOCAL_MODULE", install.FullModuleName())
|
||||||
entries.SetString("LOCAL_MODULE_PATH", install.installDirOnDevice.String())
|
entries.SetString("LOCAL_MODULE_PATH", install.installDirOnDevice.String())
|
||||||
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", install.installFileOnDevice)
|
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", install.installFileOnDevice)
|
||||||
entries.SetString("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", "false")
|
entries.SetString("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", "false")
|
||||||
|
// Unset LOCAL_SOONG_INSTALLED_MODULE so that this does not default to the primary .apex file
|
||||||
|
// Without this, installation of the dexpreopt artifacts get skipped
|
||||||
|
entries.SetString("LOCAL_SOONG_INSTALLED_MODULE", "")
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Dexpreopter struct {
|
||||||
|
dexpreopter
|
||||||
|
}
|
||||||
|
|
||||||
type dexpreopter struct {
|
type dexpreopter struct {
|
||||||
dexpreoptProperties DexpreoptProperties
|
dexpreoptProperties DexpreoptProperties
|
||||||
importDexpreoptProperties ImportDexpreoptProperties
|
importDexpreoptProperties ImportDexpreoptProperties
|
||||||
@@ -258,6 +265,17 @@ func (d *dexpreopter) getInstallPath(
|
|||||||
return defaultInstallPath
|
return defaultInstallPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DexpreoptPrebuiltApexSystemServerJars generates the dexpreopt artifacts from a jar file that has been deapexed from a prebuilt apex
|
||||||
|
func (d *Dexpreopter) DexpreoptPrebuiltApexSystemServerJars(ctx android.ModuleContext, libraryName string, di *android.DeapexerInfo) {
|
||||||
|
// A single prebuilt apex can have multiple apex system jars
|
||||||
|
// initialize the output path for this dex jar
|
||||||
|
dc := dexpreopt.GetGlobalConfig(ctx)
|
||||||
|
d.installPath = android.PathForModuleInPartitionInstall(ctx, "", strings.TrimPrefix(dexpreopt.GetSystemServerDexLocation(ctx, dc, libraryName), "/"))
|
||||||
|
// generate the rules for creating the .odex and .vdex files for this system server jar
|
||||||
|
dexJarFile := di.PrebuiltExportPath(apexRootRelativePathToJavaLib(libraryName))
|
||||||
|
d.dexpreopt(ctx, dexJarFile)
|
||||||
|
}
|
||||||
|
|
||||||
func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.WritablePath) {
|
func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.WritablePath) {
|
||||||
global := dexpreopt.GetGlobalConfig(ctx)
|
global := dexpreopt.GetGlobalConfig(ctx)
|
||||||
|
|
||||||
@@ -346,11 +364,15 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr
|
|||||||
|
|
||||||
d.dexpreoptProperties.Dex_preopt_result.Profile_guided = profileClassListing.Valid()
|
d.dexpreoptProperties.Dex_preopt_result.Profile_guided = profileClassListing.Valid()
|
||||||
|
|
||||||
|
// A single apex can have multiple system server jars
|
||||||
|
// Use the dexJar to create a unique scope for each
|
||||||
|
dexJarStem := strings.TrimSuffix(dexJarFile.Base(), dexJarFile.Ext())
|
||||||
|
|
||||||
// Full dexpreopt config, used to create dexpreopt build rules.
|
// Full dexpreopt config, used to create dexpreopt build rules.
|
||||||
dexpreoptConfig := &dexpreopt.ModuleConfig{
|
dexpreoptConfig := &dexpreopt.ModuleConfig{
|
||||||
Name: moduleName(ctx),
|
Name: moduleName(ctx),
|
||||||
DexLocation: dexLocation,
|
DexLocation: dexLocation,
|
||||||
BuildPath: android.PathForModuleOut(ctx, "dexpreopt", moduleName(ctx)+".jar").OutputPath,
|
BuildPath: android.PathForModuleOut(ctx, "dexpreopt", dexJarStem, moduleName(ctx)+".jar").OutputPath,
|
||||||
DexPath: dexJarFile,
|
DexPath: dexJarFile,
|
||||||
ManifestPath: android.OptionalPathForPath(d.manifestFile),
|
ManifestPath: android.OptionalPathForPath(d.manifestFile),
|
||||||
UncompressedDex: d.uncompressedDex,
|
UncompressedDex: d.uncompressedDex,
|
||||||
@@ -380,7 +402,7 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr
|
|||||||
PresignedPrebuilt: d.isPresignedPrebuilt,
|
PresignedPrebuilt: d.isPresignedPrebuilt,
|
||||||
}
|
}
|
||||||
|
|
||||||
d.configPath = android.PathForModuleOut(ctx, "dexpreopt", "dexpreopt.config")
|
d.configPath = android.PathForModuleOut(ctx, "dexpreopt", dexJarStem, "dexpreopt.config")
|
||||||
dexpreopt.WriteModuleConfig(ctx, dexpreoptConfig, d.configPath)
|
dexpreopt.WriteModuleConfig(ctx, dexpreoptConfig, d.configPath)
|
||||||
|
|
||||||
if d.dexpreoptDisabled(ctx) {
|
if d.dexpreoptDisabled(ctx) {
|
||||||
@@ -394,7 +416,7 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr
|
|||||||
// dependencies to create a per-app list, and use `rsync --checksum` to prevent the file's mtime
|
// dependencies to create a per-app list, and use `rsync --checksum` to prevent the file's mtime
|
||||||
// from being changed if the contents don't change. This avoids unnecessary dexpreopt reruns.
|
// from being changed if the contents don't change. This avoids unnecessary dexpreopt reruns.
|
||||||
productPackages := android.PathForModuleInPartitionInstall(ctx, "", "product_packages.txt")
|
productPackages := android.PathForModuleInPartitionInstall(ctx, "", "product_packages.txt")
|
||||||
appProductPackages := android.PathForModuleOut(ctx, "dexpreopt", "product_packages.txt")
|
appProductPackages := android.PathForModuleOut(ctx, "dexpreopt", dexJarStem, "product_packages.txt")
|
||||||
appProductPackagesStaging := appProductPackages.ReplaceExtension(ctx, "txt.tmp")
|
appProductPackagesStaging := appProductPackages.ReplaceExtension(ctx, "txt.tmp")
|
||||||
clcNames, _ := dexpreopt.ComputeClassLoaderContextDependencies(dexpreoptConfig.ClassLoaderContexts)
|
clcNames, _ := dexpreopt.ComputeClassLoaderContextDependencies(dexpreoptConfig.ClassLoaderContexts)
|
||||||
sort.Strings(clcNames) // The order needs to be deterministic.
|
sort.Strings(clcNames) // The order needs to be deterministic.
|
||||||
@@ -416,7 +438,7 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr
|
|||||||
Text("rsync --checksum").
|
Text("rsync --checksum").
|
||||||
Input(appProductPackagesStaging).
|
Input(appProductPackagesStaging).
|
||||||
Output(appProductPackages)
|
Output(appProductPackages)
|
||||||
productPackagesRule.Restat().Build("product_packages", "dexpreopt product_packages")
|
productPackagesRule.Restat().Build("product_packages."+dexJarStem, "dexpreopt product_packages")
|
||||||
|
|
||||||
dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(
|
dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(
|
||||||
ctx, globalSoong, global, dexpreoptConfig, appProductPackages)
|
ctx, globalSoong, global, dexpreoptConfig, appProductPackages)
|
||||||
@@ -425,9 +447,11 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
dexpreoptRule.Build("dexpreopt", "dexpreopt")
|
dexpreoptRule.Build("dexpreopt"+"."+dexJarStem, "dexpreopt")
|
||||||
|
|
||||||
isApexSystemServerJar := global.AllApexSystemServerJars(ctx).ContainsJar(moduleName(ctx))
|
// The current ctx might be of a deapexer module created by a prebuilt apex
|
||||||
|
// Use the path of the dex file to determine the library name
|
||||||
|
isApexSystemServerJar := global.AllApexSystemServerJars(ctx).ContainsJar(dexJarStem)
|
||||||
|
|
||||||
for _, install := range dexpreoptRule.Installs() {
|
for _, install := range dexpreoptRule.Installs() {
|
||||||
// Remove the "/" prefix because the path should be relative to $ANDROID_PRODUCT_OUT.
|
// Remove the "/" prefix because the path should be relative to $ANDROID_PRODUCT_OUT.
|
||||||
@@ -452,7 +476,7 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr
|
|||||||
// The installs will be handled by Make as sub-modules of the java library.
|
// The installs will be handled by Make as sub-modules of the java library.
|
||||||
d.builtInstalledForApex = append(d.builtInstalledForApex, dexpreopterInstall{
|
d.builtInstalledForApex = append(d.builtInstalledForApex, dexpreopterInstall{
|
||||||
name: arch + "-" + installBase,
|
name: arch + "-" + installBase,
|
||||||
moduleName: moduleName(ctx),
|
moduleName: dexJarStem,
|
||||||
outputPathOnHost: install.From,
|
outputPathOnHost: install.From,
|
||||||
installDirOnDevice: installPath,
|
installDirOnDevice: installPath,
|
||||||
installFileOnDevice: installBase,
|
installFileOnDevice: installBase,
|
||||||
|
@@ -410,7 +410,7 @@ func TestAndroidMkEntriesForApex(t *testing.T) {
|
|||||||
verifyEntries(t,
|
verifyEntries(t,
|
||||||
"entriesList[0]",
|
"entriesList[0]",
|
||||||
"service-foo-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.odex",
|
"service-foo-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.odex",
|
||||||
"/dexpreopt/oat/arm64/javalib.odex",
|
"/dexpreopt/service-foo/oat/arm64/javalib.odex",
|
||||||
"/system/framework/oat/arm64",
|
"/system/framework/oat/arm64",
|
||||||
"apex@com.android.apex1@javalib@service-foo.jar@classes.odex",
|
"apex@com.android.apex1@javalib@service-foo.jar@classes.odex",
|
||||||
entriesList[0])
|
entriesList[0])
|
||||||
@@ -418,7 +418,7 @@ func TestAndroidMkEntriesForApex(t *testing.T) {
|
|||||||
verifyEntries(t,
|
verifyEntries(t,
|
||||||
"entriesList[1]",
|
"entriesList[1]",
|
||||||
"service-foo-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.vdex",
|
"service-foo-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.vdex",
|
||||||
"/dexpreopt/oat/arm64/javalib.vdex",
|
"/dexpreopt/service-foo/oat/arm64/javalib.vdex",
|
||||||
"/system/framework/oat/arm64",
|
"/system/framework/oat/arm64",
|
||||||
"apex@com.android.apex1@javalib@service-foo.jar@classes.vdex",
|
"apex@com.android.apex1@javalib@service-foo.jar@classes.vdex",
|
||||||
entriesList[1])
|
entriesList[1])
|
||||||
@@ -459,7 +459,7 @@ func TestGenerateProfileEvenIfDexpreoptIsDisabled(t *testing.T) {
|
|||||||
ctx := result.TestContext
|
ctx := result.TestContext
|
||||||
dexpreopt := ctx.ModuleForTests("foo", "android_common").MaybeRule("dexpreopt")
|
dexpreopt := ctx.ModuleForTests("foo", "android_common").MaybeRule("dexpreopt")
|
||||||
|
|
||||||
expected := []string{"out/soong/.intermediates/foo/android_common/dexpreopt/profile.prof"}
|
expected := []string{"out/soong/.intermediates/foo/android_common/dexpreopt/foo/profile.prof"}
|
||||||
|
|
||||||
android.AssertArrayString(t, "outputs", expected, dexpreopt.AllOutputs())
|
android.AssertArrayString(t, "outputs", expected, dexpreopt.AllOutputs())
|
||||||
}
|
}
|
||||||
|
13
java/java.go
13
java/java.go
@@ -2100,6 +2100,7 @@ type Import struct {
|
|||||||
|
|
||||||
// output file containing classes.dex and resources
|
// output file containing classes.dex and resources
|
||||||
dexJarFile OptionalDexJarPath
|
dexJarFile OptionalDexJarPath
|
||||||
|
dexJarFileErr error
|
||||||
dexJarInstallFile android.Path
|
dexJarInstallFile android.Path
|
||||||
|
|
||||||
combinedClasspathFile android.Path
|
combinedClasspathFile android.Path
|
||||||
@@ -2250,9 +2251,12 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||||||
ai, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
|
ai, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
|
||||||
if ai.ForPrebuiltApex {
|
if ai.ForPrebuiltApex {
|
||||||
// Get the path of the dex implementation jar from the `deapexer` module.
|
// Get the path of the dex implementation jar from the `deapexer` module.
|
||||||
di := android.FindDeapexerProviderForModule(ctx)
|
di, err := android.FindDeapexerProviderForModule(ctx)
|
||||||
if di == nil {
|
if err != nil {
|
||||||
return // An error has been reported by FindDeapexerProviderForModule.
|
// An error was found, possibly due to multiple apexes in the tree that export this library
|
||||||
|
// Defer the error till a client tries to call DexJarBuildPath
|
||||||
|
j.dexJarFileErr = err
|
||||||
|
return
|
||||||
}
|
}
|
||||||
dexJarFileApexRootRelative := apexRootRelativePathToJavaLib(j.BaseModuleName())
|
dexJarFileApexRootRelative := apexRootRelativePathToJavaLib(j.BaseModuleName())
|
||||||
if dexOutputPath := di.PrebuiltExportPath(dexJarFileApexRootRelative); dexOutputPath != nil {
|
if dexOutputPath := di.PrebuiltExportPath(dexJarFileApexRootRelative); dexOutputPath != nil {
|
||||||
@@ -2375,6 +2379,9 @@ func (j *Import) ImplementationAndResourcesJars() android.Paths {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (j *Import) DexJarBuildPath() OptionalDexJarPath {
|
func (j *Import) DexJarBuildPath() OptionalDexJarPath {
|
||||||
|
if j.dexJarFileErr != nil {
|
||||||
|
panic(j.dexJarFileErr.Error())
|
||||||
|
}
|
||||||
return j.dexJarFile
|
return j.dexJarFile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -618,8 +618,6 @@ func TestPrebuilts(t *testing.T) {
|
|||||||
android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "java_library", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
|
android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "java_library", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
|
||||||
entries = android.AndroidMkEntriesForTest(t, ctx, barModule.Module())[0]
|
entries = android.AndroidMkEntriesForTest(t, ctx, barModule.Module())[0]
|
||||||
android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "java_import", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
|
android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "java_import", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
|
||||||
entries = android.AndroidMkEntriesForTest(t, ctx, ctx.ModuleForTests("sdklib", "android_common").Module())[0]
|
|
||||||
android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "java_sdk_library_import", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertDeepEquals(t *testing.T, message string, expected interface{}, actual interface{}) {
|
func assertDeepEquals(t *testing.T, message string, expected interface{}, actual interface{}) {
|
||||||
|
@@ -2378,7 +2378,8 @@ type SdkLibraryImport struct {
|
|||||||
xmlPermissionsFileModule *sdkLibraryXml
|
xmlPermissionsFileModule *sdkLibraryXml
|
||||||
|
|
||||||
// Build path to the dex implementation jar obtained from the prebuilt_apex, if any.
|
// Build path to the dex implementation jar obtained from the prebuilt_apex, if any.
|
||||||
dexJarFile OptionalDexJarPath
|
dexJarFile OptionalDexJarPath
|
||||||
|
dexJarFileErr error
|
||||||
|
|
||||||
// Expected install file path of the source module(sdk_library)
|
// Expected install file path of the source module(sdk_library)
|
||||||
// or dex implementation jar obtained from the prebuilt_apex, if any.
|
// or dex implementation jar obtained from the prebuilt_apex, if any.
|
||||||
@@ -2591,14 +2592,6 @@ func (module *SdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (module *SdkLibraryImport) AndroidMkEntries() []android.AndroidMkEntries {
|
|
||||||
// For an SDK library imported from a prebuilt APEX, we don't need a Make module for itself, as we
|
|
||||||
// don't need to install it. However, we need to add its dexpreopt outputs as sub-modules, if it
|
|
||||||
// is preopted.
|
|
||||||
dexpreoptEntries := module.dexpreopter.AndroidMkEntriesForApex()
|
|
||||||
return append(dexpreoptEntries, android.AndroidMkEntries{Disabled: true})
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ android.ApexModule = (*SdkLibraryImport)(nil)
|
var _ android.ApexModule = (*SdkLibraryImport)(nil)
|
||||||
|
|
||||||
// Implements android.ApexModule
|
// Implements android.ApexModule
|
||||||
@@ -2695,9 +2688,12 @@ func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleCo
|
|||||||
ai, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
|
ai, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
|
||||||
if ai.ForPrebuiltApex {
|
if ai.ForPrebuiltApex {
|
||||||
// Get the path of the dex implementation jar from the `deapexer` module.
|
// Get the path of the dex implementation jar from the `deapexer` module.
|
||||||
di := android.FindDeapexerProviderForModule(ctx)
|
di, err := android.FindDeapexerProviderForModule(ctx)
|
||||||
if di == nil {
|
if err != nil {
|
||||||
return // An error has been reported by FindDeapexerProviderForModule.
|
// An error was found, possibly due to multiple apexes in the tree that export this library
|
||||||
|
// Defer the error till a client tries to call DexJarBuildPath
|
||||||
|
module.dexJarFileErr = err
|
||||||
|
return
|
||||||
}
|
}
|
||||||
dexJarFileApexRootRelative := apexRootRelativePathToJavaLib(module.BaseModuleName())
|
dexJarFileApexRootRelative := apexRootRelativePathToJavaLib(module.BaseModuleName())
|
||||||
if dexOutputPath := di.PrebuiltExportPath(dexJarFileApexRootRelative); dexOutputPath != nil {
|
if dexOutputPath := di.PrebuiltExportPath(dexJarFileApexRootRelative); dexOutputPath != nil {
|
||||||
@@ -2759,6 +2755,9 @@ func (module *SdkLibraryImport) SdkImplementationJars(ctx android.BaseModuleCont
|
|||||||
func (module *SdkLibraryImport) DexJarBuildPath() OptionalDexJarPath {
|
func (module *SdkLibraryImport) DexJarBuildPath() OptionalDexJarPath {
|
||||||
// The dex implementation jar extracted from the .apex file should be used in preference to the
|
// The dex implementation jar extracted from the .apex file should be used in preference to the
|
||||||
// source.
|
// source.
|
||||||
|
if module.dexJarFileErr != nil {
|
||||||
|
panic(module.dexJarFileErr.Error())
|
||||||
|
}
|
||||||
if module.dexJarFile.IsSet() {
|
if module.dexJarFile.IsSet() {
|
||||||
return module.dexJarFile
|
return module.dexJarFile
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user