| // Copyright 2017 Google Inc. All rights reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package java |
| |
| import ( |
| "path/filepath" |
| "sort" |
| "strconv" |
| "strings" |
| |
| "github.com/google/blueprint" |
| |
| "android/soong/android" |
| ) |
| |
| const AAPT2_SHARD_SIZE = 100 |
| |
| // Convert input resource file path to output file path. |
| // values-[config]/<file>.xml -> values-[config]_<file>.arsc.flat; |
| // For other resource file, just replace the last "/" with "_" and |
| // add .flat extension. |
| func pathToAapt2Path(ctx android.ModuleContext, res android.Path) android.WritablePath { |
| |
| name := res.Base() |
| subDir := filepath.Dir(res.String()) |
| subDir, lastDir := filepath.Split(subDir) |
| if strings.HasPrefix(lastDir, "values") { |
| name = strings.TrimSuffix(name, ".xml") + ".arsc" |
| } |
| name = lastDir + "_" + name + ".flat" |
| return android.PathForModuleOut(ctx, "aapt2", subDir, name) |
| } |
| |
| func pathsToAapt2Paths(ctx android.ModuleContext, resPaths android.Paths) android.WritablePaths { |
| outPaths := make(android.WritablePaths, len(resPaths)) |
| |
| for i, res := range resPaths { |
| outPaths[i] = pathToAapt2Path(ctx, res) |
| } |
| |
| return outPaths |
| } |
| |
| var aapt2CompileRule = pctx.AndroidStaticRule("aapt2Compile", |
| blueprint.RuleParams{ |
| Command: `${config.Aapt2Cmd} compile -o $outDir $cFlags $in`, |
| CommandDeps: []string{"${config.Aapt2Cmd}"}, |
| }, |
| "outDir", "cFlags") |
| |
| func aapt2Compile(ctx android.ModuleContext, dir android.Path, paths android.Paths, |
| flags []string) android.WritablePaths { |
| |
| shards := android.ShardPaths(paths, AAPT2_SHARD_SIZE) |
| |
| ret := make(android.WritablePaths, 0, len(paths)) |
| |
| for i, shard := range shards { |
| outPaths := pathsToAapt2Paths(ctx, shard) |
| ret = append(ret, outPaths...) |
| |
| shardDesc := "" |
| if i != 0 { |
| shardDesc = " " + strconv.Itoa(i+1) |
| } |
| |
| ctx.Build(pctx, android.BuildParams{ |
| Rule: aapt2CompileRule, |
| Description: "aapt2 compile " + dir.String() + shardDesc, |
| Inputs: shard, |
| Outputs: outPaths, |
| Args: map[string]string{ |
| "outDir": android.PathForModuleOut(ctx, "aapt2", dir.String()).String(), |
| "cFlags": strings.Join(flags, " "), |
| }, |
| }) |
| } |
| |
| sort.Slice(ret, func(i, j int) bool { |
| return ret[i].String() < ret[j].String() |
| }) |
| return ret |
| } |
| |
| var aapt2CompileZipRule = pctx.AndroidStaticRule("aapt2CompileZip", |
| blueprint.RuleParams{ |
| Command: `${config.ZipSyncCmd} -d $resZipDir $zipSyncFlags $in && ` + |
| `${config.Aapt2Cmd} compile -o $out $cFlags --dir $resZipDir`, |
| CommandDeps: []string{ |
| "${config.Aapt2Cmd}", |
| "${config.ZipSyncCmd}", |
| }, |
| }, "cFlags", "resZipDir", "zipSyncFlags") |
| |
| func aapt2CompileZip(ctx android.ModuleContext, flata android.WritablePath, zip android.Path, zipPrefix string, |
| flags []string) { |
| |
| if zipPrefix != "" { |
| zipPrefix = "--zip-prefix " + zipPrefix |
| } |
| ctx.Build(pctx, android.BuildParams{ |
| Rule: aapt2CompileZipRule, |
| Description: "aapt2 compile zip", |
| Input: zip, |
| Output: flata, |
| Args: map[string]string{ |
| "cFlags": strings.Join(flags, " "), |
| "resZipDir": android.PathForModuleOut(ctx, "aapt2", "reszip", flata.Base()).String(), |
| "zipSyncFlags": zipPrefix, |
| }, |
| }) |
| } |
| |
| var aapt2LinkRule = pctx.AndroidStaticRule("aapt2Link", |
| blueprint.RuleParams{ |
| Command: `rm -rf $genDir && ` + |
| `${config.Aapt2Cmd} link -o $out $flags --java $genDir --proguard $proguardOptions ` + |
| `--output-text-symbols ${rTxt} $inFlags && ` + |
| `${config.SoongZipCmd} -write_if_changed -jar -o $genJar -C $genDir -D $genDir &&` + |
| `${config.ExtractJarPackagesCmd} -i $genJar -o $extraPackages --prefix '--extra-packages '`, |
| |
| CommandDeps: []string{ |
| "${config.Aapt2Cmd}", |
| "${config.SoongZipCmd}", |
| "${config.ExtractJarPackagesCmd}", |
| }, |
| Restat: true, |
| }, |
| "flags", "inFlags", "proguardOptions", "genDir", "genJar", "rTxt", "extraPackages") |
| |
| var fileListToFileRule = pctx.AndroidStaticRule("fileListToFile", |
| blueprint.RuleParams{ |
| Command: `cp $out.rsp $out`, |
| Rspfile: "$out.rsp", |
| RspfileContent: "$in", |
| }) |
| |
| var mergeAssetsRule = pctx.AndroidStaticRule("mergeAssets", |
| blueprint.RuleParams{ |
| Command: `${config.MergeZipsCmd} ${out} ${in}`, |
| CommandDeps: []string{"${config.MergeZipsCmd}"}, |
| }) |
| |
| func aapt2Link(ctx android.ModuleContext, |
| packageRes, genJar, proguardOptions, rTxt, extraPackages android.WritablePath, |
| flags []string, deps android.Paths, |
| compiledRes, compiledOverlay, assetPackages android.Paths, splitPackages android.WritablePaths) { |
| |
| genDir := android.PathForModuleGen(ctx, "aapt2", "R") |
| |
| var inFlags []string |
| |
| if len(compiledRes) > 0 { |
| resFileList := android.PathForModuleOut(ctx, "aapt2", "res.list") |
| // Write out file lists to files |
| ctx.Build(pctx, android.BuildParams{ |
| Rule: fileListToFileRule, |
| Description: "resource file list", |
| Inputs: compiledRes, |
| Output: resFileList, |
| }) |
| |
| deps = append(deps, compiledRes...) |
| deps = append(deps, resFileList) |
| inFlags = append(inFlags, "@"+resFileList.String()) |
| } |
| |
| if len(compiledOverlay) > 0 { |
| overlayFileList := android.PathForModuleOut(ctx, "aapt2", "overlay.list") |
| ctx.Build(pctx, android.BuildParams{ |
| Rule: fileListToFileRule, |
| Description: "overlay resource file list", |
| Inputs: compiledOverlay, |
| Output: overlayFileList, |
| }) |
| |
| deps = append(deps, compiledOverlay...) |
| deps = append(deps, overlayFileList) |
| inFlags = append(inFlags, "-R", "@"+overlayFileList.String()) |
| } |
| |
| implicitOutputs := append(splitPackages, proguardOptions, genJar, rTxt, extraPackages) |
| linkOutput := packageRes |
| |
| // AAPT2 ignores assets in overlays. Merge them after linking. |
| if len(assetPackages) > 0 { |
| linkOutput = android.PathForModuleOut(ctx, "aapt2", "package-res.apk") |
| inputZips := append(android.Paths{linkOutput}, assetPackages...) |
| ctx.Build(pctx, android.BuildParams{ |
| Rule: mergeAssetsRule, |
| Inputs: inputZips, |
| Output: packageRes, |
| Description: "merge assets from dependencies", |
| }) |
| } |
| |
| ctx.Build(pctx, android.BuildParams{ |
| Rule: aapt2LinkRule, |
| Description: "aapt2 link", |
| Implicits: deps, |
| Output: linkOutput, |
| ImplicitOutputs: implicitOutputs, |
| Args: map[string]string{ |
| "flags": strings.Join(flags, " "), |
| "inFlags": strings.Join(inFlags, " "), |
| "proguardOptions": proguardOptions.String(), |
| "genDir": genDir.String(), |
| "genJar": genJar.String(), |
| "rTxt": rTxt.String(), |
| "extraPackages": extraPackages.String(), |
| }, |
| }) |
| } |
| |
| var aapt2ConvertRule = pctx.AndroidStaticRule("aapt2Convert", |
| blueprint.RuleParams{ |
| Command: `${config.Aapt2Cmd} convert --output-format proto $in -o $out`, |
| CommandDeps: []string{"${config.Aapt2Cmd}"}, |
| }) |
| |
| func aapt2Convert(ctx android.ModuleContext, out android.WritablePath, in android.Path) { |
| ctx.Build(pctx, android.BuildParams{ |
| Rule: aapt2ConvertRule, |
| Input: in, |
| Output: out, |
| Description: "convert to proto", |
| }) |
| } |