1 /* 2 * Copyright 2007 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.tonicsystems.jarjar; 18 19 import com.android.jarjar.RemoveAndroidCompatAnnotationsJarTransformer; 20 import com.android.jarjar.StripAnnotation; 21 import com.android.jarjar.StripAnnotationsJarTransformer; 22 import com.tonicsystems.jarjar.util.EntryStruct; 23 import com.tonicsystems.jarjar.util.JarProcessor; 24 import com.tonicsystems.jarjar.util.JarProcessorChain; 25 import com.tonicsystems.jarjar.util.JarTransformerChain; 26 import com.tonicsystems.jarjar.util.RemappingClassTransformer; 27 import com.tonicsystems.jarjar.util.StandaloneJarProcessor; 28 import java.io.File; 29 import java.io.IOException; 30 import java.util.ArrayList; 31 import java.util.HashMap; 32 import java.util.HashSet; 33 import java.util.List; 34 import java.util.Map; 35 import java.util.Set; 36 37 class MainProcessor implements JarProcessor { 38 private final boolean verbose; 39 private final JarProcessorChain chain; 40 private final KeepProcessor kp; 41 private final Map<String, String> renames = new HashMap<>(); 42 43 // ANDROID-BEGIN: b/146418363 Add an Android-specific transformer to strip compat annotation MainProcessor(List<PatternElement> patterns, boolean verbose, boolean skipManifest)44 public MainProcessor(List<PatternElement> patterns, boolean verbose, boolean skipManifest) { 45 this(patterns, verbose, skipManifest, false /* removeAndroidCompatAnnotations */); 46 } 47 MainProcessor( List<PatternElement> patterns, boolean verbose, boolean skipManifest, boolean removeAndroidCompatAnnotations)48 public MainProcessor( 49 List<PatternElement> patterns, 50 boolean verbose, 51 boolean skipManifest, 52 boolean removeAndroidCompatAnnotations) { 53 // ANDROID-END: b/146418363 Add an Android-specific transformer to strip compat annotation 54 this.verbose = verbose; 55 List<Zap> zapList = new ArrayList<>(); 56 List<Rule> ruleList = new ArrayList<>(); 57 List<Keep> keepList = new ArrayList<>(); 58 // ANDROID-BEGIN: b/222743634 Strip annotations from system module stubs 59 List<StripAnnotation> stripAnnotationList = new ArrayList<StripAnnotation>(); 60 // ANDROID-END: b/222743634 Strip annotations from system module stubs 61 for (PatternElement pattern : patterns) { 62 if (pattern instanceof Zap) { 63 zapList.add((Zap) pattern); 64 } else if (pattern instanceof Rule) { 65 ruleList.add((Rule) pattern); 66 } else if (pattern instanceof Keep) { 67 keepList.add((Keep) pattern); 68 // ANDROID-BEGIN: b/222743634 Strip annotations from system module stubs 69 } else if (pattern instanceof StripAnnotation) { 70 stripAnnotationList.add((StripAnnotation) pattern); 71 } 72 // ANDROID-END: b/222743634 Strip annotations from system module stubs 73 } 74 75 PackageRemapper pr = new PackageRemapper(ruleList, verbose); 76 kp = keepList.isEmpty() ? null : new KeepProcessor(keepList); 77 78 List<JarProcessor> processors = new ArrayList<>(); 79 if (skipManifest) { 80 processors.add(ManifestProcessor.getInstance()); 81 } 82 if (kp != null) { 83 processors.add(kp); 84 } 85 processors.add(new ZapProcessor(zapList)); 86 // ANDROID-BEGIN: b/146418363 Add an Android-specific transformer to strip compat annotation 87 if (removeAndroidCompatAnnotations) 88 processors.add(new RemoveAndroidCompatAnnotationsJarTransformer(pr)); 89 // ANDROID-END: b/146418363 Add an Android-specific transformer to strip compat annotation 90 // ANDROID-BEGIN: b/222743634 Strip annotations from system module stubs 91 if (!stripAnnotationList.isEmpty()) { 92 processors.add(new StripAnnotationsJarTransformer(stripAnnotationList)); 93 } 94 // ANDROID-END: b/222743634 Strip annotations from system module stubs 95 processors.add( 96 new JarTransformerChain( 97 new RemappingClassTransformer[] {new RemappingClassTransformer(pr)})); 98 processors.add(new ResourceProcessor(pr)); 99 processors.add(new ServiceProcessor(pr)); 100 chain = new JarProcessorChain(processors.toArray(new JarProcessor[0])); 101 } 102 strip(File file)103 public void strip(File file) throws IOException { 104 if (kp == null) { 105 return; 106 } 107 Set<String> excludes = getExcludes(); 108 if (!excludes.isEmpty()) { 109 StandaloneJarProcessor.run(file, file, new ExcludeProcessor(excludes, verbose)); 110 } 111 } 112 113 /** 114 * Returns the <code>.class</code> files to delete. As well the root-parameter as the rename ones 115 * are taken in consideration, so that the concerned files are not listed in the result. 116 * 117 * @return the paths of the files in the jar-archive, including the <code>.class</code> suffix 118 */ getExcludes()119 private Set<String> getExcludes() { 120 Set<String> result = new HashSet<>(); 121 for (String exclude : kp.getExcludes()) { 122 String name = exclude + ".class"; 123 String renamed = renames.get(name); 124 result.add((renamed != null) ? renamed : name); 125 } 126 return result; 127 } 128 129 /** 130 * @param struct 131 * @return <code>true</code> if the entry is to include in the output jar 132 * @throws IOException 133 */ process(EntryStruct struct)134 public boolean process(EntryStruct struct) throws IOException { 135 String name = struct.name; 136 boolean keepIt = chain.process(struct); 137 if (keepIt) { 138 if (!name.equals(struct.name)) { 139 if (kp != null) { 140 renames.put(name, struct.name); 141 } 142 if (verbose) { 143 System.err.println("Renamed " + name + " -> " + struct.name); 144 } 145 } 146 } else { 147 if (verbose) { 148 System.err.println("Removed " + name); 149 } 150 } 151 return keepIt; 152 } 153 } 154