diff options
20 files changed, 371 insertions, 360 deletions
diff --git a/README.version b/README.version index ed8d2a6..3e8229a 100644 --- a/README.version +++ b/README.version @@ -1,5 +1,5 @@ URL: https://github.com/linkedin/dexmaker/ -Version: main (65749b3da4b058c0b322b2adbf3e8f70488f8d8b) +Version: master (8ff85edb2793cc1e0f6a93c67b127cb9c43d924e) License: Apache 2.0 Description: Dexmaker is a Java-language API for doing compile time or runtime code generation targeting the Dalvik VM. Unlike cglib or ASM, this library creates Dalvik .dex files instead of Java .class files. @@ -11,6 +11,10 @@ It includes a stock code generator for class proxies. If you just want to do AOP Local Modifications: Add ability to run dexmaker tests from within the source tree (I1b146841099b54f64d4a7dfe743b88717793619a) Allow to share classloader via dexmaker.share_classloader system property (I324cddd644610eef811c620a1fccf6a24b2b9406) + Do not read Build.VERSION to allow non-standard Android distributions (Ia8c4ba4c82cd6f193c565f1bfe48faffc4aac08f) Temporarily ignore failing test (Ibf7b6c2eb05c5ff83f0817f9224369e20c0b775d) + Restrict InspectClass to current thread. (Ic62951ff81bed60ac7512455fad65210e4b728a9, need upstreaming) Exclude Stress#mockALot from presubmit (Ic9a2927ffa07924bd759429e31c56dc1b71a826c) Extend timeout of Stress#mockALot() for CTS. (Iad30a8cb07b38054b490b7006d11908fc752a024) + Update to Mockito 2.25.0 and impl InlineMockMaker (29a8674036d345e4ec8635b1d38d8b2a4fe91980a, need upstreaming) + guessPath not to depend on the first level of app directory (I66f1d7036949c2f05e6d37bc270d47f8e77e51c1, need upstreaming) diff --git a/dexmaker-mockito-inline-dispatcher/build.gradle b/dexmaker-mockito-inline-dispatcher/build.gradle index b811904..73a93f3 100644 --- a/dexmaker-mockito-inline-dispatcher/build.gradle +++ b/dexmaker-mockito-inline-dispatcher/build.gradle @@ -1,12 +1,18 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 32 + compileSdkVersion 28 + buildToolsVersion '28.0.3' defaultConfig { applicationId 'com.android.dexmaker.mockito.inline.dispatcher' minSdkVersion 28 - targetSdkVersion 32 + targetSdkVersion 28 versionName VERSION_NAME } } + +repositories { + jcenter() + google() +} diff --git a/dexmaker-mockito-inline-extended-tests/build.gradle b/dexmaker-mockito-inline-extended-tests/build.gradle index e5dc213..b5664f2 100644 --- a/dexmaker-mockito-inline-extended-tests/build.gradle +++ b/dexmaker-mockito-inline-extended-tests/build.gradle @@ -1,7 +1,20 @@ +buildscript { + repositories { + maven { + url "https://plugins.gradle.org/m2/" + } + } + dependencies { + classpath "net.ltgt.gradle:gradle-errorprone-plugin:0.0.13" + } +} + +apply plugin: "net.ltgt.errorprone" apply plugin: 'com.android.library' android { - compileSdkVersion 32 + compileSdkVersion 28 + buildToolsVersion '28.0.3' android { lintOptions { @@ -11,7 +24,8 @@ android { defaultConfig { minSdkVersion 28 - targetSdkVersion 32 + targetSdkVersion 28 + versionName VERSION_NAME testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' } @@ -22,14 +36,19 @@ android { } } +repositories { + jcenter() + google() +} + dependencies { implementation project(':dexmaker-mockito-inline-tests') compileOnly project(':dexmaker-mockito-inline-extended') androidTestImplementation project(':dexmaker-mockito-inline-extended') - implementation 'junit:junit:4.13.2' - implementation 'androidx.test:runner:1.4.0' - implementation 'androidx.test:rules:1.4.0' + implementation 'junit:junit:4.12' + implementation 'com.android.support.test:runner:1.0.2' + implementation 'com.android.support.test:rules:1.0.2' - api 'org.mockito:mockito-core:2.28.2', { exclude group: 'net.bytebuddy' } + api 'org.mockito:mockito-core:2.25.0', { exclude group: 'net.bytebuddy' } } diff --git a/dexmaker-mockito-inline-extended-tests/src/main/java/com/android/dx/mockito/inline/extended/tests/StaticMockitoSession.java b/dexmaker-mockito-inline-extended-tests/src/main/java/com/android/dx/mockito/inline/extended/tests/StaticMockitoSession.java index eff42ab..7c7941b 100644 --- a/dexmaker-mockito-inline-extended-tests/src/main/java/com/android/dx/mockito/inline/extended/tests/StaticMockitoSession.java +++ b/dexmaker-mockito-inline-extended-tests/src/main/java/com/android/dx/mockito/inline/extended/tests/StaticMockitoSession.java @@ -16,7 +16,6 @@ package com.android.dx.mockito.inline.extended.tests; -import android.app.PendingIntent; import android.content.ContentResolver; import android.provider.Settings; @@ -34,9 +33,8 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; public class StaticMockitoSession { - @Test - public void strictUnnecessaryStubbing() { + public void strictUnnecessaryStubbing() throws Exception { MockitoSession session = mockitoSession().spyStatic(Settings.Global.class).startMocking(); // Set up unnecessary stubbing @@ -53,7 +51,7 @@ public class StaticMockitoSession { } @Test - public void lenientUnnecessaryStubbing() { + public void lenientUnnecessaryStubbing() throws Exception { MockitoSession session = mockitoSession().strictness(Strictness.LENIENT) .spyStatic(Settings.Global.class).startMocking(); @@ -63,22 +61,4 @@ public class StaticMockitoSession { session.finishMocking(); } - - @Test - public void spyStatic() { - mockitoSession() - .initMocks(this) - .spyStatic(PendingIntent.class) - .startMocking() - .finishMocking(); - } - - @Test - public void mockStatic() { - mockitoSession() - .initMocks(this) - .mockStatic(PendingIntent.class) - .startMocking() - .finishMocking(); - } } diff --git a/dexmaker-mockito-inline-extended/build.gradle b/dexmaker-mockito-inline-extended/build.gradle index b02cd37..fee152e 100644 --- a/dexmaker-mockito-inline-extended/build.gradle +++ b/dexmaker-mockito-inline-extended/build.gradle @@ -1,13 +1,25 @@ -plugins { - id("net.ltgt.errorprone") version "1.3.0" +buildscript { + repositories { + maven { + url "https://plugins.gradle.org/m2/" + } + } + dependencies { + classpath "net.ltgt.gradle:gradle-errorprone-plugin:0.0.13" + } } + +apply plugin: "net.ltgt.errorprone" apply plugin: 'com.android.library' -apply from: "$rootDir/gradle/publishing_aar.gradle" +apply plugin: 'maven-publish' +apply plugin: 'ivy-publish' +apply plugin: 'com.jfrog.artifactory' -description = 'Extension of the Mockito Inline API to allow mocking static methods on the Android Dalvik VM' +version = VERSION_NAME android { - compileSdkVersion 32 + compileSdkVersion 28 + buildToolsVersion '28.0.3' android { lintOptions { @@ -17,8 +29,9 @@ android { } defaultConfig { - minSdkVersion 9 - targetSdkVersion 32 + minSdkVersion 1 + targetSdkVersion 28 + versionName VERSION_NAME } externalNativeBuild { @@ -34,16 +47,77 @@ android { } tasks.withType(JavaCompile) { - options.errorprone { - disable("StringSplitter") + options.compilerArgs += ["-Xep:StringSplitter:OFF"] +} + +task sourcesJar(type: Jar) { + classifier = 'sources' + from android.sourceSets.main.java.srcDirs +} + +task javadoc(type: Javadoc) { + source = android.sourceSets.main.java.srcDirs + classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) + failOnError false +} + +task javadocJar(type: Jar, dependsOn: javadoc) { + classifier = 'javadoc' + from javadoc.destinationDir +} + +publishing { + publications { + ivyLib(IvyPublication) { + from new org.gradle.api.internal.java.JavaLibrary(new org.gradle.api.internal.artifacts.publish.DefaultPublishArtifact(project.getName(), 'aar', 'aar', null, new Date(), new File("$buildDir/outputs/aar/${project.getName()}-release.aar"), assemble), project.configurations.implementation.getAllDependencies()) + artifact sourcesJar + artifact javadocJar + } + + lib(MavenPublication) { + from new org.gradle.api.internal.java.JavaLibrary(new org.gradle.api.internal.artifacts.publish.DefaultPublishArtifact(project.getName(), 'aar', 'aar', null, new Date(), new File("$buildDir/outputs/aar/${project.getName()}-release.aar"), assemble), project.configurations.implementation.getAllDependencies()) + + artifact sourcesJar + artifact javadocJar + + pom.withXml { + asNode().children().last() + { + resolveStrategy = Closure.DELEGATE_FIRST + description = 'Extension of the Mockito Inline API to allow mocking static methods on the Android Dalvik VM' + url 'https://github.com/linkedin/dexmaker' + scm { + url 'https://github.com/linkedin/dexmaker' + connection 'scm:git:git://github.com/linkedin/dexmaker.git' + developerConnection 'https://github.com/linkedin/dexmaker.git' + } + licenses { + license { + name 'The Apache Software License, Version 2.0' + url 'http://www.apache.org/license/LICENSE-2.0.txt' + distribution 'repo' + } + } + + developers { + developer { + id 'com.linkedin' + name 'LinkedIn Corp' + email '' + } + } + } + } + } } } -dependencies { - errorprone "com.google.errorprone:error_prone_core:2.5.1" - errorproneJavac "com.google.errorprone:javac:9+181-r4173-1" +repositories { + jcenter() + google() +} +dependencies { implementation project(':dexmaker-mockito-inline') - api 'org.mockito:mockito-core:2.28.2', { exclude group: 'net.bytebuddy' } + implementation 'org.mockito:mockito-core:2.25.0', { exclude group: 'net.bytebuddy' } } diff --git a/dexmaker-mockito-inline-extended/src/main/java/com/android/dx/mockito/inline/InlineStaticMockMaker.java b/dexmaker-mockito-inline-extended/src/main/java/com/android/dx/mockito/inline/InlineStaticMockMaker.java index 05b067d..6ba11cd 100644 --- a/dexmaker-mockito-inline-extended/src/main/java/com/android/dx/mockito/inline/InlineStaticMockMaker.java +++ b/dexmaker-mockito-inline-extended/src/main/java/com/android/dx/mockito/inline/InlineStaticMockMaker.java @@ -112,7 +112,7 @@ public final class InlineStaticMockMaker implements MockMaker { * are modified, some are not. This list helps the {@link MockMethodAdvice} help figure out if a * object's method calls should be intercepted. */ - private final Map<Object, InvocationHandlerAdapter> markerToHandler = new MarkerToHandlerMap(); + private final HashMap<Object, InvocationHandlerAdapter> markerToHandler = new HashMap<>(); private final Map<Class, Object> classToMarker = new HashMap<>(); /** @@ -126,7 +126,8 @@ public final class InlineStaticMockMaker implements MockMaker { public InlineStaticMockMaker() { if (INITIALIZATION_ERROR != null) { throw new RuntimeException("Could not initialize inline mock maker.\n" + "\n" + - "Release: Android " + Build.VERSION.RELEASE + " " + Build.VERSION.INCREMENTAL + "Release: Android " + Build.VERSION.RELEASE_OR_CODENAME + " " + + Build.VERSION.INCREMENTAL + "Device: " + Build.BRAND + " " + Build.MODEL, INITIALIZATION_ERROR); } diff --git a/dexmaker-mockito-inline-extended/src/main/java/com/android/dx/mockito/inline/MarkerToHandlerMap.java b/dexmaker-mockito-inline-extended/src/main/java/com/android/dx/mockito/inline/MarkerToHandlerMap.java deleted file mode 100644 index 74a38b8..0000000 --- a/dexmaker-mockito-inline-extended/src/main/java/com/android/dx/mockito/inline/MarkerToHandlerMap.java +++ /dev/null @@ -1,118 +0,0 @@ -package com.android.dx.mockito.inline; - -import org.mockito.invocation.MockHandler; -import org.mockito.mock.MockCreationSettings; - -import java.util.AbstractMap; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -/** - * A map for mock marker object -> {@link InvocationHandlerAdapter} but - * does not use the mock marker object as the key directly. - * The problem of not doing so is that the object's real hashCode() and equals() = - * methods will be invoked during - * {@link InlineStaticMockMaker#createMock(MockCreationSettings, MockHandler)}. This poses a - * potential test runtime error depending on the object's hashCode() implementation - */ -class MarkerToHandlerMap implements Map<Object, InvocationHandlerAdapter> { - - private final Map<MockMarkerKey, InvocationHandlerAdapter> markerToHandler = new HashMap<>(); - - @Override - public int size() { - return markerToHandler.size(); - } - - @Override - public boolean isEmpty() { - return markerToHandler.isEmpty(); - } - - @Override - public boolean containsKey(Object key) { - return markerToHandler.containsKey(new MockMarkerKey(key)); - } - - @Override - public boolean containsValue(Object value) { - return markerToHandler.containsValue(value); - } - - @Override - public InvocationHandlerAdapter get(Object key) { - return markerToHandler.get(new MockMarkerKey(key)); - } - - @Override - public InvocationHandlerAdapter put(Object key, InvocationHandlerAdapter value) { - return markerToHandler.put(new MockMarkerKey(key), value); - } - - @Override - public InvocationHandlerAdapter remove(Object key) { - return markerToHandler.remove(new MockMarkerKey(key)); - } - - @Override - public void putAll(Map<?, ? extends InvocationHandlerAdapter> m) { - for (Entry<?, ? extends InvocationHandlerAdapter> entry : m.entrySet()) { - put(new MockMarkerKey(entry.getKey()), entry.getValue()); - } - } - - @Override - public void clear() { - markerToHandler.clear(); - } - - @Override - public Set<Object> keySet() { - Set<Object> set = new HashSet<>(entrySet().size()); - for (MockMarkerKey key : markerToHandler.keySet()) { - set.add(key.mockMarker); - } - return set; - } - - @Override - public Collection<InvocationHandlerAdapter> values() { - return markerToHandler.values(); - } - - @Override - public Set<Entry<Object, InvocationHandlerAdapter>> entrySet() { - Set<Entry<Object, InvocationHandlerAdapter>> set = new HashSet<>(entrySet().size()); - for (Entry<MockMarkerKey, InvocationHandlerAdapter> entry : markerToHandler.entrySet()) { - set.add(new AbstractMap.SimpleImmutableEntry<>(entry.getKey().mockMarker, entry.getValue())); - } - return set; - } - - private static class MockMarkerKey { - - private final Object mockMarker; - - public MockMarkerKey(Object mockMarker) { - this.mockMarker = mockMarker; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - MockMarkerKey mockMarkerKey = (MockMarkerKey) o; - - return mockMarker == mockMarkerKey.mockMarker; - } - - @Override - public int hashCode() { - return System.identityHashCode(mockMarker); - } - } -} diff --git a/dexmaker-mockito-inline-tests/build.gradle b/dexmaker-mockito-inline-tests/build.gradle index 4961c5e..02d0751 100644 --- a/dexmaker-mockito-inline-tests/build.gradle +++ b/dexmaker-mockito-inline-tests/build.gradle @@ -1,7 +1,20 @@ +buildscript { + repositories { + maven { + url "https://plugins.gradle.org/m2/" + } + } + dependencies { + classpath "net.ltgt.gradle:gradle-errorprone-plugin:0.0.13" + } +} + +apply plugin: "net.ltgt.errorprone" apply plugin: 'com.android.library' android { - compileSdkVersion 32 + compileSdkVersion 28 + buildToolsVersion '28.0.3' android { lintOptions { @@ -12,7 +25,8 @@ android { defaultConfig { minSdkVersion 28 - targetSdkVersion 32 + targetSdkVersion 28 + versionName VERSION_NAME testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' } @@ -24,12 +38,17 @@ android { } } +repositories { + jcenter() + google() +} + dependencies { implementation project(':dexmaker-mockito-tests') compileOnly project(':dexmaker-mockito-inline') androidTestImplementation project(':dexmaker-mockito-inline') - implementation 'junit:junit:4.13.2' - implementation 'androidx.test:runner:1.4.0' - api 'org.mockito:mockito-core:2.28.2', { exclude group: 'net.bytebuddy' } + implementation 'junit:junit:4.12' + implementation 'com.android.support.test:runner:1.0.2' + api 'org.mockito:mockito-core:2.25.0', { exclude group: 'net.bytebuddy' } } diff --git a/dexmaker-mockito-inline-tests/src/main/java/com/android/dx/mockito/inline/tests/MemoryLeaks.java b/dexmaker-mockito-inline-tests/src/main/java/com/android/dx/mockito/inline/tests/MemoryLeaks.java index 55f5893..d78bb10 100644 --- a/dexmaker-mockito-inline-tests/src/main/java/com/android/dx/mockito/inline/tests/MemoryLeaks.java +++ b/dexmaker-mockito-inline-tests/src/main/java/com/android/dx/mockito/inline/tests/MemoryLeaks.java @@ -29,7 +29,7 @@ public class MemoryLeaks { private static final int ARRAY_LENGTH = 1 << 20; // 4 MB @Test - public void callMethodWithMocksCyclically() { + public void callMethodWithMocksCycalically() { for (int i = 0; i < 100; ++i) { final A a = mock(A.class); a.largeArray = new int[ARRAY_LENGTH]; diff --git a/dexmaker-mockito-inline/build.gradle b/dexmaker-mockito-inline/build.gradle index dcffd65..00913a4 100644 --- a/dexmaker-mockito-inline/build.gradle +++ b/dexmaker-mockito-inline/build.gradle @@ -1,13 +1,25 @@ -plugins { - id("net.ltgt.errorprone") version "1.3.0" +buildscript { + repositories { + maven { + url "https://plugins.gradle.org/m2/" + } + } + dependencies { + classpath "net.ltgt.gradle:gradle-errorprone-plugin:0.0.13" + } } + +apply plugin: "net.ltgt.errorprone" apply plugin: 'com.android.library' -apply from: "$rootDir/gradle/publishing_aar.gradle" +apply plugin: 'maven-publish' +apply plugin: 'ivy-publish' +apply plugin: 'com.jfrog.artifactory' -description = 'Implementation of the Mockito Inline API for use on the Android Dalvik VM' +version = VERSION_NAME android { - compileSdkVersion 32 + compileSdkVersion 28 + buildToolsVersion '28.0.3' android { lintOptions { @@ -18,7 +30,8 @@ android { defaultConfig { minSdkVersion 1 - targetSdkVersion 32 + targetSdkVersion 28 + versionName VERSION_NAME } externalNativeBuild { @@ -29,16 +42,77 @@ android { } tasks.withType(JavaCompile) { - options.errorprone { - disable("StringSplitter") + options.compilerArgs += ["-Xep:StringSplitter:OFF"] +} + +task sourcesJar(type: Jar) { + classifier = 'sources' + from android.sourceSets.main.java.srcDirs +} + +task javadoc(type: Javadoc) { + source = android.sourceSets.main.java.srcDirs + classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) +} + +task javadocJar(type: Jar, dependsOn: javadoc) { + classifier = 'javadoc' + from javadoc.destinationDir +} + +publishing { + publications { + ivyLib(IvyPublication) { + from new org.gradle.api.internal.java.JavaLibrary(new org.gradle.api.internal.artifacts.publish.DefaultPublishArtifact(project.getName(), 'aar', 'aar', null, new Date(), new File("$buildDir/outputs/aar/${project.getName()}-release.aar"), assemble), project.configurations.implementation.getAllDependencies()) + artifact sourcesJar + artifact javadocJar + } + + lib(MavenPublication) { + from new org.gradle.api.internal.java.JavaLibrary(new org.gradle.api.internal.artifacts.publish.DefaultPublishArtifact(project.getName(), 'aar', 'aar', null, new Date(), new File("$buildDir/outputs/aar/${project.getName()}-release.aar"), assemble), project.configurations.implementation.getAllDependencies()) + + artifact sourcesJar + artifact javadocJar + + pom.withXml { + asNode().children().last() + { + resolveStrategy = Closure.DELEGATE_FIRST + description = 'Implementation of the Mockito Inline API for use on the Android Dalvik VM' + url 'https://github.com/linkedin/dexmaker' + scm { + url 'https://github.com/linkedin/dexmaker' + connection 'scm:git:git://github.com/linkedin/dexmaker.git' + developerConnection 'https://github.com/linkedin/dexmaker.git' + } + licenses { + license { + name 'The Apache Software License, Version 2.0' + url 'http://www.apache.org/license/LICENSE-2.0.txt' + distribution 'repo' + } + } + + developers { + developer { + id 'com.linkedin' + name 'LinkedIn Corp' + email '' + } + } + } + } + } } } -dependencies { - errorprone "com.google.errorprone:error_prone_core:2.5.1" - errorproneJavac "com.google.errorprone:javac:9+181-r4173-1" +repositories { + jcenter() + google() +} +dependencies { implementation project(':dexmaker') - api 'org.mockito:mockito-core:2.28.2', { exclude group: 'net.bytebuddy' } + implementation 'org.mockito:mockito-core:2.25.0', { exclude group: 'net.bytebuddy' } } + diff --git a/dexmaker-mockito-inline/src/main/java/com/android/dx/mockito/inline/InlineDexmakerMockMaker.java b/dexmaker-mockito-inline/src/main/java/com/android/dx/mockito/inline/InlineDexmakerMockMaker.java index 0a594e0..9741118 100644 --- a/dexmaker-mockito-inline/src/main/java/com/android/dx/mockito/inline/InlineDexmakerMockMaker.java +++ b/dexmaker-mockito-inline/src/main/java/com/android/dx/mockito/inline/InlineDexmakerMockMaker.java @@ -180,7 +180,8 @@ public final class InlineDexmakerMockMaker implements InlineMockMaker { throw new RuntimeException( "Could not initialize inline mock maker.\n" + "\n" - + "Release: Android " + Build.VERSION.RELEASE + " " + Build.VERSION.INCREMENTAL + + "Release: Android " + Build.VERSION.RELEASE_OR_CODENAME + " " + + Build.VERSION.INCREMENTAL + "Device: " + Build.BRAND + " " + Build.MODEL, INITIALIZATION_ERROR); } diff --git a/dexmaker-mockito-tests/build.gradle b/dexmaker-mockito-tests/build.gradle index 918f277..9379d17 100644 --- a/dexmaker-mockito-tests/build.gradle +++ b/dexmaker-mockito-tests/build.gradle @@ -1,7 +1,19 @@ +buildscript { + repositories { + maven { + url "https://plugins.gradle.org/m2/" + } + } + dependencies { + classpath "net.ltgt.gradle:gradle-errorprone-plugin:0.0.13" + } +} + +apply plugin: "net.ltgt.errorprone" apply plugin: 'com.android.library' android { - compileSdkVersion 32 + compileSdkVersion 28 android { lintOptions { @@ -11,18 +23,24 @@ android { } defaultConfig { - minSdkVersion 14 - targetSdkVersion 32 + minSdkVersion 8 + targetSdkVersion 28 + versionName VERSION_NAME testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' } } +repositories { + jcenter() + google() +} + dependencies { compileOnly project(':dexmaker-mockito') androidTestImplementation project(':dexmaker-mockito') - implementation 'androidx.test:runner:1.4.0' - implementation 'junit:junit:4.13.2' - api 'org.mockito:mockito-core:2.28.2', { exclude group: 'net.bytebuddy' } + implementation 'com.android.support.test:runner:0.5' + implementation 'junit:junit:4.12' + api 'org.mockito:mockito-core:2.25.0', { exclude group: 'net.bytebuddy' } } diff --git a/dexmaker-mockito-tests/src/main/java/com/android/dx/mockito/tests/BlacklistedApis.java b/dexmaker-mockito-tests/src/main/java/com/android/dx/mockito/tests/BlacklistedApis.java index 126647d..4a345b3 100644 --- a/dexmaker-mockito-tests/src/main/java/com/android/dx/mockito/tests/BlacklistedApis.java +++ b/dexmaker-mockito-tests/src/main/java/com/android/dx/mockito/tests/BlacklistedApis.java @@ -117,7 +117,7 @@ public class BlacklistedApis { parent.measure(100, 100); } - @SuppressLint({"PrivateApi", "CheckReturnValue", "SoonBlockedPrivateApi"}) + @SuppressLint({"PrivateApi", "CheckReturnValue"}) @Test public void cannotCallBlackListedAfterSpying() { // Spying and mocking might change the View class's byte code @@ -134,7 +134,7 @@ public class BlacklistedApis { } public static class CallBlackListedMethod { - @SuppressLint({"PrivateApi", "SoonBlockedPrivateApi"}) + @SuppressLint("PrivateApi") boolean callingBlacklistedMethodCausesException() { // Settings.Global#isValidZenMode is a blacklisted method. Resolving it should fail try { @@ -153,7 +153,7 @@ public class BlacklistedApis { } public static abstract class CallBlacklistedMethodAbstract { - @SuppressLint({"PrivateApi", "SoonBlockedPrivateApi"}) + @SuppressLint("PrivateApi") public boolean callingBlacklistedMethodCausesException() { // Settings.Global#isValidZenMode is a blacklisted method. Resolving it should fail try { diff --git a/dexmaker-mockito/build.gradle b/dexmaker-mockito/build.gradle index c3095ad..b15b30c 100644 --- a/dexmaker-mockito/build.gradle +++ b/dexmaker-mockito/build.gradle @@ -1,26 +1,30 @@ -plugins { - id("net.ltgt.errorprone") version "1.3.0" +buildscript { + repositories { + maven { + url "https://plugins.gradle.org/m2/" + } + } + dependencies { + classpath "net.ltgt.gradle:gradle-errorprone-plugin:0.0.13" + } } -description = "Implementation of the Mockito API for use on the Android Dalvik VM" - -apply plugin: 'java-library' +apply plugin: "net.ltgt.errorprone" +apply plugin: 'java' apply from: "$rootDir/gradle/publishing.gradle" +version = VERSION_NAME +description = "Implementation of the Mockito API for use on the Android Dalvik VM" + targetCompatibility = '1.7' sourceCompatibility = '1.7' -tasks.withType(JavaCompile) { - options.errorprone { - disable("StringSplitter") - } +repositories { + jcenter() } dependencies { - errorprone "com.google.errorprone:error_prone_core:2.5.1" - errorproneJavac "com.google.errorprone:javac:9+181-r4173-1" - implementation project(':dexmaker') - api 'org.mockito:mockito-core:2.28.2', { exclude group: 'net.bytebuddy' } + implementation 'org.mockito:mockito-core:2.25.0', { exclude group: 'net.bytebuddy' } } diff --git a/dexmaker-mockito/src/main/java/com/android/dx/mockito/DexmakerMockMaker.java b/dexmaker-mockito/src/main/java/com/android/dx/mockito/DexmakerMockMaker.java index e3b8630..4cdaf44 100644 --- a/dexmaker-mockito/src/main/java/com/android/dx/mockito/DexmakerMockMaker.java +++ b/dexmaker-mockito/src/main/java/com/android/dx/mockito/DexmakerMockMaker.java @@ -37,16 +37,15 @@ import java.util.Set; */ public final class DexmakerMockMaker implements MockMaker, StackTraceCleanerProvider { private final UnsafeAllocator unsafeAllocator = UnsafeAllocator.create(); - private final boolean isApi28; + private boolean isApi28; - public DexmakerMockMaker() { + public DexmakerMockMaker() throws Exception { try { Class buildVersion = Class.forName("android.os.Build$VERSION"); - isApi28 = buildVersion.getDeclaredField("SDK_INT").getInt(null) >= 28; - } catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) { - throw new IllegalStateException("Cannot find android.os.Build$VERSION#SDK_INT. " + - "Field is needed to determine Android version.", e); + } catch (ClassNotFoundException e) { + System.err.println("Could not determine platform API level, assuming >= 28: " + e); + isApi28 = true; } if (isApi28) { @@ -77,17 +76,6 @@ public final class DexmakerMockMaker implements MockMaker, StackTraceCleanerProv System.err.println("Cannot allow LenientCopyTool to copy spies of blacklisted " + "fields. This might break spying on system classes."); } - - // The ProxyBuilder class needs to be able to see hidden methods in order to proxy - // them correctly. If it cannot see blacklisted methods, then other system classes - // which call hidden methods on the mock will call through to the real method rather - // than the proxy, which may cause crashes or other unexpected behavior. - try { - allowHiddenApiReflectionFromMethod.invoke(null, ProxyBuilder.class); - } catch (InvocationTargetException | IllegalAccessException e) { - System.err.println("Cannot allow ProxyBuilder to proxy blacklisted " - + "methods. This might break mocking on system classes."); - } } } diff --git a/dexmaker-tests/build.gradle b/dexmaker-tests/build.gradle index 996008d..5ae5f2d 100644 --- a/dexmaker-tests/build.gradle +++ b/dexmaker-tests/build.gradle @@ -1,12 +1,25 @@ +buildscript { + repositories { + maven { + url "https://plugins.gradle.org/m2/" + } + } + dependencies { + classpath "net.ltgt.gradle:gradle-errorprone-plugin:0.0.13" + } +} + +apply plugin: "net.ltgt.errorprone" apply plugin: 'com.android.application' android { - compileSdkVersion 32 + compileSdkVersion 28 + buildToolsVersion '28.0.3' defaultConfig { applicationId 'com.linkedin.dexmaker' - minSdkVersion 14 - targetSdkVersion 32 + minSdkVersion 8 + targetSdkVersion 28 versionCode 1 versionName VERSION_NAME @@ -14,9 +27,15 @@ android { } } +repositories { + jcenter() + google() +} + dependencies { implementation project(":dexmaker") - androidTestImplementation 'androidx.test:runner:1.4.0' - androidTestImplementation 'junit:junit:4.13.2' + //noinspection GradleDependency + androidTestImplementation 'com.android.support.test:runner:0.5' + androidTestImplementation 'junit:junit:4.12' } diff --git a/dexmaker-tests/src/androidTest/java/com/android/dx/DexMakerTest.java b/dexmaker-tests/src/androidTest/java/com/android/dx/DexMakerTest.java index d718aaa..af520e1 100644 --- a/dexmaker-tests/src/androidTest/java/com/android/dx/DexMakerTest.java +++ b/dexmaker-tests/src/androidTest/java/com/android/dx/DexMakerTest.java @@ -172,26 +172,6 @@ public final class DexMakerTest { } @Test - public void testLoadDeferredClassConstant() throws Exception { - /* - * public static String call() { - * Class clazz = Generated.class; - * return clazz.getSimpleName(); - * } - */ - MethodId<?, String> methodId = GENERATED.getMethod(TypeId.STRING, "call"); - Code code = dexMaker.declare(methodId, PUBLIC | STATIC); - Local<Class> clazz = code.newLocal(TypeId.get(Class.class)); - Local<String> retValue = code.newLocal(TypeId.STRING); - code.loadDeferredClassConstant(clazz, GENERATED); - MethodId<Class, String> getSimpleName = TypeId.get(Class.class).getMethod(TypeId.STRING, "getSimpleName"); - code.invokeVirtual(getSimpleName, retValue, clazz); - code.returnValue(retValue); - - assertEquals("Generated", getMethod().invoke(null)); - } - - @Test public void testCreateLocalMethodAsNull() throws Exception { /* * public void call(int value) { @@ -501,58 +481,6 @@ public final class DexMakerTest { } @Test - public void testDeclareNativeMethod() throws Exception { - /* - * class Generated { - * public Generated() { - * } - * public native void nativeMethod(); - * } - */ - - addDefaultConstructor(); - String nativeMethodName = "nativeMethod"; - MethodId<?, Void> nativeMethodToGenerate = GENERATED.getMethod(TypeId.VOID, nativeMethodName); - dexMaker.declare(nativeMethodToGenerate, java.lang.reflect.Modifier.PUBLIC | java.lang.reflect.Modifier.NATIVE); - - Class<?> generatedClass = generateAndLoad(); - Object instance = generatedClass.getConstructor().newInstance(); - Method nativeMethod = instance.getClass().getMethod(nativeMethodName); - - assertTrue((nativeMethod.getModifiers() & NATIVE) != 0); - assertTrue((nativeMethod.getModifiers() & PUBLIC) != 0); - assertEquals(void.class, nativeMethod.getReturnType()); - assertEquals(nativeMethodName, nativeMethod.getName()); - assertEquals(nativeMethod.getParameterTypes().length, 0); - } - - @Test - public void testDeclareAbstractClassWithAbstractMethod() throws Exception { - /* - * public abstract class AbstractClass { - * public abstract void abstractMethod(); - * } - */ - - dexMaker = new DexMaker(); - dexMaker.declare(GENERATED, "AbstractClass.java", PUBLIC, TypeId.OBJECT); - - String abstractMethodName = "abstractMethod"; - MethodId<?, Void> nativeMethodToGenerate = GENERATED.getMethod(TypeId.VOID, abstractMethodName); - dexMaker.declare(nativeMethodToGenerate, java.lang.reflect.Modifier.PUBLIC | ABSTRACT); - - Class<?> generatedClass = generateAndLoad(); - Method nativeMethod = generatedClass.getMethod(abstractMethodName); - - assertTrue((nativeMethod.getModifiers() & ABSTRACT) != 0); - assertTrue((nativeMethod.getModifiers() & PUBLIC) != 0); - assertEquals(void.class, nativeMethod.getReturnType()); - assertEquals(abstractMethodName, nativeMethod.getName()); - assertEquals(nativeMethod.getParameterTypes().length, 0); - - } - - @Test public void testReturnType() throws Exception { testReturnType(boolean.class, true); testReturnType(byte.class, (byte) 5); @@ -2028,6 +1956,26 @@ public final class DexMakerTest { } @Test + public void testAbstractMethodsAreUnsupported() { + MethodId<?, Void> methodId = GENERATED.getMethod(TypeId.VOID, "call"); + try { + dexMaker.declare(methodId, ABSTRACT); + fail(); + } catch (IllegalArgumentException expected) { + } + } + + @Test + public void testNativeMethodsAreUnsupported() { + MethodId<?, Void> methodId = GENERATED.getMethod(TypeId.VOID, "call"); + try { + dexMaker.declare(methodId, NATIVE); + fail(); + } catch (IllegalArgumentException expected) { + } + } + + @Test public void testSynchronizedFieldsAreUnsupported() { try { FieldId<?, ?> fieldId = GENERATED.getField(TypeId.OBJECT, "synchronizedField"); @@ -2057,6 +2005,7 @@ public final class DexMakerTest { // TODO: don't generate multiple times (?) // TODO: test array types // TODO: test generating an interface + // TODO: declare native method or abstract method // TODO: get a thrown exception 'e' into a local // TODO: move a primitive or reference diff --git a/dexmaker/build.gradle b/dexmaker/build.gradle index 01b0bdb..7e8762f 100644 --- a/dexmaker/build.gradle +++ b/dexmaker/build.gradle @@ -1,28 +1,32 @@ -plugins { - id("net.ltgt.errorprone") version "1.3.0" +buildscript { + repositories { + maven { + url "https://plugins.gradle.org/m2/" + } + } + dependencies { + classpath "net.ltgt.gradle:gradle-errorprone-plugin:0.0.13" + } } -description = "A utility for doing compile or runtime code generation targeting Android's Dalvik VM" - +apply plugin: "net.ltgt.errorprone" apply plugin: 'java' apply from: "$rootDir/gradle/publishing.gradle" +version = VERSION_NAME +description = "A utility for doing compile or runtime code generation targeting Android's Dalvik VM" + targetCompatibility = '1.7' sourceCompatibility = '1.7' -tasks.withType(JavaCompile) { - options.errorprone { - disable("StringSplitter") - } +repositories { + jcenter() } -javadoc { - options.addBooleanOption("Xdoclint:-html", true) +tasks.withType(JavaCompile) { + options.compilerArgs += ["-Xep:StringSplitter:OFF"] } dependencies { - errorprone "com.google.errorprone:error_prone_core:2.5.1" - errorproneJavac "com.google.errorprone:javac:9+181-r4173-1" - implementation 'com.jakewharton.android.repackaged:dalvik-dx:9.0.0_r3' } diff --git a/dexmaker/src/main/java/com/android/dx/Code.java b/dexmaker/src/main/java/com/android/dx/Code.java index c0f2759..715d2b4 100644 --- a/dexmaker/src/main/java/com/android/dx/Code.java +++ b/dexmaker/src/main/java/com/android/dx/Code.java @@ -476,27 +476,15 @@ public final class Code { * must be a primitive, String, Class, TypeId, or null. */ public <T> void loadConstant(Local<T> target, T value) { - loadConstantInternal(target, value); - } - - /** - * Copies a class type in {@code target}. The benefit to using this method vs {@link Code#loadConstant(Local, Object)} - * is that the {@code value} can itself be a generated type - {@link TypeId} allows for deferred referencing of class types. - */ - public void loadDeferredClassConstant(Local<Class> target, TypeId value) { - loadConstantInternal(target, value); - } - - private void loadConstantInternal(Local target, Object value) { Rop rop = value == null - ? Rops.CONST_OBJECT_NOTHROW - : Rops.opConst(target.type.ropType); + ? Rops.CONST_OBJECT_NOTHROW + : Rops.opConst(target.type.ropType); if (rop.getBranchingness() == BRANCH_NONE) { addInstruction(new PlainCstInsn(rop, sourcePosition, target.spec(), - RegisterSpecList.EMPTY, Constants.getConstant(value))); + RegisterSpecList.EMPTY, Constants.getConstant(value))); } else { addInstruction(new ThrowingCstInsn(rop, sourcePosition, - RegisterSpecList.EMPTY, catches, Constants.getConstant(value))); + RegisterSpecList.EMPTY, catches, Constants.getConstant(value))); moveResult(target, true); } } diff --git a/dexmaker/src/main/java/com/android/dx/DexMaker.java b/dexmaker/src/main/java/com/android/dx/DexMaker.java index b672c53..e45ead0 100644 --- a/dexmaker/src/main/java/com/android/dx/DexMaker.java +++ b/dexmaker/src/main/java/com/android/dx/DexMaker.java @@ -32,7 +32,6 @@ import com.android.dx.rop.cst.CstString; import com.android.dx.rop.cst.CstType; import com.android.dx.rop.type.StdTypeList; -import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -47,8 +46,8 @@ import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; import static com.android.dx.rop.code.AccessFlags.ACC_CONSTRUCTOR; -import static java.lang.reflect.Modifier.*; -; +import static java.lang.reflect.Modifier.PRIVATE; +import static java.lang.reflect.Modifier.STATIC; /** * Generates a <strong>D</strong>alvik <strong>EX</strong>ecutable (dex) @@ -231,7 +230,7 @@ public final class DexMaker { * Modifier#FINAL} and {@link Modifier#ABSTRACT}. */ public void declare(TypeId<?> type, String sourceFile, int flags, - TypeId<?> supertype, TypeId<?>... interfaces) { + TypeId<?> supertype, TypeId<?>... interfaces) { TypeDeclaration declaration = getTypeDeclaration(type); int supportedFlags = Modifier.PUBLIC | Modifier.FINAL | Modifier.ABSTRACT | AccessFlags.ACC_SYNTHETIC; @@ -266,7 +265,7 @@ public final class DexMaker { throw new IllegalStateException("already declared: " + method); } - int supportedFlags = Modifier.ABSTRACT | Modifier.NATIVE | Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED + int supportedFlags = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED | Modifier.STATIC | Modifier.FINAL | Modifier.SYNCHRONIZED | AccessFlags.ACC_SYNTHETIC | AccessFlags.ACC_BRIDGE; if ((flags & ~supportedFlags) != 0) { @@ -516,12 +515,7 @@ public final class DexMaker { // Check that the file exists. If it does, return a DexClassLoader and skip all // the dex bytecode generation. if (result.exists()) { - if (!result.canWrite()) { - return generateClassLoader(result, dexCache, parent); - } else { - // Old writable files should be ignored and re-generated - result.delete(); - } + return generateClassLoader(result, dexCache, parent); } byte[] dex = generate(); @@ -533,23 +527,14 @@ public final class DexMaker { * * TODO: load the dex from memory where supported. */ - - JarOutputStream jarOut = - new JarOutputStream(new BufferedOutputStream(new FileOutputStream(result))); - result.setReadOnly(); - try { - JarEntry entry = new JarEntry(DexFormat.DEX_IN_JAR_NAME); - entry.setSize(dex.length); - jarOut.putNextEntry(entry); - try { - jarOut.write(dex); - } finally { - jarOut.closeEntry(); - } - } finally { - jarOut.close(); - } - + result.createNewFile(); + JarOutputStream jarOut = new JarOutputStream(new FileOutputStream(result)); + JarEntry entry = new JarEntry(DexFormat.DEX_IN_JAR_NAME); + entry.setSize(dex.length); + jarOut.putNextEntry(entry); + jarOut.write(dex); + jarOut.closeEntry(); + jarOut.close(); return generateClassLoader(result, dexCache, parent); } @@ -660,10 +645,6 @@ public final class DexMaker { } EncodedMethod toEncodedMethod(DexOptions dexOptions) { - if((flags & ABSTRACT) != 0 || (flags & NATIVE) != 0){ - return new EncodedMethod(method.constant, flags, null, StdTypeList.EMPTY); - } - RopMethod ropMethod = new RopMethod(code.toBasicBlocks(), 0); LocalVariableInfo locals = null; DalvCode dalvCode = RopTranslator.translate( |