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 15package apex 16 17import ( 18 "fmt" 19 "io" 20 "path/filepath" 21 "strings" 22 23 "android/soong/android" 24 "android/soong/cc" 25 "android/soong/java" 26 27 "github.com/google/blueprint/proptools" 28) 29 30func (a *apexBundle) AndroidMk() android.AndroidMkData { 31 if a.properties.HideFromMake { 32 return android.AndroidMkData{ 33 Disabled: true, 34 } 35 } 36 writers := []android.AndroidMkData{} 37 writers = append(writers, a.androidMkForType()) 38 return android.AndroidMkData{ 39 Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) { 40 for _, data := range writers { 41 data.Custom(w, name, prefix, moduleDir, data) 42 } 43 }} 44} 45 46func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, moduleDir string) []string { 47 // apexBundleName comes from the 'name' property; apexName comes from 'apex_name' property. 48 // An apex is installed to /system/apex/<apexBundleName> and is activated at /apex/<apexName> 49 // In many cases, the two names are the same, but could be different in general. 50 51 moduleNames := []string{} 52 apexType := a.properties.ApexType 53 // To avoid creating duplicate build rules, run this function only when primaryApexType is true 54 // to install symbol files in $(PRODUCT_OUT}/apex. 55 // And if apexType is flattened, run this function to install files in $(PRODUCT_OUT}/system/apex. 56 if !a.primaryApexType && apexType != flattenedApex { 57 return moduleNames 58 } 59 60 // b/140136207. When there are overriding APEXes for a VNDK APEX, the symbols file for the overridden 61 // APEX and the overriding APEX will have the same installation paths at /apex/com.android.vndk.v<ver> 62 // as their apexName will be the same. To avoid the path conflicts, skip installing the symbol files 63 // for the overriding VNDK APEXes. 64 symbolFilesNotNeeded := a.vndkApex && len(a.overridableProperties.Overrides) > 0 65 if symbolFilesNotNeeded && apexType != flattenedApex { 66 return moduleNames 67 } 68 69 var postInstallCommands []string 70 for _, fi := range a.filesInfo { 71 if a.linkToSystemLib && fi.transitiveDep && fi.AvailableToPlatform() { 72 // TODO(jiyong): pathOnDevice should come from fi.module, not being calculated here 73 linkTarget := filepath.Join("/system", fi.Path()) 74 linkPath := filepath.Join(a.installDir.ToMakePath().String(), apexBundleName, fi.Path()) 75 mkdirCmd := "mkdir -p " + filepath.Dir(linkPath) 76 linkCmd := "ln -sfn " + linkTarget + " " + linkPath 77 postInstallCommands = append(postInstallCommands, mkdirCmd, linkCmd) 78 } 79 } 80 81 for _, fi := range a.filesInfo { 82 if ccMod, ok := fi.module.(*cc.Module); ok && ccMod.Properties.HideFromMake { 83 continue 84 } 85 86 linkToSystemLib := a.linkToSystemLib && fi.transitiveDep && fi.AvailableToPlatform() 87 88 var moduleName string 89 if linkToSystemLib { 90 moduleName = fi.moduleName 91 } else { 92 moduleName = fi.moduleName + "." + apexBundleName + a.suffix 93 } 94 95 if !android.InList(moduleName, moduleNames) { 96 moduleNames = append(moduleNames, moduleName) 97 } 98 99 if linkToSystemLib { 100 // No need to copy the file since it's linked to the system file 101 continue 102 } 103 104 fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)") 105 if fi.moduleDir != "" { 106 fmt.Fprintln(w, "LOCAL_PATH :=", fi.moduleDir) 107 } else { 108 fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir) 109 } 110 fmt.Fprintln(w, "LOCAL_MODULE :=", moduleName) 111 if fi.module != nil && fi.module.Owner() != "" { 112 fmt.Fprintln(w, "LOCAL_MODULE_OWNER :=", fi.module.Owner()) 113 } 114 // /apex/<apex_name>/{lib|framework|...} 115 pathWhenActivated := filepath.Join("$(PRODUCT_OUT)", "apex", apexName, fi.installDir) 116 var modulePath string 117 if apexType == flattenedApex { 118 // /system/apex/<name>/{lib|framework|...} 119 modulePath = filepath.Join(a.installDir.ToMakePath().String(), apexBundleName, fi.installDir) 120 fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", modulePath) 121 if a.primaryApexType && !symbolFilesNotNeeded { 122 fmt.Fprintln(w, "LOCAL_SOONG_SYMBOL_PATH :=", pathWhenActivated) 123 } 124 if len(fi.symlinks) > 0 { 125 fmt.Fprintln(w, "LOCAL_MODULE_SYMLINKS :=", strings.Join(fi.symlinks, " ")) 126 } 127 128 if fi.module != nil && fi.module.NoticeFile().Valid() { 129 fmt.Fprintln(w, "LOCAL_NOTICE_FILE :=", fi.module.NoticeFile().Path().String()) 130 } 131 } else { 132 modulePath = pathWhenActivated 133 fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", pathWhenActivated) 134 135 // For non-flattend APEXes, the merged notice file is attached to the APEX itself. 136 // We don't need to have notice file for the individual modules in it. Otherwise, 137 // we will have duplicated notice entries. 138 fmt.Fprintln(w, "LOCAL_NO_NOTICE_FILE := true") 139 } 140 fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", fi.builtFile.String()) 141 fmt.Fprintln(w, "LOCAL_MODULE_CLASS :=", fi.class.NameInMake()) 142 if fi.module != nil { 143 archStr := fi.module.Target().Arch.ArchType.String() 144 host := false 145 switch fi.module.Target().Os.Class { 146 case android.Host: 147 if fi.module.Target().Arch.ArchType != android.Common { 148 fmt.Fprintln(w, "LOCAL_MODULE_HOST_ARCH :=", archStr) 149 } 150 host = true 151 case android.HostCross: 152 if fi.module.Target().Arch.ArchType != android.Common { 153 fmt.Fprintln(w, "LOCAL_MODULE_HOST_CROSS_ARCH :=", archStr) 154 } 155 host = true 156 case android.Device: 157 if fi.module.Target().Arch.ArchType != android.Common { 158 fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", archStr) 159 } 160 } 161 if host { 162 makeOs := fi.module.Target().Os.String() 163 if fi.module.Target().Os == android.Linux || fi.module.Target().Os == android.LinuxBionic { 164 makeOs = "linux" 165 } 166 fmt.Fprintln(w, "LOCAL_MODULE_HOST_OS :=", makeOs) 167 fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true") 168 } 169 } 170 if fi.jacocoReportClassesFile != nil { 171 fmt.Fprintln(w, "LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=", fi.jacocoReportClassesFile.String()) 172 } 173 switch fi.class { 174 case javaSharedLib: 175 // soong_java_prebuilt.mk sets LOCAL_MODULE_SUFFIX := .jar Therefore 176 // we need to remove the suffix from LOCAL_MODULE_STEM, otherwise 177 // we will have foo.jar.jar 178 fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", strings.TrimSuffix(fi.Stem(), ".jar")) 179 if javaModule, ok := fi.module.(java.ApexDependency); ok { 180 fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", javaModule.ImplementationAndResourcesJars()[0].String()) 181 fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", javaModule.HeaderJars()[0].String()) 182 } else { 183 fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", fi.builtFile.String()) 184 fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", fi.builtFile.String()) 185 } 186 fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", fi.builtFile.String()) 187 fmt.Fprintln(w, "LOCAL_DEX_PREOPT := false") 188 fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_java_prebuilt.mk") 189 case app: 190 fmt.Fprintln(w, "LOCAL_CERTIFICATE :=", fi.certificate.AndroidMkString()) 191 // soong_app_prebuilt.mk sets LOCAL_MODULE_SUFFIX := .apk Therefore 192 // we need to remove the suffix from LOCAL_MODULE_STEM, otherwise 193 // we will have foo.apk.apk 194 fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", strings.TrimSuffix(fi.Stem(), ".apk")) 195 if app, ok := fi.module.(*java.AndroidApp); ok { 196 if jniCoverageOutputs := app.JniCoverageOutputs(); len(jniCoverageOutputs) > 0 { 197 fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", strings.Join(jniCoverageOutputs.Strings(), " ")) 198 } 199 if jniLibSymbols := app.JNISymbolsInstalls(modulePath); len(jniLibSymbols) > 0 { 200 fmt.Fprintln(w, "LOCAL_SOONG_JNI_LIBS_SYMBOLS :=", jniLibSymbols.String()) 201 } 202 } 203 fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_app_prebuilt.mk") 204 case appSet: 205 as, ok := fi.module.(*java.AndroidAppSet) 206 if !ok { 207 panic(fmt.Sprintf("Expected %s to be AndroidAppSet", fi.module)) 208 } 209 fmt.Fprintln(w, "LOCAL_APK_SET_MASTER_FILE :=", as.MasterFile()) 210 fmt.Fprintln(w, "LOCAL_APKCERTS_FILE :=", as.APKCertsFile().String()) 211 fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_android_app_set.mk") 212 case nativeSharedLib, nativeExecutable, nativeTest: 213 fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.Stem()) 214 if ccMod, ok := fi.module.(*cc.Module); ok { 215 if ccMod.UnstrippedOutputFile() != nil { 216 fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", ccMod.UnstrippedOutputFile().String()) 217 } 218 ccMod.AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w) 219 if ccMod.CoverageOutputFile().Valid() { 220 fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", ccMod.CoverageOutputFile().String()) 221 } 222 } 223 fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_cc_prebuilt.mk") 224 default: 225 fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.Stem()) 226 if fi.builtFile == a.manifestPbOut && apexType == flattenedApex { 227 if a.primaryApexType { 228 // Make apex_manifest.pb module for this APEX to override all other 229 // modules in the APEXes being overridden by this APEX 230 var patterns []string 231 for _, o := range a.overridableProperties.Overrides { 232 patterns = append(patterns, "%."+o+a.suffix) 233 } 234 fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES :=", strings.Join(patterns, " ")) 235 236 if len(a.compatSymlinks) > 0 { 237 // For flattened apexes, compat symlinks are attached to apex_manifest.json which is guaranteed for every apex 238 postInstallCommands = append(postInstallCommands, a.compatSymlinks...) 239 } 240 } 241 if len(postInstallCommands) > 0 { 242 fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD :=", strings.Join(postInstallCommands, " && ")) 243 } 244 } 245 fmt.Fprintln(w, "include $(BUILD_PREBUILT)") 246 } 247 248 // m <module_name> will build <module_name>.<apex_name> as well. 249 if fi.moduleName != moduleName && a.primaryApexType { 250 fmt.Fprintln(w, ".PHONY: "+fi.moduleName) 251 fmt.Fprintln(w, fi.moduleName+": "+moduleName) 252 } 253 } 254 return moduleNames 255} 256 257func (a *apexBundle) writeRequiredModules(w io.Writer) { 258 var required []string 259 var targetRequired []string 260 var hostRequired []string 261 for _, fi := range a.filesInfo { 262 required = append(required, fi.requiredModuleNames...) 263 targetRequired = append(targetRequired, fi.targetRequiredModuleNames...) 264 hostRequired = append(hostRequired, fi.hostRequiredModuleNames...) 265 } 266 267 if len(required) > 0 { 268 fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(required, " ")) 269 } 270 if len(targetRequired) > 0 { 271 fmt.Fprintln(w, "LOCAL_TARGET_REQUIRED_MODULES +=", strings.Join(targetRequired, " ")) 272 } 273 if len(hostRequired) > 0 { 274 fmt.Fprintln(w, "LOCAL_HOST_REQUIRED_MODULES +=", strings.Join(hostRequired, " ")) 275 } 276} 277 278func (a *apexBundle) androidMkForType() android.AndroidMkData { 279 return android.AndroidMkData{ 280 Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) { 281 moduleNames := []string{} 282 apexType := a.properties.ApexType 283 if a.installable() { 284 apexName := proptools.StringDefault(a.properties.Apex_name, name) 285 moduleNames = a.androidMkForFiles(w, name, apexName, moduleDir) 286 } 287 288 if apexType == flattenedApex { 289 // Only image APEXes can be flattened. 290 fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)") 291 fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir) 292 fmt.Fprintln(w, "LOCAL_MODULE :=", name+a.suffix) 293 if len(moduleNames) > 0 { 294 fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(moduleNames, " ")) 295 } 296 a.writeRequiredModules(w) 297 fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)") 298 299 } else { 300 fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)") 301 fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir) 302 fmt.Fprintln(w, "LOCAL_MODULE :=", name+a.suffix) 303 fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC") // do we need a new class? 304 fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", a.outputFile.String()) 305 fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", a.installDir.ToMakePath().String()) 306 fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", name+apexType.suffix()) 307 fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !a.installable()) 308 fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES :=", strings.Join(a.overridableProperties.Overrides, " ")) 309 if len(moduleNames) > 0 { 310 fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(moduleNames, " ")) 311 } 312 if len(a.requiredDeps) > 0 { 313 fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(a.requiredDeps, " ")) 314 } 315 a.writeRequiredModules(w) 316 var postInstallCommands []string 317 if a.prebuiltFileToDelete != "" { 318 postInstallCommands = append(postInstallCommands, "rm -rf "+ 319 filepath.Join(a.installDir.ToMakePath().String(), a.prebuiltFileToDelete)) 320 } 321 // For unflattened apexes, compat symlinks are attached to apex package itself as LOCAL_POST_INSTALL_CMD 322 postInstallCommands = append(postInstallCommands, a.compatSymlinks...) 323 if len(postInstallCommands) > 0 { 324 fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD :=", strings.Join(postInstallCommands, " && ")) 325 } 326 327 if a.mergedNotices.Merged.Valid() { 328 fmt.Fprintln(w, "LOCAL_NOTICE_FILE :=", a.mergedNotices.Merged.Path().String()) 329 } 330 331 fmt.Fprintln(w, "include $(BUILD_PREBUILT)") 332 333 if apexType == imageApex { 334 fmt.Fprintln(w, "ALL_MODULES.$(LOCAL_MODULE).BUNDLE :=", a.bundleModuleFile.String()) 335 } 336 if len(a.lintReports) > 0 { 337 fmt.Fprintln(w, "ALL_MODULES.$(my_register_name).LINT_REPORTS :=", 338 strings.Join(a.lintReports.Strings(), " ")) 339 } 340 341 if a.installedFilesFile != nil { 342 goal := "checkbuild" 343 distFile := name + "-installed-files.txt" 344 fmt.Fprintln(w, ".PHONY:", goal) 345 fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n", 346 goal, a.installedFilesFile.String(), distFile) 347 } 348 } 349 }} 350} 351