sdk.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. // Copyright 2016 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package binres
  5. import (
  6. "archive/zip"
  7. "bytes"
  8. "compress/gzip"
  9. "fmt"
  10. "io"
  11. "os"
  12. "path/filepath"
  13. "golang.org/x/mobile/internal/sdkpath"
  14. )
  15. // MinSDK is the targeted sdk version for support by package binres.
  16. const MinSDK = 16
  17. func apiResources() ([]byte, error) {
  18. apiResPath, err := apiResourcesPath()
  19. if err != nil {
  20. return nil, err
  21. }
  22. zr, err := zip.OpenReader(apiResPath)
  23. if err != nil {
  24. if os.IsNotExist(err) {
  25. return nil, fmt.Errorf(`%v; consider installing with "android update sdk --all --no-ui --filter android-%d"`, err, MinSDK)
  26. }
  27. return nil, err
  28. }
  29. defer zr.Close()
  30. buf := new(bytes.Buffer)
  31. for _, f := range zr.File {
  32. if f.Name == "resources.arsc" {
  33. rc, err := f.Open()
  34. if err != nil {
  35. return nil, err
  36. }
  37. _, err = io.Copy(buf, rc)
  38. if err != nil {
  39. return nil, err
  40. }
  41. rc.Close()
  42. break
  43. }
  44. }
  45. if buf.Len() == 0 {
  46. return nil, fmt.Errorf("failed to read resources.arsc")
  47. }
  48. return buf.Bytes(), nil
  49. }
  50. func apiResourcesPath() (string, error) {
  51. platformDir, err := sdkpath.AndroidAPIPath(MinSDK)
  52. if err != nil {
  53. return "", err
  54. }
  55. return filepath.Join(platformDir, "android.jar"), nil
  56. }
  57. // PackResources produces a stripped down gzip version of the resources.arsc from api jar.
  58. func PackResources() ([]byte, error) {
  59. tbl, err := OpenSDKTable()
  60. if err != nil {
  61. return nil, err
  62. }
  63. tbl.pool.strings = []string{} // should not be needed
  64. pkg := tbl.pkgs[0]
  65. // drop language string entries
  66. for _, typ := range pkg.specs[3].types {
  67. if typ.config.locale.language != 0 {
  68. for j, nt := range typ.entries {
  69. if nt == nil { // NoEntry
  70. continue
  71. }
  72. pkg.keyPool.strings[nt.key] = ""
  73. typ.indices[j] = NoEntry
  74. typ.entries[j] = nil
  75. }
  76. }
  77. }
  78. // drop strings from pool for specs to be dropped
  79. for _, spec := range pkg.specs[4:] {
  80. for _, typ := range spec.types {
  81. for _, nt := range typ.entries {
  82. if nt == nil { // NoEntry
  83. continue
  84. }
  85. // don't drop if there's a collision
  86. var collision bool
  87. for _, xspec := range pkg.specs[:4] {
  88. for _, xtyp := range xspec.types {
  89. for _, xnt := range xtyp.entries {
  90. if xnt == nil {
  91. continue
  92. }
  93. if collision = nt.key == xnt.key; collision {
  94. break
  95. }
  96. }
  97. }
  98. }
  99. if !collision {
  100. pkg.keyPool.strings[nt.key] = ""
  101. }
  102. }
  103. }
  104. }
  105. // entries are densely packed but probably safe to drop nil entries off the end
  106. for _, spec := range pkg.specs[:4] {
  107. for _, typ := range spec.types {
  108. var last int
  109. for i, nt := range typ.entries {
  110. if nt != nil {
  111. last = i
  112. }
  113. }
  114. typ.entries = typ.entries[:last+1]
  115. typ.indices = typ.indices[:last+1]
  116. }
  117. }
  118. // keeping 0:attr, 1:id, 2:style, 3:string
  119. pkg.typePool.strings = pkg.typePool.strings[:4]
  120. pkg.specs = pkg.specs[:4]
  121. bin, err := tbl.MarshalBinary()
  122. if err != nil {
  123. return nil, err
  124. }
  125. buf := new(bytes.Buffer)
  126. zw := gzip.NewWriter(buf)
  127. if _, err := zw.Write(bin); err != nil {
  128. return nil, err
  129. }
  130. if err := zw.Flush(); err != nil {
  131. return nil, err
  132. }
  133. if err := zw.Close(); err != nil {
  134. return nil, err
  135. }
  136. return buf.Bytes(), nil
  137. }