APEX can be flattened
When TARGET_FLATTEN_APEX is set to true, APEXes are flattened, which means files in an APEX is not packaged into the mini file system image, but instead directly copied to the system partition. This option is for devices where kernel does not support loopback devices or the maximum number of loopback devices is too small (though the threshold is TBD as of now). This CL also fixes a bug that jars having bytecode are installed instead of those having dex. Bug: 118485880 Test: TARGET_FLATTEN_APEX=true m apex.test; tree out/target/product/.../system/apex/apex.test shows list of files in it. Test; m apex.test, then a file out/target/product/.../system/apex/apex .test.apex exists. Change-Id: I5a3d62d392d05f2779c4925388afe4f6e460059b
This commit is contained in:
parent
b9619f0746
commit
8fd6192480
4 changed files with 165 additions and 33 deletions
|
@ -881,6 +881,10 @@ func (c *config) NdkAbis() bool {
|
|||
return Bool(c.productVariables.Ndk_abis)
|
||||
}
|
||||
|
||||
func (c *config) FlattenApex() bool {
|
||||
return Bool(c.productVariables.FlattenApex)
|
||||
}
|
||||
|
||||
func stringSlice(s *[]string) []string {
|
||||
if s != nil {
|
||||
return *s
|
||||
|
|
|
@ -250,6 +250,8 @@ type productVariables struct {
|
|||
VendorVars map[string]map[string]string `json:",omitempty"`
|
||||
|
||||
Ndk_abis *bool `json:",omitempty"`
|
||||
|
||||
FlattenApex *bool `json:",omitempty"`
|
||||
}
|
||||
|
||||
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 {
|
||||
android.ModuleBase
|
||||
android.DefaultableModuleBase
|
||||
|
@ -238,6 +270,11 @@ type apexBundle struct {
|
|||
|
||||
outputFile android.WritablePath
|
||||
installDir android.OutputPath
|
||||
|
||||
// list of files to be included in this apex
|
||||
filesInfo []apexFile
|
||||
|
||||
flattened bool
|
||||
}
|
||||
|
||||
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) {
|
||||
dirInApex = "javalib"
|
||||
fileToCopy = java.Srcs()[0]
|
||||
fileToCopy = java.DexJarFile()
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -375,8 +412,7 @@ func getCopyManifestForPrebuiltEtc(prebuilt *android.PrebuiltEtc) (fileToCopy an
|
|||
}
|
||||
|
||||
func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||
// files to copy -> dir in apex
|
||||
copyManifest := make(map[android.Path]string)
|
||||
filesInfo := []apexFile{}
|
||||
|
||||
var keyFile android.Path
|
||||
var certificate java.Certificate
|
||||
|
@ -390,7 +426,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||
case sharedLibTag:
|
||||
if cc, ok := child.(*cc.Module); ok {
|
||||
fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc)
|
||||
copyManifest[fileToCopy] = dirInApex
|
||||
filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeSharedLib})
|
||||
return true
|
||||
} else {
|
||||
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:
|
||||
if cc, ok := child.(*cc.Module); ok {
|
||||
fileToCopy, dirInApex := getCopyManifestForExecutable(cc)
|
||||
copyManifest[fileToCopy] = dirInApex
|
||||
filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeExecutable})
|
||||
return true
|
||||
} else {
|
||||
ctx.PropertyErrorf("binaries", "%q is not a cc_binary module", depName)
|
||||
|
@ -406,7 +442,11 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||
case javaLibTag:
|
||||
if java, ok := child.(*java.Library); ok {
|
||||
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
|
||||
} else {
|
||||
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:
|
||||
if prebuilt, ok := child.(*android.PrebuiltEtc); ok {
|
||||
fileToCopy, dirInApex := getCopyManifestForPrebuiltEtc(prebuilt)
|
||||
copyManifest[fileToCopy] = dirInApex
|
||||
filesInfo = append(filesInfo, apexFile{fileToCopy, depName, prebuilt.Arch().ArchType, dirInApex, etc})
|
||||
return true
|
||||
} else {
|
||||
ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
|
||||
|
@ -438,8 +478,9 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||
// indirect dependencies
|
||||
if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() && am.IsInstallableToApex() {
|
||||
if cc, ok := child.(*cc.Module); ok {
|
||||
depName := ctx.OtherModuleName(child)
|
||||
fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc)
|
||||
copyManifest[fileToCopy] = dirInApex
|
||||
filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeSharedLib})
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -452,6 +493,42 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||
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)
|
||||
if cert != "" && android.SrcIsModule(cert) == "" {
|
||||
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
|
||||
var readOnlyPaths []string
|
||||
var executablePaths []string // this also includes dirs
|
||||
for fileToCopy, dirInApex := range copyManifest {
|
||||
pathInApex := filepath.Join(dirInApex, fileToCopy.Base())
|
||||
if dirInApex == "bin" {
|
||||
for _, f := range a.filesInfo {
|
||||
pathInApex := filepath.Join(f.installDir, f.builtFile.Base())
|
||||
if f.installDir == "bin" {
|
||||
executablePaths = append(executablePaths, pathInApex)
|
||||
} else {
|
||||
readOnlyPaths = append(readOnlyPaths, pathInApex)
|
||||
}
|
||||
if !android.InList(dirInApex, executablePaths) {
|
||||
executablePaths = append(executablePaths, dirInApex)
|
||||
if !android.InList(f.installDir, executablePaths) {
|
||||
executablePaths = append(executablePaths, f.installDir)
|
||||
}
|
||||
}
|
||||
sort.Strings(readOnlyPaths)
|
||||
|
@ -504,16 +581,13 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||
unsignedOutputFile := android.PathForModuleOut(ctx, a.ModuleBase.Name()+apexSuffix+".unsigned")
|
||||
|
||||
filesToCopy := []android.Path{}
|
||||
for file := range copyManifest {
|
||||
filesToCopy = append(filesToCopy, file)
|
||||
for _, f := range a.filesInfo {
|
||||
filesToCopy = append(filesToCopy, f.builtFile)
|
||||
}
|
||||
sort.Slice(filesToCopy, func(i, j int) bool {
|
||||
return filesToCopy[i].String() < filesToCopy[j].String()
|
||||
})
|
||||
|
||||
copyCommands := []string{}
|
||||
for _, src := range filesToCopy {
|
||||
dest := filepath.Join(copyManifest[src], src.Base())
|
||||
for i, src := range filesToCopy {
|
||||
dest := filepath.Join(a.filesInfo[i].installDir, src.Base())
|
||||
dest_path := filepath.Join(android.PathForModuleOut(ctx, "image").String(), dest)
|
||||
copyCommands = append(copyCommands, "mkdir -p "+filepath.Dir(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()}, " "),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
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 {
|
||||
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)")
|
||||
}}
|
||||
if a.flattened {
|
||||
return android.AndroidMkData{
|
||||
Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
|
||||
moduleNames := []string{}
|
||||
for _, fi := range a.filesInfo {
|
||||
if !android.InList(fi.moduleName, moduleNames) {
|
||||
moduleNames = append(moduleNames, fi.moduleName)
|
||||
}
|
||||
}
|
||||
fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
|
||||
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 {
|
||||
|
|
|
@ -330,6 +330,10 @@ func (j *Module) Srcs() android.Paths {
|
|||
return android.Paths{j.outputFile}
|
||||
}
|
||||
|
||||
func (j *Module) DexJarFile() android.Path {
|
||||
return j.dexJarFile
|
||||
}
|
||||
|
||||
var _ android.SourceFileProducer = (*Module)(nil)
|
||||
|
||||
type Dependency interface {
|
||||
|
|
Loading…
Reference in a new issue