Merge "LayoutLib: Fix EditText rendering [DO NOT MERGE]" into klp-modular-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
9a61270d67
@@ -119,8 +119,8 @@ name.
|
||||
|
||||
The class is then fed to RefactorClassAdapter which is like RenameClassAdapter but updates the
|
||||
references in all classes. This is used to update the references of classes in the java package that
|
||||
were added in the Dalvik VM but are not a part of the standard JVM. The existing classes are
|
||||
modified to update all references to these non-standard classes. An alternate implementation of
|
||||
were added in the Dalvik VM but are not a part of the Desktop VM. The existing classes are
|
||||
modified to update all references to these non-desktop classes. An alternate implementation of
|
||||
these (com.android.tools.layoutlib.java.*) is injected.
|
||||
|
||||
RenameClassAdapter and RefactorClassAdapter both inherit from AbstractClassAdapter which changes the
|
||||
@@ -130,11 +130,15 @@ the StackMapTable correctly and Java 7 VM enforces that classes with version gre
|
||||
valid StackMapTable. As a side benefit of this, we can continue to support Java 6 because Java 7 on
|
||||
Mac has horrible font rendering support.
|
||||
|
||||
ReplaceMethodCallsAdapter replaces calls to certain methods. Currently, it only rewrites calls to
|
||||
java.lang.System.arraycopy([CI[CII)V, which is not part of the Desktop VM to call the more general
|
||||
method java.lang.System.arraycopy(Ljava/lang/Object;ILjava/lang/Object;II)V.
|
||||
|
||||
The ClassAdapters are chained together to achieve the desired output. (Look at section 2.2.7
|
||||
Transformation chains in the asm user guide, link in the References.) The order of execution of
|
||||
these is:
|
||||
ClassReader -> [DelegateClassAdapter] -> TransformClassAdapter -> [RenameClassAdapter] ->
|
||||
RefactorClassAdapter -> ClassWriter
|
||||
RefactorClassAdapter -> [ReplaceMethodCallsAdapter] -> ClassWriter
|
||||
|
||||
- Method stubs
|
||||
--------------
|
||||
@@ -169,7 +173,7 @@ This is the easiest: we currently inject the following classes:
|
||||
- AutoCloseable and Objects are part of Java 7. To enable us to still run on Java 6, new classes are
|
||||
injected. The implementation for these classes has been taken from Android's libcore
|
||||
(platform/libcore/luni/src/main/java/java/...).
|
||||
- Charsets, IntegralToString and UnsafeByteSequence are not part of the standard JAVA VM. They are
|
||||
- Charsets, IntegralToString and UnsafeByteSequence are not part of the Desktop VM. They are
|
||||
added to the Dalvik VM for performance reasons. An implementation that is very close to the
|
||||
original (which is at platform/libcore/luni/src/main/java/...) is injected. Since these classees
|
||||
were in part of the java package, where we can't inject classes, all references to these have been
|
||||
@@ -209,7 +213,7 @@ This won't rename/replace the inner static methods of a given class.
|
||||
|
||||
This is very similar to the Renaming classes except that it also updates the reference in all
|
||||
classes. This is done for classes which are added to the Dalvik VM for performance reasons but are
|
||||
not present in the Standard Java VM. An implementation for these classes is also injected.
|
||||
not present in the Desktop VM. An implementation for these classes is also injected.
|
||||
|
||||
|
||||
5- Method erasure based on return type
|
||||
|
||||
@@ -32,6 +32,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
@@ -63,7 +64,8 @@ public class AsmAnalyzer {
|
||||
private final Set<String> mExcludedClasses;
|
||||
/** Glob patterns of files to keep as is. */
|
||||
private final String[] mIncludeFileGlobs;
|
||||
/** Copy these files into the output as is. */
|
||||
/** Internal names of classes that contain method calls that need to be rewritten. */
|
||||
private final Set<String> mReplaceMethodCallClasses = new HashSet<String>();
|
||||
|
||||
/**
|
||||
* Creates a new analyzer.
|
||||
@@ -109,6 +111,7 @@ public class AsmAnalyzer {
|
||||
mGen.setKeep(found);
|
||||
mGen.setDeps(deps);
|
||||
mGen.setCopyFiles(filesFound);
|
||||
mGen.setRewriteMethodCallClasses(mReplaceMethodCallClasses);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +121,7 @@ public class AsmAnalyzer {
|
||||
*
|
||||
* @param classes The map of class name => ASM ClassReader. Class names are
|
||||
* in the form "android.view.View".
|
||||
* @param fileFound The map of file name => InputStream. The file name is
|
||||
* @param filesFound The map of file name => InputStream. The file name is
|
||||
* in the form "android/data/dataFile".
|
||||
*/
|
||||
void parseZip(List<String> jarPathList, Map<String, ClassReader> classes,
|
||||
@@ -143,8 +146,8 @@ public class AsmAnalyzer {
|
||||
String className = classReaderToClassName(cr);
|
||||
classes.put(className, cr);
|
||||
} else {
|
||||
for (int i = 0; i < includeFilePatterns.length; ++i) {
|
||||
if (includeFilePatterns[i].matcher(entry.getName()).matches()) {
|
||||
for (Pattern includeFilePattern : includeFilePatterns) {
|
||||
if (includeFilePattern.matcher(entry.getName()).matches()) {
|
||||
filesFound.put(entry.getName(), zip.getInputStream(entry));
|
||||
break;
|
||||
}
|
||||
@@ -321,6 +324,7 @@ public class AsmAnalyzer {
|
||||
deps, new_deps);
|
||||
|
||||
for (ClassReader cr : inOutKeepClasses.values()) {
|
||||
visitor.setClassName(cr.getClassName());
|
||||
cr.accept(visitor, 0 /* flags */);
|
||||
}
|
||||
|
||||
@@ -367,6 +371,8 @@ public class AsmAnalyzer {
|
||||
/** New classes to keep as-is found by this visitor. */
|
||||
private final Map<String, ClassReader> mOutKeep;
|
||||
|
||||
private String mClassName;
|
||||
|
||||
/**
|
||||
* Creates a new visitor that will find all the dependencies for the visited class.
|
||||
* Types which are already in the zipClasses, keepClasses or inDeps are not marked.
|
||||
@@ -390,6 +396,10 @@ public class AsmAnalyzer {
|
||||
mOutDeps = outDeps;
|
||||
}
|
||||
|
||||
private void setClassName(String className) {
|
||||
mClassName = className;
|
||||
}
|
||||
|
||||
/**
|
||||
* Considers the given class name as a dependency.
|
||||
* If it does, add to the mOutDeps map.
|
||||
@@ -429,7 +439,7 @@ public class AsmAnalyzer {
|
||||
// - android classes are added to dependencies
|
||||
// - non-android classes are added to the list of classes to keep as-is (they don't need
|
||||
// to be stubbed).
|
||||
if (className.indexOf("android") >= 0) { // TODO make configurable
|
||||
if (className.contains("android")) { // TODO make configurable
|
||||
mOutDeps.put(className, cr);
|
||||
} else {
|
||||
mOutKeep.put(className, cr);
|
||||
@@ -594,7 +604,7 @@ public class AsmAnalyzer {
|
||||
// type and exceptions do not use generic types.
|
||||
considerSignature(signature);
|
||||
|
||||
return new MyMethodVisitor();
|
||||
return new MyMethodVisitor(mClassName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -614,8 +624,11 @@ public class AsmAnalyzer {
|
||||
|
||||
private class MyMethodVisitor extends MethodVisitor {
|
||||
|
||||
public MyMethodVisitor() {
|
||||
private String mOwnerClass;
|
||||
|
||||
public MyMethodVisitor(String ownerClass) {
|
||||
super(Opcodes.ASM4);
|
||||
mOwnerClass = ownerClass;
|
||||
}
|
||||
|
||||
|
||||
@@ -709,6 +722,13 @@ public class AsmAnalyzer {
|
||||
considerName(owner);
|
||||
// desc is the method's descriptor (see Type).
|
||||
considerDesc(desc);
|
||||
|
||||
|
||||
// Check if method is java.lang.System.arrayCopy([CI[CII)V
|
||||
if (owner.equals("java/lang/System") && name.equals("arraycopy")
|
||||
&& desc.equals("([CI[CII)V")) {
|
||||
mReplaceMethodCallClasses.add(mOwnerClass);
|
||||
}
|
||||
}
|
||||
|
||||
// instruction multianewarray, whatever that is
|
||||
|
||||
@@ -21,7 +21,6 @@ import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -55,6 +54,8 @@ public class AsmGenerator {
|
||||
private Map<String, ClassReader> mDeps;
|
||||
/** All files that are to be copied as-is. */
|
||||
private Map<String, InputStream> mCopyFiles;
|
||||
/** All classes where certain method calls need to be rewritten. */
|
||||
private Set<String> mReplaceMethodCallsClasses;
|
||||
/** Counter of number of classes renamed during transform. */
|
||||
private int mRenameCount;
|
||||
/** FQCN Names of the classes to rename: map old-FQCN => new-FQCN */
|
||||
@@ -133,7 +134,7 @@ public class AsmGenerator {
|
||||
assert i + 1 < n;
|
||||
String oldFqcn = binaryToInternalClassName(refactorClasses[i]);
|
||||
String newFqcn = binaryToInternalClassName(refactorClasses[i + 1]);
|
||||
mRefactorClasses.put(oldFqcn, newFqcn);;
|
||||
mRefactorClasses.put(oldFqcn, newFqcn);
|
||||
}
|
||||
|
||||
// create the map of renamed class -> return type of method to delete.
|
||||
@@ -203,23 +204,12 @@ public class AsmGenerator {
|
||||
mCopyFiles = copyFiles;
|
||||
}
|
||||
|
||||
/** Gets the map of classes to output as-is, except if they have native methods */
|
||||
public Map<String, ClassReader> getKeep() {
|
||||
return mKeep;
|
||||
}
|
||||
|
||||
/** Gets the map of dependencies that must be completely stubbed */
|
||||
public Map<String, ClassReader> getDeps() {
|
||||
return mDeps;
|
||||
}
|
||||
|
||||
/** Gets the map of files to output as-is. */
|
||||
public Map<String, InputStream> getCopyFiles() {
|
||||
return mCopyFiles;
|
||||
public void setRewriteMethodCallClasses(Set<String> rewriteMethodCallClasses) {
|
||||
mReplaceMethodCallsClasses = rewriteMethodCallClasses;
|
||||
}
|
||||
|
||||
/** Generates the final JAR */
|
||||
public void generate() throws FileNotFoundException, IOException {
|
||||
public void generate() throws IOException {
|
||||
TreeMap<String, byte[]> all = new TreeMap<String, byte[]>();
|
||||
|
||||
for (Class<?> clazz : mInjectClasses) {
|
||||
@@ -329,14 +319,14 @@ public class AsmGenerator {
|
||||
|
||||
String newName = transformName(className);
|
||||
// transformName returns its input argument if there's no need to rename the class
|
||||
if (newName != className) {
|
||||
if (!newName.equals(className)) {
|
||||
mRenameCount++;
|
||||
// This class is being renamed, so remove it from the list of classes not renamed.
|
||||
mClassesNotRenamed.remove(className);
|
||||
}
|
||||
|
||||
mLog.debug("Transform %s%s%s%s", className,
|
||||
newName == className ? "" : " (renamed to " + newName + ")",
|
||||
newName.equals(className) ? "" : " (renamed to " + newName + ")",
|
||||
hasNativeMethods ? " -- has natives" : "",
|
||||
stubNativesOnly ? " -- stub natives only" : "");
|
||||
|
||||
@@ -344,8 +334,14 @@ public class AsmGenerator {
|
||||
// original class reader.
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
||||
|
||||
ClassVisitor cv = new RefactorClassAdapter(cw, mRefactorClasses);
|
||||
if (newName != className) {
|
||||
ClassVisitor cv = cw;
|
||||
|
||||
if (mReplaceMethodCallsClasses.contains(className)) {
|
||||
cv = new ReplaceMethodCallsAdapter(cv);
|
||||
}
|
||||
|
||||
cv = new RefactorClassAdapter(cv, mRefactorClasses);
|
||||
if (!newName.equals(className)) {
|
||||
cv = new RenameClassAdapter(cv, className, newName);
|
||||
}
|
||||
|
||||
|
||||
@@ -193,8 +193,7 @@ public class Main {
|
||||
private static boolean processArgs(Log log, String[] args,
|
||||
ArrayList<String> osJarPath, String[] osDestJar) {
|
||||
boolean needs_dest = true;
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
String s = args[i];
|
||||
for (String s : args) {
|
||||
if (s.equals("-v")) {
|
||||
log.setVerbose(true);
|
||||
} else if (s.equals("-p")) {
|
||||
@@ -212,7 +211,7 @@ public class Main {
|
||||
osJarPath.add(s);
|
||||
}
|
||||
} else {
|
||||
log.error("Unknow argument: %s", s);
|
||||
log.error("Unknown argument: %s", s);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.tools.layoutlib.create;
|
||||
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
/**
|
||||
* Replaces calls to certain methods that do not exist in the Desktop VM.
|
||||
*/
|
||||
public class ReplaceMethodCallsAdapter extends ClassVisitor {
|
||||
public ReplaceMethodCallsAdapter(ClassVisitor cv) {
|
||||
super(Opcodes.ASM4, cv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature,
|
||||
String[] exceptions) {
|
||||
return new MyMethodVisitor(super.visitMethod(access, name, desc, signature, exceptions));
|
||||
}
|
||||
|
||||
private class MyMethodVisitor extends MethodVisitor {
|
||||
|
||||
public MyMethodVisitor(MethodVisitor mv) {
|
||||
super(Opcodes.ASM4, mv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
|
||||
// Check if method is java.lang.System.arrayCopy([CI[CII)V
|
||||
if (owner.equals("java/lang/System") && name.equals("arraycopy")
|
||||
&& desc.equals("([CI[CII)V")) {
|
||||
desc = "(Ljava/lang/Object;ILjava/lang/Object;II)V";
|
||||
}
|
||||
super.visitMethodInsn(opcode, owner, name, desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user