bp2build_test.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. // Copyright 2022 Google Inc. All rights reserved.
  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. "android/soong/android"
  17. "android/soong/android/allowlists"
  18. "android/soong/bazel/cquery"
  19. "fmt"
  20. "path/filepath"
  21. "strings"
  22. "testing"
  23. )
  24. func TestApexImageInMixedBuilds(t *testing.T) {
  25. bp := `
  26. apex_key{
  27. name: "foo_key",
  28. }
  29. apex {
  30. name: "foo",
  31. key: "foo_key",
  32. updatable: true,
  33. min_sdk_version: "31",
  34. file_contexts: ":myapex-file_contexts",
  35. bazel_module: { label: "//:foo" },
  36. }`
  37. outputBaseDir := "out/bazel"
  38. result := android.GroupFixturePreparers(
  39. prepareForApexTest,
  40. android.FixtureModifyConfig(func(config android.Config) {
  41. config.BazelContext = android.MockBazelContext{
  42. OutputBaseDir: outputBaseDir,
  43. LabelToApexInfo: map[string]cquery.ApexInfo{
  44. "//:foo": cquery.ApexInfo{
  45. // ApexInfo Starlark provider.
  46. SignedOutput: "signed_out.apex",
  47. SignedCompressedOutput: "signed_out.capex",
  48. UnsignedOutput: "unsigned_out.apex",
  49. BundleKeyInfo: []string{"public_key", "private_key"},
  50. ContainerKeyInfo: []string{"container_cert", "container_private"},
  51. SymbolsUsedByApex: "foo_using.txt",
  52. JavaSymbolsUsedByApex: "foo_using.xml",
  53. BundleFile: "apex_bundle.zip",
  54. InstalledFiles: "installed-files.txt",
  55. RequiresLibs: []string{"//path/c:c", "//path/d:d"},
  56. // unused
  57. PackageName: "pkg_name",
  58. ProvidesLibs: []string{"a", "b"},
  59. // ApexMkInfo Starlark provider
  60. PayloadFilesInfo: []map[string]string{
  61. {
  62. "built_file": "bazel-out/adbd",
  63. "install_dir": "bin",
  64. "class": "nativeExecutable",
  65. "make_module_name": "adbd",
  66. "basename": "adbd",
  67. "package": "foo",
  68. },
  69. },
  70. MakeModulesToInstall: []string{"c"}, // d deliberately omitted
  71. },
  72. },
  73. }
  74. }),
  75. ).RunTestWithBp(t, bp)
  76. m := result.ModuleForTests("foo", "android_common_foo_image").Module()
  77. ab, ok := m.(*apexBundle)
  78. if !ok {
  79. t.Fatalf("Expected module to be an apexBundle, was not")
  80. }
  81. // TODO: refactor to android.AssertStringEquals
  82. if w, g := "out/bazel/execroot/__main__/public_key", ab.publicKeyFile.String(); w != g {
  83. t.Errorf("Expected public key %q, got %q", w, g)
  84. }
  85. if w, g := "out/bazel/execroot/__main__/private_key", ab.privateKeyFile.String(); w != g {
  86. t.Errorf("Expected private key %q, got %q", w, g)
  87. }
  88. if w, g := "out/bazel/execroot/__main__/container_cert", ab.containerCertificateFile.String(); w != g {
  89. t.Errorf("Expected public container key %q, got %q", w, g)
  90. }
  91. if w, g := "out/bazel/execroot/__main__/container_private", ab.containerPrivateKeyFile.String(); w != g {
  92. t.Errorf("Expected private container key %q, got %q", w, g)
  93. }
  94. if w, g := "out/bazel/execroot/__main__/signed_out.apex", ab.outputFile.String(); w != g {
  95. t.Errorf("Expected output file %q, got %q", w, g)
  96. }
  97. if w, g := "out/bazel/execroot/__main__/foo_using.txt", ab.nativeApisUsedByModuleFile.String(); w != g {
  98. t.Errorf("Expected output file %q, got %q", w, g)
  99. }
  100. if w, g := "out/bazel/execroot/__main__/foo_using.xml", ab.javaApisUsedByModuleFile.String(); w != g {
  101. t.Errorf("Expected output file %q, got %q", w, g)
  102. }
  103. if w, g := "out/bazel/execroot/__main__/installed-files.txt", ab.installedFilesFile.String(); w != g {
  104. t.Errorf("Expected installed-files.txt %q, got %q", w, g)
  105. }
  106. mkData := android.AndroidMkDataForTest(t, result.TestContext, m)
  107. var builder strings.Builder
  108. mkData.Custom(&builder, "foo", "BAZEL_TARGET_", "", mkData)
  109. data := builder.String()
  110. if w := "ALL_MODULES.$(my_register_name).BUNDLE := out/bazel/execroot/__main__/apex_bundle.zip"; !strings.Contains(data, w) {
  111. t.Errorf("Expected %q in androidmk data, but did not find %q", w, data)
  112. }
  113. if w := "$(call dist-for-goals,checkbuild,out/bazel/execroot/__main__/installed-files.txt:foo-installed-files.txt)"; !strings.Contains(data, w) {
  114. t.Errorf("Expected %q in androidmk data, but did not find %q", w, data)
  115. }
  116. // make modules to be installed to system
  117. if len(ab.makeModulesToInstall) != 1 && ab.makeModulesToInstall[0] != "c" {
  118. t.Errorf("Expected makeModulesToInstall slice to only contain 'c', got %q", ab.makeModulesToInstall)
  119. }
  120. if w := "LOCAL_REQUIRED_MODULES := adbd.foo c"; !strings.Contains(data, w) {
  121. t.Errorf("Expected %q in androidmk data, but did not find it in %q", w, data)
  122. }
  123. }
  124. func TestApexImageCreatesFilesInfoForMake(t *testing.T) {
  125. bp := `
  126. apex_key{
  127. name: "foo_key",
  128. }
  129. apex {
  130. name: "foo",
  131. key: "foo_key",
  132. updatable: true,
  133. min_sdk_version: "31",
  134. file_contexts: ":myapex-file_contexts",
  135. bazel_module: { label: "//:foo" },
  136. }`
  137. outputBaseDir := "out/bazel"
  138. result := android.GroupFixturePreparers(
  139. prepareForApexTest,
  140. android.FixtureModifyConfig(func(config android.Config) {
  141. config.BazelContext = android.MockBazelContext{
  142. OutputBaseDir: outputBaseDir,
  143. LabelToApexInfo: map[string]cquery.ApexInfo{
  144. "//:foo": {
  145. // ApexInfo Starlark provider. Necessary for the test.
  146. SignedOutput: "signed_out.apex",
  147. BundleKeyInfo: []string{"public_key", "private_key"},
  148. ContainerKeyInfo: []string{"container_cert", "container_private"},
  149. // ApexMkInfo Starlark provider
  150. PayloadFilesInfo: []map[string]string{
  151. {
  152. "arch": "arm64",
  153. "basename": "libcrypto.so",
  154. "built_file": "bazel-out/64/libcrypto.so",
  155. "class": "nativeSharedLib",
  156. "install_dir": "lib64",
  157. "make_module_name": "libcrypto",
  158. "package": "foo/bar",
  159. "unstripped_built_file": "bazel-out/64/unstripped_libcrypto.so",
  160. },
  161. {
  162. "arch": "arm",
  163. "basename": "libcrypto.so",
  164. "built_file": "bazel-out/32/libcrypto.so",
  165. "class": "nativeSharedLib",
  166. "install_dir": "lib",
  167. "make_module_name": "libcrypto",
  168. "package": "foo/bar",
  169. },
  170. {
  171. "arch": "arm64",
  172. "basename": "adbd",
  173. "built_file": "bazel-out/adbd",
  174. "class": "nativeExecutable",
  175. "install_dir": "bin",
  176. "make_module_name": "adbd",
  177. "package": "foo",
  178. },
  179. },
  180. },
  181. },
  182. }
  183. }),
  184. ).RunTestWithBp(t, bp)
  185. m := result.ModuleForTests("foo", "android_common_foo_image").Module()
  186. ab, ok := m.(*apexBundle)
  187. if !ok {
  188. t.Fatalf("Expected module to be an apexBundle, was not")
  189. }
  190. expectedFilesInfo := []apexFile{
  191. {
  192. androidMkModuleName: "libcrypto",
  193. builtFile: android.PathForTesting("out/bazel/execroot/__main__/bazel-out/64/libcrypto.so"),
  194. class: nativeSharedLib,
  195. customStem: "libcrypto.so",
  196. installDir: "lib64",
  197. moduleDir: "foo/bar",
  198. arch: "arm64",
  199. unstrippedBuiltFile: android.PathForTesting("out/bazel/execroot/__main__/bazel-out/64/unstripped_libcrypto.so"),
  200. },
  201. {
  202. androidMkModuleName: "libcrypto",
  203. builtFile: android.PathForTesting("out/bazel/execroot/__main__/bazel-out/32/libcrypto.so"),
  204. class: nativeSharedLib,
  205. customStem: "libcrypto.so",
  206. installDir: "lib",
  207. moduleDir: "foo/bar",
  208. arch: "arm",
  209. },
  210. {
  211. androidMkModuleName: "adbd",
  212. builtFile: android.PathForTesting("out/bazel/execroot/__main__/bazel-out/adbd"),
  213. class: nativeExecutable,
  214. customStem: "adbd",
  215. installDir: "bin",
  216. moduleDir: "foo",
  217. arch: "arm64",
  218. },
  219. }
  220. if len(ab.filesInfo) != len(expectedFilesInfo) {
  221. t.Errorf("Expected %d entries in ab.filesInfo, but got %d", len(ab.filesInfo), len(expectedFilesInfo))
  222. }
  223. for idx, f := range ab.filesInfo {
  224. expected := expectedFilesInfo[idx]
  225. android.AssertSame(t, "different class", expected.class, f.class)
  226. android.AssertStringEquals(t, "different built file", expected.builtFile.String(), f.builtFile.String())
  227. android.AssertStringEquals(t, "different custom stem", expected.customStem, f.customStem)
  228. android.AssertStringEquals(t, "different install dir", expected.installDir, f.installDir)
  229. android.AssertStringEquals(t, "different make module name", expected.androidMkModuleName, f.androidMkModuleName)
  230. android.AssertStringEquals(t, "different moduleDir", expected.moduleDir, f.moduleDir)
  231. android.AssertStringEquals(t, "different arch", expected.arch, f.arch)
  232. if expected.unstrippedBuiltFile != nil {
  233. if f.unstrippedBuiltFile == nil {
  234. t.Errorf("expected an unstripped built file path.")
  235. }
  236. android.AssertStringEquals(t, "different unstripped built file", expected.unstrippedBuiltFile.String(), f.unstrippedBuiltFile.String())
  237. }
  238. }
  239. }
  240. func TestCompressedApexImageInMixedBuilds(t *testing.T) {
  241. bp := `
  242. apex_key{
  243. name: "foo_key",
  244. }
  245. apex {
  246. name: "foo",
  247. key: "foo_key",
  248. updatable: true,
  249. min_sdk_version: "31",
  250. file_contexts: ":myapex-file_contexts",
  251. bazel_module: { label: "//:foo" },
  252. test_only_force_compression: true, // force compression
  253. }`
  254. outputBaseDir := "out/bazel"
  255. result := android.GroupFixturePreparers(
  256. prepareForApexTest,
  257. android.FixtureModifyConfig(func(config android.Config) {
  258. config.BazelContext = android.MockBazelContext{
  259. OutputBaseDir: outputBaseDir,
  260. LabelToApexInfo: map[string]cquery.ApexInfo{
  261. "//:foo": cquery.ApexInfo{
  262. SignedOutput: "signed_out.apex",
  263. SignedCompressedOutput: "signed_out.capex",
  264. BundleKeyInfo: []string{"public_key", "private_key"},
  265. ContainerKeyInfo: []string{"container_cert", "container_private"},
  266. },
  267. },
  268. }
  269. }),
  270. ).RunTestWithBp(t, bp)
  271. m := result.ModuleForTests("foo", "android_common_foo_image").Module()
  272. ab, ok := m.(*apexBundle)
  273. if !ok {
  274. t.Fatalf("Expected module to be an apexBundle, was not")
  275. }
  276. if w, g := "out/bazel/execroot/__main__/signed_out.capex", ab.outputFile.String(); w != g {
  277. t.Errorf("Expected output file to be compressed apex %q, got %q", w, g)
  278. }
  279. mkData := android.AndroidMkDataForTest(t, result.TestContext, m)
  280. var builder strings.Builder
  281. mkData.Custom(&builder, "foo", "BAZEL_TARGET_", "", mkData)
  282. data := builder.String()
  283. expectedAndroidMk := []string{
  284. "LOCAL_PREBUILT_MODULE_FILE := out/bazel/execroot/__main__/signed_out.capex",
  285. // Check that the source install file is the capex. The dest is not important.
  286. "LOCAL_SOONG_INSTALL_PAIRS := out/bazel/execroot/__main__/signed_out.capex:",
  287. }
  288. for _, androidMk := range expectedAndroidMk {
  289. if !strings.Contains(data, androidMk) {
  290. t.Errorf("Expected %q in androidmk data, but did not find %q", androidMk, data)
  291. }
  292. }
  293. }
  294. func TestOverrideApexImageInMixedBuilds(t *testing.T) {
  295. originalBp := `
  296. apex_key{
  297. name: "foo_key",
  298. }
  299. apex_key{
  300. name: "override_foo_key",
  301. }
  302. apex {
  303. name: "foo",
  304. key: "foo_key",
  305. updatable: true,
  306. min_sdk_version: "31",
  307. package_name: "pkg_name",
  308. file_contexts: ":myapex-file_contexts",
  309. %s
  310. }`
  311. overrideBp := `
  312. override_apex {
  313. name: "override_foo",
  314. key: "override_foo_key",
  315. package_name: "override_pkg_name",
  316. base: "foo",
  317. %s
  318. }
  319. `
  320. originalApexBpDir := "original"
  321. originalApexName := "foo"
  322. overrideApexBpDir := "override"
  323. overrideApexName := "override_foo"
  324. defaultApexLabel := fmt.Sprintf("//%s:%s", originalApexBpDir, originalApexName)
  325. defaultOverrideApexLabel := fmt.Sprintf("//%s:%s", overrideApexBpDir, overrideApexName)
  326. testCases := []struct {
  327. desc string
  328. bazelModuleProp string
  329. apexLabel string
  330. overrideBazelModuleProp string
  331. overrideApexLabel string
  332. bp2buildConfiguration android.Bp2BuildConversionAllowlist
  333. }{
  334. {
  335. desc: "both explicit labels",
  336. bazelModuleProp: `bazel_module: { label: "//:foo" },`,
  337. apexLabel: "//:foo",
  338. overrideBazelModuleProp: `bazel_module: { label: "//:override_foo" },`,
  339. overrideApexLabel: "//:override_foo",
  340. bp2buildConfiguration: android.NewBp2BuildAllowlist(),
  341. },
  342. {
  343. desc: "both explicitly allowed",
  344. bazelModuleProp: `bazel_module: { bp2build_available: true },`,
  345. apexLabel: defaultApexLabel,
  346. overrideBazelModuleProp: `bazel_module: { bp2build_available: true },`,
  347. overrideApexLabel: defaultOverrideApexLabel,
  348. bp2buildConfiguration: android.NewBp2BuildAllowlist(),
  349. },
  350. {
  351. desc: "original allowed by dir, override allowed by name",
  352. apexLabel: defaultApexLabel,
  353. overrideApexLabel: defaultOverrideApexLabel,
  354. bp2buildConfiguration: android.NewBp2BuildAllowlist().SetDefaultConfig(
  355. map[string]allowlists.BazelConversionConfigEntry{
  356. originalApexBpDir: allowlists.Bp2BuildDefaultTrue,
  357. }).SetModuleAlwaysConvertList([]string{
  358. overrideApexName,
  359. }),
  360. },
  361. {
  362. desc: "both allowed by name",
  363. apexLabel: defaultApexLabel,
  364. overrideApexLabel: defaultOverrideApexLabel,
  365. bp2buildConfiguration: android.NewBp2BuildAllowlist().SetModuleAlwaysConvertList([]string{
  366. originalApexName,
  367. overrideApexName,
  368. }),
  369. },
  370. {
  371. desc: "override allowed by name",
  372. apexLabel: defaultApexLabel,
  373. overrideApexLabel: defaultOverrideApexLabel,
  374. bp2buildConfiguration: android.NewBp2BuildAllowlist().SetModuleAlwaysConvertList([]string{
  375. overrideApexName,
  376. }),
  377. },
  378. {
  379. desc: "override allowed by dir",
  380. apexLabel: defaultApexLabel,
  381. overrideApexLabel: defaultOverrideApexLabel,
  382. bp2buildConfiguration: android.NewBp2BuildAllowlist().SetDefaultConfig(
  383. map[string]allowlists.BazelConversionConfigEntry{
  384. overrideApexBpDir: allowlists.Bp2BuildDefaultTrue,
  385. }).SetModuleAlwaysConvertList([]string{}),
  386. },
  387. }
  388. for _, tc := range testCases {
  389. t.Run(tc.desc, func(t *testing.T) {
  390. outputBaseDir := "out/bazel"
  391. result := android.GroupFixturePreparers(
  392. prepareForApexTest,
  393. android.FixtureAddTextFile(filepath.Join(originalApexBpDir, "Android.bp"), fmt.Sprintf(originalBp, tc.bazelModuleProp)),
  394. android.FixtureAddTextFile(filepath.Join(overrideApexBpDir, "Android.bp"), fmt.Sprintf(overrideBp, tc.overrideBazelModuleProp)),
  395. android.FixtureModifyContext(func(ctx *android.TestContext) {
  396. ctx.RegisterBp2BuildConfig(tc.bp2buildConfiguration)
  397. }),
  398. android.FixtureModifyConfig(func(config android.Config) {
  399. config.BazelContext = android.MockBazelContext{
  400. OutputBaseDir: outputBaseDir,
  401. LabelToApexInfo: map[string]cquery.ApexInfo{
  402. tc.apexLabel: cquery.ApexInfo{
  403. // ApexInfo Starlark provider
  404. SignedOutput: "signed_out.apex",
  405. UnsignedOutput: "unsigned_out.apex",
  406. BundleKeyInfo: []string{"public_key", "private_key"},
  407. ContainerKeyInfo: []string{"container_cert", "container_private"},
  408. SymbolsUsedByApex: "foo_using.txt",
  409. JavaSymbolsUsedByApex: "foo_using.xml",
  410. BundleFile: "apex_bundle.zip",
  411. InstalledFiles: "installed-files.txt",
  412. RequiresLibs: []string{"//path/c:c", "//path/d:d"},
  413. // unused
  414. PackageName: "pkg_name",
  415. ProvidesLibs: []string{"a", "b"},
  416. // ApexMkInfo Starlark provider
  417. MakeModulesToInstall: []string{"c"}, // d deliberately omitted
  418. },
  419. tc.overrideApexLabel: cquery.ApexInfo{
  420. // ApexInfo Starlark provider
  421. SignedOutput: "override_signed_out.apex",
  422. UnsignedOutput: "override_unsigned_out.apex",
  423. BundleKeyInfo: []string{"override_public_key", "override_private_key"},
  424. ContainerKeyInfo: []string{"override_container_cert", "override_container_private"},
  425. SymbolsUsedByApex: "override_foo_using.txt",
  426. JavaSymbolsUsedByApex: "override_foo_using.xml",
  427. BundleFile: "override_apex_bundle.zip",
  428. InstalledFiles: "override_installed-files.txt",
  429. RequiresLibs: []string{"//path/c:c", "//path/d:d"},
  430. // unused
  431. PackageName: "override_pkg_name",
  432. ProvidesLibs: []string{"a", "b"},
  433. // ApexMkInfo Starlark provider
  434. MakeModulesToInstall: []string{"c"}, // d deliberately omitted
  435. },
  436. },
  437. }
  438. }),
  439. ).RunTest(t)
  440. m := result.ModuleForTests("foo", "android_common_override_foo_foo_image").Module()
  441. ab, ok := m.(*apexBundle)
  442. if !ok {
  443. t.Fatalf("Expected module to be an apexBundle, was not")
  444. }
  445. if w, g := "out/bazel/execroot/__main__/override_public_key", ab.publicKeyFile.String(); w != g {
  446. t.Errorf("Expected public key %q, got %q", w, g)
  447. }
  448. if w, g := "out/bazel/execroot/__main__/override_private_key", ab.privateKeyFile.String(); w != g {
  449. t.Errorf("Expected private key %q, got %q", w, g)
  450. }
  451. if w, g := "out/bazel/execroot/__main__/override_container_cert", ab.containerCertificateFile; g != nil && w != g.String() {
  452. t.Errorf("Expected public container key %q, got %q", w, g)
  453. }
  454. if w, g := "out/bazel/execroot/__main__/override_container_private", ab.containerPrivateKeyFile; g != nil && w != g.String() {
  455. t.Errorf("Expected private container key %q, got %q", w, g)
  456. }
  457. if w, g := "out/bazel/execroot/__main__/override_signed_out.apex", ab.outputFile.String(); w != g {
  458. t.Errorf("Expected output file %q, got %q", w, g)
  459. }
  460. if w, g := "out/bazel/execroot/__main__/override_foo_using.txt", ab.nativeApisUsedByModuleFile.String(); w != g {
  461. t.Errorf("Expected output file %q, got %q", w, g)
  462. }
  463. if w, g := "out/bazel/execroot/__main__/override_foo_using.xml", ab.javaApisUsedByModuleFile.String(); w != g {
  464. t.Errorf("Expected output file %q, got %q", w, g)
  465. }
  466. if w, g := "out/bazel/execroot/__main__/override_installed-files.txt", ab.installedFilesFile.String(); w != g {
  467. t.Errorf("Expected installed-files.txt %q, got %q", w, g)
  468. }
  469. mkData := android.AndroidMkDataForTest(t, result.TestContext, m)
  470. var builder strings.Builder
  471. mkData.Custom(&builder, "override_foo", "BAZEL_TARGET_", "", mkData)
  472. data := builder.String()
  473. if w := "ALL_MODULES.$(my_register_name).BUNDLE := out/bazel/execroot/__main__/override_apex_bundle.zip"; !strings.Contains(data, w) {
  474. t.Errorf("Expected %q in androidmk data, but did not find %q", w, data)
  475. }
  476. if w := "$(call dist-for-goals,checkbuild,out/bazel/execroot/__main__/override_installed-files.txt:override_foo-installed-files.txt)"; !strings.Contains(data, w) {
  477. t.Errorf("Expected %q in androidmk data, but did not find %q", w, data)
  478. }
  479. // make modules to be installed to system
  480. if len(ab.makeModulesToInstall) != 1 || ab.makeModulesToInstall[0] != "c" {
  481. t.Errorf("Expected makeModulestoInstall slice to only contain 'c', got %q", ab.makeModulesToInstall)
  482. }
  483. if w := "LOCAL_REQUIRED_MODULES := c"; !strings.Contains(data, w) {
  484. t.Errorf("Expected %q in androidmk data, but did not find it in %q", w, data)
  485. }
  486. })
  487. }
  488. }