1// Copyright 2020 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package remoteexec 16 17import ( 18 "sort" 19 "strings" 20 21 "android/soong/android" 22 23 "github.com/google/blueprint" 24) 25 26const ( 27 // ContainerImageKey is the key identifying the container image in the platform spec. 28 ContainerImageKey = "container-image" 29 30 // PoolKey is the key identifying the pool to use for remote execution. 31 PoolKey = "Pool" 32 33 // DefaultImage is the default container image used for Android remote execution. The 34 // image was built with the Dockerfile at 35 // https://android.googlesource.com/platform/prebuilts/remoteexecution-client/+/refs/heads/master/docker/Dockerfile 36 DefaultImage = "docker://gcr.io/androidbuild-re-dockerimage/android-build-remoteexec-image@sha256:582efb38f0c229ea39952fff9e132ccbe183e14869b39888010dacf56b360d62" 37 38 // DefaultWrapperPath is the default path to the remote execution wrapper. 39 DefaultWrapperPath = "prebuilts/remoteexecution-client/live/rewrapper" 40 41 // DefaultPool is the name of the pool to use for remote execution when none is specified. 42 DefaultPool = "default" 43 44 // LocalExecStrategy is the exec strategy to indicate that the action should be run locally. 45 LocalExecStrategy = "local" 46 47 // RemoteExecStrategy is the exec strategy to indicate that the action should be run 48 // remotely. 49 RemoteExecStrategy = "remote" 50 51 // RemoteLocalFallbackExecStrategy is the exec strategy to indicate that the action should 52 // be run remotely and fallback to local execution if remote fails. 53 RemoteLocalFallbackExecStrategy = "remote_local_fallback" 54) 55 56var ( 57 defaultLabels = map[string]string{"type": "tool"} 58 defaultExecStrategy = LocalExecStrategy 59 pctx = android.NewPackageContext("android/soong/remoteexec") 60) 61 62// REParams holds information pertinent to the remote execution of a rule. 63type REParams struct { 64 // Platform is the key value pair used for remotely executing the action. 65 Platform map[string]string 66 // Labels is a map of labels that identify the rule. 67 Labels map[string]string 68 // ExecStrategy is the remote execution strategy: remote, local, or remote_local_fallback. 69 ExecStrategy string 70 // Inputs is a list of input paths or ninja variables. 71 Inputs []string 72 // RSPFile is the name of the ninja variable used by the rule as a placeholder for an rsp 73 // input. 74 RSPFile string 75 // OutputFiles is a list of output file paths or ninja variables as placeholders for rule 76 // outputs. 77 OutputFiles []string 78 // OutputDirectories is a list of output directories or ninja variables as placeholders for 79 // rule output directories. 80 OutputDirectories []string 81 // ToolchainInputs is a list of paths or ninja variables pointing to the location of 82 // toolchain binaries used by the rule. 83 ToolchainInputs []string 84} 85 86func init() { 87 pctx.VariableFunc("Wrapper", func(ctx android.PackageVarContext) string { 88 return wrapper(ctx.Config()) 89 }) 90} 91 92func wrapper(cfg android.Config) string { 93 if override := cfg.Getenv("RBE_WRAPPER"); override != "" { 94 return override 95 } 96 return DefaultWrapperPath 97} 98 99// Template generates the remote execution wrapper template to be added as a prefix to the rule's 100// command. 101func (r *REParams) Template() string { 102 return "${remoteexec.Wrapper}" + r.wrapperArgs() 103} 104 105// NoVarTemplate generates the remote execution wrapper template without variables, to be used in 106// RuleBuilder. 107func (r *REParams) NoVarTemplate(cfg android.Config) string { 108 return wrapper(cfg) + r.wrapperArgs() 109} 110 111func (r *REParams) wrapperArgs() string { 112 args := "" 113 var kvs []string 114 labels := r.Labels 115 if len(labels) == 0 { 116 labels = defaultLabels 117 } 118 for k, v := range labels { 119 kvs = append(kvs, k+"="+v) 120 } 121 sort.Strings(kvs) 122 args += " --labels=" + strings.Join(kvs, ",") 123 124 var platform []string 125 for k, v := range r.Platform { 126 if v == "" { 127 continue 128 } 129 platform = append(platform, k+"="+v) 130 } 131 if _, ok := r.Platform[ContainerImageKey]; !ok { 132 platform = append(platform, ContainerImageKey+"="+DefaultImage) 133 } 134 if platform != nil { 135 sort.Strings(platform) 136 args += " --platform=\"" + strings.Join(platform, ",") + "\"" 137 } 138 139 strategy := r.ExecStrategy 140 if strategy == "" { 141 strategy = defaultExecStrategy 142 } 143 args += " --exec_strategy=" + strategy 144 145 if len(r.Inputs) > 0 { 146 args += " --inputs=" + strings.Join(r.Inputs, ",") 147 } 148 149 if r.RSPFile != "" { 150 args += " --input_list_paths=" + r.RSPFile 151 } 152 153 if len(r.OutputFiles) > 0 { 154 args += " --output_files=" + strings.Join(r.OutputFiles, ",") 155 } 156 157 if len(r.OutputDirectories) > 0 { 158 args += " --output_directories=" + strings.Join(r.OutputDirectories, ",") 159 } 160 161 if len(r.ToolchainInputs) > 0 { 162 args += " --toolchain_inputs=" + strings.Join(r.ToolchainInputs, ",") 163 } 164 165 return args + " -- " 166} 167 168// StaticRules returns a pair of rules based on the given RuleParams, where the first rule is a 169// locally executable rule and the second rule is a remotely executable rule. commonArgs are args 170// used for both the local and remotely executable rules. reArgs are used only for remote 171// execution. 172func StaticRules(ctx android.PackageContext, name string, ruleParams blueprint.RuleParams, reParams *REParams, commonArgs []string, reArgs []string) (blueprint.Rule, blueprint.Rule) { 173 ruleParamsRE := ruleParams 174 ruleParams.Command = strings.ReplaceAll(ruleParams.Command, "$reTemplate", "") 175 ruleParamsRE.Command = strings.ReplaceAll(ruleParamsRE.Command, "$reTemplate", reParams.Template()) 176 177 return ctx.AndroidStaticRule(name, ruleParams, commonArgs...), 178 ctx.AndroidRemoteStaticRule(name+"RE", android.RemoteRuleSupports{RBE: true}, ruleParamsRE, append(commonArgs, reArgs...)...) 179} 180 181// MultiCommandStaticRules returns a pair of rules based on the given RuleParams, where the first 182// rule is a locally executable rule and the second rule is a remotely executable rule. This 183// function supports multiple remote execution wrappers placed in the template when commands are 184// chained together with &&. commonArgs are args used for both the local and remotely executable 185// rules. reArgs are args used only for remote execution. 186func MultiCommandStaticRules(ctx android.PackageContext, name string, ruleParams blueprint.RuleParams, reParams map[string]*REParams, commonArgs []string, reArgs []string) (blueprint.Rule, blueprint.Rule) { 187 ruleParamsRE := ruleParams 188 for k, v := range reParams { 189 ruleParams.Command = strings.ReplaceAll(ruleParams.Command, k, "") 190 ruleParamsRE.Command = strings.ReplaceAll(ruleParamsRE.Command, k, v.Template()) 191 } 192 193 return ctx.AndroidStaticRule(name, ruleParams, commonArgs...), 194 ctx.AndroidRemoteStaticRule(name+"RE", android.RemoteRuleSupports{RBE: true}, ruleParamsRE, append(commonArgs, reArgs...)...) 195} 196 197// EnvOverrideFunc retrieves a variable func that evaluates to the value of the given environment 198// variable if set, otherwise the given default. 199func EnvOverrideFunc(envVar, defaultVal string) func(ctx android.PackageVarContext) string { 200 return func(ctx android.PackageVarContext) string { 201 if override := ctx.Config().Getenv(envVar); override != "" { 202 return override 203 } 204 return defaultVal 205 } 206} 207