Upgrade jacoco to v0.8.4

Test: None
Change-Id: I4ca05dd439b98fabd6054bee728d85e3aa11486d
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..0689525
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,107 @@
+//
+// Copyright (C) 2016 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.
+//
+
+// Build jacoco-agent from sources for the platform
+//
+// Note: this is only intended to be used for the platform development. This is *not* intended
+// to be used in the SDK where apps can use the official jacoco release.
+java_library {
+    name: "jacocoagent",
+    installable: true,
+
+    srcs: [
+        "org.jacoco.core/src/**/*.java",
+        "org.jacoco.agent/src/**/*.java",
+        "org.jacoco.agent.rt/src/**/*.java",
+    ],
+
+    // Some Jacoco source files depend on classes that do not exist in Android.
+    // While these classes are not executed at runtime (because we use offline
+    // instrumentation), they will cause issues when compiling them with ART
+    // during dex pre-opting. Therefore, it would prevent from applying code
+    // coverage on classes in the bootclasspath (frameworks, services, ...) or
+    // system apps.
+    // Note: we still may need to update the source code to cut dependencies in
+    // mandatory jacoco classes.
+    exclude_srcs: [
+        "org.jacoco.core/src/org/jacoco/core/runtime/ModifiedSystemClassRuntime.java",
+        "org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/PreMain.java",
+        "org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/CoverageTransformer.java",
+        "org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/JmxRegistration.java",
+    ],
+
+    // In order to include Jacoco in core libraries, we cannot depend on
+    // anything in the bootclasspath (or we would create dependency cycle).
+    // Therefore we compile against the SDK android.jar which gives the same
+    // APIs Jacoco depends on.
+    sdk_version: "9",
+
+    // TODO(b/69671801): there's no bytecode on the device, so these shouldn't
+    // be necessary.
+    static_libs: [
+        "asm-7.0",
+        "asm-commons-7.0",
+        "asm-tree-7.0",
+    ],
+}
+
+// Generates stubs containing the classes that will be referenced by instrumented bytecode.
+droidstubs {
+    name: "jacoco-stubs-gen",
+    srcs: ["org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/Offline.java"],
+}
+
+// A stubs target containing the parts of JaCoCo that we need to add to the hidden API whitelist.
+java_library {
+    name: "jacoco-stubs",
+    compile_dex: true,
+    srcs: [":jacoco-stubs-gen"],
+}
+
+// Build jacoco-cli from sources for the platform
+
+// TODO(jeffrygaston) it'd be nice to keep the build process and/or list of source files in sync with
+// what is defined in the pom.xml files, although it's probably much more trouble than it's worth
+java_library_host {
+    name: "jacoco-cli",
+
+    manifest: "org.jacoco.cli/src/MANIFEST.MF",
+
+    srcs: [
+        "org.jacoco.core/src/**/*.java",
+        "org.jacoco.report/src/**/*.java",
+        "org.jacoco.cli/src/**/*.java",
+    ],
+
+    java_resource_dirs: [
+        "org.jacoco.core/src",
+        "org.jacoco.report/src",
+    ],
+
+    static_libs: [
+        "asm-7.0",
+        "asm-commons-7.0",
+        "asm-tree-7.0",
+        "args4j-2.0.28",
+    ],
+
+    dist: {
+        targets: [
+            "dist_files",
+            "apps_only",
+        ],
+    },
+}
diff --git a/FETCH_HEAD b/FETCH_HEAD
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/FETCH_HEAD
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..43947c9
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,18 @@
+name: "jacoco"
+description: "JaCoCo is a free Java code coverage library."
+third_party {
+  url {
+    type: HOMEPAGE
+    value: "https://www.jacoco.org/"
+  }
+  url {
+    type: GIT
+    value: "https://github.com/jacoco/jacoco.git"
+  }
+  version: "v0.8.4"
+  last_upgrade_date {
+    year: 2019
+    month: 5
+    day: 13
+  }
+}
diff --git a/MODULE_LICENSE_EPL b/MODULE_LICENSE_EPL
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_EPL
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..54fc346
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,14 @@
+License
+=======
+
+Copyright (c) 2009, 2015 Mountainminds GmbH & Co. KG and Contributors
+
+The JaCoCo Java Code Coverage Library and all included documentation is made
+available by Mountainminds GmbH & Co. KG, Munich. Except indicated below, the
+Content is provided to you under the terms and conditions of the Eclipse Public
+License Version 1.0 ("EPL"). A copy of the EPL is available at
+[http://www.eclipse.org/legal/epl-v10.html](http://www.eclipse.org/legal/epl-v10.html).
+
+Please visit
+[http://www.eclemma.org/jacoco/trunk/doc/license.html](http://www.eclemma.org/jacoco/trunk/doc/license.html)
+for the complete license information including third party licenses and trademarks.
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..607b5c3
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,3 @@
+# Default code reviewers picked from top 3 or more developers.
+# Please update this list if you find better candidates.
+allenhair@google.com
diff --git a/README.android b/README.android
new file mode 100644
index 0000000..8fa2b90
--- /dev/null
+++ b/README.android
@@ -0,0 +1,23 @@
+We build an equivalent of the jacoco-agent.jar which contains classes from org.jacoco.core,
+org.jacoco.agent and org.jacoco.agent.rt packages but also classes from asm 5.0.1.
+
+However, Jacoco depends on classes that do not exist in Android (java.lang.instrument.* or
+javax.management.*) for runtime instrumentation only. The ART compiler would reject those classes
+when they are either in the bootclasspath (core, frameworks, ...) or system apps.
+
+Since we only use offline instrumentation for code coverage (using Jack) and do not execute these
+classes at runtime, we simply not compile them here.
+
+We also need to modify the source code to cut dependencies to the classes that we exclude from the
+compilation. The changes are surrounded by "BEGIN android-change" and "END android-change". Here
+is the list of the changes:
+
+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/config.mk b/config.mk
new file mode 100644
index 0000000..d645621
--- /dev/null
+++ b/config.mk
@@ -0,0 +1,16 @@
+# Copyright (C) 2016 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.
+
+JACOCO_PACKAGE_NAME := org.jacoco.agent.rt.internal
+
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 8cc19a7..f21968c 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 fb5cf5f..b6debe1 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
@@ -121,7 +165,9 @@
 			output = createAgentOutput();
 			output.startup(options, data);
 			if (options.getJmx()) {
-				jmxRegistration = new JmxRegistration(this);
+// BEGIN android-change
+//				jmxRegistration = new JmxRegistration(this);
+// END android-change
 			}
 		} catch (final Exception e) {
 			logger.logExeption(e);
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 cadf606..69a9909 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.cli/src/MANIFEST.MF b/org.jacoco.cli/src/MANIFEST.MF
new file mode 100644
index 0000000..bae94d5
--- /dev/null
+++ b/org.jacoco.cli/src/MANIFEST.MF
@@ -0,0 +1,2 @@
+Main-Class: org.jacoco.cli.internal.Main

+

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 0fb7a2e..b811b52 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/jacoco.properties b/org.jacoco.core/src/org/jacoco/core/jacoco.properties
index 0949337..e2f9aca 100644
--- a/org.jacoco.core/src/org/jacoco/core/jacoco.properties
+++ b/org.jacoco.core/src/org/jacoco/core/jacoco.properties
@@ -1,3 +1,6 @@
-VERSION=$qualified.bundle.version$
-HOMEURL=$jacoco.home.url$
-RUNTIMEPACKAGE=$jacoco.runtime.package.name$
\ No newline at end of file
+#This file is supposed to be processed by Maven, but Android doesn't run Maven
+#So in Android we've filled in the resulting values below
+VERSION=0.7.10.201704181138.android
+HOMEURL=http://www.jacoco.org/jacoco
+RUNTIMEPACKAGE=org.jacoco.agent.rt.internal
+
diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/AgentOptions.java b/org.jacoco.core/src/org/jacoco/core/runtime/AgentOptions.java
index 583371a..60f03c0 100644
--- a/org.jacoco.core/src/org/jacoco/core/runtime/AgentOptions.java
+++ b/org.jacoco.core/src/org/jacoco/core/runtime/AgentOptions.java
@@ -494,7 +494,10 @@
 	 */
 	public OutputMode getOutput() {
 		final String value = options.get(OUTPUT);
-		return value == null ? OutputMode.file : OutputMode.valueOf(value);
+// BEGIN android-change
+//		return value == null ? OutputMode.file : OutputMode.valueOf(value);
+		return value == null ? OutputMode.none : OutputMode.valueOf(value);
+// END android-change
 	}
 
 	/**
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 7f6fe31..afb5b7f 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