1// Copyright (C) 2019 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 15package apex 16 17import ( 18 "encoding/json" 19 "fmt" 20 "path" 21 "path/filepath" 22 "runtime" 23 "sort" 24 "strconv" 25 "strings" 26 27 "android/soong/aconfig" 28 "android/soong/android" 29 "android/soong/java" 30 31 "github.com/google/blueprint" 32 "github.com/google/blueprint/proptools" 33) 34 35var ( 36 pctx = android.NewPackageContext("android/apex") 37) 38 39func init() { 40 pctx.Import("android/soong/aconfig") 41 pctx.Import("android/soong/android") 42 pctx.Import("android/soong/cc/config") 43 pctx.Import("android/soong/java") 44 pctx.HostBinToolVariable("apexer", "apexer") 45 pctx.HostBinToolVariable("apexer_with_DCLA_preprocessing", "apexer_with_DCLA_preprocessing") 46 47 // ART minimal builds (using the master-art manifest) do not have the "frameworks/base" 48 // projects, and hence cannot build 'aapt2'. Use the SDK prebuilt instead. 49 hostBinToolVariableWithPrebuilt := func(name, prebuiltDir, tool string) { 50 pctx.VariableFunc(name, func(ctx android.PackageVarContext) string { 51 if !ctx.Config().FrameworksBaseDirExists(ctx) { 52 return filepath.Join(prebuiltDir, runtime.GOOS, "bin", tool) 53 } else { 54 return ctx.Config().HostToolPath(ctx, tool).String() 55 } 56 }) 57 } 58 hostBinToolVariableWithPrebuilt("aapt2", "prebuilts/sdk/tools", "aapt2") 59 pctx.HostBinToolVariable("avbtool", "avbtool") 60 pctx.HostBinToolVariable("e2fsdroid", "e2fsdroid") 61 pctx.HostBinToolVariable("merge_zips", "merge_zips") 62 pctx.HostBinToolVariable("mke2fs", "mke2fs") 63 pctx.HostBinToolVariable("resize2fs", "resize2fs") 64 pctx.HostBinToolVariable("sefcontext_compile", "sefcontext_compile") 65 pctx.HostBinToolVariable("soong_zip", "soong_zip") 66 pctx.HostBinToolVariable("zip2zip", "zip2zip") 67 pctx.HostBinToolVariable("zipalign", "zipalign") 68 pctx.HostBinToolVariable("jsonmodify", "jsonmodify") 69 pctx.HostBinToolVariable("conv_apex_manifest", "conv_apex_manifest") 70 pctx.HostBinToolVariable("extract_apks", "extract_apks") 71 pctx.HostBinToolVariable("make_f2fs", "make_f2fs") 72 pctx.HostBinToolVariable("sload_f2fs", "sload_f2fs") 73 pctx.HostBinToolVariable("make_erofs", "make_erofs") 74 pctx.HostBinToolVariable("apex_compression_tool", "apex_compression_tool") 75 pctx.HostBinToolVariable("dexdeps", "dexdeps") 76 pctx.HostBinToolVariable("apex_sepolicy_tests", "apex_sepolicy_tests") 77 pctx.HostBinToolVariable("deapexer", "deapexer") 78 pctx.HostBinToolVariable("debugfs_static", "debugfs_static") 79 pctx.HostBinToolVariable("fsck_erofs", "fsck.erofs") 80 pctx.SourcePathVariable("genNdkUsedbyApexPath", "build/soong/scripts/gen_ndk_usedby_apex.sh") 81 pctx.HostBinToolVariable("conv_linker_config", "conv_linker_config") 82 pctx.HostBinToolVariable("assemble_vintf", "assemble_vintf") 83 pctx.HostBinToolVariable("apex_elf_checker", "apex_elf_checker") 84 pctx.HostBinToolVariable("aconfig", "aconfig") 85 pctx.HostBinToolVariable("host_apex_verifier", "host_apex_verifier") 86} 87 88type createStorageStruct struct { 89 Output_file string 90 Desc string 91 File_type string 92} 93 94var createStorageInfo = []createStorageStruct{ 95 {"package.map", "create_aconfig_package_map_file", "package_map"}, 96 {"flag.map", "create_aconfig_flag_map_file", "flag_map"}, 97 {"flag.val", "create_aconfig_flag_val_file", "flag_val"}, 98 {"flag.info", "create_aconfig_flag_info_file", "flag_info"}, 99} 100 101var ( 102 apexManifestRule = pctx.StaticRule("apexManifestRule", blueprint.RuleParams{ 103 Command: `rm -f $out && ${jsonmodify} $in ` + 104 `-a provideNativeLibs ${provideNativeLibs} ` + 105 `-a requireNativeLibs ${requireNativeLibs} ` + 106 `-se version 0 ${default_version} ` + 107 `${opt} ` + 108 `-o $out`, 109 CommandDeps: []string{"${jsonmodify}"}, 110 Description: "prepare ${out}", 111 }, "provideNativeLibs", "requireNativeLibs", "default_version", "opt") 112 113 stripApexManifestRule = pctx.StaticRule("stripApexManifestRule", blueprint.RuleParams{ 114 Command: `rm -f $out && ${conv_apex_manifest} strip $in -o $out`, 115 CommandDeps: []string{"${conv_apex_manifest}"}, 116 Description: "strip ${in}=>${out}", 117 }) 118 119 pbApexManifestRule = pctx.StaticRule("pbApexManifestRule", blueprint.RuleParams{ 120 Command: `rm -f $out && ${conv_apex_manifest} proto $in -o $out`, 121 CommandDeps: []string{"${conv_apex_manifest}"}, 122 Description: "convert ${in}=>${out}", 123 }) 124 125 // TODO(b/113233103): make sure that file_contexts is as expected, i.e., validate 126 // against the binary policy using sefcontext_compiler -p <policy>. 127 128 // TODO(b/114327326): automate the generation of file_contexts 129 apexRule = pctx.StaticRule("apexRule", blueprint.RuleParams{ 130 Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` + 131 `(. ${out}.copy_commands) && ` + 132 `APEXER_TOOL_PATH=${tool_path} ` + 133 `${apexer} --force --manifest ${manifest} ` + 134 `--file_contexts ${file_contexts} ` + 135 `--canned_fs_config ${canned_fs_config} ` + 136 `--include_build_info ` + 137 `--payload_type image ` + 138 `--key ${key} ${opt_flags} ${image_dir} ${out} `, 139 CommandDeps: []string{"${apexer}", "${avbtool}", "${e2fsdroid}", "${merge_zips}", 140 "${mke2fs}", "${resize2fs}", "${sefcontext_compile}", "${make_f2fs}", "${sload_f2fs}", "${make_erofs}", 141 "${soong_zip}", "${zipalign}", "${aapt2}", "prebuilts/sdk/current/public/android.jar"}, 142 Rspfile: "${out}.copy_commands", 143 RspfileContent: "${copy_commands}", 144 Description: "APEX ${image_dir} => ${out}", 145 }, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key", 146 "opt_flags", "manifest") 147 148 DCLAApexRule = pctx.StaticRule("DCLAApexRule", blueprint.RuleParams{ 149 Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` + 150 `(. ${out}.copy_commands) && ` + 151 `APEXER_TOOL_PATH=${tool_path} ` + 152 `${apexer_with_DCLA_preprocessing} ` + 153 `--apexer ${apexer} ` + 154 `--canned_fs_config ${canned_fs_config} ` + 155 `${image_dir} ` + 156 `${out} ` + 157 `-- ` + 158 `--include_build_info ` + 159 `--force ` + 160 `--payload_type image ` + 161 `--key ${key} ` + 162 `--file_contexts ${file_contexts} ` + 163 `--manifest ${manifest} ` + 164 `${opt_flags} `, 165 CommandDeps: []string{"${apexer_with_DCLA_preprocessing}", "${apexer}", "${avbtool}", "${e2fsdroid}", 166 "${merge_zips}", "${mke2fs}", "${resize2fs}", "${sefcontext_compile}", "${make_f2fs}", 167 "${sload_f2fs}", "${make_erofs}", "${soong_zip}", "${zipalign}", "${aapt2}", 168 "prebuilts/sdk/current/public/android.jar"}, 169 Rspfile: "${out}.copy_commands", 170 RspfileContent: "${copy_commands}", 171 Description: "APEX ${image_dir} => ${out}", 172 }, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key", 173 "opt_flags", "manifest", "is_DCLA") 174 175 apexProtoConvertRule = pctx.AndroidStaticRule("apexProtoConvertRule", 176 blueprint.RuleParams{ 177 Command: `${aapt2} convert --output-format proto $in -o $out`, 178 CommandDeps: []string{"${aapt2}"}, 179 }) 180 181 apexBundleRule = pctx.StaticRule("apexBundleRule", blueprint.RuleParams{ 182 Command: `${zip2zip} -i $in -o $out.base ` + 183 `apex_payload.img:apex/${abi}.img ` + 184 `apex_build_info.pb:apex/${abi}.build_info.pb ` + 185 `apex_manifest.json:root/apex_manifest.json ` + 186 `apex_manifest.pb:root/apex_manifest.pb ` + 187 `AndroidManifest.xml:manifest/AndroidManifest.xml ` + 188 `assets/NOTICE.html.gz:assets/NOTICE.html.gz &&` + 189 `${soong_zip} -o $out.config -C $$(dirname ${config}) -f ${config} && ` + 190 `${merge_zips} $out $out.base $out.config`, 191 CommandDeps: []string{"${zip2zip}", "${soong_zip}", "${merge_zips}"}, 192 Description: "app bundle", 193 }, "abi", "config") 194 195 diffApexContentRule = pctx.StaticRule("diffApexContentRule", blueprint.RuleParams{ 196 Command: `diff --unchanged-group-format='' \` + 197 `--changed-group-format='%<' \` + 198 `${image_content_file} ${allowed_files_file} || (` + 199 `echo "New unexpected files were added to ${apex_module_name}." ` + 200 ` "To fix the build run following command:" && ` + 201 `echo "system/apex/tools/update_allowed_list.sh ${allowed_files_file} ${image_content_file}" && ` + 202 `exit 1); touch ${out}`, 203 Description: "Diff ${image_content_file} and ${allowed_files_file}", 204 }, "image_content_file", "allowed_files_file", "apex_module_name") 205 206 generateAPIsUsedbyApexRule = pctx.StaticRule("generateAPIsUsedbyApexRule", blueprint.RuleParams{ 207 Command: "$genNdkUsedbyApexPath ${image_dir} ${readelf} ${out}", 208 CommandDeps: []string{"${genNdkUsedbyApexPath}"}, 209 Description: "Generate symbol list used by Apex", 210 }, "image_dir", "readelf") 211 212 apexSepolicyTestsRule = pctx.StaticRule("apexSepolicyTestsRule", blueprint.RuleParams{ 213 Command: `${deapexer} --debugfs_path ${debugfs_static} list -Z ${in} > ${out}.fc` + 214 ` && ${apex_sepolicy_tests} -f ${out}.fc && touch ${out}`, 215 CommandDeps: []string{"${apex_sepolicy_tests}", "${deapexer}", "${debugfs_static}"}, 216 Description: "run apex_sepolicy_tests", 217 }) 218 219 apexLinkerconfigValidationRule = pctx.StaticRule("apexLinkerconfigValidationRule", blueprint.RuleParams{ 220 Command: `${conv_linker_config} validate --type apex ${image_dir} && touch ${out}`, 221 CommandDeps: []string{"${conv_linker_config}"}, 222 Description: "run apex_linkerconfig_validation", 223 }, "image_dir") 224 225 apexHostVerifierRule = pctx.StaticRule("apexHostVerifierRule", blueprint.RuleParams{ 226 Command: `${host_apex_verifier} --deapexer=${deapexer} --debugfs=${debugfs_static} ` + 227 `--fsckerofs=${fsck_erofs} --apex=${in} --partition_tag=${partition_tag} && touch ${out}`, 228 CommandDeps: []string{"${host_apex_verifier}", "${deapexer}", "${debugfs_static}", "${fsck_erofs}"}, 229 Description: "run host_apex_verifier", 230 }, "partition_tag") 231 232 assembleVintfRule = pctx.StaticRule("assembleVintfRule", blueprint.RuleParams{ 233 Command: `rm -f $out && VINTF_IGNORE_TARGET_FCM_VERSION=true ${assemble_vintf} -i $in -o $out`, 234 CommandDeps: []string{"${assemble_vintf}"}, 235 Description: "run assemble_vintf", 236 }) 237 238 apexElfCheckerUnwantedRule = pctx.StaticRule("apexElfCheckerUnwantedRule", blueprint.RuleParams{ 239 Command: `${apex_elf_checker} --tool_path ${tool_path} --unwanted ${unwanted} ${in} && touch ${out}`, 240 CommandDeps: []string{"${apex_elf_checker}", "${deapexer}", "${debugfs_static}", "${fsck_erofs}", "${config.ClangBin}/llvm-readelf"}, 241 Description: "run apex_elf_checker --unwanted", 242 }, "tool_path", "unwanted") 243) 244 245func (a *apexBundle) buildAconfigFiles(ctx android.ModuleContext) []apexFile { 246 var aconfigFiles android.Paths 247 for _, file := range a.filesInfo { 248 if file.module == nil { 249 continue 250 } 251 if dep, ok := android.OtherModuleProvider(ctx, file.module, android.AconfigPropagatingProviderKey); ok { 252 if len(dep.AconfigFiles) > 0 && dep.AconfigFiles[ctx.ModuleName()] != nil { 253 aconfigFiles = append(aconfigFiles, dep.AconfigFiles[ctx.ModuleName()]...) 254 } 255 } 256 257 validationFlag := ctx.DeviceConfig().AconfigContainerValidation() 258 if validationFlag == "error" || validationFlag == "warning" { 259 android.VerifyAconfigBuildMode(ctx, ctx.ModuleName(), file.module, validationFlag == "error") 260 } 261 } 262 aconfigFiles = android.FirstUniquePaths(aconfigFiles) 263 264 var files []apexFile 265 if len(aconfigFiles) > 0 { 266 apexAconfigFile := android.PathForModuleOut(ctx, "aconfig_flags.pb") 267 ctx.Build(pctx, android.BuildParams{ 268 Rule: aconfig.AllDeclarationsRule, 269 Inputs: aconfigFiles, 270 Output: apexAconfigFile, 271 Description: "combine_aconfig_declarations", 272 Args: map[string]string{ 273 "cache_files": android.JoinPathsWithPrefix(aconfigFiles, "--cache "), 274 }, 275 }) 276 files = append(files, newApexFile(ctx, apexAconfigFile, "aconfig_flags", "etc", etc, nil)) 277 278 for _, info := range createStorageInfo { 279 outputFile := android.PathForModuleOut(ctx, info.Output_file) 280 ctx.Build(pctx, android.BuildParams{ 281 Rule: aconfig.CreateStorageRule, 282 Inputs: aconfigFiles, 283 Output: outputFile, 284 Description: info.Desc, 285 Args: map[string]string{ 286 "container": ctx.ModuleName(), 287 "file_type": info.File_type, 288 "cache_files": android.JoinPathsWithPrefix(aconfigFiles, "--cache "), 289 }, 290 }) 291 files = append(files, newApexFile(ctx, outputFile, info.File_type, "etc", etc, nil)) 292 } 293 } 294 return files 295} 296 297// buildManifest creates buile rules to modify the input apex_manifest.json to add information 298// gathered by the build system such as provided/required native libraries. Two output files having 299// different formats are generated. a.manifestJsonOut is JSON format for Q devices, and 300// a.manifest.PbOut is protobuf format for R+ devices. 301// TODO(jiyong): make this to return paths instead of directly storing the paths to apexBundle 302func (a *apexBundle) buildManifest(ctx android.ModuleContext, provideNativeLibs, requireNativeLibs []string) { 303 src := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json")) 304 305 // Put dependency({provide|require}NativeLibs) in apex_manifest.json 306 provideNativeLibs = android.SortedUniqueStrings(provideNativeLibs) 307 requireNativeLibs = android.SortedUniqueStrings(android.RemoveListFromList(requireNativeLibs, provideNativeLibs)) 308 309 // VNDK APEX name is determined at runtime, so update "name" in apex_manifest 310 optCommands := []string{} 311 if a.vndkApex { 312 apexName := vndkApexNamePrefix + a.vndkVersion() 313 optCommands = append(optCommands, "-v name "+apexName) 314 } 315 316 // Collect jniLibs. Notice that a.filesInfo is already sorted 317 var jniLibs []string 318 for _, fi := range a.filesInfo { 319 if fi.isJniLib && !android.InList(fi.stem(), jniLibs) { 320 jniLibs = append(jniLibs, fi.stem()) 321 } 322 } 323 if len(jniLibs) > 0 { 324 optCommands = append(optCommands, "-a jniLibs "+strings.Join(jniLibs, " ")) 325 } 326 327 if android.InList(":vndk", requireNativeLibs) { 328 if _, vndkVersion := a.getImageVariationPair(); vndkVersion != "" { 329 optCommands = append(optCommands, "-v vndkVersion "+vndkVersion) 330 } 331 } 332 333 manifestJsonFullOut := android.PathForModuleOut(ctx, "apex_manifest_full.json") 334 defaultVersion := ctx.Config().ReleaseDefaultUpdatableModuleVersion() 335 if a.properties.Variant_version != nil { 336 defaultVersionInt, err := strconv.Atoi(defaultVersion) 337 if err != nil { 338 ctx.ModuleErrorf("expected RELEASE_DEFAULT_UPDATABLE_MODULE_VERSION to be an int, but got %s", defaultVersion) 339 } 340 if defaultVersionInt%10 != 0 { 341 ctx.ModuleErrorf("expected RELEASE_DEFAULT_UPDATABLE_MODULE_VERSION to end in a zero, but got %s", defaultVersion) 342 } 343 variantVersion := []rune(*a.properties.Variant_version) 344 if len(variantVersion) != 1 || variantVersion[0] < '0' || variantVersion[0] > '9' { 345 ctx.PropertyErrorf("variant_version", "expected an integer between 0-9; got %s", *a.properties.Variant_version) 346 } 347 defaultVersionRunes := []rune(defaultVersion) 348 defaultVersionRunes[len(defaultVersion)-1] = []rune(variantVersion)[0] 349 defaultVersion = string(defaultVersionRunes) 350 } 351 if override := ctx.Config().Getenv("OVERRIDE_APEX_MANIFEST_DEFAULT_VERSION"); override != "" { 352 defaultVersion = override 353 } 354 ctx.Build(pctx, android.BuildParams{ 355 Rule: apexManifestRule, 356 Input: src, 357 Output: manifestJsonFullOut, 358 Args: map[string]string{ 359 "provideNativeLibs": strings.Join(provideNativeLibs, " "), 360 "requireNativeLibs": strings.Join(requireNativeLibs, " "), 361 "default_version": defaultVersion, 362 "opt": strings.Join(optCommands, " "), 363 }, 364 }) 365 366 // b/143654022 Q apexd can't understand newly added keys in apex_manifest.json prepare 367 // stripped-down version so that APEX modules built from R+ can be installed to Q 368 minSdkVersion := a.minSdkVersion(ctx) 369 if minSdkVersion.EqualTo(android.SdkVersion_Android10) { 370 a.manifestJsonOut = android.PathForModuleOut(ctx, "apex_manifest.json") 371 ctx.Build(pctx, android.BuildParams{ 372 Rule: stripApexManifestRule, 373 Input: manifestJsonFullOut, 374 Output: a.manifestJsonOut, 375 }) 376 } 377 378 // From R+, protobuf binary format (.pb) is the standard format for apex_manifest 379 a.manifestPbOut = android.PathForModuleOut(ctx, "apex_manifest.pb") 380 ctx.Build(pctx, android.BuildParams{ 381 Rule: pbApexManifestRule, 382 Input: manifestJsonFullOut, 383 Output: a.manifestPbOut, 384 }) 385} 386 387// buildFileContexts create build rules to append an entry for apex_manifest.pb to the file_contexts 388// file for this APEX which is either from /systme/sepolicy/apex/<apexname>-file_contexts or from 389// the file_contexts property of this APEX. This is to make sure that the manifest file is correctly 390// labeled as system_file or vendor_apex_metadata_file. 391func (a *apexBundle) buildFileContexts(ctx android.ModuleContext) android.Path { 392 var fileContexts android.Path 393 var fileContextsDir string 394 isFileContextsModule := false 395 if a.properties.File_contexts == nil { 396 fileContexts = android.PathForSource(ctx, "system/sepolicy/apex", ctx.ModuleName()+"-file_contexts") 397 } else { 398 if m, t := android.SrcIsModuleWithTag(*a.properties.File_contexts); m != "" { 399 isFileContextsModule = true 400 otherModule := android.GetModuleProxyFromPathDep(ctx, m, t) 401 if otherModule != nil { 402 fileContextsDir = ctx.OtherModuleDir(*otherModule) 403 } 404 } 405 fileContexts = android.PathForModuleSrc(ctx, *a.properties.File_contexts) 406 } 407 if fileContextsDir == "" { 408 fileContextsDir = filepath.Dir(fileContexts.String()) 409 } 410 fileContextsDir += string(filepath.Separator) 411 412 if a.Platform() { 413 if !strings.HasPrefix(fileContextsDir, "system/sepolicy/") { 414 ctx.PropertyErrorf("file_contexts", "should be under system/sepolicy, but found in %q", fileContextsDir) 415 } 416 } 417 if !isFileContextsModule && !android.ExistentPathForSource(ctx, fileContexts.String()).Valid() { 418 ctx.PropertyErrorf("file_contexts", "cannot find file_contexts file: %q", fileContexts.String()) 419 } 420 421 useFileContextsAsIs := proptools.Bool(a.properties.Use_file_contexts_as_is) 422 423 output := android.PathForModuleOut(ctx, "file_contexts") 424 rule := android.NewRuleBuilder(pctx, ctx) 425 426 labelForRoot := "u:object_r:system_file:s0" 427 labelForManifest := "u:object_r:system_file:s0" 428 if a.SocSpecific() && !a.vndkApex { 429 // APEX on /vendor should label ./ and ./apex_manifest.pb as vendor file. 430 labelForRoot = "u:object_r:vendor_file:s0" 431 labelForManifest = "u:object_r:vendor_apex_metadata_file:s0" 432 } 433 // remove old file 434 rule.Command().Text("rm").FlagWithOutput("-f ", output) 435 // copy file_contexts 436 rule.Command().Text("cat").Input(fileContexts).Text(">>").Output(output) 437 // new line 438 rule.Command().Text("echo").Text(">>").Output(output) 439 if !useFileContextsAsIs { 440 // force-label /apex_manifest.pb and / 441 rule.Command().Text("echo").Text("/apex_manifest\\\\.pb").Text(labelForManifest).Text(">>").Output(output) 442 rule.Command().Text("echo").Text("/").Text(labelForRoot).Text(">>").Output(output) 443 } 444 445 rule.Build("file_contexts."+a.Name(), "Generate file_contexts") 446 return output 447} 448 449// buildInstalledFilesFile creates a build rule for the installed-files.txt file where the list of 450// files included in this APEX is shown. The text file is dist'ed so that people can see what's 451// included in the APEX without actually downloading and extracting it. 452func (a *apexBundle) buildInstalledFilesFile(ctx android.ModuleContext, builtApex android.Path, imageDir android.Path) android.Path { 453 output := android.PathForModuleOut(ctx, "installed-files.txt") 454 rule := android.NewRuleBuilder(pctx, ctx) 455 rule.Command(). 456 Implicit(builtApex). 457 Text("(cd " + imageDir.String() + " ; "). 458 Text("find . \\( -type f -o -type l \\) -printf \"%s %p\\n\") "). 459 Text(" | sort -nr > "). 460 Output(output) 461 rule.Build("installed-files."+a.Name(), "Installed files") 462 return output 463} 464 465// buildBundleConfig creates a build rule for the bundle config file that will control the bundle 466// creation process. 467func (a *apexBundle) buildBundleConfig(ctx android.ModuleContext) android.Path { 468 output := android.PathForModuleOut(ctx, "bundle_config.json") 469 470 type ApkConfig struct { 471 Package_name string `json:"package_name"` 472 Apk_path string `json:"path"` 473 } 474 config := struct { 475 Compression struct { 476 Uncompressed_glob []string `json:"uncompressed_glob"` 477 } `json:"compression"` 478 Apex_config struct { 479 Apex_embedded_apk_config []ApkConfig `json:"apex_embedded_apk_config,omitempty"` 480 } `json:"apex_config,omitempty"` 481 }{} 482 483 config.Compression.Uncompressed_glob = []string{ 484 "apex_payload.img", 485 "apex_manifest.*", 486 } 487 488 // Collect the manifest names and paths of android apps if their manifest names are 489 // overridden. 490 for _, fi := range a.filesInfo { 491 if fi.class != app && fi.class != appSet { 492 continue 493 } 494 packageName := fi.overriddenPackageName 495 if packageName != "" { 496 config.Apex_config.Apex_embedded_apk_config = append( 497 config.Apex_config.Apex_embedded_apk_config, 498 ApkConfig{ 499 Package_name: packageName, 500 Apk_path: fi.path(), 501 }) 502 } 503 } 504 505 j, err := json.Marshal(config) 506 if err != nil { 507 panic(fmt.Errorf("error while marshalling to %q: %#v", output, err)) 508 } 509 510 android.WriteFileRule(ctx, output, string(j)) 511 512 return output 513} 514 515func markManifestTestOnly(ctx android.ModuleContext, androidManifestFile android.Path) android.Path { 516 return java.ManifestFixer(ctx, androidManifestFile, java.ManifestFixerParams{ 517 TestOnly: true, 518 }) 519} 520 521func isVintfFragment(fi apexFile) bool { 522 isVintfFragment, _ := path.Match("etc/vintf/*", fi.path()) 523 return isVintfFragment 524} 525 526func runAssembleVintf(ctx android.ModuleContext, vintfFragment android.Path) android.Path { 527 processed := android.PathForModuleOut(ctx, "vintf", vintfFragment.Base()) 528 ctx.Build(pctx, android.BuildParams{ 529 Rule: assembleVintfRule, 530 Input: vintfFragment, 531 Output: processed, 532 Description: "run assemble_vintf for VINTF in APEX", 533 }) 534 return processed 535} 536 537// buildApex creates build rules to build an APEX using apexer. 538func (a *apexBundle) buildApex(ctx android.ModuleContext) { 539 suffix := imageApexSuffix 540 apexName := a.BaseModuleName() 541 542 //////////////////////////////////////////////////////////////////////////////////////////// 543 // Step 1: copy built files to appropriate directories under the image directory 544 545 imageDir := android.PathForModuleOut(ctx, "image"+suffix) 546 547 installSymbolFiles := (!ctx.Config().KatiEnabled() || a.ExportedToMake()) && a.installable() 548 549 // set of dependency module:location mappings 550 installMapSet := make(map[string]bool) 551 552 // TODO(jiyong): use the RuleBuilder 553 var copyCommands []string 554 var implicitInputs []android.Path 555 apexDir := android.PathForModuleInPartitionInstall(ctx, "apex", apexName) 556 for _, fi := range a.filesInfo { 557 destPath := imageDir.Join(ctx, fi.path()).String() 558 // Prepare the destination path 559 destPathDir := filepath.Dir(destPath) 560 if fi.class == appSet { 561 copyCommands = append(copyCommands, "rm -rf "+destPathDir) 562 } 563 copyCommands = append(copyCommands, "mkdir -p "+destPathDir) 564 565 installMapPath := fi.builtFile 566 567 // Copy the built file to the directory. But if the symlink optimization is turned 568 // on, place a symlink to the corresponding file in /system partition instead. 569 if a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform() { 570 pathOnDevice := filepath.Join("/", fi.partition, fi.path()) 571 copyCommands = append(copyCommands, "ln -sfn "+pathOnDevice+" "+destPath) 572 } else { 573 // Copy the file into APEX 574 if !a.testApex && isVintfFragment(fi) { 575 // copy the output of assemble_vintf instead of the original 576 vintfFragment := runAssembleVintf(ctx, fi.builtFile) 577 copyCommands = append(copyCommands, "cp -f "+vintfFragment.String()+" "+destPath) 578 implicitInputs = append(implicitInputs, vintfFragment) 579 } else { 580 copyCommands = append(copyCommands, "cp -f "+fi.builtFile.String()+" "+destPath) 581 implicitInputs = append(implicitInputs, fi.builtFile) 582 } 583 584 var installedPath android.InstallPath 585 if fi.class == appSet { 586 // In case of AppSet, we need to copy additional APKs as well. They 587 // are zipped. So we need to unzip them. 588 copyCommands = append(copyCommands, 589 fmt.Sprintf("unzip -qDD -d %s %s", destPathDir, 590 fi.module.(*java.AndroidAppSet).PackedAdditionalOutputs().String())) 591 if installSymbolFiles { 592 installedPath = ctx.InstallFileWithExtraFilesZip(apexDir.Join(ctx, fi.installDir), 593 fi.stem(), fi.builtFile, fi.module.(*java.AndroidAppSet).PackedAdditionalOutputs()) 594 } 595 } else { 596 if installSymbolFiles { 597 // store installedPath. symlinks might be created if required. 598 installedPath = apexDir.Join(ctx, fi.installDir, fi.stem()) 599 } 600 } 601 602 // Create additional symlinks pointing the file inside the APEX (if any). Note that 603 // this is independent from the symlink optimization. 604 for _, symlinkPath := range fi.symlinkPaths() { 605 symlinkDest := imageDir.Join(ctx, symlinkPath).String() 606 copyCommands = append(copyCommands, "ln -sfn "+filepath.Base(destPath)+" "+symlinkDest) 607 if installSymbolFiles { 608 ctx.InstallSymlink(apexDir.Join(ctx, filepath.Dir(symlinkPath)), filepath.Base(symlinkPath), installedPath) 609 } 610 } 611 612 installMapPath = installedPath 613 } 614 615 // Copy the test files (if any) 616 for _, d := range fi.dataPaths { 617 // TODO(eakammer): This is now the third repetition of ~this logic for test paths, refactoring should be possible 618 relPath := d.ToRelativeInstallPath() 619 dataDest := imageDir.Join(ctx, fi.apexRelativePath(relPath)).String() 620 621 copyCommands = append(copyCommands, "cp -f "+d.SrcPath.String()+" "+dataDest) 622 implicitInputs = append(implicitInputs, d.SrcPath) 623 } 624 625 installMapSet[installMapPath.String()+":"+fi.installDir+"/"+fi.builtFile.Base()] = true 626 } 627 628 implicitInputs = append(implicitInputs, a.manifestPbOut) 629 630 if len(installMapSet) > 0 { 631 var installs []string 632 installs = append(installs, android.SortedKeys(installMapSet)...) 633 ctx.SetLicenseInstallMap(installs) 634 } 635 636 //////////////////////////////////////////////////////////////////////////////////////////// 637 // Step 1.a: Write the list of files in this APEX to a txt file and compare it against 638 // the allowed list given via the allowed_files property. Build fails when the two lists 639 // differ. 640 // 641 // TODO(jiyong): consider removing this. Nobody other than com.android.apex.cts.shim.* seems 642 // to be using this at this moment. Furthermore, this looks very similar to what 643 // buildInstalledFilesFile does. At least, move this to somewhere else so that this doesn't 644 // hurt readability. 645 if a.overridableProperties.Allowed_files != nil { 646 // Build content.txt 647 var contentLines []string 648 imageContentFile := android.PathForModuleOut(ctx, "content.txt") 649 contentLines = append(contentLines, "./apex_manifest.pb") 650 minSdkVersion := a.minSdkVersion(ctx) 651 if minSdkVersion.EqualTo(android.SdkVersion_Android10) { 652 contentLines = append(contentLines, "./apex_manifest.json") 653 } 654 for _, fi := range a.filesInfo { 655 contentLines = append(contentLines, "./"+fi.path()) 656 } 657 sort.Strings(contentLines) 658 android.WriteFileRule(ctx, imageContentFile, strings.Join(contentLines, "\n")) 659 implicitInputs = append(implicitInputs, imageContentFile) 660 661 // Compare content.txt against allowed_files. 662 allowedFilesFile := android.PathForModuleSrc(ctx, proptools.String(a.overridableProperties.Allowed_files)) 663 phonyOutput := android.PathForModuleOut(ctx, a.Name()+"-diff-phony-output") 664 ctx.Build(pctx, android.BuildParams{ 665 Rule: diffApexContentRule, 666 Implicits: implicitInputs, 667 Output: phonyOutput, 668 Description: "diff apex image content", 669 Args: map[string]string{ 670 "allowed_files_file": allowedFilesFile.String(), 671 "image_content_file": imageContentFile.String(), 672 "apex_module_name": a.Name(), 673 }, 674 }) 675 implicitInputs = append(implicitInputs, phonyOutput) 676 } 677 678 unsignedOutputFile := android.PathForModuleOut(ctx, a.Name()+suffix+".unsigned") 679 outHostBinDir := ctx.Config().HostToolPath(ctx, "").String() 680 prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin") 681 682 //////////////////////////////////////////////////////////////////////////////////// 683 // Step 2: create canned_fs_config which encodes filemode,uid,gid of each files 684 // in this APEX. The file will be used by apexer in later steps. 685 cannedFsConfig := a.buildCannedFsConfig(ctx) 686 implicitInputs = append(implicitInputs, cannedFsConfig) 687 688 //////////////////////////////////////////////////////////////////////////////////// 689 // Step 3: Prepare option flags for apexer and invoke it to create an unsigned APEX. 690 // TODO(jiyong): use the RuleBuilder 691 optFlags := []string{} 692 693 fileContexts := a.buildFileContexts(ctx) 694 implicitInputs = append(implicitInputs, fileContexts) 695 696 implicitInputs = append(implicitInputs, a.privateKeyFile, a.publicKeyFile) 697 optFlags = append(optFlags, "--pubkey "+a.publicKeyFile.String()) 698 699 manifestPackageName := a.getOverrideManifestPackageName(ctx) 700 if manifestPackageName != "" { 701 optFlags = append(optFlags, "--override_apk_package_name "+manifestPackageName) 702 } 703 704 androidManifest := a.properties.AndroidManifest.GetOrDefault(ctx, "") 705 if androidManifest != "" { 706 androidManifestFile := android.PathForModuleSrc(ctx, androidManifest) 707 708 if a.testApex { 709 androidManifestFile = markManifestTestOnly(ctx, androidManifestFile) 710 } 711 712 implicitInputs = append(implicitInputs, androidManifestFile) 713 optFlags = append(optFlags, "--android_manifest "+androidManifestFile.String()) 714 } else if a.testApex { 715 optFlags = append(optFlags, "--test_only") 716 } 717 718 // Determine target/min sdk version from the context 719 // TODO(jiyong): make this as a function 720 moduleMinSdkVersion := a.minSdkVersion(ctx) 721 minSdkVersion := moduleMinSdkVersion.String() 722 723 // bundletool doesn't understand what "current" is. We need to transform it to 724 // codename 725 if moduleMinSdkVersion.IsCurrent() || moduleMinSdkVersion.IsNone() { 726 minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String() 727 728 if useApiFingerprint, fingerprintMinSdkVersion, fingerprintDeps := 729 java.UseApiFingerprint(ctx); useApiFingerprint { 730 minSdkVersion = fingerprintMinSdkVersion 731 implicitInputs = append(implicitInputs, fingerprintDeps) 732 } 733 } 734 // apex module doesn't have a concept of target_sdk_version, hence for the time 735 // being targetSdkVersion == default targetSdkVersion of the branch. 736 targetSdkVersion := strconv.Itoa(ctx.Config().DefaultAppTargetSdk(ctx).FinalOrFutureInt()) 737 738 if useApiFingerprint, fingerprintTargetSdkVersion, fingerprintDeps := 739 java.UseApiFingerprint(ctx); useApiFingerprint { 740 targetSdkVersion = fingerprintTargetSdkVersion 741 implicitInputs = append(implicitInputs, fingerprintDeps) 742 } 743 optFlags = append(optFlags, "--target_sdk_version "+targetSdkVersion) 744 optFlags = append(optFlags, "--min_sdk_version "+minSdkVersion) 745 746 if a.overridableProperties.Logging_parent != "" { 747 optFlags = append(optFlags, "--logging_parent ", a.overridableProperties.Logging_parent) 748 } 749 750 // Create a NOTICE file, and embed it as an asset file in the APEX. 751 htmlGzNotice := android.PathForModuleOut(ctx, "NOTICE.html.gz") 752 android.BuildNoticeHtmlOutputFromLicenseMetadata( 753 ctx, htmlGzNotice, "", "", 754 []string{ 755 android.PathForModuleInstall(ctx).String() + "/", 756 android.PathForModuleInPartitionInstall(ctx, "apex").String() + "/", 757 }) 758 noticeAssetPath := android.PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz") 759 builder := android.NewRuleBuilder(pctx, ctx) 760 builder.Command().Text("cp"). 761 Input(htmlGzNotice). 762 Output(noticeAssetPath) 763 builder.Build("notice_dir", "Building notice dir") 764 implicitInputs = append(implicitInputs, noticeAssetPath) 765 optFlags = append(optFlags, "--assets_dir "+filepath.Dir(noticeAssetPath.String())) 766 767 if a.testOnlyShouldSkipPayloadSign() { 768 optFlags = append(optFlags, "--unsigned_payload") 769 } 770 771 if moduleMinSdkVersion == android.SdkVersion_Android10 { 772 implicitInputs = append(implicitInputs, a.manifestJsonOut) 773 optFlags = append(optFlags, "--manifest_json "+a.manifestJsonOut.String()) 774 } 775 776 optFlags = append(optFlags, "--payload_fs_type "+a.payloadFsType.string()) 777 778 if a.dynamic_common_lib_apex() { 779 ctx.Build(pctx, android.BuildParams{ 780 Rule: DCLAApexRule, 781 Implicits: implicitInputs, 782 Output: unsignedOutputFile, 783 Description: "apex", 784 Args: map[string]string{ 785 "tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir, 786 "image_dir": imageDir.String(), 787 "copy_commands": strings.Join(copyCommands, " && "), 788 "manifest": a.manifestPbOut.String(), 789 "file_contexts": fileContexts.String(), 790 "canned_fs_config": cannedFsConfig.String(), 791 "key": a.privateKeyFile.String(), 792 "opt_flags": strings.Join(optFlags, " "), 793 }, 794 }) 795 } else { 796 ctx.Build(pctx, android.BuildParams{ 797 Rule: apexRule, 798 Implicits: implicitInputs, 799 Output: unsignedOutputFile, 800 Description: "apex", 801 Args: map[string]string{ 802 "tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir, 803 "image_dir": imageDir.String(), 804 "copy_commands": strings.Join(copyCommands, " && "), 805 "manifest": a.manifestPbOut.String(), 806 "file_contexts": fileContexts.String(), 807 "canned_fs_config": cannedFsConfig.String(), 808 "key": a.privateKeyFile.String(), 809 "opt_flags": strings.Join(optFlags, " "), 810 }, 811 }) 812 } 813 814 // TODO(jiyong): make the two rules below as separate functions 815 apexProtoFile := android.PathForModuleOut(ctx, a.Name()+".pb"+suffix) 816 bundleModuleFile := android.PathForModuleOut(ctx, a.Name()+suffix+"-base.zip") 817 a.bundleModuleFile = bundleModuleFile 818 819 ctx.Build(pctx, android.BuildParams{ 820 Rule: apexProtoConvertRule, 821 Input: unsignedOutputFile, 822 Output: apexProtoFile, 823 Description: "apex proto convert", 824 }) 825 826 implicitInputs = append(implicitInputs, unsignedOutputFile) 827 828 // Run coverage analysis 829 apisUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.txt") 830 ctx.Build(pctx, android.BuildParams{ 831 Rule: generateAPIsUsedbyApexRule, 832 Implicits: implicitInputs, 833 Description: "coverage", 834 Output: apisUsedbyOutputFile, 835 Args: map[string]string{ 836 "image_dir": imageDir.String(), 837 "readelf": "${config.ClangBin}/llvm-readelf", 838 }, 839 }) 840 a.nativeApisUsedByModuleFile = apisUsedbyOutputFile 841 842 var nativeLibNames []string 843 for _, f := range a.filesInfo { 844 if f.class == nativeSharedLib { 845 nativeLibNames = append(nativeLibNames, f.stem()) 846 } 847 } 848 apisBackedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_backing.txt") 849 rb := android.NewRuleBuilder(pctx, ctx) 850 rb.Command(). 851 Tool(android.PathForSource(ctx, "build/soong/scripts/gen_ndk_backedby_apex.sh")). 852 Output(apisBackedbyOutputFile). 853 Flags(nativeLibNames) 854 rb.Build("ndk_backedby_list", "Generate API libraries backed by Apex") 855 a.nativeApisBackedByModuleFile = apisBackedbyOutputFile 856 857 var javaLibOrApkPath []android.Path 858 for _, f := range a.filesInfo { 859 if f.class == javaSharedLib || f.class == app { 860 javaLibOrApkPath = append(javaLibOrApkPath, f.builtFile) 861 } 862 } 863 javaApiUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.xml") 864 javaUsedByRule := android.NewRuleBuilder(pctx, ctx) 865 javaUsedByRule.Command(). 866 Tool(android.PathForSource(ctx, "build/soong/scripts/gen_java_usedby_apex.sh")). 867 BuiltTool("dexdeps"). 868 Output(javaApiUsedbyOutputFile). 869 Inputs(javaLibOrApkPath) 870 javaUsedByRule.Build("java_usedby_list", "Generate Java APIs used by Apex") 871 a.javaApisUsedByModuleFile = javaApiUsedbyOutputFile 872 873 bundleConfig := a.buildBundleConfig(ctx) 874 875 var abis []string 876 for _, target := range ctx.MultiTargets() { 877 if len(target.Arch.Abi) > 0 { 878 abis = append(abis, target.Arch.Abi[0]) 879 } 880 } 881 882 abis = android.FirstUniqueStrings(abis) 883 884 ctx.Build(pctx, android.BuildParams{ 885 Rule: apexBundleRule, 886 Input: apexProtoFile, 887 Implicit: bundleConfig, 888 Output: a.bundleModuleFile, 889 Description: "apex bundle module", 890 Args: map[string]string{ 891 "abi": strings.Join(abis, "."), 892 "config": bundleConfig.String(), 893 }, 894 }) 895 896 //////////////////////////////////////////////////////////////////////////////////// 897 // Step 4: Sign the APEX using signapk 898 signedOutputFile := android.PathForModuleOut(ctx, a.Name()+suffix) 899 900 pem, key := a.getCertificateAndPrivateKey(ctx) 901 rule := java.Signapk 902 args := map[string]string{ 903 "certificates": pem.String() + " " + key.String(), 904 "flags": "-a 4096 --align-file-size", //alignment 905 } 906 implicits := android.Paths{pem, key} 907 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_SIGNAPK") { 908 rule = java.SignapkRE 909 args["implicits"] = strings.Join(implicits.Strings(), ",") 910 args["outCommaList"] = signedOutputFile.String() 911 } 912 var validations android.Paths 913 validations = append(validations, runApexLinkerconfigValidation(ctx, unsignedOutputFile, imageDir)) 914 // TODO(b/279688635) deapexer supports [ext4] 915 if !a.skipValidation(apexSepolicyTests) && suffix == imageApexSuffix && ext4 == a.payloadFsType { 916 validations = append(validations, runApexSepolicyTests(ctx, unsignedOutputFile)) 917 } 918 if !a.testApex && len(a.properties.Unwanted_transitive_deps) > 0 { 919 validations = append(validations, 920 runApexElfCheckerUnwanted(ctx, unsignedOutputFile, a.properties.Unwanted_transitive_deps)) 921 } 922 if !a.skipValidation(hostApexVerifier) && android.InList(a.payloadFsType, []fsType{ext4, erofs}) { 923 validations = append(validations, runApexHostVerifier(ctx, a, unsignedOutputFile)) 924 } 925 ctx.Build(pctx, android.BuildParams{ 926 Rule: rule, 927 Description: "signapk", 928 Output: signedOutputFile, 929 Input: unsignedOutputFile, 930 Implicits: implicits, 931 Args: args, 932 Validations: validations, 933 }) 934 if suffix == imageApexSuffix { 935 a.outputApexFile = signedOutputFile 936 } 937 a.outputFile = signedOutputFile 938 939 if ctx.ModuleDir() != "system/apex/apexd/apexd_testdata" && a.testOnlyShouldForceCompression() { 940 ctx.PropertyErrorf("test_only_force_compression", "not available") 941 return 942 } 943 944 installSuffix := suffix 945 a.setCompression(ctx) 946 if a.isCompressed { 947 unsignedCompressedOutputFile := android.PathForModuleOut(ctx, a.Name()+imageCapexSuffix+".unsigned") 948 949 compressRule := android.NewRuleBuilder(pctx, ctx) 950 compressRule.Command(). 951 Text("rm"). 952 FlagWithOutput("-f ", unsignedCompressedOutputFile) 953 compressRule.Command(). 954 BuiltTool("apex_compression_tool"). 955 Flag("compress"). 956 FlagWithArg("--apex_compression_tool ", outHostBinDir+":"+prebuiltSdkToolsBinDir). 957 FlagWithInput("--input ", signedOutputFile). 958 FlagWithOutput("--output ", unsignedCompressedOutputFile) 959 compressRule.Build("compressRule", "Generate unsigned compressed APEX file") 960 961 signedCompressedOutputFile := android.PathForModuleOut(ctx, a.Name()+imageCapexSuffix) 962 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_SIGNAPK") { 963 args["outCommaList"] = signedCompressedOutputFile.String() 964 } 965 ctx.Build(pctx, android.BuildParams{ 966 Rule: rule, 967 Description: "sign compressedApex", 968 Output: signedCompressedOutputFile, 969 Input: unsignedCompressedOutputFile, 970 Implicits: implicits, 971 Args: args, 972 }) 973 a.outputFile = signedCompressedOutputFile 974 installSuffix = imageCapexSuffix 975 } 976 977 if !a.installable() { 978 a.SkipInstall() 979 } 980 981 // Install to $OUT/soong/{target,host}/.../apex. 982 a.installedFile = ctx.InstallFile(a.installDir, a.Name()+installSuffix, a.outputFile, 983 a.compatSymlinks...) 984 985 // installed-files.txt is dist'ed 986 a.installedFilesFile = a.buildInstalledFilesFile(ctx, a.outputFile, imageDir) 987 988 a.apexKeysPath = writeApexKeys(ctx, a) 989} 990 991// getCertificateAndPrivateKey retrieves the cert and the private key that will be used to sign 992// the zip container of this APEX. See the description of the 'certificate' property for how 993// the cert and the private key are found. 994func (a *apexBundle) getCertificateAndPrivateKey(ctx android.PathContext) (pem, key android.Path) { 995 if a.containerCertificateFile != nil { 996 return a.containerCertificateFile, a.containerPrivateKeyFile 997 } 998 999 cert := String(a.overridableProperties.Certificate) 1000 if cert == "" { 1001 return ctx.Config().DefaultAppCertificate(ctx) 1002 } 1003 1004 defaultDir := ctx.Config().DefaultAppCertificateDir(ctx) 1005 pem = defaultDir.Join(ctx, cert+".x509.pem") 1006 key = defaultDir.Join(ctx, cert+".pk8") 1007 return pem, key 1008} 1009 1010func (a *apexBundle) getOverrideManifestPackageName(ctx android.ModuleContext) string { 1011 // For VNDK APEXes, check "com.android.vndk" in PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES 1012 // to see if it should be overridden because their <apex name> is dynamically generated 1013 // according to its VNDK version. 1014 if a.vndkApex { 1015 overrideName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(vndkApexName) 1016 if overridden { 1017 return overrideName + ".v" + a.vndkVersion() 1018 } 1019 return "" 1020 } 1021 packageNameFromProp := a.overridableProperties.Package_name.GetOrDefault(ctx, "") 1022 if packageNameFromProp != "" { 1023 return packageNameFromProp 1024 } 1025 manifestPackageName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(ctx.ModuleName()) 1026 if overridden { 1027 return manifestPackageName 1028 } 1029 return "" 1030} 1031 1032func (a *apexBundle) buildApexDependencyInfo(ctx android.ModuleContext) { 1033 if a.properties.IsCoverageVariant { 1034 // Otherwise, we will have duplicated rules for coverage and 1035 // non-coverage variants of the same APEX 1036 return 1037 } 1038 1039 depInfos := android.DepNameToDepInfoMap{} 1040 a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool { 1041 if from.Name() == to.Name() { 1042 // This can happen for cc.reuseObjTag. We are not interested in tracking this. 1043 // As soon as the dependency graph crosses the APEX boundary, don't go further. 1044 return !externalDep 1045 } 1046 1047 // Skip dependencies that are only available to APEXes; they are developed with updatability 1048 // in mind and don't need manual approval. 1049 if to.(android.ApexModule).NotAvailableForPlatform() { 1050 return !externalDep 1051 } 1052 1053 depTag := ctx.OtherModuleDependencyTag(to) 1054 // Check to see if dependency been marked to skip the dependency check 1055 if skipDepCheck, ok := depTag.(android.SkipApexAllowedDependenciesCheck); ok && skipDepCheck.SkipApexAllowedDependenciesCheck() { 1056 return !externalDep 1057 } 1058 1059 if info, exists := depInfos[to.Name()]; exists { 1060 if !android.InList(from.Name(), info.From) { 1061 info.From = append(info.From, from.Name()) 1062 } 1063 info.IsExternal = info.IsExternal && externalDep 1064 depInfos[to.Name()] = info 1065 } else { 1066 toMinSdkVersion := "(no version)" 1067 if m, ok := to.(interface { 1068 MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel 1069 }); ok { 1070 if v := m.MinSdkVersion(ctx); !v.IsNone() { 1071 toMinSdkVersion = v.String() 1072 } 1073 } else if m, ok := to.(interface{ MinSdkVersion() string }); ok { 1074 // TODO(b/175678607) eliminate the use of MinSdkVersion returning 1075 // string 1076 if v := m.MinSdkVersion(); v != "" { 1077 toMinSdkVersion = v 1078 } 1079 } 1080 depInfos[to.Name()] = android.ApexModuleDepInfo{ 1081 To: to.Name(), 1082 From: []string{from.Name()}, 1083 IsExternal: externalDep, 1084 MinSdkVersion: toMinSdkVersion, 1085 } 1086 } 1087 1088 // As soon as the dependency graph crosses the APEX boundary, don't go further. 1089 return !externalDep 1090 }) 1091 1092 a.ApexBundleDepsInfo.BuildDepsInfoLists(ctx, a.MinSdkVersion(ctx).String(), depInfos) 1093 1094 ctx.Build(pctx, android.BuildParams{ 1095 Rule: android.Phony, 1096 Output: android.PathForPhony(ctx, a.Name()+"-deps-info"), 1097 Inputs: []android.Path{ 1098 a.ApexBundleDepsInfo.FullListPath(), 1099 a.ApexBundleDepsInfo.FlatListPath(), 1100 }, 1101 }) 1102} 1103 1104func (a *apexBundle) buildLintReports(ctx android.ModuleContext) { 1105 depSetsBuilder := java.NewLintDepSetBuilder() 1106 for _, fi := range a.filesInfo { 1107 if fi.lintInfo != nil { 1108 depSetsBuilder.Transitive(fi.lintInfo) 1109 } 1110 } 1111 1112 depSets := depSetsBuilder.Build() 1113 var validations android.Paths 1114 1115 if a.checkStrictUpdatabilityLinting(ctx) { 1116 baselines := depSets.Baseline.ToList() 1117 if len(baselines) > 0 { 1118 outputFile := java.VerifyStrictUpdatabilityChecks(ctx, baselines) 1119 validations = append(validations, outputFile) 1120 } 1121 } 1122 1123 a.lintReports = java.BuildModuleLintReportZips(ctx, depSets, validations) 1124} 1125 1126func (a *apexBundle) buildCannedFsConfig(ctx android.ModuleContext) android.Path { 1127 var readOnlyPaths = []string{"apex_manifest.json", "apex_manifest.pb"} 1128 var executablePaths []string // this also includes dirs 1129 var appSetDirs []string 1130 appSetFiles := make(map[string]android.Path) 1131 for _, f := range a.filesInfo { 1132 pathInApex := f.path() 1133 if f.installDir == "bin" || strings.HasPrefix(f.installDir, "bin/") { 1134 executablePaths = append(executablePaths, pathInApex) 1135 for _, d := range f.dataPaths { 1136 rel := d.ToRelativeInstallPath() 1137 readOnlyPaths = append(readOnlyPaths, filepath.Join(f.installDir, rel)) 1138 } 1139 for _, s := range f.symlinks { 1140 executablePaths = append(executablePaths, filepath.Join(f.installDir, s)) 1141 } 1142 } else if f.class == appSet { 1143 // base APK 1144 readOnlyPaths = append(readOnlyPaths, pathInApex) 1145 // Additional APKs 1146 appSetDirs = append(appSetDirs, f.installDir) 1147 appSetFiles[f.installDir] = f.module.(*java.AndroidAppSet).PackedAdditionalOutputs() 1148 } else { 1149 readOnlyPaths = append(readOnlyPaths, pathInApex) 1150 } 1151 dir := f.installDir 1152 for !android.InList(dir, executablePaths) && dir != "" { 1153 executablePaths = append(executablePaths, dir) 1154 dir, _ = filepath.Split(dir) // move up to the parent 1155 if len(dir) > 0 { 1156 // remove trailing slash 1157 dir = dir[:len(dir)-1] 1158 } 1159 } 1160 } 1161 sort.Strings(readOnlyPaths) 1162 sort.Strings(executablePaths) 1163 sort.Strings(appSetDirs) 1164 1165 cannedFsConfig := android.PathForModuleOut(ctx, "canned_fs_config") 1166 builder := android.NewRuleBuilder(pctx, ctx) 1167 cmd := builder.Command() 1168 cmd.Text("(") 1169 cmd.Text("echo '/ 1000 1000 0755';") 1170 for _, p := range readOnlyPaths { 1171 cmd.Textf("echo '/%s 1000 1000 0644';", p) 1172 } 1173 for _, p := range executablePaths { 1174 cmd.Textf("echo '/%s 0 2000 0755';", p) 1175 } 1176 for _, dir := range appSetDirs { 1177 cmd.Textf("echo '/%s 0 2000 0755';", dir) 1178 file := appSetFiles[dir] 1179 cmd.Text("zipinfo -1").Input(file).Textf(`| sed "s:\(.*\):/%s/\1 1000 1000 0644:";`, dir) 1180 } 1181 // Custom fs_config is "appended" to the last so that entries from the file are preferred 1182 // over default ones set above. 1183 customFsConfig := a.properties.Canned_fs_config.GetOrDefault(ctx, "") 1184 if customFsConfig != "" { 1185 cmd.Text("cat").Input(android.PathForModuleSrc(ctx, customFsConfig)) 1186 } 1187 cmd.Text(")").FlagWithOutput("> ", cannedFsConfig) 1188 builder.Build("generateFsConfig", fmt.Sprintf("Generating canned fs config for %s", a.BaseModuleName())) 1189 1190 return cannedFsConfig 1191} 1192 1193func runApexLinkerconfigValidation(ctx android.ModuleContext, apexFile android.Path, imageDir android.Path) android.Path { 1194 timestamp := android.PathForModuleOut(ctx, "apex_linkerconfig_validation.timestamp") 1195 ctx.Build(pctx, android.BuildParams{ 1196 Rule: apexLinkerconfigValidationRule, 1197 Input: apexFile, 1198 Output: timestamp, 1199 Args: map[string]string{ 1200 "image_dir": imageDir.String(), 1201 }, 1202 }) 1203 return timestamp 1204} 1205 1206// Runs apex_sepolicy_tests 1207// 1208// $ deapexer list -Z {apex_file} > {file_contexts} 1209// $ apex_sepolicy_tests -f {file_contexts} 1210func runApexSepolicyTests(ctx android.ModuleContext, apexFile android.Path) android.Path { 1211 timestamp := android.PathForModuleOut(ctx, "apex_sepolicy_tests.timestamp") 1212 ctx.Build(pctx, android.BuildParams{ 1213 Rule: apexSepolicyTestsRule, 1214 Input: apexFile, 1215 Output: timestamp, 1216 }) 1217 return timestamp 1218} 1219 1220func runApexElfCheckerUnwanted(ctx android.ModuleContext, apexFile android.Path, unwanted []string) android.Path { 1221 timestamp := android.PathForModuleOut(ctx, "apex_elf_unwanted.timestamp") 1222 ctx.Build(pctx, android.BuildParams{ 1223 Rule: apexElfCheckerUnwantedRule, 1224 Input: apexFile, 1225 Output: timestamp, 1226 Args: map[string]string{ 1227 "unwanted": android.JoinWithSuffixAndSeparator(unwanted, ".so", ":"), 1228 "tool_path": ctx.Config().HostToolPath(ctx, "").String() + ":${config.ClangBin}", 1229 }, 1230 }) 1231 return timestamp 1232} 1233 1234func runApexHostVerifier(ctx android.ModuleContext, a *apexBundle, apexFile android.Path) android.Path { 1235 timestamp := android.PathForModuleOut(ctx, "host_apex_verifier.timestamp") 1236 ctx.Build(pctx, android.BuildParams{ 1237 Rule: apexHostVerifierRule, 1238 Input: apexFile, 1239 Output: timestamp, 1240 Args: map[string]string{ 1241 "partition_tag": a.PartitionTag(ctx.DeviceConfig()), 1242 }, 1243 }) 1244 return timestamp 1245} 1246