Snap for 7474514 from e806b919fa39dea80bb0aa330d568c5464407e9e to mainline-media-swcodec-release

Change-Id: I4c9099bc5bf63fc988e512780c614af3c568f6d7
diff --git a/Android.bp b/Android.bp
index 7b7d3f4..726af1d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -18,6 +18,44 @@
 //
 // 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.
+package {
+    default_applicable_licenses: ["external_jacoco_license"],
+}
+
+// Added automatically by a large-scale-change that took the approach of
+// 'apply every license found to every target'. While this makes sure we respect
+// every license restriction, it may not be entirely correct.
+//
+// e.g. GPL in an MIT project might only apply to the contrib/ directory.
+//
+// Please consider splitting the single license below into multiple licenses,
+// taking care not to lose any license_kind information, and overriding the
+// default license using the 'licenses: [...]' property on targets as needed.
+//
+// For unused files, consider creating a 'fileGroup' with "//visibility:private"
+// to attach the license to, and including a comment whether the files may be
+// used in the current project.
+//
+// large-scale-change included anything that looked like it might be a license
+// text as a license_text. e.g. LICENSE, NOTICE, COPYING etc.
+//
+// Please consider removing redundant or irrelevant files from 'license_text:'.
+// See: http://go/android-license-faq
+license {
+    name: "external_jacoco_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+        "SPDX-license-identifier-BSD",
+        "SPDX-license-identifier-EPL",
+        "SPDX-license-identifier-MIT",
+    ],
+    license_text: [
+        "LICENSE.md",
+        "NOTICE",
+    ],
+}
+
 java_library {
     name: "jacocoagent",
     installable: true,
diff --git a/METADATA b/METADATA
index 43947c9..16d6e52 100644
--- a/METADATA
+++ b/METADATA
@@ -10,6 +10,7 @@
     value: "https://github.com/jacoco/jacoco.git"
   }
   version: "v0.8.4"
+  license_type: RECIPROCAL
   last_upgrade_date {
     year: 2019
     month: 5
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 ee9d40b..99a054e 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,13 +11,21 @@
  *******************************************************************************/
 package org.jacoco.agent.rt.internal;
 
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.channels.FileChannel;
+import java.nio.ByteBuffer;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Properties;
 
 import org.jacoco.core.data.ExecutionData;
+import org.jacoco.core.data.ExecutionDataWriter;
+import org.jacoco.core.data.ExecutionDataDelegate;
 import org.jacoco.core.data.IExecutionData;
 import org.jacoco.core.data.ExecutionDataStore;
+import org.jacoco.core.data.MappedExecutionData;
 import org.jacoco.core.runtime.AgentOptions;
 import org.jacoco.core.runtime.RuntimeData;
 
@@ -29,7 +37,8 @@
 
 	// BEGIN android-change
 	// private static final RuntimeData DATA;
-	private static final Map<Long, IExecutionData> DATA = new HashMap<Long, IExecutionData>();
+	private static final Map<Long, ExecutionDataDelegate> DATA = new HashMap<Long, ExecutionDataDelegate>();
+	private static FileChannel CHANNEL;
 	// END android-change
 	private static final String CONFIG_RESOURCE = "/jacoco-agent.properties";
 
@@ -62,9 +71,10 @@
 		// return DATA.getExecutionData(Long.valueOf(classid), classname,
 		//		probecount).getProbes();
 		synchronized (DATA) {
-			IExecutionData entry = DATA.get(classid);
+			ExecutionDataDelegate entry = DATA.get(classid);
 			if (entry == null) {
-				entry = new ExecutionData(classid, classname, probecount);
+				entry = new ExecutionDataDelegate(
+						classid, classname, probecount, CHANNEL);
 				DATA.put(classid, entry);
 			} else {
 				entry.assertCompatibility(classid, classname, probecount);
@@ -72,6 +82,49 @@
 			return entry;
 		}
 	}
+
+	/**
+	 * Enables memory-mapped execution data and converts existing
+	 * {@link ExecutionDataDelegate}s.
+	 */
+	public static void enableMemoryMappedData() {
+		try {
+			prepareFile(getPid());
+			for (ExecutionDataDelegate data : DATA.values()) {
+				data.convert(CHANNEL);
+			}
+		}  catch (IOException e) {
+			// TODO(olivernguyen): Add logging to debug issues more easily.
+		}
+	}
+
+	/**
+	 * Creates the output file that will be mapped for probe data.
+	 */
+	private static void prepareFile(int pid) throws IOException {
+		// Write header information to the file.
+		ByteBuffer headerBuffer = ByteBuffer.allocate(5);
+		headerBuffer.put(ExecutionDataWriter.BLOCK_HEADER);
+		headerBuffer.putChar(ExecutionDataWriter.MAGIC_NUMBER);
+		headerBuffer.putChar(ExecutionDataWriter.FORMAT_VERSION);
+		headerBuffer.flip();
+
+		// If this file already exists (due to pid re-usage), the previous coverage data
+		// will be lost when the file is overwritten.
+		File outputFile = new File("/data/misc/trace/jacoco-" + pid + ".mm.ec");
+		CHANNEL = new RandomAccessFile(outputFile, "rw").getChannel();
+		synchronized (CHANNEL) {
+			CHANNEL.write(headerBuffer);
+		}
+	}
+
+	/**
+	 * Helper function to determine the pid of this process.
+	 */
+	private static int getPid() throws IOException {
+		// Read /proc/self and resolve it to obtain its pid.
+		return Integer.parseInt(new File("/proc/self").getCanonicalFile().getName());
+	}
 	// END android-change
 
 	/**
diff --git a/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataDelegate.java b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataDelegate.java
new file mode 100644
index 0000000..7cbe989
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataDelegate.java
@@ -0,0 +1,197 @@
+// BEGIN android-change
+package org.jacoco.core.data;
+
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+
+/**
+ * Class that delegates calls to {@link IExecutionData} interface methods to another instance.
+ * Also has the ability to convert the underlying implementation to a {@link MappedExecutionData}
+ * instance.
+ */
+public class ExecutionDataDelegate implements IExecutionData {
+	private IExecutionData delegate;
+
+	public ExecutionDataDelegate(
+		final long id, final String name, final int probeCount, final FileChannel channel) {
+		if ((channel != null) && canMapData(name)) {
+			try {
+				delegate = new MappedExecutionData(id, name, probeCount, channel);
+			} catch (IOException e) {
+				delegate = new ExecutionData(id, name, probeCount);
+			}
+		} else {
+			delegate = new ExecutionData(id, name, probeCount);
+		}
+	}
+
+	/**
+	 * Converts the existing delegate into a {@link MappedExecutionData} instance if it is not
+	 * already one, and copies any probe data into the new instance.
+	 */
+	public synchronized void convert(final FileChannel channel) throws IOException {
+		if (!(delegate instanceof MappedExecutionData) && canMapData(getName())) {
+			IExecutionData newDelegate = new MappedExecutionData(
+				getId(), getName(), getProbeCount(), channel);
+			newDelegate.merge(delegate);
+			delegate = newDelegate;
+		}
+	}
+
+	/**
+	 * Determines if a class can be converted to memory-mapped.
+	 */
+	private static boolean canMapData(final String name) {
+		if (name.startsWith("android/app/")
+			|| name.startsWith("android/os/")
+			|| name.startsWith("com/android/internal/util/")
+			|| name.startsWith("java/")) {
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * Return the unique identifier for this class. The identifier is the CRC64
+	 * checksum of the raw class file definition.
+	 *
+	 * @return class identifier
+	 */
+	public long getId() {
+		return delegate.getId();
+	}
+
+	/**
+	 * The VM name of the class.
+	 *
+	 * @return VM name
+	 */
+	public String getName() {
+		return delegate.getName();
+	}
+
+	/**
+	 * The number of instrumentation probes for this class.
+	 *
+	 * @return number of probes
+	 */
+	public int getProbeCount() {
+		return delegate.getProbeCount();
+	}
+
+	/**
+	 * Returns a copy of the probe data as a boolean array.
+	 *
+	 * Changes to the returned array will not be reflected in the execution data.
+	 *
+	 * @return copy of the probe data
+	 */
+	public boolean[] getProbesCopy() {
+		return delegate.getProbesCopy();
+	}
+
+	/**
+	 * Sets all probes to <code>false</code>.
+	 */
+	public void reset() {
+		delegate.reset();
+	}
+
+	/**
+	 * Checks whether any probe has been hit.
+	 *
+	 * @return <code>true</code>, if at least one probe has been hit
+	 */
+	public boolean hasHits() {
+		return delegate.hasHits();
+	}
+
+	/**
+	 * Merges the given execution data into the probe data of this object. I.e.
+	 * a probe entry in this object is marked as executed (<code>true</code>) if
+	 * this probe or the corresponding other probe was executed. So the result
+	 * is
+	 *
+	 * <pre>
+	 * A or B
+	 * </pre>
+	 *
+	 * The probe array of the other object is not modified.
+	 *
+	 * @param other
+	 *            execution data to merge
+	 */
+	public void merge(final IExecutionData other) {
+		delegate.merge(other);
+	}
+
+	/**
+	 * Merges the given execution data into the probe data of this object. A
+	 * probe in this object is set to the value of <code>flag</code> if the
+	 * corresponding other probe was executed. For <code>flag==true</code> this
+	 * corresponds to
+	 *
+	 * <pre>
+	 * A or B
+	 * </pre>
+	 *
+	 * For <code>flag==false</code> this can be considered as a subtraction
+	 *
+	 * <pre>
+	 * A and not B
+	 * </pre>
+	 *
+	 * The probe array of the other object is not modified.
+	 *
+	 * @param other
+	 *            execution data to merge
+	 * @param flag
+	 *            merge mode
+	 */
+	public void merge(final IExecutionData other, boolean flag) {
+		delegate.merge(other, flag);
+	}
+
+	/**
+	 * Asserts that this execution data object is compatible with the given
+	 * parameters. The purpose of this check is to detect a very unlikely class
+	 * id collision.
+	 *
+	 * @param id
+	 *            other class id, must be the same
+	 * @param name
+	 *            other name, must be equal to this name
+	 * @param probecount
+	 *            probe data length, must be the same as for this data
+	 * @throws IllegalStateException
+	 *             if the given parameters do not match this instance
+	 */
+	public void assertCompatibility(final long id, final String name, final int probeCount)
+			throws IllegalStateException {
+		delegate.assertCompatibility(id, name, probeCount);
+	}
+
+	/**
+	 * Returns the execution data probe for a given index. A value of
+	 * <code>true</code> indicates that the corresponding probe was
+	 * executed.
+	 *
+	 * @param index  the probe's index to look up
+	 *
+	 * @return probe data
+	 */
+	public boolean getProbe(final int index) {
+		return delegate.getProbe(index);
+	}
+
+	/**
+	 * Sets the execution data probe at the given index to <code>true</code>.
+	 *
+	 * @param index  the probe's index to set
+	 * @param value  the value to set the probe to
+	 */
+	public void setProbe(final int index) {
+		delegate.setProbe(index);
+	}
+ }
+ // END android-change
diff --git a/org.jacoco.core/src/org/jacoco/core/data/IExecutionDataVisitor.java b/org.jacoco.core/src/org/jacoco/core/data/IExecutionDataVisitor.java
index 659aa51..14eabbe 100644
--- a/org.jacoco.core/src/org/jacoco/core/data/IExecutionDataVisitor.java
+++ b/org.jacoco.core/src/org/jacoco/core/data/IExecutionDataVisitor.java
@@ -25,7 +25,7 @@
 	 *            execution data for a class
 	 */
 	// BEGIN android-change
-	public void visitClassExecution(IExecutionData data);
+	void visitClassExecution(IExecutionData data);
 	// END android-change
 
 }
diff --git a/org.jacoco.core/src/org/jacoco/core/data/MappedExecutionData.java b/org.jacoco.core/src/org/jacoco/core/data/MappedExecutionData.java
new file mode 100644
index 0000000..7e74d17
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/data/MappedExecutionData.java
@@ -0,0 +1,304 @@
+// BEGIN android-change
+package org.jacoco.core.data;
+
+import static java.lang.String.format;
+
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+import java.nio.charset.Charset;
+import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
+
+import org.jacoco.core.data.ExecutionDataWriter;
+
+/**
+ * Memory-mapped execution data implementation.
+ *
+ * Stores the probe data in a section of a memory-mapped file, so that it will be available without
+ * requiring a flush of the coverage data.
+ */
+public final class MappedExecutionData implements IExecutionData {
+	private final long id;
+	private final String name;
+	private final int probeCount;
+
+	// Stores the memory-mapped byte buffer containing the probe data, packed as bits.
+	private MappedByteBuffer probeBuffer;
+
+	/**
+	 * Creates the mapped execution data.
+	 */
+	public MappedExecutionData(
+		final long id, final String name, final int probeCount, final FileChannel channel)
+			throws IOException {
+		this.id = id;
+		this.name = name;
+		this.probeCount = probeCount;
+
+		createMemoryMappedProbeArray(id, name, probeCount, channel);
+	}
+
+	public MappedExecutionData(
+			final long id,
+			final String name,
+			final boolean[] probes,
+			final FileChannel channel) throws IOException {
+		this.id = id;
+		this.name = name;
+		this.probeCount = probes.length;
+
+		createMemoryMappedProbeArray(id, name, probes.length, channel);
+		for (int i = 0; i < probes.length; i++) {
+			if (probes[i]) {
+				setProbe(i);
+			}
+		}
+	}
+
+	/**
+	 * Maps a section of the already-opened file for the probe data.
+	 *
+	 * @param id  the class id
+	 * @param name  the VM class name
+	 * @param probeCount  the number of probes for this class
+	 */
+	private void createMemoryMappedProbeArray(
+		final long id, final String name, final int probeCount, final FileChannel channel)
+			throws IOException {
+		synchronized (channel) {
+			int byteCount = (probeCount + 7) / 8;
+
+			// Write the ExecutionData block info.
+			ByteBuffer execDataBuffer = ByteBuffer.allocate(11);
+			execDataBuffer.put(ExecutionDataWriter.BLOCK_EXECUTIONDATA);
+			execDataBuffer.putLong(id);
+			execDataBuffer.putShort((short) name.length());
+			execDataBuffer.flip();
+			channel.write(execDataBuffer);
+			channel.write(ByteBuffer.wrap(name.getBytes(Charset.forName("UTF-8"))));
+
+			// Write the probe info and map part of this file for the probe data.
+			channel.write(toVarIntByteBuffer(probeCount));
+			probeBuffer = channel.map(FileChannel.MapMode.READ_WRITE, channel.position(), byteCount);
+			channel.position(channel.position() + byteCount);
+		}
+	}
+
+	/**
+	 * Writes a variable-length int to a {@link ByteBuffer}.
+	 *
+	 * @param value  the value to write
+	 * @return a ByteBuffer that can be used to write to a FileChannel containing the value
+	 */
+	private ByteBuffer toVarIntByteBuffer(int value) {
+		ByteBuffer buffer = ByteBuffer.allocate(5);
+		if (value == 0) {
+			buffer.put((byte) 0);
+		} else {
+			while (value > 0) {
+				if ((value & 0xFFFFFF80) == 0) {
+					buffer.put((byte) value);
+				} else {
+					buffer.put((byte) (0x80 | (value & 0x7F)));
+				}
+				value >>>= 7;
+			}
+		}
+		buffer.flip();
+		return buffer;
+	}
+
+	/**
+	 * Return the unique identifier for this class. The identifier is the CRC64
+	 * checksum of the raw class file definition.
+	 *
+	 * @return class identifier
+	 */
+	public long getId() {
+		return id;
+	}
+
+	/**
+	 * The VM name of the class.
+	 *
+	 * @return VM name
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * The number of instrumentation probes for this class.
+	 *
+	 * @return number of probes
+	 */
+	public int getProbeCount() {
+		return probeCount;
+	}
+
+	/**
+	 * Returns a copy of the probe data as a boolean array.
+	 *
+	 * Changes to the returned array will not be reflected in the execution data.
+	 *
+	 * @return copy of the probe data
+	 */
+	public boolean[] getProbesCopy() {
+		final int bytes = (probeCount + 7) / 8;
+		boolean[] probes = new boolean[probeCount];
+		for (int index = 0; index < probeCount; index += 8) {
+			byte byteProbe = probeBuffer.get(index / 8);
+			for (int bit = 0; (bit < 8) && ((index + bit) < probeCount); bit++) {
+				probes[index + bit] = ((byteProbe & 0x1) > 0);
+				byteProbe >>>= 1;
+			}
+		}
+		return probes;
+	}
+
+	/**
+	 * Sets all probes to <code>false</code>.
+	 */
+	public void reset() {
+		final int bytes = (probeCount + 7) / 8;
+		synchronized (probeBuffer) {
+			for (int i = 0; i < bytes; i++) {
+				probeBuffer.put(i, (byte) 0);
+			}
+		}
+	}
+
+	/**
+	 * Checks whether any probe has been hit.
+	 *
+	 * @return <code>true</code>, if at least one probe has been hit
+	 */
+	public boolean hasHits() {
+		final int bytes = (probeCount + 7) / 8;
+		synchronized (probeBuffer) {
+			for (int i = 0; i < bytes; i++) {
+				if (probeBuffer.get(i) > 0) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Merges the given execution data into the probe data of this object. I.e.
+	 * a probe entry in this object is marked as executed (<code>true</code>) if
+	 * this probe or the corresponding other probe was executed. So the result
+	 * is
+	 *
+	 * <pre>
+	 * A or B
+	 * </pre>
+	 *
+	 * The probe array of the other object is not modified.
+	 *
+	 * @param other
+	 *            execution data to merge
+	 */
+	public void merge(final IExecutionData other) {
+		merge(other, true);
+	}
+
+	/**
+	 * Merges the given execution data into the probe data of this object. A
+	 * probe in this object is set to the value of <code>flag</code> if the
+	 * corresponding other probe was executed. For <code>flag==true</code> this
+	 * corresponds to
+	 *
+	 * <pre>
+	 * A or B
+	 * </pre>
+	 *
+	 * For <code>flag==false</code> this can be considered as a subtraction
+	 *
+	 * <pre>
+	 * A and not B
+	 * </pre>
+	 *
+	 * The probe array of the other object is not modified.
+	 *
+	 * @param other
+	 *            execution data to merge
+	 * @param flag
+	 *            merge mode
+	 */
+	public void merge(final IExecutionData other, final boolean flag) {
+		synchronized (probeBuffer) {
+			for (int i = 0; i < probeCount; i++) {
+				if (other.getProbe(i)) {
+					setProbe(i);
+				}
+			}
+		}
+	}
+
+	/**
+	 * Asserts that this execution data object is compatible with the given
+	 * parameters. The purpose of this check is to detect a very unlikely class
+	 * id collision.
+	 *
+	 * @param id
+	 *            other class id, must be the same
+	 * @param name
+	 *            other name, must be equal to this name
+	 * @param probecount
+	 *            probe data length, must be the same as for this data
+	 * @throws IllegalStateException
+	 *             if the given parameters do not match this instance
+	 */
+	public void assertCompatibility(final long id, final String name, final int probeCount)
+		throws IllegalStateException {
+		if (this.id != id) {
+			throw new IllegalStateException(format(
+					"Different ids (%016x and %016x).", Long.valueOf(this.id),
+					Long.valueOf(id)));
+		}
+		if (!this.name.equals(name)) {
+			throw new IllegalStateException(format(
+					"Different class names %s and %s for id %016x.", this.name,
+					name, Long.valueOf(id)));
+		}
+		if (this.probeCount != probeCount) {
+			throw new IllegalStateException(format(
+					"Incompatible execution data for class %s with id %016x.",
+					name, Long.valueOf(id)));
+		}
+	}
+
+	/**
+	 * Returns the execution data probe for a given index. A value of
+	 * <code>true</code> indicates that the corresponding probe was
+	 * executed.
+	 *
+	 * @param index  the probe's index to look up
+	 *
+	 * @return probe data
+	 */
+	public boolean getProbe(final int index) {
+		int offset = index / 8;
+		int bit = 1 << (index % 8);
+		return (probeBuffer.get(offset) & bit) != 0;
+	}
+
+	/**
+	 * Sets the execution data probe at the given index to <code>true</code>.
+	 *
+	 * @param index  the probe's index to set
+	 */
+	public void setProbe(final int index) {
+		int offset = index / 8;
+		int bit = 1 << (index % 8);
+		byte currentValue = probeBuffer.get(offset);
+		if ((currentValue & bit) == 0) {
+			synchronized (probeBuffer) {
+				probeBuffer.put(offset, (byte) (probeBuffer.get(offset) | bit));
+			}
+		}
+	}
+}
+// END android-change