builder.go 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085
  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. package apex
  15. import (
  16. "encoding/json"
  17. "fmt"
  18. "path/filepath"
  19. "runtime"
  20. "sort"
  21. "strconv"
  22. "strings"
  23. "android/soong/android"
  24. "android/soong/java"
  25. "github.com/google/blueprint"
  26. "github.com/google/blueprint/proptools"
  27. )
  28. var (
  29. pctx = android.NewPackageContext("android/apex")
  30. )
  31. func init() {
  32. pctx.Import("android/soong/android")
  33. pctx.Import("android/soong/cc/config")
  34. pctx.Import("android/soong/java")
  35. pctx.HostBinToolVariable("apexer", "apexer")
  36. // ART minimal builds (using the master-art manifest) do not have the "frameworks/base"
  37. // projects, and hence cannot build 'aapt2'. Use the SDK prebuilt instead.
  38. hostBinToolVariableWithPrebuilt := func(name, prebuiltDir, tool string) {
  39. pctx.VariableFunc(name, func(ctx android.PackageVarContext) string {
  40. if !ctx.Config().FrameworksBaseDirExists(ctx) {
  41. return filepath.Join(prebuiltDir, runtime.GOOS, "bin", tool)
  42. } else {
  43. return ctx.Config().HostToolPath(ctx, tool).String()
  44. }
  45. })
  46. }
  47. hostBinToolVariableWithPrebuilt("aapt2", "prebuilts/sdk/tools", "aapt2")
  48. pctx.HostBinToolVariable("avbtool", "avbtool")
  49. pctx.HostBinToolVariable("e2fsdroid", "e2fsdroid")
  50. pctx.HostBinToolVariable("merge_zips", "merge_zips")
  51. pctx.HostBinToolVariable("mke2fs", "mke2fs")
  52. pctx.HostBinToolVariable("resize2fs", "resize2fs")
  53. pctx.HostBinToolVariable("sefcontext_compile", "sefcontext_compile")
  54. pctx.HostBinToolVariable("soong_zip", "soong_zip")
  55. pctx.HostBinToolVariable("zip2zip", "zip2zip")
  56. pctx.HostBinToolVariable("zipalign", "zipalign")
  57. pctx.HostBinToolVariable("jsonmodify", "jsonmodify")
  58. pctx.HostBinToolVariable("conv_apex_manifest", "conv_apex_manifest")
  59. pctx.HostBinToolVariable("extract_apks", "extract_apks")
  60. pctx.HostBinToolVariable("make_f2fs", "make_f2fs")
  61. pctx.HostBinToolVariable("sload_f2fs", "sload_f2fs")
  62. pctx.HostBinToolVariable("make_erofs", "make_erofs")
  63. pctx.HostBinToolVariable("apex_compression_tool", "apex_compression_tool")
  64. pctx.HostBinToolVariable("dexdeps", "dexdeps")
  65. pctx.SourcePathVariable("genNdkUsedbyApexPath", "build/soong/scripts/gen_ndk_usedby_apex.sh")
  66. }
  67. var (
  68. apexManifestRule = pctx.StaticRule("apexManifestRule", blueprint.RuleParams{
  69. Command: `rm -f $out && ${jsonmodify} $in ` +
  70. `-a provideNativeLibs ${provideNativeLibs} ` +
  71. `-a requireNativeLibs ${requireNativeLibs} ` +
  72. `-se version 0 ${default_version} ` +
  73. `${opt} ` +
  74. `-o $out`,
  75. CommandDeps: []string{"${jsonmodify}"},
  76. Description: "prepare ${out}",
  77. }, "provideNativeLibs", "requireNativeLibs", "default_version", "opt")
  78. stripApexManifestRule = pctx.StaticRule("stripApexManifestRule", blueprint.RuleParams{
  79. Command: `rm -f $out && ${conv_apex_manifest} strip $in -o $out`,
  80. CommandDeps: []string{"${conv_apex_manifest}"},
  81. Description: "strip ${in}=>${out}",
  82. })
  83. pbApexManifestRule = pctx.StaticRule("pbApexManifestRule", blueprint.RuleParams{
  84. Command: `rm -f $out && ${conv_apex_manifest} proto $in -o $out`,
  85. CommandDeps: []string{"${conv_apex_manifest}"},
  86. Description: "convert ${in}=>${out}",
  87. })
  88. // TODO(b/113233103): make sure that file_contexts is as expected, i.e., validate
  89. // against the binary policy using sefcontext_compiler -p <policy>.
  90. // TODO(b/114327326): automate the generation of file_contexts
  91. apexRule = pctx.StaticRule("apexRule", blueprint.RuleParams{
  92. Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
  93. `(. ${out}.copy_commands) && ` +
  94. `APEXER_TOOL_PATH=${tool_path} ` +
  95. `${apexer} --force --manifest ${manifest} ` +
  96. `--file_contexts ${file_contexts} ` +
  97. `--canned_fs_config ${canned_fs_config} ` +
  98. `--include_build_info ` +
  99. `--payload_type image ` +
  100. `--key ${key} ${opt_flags} ${image_dir} ${out} `,
  101. CommandDeps: []string{"${apexer}", "${avbtool}", "${e2fsdroid}", "${merge_zips}",
  102. "${mke2fs}", "${resize2fs}", "${sefcontext_compile}", "${make_f2fs}", "${sload_f2fs}", "${make_erofs}",
  103. "${soong_zip}", "${zipalign}", "${aapt2}", "prebuilts/sdk/current/public/android.jar"},
  104. Rspfile: "${out}.copy_commands",
  105. RspfileContent: "${copy_commands}",
  106. Description: "APEX ${image_dir} => ${out}",
  107. }, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key", "opt_flags", "manifest", "payload_fs_type")
  108. zipApexRule = pctx.StaticRule("zipApexRule", blueprint.RuleParams{
  109. Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
  110. `(. ${out}.copy_commands) && ` +
  111. `APEXER_TOOL_PATH=${tool_path} ` +
  112. `${apexer} --force --manifest ${manifest} ` +
  113. `--payload_type zip ` +
  114. `${image_dir} ${out} `,
  115. CommandDeps: []string{"${apexer}", "${merge_zips}", "${soong_zip}", "${zipalign}", "${aapt2}"},
  116. Rspfile: "${out}.copy_commands",
  117. RspfileContent: "${copy_commands}",
  118. Description: "ZipAPEX ${image_dir} => ${out}",
  119. }, "tool_path", "image_dir", "copy_commands", "manifest")
  120. apexProtoConvertRule = pctx.AndroidStaticRule("apexProtoConvertRule",
  121. blueprint.RuleParams{
  122. Command: `${aapt2} convert --output-format proto $in -o $out`,
  123. CommandDeps: []string{"${aapt2}"},
  124. })
  125. apexBundleRule = pctx.StaticRule("apexBundleRule", blueprint.RuleParams{
  126. Command: `${zip2zip} -i $in -o $out.base ` +
  127. `apex_payload.img:apex/${abi}.img ` +
  128. `apex_build_info.pb:apex/${abi}.build_info.pb ` +
  129. `apex_manifest.json:root/apex_manifest.json ` +
  130. `apex_manifest.pb:root/apex_manifest.pb ` +
  131. `AndroidManifest.xml:manifest/AndroidManifest.xml ` +
  132. `assets/NOTICE.html.gz:assets/NOTICE.html.gz &&` +
  133. `${soong_zip} -o $out.config -C $$(dirname ${config}) -f ${config} && ` +
  134. `${merge_zips} $out $out.base $out.config`,
  135. CommandDeps: []string{"${zip2zip}", "${soong_zip}", "${merge_zips}"},
  136. Description: "app bundle",
  137. }, "abi", "config")
  138. emitApexContentRule = pctx.StaticRule("emitApexContentRule", blueprint.RuleParams{
  139. Command: `rm -f ${out} && touch ${out} && (. ${out}.emit_commands)`,
  140. Rspfile: "${out}.emit_commands",
  141. RspfileContent: "${emit_commands}",
  142. Description: "Emit APEX image content",
  143. }, "emit_commands")
  144. diffApexContentRule = pctx.StaticRule("diffApexContentRule", blueprint.RuleParams{
  145. Command: `diff --unchanged-group-format='' \` +
  146. `--changed-group-format='%<' \` +
  147. `${image_content_file} ${allowed_files_file} || (` +
  148. `echo -e "New unexpected files were added to ${apex_module_name}." ` +
  149. ` "To fix the build run following command:" && ` +
  150. `echo "system/apex/tools/update_allowed_list.sh ${allowed_files_file} ${image_content_file}" && ` +
  151. `exit 1); touch ${out}`,
  152. Description: "Diff ${image_content_file} and ${allowed_files_file}",
  153. }, "image_content_file", "allowed_files_file", "apex_module_name")
  154. generateAPIsUsedbyApexRule = pctx.StaticRule("generateAPIsUsedbyApexRule", blueprint.RuleParams{
  155. Command: "$genNdkUsedbyApexPath ${image_dir} ${readelf} ${out}",
  156. CommandDeps: []string{"${genNdkUsedbyApexPath}"},
  157. Description: "Generate symbol list used by Apex",
  158. }, "image_dir", "readelf")
  159. // Don't add more rules here. Consider using android.NewRuleBuilder instead.
  160. )
  161. // buildManifest creates buile rules to modify the input apex_manifest.json to add information
  162. // gathered by the build system such as provided/required native libraries. Two output files having
  163. // different formats are generated. a.manifestJsonOut is JSON format for Q devices, and
  164. // a.manifest.PbOut is protobuf format for R+ devices.
  165. // TODO(jiyong): make this to return paths instead of directly storing the paths to apexBundle
  166. func (a *apexBundle) buildManifest(ctx android.ModuleContext, provideNativeLibs, requireNativeLibs []string) {
  167. src := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))
  168. // Put dependency({provide|require}NativeLibs) in apex_manifest.json
  169. provideNativeLibs = android.SortedUniqueStrings(provideNativeLibs)
  170. requireNativeLibs = android.SortedUniqueStrings(android.RemoveListFromList(requireNativeLibs, provideNativeLibs))
  171. // APEX name can be overridden
  172. optCommands := []string{}
  173. if a.properties.Apex_name != nil {
  174. optCommands = append(optCommands, "-v name "+*a.properties.Apex_name)
  175. }
  176. // Collect jniLibs. Notice that a.filesInfo is already sorted
  177. var jniLibs []string
  178. for _, fi := range a.filesInfo {
  179. if fi.isJniLib && !android.InList(fi.stem(), jniLibs) {
  180. jniLibs = append(jniLibs, fi.stem())
  181. }
  182. }
  183. if len(jniLibs) > 0 {
  184. optCommands = append(optCommands, "-a jniLibs "+strings.Join(jniLibs, " "))
  185. }
  186. manifestJsonFullOut := android.PathForModuleOut(ctx, "apex_manifest_full.json")
  187. ctx.Build(pctx, android.BuildParams{
  188. Rule: apexManifestRule,
  189. Input: src,
  190. Output: manifestJsonFullOut,
  191. Args: map[string]string{
  192. "provideNativeLibs": strings.Join(provideNativeLibs, " "),
  193. "requireNativeLibs": strings.Join(requireNativeLibs, " "),
  194. "default_version": android.DefaultUpdatableModuleVersion,
  195. "opt": strings.Join(optCommands, " "),
  196. },
  197. })
  198. // b/143654022 Q apexd can't understand newly added keys in apex_manifest.json prepare
  199. // stripped-down version so that APEX modules built from R+ can be installed to Q
  200. minSdkVersion := a.minSdkVersion(ctx)
  201. if minSdkVersion.EqualTo(android.SdkVersion_Android10) {
  202. a.manifestJsonOut = android.PathForModuleOut(ctx, "apex_manifest.json")
  203. ctx.Build(pctx, android.BuildParams{
  204. Rule: stripApexManifestRule,
  205. Input: manifestJsonFullOut,
  206. Output: a.manifestJsonOut,
  207. })
  208. }
  209. // From R+, protobuf binary format (.pb) is the standard format for apex_manifest
  210. a.manifestPbOut = android.PathForModuleOut(ctx, "apex_manifest.pb")
  211. ctx.Build(pctx, android.BuildParams{
  212. Rule: pbApexManifestRule,
  213. Input: manifestJsonFullOut,
  214. Output: a.manifestPbOut,
  215. })
  216. }
  217. // buildFileContexts create build rules to append an entry for apex_manifest.pb to the file_contexts
  218. // file for this APEX which is either from /systme/sepolicy/apex/<apexname>-file_contexts or from
  219. // the file_contexts property of this APEX. This is to make sure that the manifest file is correctly
  220. // labeled as system_file.
  221. func (a *apexBundle) buildFileContexts(ctx android.ModuleContext) android.OutputPath {
  222. var fileContexts android.Path
  223. var fileContextsDir string
  224. if a.properties.File_contexts == nil {
  225. fileContexts = android.PathForSource(ctx, "system/sepolicy/apex", ctx.ModuleName()+"-file_contexts")
  226. } else {
  227. if m, t := android.SrcIsModuleWithTag(*a.properties.File_contexts); m != "" {
  228. otherModule := android.GetModuleFromPathDep(ctx, m, t)
  229. fileContextsDir = ctx.OtherModuleDir(otherModule)
  230. }
  231. fileContexts = android.PathForModuleSrc(ctx, *a.properties.File_contexts)
  232. }
  233. if fileContextsDir == "" {
  234. fileContextsDir = filepath.Dir(fileContexts.String())
  235. }
  236. fileContextsDir += string(filepath.Separator)
  237. if a.Platform() {
  238. if !strings.HasPrefix(fileContextsDir, "system/sepolicy/") {
  239. ctx.PropertyErrorf("file_contexts", "should be under system/sepolicy, but found in %q", fileContextsDir)
  240. }
  241. }
  242. if !android.ExistentPathForSource(ctx, fileContexts.String()).Valid() {
  243. ctx.PropertyErrorf("file_contexts", "cannot find file_contexts file: %q", fileContexts.String())
  244. }
  245. output := android.PathForModuleOut(ctx, "file_contexts")
  246. rule := android.NewRuleBuilder(pctx, ctx)
  247. switch a.properties.ApexType {
  248. case imageApex:
  249. // remove old file
  250. rule.Command().Text("rm").FlagWithOutput("-f ", output)
  251. // copy file_contexts
  252. rule.Command().Text("cat").Input(fileContexts).Text(">>").Output(output)
  253. // new line
  254. rule.Command().Text("echo").Text(">>").Output(output)
  255. // force-label /apex_manifest.pb and / as system_file so that apexd can read them
  256. rule.Command().Text("echo").Flag("/apex_manifest\\\\.pb u:object_r:system_file:s0").Text(">>").Output(output)
  257. rule.Command().Text("echo").Flag("/ u:object_r:system_file:s0").Text(">>").Output(output)
  258. case flattenedApex:
  259. // For flattened apexes, install path should be prepended.
  260. // File_contexts file should be emiited to make via LOCAL_FILE_CONTEXTS
  261. // so that it can be merged into file_contexts.bin
  262. apexPath := android.InstallPathToOnDevicePath(ctx, a.installDir.Join(ctx, a.Name()))
  263. apexPath = strings.ReplaceAll(apexPath, ".", `\\.`)
  264. // remove old file
  265. rule.Command().Text("rm").FlagWithOutput("-f ", output)
  266. // copy file_contexts
  267. rule.Command().Text("awk").Text(`'/object_r/{printf("` + apexPath + `%s\n", $0)}'`).Input(fileContexts).Text(">").Output(output)
  268. // new line
  269. rule.Command().Text("echo").Text(">>").Output(output)
  270. // force-label /apex_manifest.pb and / as system_file so that apexd can read them
  271. rule.Command().Text("echo").Flag(apexPath + `/apex_manifest\\.pb u:object_r:system_file:s0`).Text(">>").Output(output)
  272. rule.Command().Text("echo").Flag(apexPath + "/ u:object_r:system_file:s0").Text(">>").Output(output)
  273. default:
  274. panic(fmt.Errorf("unsupported type %v", a.properties.ApexType))
  275. }
  276. rule.Build("file_contexts."+a.Name(), "Generate file_contexts")
  277. return output.OutputPath
  278. }
  279. // buildInstalledFilesFile creates a build rule for the installed-files.txt file where the list of
  280. // files included in this APEX is shown. The text file is dist'ed so that people can see what's
  281. // included in the APEX without actually downloading and extracting it.
  282. func (a *apexBundle) buildInstalledFilesFile(ctx android.ModuleContext, builtApex android.Path, imageDir android.Path) android.OutputPath {
  283. output := android.PathForModuleOut(ctx, "installed-files.txt")
  284. rule := android.NewRuleBuilder(pctx, ctx)
  285. rule.Command().
  286. Implicit(builtApex).
  287. Text("(cd " + imageDir.String() + " ; ").
  288. Text("find . \\( -type f -o -type l \\) -printf \"%s %p\\n\") ").
  289. Text(" | sort -nr > ").
  290. Output(output)
  291. rule.Build("installed-files."+a.Name(), "Installed files")
  292. return output.OutputPath
  293. }
  294. // buildBundleConfig creates a build rule for the bundle config file that will control the bundle
  295. // creation process.
  296. func (a *apexBundle) buildBundleConfig(ctx android.ModuleContext) android.OutputPath {
  297. output := android.PathForModuleOut(ctx, "bundle_config.json")
  298. type ApkConfig struct {
  299. Package_name string `json:"package_name"`
  300. Apk_path string `json:"path"`
  301. }
  302. config := struct {
  303. Compression struct {
  304. Uncompressed_glob []string `json:"uncompressed_glob"`
  305. } `json:"compression"`
  306. Apex_config struct {
  307. Apex_embedded_apk_config []ApkConfig `json:"apex_embedded_apk_config,omitempty"`
  308. } `json:"apex_config,omitempty"`
  309. }{}
  310. config.Compression.Uncompressed_glob = []string{
  311. "apex_payload.img",
  312. "apex_manifest.*",
  313. }
  314. // Collect the manifest names and paths of android apps if their manifest names are
  315. // overridden.
  316. for _, fi := range a.filesInfo {
  317. if fi.class != app && fi.class != appSet {
  318. continue
  319. }
  320. packageName := fi.overriddenPackageName
  321. if packageName != "" {
  322. config.Apex_config.Apex_embedded_apk_config = append(
  323. config.Apex_config.Apex_embedded_apk_config,
  324. ApkConfig{
  325. Package_name: packageName,
  326. Apk_path: fi.path(),
  327. })
  328. }
  329. }
  330. j, err := json.Marshal(config)
  331. if err != nil {
  332. panic(fmt.Errorf("error while marshalling to %q: %#v", output, err))
  333. }
  334. android.WriteFileRule(ctx, output, string(j))
  335. return output.OutputPath
  336. }
  337. func markManifestTestOnly(ctx android.ModuleContext, androidManifestFile android.Path) android.Path {
  338. return java.ManifestFixer(ctx, androidManifestFile, java.ManifestFixerParams{
  339. TestOnly: true,
  340. })
  341. }
  342. // buildUnflattendApex creates build rules to build an APEX using apexer.
  343. func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
  344. apexType := a.properties.ApexType
  345. suffix := apexType.suffix()
  346. apexName := proptools.StringDefault(a.properties.Apex_name, a.BaseModuleName())
  347. ////////////////////////////////////////////////////////////////////////////////////////////
  348. // Step 1: copy built files to appropriate directories under the image directory
  349. imageDir := android.PathForModuleOut(ctx, "image"+suffix)
  350. installSymbolFiles := (!ctx.Config().KatiEnabled() || a.ExportedToMake()) && a.installable()
  351. // b/140136207. When there are overriding APEXes for a VNDK APEX, the symbols file for the overridden
  352. // APEX and the overriding APEX will have the same installation paths at /apex/com.android.vndk.v<ver>
  353. // as their apexName will be the same. To avoid the path conflicts, skip installing the symbol files
  354. // for the overriding VNDK APEXes.
  355. if a.vndkApex && len(a.overridableProperties.Overrides) > 0 {
  356. installSymbolFiles = false
  357. }
  358. // Avoid creating duplicate build rules for multi-installed APEXes.
  359. if proptools.BoolDefault(a.properties.Multi_install_skip_symbol_files, false) {
  360. installSymbolFiles = false
  361. }
  362. // set of dependency module:location mappings
  363. installMapSet := make(map[string]bool)
  364. // TODO(jiyong): use the RuleBuilder
  365. var copyCommands []string
  366. var implicitInputs []android.Path
  367. pathWhenActivated := android.PathForModuleInPartitionInstall(ctx, "apex", apexName)
  368. for _, fi := range a.filesInfo {
  369. destPath := imageDir.Join(ctx, fi.path()).String()
  370. // Prepare the destination path
  371. destPathDir := filepath.Dir(destPath)
  372. if fi.class == appSet {
  373. copyCommands = append(copyCommands, "rm -rf "+destPathDir)
  374. }
  375. copyCommands = append(copyCommands, "mkdir -p "+destPathDir)
  376. installMapPath := fi.builtFile
  377. // Copy the built file to the directory. But if the symlink optimization is turned
  378. // on, place a symlink to the corresponding file in /system partition instead.
  379. if a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform() {
  380. // TODO(jiyong): pathOnDevice should come from fi.module, not being calculated here
  381. pathOnDevice := filepath.Join("/system", fi.path())
  382. copyCommands = append(copyCommands, "ln -sfn "+pathOnDevice+" "+destPath)
  383. } else {
  384. var installedPath android.InstallPath
  385. if fi.class == appSet {
  386. copyCommands = append(copyCommands,
  387. fmt.Sprintf("unzip -qDD -d %s %s", destPathDir,
  388. fi.module.(*java.AndroidAppSet).PackedAdditionalOutputs().String()))
  389. if installSymbolFiles {
  390. installedPath = ctx.InstallFileWithExtraFilesZip(pathWhenActivated.Join(ctx, fi.installDir),
  391. fi.stem(), fi.builtFile, fi.module.(*java.AndroidAppSet).PackedAdditionalOutputs())
  392. }
  393. } else {
  394. copyCommands = append(copyCommands, "cp -f "+fi.builtFile.String()+" "+destPath)
  395. if installSymbolFiles {
  396. installedPath = ctx.InstallFile(pathWhenActivated.Join(ctx, fi.installDir), fi.stem(), fi.builtFile)
  397. }
  398. }
  399. implicitInputs = append(implicitInputs, fi.builtFile)
  400. if installSymbolFiles {
  401. implicitInputs = append(implicitInputs, installedPath)
  402. }
  403. // Create additional symlinks pointing the file inside the APEX (if any). Note that
  404. // this is independent from the symlink optimization.
  405. for _, symlinkPath := range fi.symlinkPaths() {
  406. symlinkDest := imageDir.Join(ctx, symlinkPath).String()
  407. copyCommands = append(copyCommands, "ln -sfn "+filepath.Base(destPath)+" "+symlinkDest)
  408. if installSymbolFiles {
  409. installedSymlink := ctx.InstallSymlink(pathWhenActivated.Join(ctx, filepath.Dir(symlinkPath)), filepath.Base(symlinkPath), installedPath)
  410. implicitInputs = append(implicitInputs, installedSymlink)
  411. }
  412. }
  413. installMapPath = installedPath
  414. }
  415. // Copy the test files (if any)
  416. for _, d := range fi.dataPaths {
  417. // TODO(eakammer): This is now the third repetition of ~this logic for test paths, refactoring should be possible
  418. relPath := d.SrcPath.Rel()
  419. dataPath := d.SrcPath.String()
  420. if !strings.HasSuffix(dataPath, relPath) {
  421. panic(fmt.Errorf("path %q does not end with %q", dataPath, relPath))
  422. }
  423. dataDest := imageDir.Join(ctx, fi.apexRelativePath(relPath), d.RelativeInstallPath).String()
  424. copyCommands = append(copyCommands, "cp -f "+d.SrcPath.String()+" "+dataDest)
  425. implicitInputs = append(implicitInputs, d.SrcPath)
  426. }
  427. installMapSet[installMapPath.String()+":"+fi.installDir+"/"+fi.builtFile.Base()] = true
  428. }
  429. implicitInputs = append(implicitInputs, a.manifestPbOut)
  430. if installSymbolFiles {
  431. installedManifest := ctx.InstallFile(pathWhenActivated, "apex_manifest.pb", a.manifestPbOut)
  432. installedKey := ctx.InstallFile(pathWhenActivated, "apex_pubkey", a.publicKeyFile)
  433. implicitInputs = append(implicitInputs, installedManifest, installedKey)
  434. }
  435. if len(installMapSet) > 0 {
  436. var installs []string
  437. installs = append(installs, android.SortedStringKeys(installMapSet)...)
  438. a.SetLicenseInstallMap(installs)
  439. }
  440. ////////////////////////////////////////////////////////////////////////////////////////////
  441. // Step 1.a: Write the list of files in this APEX to a txt file and compare it against
  442. // the allowed list given via the allowed_files property. Build fails when the two lists
  443. // differ.
  444. //
  445. // TODO(jiyong): consider removing this. Nobody other than com.android.apex.cts.shim.* seems
  446. // to be using this at this moment. Furthermore, this looks very similar to what
  447. // buildInstalledFilesFile does. At least, move this to somewhere else so that this doesn't
  448. // hurt readability.
  449. // TODO(jiyong): use RuleBuilder
  450. if a.overridableProperties.Allowed_files != nil {
  451. // Build content.txt
  452. var emitCommands []string
  453. imageContentFile := android.PathForModuleOut(ctx, "content.txt")
  454. emitCommands = append(emitCommands, "echo ./apex_manifest.pb >> "+imageContentFile.String())
  455. minSdkVersion := a.minSdkVersion(ctx)
  456. if minSdkVersion.EqualTo(android.SdkVersion_Android10) {
  457. emitCommands = append(emitCommands, "echo ./apex_manifest.json >> "+imageContentFile.String())
  458. }
  459. for _, fi := range a.filesInfo {
  460. emitCommands = append(emitCommands, "echo './"+fi.path()+"' >> "+imageContentFile.String())
  461. }
  462. emitCommands = append(emitCommands, "sort -o "+imageContentFile.String()+" "+imageContentFile.String())
  463. ctx.Build(pctx, android.BuildParams{
  464. Rule: emitApexContentRule,
  465. Implicits: implicitInputs,
  466. Output: imageContentFile,
  467. Description: "emit apex image content",
  468. Args: map[string]string{
  469. "emit_commands": strings.Join(emitCommands, " && "),
  470. },
  471. })
  472. implicitInputs = append(implicitInputs, imageContentFile)
  473. // Compare content.txt against allowed_files.
  474. allowedFilesFile := android.PathForModuleSrc(ctx, proptools.String(a.overridableProperties.Allowed_files))
  475. phonyOutput := android.PathForModuleOut(ctx, a.Name()+"-diff-phony-output")
  476. ctx.Build(pctx, android.BuildParams{
  477. Rule: diffApexContentRule,
  478. Implicits: implicitInputs,
  479. Output: phonyOutput,
  480. Description: "diff apex image content",
  481. Args: map[string]string{
  482. "allowed_files_file": allowedFilesFile.String(),
  483. "image_content_file": imageContentFile.String(),
  484. "apex_module_name": a.Name(),
  485. },
  486. })
  487. implicitInputs = append(implicitInputs, phonyOutput)
  488. }
  489. unsignedOutputFile := android.PathForModuleOut(ctx, a.Name()+suffix+".unsigned")
  490. outHostBinDir := ctx.Config().HostToolPath(ctx, "").String()
  491. prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin")
  492. if apexType == imageApex {
  493. ////////////////////////////////////////////////////////////////////////////////////
  494. // Step 2: create canned_fs_config which encodes filemode,uid,gid of each files
  495. // in this APEX. The file will be used by apexer in later steps.
  496. cannedFsConfig := a.buildCannedFsConfig(ctx)
  497. implicitInputs = append(implicitInputs, cannedFsConfig)
  498. ////////////////////////////////////////////////////////////////////////////////////
  499. // Step 3: Prepare option flags for apexer and invoke it to create an unsigned APEX.
  500. // TODO(jiyong): use the RuleBuilder
  501. optFlags := []string{}
  502. fileContexts := a.buildFileContexts(ctx)
  503. implicitInputs = append(implicitInputs, fileContexts)
  504. implicitInputs = append(implicitInputs, a.privateKeyFile, a.publicKeyFile)
  505. optFlags = append(optFlags, "--pubkey "+a.publicKeyFile.String())
  506. manifestPackageName := a.getOverrideManifestPackageName(ctx)
  507. if manifestPackageName != "" {
  508. optFlags = append(optFlags, "--override_apk_package_name "+manifestPackageName)
  509. }
  510. if a.properties.AndroidManifest != nil {
  511. androidManifestFile := android.PathForModuleSrc(ctx, proptools.String(a.properties.AndroidManifest))
  512. if a.testApex {
  513. androidManifestFile = markManifestTestOnly(ctx, androidManifestFile)
  514. }
  515. implicitInputs = append(implicitInputs, androidManifestFile)
  516. optFlags = append(optFlags, "--android_manifest "+androidManifestFile.String())
  517. } else if a.testApex {
  518. optFlags = append(optFlags, "--test_only")
  519. }
  520. // Determine target/min sdk version from the context
  521. // TODO(jiyong): make this as a function
  522. moduleMinSdkVersion := a.minSdkVersion(ctx)
  523. minSdkVersion := moduleMinSdkVersion.String()
  524. // bundletool doesn't understand what "current" is. We need to transform it to
  525. // codename
  526. if moduleMinSdkVersion.IsCurrent() || moduleMinSdkVersion.IsNone() {
  527. minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
  528. if java.UseApiFingerprint(ctx) {
  529. minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
  530. implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx))
  531. }
  532. }
  533. // apex module doesn't have a concept of target_sdk_version, hence for the time
  534. // being targetSdkVersion == default targetSdkVersion of the branch.
  535. targetSdkVersion := strconv.Itoa(ctx.Config().DefaultAppTargetSdk(ctx).FinalOrFutureInt())
  536. if java.UseApiFingerprint(ctx) {
  537. targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
  538. implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx))
  539. }
  540. optFlags = append(optFlags, "--target_sdk_version "+targetSdkVersion)
  541. optFlags = append(optFlags, "--min_sdk_version "+minSdkVersion)
  542. if a.overridableProperties.Logging_parent != "" {
  543. optFlags = append(optFlags, "--logging_parent ", a.overridableProperties.Logging_parent)
  544. }
  545. // Create a NOTICE file, and embed it as an asset file in the APEX.
  546. a.htmlGzNotice = android.PathForModuleOut(ctx, "NOTICE.html.gz")
  547. android.BuildNoticeHtmlOutputFromLicenseMetadata(
  548. ctx, a.htmlGzNotice, "", "",
  549. []string{
  550. android.PathForModuleInstall(ctx).String() + "/",
  551. android.PathForModuleInPartitionInstall(ctx, "apex").String() + "/",
  552. })
  553. noticeAssetPath := android.PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz")
  554. builder := android.NewRuleBuilder(pctx, ctx)
  555. builder.Command().Text("cp").
  556. Input(a.htmlGzNotice).
  557. Output(noticeAssetPath)
  558. builder.Build("notice_dir", "Building notice dir")
  559. implicitInputs = append(implicitInputs, noticeAssetPath)
  560. optFlags = append(optFlags, "--assets_dir "+filepath.Dir(noticeAssetPath.String()))
  561. // Apexes which are supposed to be installed in builtin dirs(/system, etc)
  562. // don't need hashtree for activation. Therefore, by removing hashtree from
  563. // apex bundle (filesystem image in it, to be specific), we can save storage.
  564. needHashTree := moduleMinSdkVersion.LessThanOrEqualTo(android.SdkVersion_Android10) ||
  565. a.shouldGenerateHashtree()
  566. if ctx.Config().ApexCompressionEnabled() && a.isCompressable() {
  567. needHashTree = true
  568. }
  569. if !needHashTree {
  570. optFlags = append(optFlags, "--no_hashtree")
  571. }
  572. if a.testOnlyShouldSkipPayloadSign() {
  573. optFlags = append(optFlags, "--unsigned_payload")
  574. }
  575. if a.properties.Apex_name != nil {
  576. // If apex_name is set, apexer can skip checking if key name matches with
  577. // apex name. Note that apex_manifest is also mended.
  578. optFlags = append(optFlags, "--do_not_check_keyname")
  579. }
  580. if moduleMinSdkVersion == android.SdkVersion_Android10 {
  581. implicitInputs = append(implicitInputs, a.manifestJsonOut)
  582. optFlags = append(optFlags, "--manifest_json "+a.manifestJsonOut.String())
  583. }
  584. optFlags = append(optFlags, "--payload_fs_type "+a.payloadFsType.string())
  585. ctx.Build(pctx, android.BuildParams{
  586. Rule: apexRule,
  587. Implicits: implicitInputs,
  588. Output: unsignedOutputFile,
  589. Description: "apex (" + apexType.name() + ")",
  590. Args: map[string]string{
  591. "tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir,
  592. "image_dir": imageDir.String(),
  593. "copy_commands": strings.Join(copyCommands, " && "),
  594. "manifest": a.manifestPbOut.String(),
  595. "file_contexts": fileContexts.String(),
  596. "canned_fs_config": cannedFsConfig.String(),
  597. "key": a.privateKeyFile.String(),
  598. "opt_flags": strings.Join(optFlags, " "),
  599. },
  600. })
  601. // TODO(jiyong): make the two rules below as separate functions
  602. apexProtoFile := android.PathForModuleOut(ctx, a.Name()+".pb"+suffix)
  603. bundleModuleFile := android.PathForModuleOut(ctx, a.Name()+suffix+"-base.zip")
  604. a.bundleModuleFile = bundleModuleFile
  605. ctx.Build(pctx, android.BuildParams{
  606. Rule: apexProtoConvertRule,
  607. Input: unsignedOutputFile,
  608. Output: apexProtoFile,
  609. Description: "apex proto convert",
  610. })
  611. implicitInputs = append(implicitInputs, unsignedOutputFile)
  612. // Run coverage analysis
  613. apisUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.txt")
  614. ctx.Build(pctx, android.BuildParams{
  615. Rule: generateAPIsUsedbyApexRule,
  616. Implicits: implicitInputs,
  617. Description: "coverage",
  618. Output: apisUsedbyOutputFile,
  619. Args: map[string]string{
  620. "image_dir": imageDir.String(),
  621. "readelf": "${config.ClangBin}/llvm-readelf",
  622. },
  623. })
  624. a.nativeApisUsedByModuleFile = apisUsedbyOutputFile
  625. var nativeLibNames []string
  626. for _, f := range a.filesInfo {
  627. if f.class == nativeSharedLib {
  628. nativeLibNames = append(nativeLibNames, f.stem())
  629. }
  630. }
  631. apisBackedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_backing.txt")
  632. rule := android.NewRuleBuilder(pctx, ctx)
  633. rule.Command().
  634. Tool(android.PathForSource(ctx, "build/soong/scripts/gen_ndk_backedby_apex.sh")).
  635. Output(apisBackedbyOutputFile).
  636. Flags(nativeLibNames)
  637. rule.Build("ndk_backedby_list", "Generate API libraries backed by Apex")
  638. a.nativeApisBackedByModuleFile = apisBackedbyOutputFile
  639. var javaLibOrApkPath []android.Path
  640. for _, f := range a.filesInfo {
  641. if f.class == javaSharedLib || f.class == app {
  642. javaLibOrApkPath = append(javaLibOrApkPath, f.builtFile)
  643. }
  644. }
  645. javaApiUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.xml")
  646. javaUsedByRule := android.NewRuleBuilder(pctx, ctx)
  647. javaUsedByRule.Command().
  648. Tool(android.PathForSource(ctx, "build/soong/scripts/gen_java_usedby_apex.sh")).
  649. BuiltTool("dexdeps").
  650. Output(javaApiUsedbyOutputFile).
  651. Inputs(javaLibOrApkPath)
  652. javaUsedByRule.Build("java_usedby_list", "Generate Java APIs used by Apex")
  653. a.javaApisUsedByModuleFile = javaApiUsedbyOutputFile
  654. bundleConfig := a.buildBundleConfig(ctx)
  655. var abis []string
  656. for _, target := range ctx.MultiTargets() {
  657. if len(target.Arch.Abi) > 0 {
  658. abis = append(abis, target.Arch.Abi[0])
  659. }
  660. }
  661. abis = android.FirstUniqueStrings(abis)
  662. ctx.Build(pctx, android.BuildParams{
  663. Rule: apexBundleRule,
  664. Input: apexProtoFile,
  665. Implicit: bundleConfig,
  666. Output: a.bundleModuleFile,
  667. Description: "apex bundle module",
  668. Args: map[string]string{
  669. "abi": strings.Join(abis, "."),
  670. "config": bundleConfig.String(),
  671. },
  672. })
  673. } else { // zipApex
  674. ctx.Build(pctx, android.BuildParams{
  675. Rule: zipApexRule,
  676. Implicits: implicitInputs,
  677. Output: unsignedOutputFile,
  678. Description: "apex (" + apexType.name() + ")",
  679. Args: map[string]string{
  680. "tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir,
  681. "image_dir": imageDir.String(),
  682. "copy_commands": strings.Join(copyCommands, " && "),
  683. "manifest": a.manifestPbOut.String(),
  684. },
  685. })
  686. }
  687. ////////////////////////////////////////////////////////////////////////////////////
  688. // Step 4: Sign the APEX using signapk
  689. signedOutputFile := android.PathForModuleOut(ctx, a.Name()+suffix)
  690. pem, key := a.getCertificateAndPrivateKey(ctx)
  691. rule := java.Signapk
  692. args := map[string]string{
  693. "certificates": pem.String() + " " + key.String(),
  694. "flags": "-a 4096 --align-file-size", //alignment
  695. }
  696. implicits := android.Paths{pem, key}
  697. if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_SIGNAPK") {
  698. rule = java.SignapkRE
  699. args["implicits"] = strings.Join(implicits.Strings(), ",")
  700. args["outCommaList"] = signedOutputFile.String()
  701. }
  702. ctx.Build(pctx, android.BuildParams{
  703. Rule: rule,
  704. Description: "signapk",
  705. Output: signedOutputFile,
  706. Input: unsignedOutputFile,
  707. Implicits: implicits,
  708. Args: args,
  709. })
  710. if suffix == imageApexSuffix {
  711. a.outputApexFile = signedOutputFile
  712. }
  713. a.outputFile = signedOutputFile
  714. if ctx.ModuleDir() != "system/apex/apexd/apexd_testdata" && a.testOnlyShouldForceCompression() {
  715. ctx.PropertyErrorf("test_only_force_compression", "not available")
  716. return
  717. }
  718. installSuffix := suffix
  719. a.setCompression(ctx)
  720. if a.isCompressed {
  721. unsignedCompressedOutputFile := android.PathForModuleOut(ctx, a.Name()+imageCapexSuffix+".unsigned")
  722. compressRule := android.NewRuleBuilder(pctx, ctx)
  723. compressRule.Command().
  724. Text("rm").
  725. FlagWithOutput("-f ", unsignedCompressedOutputFile)
  726. compressRule.Command().
  727. BuiltTool("apex_compression_tool").
  728. Flag("compress").
  729. FlagWithArg("--apex_compression_tool ", outHostBinDir+":"+prebuiltSdkToolsBinDir).
  730. FlagWithInput("--input ", signedOutputFile).
  731. FlagWithOutput("--output ", unsignedCompressedOutputFile)
  732. compressRule.Build("compressRule", "Generate unsigned compressed APEX file")
  733. signedCompressedOutputFile := android.PathForModuleOut(ctx, a.Name()+imageCapexSuffix)
  734. if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_SIGNAPK") {
  735. args["outCommaList"] = signedCompressedOutputFile.String()
  736. }
  737. ctx.Build(pctx, android.BuildParams{
  738. Rule: rule,
  739. Description: "sign compressedApex",
  740. Output: signedCompressedOutputFile,
  741. Input: unsignedCompressedOutputFile,
  742. Implicits: implicits,
  743. Args: args,
  744. })
  745. a.outputFile = signedCompressedOutputFile
  746. installSuffix = imageCapexSuffix
  747. }
  748. if !a.installable() {
  749. a.SkipInstall()
  750. }
  751. // Install to $OUT/soong/{target,host}/.../apex.
  752. a.installedFile = ctx.InstallFile(a.installDir, a.Name()+installSuffix, a.outputFile,
  753. a.compatSymlinks.Paths()...)
  754. // installed-files.txt is dist'ed
  755. a.installedFilesFile = a.buildInstalledFilesFile(ctx, a.outputFile, imageDir)
  756. }
  757. // buildFlattenedApex creates rules for a flattened APEX. Flattened APEX actually doesn't have a
  758. // single output file. It is a phony target for all the files under /system/apex/<name> directory.
  759. // This function creates the installation rules for the files.
  760. func (a *apexBundle) buildFlattenedApex(ctx android.ModuleContext) {
  761. bundleName := a.Name()
  762. installedSymlinks := append(android.InstallPaths(nil), a.compatSymlinks...)
  763. if a.installable() {
  764. for _, fi := range a.filesInfo {
  765. dir := filepath.Join("apex", bundleName, fi.installDir)
  766. installDir := android.PathForModuleInstall(ctx, dir)
  767. if a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform() {
  768. // TODO(jiyong): pathOnDevice should come from fi.module, not being calculated here
  769. pathOnDevice := filepath.Join("/system", fi.path())
  770. installedSymlinks = append(installedSymlinks,
  771. ctx.InstallAbsoluteSymlink(installDir, fi.stem(), pathOnDevice))
  772. } else {
  773. target := ctx.InstallFile(installDir, fi.stem(), fi.builtFile)
  774. for _, sym := range fi.symlinks {
  775. installedSymlinks = append(installedSymlinks,
  776. ctx.InstallSymlink(installDir, sym, target))
  777. }
  778. }
  779. }
  780. // Create install rules for the files added in GenerateAndroidBuildActions after
  781. // buildFlattenedApex is called. Add the links to system libs (if any) as dependencies
  782. // of the apex_manifest.pb file since it is always present.
  783. dir := filepath.Join("apex", bundleName)
  784. installDir := android.PathForModuleInstall(ctx, dir)
  785. ctx.InstallFile(installDir, "apex_manifest.pb", a.manifestPbOut, installedSymlinks.Paths()...)
  786. ctx.InstallFile(installDir, "apex_pubkey", a.publicKeyFile)
  787. }
  788. a.fileContexts = a.buildFileContexts(ctx)
  789. a.outputFile = android.PathForModuleInstall(ctx, "apex", bundleName)
  790. }
  791. // getCertificateAndPrivateKey retrieves the cert and the private key that will be used to sign
  792. // the zip container of this APEX. See the description of the 'certificate' property for how
  793. // the cert and the private key are found.
  794. func (a *apexBundle) getCertificateAndPrivateKey(ctx android.PathContext) (pem, key android.Path) {
  795. if a.containerCertificateFile != nil {
  796. return a.containerCertificateFile, a.containerPrivateKeyFile
  797. }
  798. cert := String(a.overridableProperties.Certificate)
  799. if cert == "" {
  800. return ctx.Config().DefaultAppCertificate(ctx)
  801. }
  802. defaultDir := ctx.Config().DefaultAppCertificateDir(ctx)
  803. pem = defaultDir.Join(ctx, cert+".x509.pem")
  804. key = defaultDir.Join(ctx, cert+".pk8")
  805. return pem, key
  806. }
  807. func (a *apexBundle) getOverrideManifestPackageName(ctx android.ModuleContext) string {
  808. // For VNDK APEXes, check "com.android.vndk" in PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES
  809. // to see if it should be overridden because their <apex name> is dynamically generated
  810. // according to its VNDK version.
  811. if a.vndkApex {
  812. overrideName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(vndkApexName)
  813. if overridden {
  814. return strings.Replace(*a.properties.Apex_name, vndkApexName, overrideName, 1)
  815. }
  816. return ""
  817. }
  818. if a.overridableProperties.Package_name != "" {
  819. return a.overridableProperties.Package_name
  820. }
  821. manifestPackageName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(ctx.ModuleName())
  822. if overridden {
  823. return manifestPackageName
  824. }
  825. return ""
  826. }
  827. func (a *apexBundle) buildApexDependencyInfo(ctx android.ModuleContext) {
  828. if !a.primaryApexType {
  829. return
  830. }
  831. if a.properties.IsCoverageVariant {
  832. // Otherwise, we will have duplicated rules for coverage and
  833. // non-coverage variants of the same APEX
  834. return
  835. }
  836. if ctx.Host() {
  837. // No need to generate dependency info for host variant
  838. return
  839. }
  840. depInfos := android.DepNameToDepInfoMap{}
  841. a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
  842. if from.Name() == to.Name() {
  843. // This can happen for cc.reuseObjTag. We are not interested in tracking this.
  844. // As soon as the dependency graph crosses the APEX boundary, don't go further.
  845. return !externalDep
  846. }
  847. // Skip dependencies that are only available to APEXes; they are developed with updatability
  848. // in mind and don't need manual approval.
  849. if to.(android.ApexModule).NotAvailableForPlatform() {
  850. return !externalDep
  851. }
  852. depTag := ctx.OtherModuleDependencyTag(to)
  853. // Check to see if dependency been marked to skip the dependency check
  854. if skipDepCheck, ok := depTag.(android.SkipApexAllowedDependenciesCheck); ok && skipDepCheck.SkipApexAllowedDependenciesCheck() {
  855. return !externalDep
  856. }
  857. if info, exists := depInfos[to.Name()]; exists {
  858. if !android.InList(from.Name(), info.From) {
  859. info.From = append(info.From, from.Name())
  860. }
  861. info.IsExternal = info.IsExternal && externalDep
  862. depInfos[to.Name()] = info
  863. } else {
  864. toMinSdkVersion := "(no version)"
  865. if m, ok := to.(interface {
  866. MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec
  867. }); ok {
  868. if v := m.MinSdkVersion(ctx); !v.ApiLevel.IsNone() {
  869. toMinSdkVersion = v.ApiLevel.String()
  870. }
  871. } else if m, ok := to.(interface{ MinSdkVersion() string }); ok {
  872. // TODO(b/175678607) eliminate the use of MinSdkVersion returning
  873. // string
  874. if v := m.MinSdkVersion(); v != "" {
  875. toMinSdkVersion = v
  876. }
  877. }
  878. depInfos[to.Name()] = android.ApexModuleDepInfo{
  879. To: to.Name(),
  880. From: []string{from.Name()},
  881. IsExternal: externalDep,
  882. MinSdkVersion: toMinSdkVersion,
  883. }
  884. }
  885. // As soon as the dependency graph crosses the APEX boundary, don't go further.
  886. return !externalDep
  887. })
  888. a.ApexBundleDepsInfo.BuildDepsInfoLists(ctx, a.MinSdkVersion(ctx).Raw, depInfos)
  889. ctx.Build(pctx, android.BuildParams{
  890. Rule: android.Phony,
  891. Output: android.PathForPhony(ctx, a.Name()+"-deps-info"),
  892. Inputs: []android.Path{
  893. a.ApexBundleDepsInfo.FullListPath(),
  894. a.ApexBundleDepsInfo.FlatListPath(),
  895. },
  896. })
  897. }
  898. func (a *apexBundle) buildLintReports(ctx android.ModuleContext) {
  899. depSetsBuilder := java.NewLintDepSetBuilder()
  900. for _, fi := range a.filesInfo {
  901. depSetsBuilder.Transitive(fi.lintDepSets)
  902. }
  903. a.lintReports = java.BuildModuleLintReportZips(ctx, depSetsBuilder.Build())
  904. }
  905. func (a *apexBundle) buildCannedFsConfig(ctx android.ModuleContext) android.OutputPath {
  906. var readOnlyPaths = []string{"apex_manifest.json", "apex_manifest.pb"}
  907. var executablePaths []string // this also includes dirs
  908. var appSetDirs []string
  909. appSetFiles := make(map[string]android.Path)
  910. for _, f := range a.filesInfo {
  911. pathInApex := f.path()
  912. if f.installDir == "bin" || strings.HasPrefix(f.installDir, "bin/") {
  913. executablePaths = append(executablePaths, pathInApex)
  914. for _, d := range f.dataPaths {
  915. readOnlyPaths = append(readOnlyPaths, filepath.Join(f.installDir, d.RelativeInstallPath, d.SrcPath.Rel()))
  916. }
  917. for _, s := range f.symlinks {
  918. executablePaths = append(executablePaths, filepath.Join(f.installDir, s))
  919. }
  920. } else if f.class == appSet {
  921. appSetDirs = append(appSetDirs, f.installDir)
  922. appSetFiles[f.installDir] = f.builtFile
  923. } else {
  924. readOnlyPaths = append(readOnlyPaths, pathInApex)
  925. }
  926. dir := f.installDir
  927. for !android.InList(dir, executablePaths) && dir != "" {
  928. executablePaths = append(executablePaths, dir)
  929. dir, _ = filepath.Split(dir) // move up to the parent
  930. if len(dir) > 0 {
  931. // remove trailing slash
  932. dir = dir[:len(dir)-1]
  933. }
  934. }
  935. }
  936. sort.Strings(readOnlyPaths)
  937. sort.Strings(executablePaths)
  938. sort.Strings(appSetDirs)
  939. cannedFsConfig := android.PathForModuleOut(ctx, "canned_fs_config")
  940. builder := android.NewRuleBuilder(pctx, ctx)
  941. cmd := builder.Command()
  942. cmd.Text("(")
  943. cmd.Text("echo '/ 1000 1000 0755';")
  944. for _, p := range readOnlyPaths {
  945. cmd.Textf("echo '/%s 1000 1000 0644';", p)
  946. }
  947. for _, p := range executablePaths {
  948. cmd.Textf("echo '/%s 0 2000 0755';", p)
  949. }
  950. for _, dir := range appSetDirs {
  951. cmd.Textf("echo '/%s 0 2000 0755';", dir)
  952. file := appSetFiles[dir]
  953. cmd.Text("zipinfo -1").Input(file).Textf(`| sed "s:\(.*\):/%s/\1 1000 1000 0644:";`, dir)
  954. }
  955. // Custom fs_config is "appended" to the last so that entries from the file are preferred
  956. // over default ones set above.
  957. if a.properties.Canned_fs_config != nil {
  958. cmd.Text("cat").Input(android.PathForModuleSrc(ctx, *a.properties.Canned_fs_config))
  959. }
  960. cmd.Text(")").FlagWithOutput("> ", cannedFsConfig)
  961. builder.Build("generateFsConfig", fmt.Sprintf("Generating canned fs config for %s", a.BaseModuleName()))
  962. return cannedFsConfig.OutputPath
  963. }