am 9a61270d: Merge "LayoutLib: Fix EditText rendering [DO NOT MERGE]" into klp-modular-dev
* commit '9a61270d67f654f3558b29f6b3e78c0b2fbe0178': LayoutLib: Fix EditText rendering [DO NOT MERGE]
This commit is contained in:
@@ -119,8 +119,8 @@ name.
|
|||||||
|
|
||||||
The class is then fed to RefactorClassAdapter which is like RenameClassAdapter but updates the
|
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
|
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
|
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-standard classes. An alternate implementation of
|
modified to update all references to these non-desktop classes. An alternate implementation of
|
||||||
these (com.android.tools.layoutlib.java.*) is injected.
|
these (com.android.tools.layoutlib.java.*) is injected.
|
||||||
|
|
||||||
RenameClassAdapter and RefactorClassAdapter both inherit from AbstractClassAdapter which changes the
|
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
|
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.
|
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
|
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
|
Transformation chains in the asm user guide, link in the References.) The order of execution of
|
||||||
these is:
|
these is:
|
||||||
ClassReader -> [DelegateClassAdapter] -> TransformClassAdapter -> [RenameClassAdapter] ->
|
ClassReader -> [DelegateClassAdapter] -> TransformClassAdapter -> [RenameClassAdapter] ->
|
||||||
RefactorClassAdapter -> ClassWriter
|
RefactorClassAdapter -> [ReplaceMethodCallsAdapter] -> ClassWriter
|
||||||
|
|
||||||
- Method stubs
|
- 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
|
- 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
|
injected. The implementation for these classes has been taken from Android's libcore
|
||||||
(platform/libcore/luni/src/main/java/java/...).
|
(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
|
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
|
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
|
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
|
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
|
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
|
5- Method erasure based on return type
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
@@ -63,7 +64,8 @@ public class AsmAnalyzer {
|
|||||||
private final Set<String> mExcludedClasses;
|
private final Set<String> mExcludedClasses;
|
||||||
/** Glob patterns of files to keep as is. */
|
/** Glob patterns of files to keep as is. */
|
||||||
private final String[] mIncludeFileGlobs;
|
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.
|
* Creates a new analyzer.
|
||||||
@@ -109,6 +111,7 @@ public class AsmAnalyzer {
|
|||||||
mGen.setKeep(found);
|
mGen.setKeep(found);
|
||||||
mGen.setDeps(deps);
|
mGen.setDeps(deps);
|
||||||
mGen.setCopyFiles(filesFound);
|
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
|
* @param classes The map of class name => ASM ClassReader. Class names are
|
||||||
* in the form "android.view.View".
|
* 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".
|
* in the form "android/data/dataFile".
|
||||||
*/
|
*/
|
||||||
void parseZip(List<String> jarPathList, Map<String, ClassReader> classes,
|
void parseZip(List<String> jarPathList, Map<String, ClassReader> classes,
|
||||||
@@ -143,8 +146,8 @@ public class AsmAnalyzer {
|
|||||||
String className = classReaderToClassName(cr);
|
String className = classReaderToClassName(cr);
|
||||||
classes.put(className, cr);
|
classes.put(className, cr);
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < includeFilePatterns.length; ++i) {
|
for (Pattern includeFilePattern : includeFilePatterns) {
|
||||||
if (includeFilePatterns[i].matcher(entry.getName()).matches()) {
|
if (includeFilePattern.matcher(entry.getName()).matches()) {
|
||||||
filesFound.put(entry.getName(), zip.getInputStream(entry));
|
filesFound.put(entry.getName(), zip.getInputStream(entry));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -321,6 +324,7 @@ public class AsmAnalyzer {
|
|||||||
deps, new_deps);
|
deps, new_deps);
|
||||||
|
|
||||||
for (ClassReader cr : inOutKeepClasses.values()) {
|
for (ClassReader cr : inOutKeepClasses.values()) {
|
||||||
|
visitor.setClassName(cr.getClassName());
|
||||||
cr.accept(visitor, 0 /* flags */);
|
cr.accept(visitor, 0 /* flags */);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,6 +371,8 @@ public class AsmAnalyzer {
|
|||||||
/** New classes to keep as-is found by this visitor. */
|
/** New classes to keep as-is found by this visitor. */
|
||||||
private final Map<String, ClassReader> mOutKeep;
|
private final Map<String, ClassReader> mOutKeep;
|
||||||
|
|
||||||
|
private String mClassName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new visitor that will find all the dependencies for the visited class.
|
* 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.
|
* Types which are already in the zipClasses, keepClasses or inDeps are not marked.
|
||||||
@@ -390,6 +396,10 @@ public class AsmAnalyzer {
|
|||||||
mOutDeps = outDeps;
|
mOutDeps = outDeps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setClassName(String className) {
|
||||||
|
mClassName = className;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Considers the given class name as a dependency.
|
* Considers the given class name as a dependency.
|
||||||
* If it does, add to the mOutDeps map.
|
* If it does, add to the mOutDeps map.
|
||||||
@@ -429,7 +439,7 @@ public class AsmAnalyzer {
|
|||||||
// - android classes are added to dependencies
|
// - android classes are added to dependencies
|
||||||
// - non-android classes are added to the list of classes to keep as-is (they don't need
|
// - non-android classes are added to the list of classes to keep as-is (they don't need
|
||||||
// to be stubbed).
|
// to be stubbed).
|
||||||
if (className.indexOf("android") >= 0) { // TODO make configurable
|
if (className.contains("android")) { // TODO make configurable
|
||||||
mOutDeps.put(className, cr);
|
mOutDeps.put(className, cr);
|
||||||
} else {
|
} else {
|
||||||
mOutKeep.put(className, cr);
|
mOutKeep.put(className, cr);
|
||||||
@@ -594,7 +604,7 @@ public class AsmAnalyzer {
|
|||||||
// type and exceptions do not use generic types.
|
// type and exceptions do not use generic types.
|
||||||
considerSignature(signature);
|
considerSignature(signature);
|
||||||
|
|
||||||
return new MyMethodVisitor();
|
return new MyMethodVisitor(mClassName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -614,8 +624,11 @@ public class AsmAnalyzer {
|
|||||||
|
|
||||||
private class MyMethodVisitor extends MethodVisitor {
|
private class MyMethodVisitor extends MethodVisitor {
|
||||||
|
|
||||||
public MyMethodVisitor() {
|
private String mOwnerClass;
|
||||||
|
|
||||||
|
public MyMethodVisitor(String ownerClass) {
|
||||||
super(Opcodes.ASM4);
|
super(Opcodes.ASM4);
|
||||||
|
mOwnerClass = ownerClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -709,6 +722,13 @@ public class AsmAnalyzer {
|
|||||||
considerName(owner);
|
considerName(owner);
|
||||||
// desc is the method's descriptor (see Type).
|
// desc is the method's descriptor (see Type).
|
||||||
considerDesc(desc);
|
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
|
// instruction multianewarray, whatever that is
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import org.objectweb.asm.ClassVisitor;
|
|||||||
import org.objectweb.asm.ClassWriter;
|
import org.objectweb.asm.ClassWriter;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@@ -55,6 +54,8 @@ public class AsmGenerator {
|
|||||||
private Map<String, ClassReader> mDeps;
|
private Map<String, ClassReader> mDeps;
|
||||||
/** All files that are to be copied as-is. */
|
/** All files that are to be copied as-is. */
|
||||||
private Map<String, InputStream> mCopyFiles;
|
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. */
|
/** Counter of number of classes renamed during transform. */
|
||||||
private int mRenameCount;
|
private int mRenameCount;
|
||||||
/** FQCN Names of the classes to rename: map old-FQCN => new-FQCN */
|
/** FQCN Names of the classes to rename: map old-FQCN => new-FQCN */
|
||||||
@@ -133,7 +134,7 @@ public class AsmGenerator {
|
|||||||
assert i + 1 < n;
|
assert i + 1 < n;
|
||||||
String oldFqcn = binaryToInternalClassName(refactorClasses[i]);
|
String oldFqcn = binaryToInternalClassName(refactorClasses[i]);
|
||||||
String newFqcn = binaryToInternalClassName(refactorClasses[i + 1]);
|
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.
|
// create the map of renamed class -> return type of method to delete.
|
||||||
@@ -203,23 +204,12 @@ public class AsmGenerator {
|
|||||||
mCopyFiles = copyFiles;
|
mCopyFiles = copyFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the map of classes to output as-is, except if they have native methods */
|
public void setRewriteMethodCallClasses(Set<String> rewriteMethodCallClasses) {
|
||||||
public Map<String, ClassReader> getKeep() {
|
mReplaceMethodCallsClasses = rewriteMethodCallClasses;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Generates the final JAR */
|
/** Generates the final JAR */
|
||||||
public void generate() throws FileNotFoundException, IOException {
|
public void generate() throws IOException {
|
||||||
TreeMap<String, byte[]> all = new TreeMap<String, byte[]>();
|
TreeMap<String, byte[]> all = new TreeMap<String, byte[]>();
|
||||||
|
|
||||||
for (Class<?> clazz : mInjectClasses) {
|
for (Class<?> clazz : mInjectClasses) {
|
||||||
@@ -329,14 +319,14 @@ public class AsmGenerator {
|
|||||||
|
|
||||||
String newName = transformName(className);
|
String newName = transformName(className);
|
||||||
// transformName returns its input argument if there's no need to rename the class
|
// transformName returns its input argument if there's no need to rename the class
|
||||||
if (newName != className) {
|
if (!newName.equals(className)) {
|
||||||
mRenameCount++;
|
mRenameCount++;
|
||||||
// This class is being renamed, so remove it from the list of classes not renamed.
|
// This class is being renamed, so remove it from the list of classes not renamed.
|
||||||
mClassesNotRenamed.remove(className);
|
mClassesNotRenamed.remove(className);
|
||||||
}
|
}
|
||||||
|
|
||||||
mLog.debug("Transform %s%s%s%s", className,
|
mLog.debug("Transform %s%s%s%s", className,
|
||||||
newName == className ? "" : " (renamed to " + newName + ")",
|
newName.equals(className) ? "" : " (renamed to " + newName + ")",
|
||||||
hasNativeMethods ? " -- has natives" : "",
|
hasNativeMethods ? " -- has natives" : "",
|
||||||
stubNativesOnly ? " -- stub natives only" : "");
|
stubNativesOnly ? " -- stub natives only" : "");
|
||||||
|
|
||||||
@@ -344,8 +334,14 @@ public class AsmGenerator {
|
|||||||
// original class reader.
|
// original class reader.
|
||||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
||||||
|
|
||||||
ClassVisitor cv = new RefactorClassAdapter(cw, mRefactorClasses);
|
ClassVisitor cv = cw;
|
||||||
if (newName != className) {
|
|
||||||
|
if (mReplaceMethodCallsClasses.contains(className)) {
|
||||||
|
cv = new ReplaceMethodCallsAdapter(cv);
|
||||||
|
}
|
||||||
|
|
||||||
|
cv = new RefactorClassAdapter(cv, mRefactorClasses);
|
||||||
|
if (!newName.equals(className)) {
|
||||||
cv = new RenameClassAdapter(cv, className, newName);
|
cv = new RenameClassAdapter(cv, className, newName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -193,8 +193,7 @@ public class Main {
|
|||||||
private static boolean processArgs(Log log, String[] args,
|
private static boolean processArgs(Log log, String[] args,
|
||||||
ArrayList<String> osJarPath, String[] osDestJar) {
|
ArrayList<String> osJarPath, String[] osDestJar) {
|
||||||
boolean needs_dest = true;
|
boolean needs_dest = true;
|
||||||
for (int i = 0; i < args.length; i++) {
|
for (String s : args) {
|
||||||
String s = args[i];
|
|
||||||
if (s.equals("-v")) {
|
if (s.equals("-v")) {
|
||||||
log.setVerbose(true);
|
log.setVerbose(true);
|
||||||
} else if (s.equals("-p")) {
|
} else if (s.equals("-p")) {
|
||||||
@@ -212,7 +211,7 @@ public class Main {
|
|||||||
osJarPath.add(s);
|
osJarPath.add(s);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.error("Unknow argument: %s", s);
|
log.error("Unknown argument: %s", s);
|
||||||
return false;
|
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