// Copyright (C) 2020 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 gki import ( "fmt" "io" "android/soong/android" "android/soong/apex" "github.com/google/blueprint/proptools" ) var ( prebuiltApexTag = dependencyTag{name: "prebuilt_apex"} ) type prebuiltGkiApexProperties struct { apex.PrebuiltProperties // Declared KMI version of the boot image. Example: "5.4-android12-0" Kmi_version *string } type prebuiltGkiApex struct { android.ModuleBase properties prebuiltGkiApexProperties extractedBootImage android.WritablePath } func init() { android.RegisterModuleType("prebuilt_gki_apex", prebuiltGkiApexFactory) } // Declare a prebuilt GKI APEX. When installed, the boot image is extracted from // the module. func prebuiltGkiApexFactory() android.Module { g := &prebuiltGkiApex{} g.AddProperties(&g.properties) android.InitAndroidModule(g) android.AddLoadHook(g, func(ctx android.LoadHookContext) { prebuiltGkiApexMutator(ctx, g) }) return g } func prebuiltGkiApexMutator(mctx android.LoadHookContext, g *prebuiltGkiApex) { // Whether modules should be enabled according to board variables. enabled := boardDefinesKmiVersion(mctx, proptools.String(g.properties.Kmi_version)) if !enabled { g.Disable() } // The prebuilt_apex module. mctx.CreateModule(apex.PrebuiltFactory, &moduleCommonProperties{ Name: proptools.StringPtr(g.BaseModuleName()), Enabled: proptools.BoolPtr(enabled), Product_specific: proptools.BoolPtr(true), }, &g.properties.PrebuiltProperties) } // The appeared name of this prebuiltGkiApex object. Exposed to Soong to avoid conflicting with // the generated prebuilt_apex module with name BaseModuleName(). func (g *prebuiltGkiApex) Name() string { return g.BaseModuleName() + "_boot_img" } func (g *prebuiltGkiApex) DepsMutator(ctx android.BottomUpMutatorContext) { ctx.AddDependency(ctx.Module(), prebuiltApexTag, g.BaseModuleName()) } func (g *prebuiltGkiApex) GenerateAndroidBuildActions(ctx android.ModuleContext) { var apexFile android.OptionalPath ctx.VisitDirectDepsWithTag(prebuiltApexTag, func(m android.Module) { if prebuiltApex, ok := m.(*apex.Prebuilt); ok { srcFiles, err := prebuiltApex.OutputFiles("") if err != nil { ctx.ModuleErrorf("Cannot get output files from %q: %s", ctx.OtherModuleName(m), err) } else if len(srcFiles) != 1 { ctx.ModuleErrorf("%q generated %d files", ctx.OtherModuleName(m), len(srcFiles)) } else { apexFile = android.OptionalPathForPath(srcFiles[0]) } } else { ctx.ModuleErrorf("%q is not a prebuilt_apex", ctx.OtherModuleName(m)) } }) if !apexFile.Valid() { ctx.ModuleErrorf("Can't determine the prebuilt APEX file") return } genDir := android.PathForModuleOut(ctx, "extracted") g.extractedBootImage = genDir.Join(ctx, "boot.img") rule := android.NewRuleBuilder(pctx, ctx) rule.Command(). ImplicitOutput(g.extractedBootImage). BuiltTool("extract_img_from_apex"). Flag("--tool").BuiltTool("debugfs"). Flag("--tool").BuiltTool("delta_generator"). Input(apexFile.Path()). Text(genDir.String()) rule.Build("extractImgFromApex", "Extract boot image from prebuilt GKI APEX") ctx.Phony(g.BaseModuleName(), g.extractedBootImage) } func (g *prebuiltGkiApex) AndroidMk() android.AndroidMkData { return android.AndroidMkData{ Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) { fmt.Fprintf(w, "ALL_MODULES.%s.EXTRACTED_BOOT_IMAGE := %s\n", name, g.extractedBootImage) }, } }