1*333d2b36SAndroid Build Coastguard Worker// Copyright 2018 Google Inc. All rights reserved. 2*333d2b36SAndroid Build Coastguard Worker// 3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*333d2b36SAndroid Build Coastguard Worker// 7*333d2b36SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*333d2b36SAndroid Build Coastguard Worker// 9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*333d2b36SAndroid Build Coastguard Worker// limitations under the License. 14*333d2b36SAndroid Build Coastguard Worker 15*333d2b36SAndroid Build Coastguard Workerpackage main 16*333d2b36SAndroid Build Coastguard Worker 17*333d2b36SAndroid Build Coastguard Workerimport ( 18*333d2b36SAndroid Build Coastguard Worker "bytes" 19*333d2b36SAndroid Build Coastguard Worker "flag" 20*333d2b36SAndroid Build Coastguard Worker "fmt" 21*333d2b36SAndroid Build Coastguard Worker "io/ioutil" 22*333d2b36SAndroid Build Coastguard Worker "os" 23*333d2b36SAndroid Build Coastguard Worker "path/filepath" 24*333d2b36SAndroid Build Coastguard Worker "runtime" 25*333d2b36SAndroid Build Coastguard Worker "strings" 26*333d2b36SAndroid Build Coastguard Worker 27*333d2b36SAndroid Build Coastguard Worker "android/soong/android" 28*333d2b36SAndroid Build Coastguard Worker "android/soong/dexpreopt" 29*333d2b36SAndroid Build Coastguard Worker 30*333d2b36SAndroid Build Coastguard Worker "github.com/google/blueprint" 31*333d2b36SAndroid Build Coastguard Worker "github.com/google/blueprint/pathtools" 32*333d2b36SAndroid Build Coastguard Worker) 33*333d2b36SAndroid Build Coastguard Worker 34*333d2b36SAndroid Build Coastguard Workervar ( 35*333d2b36SAndroid Build Coastguard Worker dexpreoptScriptPath = flag.String("dexpreopt_script", "", "path to output dexpreopt script") 36*333d2b36SAndroid Build Coastguard Worker globalSoongConfigPath = flag.String("global_soong", "", "path to global configuration file for settings originating from Soong") 37*333d2b36SAndroid Build Coastguard Worker globalConfigPath = flag.String("global", "", "path to global configuration file") 38*333d2b36SAndroid Build Coastguard Worker moduleConfigPath = flag.String("module", "", "path to module configuration file") 39*333d2b36SAndroid Build Coastguard Worker outDir = flag.String("out_dir", "", "path to output directory") 40*333d2b36SAndroid Build Coastguard Worker // If uses_target_files is true, dexpreopt_gen will be running on extracted target_files.zip files. 41*333d2b36SAndroid Build Coastguard Worker // In this case, the tool replace output file path with $(basePath)/$(on-device file path). 42*333d2b36SAndroid Build Coastguard Worker // The flag is useful when running dex2oat on system image and vendor image which are built separately. 43*333d2b36SAndroid Build Coastguard Worker usesTargetFiles = flag.Bool("uses_target_files", false, "whether or not dexpreopt is running on target_files") 44*333d2b36SAndroid Build Coastguard Worker // basePath indicates the path where target_files.zip is extracted. 45*333d2b36SAndroid Build Coastguard Worker basePath = flag.String("base_path", ".", "base path where images and tools are extracted") 46*333d2b36SAndroid Build Coastguard Worker productPackagesPath = flag.String("product_packages", "", "path to product_packages.txt") 47*333d2b36SAndroid Build Coastguard Worker) 48*333d2b36SAndroid Build Coastguard Worker 49*333d2b36SAndroid Build Coastguard Workertype builderContext struct { 50*333d2b36SAndroid Build Coastguard Worker config android.Config 51*333d2b36SAndroid Build Coastguard Worker} 52*333d2b36SAndroid Build Coastguard Worker 53*333d2b36SAndroid Build Coastguard Workerfunc (x *builderContext) Config() android.Config { return x.config } 54*333d2b36SAndroid Build Coastguard Workerfunc (x *builderContext) AddNinjaFileDeps(...string) {} 55*333d2b36SAndroid Build Coastguard Workerfunc (x *builderContext) Build(android.PackageContext, android.BuildParams) {} 56*333d2b36SAndroid Build Coastguard Workerfunc (x *builderContext) Rule(android.PackageContext, string, blueprint.RuleParams, ...string) blueprint.Rule { 57*333d2b36SAndroid Build Coastguard Worker return nil 58*333d2b36SAndroid Build Coastguard Worker} 59*333d2b36SAndroid Build Coastguard Worker 60*333d2b36SAndroid Build Coastguard Workerfunc main() { 61*333d2b36SAndroid Build Coastguard Worker flag.Parse() 62*333d2b36SAndroid Build Coastguard Worker 63*333d2b36SAndroid Build Coastguard Worker usage := func(err string) { 64*333d2b36SAndroid Build Coastguard Worker if err != "" { 65*333d2b36SAndroid Build Coastguard Worker fmt.Println(err) 66*333d2b36SAndroid Build Coastguard Worker flag.Usage() 67*333d2b36SAndroid Build Coastguard Worker os.Exit(1) 68*333d2b36SAndroid Build Coastguard Worker } 69*333d2b36SAndroid Build Coastguard Worker } 70*333d2b36SAndroid Build Coastguard Worker 71*333d2b36SAndroid Build Coastguard Worker if flag.NArg() > 0 { 72*333d2b36SAndroid Build Coastguard Worker usage("unrecognized argument " + flag.Arg(0)) 73*333d2b36SAndroid Build Coastguard Worker } 74*333d2b36SAndroid Build Coastguard Worker 75*333d2b36SAndroid Build Coastguard Worker if *dexpreoptScriptPath == "" { 76*333d2b36SAndroid Build Coastguard Worker usage("path to output dexpreopt script is required") 77*333d2b36SAndroid Build Coastguard Worker } 78*333d2b36SAndroid Build Coastguard Worker 79*333d2b36SAndroid Build Coastguard Worker if *globalSoongConfigPath == "" { 80*333d2b36SAndroid Build Coastguard Worker usage("--global_soong configuration file is required") 81*333d2b36SAndroid Build Coastguard Worker } 82*333d2b36SAndroid Build Coastguard Worker 83*333d2b36SAndroid Build Coastguard Worker if *globalConfigPath == "" { 84*333d2b36SAndroid Build Coastguard Worker usage("--global configuration file is required") 85*333d2b36SAndroid Build Coastguard Worker } 86*333d2b36SAndroid Build Coastguard Worker 87*333d2b36SAndroid Build Coastguard Worker if *moduleConfigPath == "" { 88*333d2b36SAndroid Build Coastguard Worker usage("--module configuration file is required") 89*333d2b36SAndroid Build Coastguard Worker } 90*333d2b36SAndroid Build Coastguard Worker 91*333d2b36SAndroid Build Coastguard Worker if *productPackagesPath == "" { 92*333d2b36SAndroid Build Coastguard Worker usage("--product_packages configuration file is required") 93*333d2b36SAndroid Build Coastguard Worker } 94*333d2b36SAndroid Build Coastguard Worker 95*333d2b36SAndroid Build Coastguard Worker // NOTE: duplicating --out_dir here is incorrect (one should be the another 96*333d2b36SAndroid Build Coastguard Worker // plus "/soong" but doing so apparently breaks dexpreopt 97*333d2b36SAndroid Build Coastguard Worker ctx := &builderContext{android.NullConfig(*outDir, *outDir)} 98*333d2b36SAndroid Build Coastguard Worker 99*333d2b36SAndroid Build Coastguard Worker globalSoongConfigData, err := ioutil.ReadFile(*globalSoongConfigPath) 100*333d2b36SAndroid Build Coastguard Worker if err != nil { 101*333d2b36SAndroid Build Coastguard Worker fmt.Fprintf(os.Stderr, "error reading global Soong config %q: %s\n", *globalSoongConfigPath, err) 102*333d2b36SAndroid Build Coastguard Worker os.Exit(2) 103*333d2b36SAndroid Build Coastguard Worker } 104*333d2b36SAndroid Build Coastguard Worker 105*333d2b36SAndroid Build Coastguard Worker globalSoongConfig, err := dexpreopt.ParseGlobalSoongConfig(ctx, globalSoongConfigData) 106*333d2b36SAndroid Build Coastguard Worker if err != nil { 107*333d2b36SAndroid Build Coastguard Worker fmt.Fprintf(os.Stderr, "error parsing global Soong config %q: %s\n", *globalSoongConfigPath, err) 108*333d2b36SAndroid Build Coastguard Worker os.Exit(2) 109*333d2b36SAndroid Build Coastguard Worker } 110*333d2b36SAndroid Build Coastguard Worker 111*333d2b36SAndroid Build Coastguard Worker globalConfigData, err := ioutil.ReadFile(*globalConfigPath) 112*333d2b36SAndroid Build Coastguard Worker if err != nil { 113*333d2b36SAndroid Build Coastguard Worker fmt.Fprintf(os.Stderr, "error reading global config %q: %s\n", *globalConfigPath, err) 114*333d2b36SAndroid Build Coastguard Worker os.Exit(2) 115*333d2b36SAndroid Build Coastguard Worker } 116*333d2b36SAndroid Build Coastguard Worker 117*333d2b36SAndroid Build Coastguard Worker globalConfig, err := dexpreopt.ParseGlobalConfig(ctx, globalConfigData) 118*333d2b36SAndroid Build Coastguard Worker if err != nil { 119*333d2b36SAndroid Build Coastguard Worker fmt.Fprintf(os.Stderr, "error parsing global config %q: %s\n", *globalConfigPath, err) 120*333d2b36SAndroid Build Coastguard Worker os.Exit(2) 121*333d2b36SAndroid Build Coastguard Worker } 122*333d2b36SAndroid Build Coastguard Worker 123*333d2b36SAndroid Build Coastguard Worker moduleConfigData, err := ioutil.ReadFile(*moduleConfigPath) 124*333d2b36SAndroid Build Coastguard Worker if err != nil { 125*333d2b36SAndroid Build Coastguard Worker fmt.Fprintf(os.Stderr, "error reading module config %q: %s\n", *moduleConfigPath, err) 126*333d2b36SAndroid Build Coastguard Worker os.Exit(2) 127*333d2b36SAndroid Build Coastguard Worker } 128*333d2b36SAndroid Build Coastguard Worker 129*333d2b36SAndroid Build Coastguard Worker moduleConfig, err := dexpreopt.ParseModuleConfig(ctx, moduleConfigData) 130*333d2b36SAndroid Build Coastguard Worker if err != nil { 131*333d2b36SAndroid Build Coastguard Worker fmt.Fprintf(os.Stderr, "error parsing module config %q: %s\n", *moduleConfigPath, err) 132*333d2b36SAndroid Build Coastguard Worker os.Exit(2) 133*333d2b36SAndroid Build Coastguard Worker } 134*333d2b36SAndroid Build Coastguard Worker 135*333d2b36SAndroid Build Coastguard Worker moduleConfig.DexPath = android.PathForTesting("$1") 136*333d2b36SAndroid Build Coastguard Worker 137*333d2b36SAndroid Build Coastguard Worker defer func() { 138*333d2b36SAndroid Build Coastguard Worker if r := recover(); r != nil { 139*333d2b36SAndroid Build Coastguard Worker switch x := r.(type) { 140*333d2b36SAndroid Build Coastguard Worker case runtime.Error: 141*333d2b36SAndroid Build Coastguard Worker panic(x) 142*333d2b36SAndroid Build Coastguard Worker case error: 143*333d2b36SAndroid Build Coastguard Worker fmt.Fprintln(os.Stderr, "error:", r) 144*333d2b36SAndroid Build Coastguard Worker os.Exit(3) 145*333d2b36SAndroid Build Coastguard Worker default: 146*333d2b36SAndroid Build Coastguard Worker panic(x) 147*333d2b36SAndroid Build Coastguard Worker } 148*333d2b36SAndroid Build Coastguard Worker } 149*333d2b36SAndroid Build Coastguard Worker }() 150*333d2b36SAndroid Build Coastguard Worker if *usesTargetFiles { 151*333d2b36SAndroid Build Coastguard Worker moduleConfig.ManifestPath = android.OptionalPath{} 152*333d2b36SAndroid Build Coastguard Worker prefix := "dex2oat_result" 153*333d2b36SAndroid Build Coastguard Worker moduleConfig.BuildPath = android.PathForOutput(ctx, filepath.Join(prefix, moduleConfig.DexLocation)) 154*333d2b36SAndroid Build Coastguard Worker for i, location := range moduleConfig.PreoptBootClassPathDexLocations { 155*333d2b36SAndroid Build Coastguard Worker moduleConfig.PreoptBootClassPathDexFiles[i] = android.PathForSource(ctx, *basePath+location) 156*333d2b36SAndroid Build Coastguard Worker } 157*333d2b36SAndroid Build Coastguard Worker for i := range moduleConfig.ClassLoaderContexts { 158*333d2b36SAndroid Build Coastguard Worker for _, v := range moduleConfig.ClassLoaderContexts[i] { 159*333d2b36SAndroid Build Coastguard Worker v.Host = android.PathForSource(ctx, *basePath+v.Device) 160*333d2b36SAndroid Build Coastguard Worker } 161*333d2b36SAndroid Build Coastguard Worker } 162*333d2b36SAndroid Build Coastguard Worker moduleConfig.EnforceUsesLibraries = false 163*333d2b36SAndroid Build Coastguard Worker for i, location := range moduleConfig.DexPreoptImageLocationsOnDevice { 164*333d2b36SAndroid Build Coastguard Worker moduleConfig.DexPreoptImageLocationsOnHost[i] = *basePath + location 165*333d2b36SAndroid Build Coastguard Worker } 166*333d2b36SAndroid Build Coastguard Worker } 167*333d2b36SAndroid Build Coastguard Worker writeScripts(ctx, globalSoongConfig, globalConfig, moduleConfig, *dexpreoptScriptPath, *productPackagesPath) 168*333d2b36SAndroid Build Coastguard Worker} 169*333d2b36SAndroid Build Coastguard Worker 170*333d2b36SAndroid Build Coastguard Workerfunc writeScripts(ctx android.BuilderContext, globalSoong *dexpreopt.GlobalSoongConfig, 171*333d2b36SAndroid Build Coastguard Worker global *dexpreopt.GlobalConfig, module *dexpreopt.ModuleConfig, dexpreoptScriptPath string, 172*333d2b36SAndroid Build Coastguard Worker productPackagesPath string) { 173*333d2b36SAndroid Build Coastguard Worker write := func(rule *android.RuleBuilder, file string) { 174*333d2b36SAndroid Build Coastguard Worker script := &bytes.Buffer{} 175*333d2b36SAndroid Build Coastguard Worker script.WriteString(scriptHeader) 176*333d2b36SAndroid Build Coastguard Worker for _, c := range rule.Commands() { 177*333d2b36SAndroid Build Coastguard Worker script.WriteString(c) 178*333d2b36SAndroid Build Coastguard Worker script.WriteString("\n\n") 179*333d2b36SAndroid Build Coastguard Worker } 180*333d2b36SAndroid Build Coastguard Worker 181*333d2b36SAndroid Build Coastguard Worker depFile := &bytes.Buffer{} 182*333d2b36SAndroid Build Coastguard Worker 183*333d2b36SAndroid Build Coastguard Worker fmt.Fprint(depFile, `: \`+"\n") 184*333d2b36SAndroid Build Coastguard Worker for _, tool := range rule.Tools() { 185*333d2b36SAndroid Build Coastguard Worker fmt.Fprintf(depFile, ` %s \`+"\n", tool) 186*333d2b36SAndroid Build Coastguard Worker } 187*333d2b36SAndroid Build Coastguard Worker for _, input := range rule.Inputs() { 188*333d2b36SAndroid Build Coastguard Worker // Assume the rule that ran the script already has a dependency on the input file passed on the 189*333d2b36SAndroid Build Coastguard Worker // command line. 190*333d2b36SAndroid Build Coastguard Worker if input.String() != "$1" { 191*333d2b36SAndroid Build Coastguard Worker fmt.Fprintf(depFile, ` %s \`+"\n", input) 192*333d2b36SAndroid Build Coastguard Worker } 193*333d2b36SAndroid Build Coastguard Worker } 194*333d2b36SAndroid Build Coastguard Worker depFile.WriteString("\n") 195*333d2b36SAndroid Build Coastguard Worker 196*333d2b36SAndroid Build Coastguard Worker fmt.Fprintln(script, "rm -f $2.d") 197*333d2b36SAndroid Build Coastguard Worker // Write the output path unescaped so the $2 gets expanded 198*333d2b36SAndroid Build Coastguard Worker fmt.Fprintln(script, `echo -n $2 > $2.d`) 199*333d2b36SAndroid Build Coastguard Worker // Write the rest of the depsfile using cat <<'EOF', which will not do any shell expansion on 200*333d2b36SAndroid Build Coastguard Worker // the contents to preserve backslashes and special characters in filenames. 201*333d2b36SAndroid Build Coastguard Worker fmt.Fprintf(script, "cat >> $2.d <<'EOF'\n%sEOF\n", depFile.String()) 202*333d2b36SAndroid Build Coastguard Worker 203*333d2b36SAndroid Build Coastguard Worker err := pathtools.WriteFileIfChanged(file, script.Bytes(), 0755) 204*333d2b36SAndroid Build Coastguard Worker if err != nil { 205*333d2b36SAndroid Build Coastguard Worker panic(err) 206*333d2b36SAndroid Build Coastguard Worker } 207*333d2b36SAndroid Build Coastguard Worker } 208*333d2b36SAndroid Build Coastguard Worker cpApexSscpServerJar := false // dexpreopt_gen operates on make modules, and since sscp libraries are in soong, this should be a noop 209*333d2b36SAndroid Build Coastguard Worker dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule( 210*333d2b36SAndroid Build Coastguard Worker ctx, globalSoong, global, module, android.PathForTesting(productPackagesPath), cpApexSscpServerJar) 211*333d2b36SAndroid Build Coastguard Worker if err != nil { 212*333d2b36SAndroid Build Coastguard Worker panic(err) 213*333d2b36SAndroid Build Coastguard Worker } 214*333d2b36SAndroid Build Coastguard Worker // When usesTargetFiles is true, only odex/vdex files are necessary. 215*333d2b36SAndroid Build Coastguard Worker // So skip redunant processes(such as copying the result to the artifact path, and zipping, and so on.) 216*333d2b36SAndroid Build Coastguard Worker if *usesTargetFiles { 217*333d2b36SAndroid Build Coastguard Worker write(dexpreoptRule, dexpreoptScriptPath) 218*333d2b36SAndroid Build Coastguard Worker return 219*333d2b36SAndroid Build Coastguard Worker } 220*333d2b36SAndroid Build Coastguard Worker installDir := module.BuildPath.InSameDir(ctx, "dexpreopt_install") 221*333d2b36SAndroid Build Coastguard Worker 222*333d2b36SAndroid Build Coastguard Worker dexpreoptRule.Command().FlagWithArg("rm -rf ", installDir.String()) 223*333d2b36SAndroid Build Coastguard Worker dexpreoptRule.Command().FlagWithArg("mkdir -p ", installDir.String()) 224*333d2b36SAndroid Build Coastguard Worker 225*333d2b36SAndroid Build Coastguard Worker for _, install := range dexpreoptRule.Installs() { 226*333d2b36SAndroid Build Coastguard Worker installPath := installDir.Join(ctx, strings.TrimPrefix(install.To, "/")) 227*333d2b36SAndroid Build Coastguard Worker dexpreoptRule.Command().Text("mkdir -p").Flag(filepath.Dir(installPath.String())) 228*333d2b36SAndroid Build Coastguard Worker dexpreoptRule.Command().Text("cp -f").Input(install.From).Output(installPath) 229*333d2b36SAndroid Build Coastguard Worker } 230*333d2b36SAndroid Build Coastguard Worker dexpreoptRule.Command().Tool(globalSoong.SoongZip). 231*333d2b36SAndroid Build Coastguard Worker FlagWithArg("-o ", "$2"). 232*333d2b36SAndroid Build Coastguard Worker FlagWithArg("-C ", installDir.String()). 233*333d2b36SAndroid Build Coastguard Worker FlagWithArg("-D ", installDir.String()) 234*333d2b36SAndroid Build Coastguard Worker 235*333d2b36SAndroid Build Coastguard Worker // The written scripts will assume the input is $1 and the output is $2 236*333d2b36SAndroid Build Coastguard Worker if module.DexPath.String() != "$1" { 237*333d2b36SAndroid Build Coastguard Worker panic(fmt.Errorf("module.DexPath must be '$1', was %q", module.DexPath)) 238*333d2b36SAndroid Build Coastguard Worker } 239*333d2b36SAndroid Build Coastguard Worker 240*333d2b36SAndroid Build Coastguard Worker write(dexpreoptRule, dexpreoptScriptPath) 241*333d2b36SAndroid Build Coastguard Worker} 242*333d2b36SAndroid Build Coastguard Worker 243*333d2b36SAndroid Build Coastguard Workerconst scriptHeader = `#!/bin/bash 244*333d2b36SAndroid Build Coastguard Worker 245*333d2b36SAndroid Build Coastguard Workererr() { 246*333d2b36SAndroid Build Coastguard Worker errno=$? 247*333d2b36SAndroid Build Coastguard Worker echo "error: $0:$1 exited with status $errno" >&2 248*333d2b36SAndroid Build Coastguard Worker echo "error in command:" >&2 249*333d2b36SAndroid Build Coastguard Worker sed -n -e "$1p" $0 >&2 250*333d2b36SAndroid Build Coastguard Worker if [ "$errno" -ne 0 ]; then 251*333d2b36SAndroid Build Coastguard Worker exit $errno 252*333d2b36SAndroid Build Coastguard Worker else 253*333d2b36SAndroid Build Coastguard Worker exit 1 254*333d2b36SAndroid Build Coastguard Worker fi 255*333d2b36SAndroid Build Coastguard Worker} 256*333d2b36SAndroid Build Coastguard Worker 257*333d2b36SAndroid Build Coastguard Workertrap 'err $LINENO' ERR 258*333d2b36SAndroid Build Coastguard Worker 259*333d2b36SAndroid Build Coastguard Worker` 260