1// Copyright 2017 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 java 16 17import ( 18 "path/filepath" 19 "sort" 20 "strconv" 21 "strings" 22 23 "github.com/google/blueprint" 24 25 "android/soong/android" 26) 27 28const AAPT2_SHARD_SIZE = 100 29 30// Convert input resource file path to output file path. 31// values-[config]/<file>.xml -> values-[config]_<file>.arsc.flat; 32// For other resource file, just replace the last "/" with "_" and 33// add .flat extension. 34func pathToAapt2Path(ctx android.ModuleContext, res android.Path) android.WritablePath { 35 36 name := res.Base() 37 subDir := filepath.Dir(res.String()) 38 subDir, lastDir := filepath.Split(subDir) 39 if strings.HasPrefix(lastDir, "values") { 40 name = strings.TrimSuffix(name, ".xml") + ".arsc" 41 } 42 name = lastDir + "_" + name + ".flat" 43 return android.PathForModuleOut(ctx, "aapt2", subDir, name) 44} 45 46func pathsToAapt2Paths(ctx android.ModuleContext, resPaths android.Paths) android.WritablePaths { 47 outPaths := make(android.WritablePaths, len(resPaths)) 48 49 for i, res := range resPaths { 50 outPaths[i] = pathToAapt2Path(ctx, res) 51 } 52 53 return outPaths 54} 55 56var aapt2CompileRule = pctx.AndroidStaticRule("aapt2Compile", 57 blueprint.RuleParams{ 58 Command: `${config.Aapt2Cmd} compile -o $outDir $cFlags --legacy $in`, 59 CommandDeps: []string{"${config.Aapt2Cmd}"}, 60 }, 61 "outDir", "cFlags") 62 63func aapt2Compile(ctx android.ModuleContext, dir android.Path, paths android.Paths) android.WritablePaths { 64 shards := shardPaths(paths, AAPT2_SHARD_SIZE) 65 66 ret := make(android.WritablePaths, 0, len(paths)) 67 68 for i, shard := range shards { 69 outPaths := pathsToAapt2Paths(ctx, shard) 70 ret = append(ret, outPaths...) 71 72 shardDesc := "" 73 if i != 0 { 74 shardDesc = " " + strconv.Itoa(i+1) 75 } 76 77 ctx.Build(pctx, android.BuildParams{ 78 Rule: aapt2CompileRule, 79 Description: "aapt2 compile " + dir.String() + shardDesc, 80 Inputs: shard, 81 Outputs: outPaths, 82 Args: map[string]string{ 83 "outDir": android.PathForModuleOut(ctx, "aapt2", dir.String()).String(), 84 // Always set --pseudo-localize, it will be stripped out later for release 85 // builds that don't want it. 86 "cFlags": "--pseudo-localize", 87 }, 88 }) 89 } 90 91 sort.Slice(ret, func(i, j int) bool { 92 return ret[i].String() < ret[j].String() 93 }) 94 return ret 95} 96 97func aapt2CompileDirs(ctx android.ModuleContext, flata android.WritablePath, dirs android.Paths, deps android.Paths) { 98 ctx.Build(pctx, android.BuildParams{ 99 Rule: aapt2CompileRule, 100 Description: "aapt2 compile dirs", 101 Implicits: deps, 102 Output: flata, 103 Args: map[string]string{ 104 "outDir": flata.String(), 105 // Always set --pseudo-localize, it will be stripped out later for release 106 // builds that don't want it. 107 "cFlags": "--pseudo-localize " + android.JoinWithPrefix(dirs.Strings(), "--dir "), 108 }, 109 }) 110} 111 112var aapt2CompileZipRule = pctx.AndroidStaticRule("aapt2CompileZip", 113 blueprint.RuleParams{ 114 Command: `${config.ZipSyncCmd} -d $resZipDir $in && ` + 115 `${config.Aapt2Cmd} compile -o $out $cFlags --legacy --dir $resZipDir`, 116 CommandDeps: []string{ 117 "${config.Aapt2Cmd}", 118 "${config.ZipSyncCmd}", 119 }, 120 }, "cFlags", "resZipDir") 121 122func aapt2CompileZip(ctx android.ModuleContext, flata android.WritablePath, zip android.Path) { 123 ctx.Build(pctx, android.BuildParams{ 124 Rule: aapt2CompileZipRule, 125 Description: "aapt2 compile zip", 126 Input: zip, 127 Output: flata, 128 Args: map[string]string{ 129 // Always set --pseudo-localize, it will be stripped out later for release 130 // builds that don't want it. 131 "cFlags": "--pseudo-localize", 132 "resZipDir": android.PathForModuleOut(ctx, "aapt2", "reszip", flata.Base()).String(), 133 }, 134 }) 135} 136 137var aapt2LinkRule = pctx.AndroidStaticRule("aapt2Link", 138 blueprint.RuleParams{ 139 Command: `rm -rf $genDir && ` + 140 `${config.Aapt2Cmd} link -o $out $flags --java $genDir --proguard $proguardOptions ` + 141 `--output-text-symbols ${rTxt} $inFlags && ` + 142 `${config.SoongZipCmd} -write_if_changed -jar -o $genJar -C $genDir -D $genDir &&` + 143 `${config.ExtractJarPackagesCmd} -i $genJar -o $extraPackages --prefix '--extra-packages '`, 144 145 CommandDeps: []string{ 146 "${config.Aapt2Cmd}", 147 "${config.SoongZipCmd}", 148 "${config.ExtractJarPackagesCmd}", 149 }, 150 Restat: true, 151 }, 152 "flags", "inFlags", "proguardOptions", "genDir", "genJar", "rTxt", "extraPackages") 153 154var fileListToFileRule = pctx.AndroidStaticRule("fileListToFile", 155 blueprint.RuleParams{ 156 Command: `cp $out.rsp $out`, 157 Rspfile: "$out.rsp", 158 RspfileContent: "$in", 159 }) 160 161func aapt2Link(ctx android.ModuleContext, 162 packageRes, genJar, proguardOptions, rTxt, extraPackages android.WritablePath, 163 flags []string, deps android.Paths, 164 compiledRes, compiledOverlay android.Paths, splitPackages android.WritablePaths) { 165 166 genDir := android.PathForModuleGen(ctx, "aapt2", "R") 167 168 var inFlags []string 169 170 if len(compiledRes) > 0 { 171 resFileList := android.PathForModuleOut(ctx, "aapt2", "res.list") 172 // Write out file lists to files 173 ctx.Build(pctx, android.BuildParams{ 174 Rule: fileListToFileRule, 175 Description: "resource file list", 176 Inputs: compiledRes, 177 Output: resFileList, 178 }) 179 180 deps = append(deps, compiledRes...) 181 deps = append(deps, resFileList) 182 inFlags = append(inFlags, "@"+resFileList.String()) 183 } 184 185 if len(compiledOverlay) > 0 { 186 overlayFileList := android.PathForModuleOut(ctx, "aapt2", "overlay.list") 187 ctx.Build(pctx, android.BuildParams{ 188 Rule: fileListToFileRule, 189 Description: "overlay resource file list", 190 Inputs: compiledOverlay, 191 Output: overlayFileList, 192 }) 193 194 deps = append(deps, compiledOverlay...) 195 deps = append(deps, overlayFileList) 196 inFlags = append(inFlags, "-R", "@"+overlayFileList.String()) 197 } 198 199 implicitOutputs := append(splitPackages, proguardOptions, genJar, rTxt, extraPackages) 200 201 ctx.Build(pctx, android.BuildParams{ 202 Rule: aapt2LinkRule, 203 Description: "aapt2 link", 204 Implicits: deps, 205 Output: packageRes, 206 ImplicitOutputs: implicitOutputs, 207 Args: map[string]string{ 208 "flags": strings.Join(flags, " "), 209 "inFlags": strings.Join(inFlags, " "), 210 "proguardOptions": proguardOptions.String(), 211 "genDir": genDir.String(), 212 "genJar": genJar.String(), 213 "rTxt": rTxt.String(), 214 "extraPackages": extraPackages.String(), 215 }, 216 }) 217} 218 219var aapt2ConvertRule = pctx.AndroidStaticRule("aapt2Convert", 220 blueprint.RuleParams{ 221 Command: `${config.Aapt2Cmd} convert --output-format proto $in -o $out`, 222 CommandDeps: []string{"${config.Aapt2Cmd}"}, 223 }) 224 225func aapt2Convert(ctx android.ModuleContext, out android.WritablePath, in android.Path) { 226 ctx.Build(pctx, android.BuildParams{ 227 Rule: aapt2ConvertRule, 228 Input: in, 229 Output: out, 230 Description: "convert to proto", 231 }) 232} 233