Yifan Hong | 0cd10dd | 2018-10-12 13:08:52 -0700 | [diff] [blame] | 1 | // Copyright (C) 2018 The Android Open Source Project |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | package vintf |
| 16 | |
| 17 | import ( |
| 18 | "fmt" |
| 19 | "io" |
| 20 | "strings" |
| 21 | |
| 22 | "github.com/google/blueprint" |
| 23 | "github.com/google/blueprint/proptools" |
| 24 | |
| 25 | "android/soong/android" |
| 26 | "android/soong/kernel/configs" |
Bill Yang | b7995ac | 2024-09-05 09:22:09 +0000 | [diff] [blame^] | 27 | "android/soong/selinux" |
Yifan Hong | 0cd10dd | 2018-10-12 13:08:52 -0700 | [diff] [blame] | 28 | ) |
| 29 | |
| 30 | type dependencyTag struct { |
| 31 | blueprint.BaseDependencyTag |
| 32 | name string |
| 33 | } |
| 34 | |
| 35 | var ( |
| 36 | pctx = android.NewPackageContext("android/vintf") |
| 37 | |
| 38 | assembleVintfRule = pctx.AndroidStaticRule("assemble_vintf", blueprint.RuleParams{ |
Bill Yang | b7995ac | 2024-09-05 09:22:09 +0000 | [diff] [blame^] | 39 | Command: `${assembleVintfEnv} ${assembleVintfCmd} -i ${inputs} -o ${out} ${extraArgs}`, |
| 40 | CommandDeps: []string{"${assembleVintfCmd}", "${AvbToolCmd}"}, |
Yifan Hong | 0cd10dd | 2018-10-12 13:08:52 -0700 | [diff] [blame] | 41 | Description: "assemble_vintf -i ${inputs}", |
Bill Yang | b7995ac | 2024-09-05 09:22:09 +0000 | [diff] [blame^] | 42 | }, "inputs", "extraArgs", "assembleVintfEnv") |
Yifan Hong | 0cd10dd | 2018-10-12 13:08:52 -0700 | [diff] [blame] | 43 | |
Yifan Hong | fca5d95 | 2020-04-10 16:42:50 -0700 | [diff] [blame] | 44 | xmllintXsd = pctx.AndroidStaticRule("xmllint-xsd", blueprint.RuleParams{ |
Yifan Hong | 5a6c7b1 | 2021-02-24 17:58:17 -0800 | [diff] [blame] | 45 | Command: `$XmlLintCmd --quiet --schema $xsd $in > /dev/null && touch -a $out`, |
Yifan Hong | fca5d95 | 2020-04-10 16:42:50 -0700 | [diff] [blame] | 46 | CommandDeps: []string{"$XmlLintCmd"}, |
| 47 | Restat: true, |
| 48 | }, "xsd") |
| 49 | |
| 50 | kernelConfigTag = dependencyTag{name: "kernel-config"} |
| 51 | schemaTag = dependencyTag{name: "matrix-schema"} |
| 52 | schemaModuleName = "compatibility_matrix_schema" |
Yifan Hong | 0cd10dd | 2018-10-12 13:08:52 -0700 | [diff] [blame] | 53 | ) |
| 54 | |
| 55 | const ( |
Bill Yang | b7995ac | 2024-09-05 09:22:09 +0000 | [diff] [blame^] | 56 | relpath = "vintf" |
| 57 | emptyManifest = "hardware/interfaces/compatibility_matrices/manifest.empty.xml" |
| 58 | compatibilityEmptyMatrix = "hardware/interfaces/compatibility_matrices/compatibility_matrix.empty.xml" |
| 59 | deviceFcmType = "device_fcm" |
| 60 | productFcmType = "product_fcm" |
Yifan Hong | 0cd10dd | 2018-10-12 13:08:52 -0700 | [diff] [blame] | 61 | ) |
| 62 | |
| 63 | type vintfCompatibilityMatrixProperties struct { |
| 64 | // set the name of the output |
| 65 | Stem *string |
| 66 | |
| 67 | // list of source compatibility matrix XML files |
| 68 | Srcs []string |
| 69 | |
| 70 | // list of kernel_config modules to be combined to final output |
| 71 | Kernel_configs []string |
Bill Yang | b7995ac | 2024-09-05 09:22:09 +0000 | [diff] [blame^] | 72 | |
| 73 | // Type of the FCM type, the allowed type are device_fcm and product_fcm and it should only be used under hardware/interfaces/compatibility_matrices |
| 74 | Type *string |
Yifan Hong | 0cd10dd | 2018-10-12 13:08:52 -0700 | [diff] [blame] | 75 | } |
| 76 | |
| 77 | type vintfCompatibilityMatrixRule struct { |
| 78 | android.ModuleBase |
| 79 | properties vintfCompatibilityMatrixProperties |
| 80 | |
Yifan Hong | fca5d95 | 2020-04-10 16:42:50 -0700 | [diff] [blame] | 81 | genFile android.WritablePath |
| 82 | additionalDependencies android.WritablePaths |
Bill Yang | b7995ac | 2024-09-05 09:22:09 +0000 | [diff] [blame^] | 83 | phonyOnly bool |
Yifan Hong | 0cd10dd | 2018-10-12 13:08:52 -0700 | [diff] [blame] | 84 | } |
| 85 | |
| 86 | func init() { |
| 87 | pctx.HostBinToolVariable("assembleVintfCmd", "assemble_vintf") |
Yifan Hong | fca5d95 | 2020-04-10 16:42:50 -0700 | [diff] [blame] | 88 | pctx.HostBinToolVariable("XmlLintCmd", "xmllint") |
Bill Yang | b7995ac | 2024-09-05 09:22:09 +0000 | [diff] [blame^] | 89 | pctx.HostBinToolVariable("AvbToolCmd", "avbtool") |
Yifan Hong | 0cd10dd | 2018-10-12 13:08:52 -0700 | [diff] [blame] | 90 | android.RegisterModuleType("vintf_compatibility_matrix", vintfCompatibilityMatrixFactory) |
| 91 | } |
| 92 | |
| 93 | func vintfCompatibilityMatrixFactory() android.Module { |
| 94 | g := &vintfCompatibilityMatrixRule{} |
| 95 | g.AddProperties(&g.properties) |
| 96 | android.InitAndroidArchModule(g, android.DeviceSupported, android.MultilibCommon) |
| 97 | return g |
| 98 | } |
| 99 | |
| 100 | var _ android.AndroidMkDataProvider = (*vintfCompatibilityMatrixRule)(nil) |
| 101 | |
| 102 | func (g *vintfCompatibilityMatrixRule) DepsMutator(ctx android.BottomUpMutatorContext) { |
| 103 | android.ExtractSourcesDeps(ctx, g.properties.Srcs) |
| 104 | ctx.AddDependency(ctx.Module(), kernelConfigTag, g.properties.Kernel_configs...) |
Yifan Hong | fca5d95 | 2020-04-10 16:42:50 -0700 | [diff] [blame] | 105 | ctx.AddDependency(ctx.Module(), schemaTag, schemaModuleName) |
| 106 | } |
| 107 | |
| 108 | func (g *vintfCompatibilityMatrixRule) timestampFilePath(ctx android.ModuleContext, path android.Path) android.WritablePath { |
| 109 | return android.GenPathWithExt(ctx, "vintf-xmllint", path, "ts") |
| 110 | } |
| 111 | |
| 112 | func (g *vintfCompatibilityMatrixRule) generateValidateBuildAction(ctx android.ModuleContext, path android.Path, schema android.Path) { |
| 113 | timestamp := g.timestampFilePath(ctx, path) |
| 114 | ctx.Build(pctx, android.BuildParams{ |
| 115 | Rule: xmllintXsd, |
| 116 | Description: "xmllint-xsd", |
| 117 | Input: path, |
| 118 | Output: timestamp, |
| 119 | Implicit: schema, |
| 120 | Args: map[string]string{ |
| 121 | "xsd": schema.String(), |
| 122 | }, |
| 123 | }) |
| 124 | g.additionalDependencies = append(g.additionalDependencies, timestamp) |
| 125 | } |
| 126 | |
| 127 | func (g *vintfCompatibilityMatrixRule) getSchema(ctx android.ModuleContext) android.OptionalPath { |
| 128 | schemaModule := ctx.GetDirectDepWithTag(schemaModuleName, schemaTag) |
| 129 | sfp, ok := schemaModule.(android.SourceFileProducer) |
| 130 | if !ok { |
| 131 | ctx.ModuleErrorf("Implicit dependency %q has no srcs", ctx.OtherModuleName(schemaModule)) |
| 132 | return android.OptionalPath{} |
| 133 | } |
| 134 | |
| 135 | schemaSrcs := sfp.Srcs() |
| 136 | if len(schemaSrcs) != 1 { |
| 137 | ctx.PropertyErrorf(`srcs of implicit dependency %q has length %d != 1`, ctx.OtherModuleName(schemaModule), len(schemaSrcs)) |
| 138 | return android.OptionalPath{} |
| 139 | } |
| 140 | return android.OptionalPathForPath(schemaSrcs[0]) |
Yifan Hong | 0cd10dd | 2018-10-12 13:08:52 -0700 | [diff] [blame] | 141 | } |
| 142 | |
| 143 | func (g *vintfCompatibilityMatrixRule) GenerateAndroidBuildActions(ctx android.ModuleContext) { |
Bill Yang | b7995ac | 2024-09-05 09:22:09 +0000 | [diff] [blame^] | 144 | // Types attribute only allow `device_fcm` or `product_fcm` if set and only restricted it being used under |
| 145 | // `hardware/interfaces/compatibility_matrices` to prevent accidental external usages. |
| 146 | matrixType := proptools.String(g.properties.Type) |
| 147 | if matrixType != "" { |
| 148 | if matrixType != deviceFcmType && matrixType != productFcmType { |
| 149 | panic(fmt.Errorf("The attribute 'type' value must be either 'device_fcm' or 'product_fcm' if set!")) |
| 150 | } |
| 151 | if !strings.HasPrefix(android.PathForModuleSrc(ctx).String(), "hardware/interfaces/compatibility_matrices") { |
| 152 | panic(fmt.Errorf("Attribute type can only be set for module under `hardware/interfaces/compatibility_matrices`!")) |
| 153 | } |
| 154 | if (len(g.properties.Srcs) + len(g.properties.Kernel_configs)) > 0 { |
| 155 | panic(fmt.Errorf("Attribute 'type' and 'srcs' or 'kernel_configs' should not set simultaneously! To update inputs for this rule, edit vintf_compatibility_matrix.go directly.")) |
| 156 | } |
| 157 | } |
Yifan Hong | 0cd10dd | 2018-10-12 13:08:52 -0700 | [diff] [blame] | 158 | |
| 159 | outputFilename := proptools.String(g.properties.Stem) |
| 160 | if outputFilename == "" { |
| 161 | outputFilename = g.Name() |
| 162 | } |
| 163 | |
Yifan Hong | fca5d95 | 2020-04-10 16:42:50 -0700 | [diff] [blame] | 164 | schema := g.getSchema(ctx) |
| 165 | if !schema.Valid() { |
| 166 | return |
| 167 | } |
| 168 | |
Yifan Hong | 0cd10dd | 2018-10-12 13:08:52 -0700 | [diff] [blame] | 169 | inputPaths := android.PathsForModuleSrc(ctx, g.properties.Srcs) |
Yifan Hong | fca5d95 | 2020-04-10 16:42:50 -0700 | [diff] [blame] | 170 | for _, srcPath := range inputPaths { |
| 171 | g.generateValidateBuildAction(ctx, srcPath, schema.Path()) |
| 172 | } |
| 173 | |
| 174 | // No need to validate matrices from kernel configs because they are generated by |
| 175 | // assemble_vintf. |
Yifan Hong | 0cd10dd | 2018-10-12 13:08:52 -0700 | [diff] [blame] | 176 | ctx.VisitDirectDepsWithTag(kernelConfigTag, func(m android.Module) { |
| 177 | if k, ok := m.(*configs.KernelConfigRule); ok { |
| 178 | inputPaths = append(inputPaths, k.OutputPath()) |
| 179 | } else { |
Steven Moreland | 3f40b2b | 2021-05-21 20:25:47 +0000 | [diff] [blame] | 180 | ctx.PropertyErrorf("kernel_configs", |
Yifan Hong | 0cd10dd | 2018-10-12 13:08:52 -0700 | [diff] [blame] | 181 | "module %q is not a kernel_config", ctx.OtherModuleName(m)) |
| 182 | } |
| 183 | }) |
| 184 | |
Bill Yang | b7995ac | 2024-09-05 09:22:09 +0000 | [diff] [blame^] | 185 | // For product_compatibility_matrix.xml the source is from the product configuration |
| 186 | // DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE. |
| 187 | extraArgs := []string{} |
| 188 | if matrixType == productFcmType { |
| 189 | productMatrixs := android.PathsForSource(ctx, ctx.Config().DeviceProductCompatibilityMatrixFile()) |
| 190 | if len(productMatrixs) > 0 { |
| 191 | inputPaths = append(inputPaths, productMatrixs...) |
| 192 | extraArgs = append(extraArgs, "-c", android.PathForSource(ctx, emptyManifest).String()) |
| 193 | } else { |
| 194 | // For product_fcm, if DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE not set, treat it as a phony target without any output generated. |
| 195 | g.phonyOnly = true |
| 196 | return |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | // For framework_compatibility_matrix.device.xml the source may come from the product configuration |
| 201 | // DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE or use compatibilityEmptyMatrix if not set. We can't |
| 202 | // use a phony target because we still need to install framework_compatibility_matrix.device.xml to |
| 203 | // include sepolicy versions. |
| 204 | frameworkRuleImplicits := []android.Path{} |
| 205 | |
| 206 | if matrixType == deviceFcmType { |
| 207 | frameworkMatrixs := android.PathsForSource(ctx, ctx.Config().DeviceFrameworkCompatibilityMatrixFile()) |
| 208 | if len(frameworkMatrixs) > 0 { |
| 209 | inputPaths = append(inputPaths, frameworkMatrixs...) |
| 210 | |
| 211 | // Generate BuildAction for generating the check manifest. |
| 212 | emptyManifestPath := android.PathForSource(ctx, emptyManifest) |
| 213 | genCheckManifest := android.PathForModuleGen(ctx, "manifest.check.xml") |
| 214 | checkManifestInputs := []android.Path{emptyManifestPath} |
| 215 | genCheckManifestEnvs := []string{ |
| 216 | "BOARD_SEPOLICY_VERS=" + ctx.DeviceConfig().BoardSepolicyVers(), |
| 217 | "VINTF_IGNORE_TARGET_FCM_VERSION=true", |
| 218 | } |
| 219 | |
| 220 | ctx.Build(pctx, android.BuildParams{ |
| 221 | Rule: assembleVintfRule, |
| 222 | Description: "Framework Check Manifest", |
| 223 | Implicits: checkManifestInputs, |
| 224 | Output: genCheckManifest, |
| 225 | Args: map[string]string{ |
| 226 | "inputs": android.PathForSource(ctx, emptyManifest).String(), |
| 227 | "extraArgs": "", |
| 228 | "assembleVintfEnv": strings.Join(genCheckManifestEnvs, " "), |
| 229 | }, |
| 230 | }) |
| 231 | |
| 232 | frameworkRuleImplicits = append(frameworkRuleImplicits, genCheckManifest) |
| 233 | extraArgs = append(extraArgs, "-c", genCheckManifest.String()) |
| 234 | } else { |
| 235 | inputPaths = append(inputPaths, android.PathForSource(ctx, compatibilityEmptyMatrix)) |
| 236 | } |
| 237 | } |
| 238 | |
Yifan Hong | 0cd10dd | 2018-10-12 13:08:52 -0700 | [diff] [blame] | 239 | g.genFile = android.PathForModuleGen(ctx, outputFilename) |
Bill Yang | b7995ac | 2024-09-05 09:22:09 +0000 | [diff] [blame^] | 240 | frameworkRuleImplicits = append(frameworkRuleImplicits, inputPaths...) |
Yifan Hong | 0cd10dd | 2018-10-12 13:08:52 -0700 | [diff] [blame] | 241 | |
| 242 | ctx.Build(pctx, android.BuildParams{ |
| 243 | Rule: assembleVintfRule, |
| 244 | Description: "Framework Compatibility Matrix", |
Bill Yang | b7995ac | 2024-09-05 09:22:09 +0000 | [diff] [blame^] | 245 | Implicits: frameworkRuleImplicits, |
Yifan Hong | 0cd10dd | 2018-10-12 13:08:52 -0700 | [diff] [blame] | 246 | Output: g.genFile, |
| 247 | Args: map[string]string{ |
Bill Yang | b7995ac | 2024-09-05 09:22:09 +0000 | [diff] [blame^] | 248 | "inputs": strings.Join(inputPaths.Strings(), ":"), |
| 249 | "extraArgs": strings.Join(extraArgs, " "), |
| 250 | "assembleVintfEnv": g.getAssembleVintfEnv(ctx), |
Yifan Hong | 0cd10dd | 2018-10-12 13:08:52 -0700 | [diff] [blame] | 251 | }, |
| 252 | }) |
Yifan Hong | fca5d95 | 2020-04-10 16:42:50 -0700 | [diff] [blame] | 253 | g.generateValidateBuildAction(ctx, g.genFile, schema.Path()) |
Yifan Hong | 0cd10dd | 2018-10-12 13:08:52 -0700 | [diff] [blame] | 254 | |
| 255 | ctx.InstallFile(android.PathForModuleInstall(ctx, "etc", relpath), outputFilename, g.genFile) |
| 256 | } |
| 257 | |
Bill Yang | b7995ac | 2024-09-05 09:22:09 +0000 | [diff] [blame^] | 258 | func (g *vintfCompatibilityMatrixRule) getAssembleVintfEnv(ctx android.ModuleContext) string { |
| 259 | if proptools.String(g.properties.Type) == deviceFcmType { |
| 260 | assembleVintfEnvs := []string{ |
| 261 | // POLICYVERS defined in system/sepolicy/build/soong/policy.go |
| 262 | fmt.Sprintf("POLICYVERS=%d", selinux.PolicyVers), |
| 263 | fmt.Sprintf("PLATFORM_SEPOLICY_VERSION=%s", ctx.DeviceConfig().PlatformSepolicyVersion()), |
| 264 | fmt.Sprintf("PLATFORM_SEPOLICY_COMPAT_VERSIONS=\"%s\"", strings.Join(ctx.DeviceConfig().PlatformSepolicyCompatVersions(), " ")), |
| 265 | } |
| 266 | |
| 267 | if ctx.Config().BoardAvbEnable() { |
| 268 | assembleVintfEnvs = append(assembleVintfEnvs, fmt.Sprintf("FRAMEWORK_VBMETA_VERSION=\"$$(${AvbToolCmd} add_hashtree_footer --print_required_libavb_version %s)\"", strings.Join(ctx.Config().BoardAvbSystemAddHashtreeFooterArgs(), " "))) |
| 269 | } else { |
| 270 | assembleVintfEnvs = append(assembleVintfEnvs, "FRAMEWORK_VBMETA_VERSION=\"0.0\"") |
| 271 | } |
| 272 | |
| 273 | return strings.Join(assembleVintfEnvs, " ") |
| 274 | } |
| 275 | |
| 276 | return "" |
| 277 | } |
| 278 | |
Yifan Hong | 0cd10dd | 2018-10-12 13:08:52 -0700 | [diff] [blame] | 279 | func (g *vintfCompatibilityMatrixRule) AndroidMk() android.AndroidMkData { |
Bill Yang | b7995ac | 2024-09-05 09:22:09 +0000 | [diff] [blame^] | 280 | if g.phonyOnly { |
| 281 | return android.AndroidMkData{ |
| 282 | Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) { |
| 283 | fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)", " # vintf.vintf_compatibility_matrix") |
| 284 | fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir) |
| 285 | fmt.Fprintln(w, "LOCAL_MODULE :=", name) |
| 286 | fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)") |
| 287 | }, |
| 288 | } |
| 289 | } |
| 290 | |
Yifan Hong | 0cd10dd | 2018-10-12 13:08:52 -0700 | [diff] [blame] | 291 | return android.AndroidMkData{ |
| 292 | Class: "ETC", |
| 293 | OutputFile: android.OptionalPathForPath(g.genFile), |
| 294 | Extra: []android.AndroidMkExtraFunc{ |
| 295 | func(w io.Writer, outputFile android.Path) { |
| 296 | fmt.Fprintln(w, "LOCAL_MODULE_RELATIVE_PATH :=", relpath) |
| 297 | if proptools.String(g.properties.Stem) != "" { |
| 298 | fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", proptools.String(g.properties.Stem)) |
| 299 | } |
Yifan Hong | fca5d95 | 2020-04-10 16:42:50 -0700 | [diff] [blame] | 300 | for _, path := range g.additionalDependencies { |
| 301 | fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES +=", path.String()) |
| 302 | } |
Yifan Hong | 0cd10dd | 2018-10-12 13:08:52 -0700 | [diff] [blame] | 303 | }, |
| 304 | }, |
| 305 | } |
| 306 | } |