Merge "APEX can be flattened"
This commit is contained in:
@@ -881,6 +881,10 @@ func (c *config) NdkAbis() bool {
|
|||||||
return Bool(c.productVariables.Ndk_abis)
|
return Bool(c.productVariables.Ndk_abis)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *config) FlattenApex() bool {
|
||||||
|
return Bool(c.productVariables.FlattenApex)
|
||||||
|
}
|
||||||
|
|
||||||
func stringSlice(s *[]string) []string {
|
func stringSlice(s *[]string) []string {
|
||||||
if s != nil {
|
if s != nil {
|
||||||
return *s
|
return *s
|
||||||
|
@@ -250,6 +250,8 @@ type productVariables struct {
|
|||||||
VendorVars map[string]map[string]string `json:",omitempty"`
|
VendorVars map[string]map[string]string `json:",omitempty"`
|
||||||
|
|
||||||
Ndk_abis *bool `json:",omitempty"`
|
Ndk_abis *bool `json:",omitempty"`
|
||||||
|
|
||||||
|
FlattenApex *bool `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func boolPtr(v bool) *bool {
|
func boolPtr(v bool) *bool {
|
||||||
|
188
apex/apex.go
188
apex/apex.go
@@ -230,6 +230,38 @@ type apexBundleProperties struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type apexFileClass int
|
||||||
|
|
||||||
|
const (
|
||||||
|
etc apexFileClass = iota
|
||||||
|
nativeSharedLib
|
||||||
|
nativeExecutable
|
||||||
|
javaSharedLib
|
||||||
|
)
|
||||||
|
|
||||||
|
func (class apexFileClass) NameInMake() string {
|
||||||
|
switch class {
|
||||||
|
case etc:
|
||||||
|
return "ETC"
|
||||||
|
case nativeSharedLib:
|
||||||
|
return "SHARED_LIBRARIES"
|
||||||
|
case nativeExecutable:
|
||||||
|
return "EXECUTABLES"
|
||||||
|
case javaSharedLib:
|
||||||
|
return "JAVA_LIBRARIES"
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("unkonwn class %d", class))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type apexFile struct {
|
||||||
|
builtFile android.Path
|
||||||
|
moduleName string
|
||||||
|
archType android.ArchType
|
||||||
|
installDir string
|
||||||
|
class apexFileClass
|
||||||
|
}
|
||||||
|
|
||||||
type apexBundle struct {
|
type apexBundle struct {
|
||||||
android.ModuleBase
|
android.ModuleBase
|
||||||
android.DefaultableModuleBase
|
android.DefaultableModuleBase
|
||||||
@@ -238,6 +270,11 @@ type apexBundle struct {
|
|||||||
|
|
||||||
outputFile android.WritablePath
|
outputFile android.WritablePath
|
||||||
installDir android.OutputPath
|
installDir android.OutputPath
|
||||||
|
|
||||||
|
// list of files to be included in this apex
|
||||||
|
filesInfo []apexFile
|
||||||
|
|
||||||
|
flattened bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
|
func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
|
||||||
@@ -364,7 +401,7 @@ func getCopyManifestForExecutable(cc *cc.Module) (fileToCopy android.Path, dirIn
|
|||||||
|
|
||||||
func getCopyManifestForJavaLibrary(java *java.Library) (fileToCopy android.Path, dirInApex string) {
|
func getCopyManifestForJavaLibrary(java *java.Library) (fileToCopy android.Path, dirInApex string) {
|
||||||
dirInApex = "javalib"
|
dirInApex = "javalib"
|
||||||
fileToCopy = java.Srcs()[0]
|
fileToCopy = java.DexJarFile()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,8 +412,7 @@ func getCopyManifestForPrebuiltEtc(prebuilt *android.PrebuiltEtc) (fileToCopy an
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||||
// files to copy -> dir in apex
|
filesInfo := []apexFile{}
|
||||||
copyManifest := make(map[android.Path]string)
|
|
||||||
|
|
||||||
var keyFile android.Path
|
var keyFile android.Path
|
||||||
var certificate java.Certificate
|
var certificate java.Certificate
|
||||||
@@ -390,7 +426,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||||||
case sharedLibTag:
|
case sharedLibTag:
|
||||||
if cc, ok := child.(*cc.Module); ok {
|
if cc, ok := child.(*cc.Module); ok {
|
||||||
fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc)
|
fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc)
|
||||||
copyManifest[fileToCopy] = dirInApex
|
filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeSharedLib})
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
ctx.PropertyErrorf("native_shared_libs", "%q is not a cc_library or cc_library_shared module", depName)
|
ctx.PropertyErrorf("native_shared_libs", "%q is not a cc_library or cc_library_shared module", depName)
|
||||||
@@ -398,7 +434,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||||||
case executableTag:
|
case executableTag:
|
||||||
if cc, ok := child.(*cc.Module); ok {
|
if cc, ok := child.(*cc.Module); ok {
|
||||||
fileToCopy, dirInApex := getCopyManifestForExecutable(cc)
|
fileToCopy, dirInApex := getCopyManifestForExecutable(cc)
|
||||||
copyManifest[fileToCopy] = dirInApex
|
filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeExecutable})
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
ctx.PropertyErrorf("binaries", "%q is not a cc_binary module", depName)
|
ctx.PropertyErrorf("binaries", "%q is not a cc_binary module", depName)
|
||||||
@@ -406,7 +442,11 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||||||
case javaLibTag:
|
case javaLibTag:
|
||||||
if java, ok := child.(*java.Library); ok {
|
if java, ok := child.(*java.Library); ok {
|
||||||
fileToCopy, dirInApex := getCopyManifestForJavaLibrary(java)
|
fileToCopy, dirInApex := getCopyManifestForJavaLibrary(java)
|
||||||
copyManifest[fileToCopy] = dirInApex
|
if fileToCopy == nil {
|
||||||
|
ctx.PropertyErrorf("java_libs", "%q is not configured to be compiled into dex", depName)
|
||||||
|
} else {
|
||||||
|
filesInfo = append(filesInfo, apexFile{fileToCopy, depName, java.Arch().ArchType, dirInApex, javaSharedLib})
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
ctx.PropertyErrorf("java_libs", "%q is not a java_library module", depName)
|
ctx.PropertyErrorf("java_libs", "%q is not a java_library module", depName)
|
||||||
@@ -414,7 +454,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||||||
case prebuiltTag:
|
case prebuiltTag:
|
||||||
if prebuilt, ok := child.(*android.PrebuiltEtc); ok {
|
if prebuilt, ok := child.(*android.PrebuiltEtc); ok {
|
||||||
fileToCopy, dirInApex := getCopyManifestForPrebuiltEtc(prebuilt)
|
fileToCopy, dirInApex := getCopyManifestForPrebuiltEtc(prebuilt)
|
||||||
copyManifest[fileToCopy] = dirInApex
|
filesInfo = append(filesInfo, apexFile{fileToCopy, depName, prebuilt.Arch().ArchType, dirInApex, etc})
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
|
ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
|
||||||
@@ -438,8 +478,9 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||||||
// indirect dependencies
|
// indirect dependencies
|
||||||
if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() && am.IsInstallableToApex() {
|
if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() && am.IsInstallableToApex() {
|
||||||
if cc, ok := child.(*cc.Module); ok {
|
if cc, ok := child.(*cc.Module); ok {
|
||||||
|
depName := ctx.OtherModuleName(child)
|
||||||
fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc)
|
fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc)
|
||||||
copyManifest[fileToCopy] = dirInApex
|
filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeSharedLib})
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -452,6 +493,42 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove duplicates in filesInfo
|
||||||
|
removeDup := func(filesInfo []apexFile) []apexFile {
|
||||||
|
encountered := make(map[android.Path]bool)
|
||||||
|
result := []apexFile{}
|
||||||
|
for _, f := range filesInfo {
|
||||||
|
if !encountered[f.builtFile] {
|
||||||
|
encountered[f.builtFile] = true
|
||||||
|
result = append(result, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
filesInfo = removeDup(filesInfo)
|
||||||
|
|
||||||
|
// to have consistent build rules
|
||||||
|
sort.Slice(filesInfo, func(i, j int) bool {
|
||||||
|
return filesInfo[i].builtFile.String() < filesInfo[j].builtFile.String()
|
||||||
|
})
|
||||||
|
|
||||||
|
// prepend the name of this APEX to the module names. These names will be the names of
|
||||||
|
// modules that will be defined if the APEX is flattened.
|
||||||
|
for i := range filesInfo {
|
||||||
|
filesInfo[i].moduleName = ctx.ModuleName() + "." + filesInfo[i].moduleName
|
||||||
|
}
|
||||||
|
|
||||||
|
a.flattened = ctx.Config().FlattenApex()
|
||||||
|
a.installDir = android.PathForModuleInstall(ctx, "apex")
|
||||||
|
a.filesInfo = filesInfo
|
||||||
|
if ctx.Config().FlattenApex() {
|
||||||
|
a.buildFlattenedApex(ctx)
|
||||||
|
} else {
|
||||||
|
a.buildUnflattenedApex(ctx, keyFile, certificate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, keyFile android.Path, certificate java.Certificate) {
|
||||||
cert := String(a.properties.Certificate)
|
cert := String(a.properties.Certificate)
|
||||||
if cert != "" && android.SrcIsModule(cert) == "" {
|
if cert != "" && android.SrcIsModule(cert) == "" {
|
||||||
defaultDir := ctx.Config().DefaultAppCertificateDir(ctx)
|
defaultDir := ctx.Config().DefaultAppCertificateDir(ctx)
|
||||||
@@ -467,15 +544,15 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||||||
// files and dirs that will be created in apex
|
// files and dirs that will be created in apex
|
||||||
var readOnlyPaths []string
|
var readOnlyPaths []string
|
||||||
var executablePaths []string // this also includes dirs
|
var executablePaths []string // this also includes dirs
|
||||||
for fileToCopy, dirInApex := range copyManifest {
|
for _, f := range a.filesInfo {
|
||||||
pathInApex := filepath.Join(dirInApex, fileToCopy.Base())
|
pathInApex := filepath.Join(f.installDir, f.builtFile.Base())
|
||||||
if dirInApex == "bin" {
|
if f.installDir == "bin" {
|
||||||
executablePaths = append(executablePaths, pathInApex)
|
executablePaths = append(executablePaths, pathInApex)
|
||||||
} else {
|
} else {
|
||||||
readOnlyPaths = append(readOnlyPaths, pathInApex)
|
readOnlyPaths = append(readOnlyPaths, pathInApex)
|
||||||
}
|
}
|
||||||
if !android.InList(dirInApex, executablePaths) {
|
if !android.InList(f.installDir, executablePaths) {
|
||||||
executablePaths = append(executablePaths, dirInApex)
|
executablePaths = append(executablePaths, f.installDir)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sort.Strings(readOnlyPaths)
|
sort.Strings(readOnlyPaths)
|
||||||
@@ -504,16 +581,13 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||||||
unsignedOutputFile := android.PathForModuleOut(ctx, a.ModuleBase.Name()+apexSuffix+".unsigned")
|
unsignedOutputFile := android.PathForModuleOut(ctx, a.ModuleBase.Name()+apexSuffix+".unsigned")
|
||||||
|
|
||||||
filesToCopy := []android.Path{}
|
filesToCopy := []android.Path{}
|
||||||
for file := range copyManifest {
|
for _, f := range a.filesInfo {
|
||||||
filesToCopy = append(filesToCopy, file)
|
filesToCopy = append(filesToCopy, f.builtFile)
|
||||||
}
|
}
|
||||||
sort.Slice(filesToCopy, func(i, j int) bool {
|
|
||||||
return filesToCopy[i].String() < filesToCopy[j].String()
|
|
||||||
})
|
|
||||||
|
|
||||||
copyCommands := []string{}
|
copyCommands := []string{}
|
||||||
for _, src := range filesToCopy {
|
for i, src := range filesToCopy {
|
||||||
dest := filepath.Join(copyManifest[src], src.Base())
|
dest := filepath.Join(a.filesInfo[i].installDir, src.Base())
|
||||||
dest_path := filepath.Join(android.PathForModuleOut(ctx, "image").String(), dest)
|
dest_path := filepath.Join(android.PathForModuleOut(ctx, "image").String(), dest)
|
||||||
copyCommands = append(copyCommands, "mkdir -p "+filepath.Dir(dest_path))
|
copyCommands = append(copyCommands, "mkdir -p "+filepath.Dir(dest_path))
|
||||||
copyCommands = append(copyCommands, "cp "+src.String()+" "+dest_path)
|
copyCommands = append(copyCommands, "cp "+src.String()+" "+dest_path)
|
||||||
@@ -547,23 +621,71 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||||||
"certificates": strings.Join([]string{certificate.Pem.String(), certificate.Key.String()}, " "),
|
"certificates": strings.Join([]string{certificate.Pem.String(), certificate.Key.String()}, " "),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
a.installDir = android.PathForModuleInstall(ctx, "apex")
|
func (a *apexBundle) buildFlattenedApex(ctx android.ModuleContext) {
|
||||||
|
// For flattened APEX, do nothing but make sure that manifest.json file is also copied along
|
||||||
|
// with other ordinary files.
|
||||||
|
manifest := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "manifest.json"))
|
||||||
|
a.filesInfo = append(a.filesInfo, apexFile{manifest, a.Name() + ".manifest.json", android.Common, ".", etc})
|
||||||
|
|
||||||
|
for _, fi := range a.filesInfo {
|
||||||
|
dir := filepath.Join("apex", a.Name(), fi.installDir)
|
||||||
|
ctx.InstallFile(android.PathForModuleInstall(ctx, dir), fi.builtFile.Base(), fi.builtFile)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *apexBundle) AndroidMk() android.AndroidMkData {
|
func (a *apexBundle) AndroidMk() android.AndroidMkData {
|
||||||
return android.AndroidMkData{
|
if a.flattened {
|
||||||
Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
|
return android.AndroidMkData{
|
||||||
fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
|
Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
|
||||||
fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
|
moduleNames := []string{}
|
||||||
fmt.Fprintln(w, "LOCAL_MODULE :=", name)
|
for _, fi := range a.filesInfo {
|
||||||
fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC") // do we need a new class?
|
if !android.InList(fi.moduleName, moduleNames) {
|
||||||
fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", a.outputFile.String())
|
moduleNames = append(moduleNames, fi.moduleName)
|
||||||
fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)", a.installDir.RelPathString()))
|
}
|
||||||
fmt.Fprintln(w, "LOCAL_INSTALLED_MODULE_STEM :=", name+apexSuffix)
|
}
|
||||||
fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", String(a.properties.Key))
|
fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
|
||||||
fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
|
fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
|
||||||
}}
|
fmt.Fprintln(w, "LOCAL_MODULE :=", name)
|
||||||
|
fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(moduleNames, " "))
|
||||||
|
fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
|
||||||
|
|
||||||
|
for _, fi := range a.filesInfo {
|
||||||
|
fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
|
||||||
|
fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
|
||||||
|
fmt.Fprintln(w, "LOCAL_MODULE :=", fi.moduleName)
|
||||||
|
fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)", a.installDir.RelPathString(), name, fi.installDir))
|
||||||
|
fmt.Fprintln(w, "LOCAL_INSTALLED_MODULE_STEM :=", fi.builtFile.Base())
|
||||||
|
fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", fi.builtFile.String())
|
||||||
|
fmt.Fprintln(w, "LOCAL_MODULE_CLASS :=", fi.class.NameInMake())
|
||||||
|
archStr := fi.archType.String()
|
||||||
|
if archStr != "common" {
|
||||||
|
fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", archStr)
|
||||||
|
}
|
||||||
|
if fi.class == javaSharedLib {
|
||||||
|
fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", fi.builtFile.String())
|
||||||
|
fmt.Fprintln(w, "LOCAL_DEX_PREOPT := false")
|
||||||
|
fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_java_prebuilt.mk")
|
||||||
|
} else {
|
||||||
|
fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
} else {
|
||||||
|
return android.AndroidMkData{
|
||||||
|
Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
|
||||||
|
fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
|
||||||
|
fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
|
||||||
|
fmt.Fprintln(w, "LOCAL_MODULE :=", name)
|
||||||
|
fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC") // do we need a new class?
|
||||||
|
fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", a.outputFile.String())
|
||||||
|
fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)", a.installDir.RelPathString()))
|
||||||
|
fmt.Fprintln(w, "LOCAL_INSTALLED_MODULE_STEM :=", name+apexSuffix)
|
||||||
|
fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", String(a.properties.Key))
|
||||||
|
fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
|
||||||
|
}}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func apexBundleFactory() android.Module {
|
func apexBundleFactory() android.Module {
|
||||||
|
@@ -330,6 +330,10 @@ func (j *Module) Srcs() android.Paths {
|
|||||||
return android.Paths{j.outputFile}
|
return android.Paths{j.outputFile}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (j *Module) DexJarFile() android.Path {
|
||||||
|
return j.dexJarFile
|
||||||
|
}
|
||||||
|
|
||||||
var _ android.SourceFileProducer = (*Module)(nil)
|
var _ android.SourceFileProducer = (*Module)(nil)
|
||||||
|
|
||||||
type Dependency interface {
|
type Dependency interface {
|
||||||
|
Reference in New Issue
Block a user