blob: 0f8f614b455e882edd073d10436db9814edb98ba [file] [log] [blame]
// Copyright (C) 2024 The Android Open Source Project
//
// 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 filesystem
import (
"fmt"
"path/filepath"
"strconv"
"strings"
"android/soong/android"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
func init() {
android.RegisterModuleType("super_image", SuperImageFactory)
}
type superImage struct {
android.ModuleBase
properties SuperImageProperties
partitionProps SuperImagePartitionNameProperties
installDir android.InstallPath
}
type SuperImageProperties struct {
// the size of the super partition
Size *int64
// the block device where metadata for dynamic partitions is stored
Metadata_device *string
// the super partition block device list
Block_devices []string
// whether A/B updater is used
Ab_update *bool
// whether dynamic partitions is enabled on devices that were launched without this support
Retrofit *bool
// whether virtual A/B seamless update is enabled
Virtual_ab *bool
// whether retrofitting virtual A/B seamless update is enabled
Virtual_ab_retrofit *bool
// whether the output is a sparse image
Sparse *bool
// information about how partitions within the super partition are grouped together
Partition_groups []PartitionGroupsInfo
// whether dynamic partitions is used
Use_dynamic_partitions *bool
}
type PartitionGroupsInfo struct {
Name string
GroupSize string
PartitionList []string
}
type SuperImagePartitionNameProperties struct {
// Name of the System partition filesystem module
System_partition *string
// Name of the System_ext partition filesystem module
System_ext_partition *string
// Name of the System_dlkm partition filesystem module
System_dlkm_partition *string
// Name of the System_other partition filesystem module
System_other_partition *string
// Name of the Product partition filesystem module
Product_partition *string
// Name of the Vendor partition filesystem module
Vendor_partition *string
// Name of the Vendor_dlkm partition filesystem module
Vendor_dlkm_partition *string
// Name of the Odm partition filesystem module
Odm_partition *string
// Name of the Odm_dlkm partition filesystem module
Odm_dlkm_partition *string
}
func SuperImageFactory() android.Module {
module := &superImage{}
module.AddProperties(&module.properties, &module.partitionProps)
android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
return module
}
type superImageDepTagType struct {
blueprint.BaseDependencyTag
}
var superImageDepTag superImageDepTagType
func (s *superImage) DepsMutator(ctx android.BottomUpMutatorContext) {
addDependencyIfDefined := func(dep *string) {
if dep != nil {
ctx.AddDependency(ctx.Module(), superImageDepTag, proptools.String(dep))
}
}
addDependencyIfDefined(s.partitionProps.System_partition)
addDependencyIfDefined(s.partitionProps.System_ext_partition)
addDependencyIfDefined(s.partitionProps.System_dlkm_partition)
addDependencyIfDefined(s.partitionProps.System_other_partition)
addDependencyIfDefined(s.partitionProps.Product_partition)
addDependencyIfDefined(s.partitionProps.Vendor_partition)
addDependencyIfDefined(s.partitionProps.Vendor_dlkm_partition)
addDependencyIfDefined(s.partitionProps.Odm_partition)
addDependencyIfDefined(s.partitionProps.Odm_dlkm_partition)
}
func (s *superImage) GenerateAndroidBuildActions(ctx android.ModuleContext) {
miscInfo, deps := s.buildMiscInfo(ctx)
builder := android.NewRuleBuilder(pctx, ctx)
output := android.PathForModuleOut(ctx, s.installFileName())
lpMake := ctx.Config().HostToolPath(ctx, "lpmake")
lpMakeDir := filepath.Dir(lpMake.String())
deps = append(deps, lpMake)
builder.Command().Textf("PATH=%s:\\$PATH", lpMakeDir).
BuiltTool("build_super_image").
Text("-v").
Input(miscInfo).
Implicits(deps).
Output(output)
builder.Build("build_super_image", fmt.Sprintf("Creating super image %s", s.BaseModuleName()))
ctx.SetOutputFiles([]android.Path{output}, "")
}
func (s *superImage) installFileName() string {
return s.BaseModuleName() + ".img"
}
func (s *superImage) buildMiscInfo(ctx android.ModuleContext) (android.Path, android.Paths) {
var miscInfoString strings.Builder
addStr := func(name string, value string) {
miscInfoString.WriteString(name)
miscInfoString.WriteRune('=')
miscInfoString.WriteString(value)
miscInfoString.WriteRune('\n')
}
addStr("use_dynamic_partitions", strconv.FormatBool(proptools.Bool(s.properties.Use_dynamic_partitions)))
addStr("dynamic_partition_retrofit", strconv.FormatBool(proptools.Bool(s.properties.Retrofit)))
addStr("lpmake", "lpmake")
addStr("super_metadata_device", proptools.String(s.properties.Metadata_device))
if len(s.properties.Block_devices) > 0 {
addStr("super_block_devices", strings.Join(s.properties.Block_devices, " "))
}
addStr("super_super_device_size", strconv.Itoa(proptools.Int(s.properties.Size)))
var groups, partitionList []string
for _, groupInfo := range s.properties.Partition_groups {
groups = append(groups, groupInfo.Name)
partitionList = append(partitionList, groupInfo.PartitionList...)
addStr("super_"+groupInfo.Name+"_group_size", groupInfo.GroupSize)
addStr("super_"+groupInfo.Name+"_partition_list", strings.Join(groupInfo.PartitionList, " "))
}
addStr("super_partition_groups", strings.Join(groups, " "))
addStr("dynamic_partition_list", strings.Join(partitionList, " "))
addStr("virtual_ab", strconv.FormatBool(proptools.Bool(s.properties.Virtual_ab)))
addStr("virtual_ab_retrofit", strconv.FormatBool(proptools.Bool(s.properties.Virtual_ab_retrofit)))
addStr("ab_update", strconv.FormatBool(proptools.Bool(s.properties.Ab_update)))
addStr("build_non_sparse_super_partition", strconv.FormatBool(!proptools.Bool(s.properties.Sparse)))
partitionToImagePath := make(map[string]string)
nameToPartition := make(map[string]string)
var systemOtherPartitionNameNeeded string
addEntryToPartitionToName := func(p string, s *string) {
if proptools.String(s) != "" {
nameToPartition[*s] = p
}
}
// Build partitionToImagePath, because system partition may need system_other
// partition image path
for _, p := range partitionList {
if _, ok := nameToPartition[p]; ok {
continue
}
switch p {
case "system":
addEntryToPartitionToName(p, s.partitionProps.System_partition)
systemOtherPartitionNameNeeded = proptools.String(s.partitionProps.System_other_partition)
case "system_dlkm":
addEntryToPartitionToName(p, s.partitionProps.System_dlkm_partition)
case "system_ext":
addEntryToPartitionToName(p, s.partitionProps.System_ext_partition)
case "product":
addEntryToPartitionToName(p, s.partitionProps.Product_partition)
case "vendor":
addEntryToPartitionToName(p, s.partitionProps.Vendor_partition)
case "vendor_dlkm":
addEntryToPartitionToName(p, s.partitionProps.Vendor_dlkm_partition)
case "odm":
addEntryToPartitionToName(p, s.partitionProps.Odm_partition)
case "odm_dlkm":
addEntryToPartitionToName(p, s.partitionProps.Odm_dlkm_partition)
default:
ctx.ModuleErrorf("current partition %s not a super image supported partition", p)
}
}
var deps android.Paths
ctx.VisitDirectDeps(func(m android.Module) {
if p, ok := nameToPartition[m.Name()]; ok {
if output, ok := android.OtherModuleProvider(ctx, m, android.OutputFilesProvider); ok {
partitionToImagePath[p] = output.DefaultOutputFiles[0].String()
deps = append(deps, output.DefaultOutputFiles[0])
}
} else if systemOtherPartitionNameNeeded != "" && m.Name() == systemOtherPartitionNameNeeded {
if output, ok := android.OtherModuleProvider(ctx, m, android.OutputFilesProvider); ok {
partitionToImagePath["system_other"] = output.DefaultOutputFiles[0].String()
// TODO: add system_other to deps after it can be generated
// deps = append(deps, output.DefaultOutputFiles[0])
}
}
})
for _, p := range android.SortedKeys(partitionToImagePath) {
addStr(p+"_image", partitionToImagePath[p])
}
miscInfo := android.PathForModuleOut(ctx, "misc_info.txt")
android.WriteFileRule(ctx, miscInfo, miscInfoString.String())
return miscInfo, deps
}