Merge Android Pie into master
Bug: 112104996
Change-Id: Ife26a62a004cc7153634b9e2f6ca9a1c805a91a3
diff --git a/Android.mk b/Android.mk
index c708fc7..a00938b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -17,5 +17,5 @@
# include jacoco-cli in the dist directory to enable running it to generate a code-coverage report
ifeq ($(EMMA_INSTRUMENT),true)
-$(call dist-for-goals, dist_files, $(HOST_OUT_JAVA_LIBRARIES)/jacoco-cli.jar)
+$(call dist-for-goals, dist_files apps_only, $(HOST_OUT_JAVA_LIBRARIES)/jacoco-cli.jar)
endif
diff --git a/README.android b/README.android
index cad30c6..8fa2b90 100644
--- a/README.android
+++ b/README.android
@@ -14,3 +14,10 @@
1) Remove the creation of JmxRegistration in org.jacoco.agent.rt.internal.Agent.
2) Change default OutputMode to none in org.jacoco.core.runtime.AgentOptions
+3) Change the runtime to reduce dependencies on core libraries.
+ Previously, Offline's static initializer would eagerly create an
+ Agent, a process which has lots of dependencies. With this change,
+ Offline only eagerly creates a Map<Long, ExecutionData>, which is much
+ more lightweight. The Agent is only created when it's actually
+ needed. This makes it possible to instrument a lot of more core
+ libraries without creating a circular dependency at runtime.
diff --git a/org.jacoco.agent.rt.test/src/org/jacoco/agent/rt/internal/AgentTest.java b/org.jacoco.agent.rt.test/src/org/jacoco/agent/rt/internal/AgentTest.java
index 45bc8bd..9f9fc78 100644
--- a/org.jacoco.agent.rt.test/src/org/jacoco/agent/rt/internal/AgentTest.java
+++ b/org.jacoco.agent.rt.test/src/org/jacoco/agent/rt/internal/AgentTest.java
@@ -37,6 +37,7 @@
import org.jacoco.core.runtime.RuntimeData;
import org.jacoco.core.tools.ExecFileLoader;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
/**
@@ -132,6 +133,9 @@
}
@Test
+ // BEGIN android-change
+ @Ignore
+ // END android-change
public void startup_should_register_mbean_when_enabled() throws Exception {
options.setJmx(true);
Agent agent = createAgent();
diff --git a/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/Agent.java b/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/Agent.java
index 667a7d0..b4dd0c1 100644
--- a/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/Agent.java
+++ b/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/Agent.java
@@ -45,8 +45,26 @@
* @return global instance
*/
public static synchronized Agent getInstance(final AgentOptions options) {
+ // BEGIN android-change
+ return getInstance(options, new RuntimeData());
+ // END android-change
+ }
+
+ // BEGIN android-change
+ /**
+ * Returns a global instance which is already started, reusing an existing set of runtime
+ * data. If the method is called the first time the instance is created with the given
+ * options.
+ *
+ * @param options
+ * options to configure the instance
+ * @param data
+ * the runtime data to reuse
+ * @return global instance
+ */
+ public static synchronized Agent getInstance(final AgentOptions options, RuntimeData data) {
if (singleton == null) {
- final Agent agent = new Agent(options, IExceptionLogger.SYSTEM_ERR);
+ final Agent agent = new Agent(options, IExceptionLogger.SYSTEM_ERR, data);
agent.startup();
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
@@ -58,18 +76,26 @@
}
return singleton;
}
+ // END android-change
+ // BEGIN android-change
/**
- * Returns a global instance which is already started. If a agent has not
- * been initialized before this method will fail.
+ * Returns a global instance which is already started. If an agent has not
+ * been initialized then one will be created via {@link Offline#createAgent()}.
+ * This will capture any data written via {@link Offline#getProbes} prior to
+ * this call, but not subsequently.
*
* @return global instance
* @throws IllegalStateException
* if no Agent has been started yet
*/
+ // END android-change
public static synchronized Agent getInstance() throws IllegalStateException {
if (singleton == null) {
- throw new IllegalStateException("JaCoCo agent not started.");
+ // BEGIN android-change
+ // throw new IllegalStateException("JaCoCo agent not started.");
+ singleton = Offline.createAgent();
+ // END android-change
}
return singleton;
}
@@ -93,10 +119,28 @@
* logger used by this agent
*/
Agent(final AgentOptions options, final IExceptionLogger logger) {
+ // BEGIN android-change
+ this(options, logger, new RuntimeData());
+ // END android-change
+ }
+
+ // BEGIN android-change
+ /**
+ * Creates a new agent with the given agent options, reusing the given runtime data.
+ *
+ * @param options
+ * agent options
+ * @param logger
+ * logger used by this agent
+ * @param data
+ * the runtime data to reuse
+ */
+ private Agent(final AgentOptions options, final IExceptionLogger logger, RuntimeData data) {
this.options = options;
this.logger = logger;
- this.data = new RuntimeData();
+ this.data = data;
}
+ // END android-change
/**
* Returns the runtime data object created by this agent
diff --git a/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/Offline.java b/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/Offline.java
index 8b8b40c..7eac19f 100644
--- a/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/Offline.java
+++ b/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/Offline.java
@@ -11,8 +11,12 @@
*******************************************************************************/
package org.jacoco.agent.rt.internal;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Properties;
+import org.jacoco.core.data.ExecutionData;
+import org.jacoco.core.data.ExecutionDataStore;
import org.jacoco.core.runtime.AgentOptions;
import org.jacoco.core.runtime.RuntimeData;
@@ -22,14 +26,19 @@
*/
public final class Offline {
- private static final RuntimeData DATA;
+ // BEGIN android-change
+ // private static final RuntimeData DATA;
+ private static final Map<Long, ExecutionData> DATA = new HashMap<Long, ExecutionData>();
+ // END android-change
private static final String CONFIG_RESOURCE = "/jacoco-agent.properties";
- static {
- final Properties config = ConfigLoader.load(CONFIG_RESOURCE,
- System.getProperties());
- DATA = Agent.getInstance(new AgentOptions(config)).getData();
- }
+ // BEGIN android-change
+ // static {
+ // final Properties config = ConfigLoader.load(CONFIG_RESOURCE,
+ // System.getProperties());
+ // DATA = Agent.getInstance(new AgentOptions(config)).getData();
+ // }
+ // END android-change
private Offline() {
// no instances
@@ -48,8 +57,41 @@
*/
public static boolean[] getProbes(final long classid,
final String classname, final int probecount) {
- return DATA.getExecutionData(Long.valueOf(classid), classname,
- probecount).getProbes();
+ // BEGIN android-change
+ // return DATA.getExecutionData(Long.valueOf(classid), classname,
+ // probecount).getProbes();
+ synchronized (DATA) {
+ ExecutionData entry = DATA.get(classid);
+ if (entry == null) {
+ entry = new ExecutionData(classid, classname, probecount);
+ DATA.put(classid, entry);
+ } else {
+ entry.assertCompatibility(classid, classname, probecount);
+ }
+ return entry.getProbes();
+ }
+ // END android-change
}
+ // BEGIN android-change
+ /**
+ * Creates a default agent, using config loaded from the classpath resource and the system
+ * properties, and a runtime data instance populated with the execution data accumulated by
+ * the probes up until this call is made (subsequent probe updates will not be reflected in
+ * this agent).
+ *
+ * @return the new agent
+ */
+ static Agent createAgent() {
+ final Properties config = ConfigLoader.load(CONFIG_RESOURCE,
+ System.getProperties());
+ synchronized (DATA) {
+ ExecutionDataStore store = new ExecutionDataStore();
+ for (ExecutionData data : DATA.values()) {
+ store.put(data);
+ }
+ return Agent.getInstance(new AgentOptions(config), new RuntimeData(store));
+ }
+ }
+ // END android-change
}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/runtime/AgentOptionsTest.java b/org.jacoco.core.test/src/org/jacoco/core/runtime/AgentOptionsTest.java
index f65142e..155e3e8 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/runtime/AgentOptionsTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/runtime/AgentOptionsTest.java
@@ -47,7 +47,10 @@
assertFalse(options.getInclNoLocationClasses());
assertNull(options.getSessionId());
assertTrue(options.getDumpOnExit());
- assertEquals(AgentOptions.OutputMode.file, options.getOutput());
+ // BEGIN android-change
+ // assertEquals(AgentOptions.OutputMode.file, options.getOutput());
+ assertEquals(AgentOptions.OutputMode.none, options.getOutput());
+ // END android-change
assertEquals(AgentOptions.DEFAULT_ADDRESS, options.getAddress());
assertEquals(AgentOptions.DEFAULT_PORT, options.getPort());
assertNull(options.getClassDumpDir());
diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/RuntimeData.java b/org.jacoco.core/src/org/jacoco/core/runtime/RuntimeData.java
index ff249e7..74a51dc 100644
--- a/org.jacoco.core/src/org/jacoco/core/runtime/RuntimeData.java
+++ b/org.jacoco.core/src/org/jacoco/core/runtime/RuntimeData.java
@@ -37,10 +37,24 @@
* Creates a new runtime.
*/
public RuntimeData() {
- store = new ExecutionDataStore();
+ // BEGIN android-change
+ this(new ExecutionDataStore());
+ // END android-change
+ }
+
+ // BEGIN android-change
+ /**
+ * Creates a new runtime, reusing an existing {@link ExecutionDataStore}.
+ *
+ * @param store
+ * the store to reuse
+ */
+ public RuntimeData(ExecutionDataStore store) {
+ this.store = store;
sessionId = "<none>";
startTimeStamp = System.currentTimeMillis();
}
+ // END android-change
/**
* Sets a session identifier for this runtime. The identifier is used when