diff options
-rw-r--r-- | android/rule_builder.go | 172 | ||||
-rw-r--r-- | android/rule_builder_test.go | 175 | ||||
-rw-r--r-- | dexpreopt/config.go | 234 | ||||
-rw-r--r-- | dexpreopt/dexpreopt.go | 105 | ||||
-rw-r--r-- | dexpreopt/dexpreopt_gen/dexpreopt_gen.go | 52 | ||||
-rw-r--r-- | dexpreopt/dexpreopt_test.go | 173 | ||||
-rw-r--r-- | java/dexpreopt.go | 38 | ||||
-rw-r--r-- | java/dexpreopt_bootjars.go | 74 | ||||
-rw-r--r-- | java/hiddenapi.go | 13 | ||||
-rw-r--r-- | java/hiddenapi_singleton.go | 50 | ||||
-rw-r--r-- | java/testing.go | 4 |
11 files changed, 633 insertions, 457 deletions
diff --git a/android/rule_builder.go b/android/rule_builder.go index 3b869470..5edd7b65 100644 --- a/android/rule_builder.go +++ b/android/rule_builder.go @@ -16,7 +16,6 @@ package android import ( "fmt" - "path/filepath" "sort" "strings" @@ -29,7 +28,7 @@ import ( type RuleBuilder struct { commands []*RuleBuilderCommand installs RuleBuilderInstalls - temporariesSet map[string]bool + temporariesSet map[WritablePath]bool restat bool missingDeps []string } @@ -37,13 +36,14 @@ type RuleBuilder struct { // NewRuleBuilder returns a newly created RuleBuilder. func NewRuleBuilder() *RuleBuilder { return &RuleBuilder{ - temporariesSet: make(map[string]bool), + temporariesSet: make(map[WritablePath]bool), } } // RuleBuilderInstall is a tuple of install from and to locations. type RuleBuilderInstall struct { - From, To string + From Path + To string } type RuleBuilderInstalls []RuleBuilderInstall @@ -56,7 +56,7 @@ func (installs RuleBuilderInstalls) String() string { if i != 0 { sb.WriteRune(' ') } - sb.WriteString(install.From) + sb.WriteString(install.From.String()) sb.WriteRune(':') sb.WriteString(install.To) } @@ -80,7 +80,7 @@ func (r *RuleBuilder) Restat() *RuleBuilder { // Install associates an output of the rule with an install location, which can be retrieved later using // RuleBuilder.Installs. -func (r *RuleBuilder) Install(from, to string) { +func (r *RuleBuilder) Install(from Path, to string) { r.installs = append(r.installs, RuleBuilderInstall{from, to}) } @@ -95,19 +95,22 @@ func (r *RuleBuilder) Command() *RuleBuilderCommand { // Temporary marks an output of a command as an intermediate file that will be used as an input to another command // in the same rule, and should not be listed in Outputs. -func (r *RuleBuilder) Temporary(path string) { +func (r *RuleBuilder) Temporary(path WritablePath) { r.temporariesSet[path] = true } // DeleteTemporaryFiles adds a command to the rule that deletes any outputs that have been marked using Temporary // when the rule runs. DeleteTemporaryFiles should be called after all calls to Temporary. func (r *RuleBuilder) DeleteTemporaryFiles() { - var temporariesList []string + var temporariesList WritablePaths for intermediate := range r.temporariesSet { temporariesList = append(temporariesList, intermediate) } - sort.Strings(temporariesList) + + sort.Slice(temporariesList, func(i, j int) bool { + return temporariesList[i].String() < temporariesList[j].String() + }) r.Command().Text("rm").Flag("-f").Outputs(temporariesList) } @@ -115,32 +118,35 @@ func (r *RuleBuilder) DeleteTemporaryFiles() { // Inputs returns the list of paths that were passed to the RuleBuilderCommand methods that take input paths, such // as RuleBuilderCommand.Input, RuleBuilderComand.Implicit, or RuleBuilderCommand.FlagWithInput. Inputs to a command // that are also outputs of another command in the same RuleBuilder are filtered out. -func (r *RuleBuilder) Inputs() []string { +func (r *RuleBuilder) Inputs() Paths { outputs := r.outputSet() - inputs := make(map[string]bool) + inputs := make(map[string]Path) for _, c := range r.commands { for _, input := range c.inputs { - if !outputs[input] { - inputs[input] = true + if _, isOutput := outputs[input.String()]; !isOutput { + inputs[input.String()] = input } } } - var inputList []string - for input := range inputs { + var inputList Paths + for _, input := range inputs { inputList = append(inputList, input) } - sort.Strings(inputList) + + sort.Slice(inputList, func(i, j int) bool { + return inputList[i].String() < inputList[j].String() + }) return inputList } -func (r *RuleBuilder) outputSet() map[string]bool { - outputs := make(map[string]bool) +func (r *RuleBuilder) outputSet() map[string]WritablePath { + outputs := make(map[string]WritablePath) for _, c := range r.commands { for _, output := range c.outputs { - outputs[output] = true + outputs[output.String()] = output } } return outputs @@ -148,16 +154,20 @@ func (r *RuleBuilder) outputSet() map[string]bool { // Outputs returns the list of paths that were passed to the RuleBuilderCommand methods that take output paths, such // as RuleBuilderCommand.Output, RuleBuilderCommand.ImplicitOutput, or RuleBuilderCommand.FlagWithInput. -func (r *RuleBuilder) Outputs() []string { +func (r *RuleBuilder) Outputs() WritablePaths { outputs := r.outputSet() - var outputList []string - for output := range outputs { + var outputList WritablePaths + for _, output := range outputs { if !r.temporariesSet[output] { outputList = append(outputList, output) } } - sort.Strings(outputList) + + sort.Slice(outputList, func(i, j int) bool { + return outputList[i].String() < outputList[j].String() + }) + return outputList } @@ -166,11 +176,11 @@ func (r *RuleBuilder) Installs() RuleBuilderInstalls { return append(RuleBuilderInstalls(nil), r.installs...) } -func (r *RuleBuilder) toolsSet() map[string]bool { - tools := make(map[string]bool) +func (r *RuleBuilder) toolsSet() map[string]Path { + tools := make(map[string]Path) for _, c := range r.commands { for _, tool := range c.tools { - tools[tool] = true + tools[tool.String()] = tool } } @@ -178,14 +188,18 @@ func (r *RuleBuilder) toolsSet() map[string]bool { } // Tools returns the list of paths that were passed to the RuleBuilderCommand.Tool method. -func (r *RuleBuilder) Tools() []string { +func (r *RuleBuilder) Tools() Paths { toolsSet := r.toolsSet() - var toolsList []string - for tool := range toolsSet { + var toolsList Paths + for _, tool := range toolsSet { toolsList = append(toolsList, tool) } - sort.Strings(toolsList) + + sort.Slice(toolsList, func(i, j int) bool { + return toolsList[i].String() < toolsList[j].String() + }) + return toolsList } @@ -211,45 +225,10 @@ var _ BuilderContext = SingletonContext(nil) // Build adds the built command line to the build graph, with dependencies on Inputs and Tools, and output files for // Outputs. func (r *RuleBuilder) Build(pctx PackageContext, ctx BuilderContext, name string, desc string) { - // TODO: convert RuleBuilder arguments and storage to Paths - mctx, _ := ctx.(ModuleContext) - var inputs Paths - for _, input := range r.Inputs() { - // Module output paths - if mctx != nil { - rel, isRel := MaybeRel(ctx, PathForModuleOut(mctx).String(), input) - if isRel { - inputs = append(inputs, PathForModuleOut(mctx, rel)) - continue - } - } - - // Other output paths - rel, isRel := MaybeRel(ctx, PathForOutput(ctx).String(), input) - if isRel { - inputs = append(inputs, PathForOutput(ctx, rel)) - continue - } - - // TODO: remove this once boot image is moved to where PathForOutput can find it. - inputs = append(inputs, &unknownRulePath{input}) - } - - var outputs WritablePaths - for _, output := range r.Outputs() { - if mctx != nil { - rel := Rel(ctx, PathForModuleOut(mctx).String(), output) - outputs = append(outputs, PathForModuleOut(mctx, rel)) - } else { - rel := Rel(ctx, PathForOutput(ctx).String(), output) - outputs = append(outputs, PathForOutput(ctx, rel)) - } - } - if len(r.missingDeps) > 0 { ctx.Build(pctx, BuildParams{ Rule: ErrorRule, - Outputs: outputs, + Outputs: r.Outputs(), Description: desc, Args: map[string]string{ "error": "missing dependencies: " + strings.Join(r.missingDeps, ", "), @@ -262,10 +241,10 @@ func (r *RuleBuilder) Build(pctx PackageContext, ctx BuilderContext, name string ctx.Build(pctx, BuildParams{ Rule: ctx.Rule(pctx, name, blueprint.RuleParams{ Command: strings.Join(proptools.NinjaEscape(r.Commands()), " && "), - CommandDeps: r.Tools(), + CommandDeps: r.Tools().Strings(), }), - Implicits: inputs, - Outputs: outputs, + Implicits: r.Inputs(), + Outputs: r.Outputs(), Description: desc, }) } @@ -277,9 +256,9 @@ func (r *RuleBuilder) Build(pctx PackageContext, ctx BuilderContext, name string // space as a separator from the previous method. type RuleBuilderCommand struct { buf []byte - inputs []string - outputs []string - tools []string + inputs Paths + outputs WritablePaths + tools Paths } // Text adds the specified raw text to the command line. The text should not contain input or output paths or the @@ -329,21 +308,21 @@ func (c *RuleBuilderCommand) FlagWithList(flag string, list []string, sep string // Tool adds the specified tool path to the command line. The path will be also added to the dependencies returned by // RuleBuilder.Tools. -func (c *RuleBuilderCommand) Tool(path string) *RuleBuilderCommand { +func (c *RuleBuilderCommand) Tool(path Path) *RuleBuilderCommand { c.tools = append(c.tools, path) - return c.Text(path) + return c.Text(path.String()) } // Input adds the specified input path to the command line. The path will also be added to the dependencies returned by // RuleBuilder.Inputs. -func (c *RuleBuilderCommand) Input(path string) *RuleBuilderCommand { +func (c *RuleBuilderCommand) Input(path Path) *RuleBuilderCommand { c.inputs = append(c.inputs, path) - return c.Text(path) + return c.Text(path.String()) } // Inputs adds the specified input paths to the command line, separated by spaces. The paths will also be added to the // dependencies returned by RuleBuilder.Inputs. -func (c *RuleBuilderCommand) Inputs(paths []string) *RuleBuilderCommand { +func (c *RuleBuilderCommand) Inputs(paths Paths) *RuleBuilderCommand { for _, path := range paths { c.Input(path) } @@ -352,28 +331,28 @@ func (c *RuleBuilderCommand) Inputs(paths []string) *RuleBuilderCommand { // Implicit adds the specified input path to the dependencies returned by RuleBuilder.Inputs without modifying the // command line. -func (c *RuleBuilderCommand) Implicit(path string) *RuleBuilderCommand { +func (c *RuleBuilderCommand) Implicit(path Path) *RuleBuilderCommand { c.inputs = append(c.inputs, path) return c } // Implicits adds the specified input paths to the dependencies returned by RuleBuilder.Inputs without modifying the // command line. -func (c *RuleBuilderCommand) Implicits(paths []string) *RuleBuilderCommand { +func (c *RuleBuilderCommand) Implicits(paths Paths) *RuleBuilderCommand { c.inputs = append(c.inputs, paths...) return c } // Output adds the specified output path to the command line. The path will also be added to the outputs returned by // RuleBuilder.Outputs. -func (c *RuleBuilderCommand) Output(path string) *RuleBuilderCommand { +func (c *RuleBuilderCommand) Output(path WritablePath) *RuleBuilderCommand { c.outputs = append(c.outputs, path) - return c.Text(path) + return c.Text(path.String()) } // Outputs adds the specified output paths to the command line, separated by spaces. The paths will also be added to // the outputs returned by RuleBuilder.Outputs. -func (c *RuleBuilderCommand) Outputs(paths []string) *RuleBuilderCommand { +func (c *RuleBuilderCommand) Outputs(paths WritablePaths) *RuleBuilderCommand { for _, path := range paths { c.Output(path) } @@ -382,37 +361,37 @@ func (c *RuleBuilderCommand) Outputs(paths []string) *RuleBuilderCommand { // ImplicitOutput adds the specified output path to the dependencies returned by RuleBuilder.Outputs without modifying // the command line. -func (c *RuleBuilderCommand) ImplicitOutput(path string) *RuleBuilderCommand { +func (c *RuleBuilderCommand) ImplicitOutput(path WritablePath) *RuleBuilderCommand { c.outputs = append(c.outputs, path) return c } // ImplicitOutputs adds the specified output paths to the dependencies returned by RuleBuilder.Outputs without modifying // the command line. -func (c *RuleBuilderCommand) ImplicitOutputs(paths []string) *RuleBuilderCommand { +func (c *RuleBuilderCommand) ImplicitOutputs(paths WritablePaths) *RuleBuilderCommand { c.outputs = append(c.outputs, paths...) return c } // FlagWithInput adds the specified flag and input path to the command line, with no separator between them. The path // will also be added to the dependencies returned by RuleBuilder.Inputs. -func (c *RuleBuilderCommand) FlagWithInput(flag, path string) *RuleBuilderCommand { +func (c *RuleBuilderCommand) FlagWithInput(flag string, path Path) *RuleBuilderCommand { c.inputs = append(c.inputs, path) - return c.Text(flag + path) + return c.Text(flag + path.String()) } // FlagWithInputList adds the specified flag and input paths to the command line, with the inputs joined by sep // and no separator between the flag and inputs. The input paths will also be added to the dependencies returned by // RuleBuilder.Inputs. -func (c *RuleBuilderCommand) FlagWithInputList(flag string, paths []string, sep string) *RuleBuilderCommand { +func (c *RuleBuilderCommand) FlagWithInputList(flag string, paths Paths, sep string) *RuleBuilderCommand { c.inputs = append(c.inputs, paths...) - return c.FlagWithList(flag, paths, sep) + return c.FlagWithList(flag, paths.Strings(), sep) } // FlagForEachInput adds the specified flag joined with each input path to the command line. The input paths will also // be added to the dependencies returned by RuleBuilder.Inputs. The result is identical to calling FlagWithInput for // each input path. -func (c *RuleBuilderCommand) FlagForEachInput(flag string, paths []string) *RuleBuilderCommand { +func (c *RuleBuilderCommand) FlagForEachInput(flag string, paths Paths) *RuleBuilderCommand { for _, path := range paths { c.FlagWithInput(flag, path) } @@ -421,23 +400,12 @@ func (c *RuleBuilderCommand) FlagForEachInput(flag string, paths []string) *Rule // FlagWithOutput adds the specified flag and output path to the command line, with no separator between them. The path // will also be added to the outputs returned by RuleBuilder.Outputs. -func (c *RuleBuilderCommand) FlagWithOutput(flag, path string) *RuleBuilderCommand { +func (c *RuleBuilderCommand) FlagWithOutput(flag string, path WritablePath) *RuleBuilderCommand { c.outputs = append(c.outputs, path) - return c.Text(flag + path) + return c.Text(flag + path.String()) } // String returns the command line. func (c *RuleBuilderCommand) String() string { return string(c.buf) } - -type unknownRulePath struct { - path string -} - -var _ Path = (*unknownRulePath)(nil) - -func (p *unknownRulePath) String() string { return p.path } -func (p *unknownRulePath) Ext() string { return filepath.Ext(p.path) } -func (p *unknownRulePath) Base() string { return filepath.Base(p.path) } -func (p *unknownRulePath) Rel() string { return p.path } diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go index f9473489..f738fafc 100644 --- a/android/rule_builder_test.go +++ b/android/rule_builder_test.go @@ -24,10 +24,30 @@ import ( "testing" ) +func pathContext() PathContext { + return PathContextForTesting(TestConfig("out", nil), + map[string][]byte{ + "ld": nil, + "a.o": nil, + "b.o": nil, + "cp": nil, + "a": nil, + "b": nil, + "ls": nil, + "turbine": nil, + "java": nil, + }) +} + func ExampleRuleBuilder() { rule := NewRuleBuilder() - rule.Command().Tool("ld").Inputs([]string{"a.o", "b.o"}).FlagWithOutput("-o ", "linked") + ctx := pathContext() + + rule.Command(). + Tool(PathForSource(ctx, "ld")). + Inputs(PathsForTesting("a.o", "b.o")). + FlagWithOutput("-o ", PathForOutput(ctx, "linked")) rule.Command().Text("echo success") // To add the command to the build graph: @@ -39,18 +59,26 @@ func ExampleRuleBuilder() { fmt.Printf("outputs: %q\n", rule.Outputs()) // Output: - // commands: "ld a.o b.o -o linked && echo success" + // commands: "ld a.o b.o -o out/linked && echo success" // tools: ["ld"] // inputs: ["a.o" "b.o"] - // outputs: ["linked"] + // outputs: ["out/linked"] } func ExampleRuleBuilder_Temporary() { rule := NewRuleBuilder() - rule.Command().Tool("cp").Input("a").Output("b") - rule.Command().Tool("cp").Input("b").Output("c") - rule.Temporary("b") + ctx := pathContext() + + rule.Command(). + Tool(PathForSource(ctx, "cp")). + Input(PathForSource(ctx, "a")). + Output(PathForOutput(ctx, "b")) + rule.Command(). + Tool(PathForSource(ctx, "cp")). + Input(PathForOutput(ctx, "b")). + Output(PathForOutput(ctx, "c")) + rule.Temporary(PathForOutput(ctx, "b")) fmt.Printf("commands: %q\n", strings.Join(rule.Commands(), " && ")) fmt.Printf("tools: %q\n", rule.Tools()) @@ -58,18 +86,26 @@ func ExampleRuleBuilder_Temporary() { fmt.Printf("outputs: %q\n", rule.Outputs()) // Output: - // commands: "cp a b && cp b c" + // commands: "cp a out/b && cp out/b out/c" // tools: ["cp"] // inputs: ["a"] - // outputs: ["c"] + // outputs: ["out/c"] } func ExampleRuleBuilder_DeleteTemporaryFiles() { rule := NewRuleBuilder() - rule.Command().Tool("cp").Input("a").Output("b") - rule.Command().Tool("cp").Input("b").Output("c") - rule.Temporary("b") + ctx := pathContext() + + rule.Command(). + Tool(PathForSource(ctx, "cp")). + Input(PathForSource(ctx, "a")). + Output(PathForOutput(ctx, "b")) + rule.Command(). + Tool(PathForSource(ctx, "cp")). + Input(PathForOutput(ctx, "b")). + Output(PathForOutput(ctx, "c")) + rule.Temporary(PathForOutput(ctx, "b")) rule.DeleteTemporaryFiles() fmt.Printf("commands: %q\n", strings.Join(rule.Commands(), " && ")) @@ -78,93 +114,112 @@ func ExampleRuleBuilder_DeleteTemporaryFiles() { fmt.Printf("outputs: %q\n", rule.Outputs()) // Output: - // commands: "cp a b && cp b c && rm -f b" + // commands: "cp a out/b && cp out/b out/c && rm -f out/b" // tools: ["cp"] // inputs: ["a"] - // outputs: ["c"] + // outputs: ["out/c"] } func ExampleRuleBuilder_Installs() { rule := NewRuleBuilder() - rule.Command().Tool("ld").Inputs([]string{"a.o", "b.o"}).FlagWithOutput("-o ", "linked") - rule.Install("linked", "/bin/linked") - rule.Install("linked", "/sbin/linked") + ctx := pathContext() + + out := PathForOutput(ctx, "linked") + + rule.Command(). + Tool(PathForSource(ctx, "ld")). + Inputs(PathsForTesting("a.o", "b.o")). + FlagWithOutput("-o ", out) + rule.Install(out, "/bin/linked") + rule.Install(out, "/sbin/linked") fmt.Printf("rule.Installs().String() = %q\n", rule.Installs().String()) // Output: - // rule.Installs().String() = "linked:/bin/linked linked:/sbin/linked" + // rule.Installs().String() = "out/linked:/bin/linked out/linked:/sbin/linked" } func ExampleRuleBuilderCommand() { rule := NewRuleBuilder() + ctx := pathContext() + // chained - rule.Command().Tool("ld").Inputs([]string{"a.o", "b.o"}).FlagWithOutput("-o ", "linked") + rule.Command(). + Tool(PathForSource(ctx, "ld")). + Inputs(PathsForTesting("a.o", "b.o")). + FlagWithOutput("-o ", PathForOutput(ctx, "linked")) // unchained cmd := rule.Command() - cmd.Tool("ld") - cmd.Inputs([]string{"a.o", "b.o"}) - cmd.FlagWithOutput("-o ", "linked") + cmd.Tool(PathForSource(ctx, "ld")) + cmd.Inputs(PathsForTesting("a.o", "b.o")) + cmd.FlagWithOutput("-o ", PathForOutput(ctx, "linked")) // mixed: - cmd = rule.Command().Tool("ld") - cmd.Inputs([]string{"a.o", "b.o"}) - cmd.FlagWithOutput("-o ", "linked") + cmd = rule.Command().Tool(PathForSource(ctx, "ld")) + cmd.Inputs(PathsForTesting("a.o", "b.o")) + cmd.FlagWithOutput("-o ", PathForOutput(ctx, "linked")) } func ExampleRuleBuilderCommand_Flag() { + ctx := pathContext() fmt.Println(NewRuleBuilder().Command(). - Tool("ls").Flag("-l")) + Tool(PathForSource(ctx, "ls")).Flag("-l")) // Output: // ls -l } func ExampleRuleBuilderCommand_FlagWithArg() { + ctx := pathContext() fmt.Println(NewRuleBuilder().Command(). - Tool("ls"). + Tool(PathForSource(ctx, "ls")). FlagWithArg("--sort=", "time")) // Output: // ls --sort=time } func ExampleRuleBuilderCommand_FlagForEachArg() { + ctx := pathContext() fmt.Println(NewRuleBuilder().Command(). - Tool("ls"). + Tool(PathForSource(ctx, "ls")). FlagForEachArg("--sort=", []string{"time", "size"})) // Output: // ls --sort=time --sort=size } func ExampleRuleBuilderCommand_FlagForEachInput() { + ctx := pathContext() fmt.Println(NewRuleBuilder().Command(). - Tool("turbine"). - FlagForEachInput("--classpath ", []string{"a.jar", "b.jar"})) + Tool(PathForSource(ctx, "turbine")). + FlagForEachInput("--classpath ", PathsForTesting("a.jar", "b.jar"))) // Output: // turbine --classpath a.jar --classpath b.jar } func ExampleRuleBuilderCommand_FlagWithInputList() { + ctx := pathContext() fmt.Println(NewRuleBuilder().Command(). - Tool("java"). - FlagWithInputList("-classpath=", []string{"a.jar", "b.jar"}, ":")) + Tool(PathForSource(ctx, "java")). + FlagWithInputList("-classpath=", PathsForTesting("a.jar", "b.jar"), ":")) // Output: // java -classpath=a.jar:b.jar } func ExampleRuleBuilderCommand_FlagWithInput() { + ctx := pathContext() fmt.Println(NewRuleBuilder().Command(). - Tool("java"). - FlagWithInput("-classpath=", "a")) + Tool(PathForSource(ctx, "java")). + FlagWithInput("-classpath=", PathForSource(ctx, "a"))) // Output: // java -classpath=a } func ExampleRuleBuilderCommand_FlagWithList() { + ctx := pathContext() fmt.Println(NewRuleBuilder().Command(). - Tool("ls"). + Tool(PathForSource(ctx, "ls")). FlagWithList("--sort=", []string{"time", "size"}, ",")) // Output: // ls --sort=time,size @@ -173,23 +228,35 @@ func ExampleRuleBuilderCommand_FlagWithList() { func TestRuleBuilder(t *testing.T) { rule := NewRuleBuilder() + fs := map[string][]byte{ + "input": nil, + "Implicit": nil, + "Input": nil, + "Tool": nil, + "input2": nil, + "tool2": nil, + "input3": nil, + } + + ctx := PathContextForTesting(TestConfig("out", nil), fs) + cmd := rule.Command(). Flag("Flag"). FlagWithArg("FlagWithArg=", "arg"). - FlagWithInput("FlagWithInput=", "input"). - FlagWithOutput("FlagWithOutput=", "output"). - Implicit("Implicit"). - ImplicitOutput("ImplicitOutput"). - Input("Input"). - Output("Output"). + FlagWithInput("FlagWithInput=", PathForSource(ctx, "input")). + FlagWithOutput("FlagWithOutput=", PathForOutput(ctx, "output")). + Implicit(PathForSource(ctx, "Implicit")). + ImplicitOutput(PathForOutput(ctx, "ImplicitOutput")). + Input(PathForSource(ctx, "Input")). + Output(PathForOutput(ctx, "Output")). Text("Text"). - Tool("Tool") + Tool(PathForSource(ctx, "Tool")) rule.Command(). Text("command2"). - Input("input2"). - Output("output2"). - Tool("tool2") + Input(PathForSource(ctx, "input2")). + Output(PathForOutput(ctx, "output2")). + Tool(PathForSource(ctx, "tool2")) // Test updates to the first command after the second command has been started cmd.Text("after command2") @@ -199,18 +266,18 @@ func TestRuleBuilder(t *testing.T) { // Test a command that uses the output of a previous command as an input rule.Command(). Text("command3"). - Input("input3"). - Input("output2"). - Output("output3") + Input(PathForSource(ctx, "input3")). + Input(PathForOutput(ctx, "output2")). + Output(PathForOutput(ctx, "output3")) wantCommands := []string{ - "Flag FlagWithArg=arg FlagWithInput=input FlagWithOutput=output Input Output Text Tool after command2 old cmd", - "command2 input2 output2 tool2", - "command3 input3 output2 output3", + "Flag FlagWithArg=arg FlagWithInput=input FlagWithOutput=out/output Input out/Output Text Tool after command2 old cmd", + "command2 input2 out/output2 tool2", + "command3 input3 out/output2 out/output3", } - wantInputs := []string{"Implicit", "Input", "input", "input2", "input3"} - wantOutputs := []string{"ImplicitOutput", "Output", "output", "output2", "output3"} - wantTools := []string{"Tool", "tool2"} + wantInputs := PathsForSource(ctx, []string{"Implicit", "Input", "input", "input2", "input3"}) + wantOutputs := PathsForOutput(ctx, []string{"ImplicitOutput", "Output", "output", "output2", "output3"}) + wantTools := PathsForSource(ctx, []string{"Tool", "tool2"}) if !reflect.DeepEqual(rule.Commands(), wantCommands) { t.Errorf("\nwant rule.Commands() = %#v\n got %#v", wantCommands, rule.Commands()) @@ -262,7 +329,7 @@ func (t *testRuleBuilderSingleton) GenerateBuildActions(ctx SingletonContext) { func testRuleBuilder_Build(ctx BuilderContext, in Path, out WritablePath) { rule := NewRuleBuilder() - rule.Command().Tool("cp").Input(in.String()).Output(out.String()) + rule.Command().Tool(PathForSource(ctx, "cp")).Input(in).Output(out) rule.Build(pctx, ctx, "rule", "desc") } diff --git a/dexpreopt/config.go b/dexpreopt/config.go index ee3cc8db..6f8ea3a1 100644 --- a/dexpreopt/config.go +++ b/dexpreopt/config.go @@ -17,6 +17,7 @@ package dexpreopt import ( "encoding/json" "io/ioutil" + "strings" "android/soong/android" ) @@ -74,12 +75,13 @@ type GlobalConfig struct { InstructionSetFeatures map[android.ArchType]string // instruction set for each architecture // Only used for boot image - DirtyImageObjects string // path to a dirty-image-objects file - PreloadedClasses string // path to a preloaded-classes file - BootImageProfiles []string // path to a boot-image-profile.txt file - BootFlags string // extra flags to pass to dex2oat for the boot image - Dex2oatImageXmx string // max heap size for dex2oat for the boot image - Dex2oatImageXms string // initial heap size for dex2oat for the boot image + DirtyImageObjects android.OptionalPath // path to a dirty-image-objects file + PreloadedClasses android.OptionalPath // path to a preloaded-classes file + BootImageProfiles android.Paths // path to a boot-image-profile.txt file + UseProfileForBootImage bool // whether a profile should be used to compile the boot image + BootFlags string // extra flags to pass to dex2oat for the boot image + Dex2oatImageXmx string // max heap size for dex2oat for the boot image + Dex2oatImageXms string // initial heap size for dex2oat for the boot image Tools Tools // paths to tools possibly used by the generated commands } @@ -87,38 +89,38 @@ type GlobalConfig struct { // Tools contains paths to tools possibly used by the generated commands. If you add a new tool here you MUST add it // to the order-only dependency list in DEXPREOPT_GEN_DEPS. type Tools struct { - Profman string - Dex2oat string - Aapt string - SoongZip string - Zip2zip string - - VerifyUsesLibraries string - ConstructContext string + Profman android.Path + Dex2oat android.Path + Aapt android.Path + SoongZip android.Path + Zip2zip android.Path + + VerifyUsesLibraries android.Path + ConstructContext android.Path } type ModuleConfig struct { Name string DexLocation string // dex location on device - BuildPath string - DexPath string + BuildPath android.OutputPath + DexPath android.Path UncompressedDex bool HasApkLibraries bool PreoptFlags []string - ProfileClassListing string + ProfileClassListing android.OptionalPath ProfileIsTextListing bool EnforceUsesLibraries bool OptionalUsesLibraries []string UsesLibraries []string - LibraryPaths map[string]string + LibraryPaths map[string]android.Path Archs []android.ArchType - DexPreoptImages []string + DexPreoptImages []android.Path - PreoptBootClassPathDexFiles []string // file paths of boot class path files - PreoptBootClassPathDexLocations []string // virtual locations of boot class path files + PreoptBootClassPathDexFiles android.Paths // file paths of boot class path files + PreoptBootClassPathDexLocations []string // virtual locations of boot class path files PreoptExtractedApk bool // Overrides OnlyPreoptModules @@ -128,24 +130,137 @@ type ModuleConfig struct { PresignedPrebuilt bool NoStripping bool - StripInputPath string - StripOutputPath string + StripInputPath android.Path + StripOutputPath android.WritablePath } -func LoadGlobalConfig(path string) (GlobalConfig, error) { - config := GlobalConfig{} - err := loadConfig(path, &config) - return config, err +func constructPath(ctx android.PathContext, path string) android.Path { + buildDirPrefix := ctx.Config().BuildDir() + "/" + if path == "" { + return nil + } else if strings.HasPrefix(path, buildDirPrefix) { + return android.PathForOutput(ctx, strings.TrimPrefix(path, buildDirPrefix)) + } else { + return android.PathForSource(ctx, path) + } +} + +func constructPaths(ctx android.PathContext, paths []string) android.Paths { + var ret android.Paths + for _, path := range paths { + ret = append(ret, constructPath(ctx, path)) + } + return ret +} + +func constructPathMap(ctx android.PathContext, paths map[string]string) map[string]android.Path { + ret := map[string]android.Path{} + for key, path := range paths { + ret[key] = constructPath(ctx, path) + } + return ret +} + +func constructWritablePath(ctx android.PathContext, path string) android.WritablePath { + if path == "" { + return nil + } + return constructPath(ctx, path).(android.WritablePath) +} + +// LoadGlobalConfig reads the global dexpreopt.config file into a GlobalConfig struct. It is used directly in Soong +// and in dexpreopt_gen called from Make to read the $OUT/dexpreopt.config written by Make. +func LoadGlobalConfig(ctx android.PathContext, path string) (GlobalConfig, error) { + type GlobalJSONConfig struct { + GlobalConfig + + // Copies of entries in GlobalConfig that are not constructable without extra parameters. They will be + // used to construct the real value manually below. + DirtyImageObjects string + PreloadedClasses string + BootImageProfiles []string + + Tools struct { + Profman string + Dex2oat string + Aapt string + SoongZip string + Zip2zip string + + VerifyUsesLibraries string + ConstructContext string + } + } + + config := GlobalJSONConfig{} + err := loadConfig(ctx, path, &config) + if err != nil { + return config.GlobalConfig, err + } + + // Construct paths that require a PathContext. + config.GlobalConfig.DirtyImageObjects = android.OptionalPathForPath(constructPath(ctx, config.DirtyImageObjects)) + config.GlobalConfig.PreloadedClasses = android.OptionalPathForPath(constructPath(ctx, config.PreloadedClasses)) + config.GlobalConfig.BootImageProfiles = constructPaths(ctx, config.BootImageProfiles) + + config.GlobalConfig.Tools.Profman = constructPath(ctx, config.Tools.Profman) + config.GlobalConfig.Tools.Dex2oat = constructPath(ctx, config.Tools.Dex2oat) + config.GlobalConfig.Tools.Aapt = constructPath(ctx, config.Tools.Aapt) + config.GlobalConfig.Tools.SoongZip = constructPath(ctx, config.Tools.SoongZip) + config.GlobalConfig.Tools.Zip2zip = constructPath(ctx, config.Tools.Zip2zip) + config.GlobalConfig.Tools.VerifyUsesLibraries = constructPath(ctx, config.Tools.VerifyUsesLibraries) + config.GlobalConfig.Tools.ConstructContext = constructPath(ctx, config.Tools.ConstructContext) + + return config.GlobalConfig, nil } -func LoadModuleConfig(path string) (ModuleConfig, error) { - config := ModuleConfig{} - err := loadConfig(path, &config) - return config, err +// LoadModuleConfig reads a per-module dexpreopt.config file into a ModuleConfig struct. It is not used in Soong, which +// receives a ModuleConfig struct directly from java/dexpreopt.go. It is used in dexpreopt_gen called from oMake to +// read the module dexpreopt.config written by Make. +func LoadModuleConfig(ctx android.PathContext, path string) (ModuleConfig, error) { + type ModuleJSONConfig struct { + ModuleConfig + + // Copies of entries in ModuleConfig that are not constructable without extra parameters. They will be + // used to construct the real value manually below. + BuildPath string + DexPath string + ProfileClassListing string + LibraryPaths map[string]string + DexPreoptImages []string + PreoptBootClassPathDexFiles []string + StripInputPath string + StripOutputPath string + } + + config := ModuleJSONConfig{} + + err := loadConfig(ctx, path, &config) + if err != nil { + return config.ModuleConfig, err + } + + // Construct paths that require a PathContext. + config.ModuleConfig.BuildPath = constructPath(ctx, config.BuildPath).(android.OutputPath) + config.ModuleConfig.DexPath = constructPath(ctx, config.DexPath) + config.ModuleConfig.ProfileClassListing = android.OptionalPathForPath(constructPath(ctx, config.ProfileClassListing)) + config.ModuleConfig.LibraryPaths = constructPathMap(ctx, config.LibraryPaths) + config.ModuleConfig.DexPreoptImages = constructPaths(ctx, config.DexPreoptImages) + config.ModuleConfig.PreoptBootClassPathDexFiles = constructPaths(ctx, config.PreoptBootClassPathDexFiles) + config.ModuleConfig.StripInputPath = constructPath(ctx, config.StripInputPath) + config.ModuleConfig.StripOutputPath = constructWritablePath(ctx, config.StripOutputPath) + + return config.ModuleConfig, nil } -func loadConfig(path string, config interface{}) error { - data, err := ioutil.ReadFile(path) +func loadConfig(ctx android.PathContext, path string, config interface{}) error { + r, err := ctx.Fs().Open(path) + if err != nil { + return err + } + defer r.Close() + + data, err := ioutil.ReadAll(r) if err != nil { return err } @@ -157,3 +272,56 @@ func loadConfig(path string, config interface{}) error { return nil } + +func GlobalConfigForTests(ctx android.PathContext) GlobalConfig { + return GlobalConfig{ + DefaultNoStripping: false, + DisablePreoptModules: nil, + OnlyPreoptBootImageAndSystemServer: false, + HasSystemOther: false, + PatternsOnSystemOther: nil, + DisableGenerateProfile: false, + BootJars: nil, + RuntimeApexJars: nil, + ProductUpdatableBootModules: nil, + ProductUpdatableBootLocations: nil, + SystemServerJars: nil, + SystemServerApps: nil, + SpeedApps: nil, + PreoptFlags: nil, + DefaultCompilerFilter: "", + SystemServerCompilerFilter: "", + GenerateDMFiles: false, + NeverAllowStripping: false, + NoDebugInfo: false, + AlwaysSystemServerDebugInfo: false, + NeverSystemServerDebugInfo: false, + AlwaysOtherDebugInfo: false, + NeverOtherDebugInfo: false, + MissingUsesLibraries: nil, + IsEng: false, + SanitizeLite: false, + DefaultAppImages: false, + Dex2oatXmx: "", + Dex2oatXms: "", + EmptyDirectory: "empty_dir", + CpuVariant: nil, + InstructionSetFeatures: nil, + DirtyImageObjects: android.OptionalPath{}, + PreloadedClasses: android.OptionalPath{}, + BootImageProfiles: nil, + UseProfileForBootImage: false, + BootFlags: "", + Dex2oatImageXmx: "", + Dex2oatImageXms: "", + Tools: Tools{ + Profman: android.PathForTesting("profman"), + Dex2oat: android.PathForTesting("dex2oat"), + Aapt: android.PathForTesting("aapt"), + SoongZip: android.PathForTesting("soong_zip"), + Zip2zip: android.PathForTesting("zip2zip"), + VerifyUsesLibraries: android.PathForTesting("verify_uses_libraries.sh"), + ConstructContext: android.PathForTesting("construct_context.sh"), + }, + } +} diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go index 7fdfb496..9e333c10 100644 --- a/dexpreopt/dexpreopt.go +++ b/dexpreopt/dexpreopt.go @@ -37,6 +37,7 @@ package dexpreopt import ( "fmt" "path/filepath" + "runtime" "strings" "android/soong/android" @@ -52,7 +53,9 @@ const SystemOtherPartition = "/system_other/" func GenerateStripRule(global GlobalConfig, module ModuleConfig) (rule *android.RuleBuilder, err error) { defer func() { if r := recover(); r != nil { - if e, ok := r.(error); ok { + if _, ok := r.(runtime.Error); ok { + panic(r) + } else if e, ok := r.(error); ok { err = e rule = nil } else { @@ -86,10 +89,14 @@ func GenerateStripRule(global GlobalConfig, module ModuleConfig) (rule *android. // GenerateDexpreoptRule generates a set of commands that will preopt a module based on a GlobalConfig and a // ModuleConfig. The produced files and their install locations will be available through rule.Installs(). -func GenerateDexpreoptRule(global GlobalConfig, module ModuleConfig) (rule *android.RuleBuilder, err error) { +func GenerateDexpreoptRule(ctx android.PathContext, + global GlobalConfig, module ModuleConfig) (rule *android.RuleBuilder, err error) { + defer func() { if r := recover(); r != nil { - if e, ok := r.(error); ok { + if _, ok := r.(runtime.Error); ok { + panic(r) + } else if e, ok := r.(error); ok { err = e rule = nil } else { @@ -100,11 +107,11 @@ func GenerateDexpreoptRule(global GlobalConfig, module ModuleConfig) (rule *andr rule = android.NewRuleBuilder() - generateProfile := module.ProfileClassListing != "" && !global.DisableGenerateProfile + generateProfile := module.ProfileClassListing.Valid() && !global.DisableGenerateProfile - var profile string + var profile android.WritablePath if generateProfile { - profile = profileCommand(global, module, rule) + profile = profileCommand(ctx, global, module, rule) } if !dexpreoptDisabled(global, module) { @@ -118,7 +125,7 @@ func GenerateDexpreoptRule(global GlobalConfig, module ModuleConfig) (rule *andr for i, arch := range module.Archs { image := module.DexPreoptImages[i] - dexpreoptCommand(global, module, rule, arch, profile, image, appImage, generateDM) + dexpreoptCommand(ctx, global, module, rule, arch, profile, image, appImage, generateDM) } } } @@ -143,8 +150,10 @@ func dexpreoptDisabled(global GlobalConfig, module ModuleConfig) bool { return false } -func profileCommand(global GlobalConfig, module ModuleConfig, rule *android.RuleBuilder) string { - profilePath := filepath.Join(filepath.Dir(module.BuildPath), "profile.prof") +func profileCommand(ctx android.PathContext, global GlobalConfig, module ModuleConfig, + rule *android.RuleBuilder) android.WritablePath { + + profilePath := module.BuildPath.InSameDir(ctx, "profile.prof") profileInstalledPath := module.DexLocation + ".prof" if !module.ProfileIsTextListing { @@ -158,13 +167,13 @@ func profileCommand(global GlobalConfig, module ModuleConfig, rule *android.Rule if module.ProfileIsTextListing { // The profile is a test listing of classes (used for framework jars). // We need to generate the actual binary profile before being able to compile. - cmd.FlagWithInput("--create-profile-from=", module.ProfileClassListing) + cmd.FlagWithInput("--create-profile-from=", module.ProfileClassListing.Path()) } else { // The profile is binary profile (used for apps). Run it through profman to // ensure the profile keys match the apk. cmd. Flag("--copy-and-update-profile-key"). - FlagWithInput("--profile-file=", module.ProfileClassListing) + FlagWithInput("--profile-file=", module.ProfileClassListing.Path()) } cmd. @@ -180,8 +189,8 @@ func profileCommand(global GlobalConfig, module ModuleConfig, rule *android.Rule return profilePath } -func dexpreoptCommand(global GlobalConfig, module ModuleConfig, rule *android.RuleBuilder, - arch android.ArchType, profile, bootImage string, appImage, generateDM bool) { +func dexpreoptCommand(ctx android.PathContext, global GlobalConfig, module ModuleConfig, rule *android.RuleBuilder, + arch android.ArchType, profile, bootImage android.Path, appImage, generateDM bool) { // HACK: make soname in Soong-generated .odex files match Make. base := filepath.Base(module.DexLocation) @@ -199,21 +208,21 @@ func dexpreoptCommand(global GlobalConfig, module ModuleConfig, rule *android.Ru pathtools.ReplaceExtension(filepath.Base(path), "odex")) } - odexPath := toOdexPath(filepath.Join(filepath.Dir(module.BuildPath), base)) + odexPath := module.BuildPath.InSameDir(ctx, "oat", arch.String(), pathtools.ReplaceExtension(base, "odex")) odexInstallPath := toOdexPath(module.DexLocation) if odexOnSystemOther(module, global) { odexInstallPath = strings.Replace(odexInstallPath, SystemPartition, SystemOtherPartition, 1) } - vdexPath := pathtools.ReplaceExtension(odexPath, "vdex") + vdexPath := odexPath.ReplaceExtension(ctx, "vdex") vdexInstallPath := pathtools.ReplaceExtension(odexInstallPath, "vdex") - invocationPath := pathtools.ReplaceExtension(odexPath, "invocation") + invocationPath := odexPath.ReplaceExtension(ctx, "invocation") // bootImage is .../dex_bootjars/system/framework/arm64/boot.art, but dex2oat wants // .../dex_bootjars/system/framework/boot.art on the command line var bootImageLocation string - if bootImage != "" { + if bootImage != nil { bootImageLocation = PathToLocation(bootImage, arch) } @@ -227,19 +236,21 @@ func dexpreoptCommand(global GlobalConfig, module ModuleConfig, rule *android.Ru var filteredOptionalUsesLibs []string // The class loader context using paths in the build - var classLoaderContextHost []string + var classLoaderContextHost android.Paths // The class loader context using paths as they will be on the device var classLoaderContextTarget []string // Extra paths that will be appended to the class loader if the APK manifest has targetSdkVersion < 28 - var conditionalClassLoaderContextHost28 []string + var conditionalClassLoaderContextHost28 android.Paths var conditionalClassLoaderContextTarget28 []string // Extra paths that will be appended to the class loader if the APK manifest has targetSdkVersion < 29 - var conditionalClassLoaderContextHost29 []string + var conditionalClassLoaderContextHost29 android.Paths var conditionalClassLoaderContextTarget29 []string + var classLoaderContextHostString string + if module.EnforceUsesLibraries { verifyUsesLibs = copyOf(module.UsesLibraries) verifyOptionalUsesLibs = copyOf(module.OptionalUsesLibraries) @@ -281,31 +292,41 @@ func dexpreoptCommand(global GlobalConfig, module ModuleConfig, rule *android.Ru pathForLibrary(module, hidlBase)) conditionalClassLoaderContextTarget29 = append(conditionalClassLoaderContextTarget29, filepath.Join("/system/framework", hidlBase+".jar")) + + classLoaderContextHostString = strings.Join(classLoaderContextHost.Strings(), ":") } else { // Pass special class loader context to skip the classpath and collision check. // This will get removed once LOCAL_USES_LIBRARIES is enforced. // Right now LOCAL_USES_LIBRARIES is opt in, for the case where it's not specified we still default // to the &. - classLoaderContextHost = []string{`\&`} + classLoaderContextHostString = `\&` } - rule.Command().FlagWithArg("mkdir -p ", filepath.Dir(odexPath)) + rule.Command().FlagWithArg("mkdir -p ", filepath.Dir(odexPath.String())) rule.Command().FlagWithOutput("rm -f ", odexPath) // Set values in the environment of the rule. These may be modified by construct_context.sh. - rule.Command().FlagWithArg("class_loader_context_arg=--class-loader-context=", - strings.Join(classLoaderContextHost, ":")) + rule.Command().FlagWithArg("class_loader_context_arg=--class-loader-context=", classLoaderContextHostString) rule.Command().Text(`stored_class_loader_context_arg=""`) if module.EnforceUsesLibraries { rule.Command().Textf(`uses_library_names="%s"`, strings.Join(verifyUsesLibs, " ")) rule.Command().Textf(`optional_uses_library_names="%s"`, strings.Join(verifyOptionalUsesLibs, " ")) rule.Command().Textf(`aapt_binary="%s"`, global.Tools.Aapt) - rule.Command().Textf(`dex_preopt_host_libraries="%s"`, strings.Join(classLoaderContextHost, " ")) - rule.Command().Textf(`dex_preopt_target_libraries="%s"`, strings.Join(classLoaderContextTarget, " ")) - rule.Command().Textf(`conditional_host_libs_28="%s"`, strings.Join(conditionalClassLoaderContextHost28, " ")) - rule.Command().Textf(`conditional_target_libs_28="%s"`, strings.Join(conditionalClassLoaderContextTarget28, " ")) - rule.Command().Textf(`conditional_host_libs_29="%s"`, strings.Join(conditionalClassLoaderContextHost29, " ")) - rule.Command().Textf(`conditional_target_libs_29="%s"`, strings.Join(conditionalClassLoaderContextTarget29, " ")) + rule.Command().Textf(`dex_preopt_host_libraries="%s"`, + strings.Join(classLoaderContextHost.Strings(), " ")). + Implicits(classLoaderContextHost) + rule.Command().Textf(`dex_preopt_target_libraries="%s"`, + strings.Join(classLoaderContextTarget, " ")) + rule.Command().Textf(`conditional_host_libs_28="%s"`, + strings.Join(conditionalClassLoaderContextHost28.Strings(), " ")). + Implicits(conditionalClassLoaderContextHost28) + rule.Command().Textf(`conditional_target_libs_28="%s"`, + strings.Join(conditionalClassLoaderContextTarget28, " ")) + rule.Command().Textf(`conditional_host_libs_29="%s"`, + strings.Join(conditionalClassLoaderContextHost29.Strings(), " ")). + Implicits(conditionalClassLoaderContextHost29) + rule.Command().Textf(`conditional_target_libs_29="%s"`, + strings.Join(conditionalClassLoaderContextTarget29, " ")) rule.Command().Text("source").Tool(global.Tools.VerifyUsesLibraries).Input(module.DexPath) rule.Command().Text("source").Tool(global.Tools.ConstructContext) } @@ -364,7 +385,7 @@ func dexpreoptCommand(global GlobalConfig, module ModuleConfig, rule *android.Ru // Apps loaded into system server, and apps the product default to being compiled with the // 'speed' compiler filter. compilerFilter = "speed" - } else if profile != "" { + } else if profile != nil { // For non system server jars, use speed-profile when we have a profile. compilerFilter = "speed-profile" } else if global.DefaultCompilerFilter != "" { @@ -377,9 +398,9 @@ func dexpreoptCommand(global GlobalConfig, module ModuleConfig, rule *android.Ru if generateDM { cmd.FlagWithArg("--copy-dex-files=", "false") - dmPath := filepath.Join(filepath.Dir(module.BuildPath), "generated.dm") + dmPath := module.BuildPath.InSameDir(ctx, "generated.dm") dmInstalledPath := pathtools.ReplaceExtension(module.DexLocation, "dm") - tmpPath := filepath.Join(filepath.Dir(module.BuildPath), "primary.vdex") + tmpPath := module.BuildPath.InSameDir(ctx, "primary.vdex") rule.Command().Text("cp -f").Input(vdexPath).Output(tmpPath) rule.Command().Tool(global.Tools.SoongZip). FlagWithArg("-L", "9"). @@ -428,15 +449,15 @@ func dexpreoptCommand(global GlobalConfig, module ModuleConfig, rule *android.Ru cmd.FlagWithArg("--compilation-reason=", "prebuilt") if appImage { - appImagePath := pathtools.ReplaceExtension(odexPath, "art") + appImagePath := odexPath.ReplaceExtension(ctx, "art") appImageInstallPath := pathtools.ReplaceExtension(odexInstallPath, "art") cmd.FlagWithOutput("--app-image-file=", appImagePath). FlagWithArg("--image-format=", "lz4") rule.Install(appImagePath, appImageInstallPath) } - if profile != "" { - cmd.FlagWithArg("--profile-file=", profile) + if profile != nil { + cmd.FlagWithInput("--profile-file=", profile) } rule.Install(odexPath, odexInstallPath) @@ -522,17 +543,17 @@ func odexOnSystemOther(module ModuleConfig, global GlobalConfig) bool { } // PathToLocation converts .../system/framework/arm64/boot.art to .../system/framework/boot.art -func PathToLocation(path string, arch android.ArchType) string { - pathArch := filepath.Base(filepath.Dir(path)) +func PathToLocation(path android.Path, arch android.ArchType) string { + pathArch := filepath.Base(filepath.Dir(path.String())) if pathArch != arch.String() { panic(fmt.Errorf("last directory in %q must be %q", path, arch.String())) } - return filepath.Join(filepath.Dir(filepath.Dir(path)), filepath.Base(path)) + return filepath.Join(filepath.Dir(filepath.Dir(path.String())), filepath.Base(path.String())) } -func pathForLibrary(module ModuleConfig, lib string) string { - path := module.LibraryPaths[lib] - if path == "" { +func pathForLibrary(module ModuleConfig, lib string) android.Path { + path, ok := module.LibraryPaths[lib] + if !ok { panic(fmt.Errorf("unknown library path for %q", lib)) } return path diff --git a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go index cc3c1f10..c72f6842 100644 --- a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go +++ b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go @@ -21,6 +21,7 @@ import ( "os" "path/filepath" "runtime" + "strings" "android/soong/android" "android/soong/dexpreopt" @@ -33,8 +34,17 @@ var ( stripScriptPath = flag.String("strip_script", "", "path to output strip script") globalConfigPath = flag.String("global", "", "path to global configuration file") moduleConfigPath = flag.String("module", "", "path to module configuration file") + outDir = flag.String("out_dir", "", "path to output directory") ) +type pathContext struct { + config android.Config +} + +func (x *pathContext) Fs() pathtools.FileSystem { return pathtools.OsFs } +func (x *pathContext) Config() android.Config { return x.config } +func (x *pathContext) AddNinjaFileDeps(...string) {} + func main() { flag.Parse() @@ -66,18 +76,26 @@ func main() { usage("path to module configuration file is required") } - globalConfig, err := dexpreopt.LoadGlobalConfig(*globalConfigPath) + ctx := &pathContext{android.TestConfig(*outDir, nil)} + + globalConfig, err := dexpreopt.LoadGlobalConfig(ctx, *globalConfigPath) if err != nil { fmt.Fprintf(os.Stderr, "error loading global config %q: %s\n", *globalConfigPath, err) os.Exit(2) } - moduleConfig, err := dexpreopt.LoadModuleConfig(*moduleConfigPath) + moduleConfig, err := dexpreopt.LoadModuleConfig(ctx, *moduleConfigPath) if err != nil { fmt.Fprintf(os.Stderr, "error loading module config %q: %s\n", *moduleConfigPath, err) os.Exit(2) } + // This shouldn't be using *PathForTesting, but it's outside of soong_build so its OK for now. + moduleConfig.StripInputPath = android.PathForTesting("$1") + moduleConfig.StripOutputPath = android.WritablePathForTesting("$2") + + moduleConfig.DexPath = android.PathForTesting("$1") + defer func() { if r := recover(); r != nil { switch x := r.(type) { @@ -92,30 +110,30 @@ func main() { } }() - writeScripts(globalConfig, moduleConfig, *dexpreoptScriptPath, *stripScriptPath) + writeScripts(ctx, globalConfig, moduleConfig, *dexpreoptScriptPath, *stripScriptPath) } -func writeScripts(global dexpreopt.GlobalConfig, module dexpreopt.ModuleConfig, +func writeScripts(ctx android.PathContext, global dexpreopt.GlobalConfig, module dexpreopt.ModuleConfig, dexpreoptScriptPath, stripScriptPath string) { - dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(global, module) + dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, global, module) if err != nil { panic(err) } - installDir := filepath.Join(filepath.Dir(module.BuildPath), "dexpreopt_install") + installDir := module.BuildPath.InSameDir(ctx, "dexpreopt_install") - dexpreoptRule.Command().FlagWithArg("rm -rf ", installDir) - dexpreoptRule.Command().FlagWithArg("mkdir -p ", installDir) + dexpreoptRule.Command().FlagWithArg("rm -rf ", installDir.String()) + dexpreoptRule.Command().FlagWithArg("mkdir -p ", installDir.String()) for _, install := range dexpreoptRule.Installs() { - installPath := filepath.Join(installDir, install.To) - dexpreoptRule.Command().Text("mkdir -p").Flag(filepath.Dir(installPath)) + installPath := installDir.Join(ctx, strings.TrimPrefix(install.To, "/")) + dexpreoptRule.Command().Text("mkdir -p").Flag(filepath.Dir(installPath.String())) dexpreoptRule.Command().Text("cp -f").Input(install.From).Output(installPath) } dexpreoptRule.Command().Tool(global.Tools.SoongZip). - FlagWithOutput("-o ", "$2"). - FlagWithArg("-C ", installDir). - FlagWithArg("-D ", installDir) + FlagWithArg("-o ", "$2"). + FlagWithArg("-C ", installDir.String()). + FlagWithArg("-D ", installDir.String()) stripRule, err := dexpreopt.GenerateStripRule(global, module) if err != nil { @@ -139,7 +157,7 @@ func writeScripts(global dexpreopt.GlobalConfig, module dexpreopt.ModuleConfig, for _, input := range rule.Inputs() { // Assume the rule that ran the script already has a dependency on the input file passed on the // command line. - if input != "$1" { + if input.String() != "$1" { fmt.Fprintf(depFile, ` %s \`+"\n", input) } } @@ -159,13 +177,13 @@ func writeScripts(global dexpreopt.GlobalConfig, module dexpreopt.ModuleConfig, } // The written scripts will assume the input is $1 and the output is $2 - if module.DexPath != "$1" { + if module.DexPath.String() != "$1" { panic(fmt.Errorf("module.DexPath must be '$1', was %q", module.DexPath)) } - if module.StripInputPath != "$1" { + if module.StripInputPath.String() != "$1" { panic(fmt.Errorf("module.StripInputPath must be '$1', was %q", module.StripInputPath)) } - if module.StripOutputPath != "$2" { + if module.StripOutputPath.String() != "$2" { panic(fmt.Errorf("module.StripOutputPath must be '$2', was %q", module.StripOutputPath)) } diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go index 949f91f3..2a58ab9c 100644 --- a/dexpreopt/dexpreopt_test.go +++ b/dexpreopt/dexpreopt_test.go @@ -21,98 +21,47 @@ import ( "testing" ) -var testGlobalConfig = GlobalConfig{ - DefaultNoStripping: false, - DisablePreoptModules: nil, - OnlyPreoptBootImageAndSystemServer: false, - HasSystemOther: false, - PatternsOnSystemOther: nil, - DisableGenerateProfile: false, - BootJars: nil, - RuntimeApexJars: nil, - ProductUpdatableBootModules: nil, - ProductUpdatableBootLocations: nil, - SystemServerJars: nil, - SystemServerApps: nil, - SpeedApps: nil, - PreoptFlags: nil, - DefaultCompilerFilter: "", - SystemServerCompilerFilter: "", - GenerateDMFiles: false, - NeverAllowStripping: false, - NoDebugInfo: false, - AlwaysSystemServerDebugInfo: false, - NeverSystemServerDebugInfo: false, - AlwaysOtherDebugInfo: false, - NeverOtherDebugInfo: false, - MissingUsesLibraries: nil, - IsEng: false, - SanitizeLite: false, - DefaultAppImages: false, - Dex2oatXmx: "", - Dex2oatXms: "", - EmptyDirectory: "", - CpuVariant: nil, - InstructionSetFeatures: nil, - DirtyImageObjects: "", - PreloadedClasses: "", - BootImageProfiles: nil, - BootFlags: "", - Dex2oatImageXmx: "", - Dex2oatImageXms: "", - Tools: Tools{ - Profman: "profman", - Dex2oat: "dex2oat", - Aapt: "aapt", - SoongZip: "soong_zip", - Zip2zip: "zip2zip", - VerifyUsesLibraries: "verify_uses_libraries.sh", - ConstructContext: "construct_context.sh", - }, -} - -var testModuleConfig = ModuleConfig{ - Name: "", - DexLocation: "", - BuildPath: "", - DexPath: "", - UncompressedDex: false, - HasApkLibraries: false, - PreoptFlags: nil, - ProfileClassListing: "", - ProfileIsTextListing: false, - EnforceUsesLibraries: false, - OptionalUsesLibraries: nil, - UsesLibraries: nil, - LibraryPaths: nil, - Archs: []android.ArchType{android.Arm}, - DexPreoptImages: []string{"system/framework/arm/boot.art"}, - PreoptBootClassPathDexFiles: nil, - PreoptBootClassPathDexLocations: nil, - PreoptExtractedApk: false, - NoCreateAppImage: false, - ForceCreateAppImage: false, - PresignedPrebuilt: false, - NoStripping: false, - StripInputPath: "", - StripOutputPath: "", +func testModuleConfig(ctx android.PathContext) ModuleConfig { + return ModuleConfig{ + Name: "test", + DexLocation: "/system/app/test/test.apk", + BuildPath: android.PathForOutput(ctx, "test/test.apk"), + DexPath: android.PathForOutput(ctx, "test/dex/test.jar"), + UncompressedDex: false, + HasApkLibraries: false, + PreoptFlags: nil, + ProfileClassListing: android.OptionalPath{}, + ProfileIsTextListing: false, + EnforceUsesLibraries: false, + OptionalUsesLibraries: nil, + UsesLibraries: nil, + LibraryPaths: nil, + Archs: []android.ArchType{android.Arm}, + DexPreoptImages: android.Paths{android.PathForTesting("system/framework/arm/boot.art")}, + PreoptBootClassPathDexFiles: nil, + PreoptBootClassPathDexLocations: nil, + PreoptExtractedApk: false, + NoCreateAppImage: false, + ForceCreateAppImage: false, + PresignedPrebuilt: false, + NoStripping: false, + StripInputPath: android.PathForOutput(ctx, "unstripped/test.apk"), + StripOutputPath: android.PathForOutput(ctx, "stripped/test.apk"), + } } func TestDexPreopt(t *testing.T) { - global, module := testGlobalConfig, testModuleConfig + ctx := android.PathContextForTesting(android.TestConfig("out", nil), nil) + global, module := GlobalConfigForTests(ctx), testModuleConfig(ctx) - module.Name = "test" - module.DexLocation = "/system/app/test/test.apk" - module.BuildPath = "out/test/test.apk" - - rule, err := GenerateDexpreoptRule(global, module) + rule, err := GenerateDexpreoptRule(ctx, global, module) if err != nil { - t.Error(err) + t.Fatal(err) } wantInstalls := android.RuleBuilderInstalls{ - {"out/test/oat/arm/package.odex", "/system/app/test/oat/arm/test.odex"}, - {"out/test/oat/arm/package.vdex", "/system/app/test/oat/arm/test.vdex"}, + {android.PathForOutput(ctx, "test/oat/arm/package.odex"), "/system/app/test/oat/arm/test.odex"}, + {android.PathForOutput(ctx, "test/oat/arm/package.vdex"), "/system/app/test/oat/arm/test.vdex"}, } if !reflect.DeepEqual(rule.Installs(), wantInstalls) { @@ -122,13 +71,11 @@ func TestDexPreopt(t *testing.T) { func TestDexPreoptStrip(t *testing.T) { // Test that we panic if we strip in a configuration where stripping is not allowed. - global, module := testGlobalConfig, testModuleConfig + ctx := android.PathContextForTesting(android.TestConfig("out", nil), nil) + global, module := GlobalConfigForTests(ctx), testModuleConfig(ctx) global.NeverAllowStripping = true module.NoStripping = false - module.Name = "test" - module.DexLocation = "/system/app/test/test.apk" - module.BuildPath = "out/test/test.apk" _, err := GenerateStripRule(global, module) if err == nil { @@ -137,23 +84,20 @@ func TestDexPreoptStrip(t *testing.T) { } func TestDexPreoptSystemOther(t *testing.T) { - global, module := testGlobalConfig, testModuleConfig + ctx := android.PathContextForTesting(android.TestConfig("out", nil), nil) + global, module := GlobalConfigForTests(ctx), testModuleConfig(ctx) global.HasSystemOther = true global.PatternsOnSystemOther = []string{"app/%"} - module.Name = "test" - module.DexLocation = "/system/app/test/test.apk" - module.BuildPath = "out/test/test.apk" - - rule, err := GenerateDexpreoptRule(global, module) + rule, err := GenerateDexpreoptRule(ctx, global, module) if err != nil { - t.Error(err) + t.Fatal(err) } wantInstalls := android.RuleBuilderInstalls{ - {"out/test/oat/arm/package.odex", "/system_other/app/test/oat/arm/test.odex"}, - {"out/test/oat/arm/package.vdex", "/system_other/app/test/oat/arm/test.vdex"}, + {android.PathForOutput(ctx, "test/oat/arm/package.odex"), "/system_other/app/test/oat/arm/test.odex"}, + {android.PathForOutput(ctx, "test/oat/arm/package.vdex"), "/system_other/app/test/oat/arm/test.vdex"}, } if !reflect.DeepEqual(rule.Installs(), wantInstalls) { @@ -162,23 +106,21 @@ func TestDexPreoptSystemOther(t *testing.T) { } func TestDexPreoptProfile(t *testing.T) { - global, module := testGlobalConfig, testModuleConfig + ctx := android.PathContextForTesting(android.TestConfig("out", nil), nil) + global, module := GlobalConfigForTests(ctx), testModuleConfig(ctx) - module.Name = "test" - module.DexLocation = "/system/app/test/test.apk" - module.BuildPath = "out/test/test.apk" - module.ProfileClassListing = "profile" + module.ProfileClassListing = android.OptionalPathForPath(android.PathForTesting("profile")) - rule, err := GenerateDexpreoptRule(global, module) + rule, err := GenerateDexpreoptRule(ctx, global, module) if err != nil { - t.Error(err) + t.Fatal(err) } wantInstalls := android.RuleBuilderInstalls{ - {"out/test/profile.prof", "/system/app/test/test.apk.prof"}, - {"out/test/oat/arm/package.art", "/system/app/test/oat/arm/test.art"}, - {"out/test/oat/arm/package.odex", "/system/app/test/oat/arm/test.odex"}, - {"out/test/oat/arm/package.vdex", "/system/app/test/oat/arm/test.vdex"}, + {android.PathForOutput(ctx, "test/profile.prof"), "/system/app/test/test.apk.prof"}, + {android.PathForOutput(ctx, "test/oat/arm/package.art"), "/system/app/test/oat/arm/test.art"}, + {android.PathForOutput(ctx, "test/oat/arm/package.odex"), "/system/app/test/oat/arm/test.odex"}, + {android.PathForOutput(ctx, "test/oat/arm/package.vdex"), "/system/app/test/oat/arm/test.vdex"}, } if !reflect.DeepEqual(rule.Installs(), wantInstalls) { @@ -212,29 +154,24 @@ func TestStripDex(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - global, module := testGlobalConfig, testModuleConfig - - module.Name = "test" - module.DexLocation = "/system/app/test/test.apk" - module.BuildPath = "out/test/test.apk" - module.StripInputPath = "$1" - module.StripOutputPath = "$2" + ctx := android.PathContextForTesting(android.TestConfig("out", nil), nil) + global, module := GlobalConfigForTests(ctx), testModuleConfig(ctx) test.setup(&global, &module) rule, err := GenerateStripRule(global, module) if err != nil { - t.Error(err) + t.Fatal(err) } if test.strip { - want := `zip2zip -i $1 -o $2 -x "classes*.dex"` + want := `zip2zip -i out/unstripped/test.apk -o out/stripped/test.apk -x "classes*.dex"` if len(rule.Commands()) < 1 || !strings.Contains(rule.Commands()[0], want) { t.Errorf("\nwant commands[0] to have:\n %v\ngot:\n %v", want, rule.Commands()[0]) } } else { wantCommands := []string{ - "cp -f $1 $2", + "cp -f out/unstripped/test.apk out/stripped/test.apk", } if !reflect.DeepEqual(rule.Commands(), wantCommands) { t.Errorf("\nwant commands:\n %v\ngot:\n %v", wantCommands, rule.Commands()) diff --git a/java/dexpreopt.go b/java/dexpreopt.go index 0a565297..b53e9c47 100644 --- a/java/dexpreopt.go +++ b/java/dexpreopt.go @@ -86,18 +86,28 @@ func (d *dexpreopter) dexpreoptDisabled(ctx android.ModuleContext) bool { } var dexpreoptGlobalConfigKey = android.NewOnceKey("DexpreoptGlobalConfig") +var dexpreoptTestGlobalConfigKey = android.NewOnceKey("TestDexpreoptGlobalConfig") + +func setDexpreoptGlobalConfig(config android.Config, globalConfig dexpreopt.GlobalConfig) { + config.Once(dexpreoptTestGlobalConfigKey, func() interface{} { return globalConfig }) +} func dexpreoptGlobalConfig(ctx android.PathContext) dexpreopt.GlobalConfig { return ctx.Config().Once(dexpreoptGlobalConfigKey, func() interface{} { if f := ctx.Config().DexpreoptGlobalConfig(); f != "" { ctx.AddNinjaFileDeps(f) - globalConfig, err := dexpreopt.LoadGlobalConfig(f) + globalConfig, err := dexpreopt.LoadGlobalConfig(ctx, f) if err != nil { panic(err) } return globalConfig } - return dexpreopt.GlobalConfig{} + + // No global config filename set, see if there is a test config set + return ctx.Config().Once(dexpreoptTestGlobalConfigKey, func() interface{} { + // Nope, return an empty config + return dexpreopt.GlobalConfig{} + }) }).(dexpreopt.GlobalConfig) } @@ -131,17 +141,15 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo archs = archs[:1] } - var images []string + var images android.Paths for _, arch := range archs { - images = append(images, info.images[arch].String()) + images = append(images, info.images[arch]) } dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath) strippedDexJarFile := android.PathForModuleOut(ctx, "dexpreopt", dexJarFile.Base()) - deps := android.Paths{dexJarFile} - var profileClassListing android.OptionalPath profileIsTextListing := false if BoolDefault(d.dexpreoptProperties.Dex_preopt.Profile_guided, true) { @@ -157,20 +165,16 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo } } - if profileClassListing.Valid() { - deps = append(deps, profileClassListing.Path()) - } - dexpreoptConfig := dexpreopt.ModuleConfig{ Name: ctx.ModuleName(), DexLocation: dexLocation, - BuildPath: android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").String(), - DexPath: dexJarFile.String(), + BuildPath: android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").OutputPath, + DexPath: dexJarFile, UncompressedDex: d.uncompressedDex, HasApkLibraries: false, PreoptFlags: nil, - ProfileClassListing: profileClassListing.String(), + ProfileClassListing: profileClassListing, ProfileIsTextListing: profileIsTextListing, EnforceUsesLibraries: false, @@ -181,7 +185,7 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo Archs: archs, DexPreoptImages: images, - PreoptBootClassPathDexFiles: info.preoptBootDex.Strings(), + PreoptBootClassPathDexFiles: info.preoptBootDex.Paths(), PreoptBootClassPathDexLocations: info.preoptBootLocations, PreoptExtractedApk: false, @@ -190,11 +194,11 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo ForceCreateAppImage: BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, false), NoStripping: Bool(d.dexpreoptProperties.Dex_preopt.No_stripping), - StripInputPath: dexJarFile.String(), - StripOutputPath: strippedDexJarFile.String(), + StripInputPath: dexJarFile, + StripOutputPath: strippedDexJarFile.OutputPath, } - dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(info.global, dexpreoptConfig) + dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, info.global, dexpreoptConfig) if err != nil { ctx.ModuleErrorf("error generating dexpreopt rule: %s", err.Error()) return dexJarFile diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index 88534283..bb88d32b 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -259,7 +259,7 @@ func dexPreoptBootImageRule(ctx android.SingletonContext, info *bootJarsInfo, symbolsFile := symbolsDir.Join(ctx, "boot.oat") outputDir := info.dir.Join(ctx, "system/framework", arch.String()) outputPath := info.images[arch] - oatLocation := pathtools.ReplaceExtension(dexpreopt.PathToLocation(outputPath.String(), arch), "oat") + oatLocation := pathtools.ReplaceExtension(dexpreopt.PathToLocation(outputPath, arch), "oat") rule := android.NewRuleBuilder() rule.MissingDeps(missingDeps) @@ -289,31 +289,31 @@ func dexPreoptBootImageRule(ctx android.SingletonContext, info *bootJarsInfo, cmd.Tool(info.global.Tools.Dex2oat). Flag("--avoid-storing-invocation"). - FlagWithOutput("--write-invocation-to=", invocationPath.String()).ImplicitOutput(invocationPath.String()). + FlagWithOutput("--write-invocation-to=", invocationPath).ImplicitOutput(invocationPath). Flag("--runtime-arg").FlagWithArg("-Xms", info.global.Dex2oatImageXms). Flag("--runtime-arg").FlagWithArg("-Xmx", info.global.Dex2oatImageXmx) - if profile == nil { - cmd.FlagWithArg("--image-classes=", info.global.PreloadedClasses) - } else { + if profile != nil { cmd.FlagWithArg("--compiler-filter=", "speed-profile") - cmd.FlagWithInput("--profile-file=", profile.String()) + cmd.FlagWithInput("--profile-file=", profile) + } else if info.global.PreloadedClasses.Valid() { + cmd.FlagWithInput("--image-classes=", info.global.PreloadedClasses.Path()) } - if info.global.DirtyImageObjects != "" { - cmd.FlagWithArg("--dirty-image-objects=", info.global.DirtyImageObjects) + if info.global.DirtyImageObjects.Valid() { + cmd.FlagWithInput("--dirty-image-objects=", info.global.DirtyImageObjects.Path()) } cmd. - FlagForEachInput("--dex-file=", info.preoptBootDex.Strings()). + FlagForEachInput("--dex-file=", info.preoptBootDex.Paths()). FlagForEachArg("--dex-location=", info.preoptBootLocations). Flag("--generate-debug-info"). Flag("--generate-build-id"). - FlagWithArg("--oat-symbols=", symbolsFile.String()). + FlagWithOutput("--oat-symbols=", symbolsFile). Flag("--strip"). - FlagWithOutput("--oat-file=", outputPath.ReplaceExtension(ctx, "oat").String()). + FlagWithOutput("--oat-file=", outputPath.ReplaceExtension(ctx, "oat")). FlagWithArg("--oat-location=", oatLocation). - FlagWithOutput("--image=", outputPath.String()). + FlagWithOutput("--image=", outputPath). FlagWithArg("--base=", ctx.Config().LibartImgDeviceBaseAddress()). FlagWithArg("--instruction-set=", arch.String()). FlagWithArg("--instruction-set-variant=", info.global.CpuVariant[arch]). @@ -358,21 +358,21 @@ func dexPreoptBootImageRule(ctx android.SingletonContext, info *bootJarsInfo, extraFiles = append(extraFiles, art, oat, vdex, unstrippedOat) // Install the .oat and .art files. - rule.Install(art.String(), filepath.Join(installDir, art.Base())) - rule.Install(oat.String(), filepath.Join(installDir, oat.Base())) + rule.Install(art, filepath.Join(installDir, art.Base())) + rule.Install(oat, filepath.Join(installDir, oat.Base())) // The vdex files are identical between architectures, install them to a shared location. The Make rules will // only use the install rules for one architecture, and will create symlinks into the architecture-specific // directories. vdexInstalls = append(vdexInstalls, - android.RuleBuilderInstall{vdex.String(), filepath.Join(vdexInstallDir, vdex.Base())}) + android.RuleBuilderInstall{vdex, filepath.Join(vdexInstallDir, vdex.Base())}) // Install the unstripped oat files. The Make rules will put these in $(TARGET_OUT_UNSTRIPPED) unstrippedInstalls = append(unstrippedInstalls, - android.RuleBuilderInstall{unstrippedOat.String(), filepath.Join(installDir, unstrippedOat.Base())}) + android.RuleBuilderInstall{unstrippedOat, filepath.Join(installDir, unstrippedOat.Base())}) } - cmd.ImplicitOutputs(extraFiles.Strings()) + cmd.ImplicitOutputs(extraFiles) rule.Build(pctx, ctx, "bootJarsDexpreopt_"+arch.String(), "dexpreopt boot jars "+arch.String()) @@ -387,7 +387,7 @@ It is likely that the boot classpath is inconsistent. Rebuild with ART_BOOT_IMAGE_EXTRA_ARGS="--runtime-arg -verbose:verifier" to see verification errors.` func bootImageProfileRule(ctx android.SingletonContext, info *bootJarsInfo, missingDeps []string) android.WritablePath { - if len(info.global.BootImageProfiles) == 0 { + if !info.global.UseProfileForBootImage || ctx.Config().IsPdkBuild() || ctx.Config().UnbundledBuild() { return nil } @@ -396,13 +396,25 @@ func bootImageProfileRule(ctx android.SingletonContext, info *bootJarsInfo, miss rule := android.NewRuleBuilder() rule.MissingDeps(missingDeps) - var bootImageProfile string + var bootImageProfile android.Path if len(info.global.BootImageProfiles) > 1 { combinedBootImageProfile := info.dir.Join(ctx, "boot-image-profile.txt") - rule.Command().Text("cat").Inputs(info.global.BootImageProfiles).Text(">").Output(combinedBootImageProfile.String()) - bootImageProfile = combinedBootImageProfile.String() - } else { + rule.Command().Text("cat").Inputs(info.global.BootImageProfiles).Text(">").Output(combinedBootImageProfile) + bootImageProfile = combinedBootImageProfile + } else if len(info.global.BootImageProfiles) == 1 { bootImageProfile = info.global.BootImageProfiles[0] + } else { + // If not set, use the default. Some branches like master-art-host don't have frameworks/base, so manually + // handle the case that the default is missing. Those branches won't attempt to build the profile rule, + // and if they do they'll get a missing deps error. + defaultProfile := "frameworks/base/config/boot-image-profile.txt" + path := android.ExistentPathForSource(ctx, defaultProfile) + if path.Valid() { + bootImageProfile = path.Path() + } else { + missingDeps = append(missingDeps, defaultProfile) + bootImageProfile = android.PathForOutput(ctx, "missing") + } } profile := info.dir.Join(ctx, "boot.prof") @@ -410,12 +422,12 @@ func bootImageProfileRule(ctx android.SingletonContext, info *bootJarsInfo, miss rule.Command(). Text(`ANDROID_LOG_TAGS="*:e"`). Tool(tools.Profman). - FlagWithArg("--create-profile-from=", bootImageProfile). - FlagForEachInput("--apk=", info.preoptBootDex.Strings()). + FlagWithInput("--create-profile-from=", bootImageProfile). + FlagForEachInput("--apk=", info.preoptBootDex.Paths()). FlagForEachArg("--dex-location=", info.preoptBootLocations). - FlagWithOutput("--reference-profile-file=", profile.String()) + FlagWithOutput("--reference-profile-file=", profile) - rule.Install(profile.String(), "/system/etc/boot-image.prof") + rule.Install(profile, "/system/etc/boot-image.prof") rule.Build(pctx, ctx, "bootJarsProfile", "profile boot jars") @@ -439,16 +451,6 @@ func bootImageMakeVars(ctx android.MakeVarsContext) { for arch, _ := range info.images { ctx.Strict("DEXPREOPT_IMAGE_"+arch.String(), info.images[arch].String()) - var builtInstalled []string - for _, install := range info.installs[arch] { - builtInstalled = append(builtInstalled, install.From+":"+install.To) - } - - var unstrippedBuiltInstalled []string - for _, install := range info.unstrippedInstalls[arch] { - unstrippedBuiltInstalled = append(unstrippedBuiltInstalled, install.From+":"+install.To) - } - ctx.Strict("DEXPREOPT_IMAGE_BUILT_INSTALLED_"+arch.String(), info.installs[arch].String()) ctx.Strict("DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_"+arch.String(), info.unstrippedInstalls[arch].String()) ctx.Strict("DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_"+arch.String(), info.vdexInstalls[arch].String()) diff --git a/java/hiddenapi.go b/java/hiddenapi.go index 01e2c5ec..104cd767 100644 --- a/java/hiddenapi.go +++ b/java/hiddenapi.go @@ -15,8 +15,6 @@ package java import ( - "path/filepath" - "github.com/google/blueprint" "android/soong/android" @@ -175,14 +173,3 @@ func hiddenAPIEncodeDex(ctx android.ModuleContext, output android.WritablePath, TransformZipAlign(ctx, output, tmpOutput) } } - -type hiddenAPIPath struct { - path string -} - -var _ android.Path = (*hiddenAPIPath)(nil) - -func (p *hiddenAPIPath) String() string { return p.path } -func (p *hiddenAPIPath) Ext() string { return filepath.Ext(p.path) } -func (p *hiddenAPIPath) Base() string { return filepath.Base(p.path) } -func (p *hiddenAPIPath) Rel() string { return p.path } diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go index adbd3567..ba8b3e1f 100644 --- a/java/hiddenapi_singleton.go +++ b/java/hiddenapi_singleton.go @@ -170,14 +170,14 @@ func stubFlagsRule(ctx android.SingletonContext) { rule.MissingDeps(missingDeps) rule.Command(). - Tool(pctx.HostBinToolPath(ctx, "hiddenapi").String()). + Tool(pctx.HostBinToolPath(ctx, "hiddenapi")). Text("list"). - FlagForEachInput("--boot-dex=", bootDexJars.Strings()). - FlagWithInputList("--public-stub-classpath=", publicStubPaths.Strings(), ":"). - FlagWithInputList("--public-stub-classpath=", systemStubPaths.Strings(), ":"). - FlagWithInputList("--public-stub-classpath=", testStubPaths.Strings(), ":"). - FlagWithInputList("--core-platform-stub-classpath=", corePlatformStubPaths.Strings(), ":"). - FlagWithOutput("--out-api-flags=", tempPath.String()) + FlagForEachInput("--boot-dex=", bootDexJars). + FlagWithInputList("--public-stub-classpath=", publicStubPaths, ":"). + FlagWithInputList("--public-stub-classpath=", systemStubPaths, ":"). + FlagWithInputList("--public-stub-classpath=", testStubPaths, ":"). + FlagWithInputList("--core-platform-stub-classpath=", corePlatformStubPaths, ":"). + FlagWithOutput("--out-api-flags=", tempPath) commitChangeForRestat(rule, tempPath, outputPath) @@ -214,20 +214,20 @@ func flagsRule(ctx android.SingletonContext) android.Path { stubFlags := hiddenAPISingletonPaths(ctx).stubFlags rule.Command(). - Tool(android.PathForSource(ctx, "frameworks/base/tools/hiddenapi/generate_hiddenapi_lists.py").String()). - FlagWithInput("--csv ", stubFlags.String()). - Inputs(flagsCSV.Strings()). + Tool(android.PathForSource(ctx, "frameworks/base/tools/hiddenapi/generate_hiddenapi_lists.py")). + FlagWithInput("--csv ", stubFlags). + Inputs(flagsCSV). FlagWithInput("--greylist ", - android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist.txt").String()). + android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist.txt")). FlagWithInput("--greylist-ignore-conflicts ", - greylistIgnoreConflicts.String()). + greylistIgnoreConflicts). FlagWithInput("--greylist-max-p ", - android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-p.txt").String()). + android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-p.txt")). FlagWithInput("--greylist-max-o-ignore-conflicts ", - android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-o.txt").String()). + android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-o.txt")). FlagWithInput("--blacklist ", - android.PathForSource(ctx, "frameworks/base/config/hiddenapi-force-blacklist.txt").String()). - FlagWithOutput("--output ", tempPath.String()) + android.PathForSource(ctx, "frameworks/base/config/hiddenapi-force-blacklist.txt")). + FlagWithOutput("--output ", tempPath) commitChangeForRestat(rule, tempPath, outputPath) @@ -243,8 +243,8 @@ func emptyFlagsRule(ctx android.SingletonContext) android.Path { outputPath := hiddenAPISingletonPaths(ctx).flags - rule.Command().Text("rm").Flag("-f").Output(outputPath.String()) - rule.Command().Text("touch").Output(outputPath.String()) + rule.Command().Text("rm").Flag("-f").Output(outputPath) + rule.Command().Text("touch").Output(outputPath) rule.Build(pctx, ctx, "emptyHiddenAPIFlagsFile", "empty hiddenapi flags") @@ -269,10 +269,10 @@ func metadataRule(ctx android.SingletonContext) android.Path { outputPath := hiddenAPISingletonPaths(ctx).metadata rule.Command(). - Tool(android.PathForSource(ctx, "frameworks/base/tools/hiddenapi/merge_csv.py").String()). - Inputs(metadataCSV.Strings()). + Tool(android.PathForSource(ctx, "frameworks/base/tools/hiddenapi/merge_csv.py")). + Inputs(metadataCSV). Text(">"). - Output(outputPath.String()) + Output(outputPath) rule.Build(pctx, ctx, "hiddenAPIGreylistMetadataFile", "hiddenapi greylist metadata") @@ -284,15 +284,15 @@ func metadataRule(ctx android.SingletonContext) android.Path { // the rule. func commitChangeForRestat(rule *android.RuleBuilder, tempPath, outputPath android.WritablePath) { rule.Restat() - rule.Temporary(tempPath.String()) + rule.Temporary(tempPath) rule.Command(). Text("("). Text("if"). - Text("cmp -s").Input(tempPath.String()).Output(outputPath.String()).Text(";"). + Text("cmp -s").Input(tempPath).Output(outputPath).Text(";"). Text("then"). - Text("rm").Input(tempPath.String()).Text(";"). + Text("rm").Input(tempPath).Text(";"). Text("else"). - Text("mv").Input(tempPath.String()).Output(outputPath.String()).Text(";"). + Text("mv").Input(tempPath).Output(outputPath).Text(";"). Text("fi"). Text(")") } diff --git a/java/testing.go b/java/testing.go index 6febfa1d..bec3c0b2 100644 --- a/java/testing.go +++ b/java/testing.go @@ -18,6 +18,7 @@ import ( "fmt" "android/soong/android" + "android/soong/dexpreopt" ) func TestConfig(buildDir string, env map[string]string) android.Config { @@ -30,6 +31,9 @@ func TestConfig(buildDir string, env map[string]string) android.Config { config := android.TestArchConfig(buildDir, env) config.TestProductVariables.DeviceSystemSdkVersions = []string{"14", "15"} + pathCtx := android.PathContextForTesting(config, nil) + setDexpreoptGlobalConfig(config, dexpreopt.GlobalConfigForTests(pathCtx)) + return config } |