/** * Creates a generating action for {@code outApk} that builds the APK specified. * * <p>If {@code signingKey} is not null, the apk will be signed with it using the V1 signature * scheme. */ Action[] buildApk(RuleContext ruleContext, Artifact outApk, Artifact signingKey, String message) { SpawnAction.Builder actionBuilder = new SpawnAction.Builder() .setExecutable(AndroidSdkProvider.fromRuleContext(ruleContext).getApkBuilder()) .setProgressMessage(message) .setMnemonic("AndroidApkBuilder") .addOutputArgument(outApk); if (javaResourceZip != null) { actionBuilder.addArgument("-rj").addInputArgument(javaResourceZip); } Artifact nativeSymlinks = nativeLibs.createApkBuilderSymlinks(ruleContext); if (nativeSymlinks != null) { PathFragment nativeSymlinksDir = nativeSymlinks.getExecPath().getParentDirectory(); actionBuilder .addInputManifest(nativeSymlinks, nativeSymlinksDir) .addInput(nativeSymlinks) .addInputs(nativeLibs.getAllNativeLibs()) .addArgument("-nf") // If the native libs are "foo/bar/x86/foo.so", we need to pass "foo/bar" here .addArgument(nativeSymlinksDir.getPathString()); } if (nativeLibs.getName() != null) { actionBuilder .addArgument("-rf") .addArgument(nativeLibs.getName().getExecPath().getParentDirectory().getPathString()) .addInput(nativeLibs.getName()); } if (javaResourceFile != null) { actionBuilder .addArgument("-rf") .addArgument((javaResourceFile.getExecPath().getParentDirectory().getPathString())) .addInput(javaResourceFile); } if (signingKey == null) { actionBuilder.addArgument("-u"); } else { actionBuilder.addArgument("-ks").addArgument(signingKey.getExecPathString()); actionBuilder.addInput(signingKey); } actionBuilder.addArgument("-z").addInputArgument(resourceApk); if (classesDex != null) { actionBuilder .addArgument(classesDex.getFilename().endsWith(".dex") ? "-f" : "-z") .addInputArgument(classesDex); } return actionBuilder.build(ruleContext); }
/** Uses the zipalign tool to align the zip boundaries for uncompressed resources by 4 bytes. */ Action[] zipalignApk(RuleContext ruleContext, Artifact inputApk, Artifact zipAlignedApk) { return new SpawnAction.Builder() .addInput(inputApk) .addOutput(zipAlignedApk) .setExecutable(AndroidSdkProvider.fromRuleContext(ruleContext).getZipalign()) .addArgument("4") .addInputArgument(inputApk) .addOutputArgument(zipAlignedApk) .setProgressMessage("Zipaligning " + apkName) .setMnemonic("AndroidZipAlign") .build(ruleContext); }
/** * Creates an action that converts {@code jarToDex} to a dex file. The output will be stored in * the {@link com.google.devtools.build.lib.actions.Artifact} {@code dxJar}. */ public static void createDexAction( RuleContext ruleContext, Artifact jarToDex, Artifact classesDex, List<String> dexOptions, boolean multidex, Artifact mainDexList) { List<String> args = new ArrayList<>(); args.add("--dex"); // Add --no-locals to coverage builds. Older coverage tools don't correctly preserve local // variable information in stack frame maps that are required since Java 7, so to avoid runtime // errors we just don't add local variable info in the first place. This may no longer be // necessary, however, as long as we use a coverage tool that generates stack frame maps. if (ruleContext.getConfiguration().isCodeCoverageEnabled()) { args.add("--no-locals"); // TODO(bazel-team): Is this still needed? } // Multithreaded dex does not work when using --multi-dex. if (!multidex) { // Multithreaded dex tends to run faster, but only up to about 5 threads (at which point the // law of diminishing returns kicks in). This was determined experimentally, with 5-thread dex // performing about 25% faster than 1-thread dex. args.add("--num-threads=5"); } args.addAll(dexOptions); if (multidex) { args.add("--multi-dex"); if (mainDexList != null) { args.add("--main-dex-list=" + mainDexList.getExecPathString()); } } args.add("--output=" + classesDex.getExecPathString()); args.add(jarToDex.getExecPathString()); SpawnAction.Builder builder = new SpawnAction.Builder() .setExecutable(AndroidSdkProvider.fromRuleContext(ruleContext).getDx()) .addInput(jarToDex) .addOutput(classesDex) .addArguments(args) .setProgressMessage("Converting " + jarToDex.getExecPathString() + " to dex format") .setMnemonic("AndroidDexer") .setResources(ResourceSet.createWithRamCpuIo(4096.0, 5.0, 0.0)); if (mainDexList != null) { builder.addInput(mainDexList); } ruleContext.registerAction(builder.build(ruleContext)); }
/** * Signs an APK using the ApkSignerTool. Supports both the jar signing scheme(v1) and the apk * signing scheme v2. Note that zip alignment is preserved by this step. Furthermore, zip * alignment cannot be performed after v2 signing without invalidating the signature. */ private Action[] signApk( RuleContext ruleContext, Artifact signingKey, Artifact unsignedApk, Artifact signedAndZipalignedApk) { return new SpawnAction.Builder() .setExecutable(AndroidSdkProvider.fromRuleContext(ruleContext).getApkSigner()) .setProgressMessage("Signing and zipaligning " + apkName) .setMnemonic("ApkSignerTool") .addArgument("sign") .addArgument("--ks") .addInputArgument(signingKey) .addArguments("--ks-pass", "pass:android") .addArguments("--v1-signing-enabled", Boolean.toString(signingMethod.signV1())) .addArguments("--v1-signer-name", "CERT") .addArguments("--v2-signing-enabled", Boolean.toString(signingMethod.signV2())) .addArgument("--out") .addOutputArgument(signedAndZipalignedApk) .addInputArgument(unsignedApk) .build(ruleContext); }
JackCompilationHelper initJack(JavaTargetAttributes attributes) throws InterruptedException { AndroidSdkProvider sdk = AndroidSdkProvider.fromRuleContext(ruleContext); return new JackCompilationHelper.Builder() // blaze infrastructure .setRuleContext(ruleContext) // configuration .setOutputArtifact( ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_LIBRARY_JACK_FILE)) // tools .setJackBinary(sdk.getJack()) .setJillBinary(sdk.getJill()) .setResourceExtractorBinary(sdk.getResourceExtractor()) .setJackBaseClasspath(sdk.getAndroidBaseClasspathForJack()) // sources .addJavaSources(attributes.getSourceFiles()) .addSourceJars(attributes.getSourceJars()) .addResources(attributes.getResources()) .addProcessorNames(attributes.getProcessorNames()) .addProcessorClasspathJars(attributes.getProcessorPath()) .addExports(JavaCommon.getExports(ruleContext)) .addClasspathDeps(javaCommon.targetsTreatedAsDeps(ClasspathType.COMPILE_ONLY)) .addRuntimeDeps(javaCommon.targetsTreatedAsDeps(ClasspathType.RUNTIME_ONLY)) .build(); }
public JavaTargetAttributes init( JavaSemantics javaSemantics, AndroidSemantics androidSemantics, ResourceApk resourceApk, boolean addCoverageSupport, boolean collectJavaCompilationArgs) throws InterruptedException { classJar = ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_LIBRARY_CLASS_JAR); idlHelper = new AndroidIdlHelper(ruleContext, classJar); JavaTargetAttributes.Builder attributes = javaCommon .initCommon( idlHelper.getIdlGeneratedJavaSources(), androidSemantics.getJavacArguments()) .setBootClassPath( ImmutableList.of(AndroidSdkProvider.fromRuleContext(ruleContext).getAndroidJar())); JavaCompilationArtifacts.Builder artifactsBuilder = new JavaCompilationArtifacts.Builder(); ImmutableList.Builder<Artifact> jarsProducedForRuntime = ImmutableList.builder(); NestedSetBuilder<Artifact> filesBuilder = NestedSetBuilder.<Artifact>stableOrder(); Artifact resourcesJar = resourceApk.getResourceJavaSrcJar(); if (resourcesJar != null) { filesBuilder.add(resourcesJar); compileResources( javaSemantics, resourcesJar, artifactsBuilder, attributes, filesBuilder, jarsProducedForRuntime); if (resourceApk.isLegacy()) { // Repackages the R.java for each dependency package and places the resultant jars before // the dependency libraries to ensure that the generated resource ids are correct. createJarJarActions( attributes, jarsProducedForRuntime, resourceApk.getResourceDependencies().getResources(), resourceApk.getPrimaryResource().getJavaPackage(), resourceClassJar); } } JavaCompilationHelper helper = initAttributes(attributes, javaSemantics); if (ruleContext.hasErrors()) { return null; } if (addCoverageSupport) { androidSemantics.addCoverageSupport( ruleContext, this, javaSemantics, true, attributes, artifactsBuilder); if (ruleContext.hasErrors()) { return null; } } jackCompilationHelper = initJack(helper.getAttributes()); if (ruleContext.hasErrors()) { return null; } initJava(helper, artifactsBuilder, collectJavaCompilationArgs, filesBuilder); if (ruleContext.hasErrors()) { return null; } this.jarsProducedForRuntime = jarsProducedForRuntime.add(classJar).build(); return helper.getAttributes(); }