diff options
-rw-r--r-- | android/config.go | 4 | ||||
-rw-r--r-- | android/variable.go | 2 | ||||
-rw-r--r-- | apex/apex.go | 204 | ||||
-rw-r--r-- | cc/config/arm_device.go | 14 | ||||
-rw-r--r-- | java/config/kotlin.go | 6 | ||||
-rw-r--r-- | java/java.go | 46 | ||||
-rw-r--r-- | java/java_test.go | 61 | ||||
-rw-r--r-- | ui/build/paths/config.go | 4 |
8 files changed, 297 insertions, 44 deletions
diff --git a/android/config.go b/android/config.go index 695a2980..367b42c0 100644 --- a/android/config.go +++ b/android/config.go @@ -881,6 +881,10 @@ func (c *config) NdkAbis() bool { return Bool(c.productVariables.Ndk_abis) } +func (c *config) FlattenApex() bool { + return Bool(c.productVariables.FlattenApex) +} + func stringSlice(s *[]string) []string { if s != nil { return *s diff --git a/android/variable.go b/android/variable.go index 2686049d..2763bf29 100644 --- a/android/variable.go +++ b/android/variable.go @@ -250,6 +250,8 @@ type productVariables struct { VendorVars map[string]map[string]string `json:",omitempty"` Ndk_abis *bool `json:",omitempty"` + + FlattenApex *bool `json:",omitempty"` } func boolPtr(v bool) *bool { diff --git a/apex/apex.go b/apex/apex.go index 3e7c0a79..177856e6 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -171,8 +171,10 @@ type apexBundleProperties struct { // "manifest.json" Manifest *string - // File contexts file for setting security context to each file in this APEX bundle - // Default: "file_contexts". + // Determines the file contexts file for setting security context to each file in this APEX bundle. + // Specifically, when this is set to <value>, /system/sepolicy/apex/<value>_file_contexts file is + // used. + // Default: <name_of_this_module> File_contexts *string // List of native shared libs that are embedded inside this APEX bundle @@ -228,6 +230,38 @@ type apexBundleProperties struct { } } +type apexFileClass int + +const ( + etc apexFileClass = iota + nativeSharedLib + nativeExecutable + javaSharedLib +) + +func (class apexFileClass) NameInMake() string { + switch class { + case etc: + return "ETC" + case nativeSharedLib: + return "SHARED_LIBRARIES" + case nativeExecutable: + return "EXECUTABLES" + case javaSharedLib: + return "JAVA_LIBRARIES" + default: + panic(fmt.Errorf("unkonwn class %d", class)) + } +} + +type apexFile struct { + builtFile android.Path + moduleName string + archType android.ArchType + installDir string + class apexFileClass +} + type apexBundle struct { android.ModuleBase android.DefaultableModuleBase @@ -236,6 +270,11 @@ type apexBundle struct { outputFile android.WritablePath installDir android.OutputPath + + // list of files to be included in this apex + filesInfo []apexFile + + flattened bool } func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext, @@ -362,7 +401,7 @@ func getCopyManifestForExecutable(cc *cc.Module) (fileToCopy android.Path, dirIn func getCopyManifestForJavaLibrary(java *java.Library) (fileToCopy android.Path, dirInApex string) { dirInApex = "javalib" - fileToCopy = java.Srcs()[0] + fileToCopy = java.DexJarFile() return } @@ -373,8 +412,7 @@ func getCopyManifestForPrebuiltEtc(prebuilt *android.PrebuiltEtc) (fileToCopy an } func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { - // files to copy -> dir in apex - copyManifest := make(map[android.Path]string) + filesInfo := []apexFile{} var keyFile android.Path var certificate java.Certificate @@ -388,7 +426,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { case sharedLibTag: if cc, ok := child.(*cc.Module); ok { fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc) - copyManifest[fileToCopy] = dirInApex + filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeSharedLib}) return true } else { ctx.PropertyErrorf("native_shared_libs", "%q is not a cc_library or cc_library_shared module", depName) @@ -396,7 +434,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { case executableTag: if cc, ok := child.(*cc.Module); ok { fileToCopy, dirInApex := getCopyManifestForExecutable(cc) - copyManifest[fileToCopy] = dirInApex + filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeExecutable}) return true } else { ctx.PropertyErrorf("binaries", "%q is not a cc_binary module", depName) @@ -404,7 +442,11 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { case javaLibTag: if java, ok := child.(*java.Library); ok { fileToCopy, dirInApex := getCopyManifestForJavaLibrary(java) - copyManifest[fileToCopy] = dirInApex + if fileToCopy == nil { + ctx.PropertyErrorf("java_libs", "%q is not configured to be compiled into dex", depName) + } else { + filesInfo = append(filesInfo, apexFile{fileToCopy, depName, java.Arch().ArchType, dirInApex, javaSharedLib}) + } return true } else { ctx.PropertyErrorf("java_libs", "%q is not a java_library module", depName) @@ -412,7 +454,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { case prebuiltTag: if prebuilt, ok := child.(*android.PrebuiltEtc); ok { fileToCopy, dirInApex := getCopyManifestForPrebuiltEtc(prebuilt) - copyManifest[fileToCopy] = dirInApex + filesInfo = append(filesInfo, apexFile{fileToCopy, depName, prebuilt.Arch().ArchType, dirInApex, etc}) return true } else { ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName) @@ -436,8 +478,9 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { // indirect dependencies if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() && am.IsInstallableToApex() { if cc, ok := child.(*cc.Module); ok { + depName := ctx.OtherModuleName(child) fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc) - copyManifest[fileToCopy] = dirInApex + filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeSharedLib}) return true } } @@ -450,6 +493,42 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { return } + // remove duplicates in filesInfo + removeDup := func(filesInfo []apexFile) []apexFile { + encountered := make(map[android.Path]bool) + result := []apexFile{} + for _, f := range filesInfo { + if !encountered[f.builtFile] { + encountered[f.builtFile] = true + result = append(result, f) + } + } + return result + } + filesInfo = removeDup(filesInfo) + + // to have consistent build rules + sort.Slice(filesInfo, func(i, j int) bool { + return filesInfo[i].builtFile.String() < filesInfo[j].builtFile.String() + }) + + // prepend the name of this APEX to the module names. These names will be the names of + // modules that will be defined if the APEX is flattened. + for i := range filesInfo { + filesInfo[i].moduleName = ctx.ModuleName() + "." + filesInfo[i].moduleName + } + + a.flattened = ctx.Config().FlattenApex() + a.installDir = android.PathForModuleInstall(ctx, "apex") + a.filesInfo = filesInfo + if ctx.Config().FlattenApex() { + a.buildFlattenedApex(ctx) + } else { + a.buildUnflattenedApex(ctx, keyFile, certificate) + } +} + +func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, keyFile android.Path, certificate java.Certificate) { cert := String(a.properties.Certificate) if cert != "" && android.SrcIsModule(cert) == "" { defaultDir := ctx.Config().DefaultAppCertificateDir(ctx) @@ -465,15 +544,15 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { // files and dirs that will be created in apex var readOnlyPaths []string var executablePaths []string // this also includes dirs - for fileToCopy, dirInApex := range copyManifest { - pathInApex := filepath.Join(dirInApex, fileToCopy.Base()) - if dirInApex == "bin" { + for _, f := range a.filesInfo { + pathInApex := filepath.Join(f.installDir, f.builtFile.Base()) + if f.installDir == "bin" { executablePaths = append(executablePaths, pathInApex) } else { readOnlyPaths = append(readOnlyPaths, pathInApex) } - if !android.InList(dirInApex, executablePaths) { - executablePaths = append(executablePaths, dirInApex) + if !android.InList(f.installDir, executablePaths) { + executablePaths = append(executablePaths, f.installDir) } } sort.Strings(readOnlyPaths) @@ -489,21 +568,26 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { }) manifest := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "manifest.json")) - fileContexts := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.File_contexts, "file_contexts")) + + fcName := proptools.StringDefault(a.properties.File_contexts, a.ModuleBase.Name()) + fileContextsPath := "system/sepolicy/apex/" + fcName + "_file_contexts" + fileContextsOptionalPath := android.ExistentPathForSource(ctx, fileContextsPath) + if !fileContextsOptionalPath.Valid() { + ctx.ModuleErrorf("Cannot find file_contexts file: %q", fileContextsPath) + return + } + fileContexts := fileContextsOptionalPath.Path() unsignedOutputFile := android.PathForModuleOut(ctx, a.ModuleBase.Name()+apexSuffix+".unsigned") filesToCopy := []android.Path{} - for file := range copyManifest { - filesToCopy = append(filesToCopy, file) + for _, f := range a.filesInfo { + filesToCopy = append(filesToCopy, f.builtFile) } - sort.Slice(filesToCopy, func(i, j int) bool { - return filesToCopy[i].String() < filesToCopy[j].String() - }) copyCommands := []string{} - for _, src := range filesToCopy { - dest := filepath.Join(copyManifest[src], src.Base()) + for i, src := range filesToCopy { + dest := filepath.Join(a.filesInfo[i].installDir, src.Base()) dest_path := filepath.Join(android.PathForModuleOut(ctx, "image").String(), dest) copyCommands = append(copyCommands, "mkdir -p "+filepath.Dir(dest_path)) copyCommands = append(copyCommands, "cp "+src.String()+" "+dest_path) @@ -537,23 +621,71 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { "certificates": strings.Join([]string{certificate.Pem.String(), certificate.Key.String()}, " "), }, }) +} - a.installDir = android.PathForModuleInstall(ctx, "apex") +func (a *apexBundle) buildFlattenedApex(ctx android.ModuleContext) { + // For flattened APEX, do nothing but make sure that manifest.json file is also copied along + // with other ordinary files. + manifest := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "manifest.json")) + a.filesInfo = append(a.filesInfo, apexFile{manifest, a.Name() + ".manifest.json", android.Common, ".", etc}) + + for _, fi := range a.filesInfo { + dir := filepath.Join("apex", a.Name(), fi.installDir) + ctx.InstallFile(android.PathForModuleInstall(ctx, dir), fi.builtFile.Base(), fi.builtFile) + } } func (a *apexBundle) AndroidMk() android.AndroidMkData { - return android.AndroidMkData{ - Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) { - fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)") - fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir) - fmt.Fprintln(w, "LOCAL_MODULE :=", name) - fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC") // do we need a new class? - fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", a.outputFile.String()) - fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)", a.installDir.RelPathString())) - fmt.Fprintln(w, "LOCAL_INSTALLED_MODULE_STEM :=", name+apexSuffix) - fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", String(a.properties.Key)) - fmt.Fprintln(w, "include $(BUILD_PREBUILT)") - }} + if a.flattened { + return android.AndroidMkData{ + Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) { + moduleNames := []string{} + for _, fi := range a.filesInfo { + if !android.InList(fi.moduleName, moduleNames) { + moduleNames = append(moduleNames, fi.moduleName) + } + } + fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)") + fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir) + fmt.Fprintln(w, "LOCAL_MODULE :=", name) + fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(moduleNames, " ")) + fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)") + + for _, fi := range a.filesInfo { + fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)") + fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir) + fmt.Fprintln(w, "LOCAL_MODULE :=", fi.moduleName) + fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)", a.installDir.RelPathString(), name, fi.installDir)) + fmt.Fprintln(w, "LOCAL_INSTALLED_MODULE_STEM :=", fi.builtFile.Base()) + fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", fi.builtFile.String()) + fmt.Fprintln(w, "LOCAL_MODULE_CLASS :=", fi.class.NameInMake()) + archStr := fi.archType.String() + if archStr != "common" { + fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", archStr) + } + if fi.class == javaSharedLib { + fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", fi.builtFile.String()) + fmt.Fprintln(w, "LOCAL_DEX_PREOPT := false") + fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_java_prebuilt.mk") + } else { + fmt.Fprintln(w, "include $(BUILD_PREBUILT)") + } + } + }} + } else { + return android.AndroidMkData{ + Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) { + fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)") + fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir) + fmt.Fprintln(w, "LOCAL_MODULE :=", name) + fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC") // do we need a new class? + fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", a.outputFile.String()) + fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)", a.installDir.RelPathString())) + fmt.Fprintln(w, "LOCAL_INSTALLED_MODULE_STEM :=", name+apexSuffix) + fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", String(a.properties.Key)) + fmt.Fprintln(w, "include $(BUILD_PREBUILT)") + }} + } } func apexBundleFactory() android.Module { diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go index 75f59621..d7591255 100644 --- a/cc/config/arm_device.go +++ b/cc/config/arm_device.go @@ -66,6 +66,11 @@ var ( "-mfloat-abi=softfp", "-mfpu=neon-fp-armv8", }, + "armv8-2a": []string{ + "-march=armv8.2-a", + "-mfloat-abi=softfp", + "-mfpu=neon-fp-armv8", + }, } armClangCpuVariantCflags = map[string][]string{ @@ -161,6 +166,7 @@ func init() { "armv7-a", "armv7-a-neon", "armv8-a", + "armv8-2a", "cortex-a7", "cortex-a8", "cortex-a9", @@ -180,6 +186,7 @@ func init() { android.RegisterArchVariantFeatures(android.Arm, "armv7-a-neon", "neon") android.RegisterArchVariantFeatures(android.Arm, "armv8-a", "neon") + android.RegisterArchVariantFeatures(android.Arm, "armv8-2a", "neon") pctx.StaticVariable("armGccVersion", armGccVersion) @@ -208,6 +215,8 @@ func init() { strings.Join(armClangArchVariantCflags["armv7-a-neon"], " ")) pctx.StaticVariable("ArmClangArmv8ACflags", strings.Join(armClangArchVariantCflags["armv8-a"], " ")) + pctx.StaticVariable("ArmClangArmv82ACflags", + strings.Join(armClangArchVariantCflags["armv8-2a"], " ")) // Clang cpu variant cflags pctx.StaticVariable("ArmClangGenericCflags", @@ -233,6 +242,7 @@ var ( "armv7-a": "${config.ArmClangArmv7ACflags}", "armv7-a-neon": "${config.ArmClangArmv7ANeonCflags}", "armv8-a": "${config.ArmClangArmv8ACflags}", + "armv8-2a": "${config.ArmClangArmv82ACflags}", } armClangCpuVariantCflagsVar = map[string]string{ @@ -347,8 +357,8 @@ func armToolchainFactory(arch android.Arch) Toolchain { } case "armv7-a": fixCortexA8 = "-Wl,--fix-cortex-a8" - case "armv8-a": - // Nothing extra for armv8-a + case "armv8-a", "armv8-2a": + // Nothing extra for armv8-a/armv8-2a default: panic(fmt.Sprintf("Unknown ARM architecture version: %q", arch.ArchVariant)) } diff --git a/java/config/kotlin.go b/java/config/kotlin.go index 35f9e9d7..432840e5 100644 --- a/java/config/kotlin.go +++ b/java/config/kotlin.go @@ -15,7 +15,11 @@ package config var ( - KotlinStdlibJar = "external/kotlinc/lib/kotlin-stdlib.jar" + KotlinStdlibJar = "external/kotlinc/lib/kotlin-stdlib.jar" + KotlincIllegalFlags = []string{ + "-no-jdk", + "-no-stdlib", + } ) func init() { diff --git a/java/java.go b/java/java.go index 50c284a9..5ed99f7e 100644 --- a/java/java.go +++ b/java/java.go @@ -89,6 +89,9 @@ type CompilerProperties struct { // list of module-specific flags that will be used for javac compiles Javacflags []string `android:"arch_variant"` + // list of module-specific flags that will be used for kotlinc compiles + Kotlincflags []string `android:"arch_variant"` + // list of of java libraries that will be in the classpath Libs []string `android:"arch_variant"` @@ -330,6 +333,10 @@ func (j *Module) Srcs() android.Paths { return android.Paths{j.outputFile} } +func (j *Module) DexJarFile() android.Path { + return j.dexJarFile +} + var _ android.SourceFileProducer = (*Module)(nil) type Dependency interface { @@ -1083,13 +1090,21 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars ...android.Path var kotlinJars android.Paths if srcFiles.HasExt(".kt") { + // user defined kotlin flags. + kotlincFlags := j.properties.Kotlincflags + CheckKotlincFlags(ctx, kotlincFlags) + // If there are kotlin files, compile them first but pass all the kotlin and java files // kotlinc will use the java files to resolve types referenced by the kotlin files, but // won't emit any classes for them. - - flags.kotlincFlags = "-no-stdlib" + kotlincFlags = append(kotlincFlags, "-no-stdlib") if ctx.Device() { - flags.kotlincFlags += " -no-jdk" + kotlincFlags = append(kotlincFlags, "-no-jdk") + } + if len(kotlincFlags) > 0 { + // optimization. + ctx.Variable(pctx, "kotlincFlags", strings.Join(kotlincFlags, " ")) + flags.kotlincFlags += "$kotlincFlags" } var kotlinSrcFiles android.Paths @@ -1328,6 +1343,31 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars ...android.Path j.outputFile = outputFile.WithoutRel() } +// Check for invalid kotlinc flags. Only use this for flags explicitly passed by the user, +// since some of these flags may be used internally. +func CheckKotlincFlags(ctx android.ModuleContext, flags []string) { + for _, flag := range flags { + flag = strings.TrimSpace(flag) + + if !strings.HasPrefix(flag, "-") { + ctx.PropertyErrorf("kotlincflags", "Flag `%s` must start with `-`", flag) + } else if strings.HasPrefix(flag, "-Xintellij-plugin-root") { + ctx.PropertyErrorf("kotlincflags", + "Bad flag: `%s`, only use internal compiler for consistency.", flag) + } else if inList(flag, config.KotlincIllegalFlags) { + ctx.PropertyErrorf("kotlincflags", "Flag `%s` already used by build system", flag) + } else if flag == "-include-runtime" { + ctx.PropertyErrorf("kotlincflags", "Bad flag: `%s`, do not include runtime.", flag) + } else { + args := strings.Split(flag, " ") + if args[0] == "-kotlin-home" { + ctx.PropertyErrorf("kotlincflags", + "Bad flag: `%s`, kotlin home already set to default (path to kotlinc in the repo).", flag) + } + } + } +} + func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles, srcJars android.Paths, deps deps, flags javaBuilderFlags, jarName string, extraJars android.Paths) android.Path { diff --git a/java/java_test.go b/java/java_test.go index 86349fe6..4d4b8361 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -1124,3 +1124,64 @@ func TestJavaSdkLibrary(t *testing.T) { } } } + +var compilerFlagsTestCases = []struct { + in string + out bool +}{ + { + in: "a", + out: false, + }, + { + in: "-a", + out: true, + }, + { + in: "-no-jdk", + out: false, + }, + { + in: "-no-stdlib", + out: false, + }, + { + in: "-kotlin-home", + out: false, + }, + { + in: "-kotlin-home /some/path", + out: false, + }, + { + in: "-include-runtime", + out: false, + }, + { + in: "-Xintellij-plugin-root", + out: false, + }, +} + +type mockContext struct { + android.ModuleContext + result bool +} + +func (ctx *mockContext) PropertyErrorf(property, format string, args ...interface{}) { + // CheckBadCompilerFlags calls this function when the flag should be rejected + ctx.result = false +} + +func TestCompilerFlags(t *testing.T) { + for _, testCase := range compilerFlagsTestCases { + ctx := &mockContext{result: true} + CheckKotlincFlags(ctx, []string{testCase.in}) + if ctx.result != testCase.out { + t.Errorf("incorrect output:") + t.Errorf(" input: %#v", testCase.in) + t.Errorf(" expected: %#v", testCase.out) + t.Errorf(" got: %#v", ctx.result) + } + } +} diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go index f3406e52..4034533b 100644 --- a/ui/build/paths/config.go +++ b/ui/build/paths/config.go @@ -79,7 +79,6 @@ var Configuration = map[string]PathConfig{ "bash": Allowed, "bc": Allowed, "bzip2": Allowed, - "cat": Allowed, "chmod": Allowed, "cmp": Allowed, "comm": Allowed, @@ -148,7 +147,6 @@ var Configuration = map[string]PathConfig{ "todos": Allowed, "touch": Allowed, "tr": Allowed, - "uniq": Allowed, "unix2dos": Allowed, "unzip": Allowed, "wc": Allowed, @@ -174,9 +172,11 @@ var Configuration = map[string]PathConfig{ "pkg-config": Forbidden, // On linux we'll use the toybox version of these instead + "cat": Toybox, "id": Toybox, "true": Toybox, "uname": Toybox, + "uniq": Toybox, "whoami": Toybox, } |