configured_jars.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  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 android
  15. import (
  16. "encoding/json"
  17. "errors"
  18. "fmt"
  19. "path/filepath"
  20. "strings"
  21. )
  22. // The ConfiguredJarList struct provides methods for handling a list of (apex, jar) pairs.
  23. // Such lists are used in the build system for things like bootclasspath jars or system server jars.
  24. // The apex part is either an apex name, or a special names "platform" or "system_ext". Jar is a
  25. // module name. The pairs come from Make product variables as a list of colon-separated strings.
  26. //
  27. // Examples:
  28. // - "com.android.art:core-oj"
  29. // - "platform:framework"
  30. // - "system_ext:foo"
  31. type ConfiguredJarList struct {
  32. // A list of apex components, which can be an apex name,
  33. // or special names like "platform" or "system_ext".
  34. apexes []string
  35. // A list of jar module name components.
  36. jars []string
  37. }
  38. // Len returns the length of the list of jars.
  39. func (l *ConfiguredJarList) Len() int {
  40. return len(l.jars)
  41. }
  42. // Jar returns the idx-th jar component of (apex, jar) pairs.
  43. func (l *ConfiguredJarList) Jar(idx int) string {
  44. return l.jars[idx]
  45. }
  46. // Apex returns the idx-th apex component of (apex, jar) pairs.
  47. func (l *ConfiguredJarList) Apex(idx int) string {
  48. return l.apexes[idx]
  49. }
  50. // ContainsJar returns true if the (apex, jar) pairs contains a pair with the
  51. // given jar module name.
  52. func (l *ConfiguredJarList) ContainsJar(jar string) bool {
  53. return InList(jar, l.jars)
  54. }
  55. // If the list contains the given (apex, jar) pair.
  56. func (l *ConfiguredJarList) containsApexJarPair(apex, jar string) bool {
  57. for i := 0; i < l.Len(); i++ {
  58. if apex == l.apexes[i] && jar == l.jars[i] {
  59. return true
  60. }
  61. }
  62. return false
  63. }
  64. // ApexOfJar returns the apex component of the first pair with the given jar name on the list, or
  65. // an empty string if not found.
  66. func (l *ConfiguredJarList) ApexOfJar(jar string) string {
  67. if idx := IndexList(jar, l.jars); idx != -1 {
  68. return l.Apex(IndexList(jar, l.jars))
  69. }
  70. return ""
  71. }
  72. // IndexOfJar returns the first pair with the given jar name on the list, or -1
  73. // if not found.
  74. func (l *ConfiguredJarList) IndexOfJar(jar string) int {
  75. return IndexList(jar, l.jars)
  76. }
  77. func copyAndAppend(list []string, item string) []string {
  78. // Create the result list to be 1 longer than the input.
  79. result := make([]string, len(list)+1)
  80. // Copy the whole input list into the result.
  81. count := copy(result, list)
  82. // Insert the extra item at the end.
  83. result[count] = item
  84. return result
  85. }
  86. // Append an (apex, jar) pair to the list.
  87. func (l *ConfiguredJarList) Append(apex string, jar string) ConfiguredJarList {
  88. // Create a copy of the backing arrays before appending to avoid sharing backing
  89. // arrays that are mutated across instances.
  90. apexes := copyAndAppend(l.apexes, apex)
  91. jars := copyAndAppend(l.jars, jar)
  92. return ConfiguredJarList{apexes, jars}
  93. }
  94. // Append a list of (apex, jar) pairs to the list.
  95. func (l *ConfiguredJarList) AppendList(other *ConfiguredJarList) ConfiguredJarList {
  96. apexes := make([]string, 0, l.Len()+other.Len())
  97. jars := make([]string, 0, l.Len()+other.Len())
  98. apexes = append(apexes, l.apexes...)
  99. jars = append(jars, l.jars...)
  100. apexes = append(apexes, other.apexes...)
  101. jars = append(jars, other.jars...)
  102. return ConfiguredJarList{apexes, jars}
  103. }
  104. // RemoveList filters out a list of (apex, jar) pairs from the receiving list of pairs.
  105. func (l *ConfiguredJarList) RemoveList(list ConfiguredJarList) ConfiguredJarList {
  106. apexes := make([]string, 0, l.Len())
  107. jars := make([]string, 0, l.Len())
  108. for i, jar := range l.jars {
  109. apex := l.apexes[i]
  110. if !list.containsApexJarPair(apex, jar) {
  111. apexes = append(apexes, apex)
  112. jars = append(jars, jar)
  113. }
  114. }
  115. return ConfiguredJarList{apexes, jars}
  116. }
  117. // Filter keeps the entries if a jar appears in the given list of jars to keep. Returns a new list
  118. // and any remaining jars that are not on this list.
  119. func (l *ConfiguredJarList) Filter(jarsToKeep []string) (ConfiguredJarList, []string) {
  120. var apexes []string
  121. var jars []string
  122. for i, jar := range l.jars {
  123. if InList(jar, jarsToKeep) {
  124. apexes = append(apexes, l.apexes[i])
  125. jars = append(jars, jar)
  126. }
  127. }
  128. return ConfiguredJarList{apexes, jars}, RemoveListFromList(jarsToKeep, jars)
  129. }
  130. // CopyOfJars returns a copy of the list of strings containing jar module name
  131. // components.
  132. func (l *ConfiguredJarList) CopyOfJars() []string {
  133. return CopyOf(l.jars)
  134. }
  135. // CopyOfApexJarPairs returns a copy of the list of strings with colon-separated
  136. // (apex, jar) pairs.
  137. func (l *ConfiguredJarList) CopyOfApexJarPairs() []string {
  138. pairs := make([]string, 0, l.Len())
  139. for i, jar := range l.jars {
  140. apex := l.apexes[i]
  141. pairs = append(pairs, apex+":"+jar)
  142. }
  143. return pairs
  144. }
  145. // BuildPaths returns a list of build paths based on the given directory prefix.
  146. func (l *ConfiguredJarList) BuildPaths(ctx PathContext, dir OutputPath) WritablePaths {
  147. paths := make(WritablePaths, l.Len())
  148. for i, jar := range l.jars {
  149. paths[i] = dir.Join(ctx, ModuleStem(jar)+".jar")
  150. }
  151. return paths
  152. }
  153. // BuildPathsByModule returns a map from module name to build paths based on the given directory
  154. // prefix.
  155. func (l *ConfiguredJarList) BuildPathsByModule(ctx PathContext, dir OutputPath) map[string]WritablePath {
  156. paths := map[string]WritablePath{}
  157. for _, jar := range l.jars {
  158. paths[jar] = dir.Join(ctx, ModuleStem(jar)+".jar")
  159. }
  160. return paths
  161. }
  162. // UnmarshalJSON converts JSON configuration from raw bytes into a
  163. // ConfiguredJarList structure.
  164. func (l *ConfiguredJarList) UnmarshalJSON(b []byte) error {
  165. // Try and unmarshal into a []string each item of which contains a pair
  166. // <apex>:<jar>.
  167. var list []string
  168. err := json.Unmarshal(b, &list)
  169. if err != nil {
  170. // Did not work so return
  171. return err
  172. }
  173. apexes, jars, err := splitListOfPairsIntoPairOfLists(list)
  174. if err != nil {
  175. return err
  176. }
  177. l.apexes = apexes
  178. l.jars = jars
  179. return nil
  180. }
  181. func (l *ConfiguredJarList) MarshalJSON() ([]byte, error) {
  182. if len(l.apexes) != len(l.jars) {
  183. return nil, errors.New(fmt.Sprintf("Inconsistent ConfiguredJarList: apexes: %q, jars: %q", l.apexes, l.jars))
  184. }
  185. list := make([]string, 0, len(l.apexes))
  186. for i := 0; i < len(l.apexes); i++ {
  187. list = append(list, l.apexes[i]+":"+l.jars[i])
  188. }
  189. return json.Marshal(list)
  190. }
  191. // ModuleStem hardcodes the stem of framework-minus-apex to return "framework".
  192. //
  193. // TODO(b/139391334): hard coded until we find a good way to query the stem of a
  194. // module before any other mutators are run.
  195. func ModuleStem(module string) string {
  196. if module == "framework-minus-apex" {
  197. return "framework"
  198. }
  199. return module
  200. }
  201. // DevicePaths computes the on-device paths for the list of (apex, jar) pairs,
  202. // based on the operating system.
  203. func (l *ConfiguredJarList) DevicePaths(cfg Config, ostype OsType) []string {
  204. paths := make([]string, l.Len())
  205. for i, jar := range l.jars {
  206. apex := l.apexes[i]
  207. name := ModuleStem(jar) + ".jar"
  208. var subdir string
  209. if apex == "platform" {
  210. subdir = "system/framework"
  211. } else if apex == "system_ext" {
  212. subdir = "system_ext/framework"
  213. } else {
  214. subdir = filepath.Join("apex", apex, "javalib")
  215. }
  216. if ostype.Class == Host {
  217. paths[i] = filepath.Join(cfg.Getenv("OUT_DIR"), "host", cfg.PrebuiltOS(), subdir, name)
  218. } else {
  219. paths[i] = filepath.Join("/", subdir, name)
  220. }
  221. }
  222. return paths
  223. }
  224. func (l *ConfiguredJarList) String() string {
  225. var pairs []string
  226. for i := 0; i < l.Len(); i++ {
  227. pairs = append(pairs, l.apexes[i]+":"+l.jars[i])
  228. }
  229. return strings.Join(pairs, ",")
  230. }
  231. func splitListOfPairsIntoPairOfLists(list []string) ([]string, []string, error) {
  232. // Now we need to populate this list by splitting each item in the slice of
  233. // pairs and appending them to the appropriate list of apexes or jars.
  234. apexes := make([]string, len(list))
  235. jars := make([]string, len(list))
  236. for i, apexjar := range list {
  237. apex, jar, err := splitConfiguredJarPair(apexjar)
  238. if err != nil {
  239. return nil, nil, err
  240. }
  241. apexes[i] = apex
  242. jars[i] = jar
  243. }
  244. return apexes, jars, nil
  245. }
  246. // Expected format for apexJarValue = <apex name>:<jar name>
  247. func splitConfiguredJarPair(str string) (string, string, error) {
  248. pair := strings.SplitN(str, ":", 2)
  249. if len(pair) == 2 {
  250. apex := pair[0]
  251. jar := pair[1]
  252. if apex == "" {
  253. return apex, jar, fmt.Errorf("invalid apex '%s' in <apex>:<jar> pair '%s', expected format: <apex>:<jar>", apex, str)
  254. }
  255. return apex, jar, nil
  256. } else {
  257. return "error-apex", "error-jar", fmt.Errorf("malformed (apex, jar) pair: '%s', expected format: <apex>:<jar>", str)
  258. }
  259. }
  260. // EmptyConfiguredJarList returns an empty jar list.
  261. func EmptyConfiguredJarList() ConfiguredJarList {
  262. return ConfiguredJarList{}
  263. }
  264. var earlyBootJarsKey = NewOnceKey("earlyBootJars")