summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArtur Satayev <satayev@google.com>2020-04-09 19:53:35 +0100
committerArtur Satayev <satayev@google.com>2020-04-21 10:41:46 +0000
commit05bc010f959ef81af8326ab6654b871ecee57ded (patch)
tree3b6c36375f0d0e569d4b2e2de5d089bbe9e18160
parente5f0f6fc4d901a787c15ce44a2d3cdb3c3c77594 (diff)
downloadjarjar-05bc010f959ef81af8326ab6654b871ecee57ded.tar.gz
Add RemoveAndroidCompatAnnotationsJarTransformer to JarJar.android11-dev
New transformer drops given annotations from classes that jarjar repackages. Dropped annotation, as of this change, includes "UnsupportedAppUsage". Greylisted APIs removed via this change should be safe for rvc, since they were added after Q aosp. Bug: 146418363 Test: m, diff hiddenapi-flags.csv Change-Id: Ic95dce29f81fe9ce80e607150f294d7e105d1abe Merged-In: Ic95dce29f81fe9ce80e607150f294d7e105d1abe Exempt-From-Owner-Approval: cherrypick from aosp (cherry picked from commit 0ecdee5310522cd1b04d2241b612aa9a5c100167)
-rw-r--r--Android.bp5
-rw-r--r--src/android/com/android/jarjar/RemoveAndroidCompatAnnotationsJarTransformer.java120
-rw-r--r--src/main/com/tonicsystems/jarjar/Main.java6
-rw-r--r--src/main/com/tonicsystems/jarjar/MainProcessor.java15
4 files changed, 143 insertions, 3 deletions
diff --git a/Android.bp b/Android.bp
index c1340d9..ea48443 100644
--- a/Android.bp
+++ b/Android.bp
@@ -16,7 +16,10 @@ java_library_host {
name: "jarjar",
manifest: "manifest.txt",
- srcs: ["src/main/**/*.java"],
+ srcs: [
+ "src/android/**/*.java",
+ "src/main/**/*.java",
+ ],
java_resource_dirs: ["res"],
static_libs: [
diff --git a/src/android/com/android/jarjar/RemoveAndroidCompatAnnotationsJarTransformer.java b/src/android/com/android/jarjar/RemoveAndroidCompatAnnotationsJarTransformer.java
new file mode 100644
index 0000000..990e048
--- /dev/null
+++ b/src/android/com/android/jarjar/RemoveAndroidCompatAnnotationsJarTransformer.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * 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 com.android.jarjar;
+
+import com.tonicsystems.jarjar.util.JarTransformer;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.commons.Remapper;
+
+import java.util.Set;
+import java.util.function.Supplier;
+
+/**
+ * A transformer that removes annotations from repackaged classes.
+ */
+public final class RemoveAndroidCompatAnnotationsJarTransformer extends JarTransformer {
+
+ private static final Set<String> REMOVE_ANNOTATIONS = Set.of(
+ "Landroid/compat/annotation/UnsupportedAppUsage;");
+
+ private final Remapper remapper;
+
+ public RemoveAndroidCompatAnnotationsJarTransformer(Remapper remapper) {
+ this.remapper = remapper;
+ }
+
+ protected ClassVisitor transform(ClassVisitor classVisitor) {
+ return new AnnotationRemover(classVisitor);
+ }
+
+ private class AnnotationRemover extends ClassVisitor {
+
+ private boolean isClassRemapped;
+
+ AnnotationRemover(ClassVisitor cv) {
+ super(Opcodes.ASM6, cv);
+ }
+
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName,
+ String[] interfaces) {
+ String newName = remapper.map(name);
+ // On every new class header visit, remember whether the class is repackaged.
+ isClassRemapped = newName != null && !newName.equals(name);
+ super.visit(version, access, name, signature, superName, interfaces);
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
+ return visitAnnotationCommon(descriptor,
+ () -> super.visitAnnotation(descriptor, visible));
+ }
+
+ @Override
+ public FieldVisitor visitField(int access, String name, String descriptor, String signature,
+ Object value) {
+ FieldVisitor superVisitor =
+ super.visitField(access, name, descriptor, signature, value);
+ return new FieldVisitor(Opcodes.ASM6, superVisitor) {
+ @Override
+ public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
+ return visitAnnotationCommon(descriptor,
+ () -> super.visitAnnotation(descriptor, visible));
+
+ }
+ };
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String descriptor,
+ String signature, String[] exceptions) {
+ MethodVisitor superVisitor =
+ super.visitMethod(access, name, descriptor, signature, exceptions);
+ return new MethodVisitor(Opcodes.ASM6, superVisitor) {
+ @Override
+ public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
+ return visitAnnotationCommon(descriptor,
+ () -> super.visitAnnotation(descriptor, visible));
+ }
+ };
+ }
+
+ /**
+ * Create an {@link AnnotationVisitor} that removes any annotations from {@link
+ * #REMOVE_ANNOTATIONS} if the class is being repackaged.
+ *
+ * <p>For the annotations to be dropped correctly, do not visit the annotation beforehand,
+ * provide a supplier instead.
+ */
+ private AnnotationVisitor visitAnnotationCommon(String annotation,
+ Supplier<AnnotationVisitor> defaultVisitorSupplier) {
+ if (isClassRemapped && REMOVE_ANNOTATIONS.contains(annotation)) {
+ return null;
+ }
+ // Only get() the default AnnotationVisitor if the annotation is to be included.
+ // Invoking super.visitAnnotation(descriptor, visible) causes the annotation to be
+ // included in the output even if the resulting AnnotationVisitor is not returned or
+ // used.
+ return defaultVisitorSupplier.get();
+ }
+ }
+}
diff --git a/src/main/com/tonicsystems/jarjar/Main.java b/src/main/com/tonicsystems/jarjar/Main.java
index 117bdbb..1eaa3e3 100644
--- a/src/main/com/tonicsystems/jarjar/Main.java
+++ b/src/main/com/tonicsystems/jarjar/Main.java
@@ -90,7 +90,11 @@ public class Main {
List<PatternElement> rules = RulesFileParser.parse(rulesFile);
boolean verbose = Boolean.getBoolean("verbose");
boolean skipManifest = Boolean.getBoolean("skipManifest");
- MainProcessor proc = new MainProcessor(rules, verbose, skipManifest);
+ // ANDROID-BEGIN: b/146418363 Add an Android-specific transformer to strip compat annotation
+ boolean removeAndroidCompatAnnotations = Boolean.getBoolean("removeAndroidCompatAnnotations");
+ MainProcessor proc = new MainProcessor(rules, verbose, skipManifest,
+ removeAndroidCompatAnnotations);
+ // ANDROID-END: b/146418363 Add an Android-specific transformer to strip compat annotation
StandaloneJarProcessor.run(inJar, outJar, proc);
proc.strip(outJar);
}
diff --git a/src/main/com/tonicsystems/jarjar/MainProcessor.java b/src/main/com/tonicsystems/jarjar/MainProcessor.java
index de15924..2778cc5 100644
--- a/src/main/com/tonicsystems/jarjar/MainProcessor.java
+++ b/src/main/com/tonicsystems/jarjar/MainProcessor.java
@@ -21,14 +21,23 @@ import java.io.File;
import java.io.IOException;
import java.util.*;
+import com.android.jarjar.RemoveAndroidCompatAnnotationsJarTransformer;
+
class MainProcessor implements JarProcessor
{
private final boolean verbose;
private final JarProcessorChain chain;
private final KeepProcessor kp;
private final Map<String, String> renames = new HashMap<String, String>();
-
+
+ // ANDROID-BEGIN: b/146418363 Add an Android-specific transformer to strip compat annotation
public MainProcessor(List<PatternElement> patterns, boolean verbose, boolean skipManifest) {
+ this(patterns, verbose, skipManifest, false /* removeAndroidCompatAnnotations */);
+ }
+
+ public MainProcessor(List<PatternElement> patterns, boolean verbose, boolean skipManifest,
+ boolean removeAndroidCompatAnnotations) {
+ // ANDROID-END: b/146418363 Add an Android-specific transformer to strip compat annotation
this.verbose = verbose;
List<Zap> zapList = new ArrayList<Zap>();
List<Rule> ruleList = new ArrayList<Rule>();
@@ -52,6 +61,10 @@ class MainProcessor implements JarProcessor
if (kp != null)
processors.add(kp);
processors.add(new ZapProcessor(zapList));
+ // ANDROID-BEGIN: b/146418363 Add an Android-specific transformer to strip compat annotation
+ if (removeAndroidCompatAnnotations)
+ processors.add(new RemoveAndroidCompatAnnotationsJarTransformer(pr));
+ // ANDROID-END: b/146418363 Add an Android-specific transformer to strip compat annotation
processors.add(new JarTransformerChain(new RemappingClassTransformer[]{ new RemappingClassTransformer(pr) }));
processors.add(new ResourceProcessor(pr));
chain = new JarProcessorChain(processors.toArray(new JarProcessor[processors.size()]));