vendor_snapshot.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. // Copyright 2020 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 cc
  15. import (
  16. "encoding/json"
  17. "path/filepath"
  18. "strings"
  19. "android/soong/android"
  20. "android/soong/snapshot"
  21. )
  22. // This file defines how to capture cc modules into snapshot package.
  23. // Checks if the target image would contain VNDK
  24. func includeVndk(image snapshot.SnapshotImage) bool {
  25. if image.ImageName() == snapshot.VendorSnapshotImageName {
  26. return true
  27. }
  28. return false
  29. }
  30. // Check if the module is VNDK private
  31. func isPrivate(image snapshot.SnapshotImage, m LinkableInterface) bool {
  32. if image.ImageName() == snapshot.VendorSnapshotImageName && m.IsVndkPrivate() {
  33. return true
  34. }
  35. return false
  36. }
  37. // Checks if target image supports VNDK Ext
  38. func supportsVndkExt(image snapshot.SnapshotImage) bool {
  39. if image.ImageName() == snapshot.VendorSnapshotImageName {
  40. return true
  41. }
  42. return false
  43. }
  44. // Determines if the module is a candidate for snapshot.
  45. func isSnapshotAware(cfg android.DeviceConfig, m LinkableInterface, inProprietaryPath bool, apexInfo android.ApexInfo, image snapshot.SnapshotImage) bool {
  46. if !m.Enabled() || m.HiddenFromMake() {
  47. return false
  48. }
  49. // When android/prebuilt.go selects between source and prebuilt, it sets
  50. // HideFromMake on the other one to avoid duplicate install rules in make.
  51. if m.IsHideFromMake() {
  52. return false
  53. }
  54. // skip proprietary modules, but (for the vendor snapshot only)
  55. // include all VNDK (static)
  56. if inProprietaryPath && (!includeVndk(image) || !m.IsVndk()) {
  57. return false
  58. }
  59. // If the module would be included based on its path, check to see if
  60. // the module is marked to be excluded. If so, skip it.
  61. if image.ExcludeFromSnapshot(m) {
  62. return false
  63. }
  64. if m.Target().Os.Class != android.Device {
  65. return false
  66. }
  67. if m.Target().NativeBridge == android.NativeBridgeEnabled {
  68. return false
  69. }
  70. // the module must be installed in target image
  71. if !apexInfo.IsForPlatform() || m.IsSnapshotPrebuilt() || !image.InImage(m)() {
  72. return false
  73. }
  74. // skip kernel_headers which always depend on vendor
  75. if m.KernelHeadersDecorator() {
  76. return false
  77. }
  78. if m.IsLlndk() {
  79. return false
  80. }
  81. // Libraries
  82. if sanitizable, ok := m.(PlatformSanitizeable); ok && sanitizable.IsSnapshotLibrary() {
  83. if sanitizable.SanitizePropDefined() {
  84. // scs exports both sanitized and unsanitized variants for static and header
  85. // Always use unsanitized variant of it.
  86. if !sanitizable.Shared() && sanitizable.IsSanitizerEnabled(scs) {
  87. return false
  88. }
  89. // cfi and hwasan also export both variants. But for static, we capture both.
  90. // This is because cfi static libraries can't be linked from non-cfi modules,
  91. // and vice versa.
  92. // hwasan is captured as well to support hwasan build.
  93. if !sanitizable.Static() &&
  94. !sanitizable.Shared() &&
  95. (sanitizable.IsSanitizerEnabled(cfi) || sanitizable.IsSanitizerEnabled(Hwasan)) {
  96. return false
  97. }
  98. }
  99. if sanitizable.Static() {
  100. return sanitizable.OutputFile().Valid() && !isPrivate(image, m)
  101. }
  102. if sanitizable.Shared() || sanitizable.Rlib() {
  103. if !sanitizable.OutputFile().Valid() {
  104. return false
  105. }
  106. if includeVndk(image) {
  107. if !sanitizable.IsVndk() {
  108. return true
  109. }
  110. return sanitizable.IsVndkExt()
  111. }
  112. }
  113. return true
  114. }
  115. // Binaries and Objects
  116. if m.Binary() || m.Object() {
  117. return m.OutputFile().Valid()
  118. }
  119. return false
  120. }
  121. // Extend the snapshot.SnapshotJsonFlags to include cc specific fields.
  122. type snapshotJsonFlags struct {
  123. snapshot.SnapshotJsonFlags
  124. // library flags
  125. ExportedDirs []string `json:",omitempty"`
  126. ExportedSystemDirs []string `json:",omitempty"`
  127. ExportedFlags []string `json:",omitempty"`
  128. Sanitize string `json:",omitempty"`
  129. SanitizeMinimalDep bool `json:",omitempty"`
  130. SanitizeUbsanDep bool `json:",omitempty"`
  131. // binary flags
  132. Symlinks []string `json:",omitempty"`
  133. StaticExecutable bool `json:",omitempty"`
  134. InstallInRoot bool `json:",omitempty"`
  135. // dependencies
  136. SharedLibs []string `json:",omitempty"`
  137. StaticLibs []string `json:",omitempty"`
  138. RuntimeLibs []string `json:",omitempty"`
  139. // extra config files
  140. InitRc []string `json:",omitempty"`
  141. VintfFragments []string `json:",omitempty"`
  142. MinSdkVersion string `json:",omitempty"`
  143. }
  144. var ccSnapshotAction snapshot.GenerateSnapshotAction = func(s snapshot.SnapshotSingleton, ctx android.SingletonContext, snapshotArchDir string) snapshot.SnapshotPaths {
  145. /*
  146. Vendor snapshot zipped artifacts directory structure for cc modules:
  147. {SNAPSHOT_ARCH}/
  148. arch-{TARGET_ARCH}-{TARGET_ARCH_VARIANT}/
  149. shared/
  150. (.so shared libraries)
  151. static/
  152. (.a static libraries)
  153. header/
  154. (header only libraries)
  155. binary/
  156. (executable binaries)
  157. object/
  158. (.o object files)
  159. arch-{TARGET_2ND_ARCH}-{TARGET_2ND_ARCH_VARIANT}/
  160. shared/
  161. (.so shared libraries)
  162. static/
  163. (.a static libraries)
  164. header/
  165. (header only libraries)
  166. binary/
  167. (executable binaries)
  168. object/
  169. (.o object files)
  170. NOTICE_FILES/
  171. (notice files, e.g. libbase.txt)
  172. configs/
  173. (config files, e.g. init.rc files, vintf_fragments.xml files, etc.)
  174. include/
  175. (header files of same directory structure with source tree)
  176. */
  177. var snapshotOutputs android.Paths
  178. var snapshotNotices android.Paths
  179. includeDir := filepath.Join(snapshotArchDir, "include")
  180. configsDir := filepath.Join(snapshotArchDir, "configs")
  181. installedNotices := make(map[string]bool)
  182. installedConfigs := make(map[string]bool)
  183. var headers android.Paths
  184. copyFile := func(ctx android.SingletonContext, path android.Path, out string, fake bool) android.OutputPath {
  185. if fake {
  186. // All prebuilt binaries and headers are installed by copyFile function. This makes a fake
  187. // snapshot just touch prebuilts and headers, rather than installing real files.
  188. return snapshot.WriteStringToFileRule(ctx, "", out)
  189. } else {
  190. return snapshot.CopyFileRule(pctx, ctx, path, out)
  191. }
  192. }
  193. // installSnapshot function copies prebuilt file (.so, .a, or executable) and json flag file.
  194. // For executables, init_rc and vintf_fragments files are also copied.
  195. installSnapshot := func(m LinkableInterface, fake bool) android.Paths {
  196. targetArch := "arch-" + m.Target().Arch.ArchType.String()
  197. if m.Target().Arch.ArchVariant != "" {
  198. targetArch += "-" + m.Target().Arch.ArchVariant
  199. }
  200. var ret android.Paths
  201. prop := snapshotJsonFlags{}
  202. // Common properties among snapshots.
  203. prop.InitBaseSnapshotPropsWithName(m, ctx.ModuleName(m))
  204. if supportsVndkExt(s.Image) && m.IsVndkExt() {
  205. // vndk exts are installed to /vendor/lib(64)?/vndk(-sp)?
  206. if m.IsVndkSp() {
  207. prop.RelativeInstallPath = "vndk-sp"
  208. } else {
  209. prop.RelativeInstallPath = "vndk"
  210. }
  211. } else {
  212. prop.RelativeInstallPath = m.RelativeInstallPath()
  213. }
  214. prop.RuntimeLibs = m.SnapshotRuntimeLibs()
  215. prop.Required = m.RequiredModuleNames()
  216. if o, ok := m.(overridable); ok {
  217. prop.Overrides = o.overriddenModules()
  218. }
  219. for _, path := range m.InitRc() {
  220. prop.InitRc = append(prop.InitRc, filepath.Join("configs", path.Base()))
  221. }
  222. for _, path := range m.VintfFragments() {
  223. prop.VintfFragments = append(prop.VintfFragments, filepath.Join("configs", path.Base()))
  224. }
  225. if m.IsPrebuilt() {
  226. prop.MinSdkVersion = "apex_inherit"
  227. } else {
  228. prop.MinSdkVersion = m.MinSdkVersion()
  229. }
  230. // install config files. ignores any duplicates.
  231. for _, path := range append(m.InitRc(), m.VintfFragments()...) {
  232. out := filepath.Join(configsDir, path.Base())
  233. if !installedConfigs[out] {
  234. installedConfigs[out] = true
  235. ret = append(ret, copyFile(ctx, path, out, fake))
  236. }
  237. }
  238. var propOut string
  239. if m.IsSnapshotLibrary() {
  240. exporterInfo := ctx.ModuleProvider(m.Module(), FlagExporterInfoProvider).(FlagExporterInfo)
  241. // library flags
  242. prop.ExportedFlags = exporterInfo.Flags
  243. for _, dir := range exporterInfo.IncludeDirs {
  244. prop.ExportedDirs = append(prop.ExportedDirs, filepath.Join("include", dir.String()))
  245. }
  246. for _, dir := range exporterInfo.SystemIncludeDirs {
  247. prop.ExportedSystemDirs = append(prop.ExportedSystemDirs, filepath.Join("include", dir.String()))
  248. }
  249. // shared libs dependencies aren't meaningful on static or header libs
  250. if m.Shared() {
  251. prop.SharedLibs = m.SnapshotSharedLibs()
  252. }
  253. // static libs dependencies are required to collect the NOTICE files.
  254. prop.StaticLibs = m.SnapshotStaticLibs()
  255. if sanitizable, ok := m.(PlatformSanitizeable); ok {
  256. if sanitizable.Static() && sanitizable.SanitizePropDefined() {
  257. prop.SanitizeMinimalDep = sanitizable.MinimalRuntimeDep() || sanitizable.MinimalRuntimeNeeded()
  258. prop.SanitizeUbsanDep = sanitizable.UbsanRuntimeDep() || sanitizable.UbsanRuntimeNeeded()
  259. }
  260. }
  261. var libType string
  262. if m.Static() {
  263. libType = "static"
  264. } else if m.Shared() {
  265. libType = "shared"
  266. } else if m.Rlib() {
  267. libType = "rlib"
  268. } else {
  269. libType = "header"
  270. }
  271. var stem string
  272. // install .a or .so
  273. if libType != "header" {
  274. libPath := m.OutputFile().Path()
  275. stem = libPath.Base()
  276. if sanitizable, ok := m.(PlatformSanitizeable); ok {
  277. if (sanitizable.Static() || sanitizable.Rlib()) && sanitizable.SanitizePropDefined() {
  278. if sanitizable.IsSanitizerEnabled(cfi) {
  279. // both cfi and non-cfi variant for static libraries can exist.
  280. // attach .cfi to distinguish between cfi and non-cfi.
  281. // e.g. libbase.a -> libbase.cfi.a
  282. ext := filepath.Ext(stem)
  283. stem = strings.TrimSuffix(stem, ext) + ".cfi" + ext
  284. prop.Sanitize = "cfi"
  285. prop.ModuleName += ".cfi"
  286. } else if sanitizable.IsSanitizerEnabled(Hwasan) {
  287. // Same for the hwasan
  288. ext := filepath.Ext(stem)
  289. stem = strings.TrimSuffix(stem, ext) + ".hwasan" + ext
  290. prop.Sanitize = "hwasan"
  291. prop.ModuleName += ".hwasan"
  292. }
  293. }
  294. }
  295. snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, libType, m.RelativeInstallPath(), stem)
  296. ret = append(ret, copyFile(ctx, libPath, snapshotLibOut, fake))
  297. } else {
  298. stem = ctx.ModuleName(m)
  299. }
  300. propOut = filepath.Join(snapshotArchDir, targetArch, libType, m.RelativeInstallPath(), stem+".json")
  301. } else if m.Binary() {
  302. // binary flags
  303. prop.Symlinks = m.Symlinks()
  304. prop.StaticExecutable = m.StaticExecutable()
  305. prop.InstallInRoot = m.InstallInRoot()
  306. prop.SharedLibs = m.SnapshotSharedLibs()
  307. // static libs dependencies are required to collect the NOTICE files.
  308. prop.StaticLibs = m.SnapshotStaticLibs()
  309. // install bin
  310. binPath := m.OutputFile().Path()
  311. snapshotBinOut := filepath.Join(snapshotArchDir, targetArch, "binary", binPath.Base())
  312. ret = append(ret, copyFile(ctx, binPath, snapshotBinOut, fake))
  313. propOut = snapshotBinOut + ".json"
  314. } else if m.Object() {
  315. // object files aren't installed to the device, so their names can conflict.
  316. // Use module name as stem.
  317. objPath := m.OutputFile().Path()
  318. snapshotObjOut := filepath.Join(snapshotArchDir, targetArch, "object",
  319. ctx.ModuleName(m)+filepath.Ext(objPath.Base()))
  320. ret = append(ret, copyFile(ctx, objPath, snapshotObjOut, fake))
  321. propOut = snapshotObjOut + ".json"
  322. } else {
  323. ctx.Errorf("unknown module %q in vendor snapshot", m.String())
  324. return nil
  325. }
  326. j, err := json.Marshal(prop)
  327. if err != nil {
  328. ctx.Errorf("json marshal to %q failed: %#v", propOut, err)
  329. return nil
  330. }
  331. ret = append(ret, snapshot.WriteStringToFileRule(ctx, string(j), propOut))
  332. return ret
  333. }
  334. ctx.VisitAllModules(func(module android.Module) {
  335. m, ok := module.(LinkableInterface)
  336. if !ok {
  337. return
  338. }
  339. moduleDir := ctx.ModuleDir(module)
  340. inProprietaryPath := s.Image.IsProprietaryPath(moduleDir, ctx.DeviceConfig())
  341. apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
  342. if s.Image.ExcludeFromSnapshot(m) {
  343. if inProprietaryPath {
  344. // Error: exclude_from_vendor_snapshot applies
  345. // to framework-path modules only.
  346. ctx.Errorf("module %q in vendor proprietary path %q may not use \"exclude_from_vendor_snapshot: true\"", m.String(), moduleDir)
  347. return
  348. }
  349. }
  350. if !isSnapshotAware(ctx.DeviceConfig(), m, inProprietaryPath, apexInfo, s.Image) {
  351. return
  352. }
  353. // If we are using directed snapshot and a module is not included in the
  354. // list, we will still include the module as if it was a fake module.
  355. // The reason is that soong needs all the dependencies to be present, even
  356. // if they are not using during the build.
  357. installAsFake := s.Fake
  358. if s.Image.ExcludeFromDirectedSnapshot(ctx.DeviceConfig(), m.BaseModuleName()) {
  359. installAsFake = true
  360. }
  361. // installSnapshot installs prebuilts and json flag files
  362. snapshotOutputs = append(snapshotOutputs, installSnapshot(m, installAsFake)...)
  363. // just gather headers and notice files here, because they are to be deduplicated
  364. if m.IsSnapshotLibrary() {
  365. headers = append(headers, m.SnapshotHeaders()...)
  366. }
  367. for _, notice := range m.EffectiveLicenseFiles() {
  368. if _, ok := installedNotices[notice.String()]; !ok {
  369. installedNotices[notice.String()] = true
  370. snapshotNotices = append(snapshotNotices, notice)
  371. }
  372. }
  373. })
  374. // install all headers after removing duplicates
  375. for _, header := range android.FirstUniquePaths(headers) {
  376. snapshotOutputs = append(snapshotOutputs, copyFile(ctx, header, filepath.Join(includeDir, header.String()), s.Fake))
  377. }
  378. return snapshot.SnapshotPaths{OutputFiles: snapshotOutputs, NoticeFiles: snapshotNotices}
  379. }
  380. func init() {
  381. snapshot.RegisterSnapshotAction(ccSnapshotAction)
  382. }