aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Wu <topjohnwu@google.com>2022-09-12 23:50:34 +0000
committerJohn Wu <topjohnwu@google.com>2022-09-12 23:50:34 +0000
commitc57c3d977b947dfafdcc8e27bf5c1cd6e3342f95 (patch)
tree172d1f762cf1c1f63882536463374e6b04ec4a35
parentecb8636406ec1c4c89e721e38d570e8c19bba866 (diff)
downloaddexmaker-c57c3d977b947dfafdcc8e27bf5c1cd6e3342f95.tar.gz
Update to upstream dexmaker
New changes are submitted upstream to support latest Java DCL restrictions added to the platform. Test: m Bug: 218865702 Change-Id: Ie081df9004c01d9e4e1bcefba22cce3d92f49d4a
-rw-r--r--README.version6
-rw-r--r--dexmaker-mockito-inline-dispatcher/build.gradle10
-rw-r--r--dexmaker-mockito-inline-extended-tests/build.gradle31
-rw-r--r--dexmaker-mockito-inline-extended-tests/src/main/java/com/android/dx/mockito/inline/extended/tests/StaticMockitoSession.java24
-rw-r--r--dexmaker-mockito-inline-extended/build.gradle100
-rw-r--r--dexmaker-mockito-inline-extended/src/main/java/com/android/dx/mockito/inline/InlineStaticMockMaker.java5
-rw-r--r--dexmaker-mockito-inline-extended/src/main/java/com/android/dx/mockito/inline/MarkerToHandlerMap.java118
-rw-r--r--dexmaker-mockito-inline-tests/build.gradle29
-rw-r--r--dexmaker-mockito-inline-tests/src/main/java/com/android/dx/mockito/inline/tests/MemoryLeaks.java2
-rw-r--r--dexmaker-mockito-inline/build.gradle98
-rw-r--r--dexmaker-mockito-inline/src/main/java/com/android/dx/mockito/inline/InlineDexmakerMockMaker.java3
-rw-r--r--dexmaker-mockito-tests/build.gradle30
-rw-r--r--dexmaker-mockito-tests/src/main/java/com/android/dx/mockito/tests/BlacklistedApis.java6
-rw-r--r--dexmaker-mockito/build.gradle30
-rw-r--r--dexmaker-mockito/src/main/java/com/android/dx/mockito/DexmakerMockMaker.java22
-rw-r--r--dexmaker-tests/build.gradle29
-rw-r--r--dexmaker-tests/src/androidTest/java/com/android/dx/DexMakerTest.java93
-rw-r--r--dexmaker/build.gradle30
-rw-r--r--dexmaker/src/main/java/com/android/dx/Code.java20
-rw-r--r--dexmaker/src/main/java/com/android/dx/DexMaker.java45
20 files changed, 360 insertions, 371 deletions
diff --git a/README.version b/README.version
index 3e8229a..ed8d2a6 100644
--- a/README.version
+++ b/README.version
@@ -1,5 +1,5 @@
URL: https://github.com/linkedin/dexmaker/
-Version: master (8ff85edb2793cc1e0f6a93c67b127cb9c43d924e)
+Version: main (65749b3da4b058c0b322b2adbf3e8f70488f8d8b)
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,10 +11,6 @@ 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 73a93f3..b811904 100644
--- a/dexmaker-mockito-inline-dispatcher/build.gradle
+++ b/dexmaker-mockito-inline-dispatcher/build.gradle
@@ -1,18 +1,12 @@
apply plugin: 'com.android.application'
android {
- compileSdkVersion 28
- buildToolsVersion '28.0.3'
+ compileSdkVersion 32
defaultConfig {
applicationId 'com.android.dexmaker.mockito.inline.dispatcher'
minSdkVersion 28
- targetSdkVersion 28
+ targetSdkVersion 32
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 b5664f2..e5dc213 100644
--- a/dexmaker-mockito-inline-extended-tests/build.gradle
+++ b/dexmaker-mockito-inline-extended-tests/build.gradle
@@ -1,20 +1,7 @@
-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 28
- buildToolsVersion '28.0.3'
+ compileSdkVersion 32
android {
lintOptions {
@@ -24,8 +11,7 @@ android {
defaultConfig {
minSdkVersion 28
- targetSdkVersion 28
- versionName VERSION_NAME
+ targetSdkVersion 32
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
@@ -36,19 +22,14 @@ 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.12'
- implementation 'com.android.support.test:runner:1.0.2'
- implementation 'com.android.support.test:rules:1.0.2'
+ implementation 'junit:junit:4.13.2'
+ implementation 'androidx.test:runner:1.4.0'
+ implementation 'androidx.test:rules:1.4.0'
- api 'org.mockito:mockito-core:2.25.0', { exclude group: 'net.bytebuddy' }
+ api 'org.mockito:mockito-core:2.28.2', { 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 7c7941b..eff42ab 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,6 +16,7 @@
package com.android.dx.mockito.inline.extended.tests;
+import android.app.PendingIntent;
import android.content.ContentResolver;
import android.provider.Settings;
@@ -33,8 +34,9 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
public class StaticMockitoSession {
+
@Test
- public void strictUnnecessaryStubbing() throws Exception {
+ public void strictUnnecessaryStubbing() {
MockitoSession session = mockitoSession().spyStatic(Settings.Global.class).startMocking();
// Set up unnecessary stubbing
@@ -51,7 +53,7 @@ public class StaticMockitoSession {
}
@Test
- public void lenientUnnecessaryStubbing() throws Exception {
+ public void lenientUnnecessaryStubbing() {
MockitoSession session = mockitoSession().strictness(Strictness.LENIENT)
.spyStatic(Settings.Global.class).startMocking();
@@ -61,4 +63,22 @@ 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 fee152e..b02cd37 100644
--- a/dexmaker-mockito-inline-extended/build.gradle
+++ b/dexmaker-mockito-inline-extended/build.gradle
@@ -1,25 +1,13 @@
-buildscript {
- repositories {
- maven {
- url "https://plugins.gradle.org/m2/"
- }
- }
- dependencies {
- classpath "net.ltgt.gradle:gradle-errorprone-plugin:0.0.13"
- }
+plugins {
+ id("net.ltgt.errorprone") version "1.3.0"
}
-
-apply plugin: "net.ltgt.errorprone"
apply plugin: 'com.android.library'
-apply plugin: 'maven-publish'
-apply plugin: 'ivy-publish'
-apply plugin: 'com.jfrog.artifactory'
+apply from: "$rootDir/gradle/publishing_aar.gradle"
-version = VERSION_NAME
+description = 'Extension of the Mockito Inline API to allow mocking static methods on the Android Dalvik VM'
android {
- compileSdkVersion 28
- buildToolsVersion '28.0.3'
+ compileSdkVersion 32
android {
lintOptions {
@@ -29,9 +17,8 @@ android {
}
defaultConfig {
- minSdkVersion 1
- targetSdkVersion 28
- versionName VERSION_NAME
+ minSdkVersion 9
+ targetSdkVersion 32
}
externalNativeBuild {
@@ -47,77 +34,16 @@ android {
}
tasks.withType(JavaCompile) {
- 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 ''
- }
- }
- }
- }
- }
+ options.errorprone {
+ disable("StringSplitter")
}
}
-repositories {
- jcenter()
- google()
-}
-
dependencies {
+ errorprone "com.google.errorprone:error_prone_core:2.5.1"
+ errorproneJavac "com.google.errorprone:javac:9+181-r4173-1"
+
implementation project(':dexmaker-mockito-inline')
- implementation 'org.mockito:mockito-core:2.25.0', { exclude group: 'net.bytebuddy' }
+ api 'org.mockito:mockito-core:2.28.2', { 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 6ba11cd..05b067d 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 HashMap<Object, InvocationHandlerAdapter> markerToHandler = new HashMap<>();
+ private final Map<Object, InvocationHandlerAdapter> markerToHandler = new MarkerToHandlerMap();
private final Map<Class, Object> classToMarker = new HashMap<>();
/**
@@ -126,8 +126,7 @@ 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_OR_CODENAME + " "
- + Build.VERSION.INCREMENTAL
+ "Release: Android " + Build.VERSION.RELEASE + " " + 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
new file mode 100644
index 0000000..74a38b8
--- /dev/null
+++ b/dexmaker-mockito-inline-extended/src/main/java/com/android/dx/mockito/inline/MarkerToHandlerMap.java
@@ -0,0 +1,118 @@
+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 02d0751..4961c5e 100644
--- a/dexmaker-mockito-inline-tests/build.gradle
+++ b/dexmaker-mockito-inline-tests/build.gradle
@@ -1,20 +1,7 @@
-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 28
- buildToolsVersion '28.0.3'
+ compileSdkVersion 32
android {
lintOptions {
@@ -25,8 +12,7 @@ android {
defaultConfig {
minSdkVersion 28
- targetSdkVersion 28
- versionName VERSION_NAME
+ targetSdkVersion 32
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
@@ -38,17 +24,12 @@ android {
}
}
-repositories {
- jcenter()
- google()
-}
-
dependencies {
implementation project(':dexmaker-mockito-tests')
compileOnly project(':dexmaker-mockito-inline')
androidTestImplementation project(':dexmaker-mockito-inline')
- 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' }
+ 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' }
}
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 d78bb10..55f5893 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 callMethodWithMocksCycalically() {
+ public void callMethodWithMocksCyclically() {
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 00913a4..dcffd65 100644
--- a/dexmaker-mockito-inline/build.gradle
+++ b/dexmaker-mockito-inline/build.gradle
@@ -1,25 +1,13 @@
-buildscript {
- repositories {
- maven {
- url "https://plugins.gradle.org/m2/"
- }
- }
- dependencies {
- classpath "net.ltgt.gradle:gradle-errorprone-plugin:0.0.13"
- }
+plugins {
+ id("net.ltgt.errorprone") version "1.3.0"
}
-
-apply plugin: "net.ltgt.errorprone"
apply plugin: 'com.android.library'
-apply plugin: 'maven-publish'
-apply plugin: 'ivy-publish'
-apply plugin: 'com.jfrog.artifactory'
+apply from: "$rootDir/gradle/publishing_aar.gradle"
-version = VERSION_NAME
+description = 'Implementation of the Mockito Inline API for use on the Android Dalvik VM'
android {
- compileSdkVersion 28
- buildToolsVersion '28.0.3'
+ compileSdkVersion 32
android {
lintOptions {
@@ -30,8 +18,7 @@ android {
defaultConfig {
minSdkVersion 1
- targetSdkVersion 28
- versionName VERSION_NAME
+ targetSdkVersion 32
}
externalNativeBuild {
@@ -42,77 +29,16 @@ android {
}
tasks.withType(JavaCompile) {
- 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 ''
- }
- }
- }
- }
- }
+ options.errorprone {
+ disable("StringSplitter")
}
}
-repositories {
- jcenter()
- google()
-}
-
dependencies {
+ errorprone "com.google.errorprone:error_prone_core:2.5.1"
+ errorproneJavac "com.google.errorprone:javac:9+181-r4173-1"
+
implementation project(':dexmaker')
- implementation 'org.mockito:mockito-core:2.25.0', { exclude group: 'net.bytebuddy' }
+ api 'org.mockito:mockito-core:2.28.2', { 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 9741118..0a594e0 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,8 +180,7 @@ public final class InlineDexmakerMockMaker implements InlineMockMaker {
throw new RuntimeException(
"Could not initialize inline mock maker.\n"
+ "\n"
- + "Release: Android " + Build.VERSION.RELEASE_OR_CODENAME + " "
- + Build.VERSION.INCREMENTAL
+ + "Release: Android " + Build.VERSION.RELEASE + " " + 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 9379d17..918f277 100644
--- a/dexmaker-mockito-tests/build.gradle
+++ b/dexmaker-mockito-tests/build.gradle
@@ -1,19 +1,7 @@
-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 28
+ compileSdkVersion 32
android {
lintOptions {
@@ -23,24 +11,18 @@ android {
}
defaultConfig {
- minSdkVersion 8
- targetSdkVersion 28
- versionName VERSION_NAME
+ minSdkVersion 14
+ targetSdkVersion 32
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
}
-repositories {
- jcenter()
- google()
-}
-
dependencies {
compileOnly project(':dexmaker-mockito')
androidTestImplementation project(':dexmaker-mockito')
- 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' }
+ 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' }
}
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 4a345b3..126647d 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"})
+ @SuppressLint({"PrivateApi", "CheckReturnValue", "SoonBlockedPrivateApi"})
@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")
+ @SuppressLint({"PrivateApi", "SoonBlockedPrivateApi"})
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")
+ @SuppressLint({"PrivateApi", "SoonBlockedPrivateApi"})
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 b15b30c..c3095ad 100644
--- a/dexmaker-mockito/build.gradle
+++ b/dexmaker-mockito/build.gradle
@@ -1,30 +1,26 @@
-buildscript {
- repositories {
- maven {
- url "https://plugins.gradle.org/m2/"
- }
- }
- dependencies {
- classpath "net.ltgt.gradle:gradle-errorprone-plugin:0.0.13"
- }
+plugins {
+ id("net.ltgt.errorprone") version "1.3.0"
}
-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"
+apply plugin: 'java-library'
+apply from: "$rootDir/gradle/publishing.gradle"
+
targetCompatibility = '1.7'
sourceCompatibility = '1.7'
-repositories {
- jcenter()
+tasks.withType(JavaCompile) {
+ options.errorprone {
+ disable("StringSplitter")
+ }
}
dependencies {
+ errorprone "com.google.errorprone:error_prone_core:2.5.1"
+ errorproneJavac "com.google.errorprone:javac:9+181-r4173-1"
+
implementation project(':dexmaker')
- implementation 'org.mockito:mockito-core:2.25.0', { exclude group: 'net.bytebuddy' }
+ api 'org.mockito:mockito-core:2.28.2', { 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 4cdaf44..e3b8630 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,15 +37,16 @@ import java.util.Set;
*/
public final class DexmakerMockMaker implements MockMaker, StackTraceCleanerProvider {
private final UnsafeAllocator unsafeAllocator = UnsafeAllocator.create();
- private boolean isApi28;
+ private final boolean isApi28;
- public DexmakerMockMaker() throws Exception {
+ public DexmakerMockMaker() {
try {
Class buildVersion = Class.forName("android.os.Build$VERSION");
+
isApi28 = buildVersion.getDeclaredField("SDK_INT").getInt(null) >= 28;
- } catch (ClassNotFoundException e) {
- System.err.println("Could not determine platform API level, assuming >= 28: " + e);
- isApi28 = true;
+ } catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
+ throw new IllegalStateException("Cannot find android.os.Build$VERSION#SDK_INT. " +
+ "Field is needed to determine Android version.", e);
}
if (isApi28) {
@@ -76,6 +77,17 @@ 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 5ae5f2d..996008d 100644
--- a/dexmaker-tests/build.gradle
+++ b/dexmaker-tests/build.gradle
@@ -1,25 +1,12 @@
-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 28
- buildToolsVersion '28.0.3'
+ compileSdkVersion 32
defaultConfig {
applicationId 'com.linkedin.dexmaker'
- minSdkVersion 8
- targetSdkVersion 28
+ minSdkVersion 14
+ targetSdkVersion 32
versionCode 1
versionName VERSION_NAME
@@ -27,15 +14,9 @@ android {
}
}
-repositories {
- jcenter()
- google()
-}
-
dependencies {
implementation project(":dexmaker")
- //noinspection GradleDependency
- androidTestImplementation 'com.android.support.test:runner:0.5'
- androidTestImplementation 'junit:junit:4.12'
+ androidTestImplementation 'androidx.test:runner:1.4.0'
+ androidTestImplementation 'junit:junit:4.13.2'
}
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 af520e1..d718aaa 100644
--- a/dexmaker-tests/src/androidTest/java/com/android/dx/DexMakerTest.java
+++ b/dexmaker-tests/src/androidTest/java/com/android/dx/DexMakerTest.java
@@ -172,6 +172,26 @@ 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) {
@@ -481,6 +501,58 @@ 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);
@@ -1956,26 +2028,6 @@ 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");
@@ -2005,7 +2057,6 @@ 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 7e8762f..01b0bdb 100644
--- a/dexmaker/build.gradle
+++ b/dexmaker/build.gradle
@@ -1,32 +1,28 @@
-buildscript {
- repositories {
- maven {
- url "https://plugins.gradle.org/m2/"
- }
- }
- dependencies {
- classpath "net.ltgt.gradle:gradle-errorprone-plugin:0.0.13"
- }
+plugins {
+ id("net.ltgt.errorprone") version "1.3.0"
}
-apply plugin: "net.ltgt.errorprone"
+description = "A utility for doing compile or runtime code generation targeting Android's Dalvik VM"
+
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'
-repositories {
- jcenter()
+tasks.withType(JavaCompile) {
+ options.errorprone {
+ disable("StringSplitter")
+ }
}
-tasks.withType(JavaCompile) {
- options.compilerArgs += ["-Xep:StringSplitter:OFF"]
+javadoc {
+ options.addBooleanOption("Xdoclint:-html", true)
}
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 715d2b4..c0f2759 100644
--- a/dexmaker/src/main/java/com/android/dx/Code.java
+++ b/dexmaker/src/main/java/com/android/dx/Code.java
@@ -476,15 +476,27 @@ 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 e45ead0..b672c53 100644
--- a/dexmaker/src/main/java/com/android/dx/DexMaker.java
+++ b/dexmaker/src/main/java/com/android/dx/DexMaker.java
@@ -32,6 +32,7 @@ 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;
@@ -46,8 +47,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.PRIVATE;
-import static java.lang.reflect.Modifier.STATIC;
+import static java.lang.reflect.Modifier.*;
+;
/**
* Generates a <strong>D</strong>alvik <strong>EX</strong>ecutable (dex)
@@ -230,7 +231,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;
@@ -265,7 +266,7 @@ public final class DexMaker {
throw new IllegalStateException("already declared: " + method);
}
- int supportedFlags = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED
+ int supportedFlags = Modifier.ABSTRACT | Modifier.NATIVE | Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED
| Modifier.STATIC | Modifier.FINAL | Modifier.SYNCHRONIZED
| AccessFlags.ACC_SYNTHETIC | AccessFlags.ACC_BRIDGE;
if ((flags & ~supportedFlags) != 0) {
@@ -515,7 +516,12 @@ 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()) {
- return generateClassLoader(result, dexCache, parent);
+ if (!result.canWrite()) {
+ return generateClassLoader(result, dexCache, parent);
+ } else {
+ // Old writable files should be ignored and re-generated
+ result.delete();
+ }
}
byte[] dex = generate();
@@ -527,14 +533,23 @@ public final class DexMaker {
*
* TODO: load the dex from memory where supported.
*/
- 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();
+
+ 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();
+ }
+
return generateClassLoader(result, dexCache, parent);
}
@@ -645,6 +660,10 @@ 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(