From b9499e9c56ecedd457a6d2f3357c6e5dc37cde3e Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Thu, 23 Apr 2020 16:42:09 -0700 Subject: Add license type: EPL is a RECIPROCAL license Bug: 68860345 Bug: 69058154 Bug: 151953481 Test: no code changes Change-Id: I9c68a95da9b40beea49a76560a817ca678922121 --- METADATA | 1 + 1 file changed, 1 insertion(+) diff --git a/METADATA b/METADATA index 43947c97..16d6e52d 100644 --- a/METADATA +++ b/METADATA @@ -10,6 +10,7 @@ third_party { value: "https://github.com/jacoco/jacoco.git" } version: "v0.8.4" + license_type: RECIPROCAL last_upgrade_date { year: 2019 month: 5 -- cgit v1.2.3 From 28558ef2ec7635c0a7e10fbb1fe9b8a80d32b636 Mon Sep 17 00:00:00 2001 From: Oliver Nguyen Date: Thu, 9 Jul 2020 15:11:30 -0700 Subject: Add IExecutionData interface and move all usage to the interface. Abstracts the underlying execution data implementation to allow for more complex execution data storage mechanisms. For offline instrumentation, classes store the IExecutionData object and make calls into it to set probe data. This results in additional overhead of looking up the vtable for the interface and making the method call, rather than just directly setting the value in the boolean array. Bug: 147904124 Test: m EMMA_INSTRUMENT=true EMMA_INSTRUMENT_FRAMEWORK=true and verify Java coverage collection and parsing Change-Id: I41235626b1040a6a21c6aef300f2dfe064393e1f --- Android.bp | 5 +- .../src/org/jacoco/agent/rt/internal/Offline.java | 18 +-- .../org/jacoco/cli/internal/commands/ExecInfo.java | 10 +- .../src/org/jacoco/core/analysis/Analyzer.java | 8 +- .../src/org/jacoco/core/data/ExecutionData.java | 52 +++++++-- .../org/jacoco/core/data/ExecutionDataStore.java | 48 +++++--- .../org/jacoco/core/data/ExecutionDataWriter.java | 8 +- .../src/org/jacoco/core/data/IExecutionData.java | 129 +++++++++++++++++++++ .../jacoco/core/data/IExecutionDataVisitor.java | 4 +- .../jacoco/core/internal/instr/InstrSupport.java | 8 +- .../jacoco/core/internal/instr/ProbeInserter.java | 17 +-- .../src/org/jacoco/core/runtime/LoggerRuntime.java | 4 +- .../OfflineInstrumentationAccessGenerator.java | 6 +- .../src/org/jacoco/core/runtime/RuntimeData.java | 20 ++-- .../src/org/jacoco/report/IReportVisitor.java | 6 +- .../src/org/jacoco/report/MultiReportVisitor.java | 6 +- .../src/org/jacoco/report/check/RulesChecker.java | 6 +- .../src/org/jacoco/report/csv/CSVFormatter.java | 6 +- .../src/org/jacoco/report/html/HTMLFormatter.java | 10 +- .../report/internal/html/page/SessionsPage.java | 22 ++-- .../src/org/jacoco/report/xml/XMLFormatter.java | 6 +- 21 files changed, 313 insertions(+), 86 deletions(-) create mode 100644 org.jacoco.core/src/org/jacoco/core/data/IExecutionData.java diff --git a/Android.bp b/Android.bp index 0641bdec..7b7d3f49 100644 --- a/Android.bp +++ b/Android.bp @@ -66,7 +66,10 @@ java_library { // 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"], + srcs: [ + "org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/Offline.java", + "org.jacoco.core/src/org/jacoco/core/data/IExecutionData.java", + ], } // A stubs target containing the parts of JaCoCo that we need to add to the hidden API whitelist. 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 69a9909e..ee9d40b1 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 @@ -16,6 +16,7 @@ import java.util.Map; import java.util.Properties; import org.jacoco.core.data.ExecutionData; +import org.jacoco.core.data.IExecutionData; import org.jacoco.core.data.ExecutionDataStore; import org.jacoco.core.runtime.AgentOptions; import org.jacoco.core.runtime.RuntimeData; @@ -28,7 +29,7 @@ public final class Offline { // BEGIN android-change // private static final RuntimeData DATA; - private static final Map DATA = new HashMap(); + private static final Map DATA = new HashMap(); // END android-change private static final String CONFIG_RESOURCE = "/jacoco-agent.properties"; @@ -44,6 +45,7 @@ public final class Offline { // no instances } + // BEGIN android-change /** * API for offline instrumented classes. * @@ -53,27 +55,25 @@ public final class Offline { * VM class name * @param probecount * probe count for this class - * @return probe array instance for this class + * @return IExecutionData instance for this class */ - public static boolean[] getProbes(final long classid, + public static IExecutionData getExecutionData(final long classid, final String classname, final int probecount) { - // BEGIN android-change // return DATA.getExecutionData(Long.valueOf(classid), classname, // probecount).getProbes(); synchronized (DATA) { - ExecutionData entry = DATA.get(classid); + IExecutionData 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(); + return entry; } - // END android-change } + // 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 @@ -87,7 +87,7 @@ public final class Offline { System.getProperties()); synchronized (DATA) { ExecutionDataStore store = new ExecutionDataStore(); - for (ExecutionData data : DATA.values()) { + for (IExecutionData data : DATA.values()) { store.put(data); } return Agent.getInstance(new AgentOptions(config), new RuntimeData(store)); diff --git a/org.jacoco.cli/src/org/jacoco/cli/internal/commands/ExecInfo.java b/org.jacoco.cli/src/org/jacoco/cli/internal/commands/ExecInfo.java index cacf4cbe..4519d28f 100644 --- a/org.jacoco.cli/src/org/jacoco/cli/internal/commands/ExecInfo.java +++ b/org.jacoco.cli/src/org/jacoco/cli/internal/commands/ExecInfo.java @@ -20,7 +20,7 @@ import java.util.Date; import java.util.List; import org.jacoco.cli.internal.Command; -import org.jacoco.core.data.ExecutionData; +import org.jacoco.core.data.IExecutionData; import org.jacoco.core.data.ExecutionDataReader; import org.jacoco.core.data.IExecutionDataVisitor; import org.jacoco.core.data.ISessionInfoVisitor; @@ -68,13 +68,15 @@ public class ExecInfo extends Command { } }); reader.setExecutionDataVisitor(new IExecutionDataVisitor() { - public void visitClassExecution(final ExecutionData data) { + // BEGIN android-change + public void visitClassExecution(final IExecutionData data) { out.printf("%016x %3d of %3d %s%n", Long.valueOf(data.getId()), - Integer.valueOf(getHitCount(data.getProbes())), - Integer.valueOf(data.getProbes().length), + Integer.valueOf(getHitCount(data.getProbesCopy())), + Integer.valueOf(data.getProbeCount()), data.getName()); } + // END android-change }); reader.read(); in.close(); diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java b/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java index 76b7be3c..7759b89d 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java @@ -20,7 +20,7 @@ import java.util.zip.GZIPInputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; -import org.jacoco.core.data.ExecutionData; +import org.jacoco.core.data.IExecutionData; import org.jacoco.core.data.ExecutionDataStore; import org.jacoco.core.internal.ContentTypeDetector; import org.jacoco.core.internal.InputStreams; @@ -78,16 +78,18 @@ public class Analyzer { */ private ClassVisitor createAnalyzingVisitor(final long classid, final String className) { - final ExecutionData data = executionData.get(classid); + // BEGIN android-change + final IExecutionData data = executionData.get(classid); final boolean[] probes; final boolean noMatch; if (data == null) { probes = null; noMatch = executionData.contains(className); } else { - probes = data.getProbes(); + probes = data.getProbesCopy(); noMatch = false; } + // END android-change final ClassCoverageImpl coverage = new ClassCoverageImpl(className, classid, noMatch); final ClassAnalyzer analyzer = new ClassAnalyzer(coverage, probes, diff --git a/org.jacoco.core/src/org/jacoco/core/data/ExecutionData.java b/org.jacoco.core/src/org/jacoco/core/data/ExecutionData.java index d98775eb..a728e033 100644 --- a/org.jacoco.core/src/org/jacoco/core/data/ExecutionData.java +++ b/org.jacoco.core/src/org/jacoco/core/data/ExecutionData.java @@ -20,7 +20,9 @@ import java.util.Arrays; * has to be taken about the probe data array of type boolean[] * which can be modified. */ -public final class ExecutionData { +// BEGIN android-change +public final class ExecutionData implements IExecutionData { +// END android-change private final long id; @@ -81,15 +83,43 @@ public final class ExecutionData { return name; } + // BEGIN android-change /** - * Returns the execution data probes. A value of true indicates - * that the corresponding probe was executed. + * Returns a copy of the current probe values. + * + * @return copy of the probe array + */ + public boolean[] getProbesCopy() { + return Arrays.copyOf(probes, probes.length); + } + + /** + * The number of probes in this ExecutionData. + * + * @return the number of probes + */ + public int getProbeCount() { + return probes.length; + } + + /** + * Returns the execution data probe for a given index. A value of + * true indicates that the corresponding probe was + * executed. * * @return probe data */ - public boolean[] getProbes() { - return probes; + public boolean getProbe(final int index) { + return probes[index]; + } + + /** + * Sets the execution data probe for a given index to true. + */ + public void setProbe(final int index) { + probes[index] = true; } + // END android-change /** * Sets all probes to false. @@ -127,7 +157,9 @@ public final class ExecutionData { * @param other * execution data to merge */ - public void merge(final ExecutionData other) { + // BEGIN android-change + public void merge(final IExecutionData other) { + // END android-change merge(other, true); } @@ -154,10 +186,12 @@ public final class ExecutionData { * @param flag * merge mode */ - public void merge(final ExecutionData other, final boolean flag) { + public void merge(final IExecutionData other, final boolean flag) { + // BEGIN android-change assertCompatibility(other.getId(), other.getName(), - other.getProbes().length); - final boolean[] otherData = other.getProbes(); + other.getProbeCount()); + final boolean[] otherData = other.getProbesCopy(); + // END android-change for (int i = 0; i < probes.length; i++) { if (otherData[i]) { probes[i] = flag; diff --git a/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataStore.java b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataStore.java index 3e567a3b..ce0bec47 100644 --- a/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataStore.java +++ b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataStore.java @@ -28,7 +28,9 @@ import java.util.Set; */ public final class ExecutionDataStore implements IExecutionDataVisitor { - private final Map entries = new HashMap(); + // BEGIN android-change + private final Map entries = new HashMap(); + // END android-change private final Set names = new HashSet(); @@ -44,9 +46,11 @@ public final class ExecutionDataStore implements IExecutionDataVisitor { * to a corresponding one, that is already contained * @see ExecutionData#assertCompatibility(long, String, int) */ - public void put(final ExecutionData data) throws IllegalStateException { + // BEGIN android-change + public void put(final IExecutionData data) throws IllegalStateException { final Long id = Long.valueOf(data.getId()); - final ExecutionData entry = entries.get(id); + final IExecutionData entry = entries.get(id); + // END android-change if (entry == null) { entries.put(id, data); names.add(data.getName()); @@ -68,9 +72,11 @@ public final class ExecutionDataStore implements IExecutionDataVisitor { * to a corresponding one, that is already contained * @see ExecutionData#assertCompatibility(long, String, int) */ - public void subtract(final ExecutionData data) throws IllegalStateException { + // BEGIN android-change + public void subtract(final IExecutionData data) throws IllegalStateException { final Long id = Long.valueOf(data.getId()); - final ExecutionData entry = entries.get(id); + final IExecutionData entry = entries.get(id); + // END android-change if (entry != null) { entry.merge(data, false); } @@ -84,7 +90,9 @@ public final class ExecutionDataStore implements IExecutionDataVisitor { * @see #subtract(ExecutionData) */ public void subtract(final ExecutionDataStore store) { - for (final ExecutionData data : store.getContents()) { + // BEGIN android-change + for (final IExecutionData data : store.getContents()) { + // END android-change subtract(data); } } @@ -97,7 +105,9 @@ public final class ExecutionDataStore implements IExecutionDataVisitor { * class id * @return execution data or null */ - public ExecutionData get(final long id) { + // BEGIN android-change + public IExecutionData get(final long id) { + // END android-change return entries.get(Long.valueOf(id)); } @@ -126,9 +136,11 @@ public final class ExecutionDataStore implements IExecutionDataVisitor { * probe data length * @return execution data */ - public ExecutionData get(final Long id, final String name, + // BEGIN android-change + public IExecutionData get(final Long id, final String name, final int probecount) { - ExecutionData entry = entries.get(id); + IExecutionData entry = entries.get(id); + // END android-change if (entry == null) { entry = new ExecutionData(id.longValue(), name, probecount); entries.put(id, entry); @@ -144,7 +156,9 @@ public final class ExecutionDataStore implements IExecutionDataVisitor { * execution data objects itself are not removed. */ public void reset() { - for (final ExecutionData executionData : this.entries.values()) { + // BEGIN android-change + for (final IExecutionData executionData : this.entries.values()) { + // END android-change executionData.reset(); } } @@ -154,9 +168,11 @@ public final class ExecutionDataStore implements IExecutionDataVisitor { * * @return current contents */ - public Collection getContents() { - return new ArrayList(entries.values()); + // BEGIN android-change + public Collection getContents() { + return new ArrayList(entries.values()); } + // END android-change /** * Writes the content of the store to the given visitor interface. @@ -165,14 +181,18 @@ public final class ExecutionDataStore implements IExecutionDataVisitor { * interface to write content to */ public void accept(final IExecutionDataVisitor visitor) { - for (final ExecutionData data : getContents()) { + // BEGIN android-change + for (final IExecutionData data : getContents()) { + // END android-change visitor.visitClassExecution(data); } } // === IExecutionDataVisitor === - public void visitClassExecution(final ExecutionData data) { + // BEGIN android-change + public void visitClassExecution(final IExecutionData data) { + // END android-change put(data); } } diff --git a/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataWriter.java b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataWriter.java index e697dda3..bdf3445d 100644 --- a/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataWriter.java +++ b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataWriter.java @@ -94,13 +94,17 @@ public class ExecutionDataWriter implements ISessionInfoVisitor, } } - public void visitClassExecution(final ExecutionData data) { + // BEGIN android-change + public void visitClassExecution(final IExecutionData data) { + // END android-change if (data.hasHits()) { try { out.writeByte(BLOCK_EXECUTIONDATA); out.writeLong(data.getId()); out.writeUTF(data.getName()); - out.writeBooleanArray(data.getProbes()); + // BEGIN android-change + out.writeBooleanArray(data.getProbesCopy()); + // END android-change } catch (final IOException e) { throw new RuntimeException(e); } diff --git a/org.jacoco.core/src/org/jacoco/core/data/IExecutionData.java b/org.jacoco.core/src/org/jacoco/core/data/IExecutionData.java new file mode 100644 index 00000000..289c3726 --- /dev/null +++ b/org.jacoco.core/src/org/jacoco/core/data/IExecutionData.java @@ -0,0 +1,129 @@ +// BEGIN android-change +package org.jacoco.core.data; + +/** + * Interface for interacting with execution data for a single Java class. + */ +public interface IExecutionData { + + /** + * Return the unique identifier for this class. The identifier is the CRC64 + * checksum of the raw class file definition. + * + * @return class identifier + */ + public abstract long getId(); + + /** + * The VM name of the class. + * + * @return VM name + */ + public abstract String getName(); + + /** + * The number of instrumentation probes for this class. + * + * @return number of probes + */ + public abstract int 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 abstract boolean[] getProbesCopy(); + + /** + * Sets all probes to false. + */ + public abstract void reset(); + + /** + * Checks whether any probe has been hit. + * + * @return true, if at least one probe has been hit + */ + public abstract boolean 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 (true) if + * this probe or the corresponding other probe was executed. So the result + * is + * + *
+	 * A or B
+	 * 
+ * + * The probe array of the other object is not modified. + * + * @param other + * execution data to merge + */ + public abstract void merge(final IExecutionData other); + + /** + * Merges the given execution data into the probe data of this object. A + * probe in this object is set to the value of flag if the + * corresponding other probe was executed. For flag==true this + * corresponds to + * + *
+	 * A or B
+	 * 
+ * + * For flag==false this can be considered as a subtraction + * + *
+	 * A and not B
+	 * 
+ * + * The probe array of the other object is not modified. + * + * @param other + * execution data to merge + * @param flag + * merge mode + */ + public abstract void merge(final IExecutionData other, boolean 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 abstract void assertCompatibility(final long id, final String name, final int probeCount) throws IllegalStateException; + + /** + * Returns the execution data probe for a given index. A value of + * true indicates that the corresponding probe was + * executed. + * + * @param index the probe's index to look up + * + * @return probe data + */ + public abstract boolean getProbe(final int index); + + /** + * Sets the execution data probe at the given index to true. + * + * @param index the probe's index to set + * @param value the value to set the probe to + */ + public abstract void setProbe(final int 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 6cea7c57..14eabbe7 100644 --- a/org.jacoco.core/src/org/jacoco/core/data/IExecutionDataVisitor.java +++ b/org.jacoco.core/src/org/jacoco/core/data/IExecutionDataVisitor.java @@ -24,6 +24,8 @@ public interface IExecutionDataVisitor { * @param data * execution data for a class */ - void visitClassExecution(ExecutionData data); + // BEGIN android-change + void visitClassExecution(IExecutionData data); + // END android-change } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java index 85e83a3a..4d4e1ba1 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java @@ -77,7 +77,9 @@ public final class InstrSupport { * Data type of the field that stores coverage information for a class ( * boolean[]). */ - public static final String DATAFIELD_DESC = "[Z"; + // BEGIN android-change + public static final String DATAFIELD_DESC = "Lorg/jacoco/core/data/IExecutionData;"; + // END android-change // === Init Method === @@ -89,7 +91,9 @@ public final class InstrSupport { /** * Descriptor of the initialization method. */ - public static final String INITMETHOD_DESC = "()[Z"; + // BEGIN android-change + public static final String INITMETHOD_DESC = "()Lorg/jacoco/core/data/IExecutionData;"; + // END android-change /** * Access modifiers of the initialization method. diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java index 63fbf765..0cac8f8f 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java @@ -67,25 +67,20 @@ class ProbeInserter extends MethodVisitor implements IProbeInserter { public void insertProbe(final int id) { - // For a probe we set the corresponding position in the boolean[] array - // to true. + // BEGIN android-change + // For a probe we call setProbe on the IExecutionData object. mv.visitVarInsn(Opcodes.ALOAD, variable); - // Stack[0]: [Z + // Stack[0]: Lorg/jacoco/core/data/IExecutionData; InstrSupport.push(mv, id); // Stack[1]: I - // Stack[0]: [Z + // Stack[0]: Lorg/jacoco/core/data/IExecutionData; - mv.visitInsn(Opcodes.ICONST_1); - - // Stack[2]: I - // Stack[1]: I - // Stack[0]: [Z - - mv.visitInsn(Opcodes.BASTORE); + mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, "org/jacoco/core/data/IExecutionData", "setProbe", "(I)V", true); + // END android-change } @Override diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/LoggerRuntime.java b/org.jacoco.core/src/org/jacoco/core/runtime/LoggerRuntime.java index 72553956..bef42030 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/LoggerRuntime.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/LoggerRuntime.java @@ -168,7 +168,9 @@ public class LoggerRuntime extends AbstractRuntime { @Override public void publish(final LogRecord record) { if (key.equals(record.getMessage())) { - data.getProbes(record.getParameters()); + // BEGIN android-change + data.getExecutionData(record.getParameters()); + // END android-change } } diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/OfflineInstrumentationAccessGenerator.java b/org.jacoco.core/src/org/jacoco/core/runtime/OfflineInstrumentationAccessGenerator.java index af6671ee..a5e88b60 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/OfflineInstrumentationAccessGenerator.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/OfflineInstrumentationAccessGenerator.java @@ -50,8 +50,10 @@ public class OfflineInstrumentationAccessGenerator implements mv.visitLdcInsn(Long.valueOf(classid)); mv.visitLdcInsn(classname); InstrSupport.push(mv, probecount); - mv.visitMethodInsn(Opcodes.INVOKESTATIC, runtimeClassName, "getProbes", - "(JLjava/lang/String;I)[Z", false); + // BEGIN android-change + mv.visitMethodInsn(Opcodes.INVOKESTATIC, runtimeClassName, "getExecutionData", + "(JLjava/lang/String;I)Lorg/jacoco/core/data/IExecutionData;", false); + // END android-change return 4; } 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 afb5b7f3..c0fbb654 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/RuntimeData.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/RuntimeData.java @@ -11,7 +11,7 @@ *******************************************************************************/ package org.jacoco.core.runtime; -import org.jacoco.core.data.ExecutionData; +import org.jacoco.core.data.IExecutionData; import org.jacoco.core.data.ExecutionDataStore; import org.jacoco.core.data.IExecutionDataVisitor; import org.jacoco.core.data.ISessionInfoVisitor; @@ -128,15 +128,18 @@ public class RuntimeData { * probe data length * @return execution data */ - public ExecutionData getExecutionData(final Long id, final String name, + // BEGIN android-change + public IExecutionData getExecutionData(final Long id, final String name, final int probecount) { + // END android-change synchronized (store) { return store.get(id, name, probecount); } } + // BEGIN android-change /** - * Retrieves the execution probe array for a given class. The passed + * Retrieves the execution data for a given class. The passed * {@link Object} array instance is used for parameters and the return value * as follows. Call parameters: * @@ -149,18 +152,19 @@ public class RuntimeData { * Return value: * *
    - *
  • args[0]: probe array (boolean[]) + *
  • args[0]: execution data ({@link IExecutionData}) *
* * @param args * parameter array of length 3 */ - public void getProbes(final Object[] args) { + public void getExecutionData(final Object[] args) { final Long classid = (Long) args[0]; final String name = (String) args[1]; final int probecount = ((Integer) args[2]).intValue(); - args[0] = getExecutionData(classid, name, probecount).getProbes(); + args[0] = getExecutionData(classid, name, probecount); } + // END android-change /** * In violation of the regular semantic of {@link Object#equals(Object)} @@ -173,7 +177,9 @@ public class RuntimeData { @Override public boolean equals(final Object args) { if (args instanceof Object[]) { - getProbes((Object[]) args); + // BEGIN android-change + getExecutionData((Object[]) args); + // END android-change } return super.equals(args); } diff --git a/org.jacoco.report/src/org/jacoco/report/IReportVisitor.java b/org.jacoco.report/src/org/jacoco/report/IReportVisitor.java index db36796d..1cf4aed4 100644 --- a/org.jacoco.report/src/org/jacoco/report/IReportVisitor.java +++ b/org.jacoco.report/src/org/jacoco/report/IReportVisitor.java @@ -15,7 +15,7 @@ import java.io.IOException; import java.util.Collection; import java.util.List; -import org.jacoco.core.data.ExecutionData; +import org.jacoco.core.data.IExecutionData; import org.jacoco.core.data.SessionInfo; /** @@ -39,7 +39,9 @@ public interface IReportVisitor extends IReportGroupVisitor { * in case of IO problems with the report writer */ void visitInfo(List sessionInfos, - Collection executionData) throws IOException; + // BEGIN android-change + Collection executionData) throws IOException; + // END android-change /** * Has to be called after all report data has been emitted. diff --git a/org.jacoco.report/src/org/jacoco/report/MultiReportVisitor.java b/org.jacoco.report/src/org/jacoco/report/MultiReportVisitor.java index 3cd5e558..f4fefa85 100644 --- a/org.jacoco.report/src/org/jacoco/report/MultiReportVisitor.java +++ b/org.jacoco.report/src/org/jacoco/report/MultiReportVisitor.java @@ -17,7 +17,7 @@ import java.util.Collection; import java.util.List; import org.jacoco.core.analysis.IBundleCoverage; -import org.jacoco.core.data.ExecutionData; +import org.jacoco.core.data.IExecutionData; import org.jacoco.core.data.SessionInfo; /** @@ -41,7 +41,9 @@ public class MultiReportVisitor extends MultiGroupVisitor implements } public void visitInfo(final List sessionInfos, - final Collection executionData) throws IOException { + // BEGIN android-change + final Collection executionData) throws IOException { + // END android-chnage for (final IReportVisitor v : visitors) { v.visitInfo(sessionInfos, executionData); } diff --git a/org.jacoco.report/src/org/jacoco/report/check/RulesChecker.java b/org.jacoco.report/src/org/jacoco/report/check/RulesChecker.java index cc6acf04..f7435600 100644 --- a/org.jacoco.report/src/org/jacoco/report/check/RulesChecker.java +++ b/org.jacoco.report/src/org/jacoco/report/check/RulesChecker.java @@ -17,7 +17,7 @@ import java.util.Collection; import java.util.List; import org.jacoco.core.analysis.IBundleCoverage; -import org.jacoco.core.data.ExecutionData; +import org.jacoco.core.data.IExecutionData; import org.jacoco.core.data.SessionInfo; import org.jacoco.report.ILanguageNames; import org.jacoco.report.IReportGroupVisitor; @@ -86,7 +86,9 @@ public class RulesChecker { } public void visitInfo(final List sessionInfos, - final Collection executionData) + // BEGIN android-change + final Collection executionData) + // END android-change throws IOException { } diff --git a/org.jacoco.report/src/org/jacoco/report/csv/CSVFormatter.java b/org.jacoco.report/src/org/jacoco/report/csv/CSVFormatter.java index 793e2153..42939daa 100644 --- a/org.jacoco.report/src/org/jacoco/report/csv/CSVFormatter.java +++ b/org.jacoco.report/src/org/jacoco/report/csv/CSVFormatter.java @@ -17,7 +17,7 @@ import java.io.OutputStreamWriter; import java.util.Collection; import java.util.List; -import org.jacoco.core.data.ExecutionData; +import org.jacoco.core.data.IExecutionData; import org.jacoco.core.data.SessionInfo; import org.jacoco.report.ILanguageNames; import org.jacoco.report.IReportVisitor; @@ -84,7 +84,9 @@ public class CSVFormatter { } public void visitInfo(final List sessionInfos, - final Collection executionData) + // BEGIN android-change + final Collection executionData) + // END android-change throws IOException { // Info not used for CSV report } diff --git a/org.jacoco.report/src/org/jacoco/report/html/HTMLFormatter.java b/org.jacoco.report/src/org/jacoco/report/html/HTMLFormatter.java index 9994ced0..ce8cd2d9 100644 --- a/org.jacoco.report/src/org/jacoco/report/html/HTMLFormatter.java +++ b/org.jacoco.report/src/org/jacoco/report/html/HTMLFormatter.java @@ -18,7 +18,7 @@ import java.util.Locale; import org.jacoco.core.analysis.IBundleCoverage; import org.jacoco.core.analysis.ICoverageNode.CounterEntity; -import org.jacoco.core.data.ExecutionData; +import org.jacoco.core.data.IExecutionData; import org.jacoco.core.data.SessionInfo; import org.jacoco.report.ILanguageNames; import org.jacoco.report.IMultiReportOutput; @@ -193,12 +193,16 @@ public class HTMLFormatter implements IHTMLReportContext { return new IReportVisitor() { private List sessionInfos; - private Collection executionData; + // BEGIN android-change + private Collection executionData; + // END android-change private HTMLGroupVisitor groupHandler; public void visitInfo(final List sessionInfos, - final Collection executionData) + // BEGIN android-change + final Collection executionData) + // END android-change throws IOException { this.sessionInfos = sessionInfos; this.executionData = executionData; diff --git a/org.jacoco.report/src/org/jacoco/report/internal/html/page/SessionsPage.java b/org.jacoco.report/src/org/jacoco/report/internal/html/page/SessionsPage.java index 67de4941..3a489025 100644 --- a/org.jacoco.report/src/org/jacoco/report/internal/html/page/SessionsPage.java +++ b/org.jacoco.report/src/org/jacoco/report/internal/html/page/SessionsPage.java @@ -20,7 +20,7 @@ import java.util.Comparator; import java.util.Date; import java.util.List; -import org.jacoco.core.data.ExecutionData; +import org.jacoco.core.data.IExecutionData; import org.jacoco.core.data.SessionInfo; import org.jacoco.report.ILanguageNames; import org.jacoco.report.internal.ReportOutputFolder; @@ -48,7 +48,7 @@ public class SessionsPage extends ReportPage { private final DateFormat dateFormat; - private final List executionData; + private final List executionData; private final ElementIndex index; @@ -69,18 +69,24 @@ public class SessionsPage extends ReportPage { * settings context */ public SessionsPage(final List sessionInfos, - final Collection executionData, + // BEGIN android-change + final Collection executionData, + // END android-change final ElementIndex index, final ReportPage parent, final ReportOutputFolder folder, final IHTMLReportContext context) { super(parent, folder, context); this.sessionInfos = sessionInfos; - this.executionData = new ArrayList(executionData); + // BEGIN android-change + this.executionData = new ArrayList(executionData); + // END android-change this.index = index; this.dateFormat = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, context.getLocale()); final ILanguageNames names = context.getLanguageNames(); - Collections.sort(this.executionData, new Comparator() { - public int compare(final ExecutionData e1, final ExecutionData e2) { + // BEGIN android-change + Collections.sort(this.executionData, new Comparator() { + public int compare(final IExecutionData e1, final IExecutionData e2) { + // END android-change return names.getQualifiedClassName(e1.getName()).compareTo( names.getQualifiedClassName(e2.getName())); } @@ -129,7 +135,9 @@ public class SessionsPage extends ReportPage { } final HTMLElement tbody = table.tbody(); final ILanguageNames names = context.getLanguageNames(); - for (final ExecutionData e : executionData) { + // BEGIN android-change + for (final IExecutionData e : executionData) { + // END android-change final HTMLElement tr = tbody.tr(); final String link = index.getLinkToClass(e.getId()); final String qualifiedName = names.getQualifiedClassName(e diff --git a/org.jacoco.report/src/org/jacoco/report/xml/XMLFormatter.java b/org.jacoco.report/src/org/jacoco/report/xml/XMLFormatter.java index a1fee86e..3bda5ed4 100644 --- a/org.jacoco.report/src/org/jacoco/report/xml/XMLFormatter.java +++ b/org.jacoco.report/src/org/jacoco/report/xml/XMLFormatter.java @@ -17,7 +17,7 @@ import java.util.Collection; import java.util.List; import org.jacoco.core.analysis.IBundleCoverage; -import org.jacoco.core.data.ExecutionData; +import org.jacoco.core.data.IExecutionData; import org.jacoco.core.data.SessionInfo; import org.jacoco.report.IReportGroupVisitor; import org.jacoco.report.IReportVisitor; @@ -61,7 +61,9 @@ public class XMLFormatter { private XMLGroupVisitor groupVisitor; public void visitInfo(final List sessionInfos, - final Collection executionData) + // BEGIN android-change + final Collection executionData) + // END android-change throws IOException { this.sessionInfos = sessionInfos; } -- cgit v1.2.3 From d29cfbbb94ce3952e034af105dced62b6fc2c28c Mon Sep 17 00:00:00 2001 From: Jackal Guo Date: Thu, 13 Aug 2020 01:54:53 +0000 Subject: Revert "Add IExecutionData interface and move all usage to the i..." Revert "Update JavaCodeCoverageListenerTest to new IExecutionDat..." Revert submission 1364940-IExecutionData Reason for revert: b/163919667 Reverted Changes: I4fbee7a43:Update JavaCodeCoverageListenerTest to new IExecut... I41235626b:Add IExecutionData interface and move all usage to... Change-Id: I609da053cf4427b250efe222ee3d54fb0a9f21d2 --- Android.bp | 5 +- .../src/org/jacoco/agent/rt/internal/Offline.java | 18 +-- .../org/jacoco/cli/internal/commands/ExecInfo.java | 10 +- .../src/org/jacoco/core/analysis/Analyzer.java | 8 +- .../src/org/jacoco/core/data/ExecutionData.java | 52 ++------- .../org/jacoco/core/data/ExecutionDataStore.java | 48 +++----- .../org/jacoco/core/data/ExecutionDataWriter.java | 8 +- .../src/org/jacoco/core/data/IExecutionData.java | 129 --------------------- .../jacoco/core/data/IExecutionDataVisitor.java | 4 +- .../jacoco/core/internal/instr/InstrSupport.java | 8 +- .../jacoco/core/internal/instr/ProbeInserter.java | 17 ++- .../src/org/jacoco/core/runtime/LoggerRuntime.java | 4 +- .../OfflineInstrumentationAccessGenerator.java | 6 +- .../src/org/jacoco/core/runtime/RuntimeData.java | 20 ++-- .../src/org/jacoco/report/IReportVisitor.java | 6 +- .../src/org/jacoco/report/MultiReportVisitor.java | 6 +- .../src/org/jacoco/report/check/RulesChecker.java | 6 +- .../src/org/jacoco/report/csv/CSVFormatter.java | 6 +- .../src/org/jacoco/report/html/HTMLFormatter.java | 10 +- .../report/internal/html/page/SessionsPage.java | 22 ++-- .../src/org/jacoco/report/xml/XMLFormatter.java | 6 +- 21 files changed, 86 insertions(+), 313 deletions(-) delete mode 100644 org.jacoco.core/src/org/jacoco/core/data/IExecutionData.java diff --git a/Android.bp b/Android.bp index 7b7d3f49..0641bdec 100644 --- a/Android.bp +++ b/Android.bp @@ -66,10 +66,7 @@ java_library { // 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", - "org.jacoco.core/src/org/jacoco/core/data/IExecutionData.java", - ], + 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. 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 ee9d40b1..69a9909e 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 @@ -16,7 +16,6 @@ import java.util.Map; import java.util.Properties; import org.jacoco.core.data.ExecutionData; -import org.jacoco.core.data.IExecutionData; import org.jacoco.core.data.ExecutionDataStore; import org.jacoco.core.runtime.AgentOptions; import org.jacoco.core.runtime.RuntimeData; @@ -29,7 +28,7 @@ public final class Offline { // BEGIN android-change // private static final RuntimeData DATA; - private static final Map DATA = new HashMap(); + private static final Map DATA = new HashMap(); // END android-change private static final String CONFIG_RESOURCE = "/jacoco-agent.properties"; @@ -45,7 +44,6 @@ public final class Offline { // no instances } - // BEGIN android-change /** * API for offline instrumented classes. * @@ -55,25 +53,27 @@ public final class Offline { * VM class name * @param probecount * probe count for this class - * @return IExecutionData instance for this class + * @return probe array instance for this class */ - public static IExecutionData getExecutionData(final long classid, + public static boolean[] getProbes(final long classid, final String classname, final int probecount) { + // BEGIN android-change // return DATA.getExecutionData(Long.valueOf(classid), classname, // probecount).getProbes(); synchronized (DATA) { - IExecutionData entry = DATA.get(classid); + 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; + return entry.getProbes(); } + // END android-change } - // 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 @@ -87,7 +87,7 @@ public final class Offline { System.getProperties()); synchronized (DATA) { ExecutionDataStore store = new ExecutionDataStore(); - for (IExecutionData data : DATA.values()) { + for (ExecutionData data : DATA.values()) { store.put(data); } return Agent.getInstance(new AgentOptions(config), new RuntimeData(store)); diff --git a/org.jacoco.cli/src/org/jacoco/cli/internal/commands/ExecInfo.java b/org.jacoco.cli/src/org/jacoco/cli/internal/commands/ExecInfo.java index 4519d28f..cacf4cbe 100644 --- a/org.jacoco.cli/src/org/jacoco/cli/internal/commands/ExecInfo.java +++ b/org.jacoco.cli/src/org/jacoco/cli/internal/commands/ExecInfo.java @@ -20,7 +20,7 @@ import java.util.Date; import java.util.List; import org.jacoco.cli.internal.Command; -import org.jacoco.core.data.IExecutionData; +import org.jacoco.core.data.ExecutionData; import org.jacoco.core.data.ExecutionDataReader; import org.jacoco.core.data.IExecutionDataVisitor; import org.jacoco.core.data.ISessionInfoVisitor; @@ -68,15 +68,13 @@ public class ExecInfo extends Command { } }); reader.setExecutionDataVisitor(new IExecutionDataVisitor() { - // BEGIN android-change - public void visitClassExecution(final IExecutionData data) { + public void visitClassExecution(final ExecutionData data) { out.printf("%016x %3d of %3d %s%n", Long.valueOf(data.getId()), - Integer.valueOf(getHitCount(data.getProbesCopy())), - Integer.valueOf(data.getProbeCount()), + Integer.valueOf(getHitCount(data.getProbes())), + Integer.valueOf(data.getProbes().length), data.getName()); } - // END android-change }); reader.read(); in.close(); diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java b/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java index 7759b89d..76b7be3c 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java @@ -20,7 +20,7 @@ import java.util.zip.GZIPInputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; -import org.jacoco.core.data.IExecutionData; +import org.jacoco.core.data.ExecutionData; import org.jacoco.core.data.ExecutionDataStore; import org.jacoco.core.internal.ContentTypeDetector; import org.jacoco.core.internal.InputStreams; @@ -78,18 +78,16 @@ public class Analyzer { */ private ClassVisitor createAnalyzingVisitor(final long classid, final String className) { - // BEGIN android-change - final IExecutionData data = executionData.get(classid); + final ExecutionData data = executionData.get(classid); final boolean[] probes; final boolean noMatch; if (data == null) { probes = null; noMatch = executionData.contains(className); } else { - probes = data.getProbesCopy(); + probes = data.getProbes(); noMatch = false; } - // END android-change final ClassCoverageImpl coverage = new ClassCoverageImpl(className, classid, noMatch); final ClassAnalyzer analyzer = new ClassAnalyzer(coverage, probes, diff --git a/org.jacoco.core/src/org/jacoco/core/data/ExecutionData.java b/org.jacoco.core/src/org/jacoco/core/data/ExecutionData.java index a728e033..d98775eb 100644 --- a/org.jacoco.core/src/org/jacoco/core/data/ExecutionData.java +++ b/org.jacoco.core/src/org/jacoco/core/data/ExecutionData.java @@ -20,9 +20,7 @@ import java.util.Arrays; * has to be taken about the probe data array of type boolean[] * which can be modified. */ -// BEGIN android-change -public final class ExecutionData implements IExecutionData { -// END android-change +public final class ExecutionData { private final long id; @@ -83,43 +81,15 @@ public final class ExecutionData implements IExecutionData { return name; } - // BEGIN android-change /** - * Returns a copy of the current probe values. - * - * @return copy of the probe array - */ - public boolean[] getProbesCopy() { - return Arrays.copyOf(probes, probes.length); - } - - /** - * The number of probes in this ExecutionData. - * - * @return the number of probes - */ - public int getProbeCount() { - return probes.length; - } - - /** - * Returns the execution data probe for a given index. A value of - * true indicates that the corresponding probe was - * executed. + * Returns the execution data probes. A value of true indicates + * that the corresponding probe was executed. * * @return probe data */ - public boolean getProbe(final int index) { - return probes[index]; - } - - /** - * Sets the execution data probe for a given index to true. - */ - public void setProbe(final int index) { - probes[index] = true; + public boolean[] getProbes() { + return probes; } - // END android-change /** * Sets all probes to false. @@ -157,9 +127,7 @@ public final class ExecutionData implements IExecutionData { * @param other * execution data to merge */ - // BEGIN android-change - public void merge(final IExecutionData other) { - // END android-change + public void merge(final ExecutionData other) { merge(other, true); } @@ -186,12 +154,10 @@ public final class ExecutionData implements IExecutionData { * @param flag * merge mode */ - public void merge(final IExecutionData other, final boolean flag) { - // BEGIN android-change + public void merge(final ExecutionData other, final boolean flag) { assertCompatibility(other.getId(), other.getName(), - other.getProbeCount()); - final boolean[] otherData = other.getProbesCopy(); - // END android-change + other.getProbes().length); + final boolean[] otherData = other.getProbes(); for (int i = 0; i < probes.length; i++) { if (otherData[i]) { probes[i] = flag; diff --git a/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataStore.java b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataStore.java index ce0bec47..3e567a3b 100644 --- a/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataStore.java +++ b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataStore.java @@ -28,9 +28,7 @@ import java.util.Set; */ public final class ExecutionDataStore implements IExecutionDataVisitor { - // BEGIN android-change - private final Map entries = new HashMap(); - // END android-change + private final Map entries = new HashMap(); private final Set names = new HashSet(); @@ -46,11 +44,9 @@ public final class ExecutionDataStore implements IExecutionDataVisitor { * to a corresponding one, that is already contained * @see ExecutionData#assertCompatibility(long, String, int) */ - // BEGIN android-change - public void put(final IExecutionData data) throws IllegalStateException { + public void put(final ExecutionData data) throws IllegalStateException { final Long id = Long.valueOf(data.getId()); - final IExecutionData entry = entries.get(id); - // END android-change + final ExecutionData entry = entries.get(id); if (entry == null) { entries.put(id, data); names.add(data.getName()); @@ -72,11 +68,9 @@ public final class ExecutionDataStore implements IExecutionDataVisitor { * to a corresponding one, that is already contained * @see ExecutionData#assertCompatibility(long, String, int) */ - // BEGIN android-change - public void subtract(final IExecutionData data) throws IllegalStateException { + public void subtract(final ExecutionData data) throws IllegalStateException { final Long id = Long.valueOf(data.getId()); - final IExecutionData entry = entries.get(id); - // END android-change + final ExecutionData entry = entries.get(id); if (entry != null) { entry.merge(data, false); } @@ -90,9 +84,7 @@ public final class ExecutionDataStore implements IExecutionDataVisitor { * @see #subtract(ExecutionData) */ public void subtract(final ExecutionDataStore store) { - // BEGIN android-change - for (final IExecutionData data : store.getContents()) { - // END android-change + for (final ExecutionData data : store.getContents()) { subtract(data); } } @@ -105,9 +97,7 @@ public final class ExecutionDataStore implements IExecutionDataVisitor { * class id * @return execution data or null */ - // BEGIN android-change - public IExecutionData get(final long id) { - // END android-change + public ExecutionData get(final long id) { return entries.get(Long.valueOf(id)); } @@ -136,11 +126,9 @@ public final class ExecutionDataStore implements IExecutionDataVisitor { * probe data length * @return execution data */ - // BEGIN android-change - public IExecutionData get(final Long id, final String name, + public ExecutionData get(final Long id, final String name, final int probecount) { - IExecutionData entry = entries.get(id); - // END android-change + ExecutionData entry = entries.get(id); if (entry == null) { entry = new ExecutionData(id.longValue(), name, probecount); entries.put(id, entry); @@ -156,9 +144,7 @@ public final class ExecutionDataStore implements IExecutionDataVisitor { * execution data objects itself are not removed. */ public void reset() { - // BEGIN android-change - for (final IExecutionData executionData : this.entries.values()) { - // END android-change + for (final ExecutionData executionData : this.entries.values()) { executionData.reset(); } } @@ -168,11 +154,9 @@ public final class ExecutionDataStore implements IExecutionDataVisitor { * * @return current contents */ - // BEGIN android-change - public Collection getContents() { - return new ArrayList(entries.values()); + public Collection getContents() { + return new ArrayList(entries.values()); } - // END android-change /** * Writes the content of the store to the given visitor interface. @@ -181,18 +165,14 @@ public final class ExecutionDataStore implements IExecutionDataVisitor { * interface to write content to */ public void accept(final IExecutionDataVisitor visitor) { - // BEGIN android-change - for (final IExecutionData data : getContents()) { - // END android-change + for (final ExecutionData data : getContents()) { visitor.visitClassExecution(data); } } // === IExecutionDataVisitor === - // BEGIN android-change - public void visitClassExecution(final IExecutionData data) { - // END android-change + public void visitClassExecution(final ExecutionData data) { put(data); } } diff --git a/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataWriter.java b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataWriter.java index bdf3445d..e697dda3 100644 --- a/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataWriter.java +++ b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataWriter.java @@ -94,17 +94,13 @@ public class ExecutionDataWriter implements ISessionInfoVisitor, } } - // BEGIN android-change - public void visitClassExecution(final IExecutionData data) { - // END android-change + public void visitClassExecution(final ExecutionData data) { if (data.hasHits()) { try { out.writeByte(BLOCK_EXECUTIONDATA); out.writeLong(data.getId()); out.writeUTF(data.getName()); - // BEGIN android-change - out.writeBooleanArray(data.getProbesCopy()); - // END android-change + out.writeBooleanArray(data.getProbes()); } catch (final IOException e) { throw new RuntimeException(e); } diff --git a/org.jacoco.core/src/org/jacoco/core/data/IExecutionData.java b/org.jacoco.core/src/org/jacoco/core/data/IExecutionData.java deleted file mode 100644 index 289c3726..00000000 --- a/org.jacoco.core/src/org/jacoco/core/data/IExecutionData.java +++ /dev/null @@ -1,129 +0,0 @@ -// BEGIN android-change -package org.jacoco.core.data; - -/** - * Interface for interacting with execution data for a single Java class. - */ -public interface IExecutionData { - - /** - * Return the unique identifier for this class. The identifier is the CRC64 - * checksum of the raw class file definition. - * - * @return class identifier - */ - public abstract long getId(); - - /** - * The VM name of the class. - * - * @return VM name - */ - public abstract String getName(); - - /** - * The number of instrumentation probes for this class. - * - * @return number of probes - */ - public abstract int 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 abstract boolean[] getProbesCopy(); - - /** - * Sets all probes to false. - */ - public abstract void reset(); - - /** - * Checks whether any probe has been hit. - * - * @return true, if at least one probe has been hit - */ - public abstract boolean 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 (true) if - * this probe or the corresponding other probe was executed. So the result - * is - * - *
-	 * A or B
-	 * 
- * - * The probe array of the other object is not modified. - * - * @param other - * execution data to merge - */ - public abstract void merge(final IExecutionData other); - - /** - * Merges the given execution data into the probe data of this object. A - * probe in this object is set to the value of flag if the - * corresponding other probe was executed. For flag==true this - * corresponds to - * - *
-	 * A or B
-	 * 
- * - * For flag==false this can be considered as a subtraction - * - *
-	 * A and not B
-	 * 
- * - * The probe array of the other object is not modified. - * - * @param other - * execution data to merge - * @param flag - * merge mode - */ - public abstract void merge(final IExecutionData other, boolean 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 abstract void assertCompatibility(final long id, final String name, final int probeCount) throws IllegalStateException; - - /** - * Returns the execution data probe for a given index. A value of - * true indicates that the corresponding probe was - * executed. - * - * @param index the probe's index to look up - * - * @return probe data - */ - public abstract boolean getProbe(final int index); - - /** - * Sets the execution data probe at the given index to true. - * - * @param index the probe's index to set - * @param value the value to set the probe to - */ - public abstract void setProbe(final int 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 14eabbe7..6cea7c57 100644 --- a/org.jacoco.core/src/org/jacoco/core/data/IExecutionDataVisitor.java +++ b/org.jacoco.core/src/org/jacoco/core/data/IExecutionDataVisitor.java @@ -24,8 +24,6 @@ public interface IExecutionDataVisitor { * @param data * execution data for a class */ - // BEGIN android-change - void visitClassExecution(IExecutionData data); - // END android-change + void visitClassExecution(ExecutionData data); } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java index 4d4e1ba1..85e83a3a 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java @@ -77,9 +77,7 @@ public final class InstrSupport { * Data type of the field that stores coverage information for a class ( * boolean[]). */ - // BEGIN android-change - public static final String DATAFIELD_DESC = "Lorg/jacoco/core/data/IExecutionData;"; - // END android-change + public static final String DATAFIELD_DESC = "[Z"; // === Init Method === @@ -91,9 +89,7 @@ public final class InstrSupport { /** * Descriptor of the initialization method. */ - // BEGIN android-change - public static final String INITMETHOD_DESC = "()Lorg/jacoco/core/data/IExecutionData;"; - // END android-change + public static final String INITMETHOD_DESC = "()[Z"; /** * Access modifiers of the initialization method. diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java index 0cac8f8f..63fbf765 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java @@ -67,20 +67,25 @@ class ProbeInserter extends MethodVisitor implements IProbeInserter { public void insertProbe(final int id) { - // BEGIN android-change - // For a probe we call setProbe on the IExecutionData object. + // For a probe we set the corresponding position in the boolean[] array + // to true. mv.visitVarInsn(Opcodes.ALOAD, variable); - // Stack[0]: Lorg/jacoco/core/data/IExecutionData; + // Stack[0]: [Z InstrSupport.push(mv, id); // Stack[1]: I - // Stack[0]: Lorg/jacoco/core/data/IExecutionData; + // Stack[0]: [Z - mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, "org/jacoco/core/data/IExecutionData", "setProbe", "(I)V", true); - // END android-change + mv.visitInsn(Opcodes.ICONST_1); + + // Stack[2]: I + // Stack[1]: I + // Stack[0]: [Z + + mv.visitInsn(Opcodes.BASTORE); } @Override diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/LoggerRuntime.java b/org.jacoco.core/src/org/jacoco/core/runtime/LoggerRuntime.java index bef42030..72553956 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/LoggerRuntime.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/LoggerRuntime.java @@ -168,9 +168,7 @@ public class LoggerRuntime extends AbstractRuntime { @Override public void publish(final LogRecord record) { if (key.equals(record.getMessage())) { - // BEGIN android-change - data.getExecutionData(record.getParameters()); - // END android-change + data.getProbes(record.getParameters()); } } diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/OfflineInstrumentationAccessGenerator.java b/org.jacoco.core/src/org/jacoco/core/runtime/OfflineInstrumentationAccessGenerator.java index a5e88b60..af6671ee 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/OfflineInstrumentationAccessGenerator.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/OfflineInstrumentationAccessGenerator.java @@ -50,10 +50,8 @@ public class OfflineInstrumentationAccessGenerator implements mv.visitLdcInsn(Long.valueOf(classid)); mv.visitLdcInsn(classname); InstrSupport.push(mv, probecount); - // BEGIN android-change - mv.visitMethodInsn(Opcodes.INVOKESTATIC, runtimeClassName, "getExecutionData", - "(JLjava/lang/String;I)Lorg/jacoco/core/data/IExecutionData;", false); - // END android-change + mv.visitMethodInsn(Opcodes.INVOKESTATIC, runtimeClassName, "getProbes", + "(JLjava/lang/String;I)[Z", false); return 4; } 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 c0fbb654..afb5b7f3 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/RuntimeData.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/RuntimeData.java @@ -11,7 +11,7 @@ *******************************************************************************/ package org.jacoco.core.runtime; -import org.jacoco.core.data.IExecutionData; +import org.jacoco.core.data.ExecutionData; import org.jacoco.core.data.ExecutionDataStore; import org.jacoco.core.data.IExecutionDataVisitor; import org.jacoco.core.data.ISessionInfoVisitor; @@ -128,18 +128,15 @@ public class RuntimeData { * probe data length * @return execution data */ - // BEGIN android-change - public IExecutionData getExecutionData(final Long id, final String name, + public ExecutionData getExecutionData(final Long id, final String name, final int probecount) { - // END android-change synchronized (store) { return store.get(id, name, probecount); } } - // BEGIN android-change /** - * Retrieves the execution data for a given class. The passed + * Retrieves the execution probe array for a given class. The passed * {@link Object} array instance is used for parameters and the return value * as follows. Call parameters: * @@ -152,19 +149,18 @@ public class RuntimeData { * Return value: * *
    - *
  • args[0]: execution data ({@link IExecutionData}) + *
  • args[0]: probe array (boolean[]) *
* * @param args * parameter array of length 3 */ - public void getExecutionData(final Object[] args) { + public void getProbes(final Object[] args) { final Long classid = (Long) args[0]; final String name = (String) args[1]; final int probecount = ((Integer) args[2]).intValue(); - args[0] = getExecutionData(classid, name, probecount); + args[0] = getExecutionData(classid, name, probecount).getProbes(); } - // END android-change /** * In violation of the regular semantic of {@link Object#equals(Object)} @@ -177,9 +173,7 @@ public class RuntimeData { @Override public boolean equals(final Object args) { if (args instanceof Object[]) { - // BEGIN android-change - getExecutionData((Object[]) args); - // END android-change + getProbes((Object[]) args); } return super.equals(args); } diff --git a/org.jacoco.report/src/org/jacoco/report/IReportVisitor.java b/org.jacoco.report/src/org/jacoco/report/IReportVisitor.java index 1cf4aed4..db36796d 100644 --- a/org.jacoco.report/src/org/jacoco/report/IReportVisitor.java +++ b/org.jacoco.report/src/org/jacoco/report/IReportVisitor.java @@ -15,7 +15,7 @@ import java.io.IOException; import java.util.Collection; import java.util.List; -import org.jacoco.core.data.IExecutionData; +import org.jacoco.core.data.ExecutionData; import org.jacoco.core.data.SessionInfo; /** @@ -39,9 +39,7 @@ public interface IReportVisitor extends IReportGroupVisitor { * in case of IO problems with the report writer */ void visitInfo(List sessionInfos, - // BEGIN android-change - Collection executionData) throws IOException; - // END android-change + Collection executionData) throws IOException; /** * Has to be called after all report data has been emitted. diff --git a/org.jacoco.report/src/org/jacoco/report/MultiReportVisitor.java b/org.jacoco.report/src/org/jacoco/report/MultiReportVisitor.java index f4fefa85..3cd5e558 100644 --- a/org.jacoco.report/src/org/jacoco/report/MultiReportVisitor.java +++ b/org.jacoco.report/src/org/jacoco/report/MultiReportVisitor.java @@ -17,7 +17,7 @@ import java.util.Collection; import java.util.List; import org.jacoco.core.analysis.IBundleCoverage; -import org.jacoco.core.data.IExecutionData; +import org.jacoco.core.data.ExecutionData; import org.jacoco.core.data.SessionInfo; /** @@ -41,9 +41,7 @@ public class MultiReportVisitor extends MultiGroupVisitor implements } public void visitInfo(final List sessionInfos, - // BEGIN android-change - final Collection executionData) throws IOException { - // END android-chnage + final Collection executionData) throws IOException { for (final IReportVisitor v : visitors) { v.visitInfo(sessionInfos, executionData); } diff --git a/org.jacoco.report/src/org/jacoco/report/check/RulesChecker.java b/org.jacoco.report/src/org/jacoco/report/check/RulesChecker.java index f7435600..cc6acf04 100644 --- a/org.jacoco.report/src/org/jacoco/report/check/RulesChecker.java +++ b/org.jacoco.report/src/org/jacoco/report/check/RulesChecker.java @@ -17,7 +17,7 @@ import java.util.Collection; import java.util.List; import org.jacoco.core.analysis.IBundleCoverage; -import org.jacoco.core.data.IExecutionData; +import org.jacoco.core.data.ExecutionData; import org.jacoco.core.data.SessionInfo; import org.jacoco.report.ILanguageNames; import org.jacoco.report.IReportGroupVisitor; @@ -86,9 +86,7 @@ public class RulesChecker { } public void visitInfo(final List sessionInfos, - // BEGIN android-change - final Collection executionData) - // END android-change + final Collection executionData) throws IOException { } diff --git a/org.jacoco.report/src/org/jacoco/report/csv/CSVFormatter.java b/org.jacoco.report/src/org/jacoco/report/csv/CSVFormatter.java index 42939daa..793e2153 100644 --- a/org.jacoco.report/src/org/jacoco/report/csv/CSVFormatter.java +++ b/org.jacoco.report/src/org/jacoco/report/csv/CSVFormatter.java @@ -17,7 +17,7 @@ import java.io.OutputStreamWriter; import java.util.Collection; import java.util.List; -import org.jacoco.core.data.IExecutionData; +import org.jacoco.core.data.ExecutionData; import org.jacoco.core.data.SessionInfo; import org.jacoco.report.ILanguageNames; import org.jacoco.report.IReportVisitor; @@ -84,9 +84,7 @@ public class CSVFormatter { } public void visitInfo(final List sessionInfos, - // BEGIN android-change - final Collection executionData) - // END android-change + final Collection executionData) throws IOException { // Info not used for CSV report } diff --git a/org.jacoco.report/src/org/jacoco/report/html/HTMLFormatter.java b/org.jacoco.report/src/org/jacoco/report/html/HTMLFormatter.java index ce8cd2d9..9994ced0 100644 --- a/org.jacoco.report/src/org/jacoco/report/html/HTMLFormatter.java +++ b/org.jacoco.report/src/org/jacoco/report/html/HTMLFormatter.java @@ -18,7 +18,7 @@ import java.util.Locale; import org.jacoco.core.analysis.IBundleCoverage; import org.jacoco.core.analysis.ICoverageNode.CounterEntity; -import org.jacoco.core.data.IExecutionData; +import org.jacoco.core.data.ExecutionData; import org.jacoco.core.data.SessionInfo; import org.jacoco.report.ILanguageNames; import org.jacoco.report.IMultiReportOutput; @@ -193,16 +193,12 @@ public class HTMLFormatter implements IHTMLReportContext { return new IReportVisitor() { private List sessionInfos; - // BEGIN android-change - private Collection executionData; - // END android-change + private Collection executionData; private HTMLGroupVisitor groupHandler; public void visitInfo(final List sessionInfos, - // BEGIN android-change - final Collection executionData) - // END android-change + final Collection executionData) throws IOException { this.sessionInfos = sessionInfos; this.executionData = executionData; diff --git a/org.jacoco.report/src/org/jacoco/report/internal/html/page/SessionsPage.java b/org.jacoco.report/src/org/jacoco/report/internal/html/page/SessionsPage.java index 3a489025..67de4941 100644 --- a/org.jacoco.report/src/org/jacoco/report/internal/html/page/SessionsPage.java +++ b/org.jacoco.report/src/org/jacoco/report/internal/html/page/SessionsPage.java @@ -20,7 +20,7 @@ import java.util.Comparator; import java.util.Date; import java.util.List; -import org.jacoco.core.data.IExecutionData; +import org.jacoco.core.data.ExecutionData; import org.jacoco.core.data.SessionInfo; import org.jacoco.report.ILanguageNames; import org.jacoco.report.internal.ReportOutputFolder; @@ -48,7 +48,7 @@ public class SessionsPage extends ReportPage { private final DateFormat dateFormat; - private final List executionData; + private final List executionData; private final ElementIndex index; @@ -69,24 +69,18 @@ public class SessionsPage extends ReportPage { * settings context */ public SessionsPage(final List sessionInfos, - // BEGIN android-change - final Collection executionData, - // END android-change + final Collection executionData, final ElementIndex index, final ReportPage parent, final ReportOutputFolder folder, final IHTMLReportContext context) { super(parent, folder, context); this.sessionInfos = sessionInfos; - // BEGIN android-change - this.executionData = new ArrayList(executionData); - // END android-change + this.executionData = new ArrayList(executionData); this.index = index; this.dateFormat = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, context.getLocale()); final ILanguageNames names = context.getLanguageNames(); - // BEGIN android-change - Collections.sort(this.executionData, new Comparator() { - public int compare(final IExecutionData e1, final IExecutionData e2) { - // END android-change + Collections.sort(this.executionData, new Comparator() { + public int compare(final ExecutionData e1, final ExecutionData e2) { return names.getQualifiedClassName(e1.getName()).compareTo( names.getQualifiedClassName(e2.getName())); } @@ -135,9 +129,7 @@ public class SessionsPage extends ReportPage { } final HTMLElement tbody = table.tbody(); final ILanguageNames names = context.getLanguageNames(); - // BEGIN android-change - for (final IExecutionData e : executionData) { - // END android-change + for (final ExecutionData e : executionData) { final HTMLElement tr = tbody.tr(); final String link = index.getLinkToClass(e.getId()); final String qualifiedName = names.getQualifiedClassName(e diff --git a/org.jacoco.report/src/org/jacoco/report/xml/XMLFormatter.java b/org.jacoco.report/src/org/jacoco/report/xml/XMLFormatter.java index 3bda5ed4..a1fee86e 100644 --- a/org.jacoco.report/src/org/jacoco/report/xml/XMLFormatter.java +++ b/org.jacoco.report/src/org/jacoco/report/xml/XMLFormatter.java @@ -17,7 +17,7 @@ import java.util.Collection; import java.util.List; import org.jacoco.core.analysis.IBundleCoverage; -import org.jacoco.core.data.IExecutionData; +import org.jacoco.core.data.ExecutionData; import org.jacoco.core.data.SessionInfo; import org.jacoco.report.IReportGroupVisitor; import org.jacoco.report.IReportVisitor; @@ -61,9 +61,7 @@ public class XMLFormatter { private XMLGroupVisitor groupVisitor; public void visitInfo(final List sessionInfos, - // BEGIN android-change - final Collection executionData) - // END android-change + final Collection executionData) throws IOException { this.sessionInfos = sessionInfos; } -- cgit v1.2.3 From bf6088bd3a28237e8d7eb33579140fa17bcee57a Mon Sep 17 00:00:00 2001 From: Oliver Nguyen Date: Mon, 17 Aug 2020 22:03:21 +0000 Subject: Revert "Revert "Add IExecutionData interface and move all usage ..." Revert "Revert "Update JavaCodeCoverageListenerTest to new IExec..." Revert submission 1398750-revert-1364940-IExecutionData-FHXOSGWBLA Reason for revert: Fixed build Reverted Changes: I609da053c:Revert "Add IExecutionData interface and move all ... Iff176c367:Revert "Update JavaCodeCoverageListenerTest to new... Change-Id: I2b1653276b15049c53c8f186a603cfc4b2015ed5 --- Android.bp | 5 +- .../src/org/jacoco/agent/rt/internal/Offline.java | 18 +-- .../org/jacoco/cli/internal/commands/ExecInfo.java | 10 +- .../src/org/jacoco/core/analysis/Analyzer.java | 8 +- .../src/org/jacoco/core/data/ExecutionData.java | 52 +++++++-- .../org/jacoco/core/data/ExecutionDataStore.java | 48 +++++--- .../org/jacoco/core/data/ExecutionDataWriter.java | 8 +- .../src/org/jacoco/core/data/IExecutionData.java | 129 +++++++++++++++++++++ .../jacoco/core/data/IExecutionDataVisitor.java | 4 +- .../jacoco/core/internal/instr/InstrSupport.java | 8 +- .../jacoco/core/internal/instr/ProbeInserter.java | 17 +-- .../src/org/jacoco/core/runtime/LoggerRuntime.java | 4 +- .../OfflineInstrumentationAccessGenerator.java | 6 +- .../src/org/jacoco/core/runtime/RuntimeData.java | 20 ++-- .../src/org/jacoco/report/IReportVisitor.java | 6 +- .../src/org/jacoco/report/MultiReportVisitor.java | 6 +- .../src/org/jacoco/report/check/RulesChecker.java | 6 +- .../src/org/jacoco/report/csv/CSVFormatter.java | 6 +- .../src/org/jacoco/report/html/HTMLFormatter.java | 10 +- .../report/internal/html/page/SessionsPage.java | 22 ++-- .../src/org/jacoco/report/xml/XMLFormatter.java | 6 +- 21 files changed, 313 insertions(+), 86 deletions(-) create mode 100644 org.jacoco.core/src/org/jacoco/core/data/IExecutionData.java diff --git a/Android.bp b/Android.bp index 0641bdec..7b7d3f49 100644 --- a/Android.bp +++ b/Android.bp @@ -66,7 +66,10 @@ java_library { // 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"], + srcs: [ + "org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/Offline.java", + "org.jacoco.core/src/org/jacoco/core/data/IExecutionData.java", + ], } // A stubs target containing the parts of JaCoCo that we need to add to the hidden API whitelist. 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 69a9909e..ee9d40b1 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 @@ -16,6 +16,7 @@ import java.util.Map; import java.util.Properties; import org.jacoco.core.data.ExecutionData; +import org.jacoco.core.data.IExecutionData; import org.jacoco.core.data.ExecutionDataStore; import org.jacoco.core.runtime.AgentOptions; import org.jacoco.core.runtime.RuntimeData; @@ -28,7 +29,7 @@ public final class Offline { // BEGIN android-change // private static final RuntimeData DATA; - private static final Map DATA = new HashMap(); + private static final Map DATA = new HashMap(); // END android-change private static final String CONFIG_RESOURCE = "/jacoco-agent.properties"; @@ -44,6 +45,7 @@ public final class Offline { // no instances } + // BEGIN android-change /** * API for offline instrumented classes. * @@ -53,27 +55,25 @@ public final class Offline { * VM class name * @param probecount * probe count for this class - * @return probe array instance for this class + * @return IExecutionData instance for this class */ - public static boolean[] getProbes(final long classid, + public static IExecutionData getExecutionData(final long classid, final String classname, final int probecount) { - // BEGIN android-change // return DATA.getExecutionData(Long.valueOf(classid), classname, // probecount).getProbes(); synchronized (DATA) { - ExecutionData entry = DATA.get(classid); + IExecutionData 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(); + return entry; } - // END android-change } + // 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 @@ -87,7 +87,7 @@ public final class Offline { System.getProperties()); synchronized (DATA) { ExecutionDataStore store = new ExecutionDataStore(); - for (ExecutionData data : DATA.values()) { + for (IExecutionData data : DATA.values()) { store.put(data); } return Agent.getInstance(new AgentOptions(config), new RuntimeData(store)); diff --git a/org.jacoco.cli/src/org/jacoco/cli/internal/commands/ExecInfo.java b/org.jacoco.cli/src/org/jacoco/cli/internal/commands/ExecInfo.java index cacf4cbe..4519d28f 100644 --- a/org.jacoco.cli/src/org/jacoco/cli/internal/commands/ExecInfo.java +++ b/org.jacoco.cli/src/org/jacoco/cli/internal/commands/ExecInfo.java @@ -20,7 +20,7 @@ import java.util.Date; import java.util.List; import org.jacoco.cli.internal.Command; -import org.jacoco.core.data.ExecutionData; +import org.jacoco.core.data.IExecutionData; import org.jacoco.core.data.ExecutionDataReader; import org.jacoco.core.data.IExecutionDataVisitor; import org.jacoco.core.data.ISessionInfoVisitor; @@ -68,13 +68,15 @@ public class ExecInfo extends Command { } }); reader.setExecutionDataVisitor(new IExecutionDataVisitor() { - public void visitClassExecution(final ExecutionData data) { + // BEGIN android-change + public void visitClassExecution(final IExecutionData data) { out.printf("%016x %3d of %3d %s%n", Long.valueOf(data.getId()), - Integer.valueOf(getHitCount(data.getProbes())), - Integer.valueOf(data.getProbes().length), + Integer.valueOf(getHitCount(data.getProbesCopy())), + Integer.valueOf(data.getProbeCount()), data.getName()); } + // END android-change }); reader.read(); in.close(); diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java b/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java index 76b7be3c..7759b89d 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java @@ -20,7 +20,7 @@ import java.util.zip.GZIPInputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; -import org.jacoco.core.data.ExecutionData; +import org.jacoco.core.data.IExecutionData; import org.jacoco.core.data.ExecutionDataStore; import org.jacoco.core.internal.ContentTypeDetector; import org.jacoco.core.internal.InputStreams; @@ -78,16 +78,18 @@ public class Analyzer { */ private ClassVisitor createAnalyzingVisitor(final long classid, final String className) { - final ExecutionData data = executionData.get(classid); + // BEGIN android-change + final IExecutionData data = executionData.get(classid); final boolean[] probes; final boolean noMatch; if (data == null) { probes = null; noMatch = executionData.contains(className); } else { - probes = data.getProbes(); + probes = data.getProbesCopy(); noMatch = false; } + // END android-change final ClassCoverageImpl coverage = new ClassCoverageImpl(className, classid, noMatch); final ClassAnalyzer analyzer = new ClassAnalyzer(coverage, probes, diff --git a/org.jacoco.core/src/org/jacoco/core/data/ExecutionData.java b/org.jacoco.core/src/org/jacoco/core/data/ExecutionData.java index d98775eb..a728e033 100644 --- a/org.jacoco.core/src/org/jacoco/core/data/ExecutionData.java +++ b/org.jacoco.core/src/org/jacoco/core/data/ExecutionData.java @@ -20,7 +20,9 @@ import java.util.Arrays; * has to be taken about the probe data array of type boolean[] * which can be modified. */ -public final class ExecutionData { +// BEGIN android-change +public final class ExecutionData implements IExecutionData { +// END android-change private final long id; @@ -81,15 +83,43 @@ public final class ExecutionData { return name; } + // BEGIN android-change /** - * Returns the execution data probes. A value of true indicates - * that the corresponding probe was executed. + * Returns a copy of the current probe values. + * + * @return copy of the probe array + */ + public boolean[] getProbesCopy() { + return Arrays.copyOf(probes, probes.length); + } + + /** + * The number of probes in this ExecutionData. + * + * @return the number of probes + */ + public int getProbeCount() { + return probes.length; + } + + /** + * Returns the execution data probe for a given index. A value of + * true indicates that the corresponding probe was + * executed. * * @return probe data */ - public boolean[] getProbes() { - return probes; + public boolean getProbe(final int index) { + return probes[index]; + } + + /** + * Sets the execution data probe for a given index to true. + */ + public void setProbe(final int index) { + probes[index] = true; } + // END android-change /** * Sets all probes to false. @@ -127,7 +157,9 @@ public final class ExecutionData { * @param other * execution data to merge */ - public void merge(final ExecutionData other) { + // BEGIN android-change + public void merge(final IExecutionData other) { + // END android-change merge(other, true); } @@ -154,10 +186,12 @@ public final class ExecutionData { * @param flag * merge mode */ - public void merge(final ExecutionData other, final boolean flag) { + public void merge(final IExecutionData other, final boolean flag) { + // BEGIN android-change assertCompatibility(other.getId(), other.getName(), - other.getProbes().length); - final boolean[] otherData = other.getProbes(); + other.getProbeCount()); + final boolean[] otherData = other.getProbesCopy(); + // END android-change for (int i = 0; i < probes.length; i++) { if (otherData[i]) { probes[i] = flag; diff --git a/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataStore.java b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataStore.java index 3e567a3b..ce0bec47 100644 --- a/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataStore.java +++ b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataStore.java @@ -28,7 +28,9 @@ import java.util.Set; */ public final class ExecutionDataStore implements IExecutionDataVisitor { - private final Map entries = new HashMap(); + // BEGIN android-change + private final Map entries = new HashMap(); + // END android-change private final Set names = new HashSet(); @@ -44,9 +46,11 @@ public final class ExecutionDataStore implements IExecutionDataVisitor { * to a corresponding one, that is already contained * @see ExecutionData#assertCompatibility(long, String, int) */ - public void put(final ExecutionData data) throws IllegalStateException { + // BEGIN android-change + public void put(final IExecutionData data) throws IllegalStateException { final Long id = Long.valueOf(data.getId()); - final ExecutionData entry = entries.get(id); + final IExecutionData entry = entries.get(id); + // END android-change if (entry == null) { entries.put(id, data); names.add(data.getName()); @@ -68,9 +72,11 @@ public final class ExecutionDataStore implements IExecutionDataVisitor { * to a corresponding one, that is already contained * @see ExecutionData#assertCompatibility(long, String, int) */ - public void subtract(final ExecutionData data) throws IllegalStateException { + // BEGIN android-change + public void subtract(final IExecutionData data) throws IllegalStateException { final Long id = Long.valueOf(data.getId()); - final ExecutionData entry = entries.get(id); + final IExecutionData entry = entries.get(id); + // END android-change if (entry != null) { entry.merge(data, false); } @@ -84,7 +90,9 @@ public final class ExecutionDataStore implements IExecutionDataVisitor { * @see #subtract(ExecutionData) */ public void subtract(final ExecutionDataStore store) { - for (final ExecutionData data : store.getContents()) { + // BEGIN android-change + for (final IExecutionData data : store.getContents()) { + // END android-change subtract(data); } } @@ -97,7 +105,9 @@ public final class ExecutionDataStore implements IExecutionDataVisitor { * class id * @return execution data or null */ - public ExecutionData get(final long id) { + // BEGIN android-change + public IExecutionData get(final long id) { + // END android-change return entries.get(Long.valueOf(id)); } @@ -126,9 +136,11 @@ public final class ExecutionDataStore implements IExecutionDataVisitor { * probe data length * @return execution data */ - public ExecutionData get(final Long id, final String name, + // BEGIN android-change + public IExecutionData get(final Long id, final String name, final int probecount) { - ExecutionData entry = entries.get(id); + IExecutionData entry = entries.get(id); + // END android-change if (entry == null) { entry = new ExecutionData(id.longValue(), name, probecount); entries.put(id, entry); @@ -144,7 +156,9 @@ public final class ExecutionDataStore implements IExecutionDataVisitor { * execution data objects itself are not removed. */ public void reset() { - for (final ExecutionData executionData : this.entries.values()) { + // BEGIN android-change + for (final IExecutionData executionData : this.entries.values()) { + // END android-change executionData.reset(); } } @@ -154,9 +168,11 @@ public final class ExecutionDataStore implements IExecutionDataVisitor { * * @return current contents */ - public Collection getContents() { - return new ArrayList(entries.values()); + // BEGIN android-change + public Collection getContents() { + return new ArrayList(entries.values()); } + // END android-change /** * Writes the content of the store to the given visitor interface. @@ -165,14 +181,18 @@ public final class ExecutionDataStore implements IExecutionDataVisitor { * interface to write content to */ public void accept(final IExecutionDataVisitor visitor) { - for (final ExecutionData data : getContents()) { + // BEGIN android-change + for (final IExecutionData data : getContents()) { + // END android-change visitor.visitClassExecution(data); } } // === IExecutionDataVisitor === - public void visitClassExecution(final ExecutionData data) { + // BEGIN android-change + public void visitClassExecution(final IExecutionData data) { + // END android-change put(data); } } diff --git a/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataWriter.java b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataWriter.java index e697dda3..bdf3445d 100644 --- a/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataWriter.java +++ b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataWriter.java @@ -94,13 +94,17 @@ public class ExecutionDataWriter implements ISessionInfoVisitor, } } - public void visitClassExecution(final ExecutionData data) { + // BEGIN android-change + public void visitClassExecution(final IExecutionData data) { + // END android-change if (data.hasHits()) { try { out.writeByte(BLOCK_EXECUTIONDATA); out.writeLong(data.getId()); out.writeUTF(data.getName()); - out.writeBooleanArray(data.getProbes()); + // BEGIN android-change + out.writeBooleanArray(data.getProbesCopy()); + // END android-change } catch (final IOException e) { throw new RuntimeException(e); } diff --git a/org.jacoco.core/src/org/jacoco/core/data/IExecutionData.java b/org.jacoco.core/src/org/jacoco/core/data/IExecutionData.java new file mode 100644 index 00000000..289c3726 --- /dev/null +++ b/org.jacoco.core/src/org/jacoco/core/data/IExecutionData.java @@ -0,0 +1,129 @@ +// BEGIN android-change +package org.jacoco.core.data; + +/** + * Interface for interacting with execution data for a single Java class. + */ +public interface IExecutionData { + + /** + * Return the unique identifier for this class. The identifier is the CRC64 + * checksum of the raw class file definition. + * + * @return class identifier + */ + public abstract long getId(); + + /** + * The VM name of the class. + * + * @return VM name + */ + public abstract String getName(); + + /** + * The number of instrumentation probes for this class. + * + * @return number of probes + */ + public abstract int 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 abstract boolean[] getProbesCopy(); + + /** + * Sets all probes to false. + */ + public abstract void reset(); + + /** + * Checks whether any probe has been hit. + * + * @return true, if at least one probe has been hit + */ + public abstract boolean 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 (true) if + * this probe or the corresponding other probe was executed. So the result + * is + * + *
+	 * A or B
+	 * 
+ * + * The probe array of the other object is not modified. + * + * @param other + * execution data to merge + */ + public abstract void merge(final IExecutionData other); + + /** + * Merges the given execution data into the probe data of this object. A + * probe in this object is set to the value of flag if the + * corresponding other probe was executed. For flag==true this + * corresponds to + * + *
+	 * A or B
+	 * 
+ * + * For flag==false this can be considered as a subtraction + * + *
+	 * A and not B
+	 * 
+ * + * The probe array of the other object is not modified. + * + * @param other + * execution data to merge + * @param flag + * merge mode + */ + public abstract void merge(final IExecutionData other, boolean 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 abstract void assertCompatibility(final long id, final String name, final int probeCount) throws IllegalStateException; + + /** + * Returns the execution data probe for a given index. A value of + * true indicates that the corresponding probe was + * executed. + * + * @param index the probe's index to look up + * + * @return probe data + */ + public abstract boolean getProbe(final int index); + + /** + * Sets the execution data probe at the given index to true. + * + * @param index the probe's index to set + * @param value the value to set the probe to + */ + public abstract void setProbe(final int 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 6cea7c57..14eabbe7 100644 --- a/org.jacoco.core/src/org/jacoco/core/data/IExecutionDataVisitor.java +++ b/org.jacoco.core/src/org/jacoco/core/data/IExecutionDataVisitor.java @@ -24,6 +24,8 @@ public interface IExecutionDataVisitor { * @param data * execution data for a class */ - void visitClassExecution(ExecutionData data); + // BEGIN android-change + void visitClassExecution(IExecutionData data); + // END android-change } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java index 85e83a3a..4d4e1ba1 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java @@ -77,7 +77,9 @@ public final class InstrSupport { * Data type of the field that stores coverage information for a class ( * boolean[]). */ - public static final String DATAFIELD_DESC = "[Z"; + // BEGIN android-change + public static final String DATAFIELD_DESC = "Lorg/jacoco/core/data/IExecutionData;"; + // END android-change // === Init Method === @@ -89,7 +91,9 @@ public final class InstrSupport { /** * Descriptor of the initialization method. */ - public static final String INITMETHOD_DESC = "()[Z"; + // BEGIN android-change + public static final String INITMETHOD_DESC = "()Lorg/jacoco/core/data/IExecutionData;"; + // END android-change /** * Access modifiers of the initialization method. diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java index 63fbf765..0cac8f8f 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java @@ -67,25 +67,20 @@ class ProbeInserter extends MethodVisitor implements IProbeInserter { public void insertProbe(final int id) { - // For a probe we set the corresponding position in the boolean[] array - // to true. + // BEGIN android-change + // For a probe we call setProbe on the IExecutionData object. mv.visitVarInsn(Opcodes.ALOAD, variable); - // Stack[0]: [Z + // Stack[0]: Lorg/jacoco/core/data/IExecutionData; InstrSupport.push(mv, id); // Stack[1]: I - // Stack[0]: [Z + // Stack[0]: Lorg/jacoco/core/data/IExecutionData; - mv.visitInsn(Opcodes.ICONST_1); - - // Stack[2]: I - // Stack[1]: I - // Stack[0]: [Z - - mv.visitInsn(Opcodes.BASTORE); + mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, "org/jacoco/core/data/IExecutionData", "setProbe", "(I)V", true); + // END android-change } @Override diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/LoggerRuntime.java b/org.jacoco.core/src/org/jacoco/core/runtime/LoggerRuntime.java index 72553956..bef42030 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/LoggerRuntime.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/LoggerRuntime.java @@ -168,7 +168,9 @@ public class LoggerRuntime extends AbstractRuntime { @Override public void publish(final LogRecord record) { if (key.equals(record.getMessage())) { - data.getProbes(record.getParameters()); + // BEGIN android-change + data.getExecutionData(record.getParameters()); + // END android-change } } diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/OfflineInstrumentationAccessGenerator.java b/org.jacoco.core/src/org/jacoco/core/runtime/OfflineInstrumentationAccessGenerator.java index af6671ee..a5e88b60 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/OfflineInstrumentationAccessGenerator.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/OfflineInstrumentationAccessGenerator.java @@ -50,8 +50,10 @@ public class OfflineInstrumentationAccessGenerator implements mv.visitLdcInsn(Long.valueOf(classid)); mv.visitLdcInsn(classname); InstrSupport.push(mv, probecount); - mv.visitMethodInsn(Opcodes.INVOKESTATIC, runtimeClassName, "getProbes", - "(JLjava/lang/String;I)[Z", false); + // BEGIN android-change + mv.visitMethodInsn(Opcodes.INVOKESTATIC, runtimeClassName, "getExecutionData", + "(JLjava/lang/String;I)Lorg/jacoco/core/data/IExecutionData;", false); + // END android-change return 4; } 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 afb5b7f3..c0fbb654 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/RuntimeData.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/RuntimeData.java @@ -11,7 +11,7 @@ *******************************************************************************/ package org.jacoco.core.runtime; -import org.jacoco.core.data.ExecutionData; +import org.jacoco.core.data.IExecutionData; import org.jacoco.core.data.ExecutionDataStore; import org.jacoco.core.data.IExecutionDataVisitor; import org.jacoco.core.data.ISessionInfoVisitor; @@ -128,15 +128,18 @@ public class RuntimeData { * probe data length * @return execution data */ - public ExecutionData getExecutionData(final Long id, final String name, + // BEGIN android-change + public IExecutionData getExecutionData(final Long id, final String name, final int probecount) { + // END android-change synchronized (store) { return store.get(id, name, probecount); } } + // BEGIN android-change /** - * Retrieves the execution probe array for a given class. The passed + * Retrieves the execution data for a given class. The passed * {@link Object} array instance is used for parameters and the return value * as follows. Call parameters: * @@ -149,18 +152,19 @@ public class RuntimeData { * Return value: * *
    - *
  • args[0]: probe array (boolean[]) + *
  • args[0]: execution data ({@link IExecutionData}) *
* * @param args * parameter array of length 3 */ - public void getProbes(final Object[] args) { + public void getExecutionData(final Object[] args) { final Long classid = (Long) args[0]; final String name = (String) args[1]; final int probecount = ((Integer) args[2]).intValue(); - args[0] = getExecutionData(classid, name, probecount).getProbes(); + args[0] = getExecutionData(classid, name, probecount); } + // END android-change /** * In violation of the regular semantic of {@link Object#equals(Object)} @@ -173,7 +177,9 @@ public class RuntimeData { @Override public boolean equals(final Object args) { if (args instanceof Object[]) { - getProbes((Object[]) args); + // BEGIN android-change + getExecutionData((Object[]) args); + // END android-change } return super.equals(args); } diff --git a/org.jacoco.report/src/org/jacoco/report/IReportVisitor.java b/org.jacoco.report/src/org/jacoco/report/IReportVisitor.java index db36796d..1cf4aed4 100644 --- a/org.jacoco.report/src/org/jacoco/report/IReportVisitor.java +++ b/org.jacoco.report/src/org/jacoco/report/IReportVisitor.java @@ -15,7 +15,7 @@ import java.io.IOException; import java.util.Collection; import java.util.List; -import org.jacoco.core.data.ExecutionData; +import org.jacoco.core.data.IExecutionData; import org.jacoco.core.data.SessionInfo; /** @@ -39,7 +39,9 @@ public interface IReportVisitor extends IReportGroupVisitor { * in case of IO problems with the report writer */ void visitInfo(List sessionInfos, - Collection executionData) throws IOException; + // BEGIN android-change + Collection executionData) throws IOException; + // END android-change /** * Has to be called after all report data has been emitted. diff --git a/org.jacoco.report/src/org/jacoco/report/MultiReportVisitor.java b/org.jacoco.report/src/org/jacoco/report/MultiReportVisitor.java index 3cd5e558..f4fefa85 100644 --- a/org.jacoco.report/src/org/jacoco/report/MultiReportVisitor.java +++ b/org.jacoco.report/src/org/jacoco/report/MultiReportVisitor.java @@ -17,7 +17,7 @@ import java.util.Collection; import java.util.List; import org.jacoco.core.analysis.IBundleCoverage; -import org.jacoco.core.data.ExecutionData; +import org.jacoco.core.data.IExecutionData; import org.jacoco.core.data.SessionInfo; /** @@ -41,7 +41,9 @@ public class MultiReportVisitor extends MultiGroupVisitor implements } public void visitInfo(final List sessionInfos, - final Collection executionData) throws IOException { + // BEGIN android-change + final Collection executionData) throws IOException { + // END android-chnage for (final IReportVisitor v : visitors) { v.visitInfo(sessionInfos, executionData); } diff --git a/org.jacoco.report/src/org/jacoco/report/check/RulesChecker.java b/org.jacoco.report/src/org/jacoco/report/check/RulesChecker.java index cc6acf04..f7435600 100644 --- a/org.jacoco.report/src/org/jacoco/report/check/RulesChecker.java +++ b/org.jacoco.report/src/org/jacoco/report/check/RulesChecker.java @@ -17,7 +17,7 @@ import java.util.Collection; import java.util.List; import org.jacoco.core.analysis.IBundleCoverage; -import org.jacoco.core.data.ExecutionData; +import org.jacoco.core.data.IExecutionData; import org.jacoco.core.data.SessionInfo; import org.jacoco.report.ILanguageNames; import org.jacoco.report.IReportGroupVisitor; @@ -86,7 +86,9 @@ public class RulesChecker { } public void visitInfo(final List sessionInfos, - final Collection executionData) + // BEGIN android-change + final Collection executionData) + // END android-change throws IOException { } diff --git a/org.jacoco.report/src/org/jacoco/report/csv/CSVFormatter.java b/org.jacoco.report/src/org/jacoco/report/csv/CSVFormatter.java index 793e2153..42939daa 100644 --- a/org.jacoco.report/src/org/jacoco/report/csv/CSVFormatter.java +++ b/org.jacoco.report/src/org/jacoco/report/csv/CSVFormatter.java @@ -17,7 +17,7 @@ import java.io.OutputStreamWriter; import java.util.Collection; import java.util.List; -import org.jacoco.core.data.ExecutionData; +import org.jacoco.core.data.IExecutionData; import org.jacoco.core.data.SessionInfo; import org.jacoco.report.ILanguageNames; import org.jacoco.report.IReportVisitor; @@ -84,7 +84,9 @@ public class CSVFormatter { } public void visitInfo(final List sessionInfos, - final Collection executionData) + // BEGIN android-change + final Collection executionData) + // END android-change throws IOException { // Info not used for CSV report } diff --git a/org.jacoco.report/src/org/jacoco/report/html/HTMLFormatter.java b/org.jacoco.report/src/org/jacoco/report/html/HTMLFormatter.java index 9994ced0..ce8cd2d9 100644 --- a/org.jacoco.report/src/org/jacoco/report/html/HTMLFormatter.java +++ b/org.jacoco.report/src/org/jacoco/report/html/HTMLFormatter.java @@ -18,7 +18,7 @@ import java.util.Locale; import org.jacoco.core.analysis.IBundleCoverage; import org.jacoco.core.analysis.ICoverageNode.CounterEntity; -import org.jacoco.core.data.ExecutionData; +import org.jacoco.core.data.IExecutionData; import org.jacoco.core.data.SessionInfo; import org.jacoco.report.ILanguageNames; import org.jacoco.report.IMultiReportOutput; @@ -193,12 +193,16 @@ public class HTMLFormatter implements IHTMLReportContext { return new IReportVisitor() { private List sessionInfos; - private Collection executionData; + // BEGIN android-change + private Collection executionData; + // END android-change private HTMLGroupVisitor groupHandler; public void visitInfo(final List sessionInfos, - final Collection executionData) + // BEGIN android-change + final Collection executionData) + // END android-change throws IOException { this.sessionInfos = sessionInfos; this.executionData = executionData; diff --git a/org.jacoco.report/src/org/jacoco/report/internal/html/page/SessionsPage.java b/org.jacoco.report/src/org/jacoco/report/internal/html/page/SessionsPage.java index 67de4941..3a489025 100644 --- a/org.jacoco.report/src/org/jacoco/report/internal/html/page/SessionsPage.java +++ b/org.jacoco.report/src/org/jacoco/report/internal/html/page/SessionsPage.java @@ -20,7 +20,7 @@ import java.util.Comparator; import java.util.Date; import java.util.List; -import org.jacoco.core.data.ExecutionData; +import org.jacoco.core.data.IExecutionData; import org.jacoco.core.data.SessionInfo; import org.jacoco.report.ILanguageNames; import org.jacoco.report.internal.ReportOutputFolder; @@ -48,7 +48,7 @@ public class SessionsPage extends ReportPage { private final DateFormat dateFormat; - private final List executionData; + private final List executionData; private final ElementIndex index; @@ -69,18 +69,24 @@ public class SessionsPage extends ReportPage { * settings context */ public SessionsPage(final List sessionInfos, - final Collection executionData, + // BEGIN android-change + final Collection executionData, + // END android-change final ElementIndex index, final ReportPage parent, final ReportOutputFolder folder, final IHTMLReportContext context) { super(parent, folder, context); this.sessionInfos = sessionInfos; - this.executionData = new ArrayList(executionData); + // BEGIN android-change + this.executionData = new ArrayList(executionData); + // END android-change this.index = index; this.dateFormat = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, context.getLocale()); final ILanguageNames names = context.getLanguageNames(); - Collections.sort(this.executionData, new Comparator() { - public int compare(final ExecutionData e1, final ExecutionData e2) { + // BEGIN android-change + Collections.sort(this.executionData, new Comparator() { + public int compare(final IExecutionData e1, final IExecutionData e2) { + // END android-change return names.getQualifiedClassName(e1.getName()).compareTo( names.getQualifiedClassName(e2.getName())); } @@ -129,7 +135,9 @@ public class SessionsPage extends ReportPage { } final HTMLElement tbody = table.tbody(); final ILanguageNames names = context.getLanguageNames(); - for (final ExecutionData e : executionData) { + // BEGIN android-change + for (final IExecutionData e : executionData) { + // END android-change final HTMLElement tr = tbody.tr(); final String link = index.getLinkToClass(e.getId()); final String qualifiedName = names.getQualifiedClassName(e diff --git a/org.jacoco.report/src/org/jacoco/report/xml/XMLFormatter.java b/org.jacoco.report/src/org/jacoco/report/xml/XMLFormatter.java index a1fee86e..3bda5ed4 100644 --- a/org.jacoco.report/src/org/jacoco/report/xml/XMLFormatter.java +++ b/org.jacoco.report/src/org/jacoco/report/xml/XMLFormatter.java @@ -17,7 +17,7 @@ import java.util.Collection; import java.util.List; import org.jacoco.core.analysis.IBundleCoverage; -import org.jacoco.core.data.ExecutionData; +import org.jacoco.core.data.IExecutionData; import org.jacoco.core.data.SessionInfo; import org.jacoco.report.IReportGroupVisitor; import org.jacoco.report.IReportVisitor; @@ -61,7 +61,9 @@ public class XMLFormatter { private XMLGroupVisitor groupVisitor; public void visitInfo(final List sessionInfos, - final Collection executionData) + // BEGIN android-change + final Collection executionData) + // END android-change throws IOException { this.sessionInfos = sessionInfos; } -- cgit v1.2.3 From cb523bf186baa02b7478c81a7a64d2a2ee3d6b5f Mon Sep 17 00:00:00 2001 From: Oliver Nguyen Date: Fri, 10 Jul 2020 10:46:29 -0700 Subject: Implement memory-mapped ExecutionData class. This allows apps to write coverage to disk during execution and not require any flushing mechanism in order to collect coverage. The results will be left in /data/misc/trace/jacoco-*.mm.ec and can be collected later for coverage analysis. These .mm.ec files conform to the current exec file format and can be loaded with the command-line tool. Test: m -j EMMA_INSTRUMENT=true EMMA_INSTRUMENT_FRAMEWORK=true and generate coverage report from /data/misc/trace Bug: 147904124 Change-Id: If08492405b86a063ae714c259a2fb954bc5aa946 --- .../src/org/jacoco/agent/rt/internal/Offline.java | 76 ++++- .../org/jacoco/core/data/MappedExecutionData.java | 324 +++++++++++++++++++++ 2 files changed, 399 insertions(+), 1 deletion(-) create mode 100644 org.jacoco.core/src/org/jacoco/core/data/MappedExecutionData.java 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 ee9d40b1..445722af 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,6 +11,8 @@ *******************************************************************************/ package org.jacoco.agent.rt.internal; +import java.io.File; +import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Properties; @@ -18,6 +20,7 @@ import java.util.Properties; import org.jacoco.core.data.ExecutionData; 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; @@ -30,6 +33,7 @@ public final class Offline { // BEGIN android-change // private static final RuntimeData DATA; private static final Map DATA = new HashMap(); + private static int PID = -1; // END android-change private static final String CONFIG_RESOURCE = "/jacoco-agent.properties"; @@ -64,7 +68,49 @@ public final class Offline { synchronized (DATA) { IExecutionData entry = DATA.get(classid); if (entry == null) { - entry = new ExecutionData(classid, classname, probecount); + // BEGIN android-change + // The list below are not allowed to use the memory-mapped + // implementation due either: + // 1) They are loaded at VM initialization time. + // a) android.* + // b) dalvik.* + // c) libcore.* + // 2) They are used by the memory-mapped execution data + // implementation, which would cause a stack overflow due + // to the circular dependency. + // a) com.android.i18n.* + // b) com.android.icu.* + // c) java.* + // d) org.apache.* + // e) sun.* + // These classes can still have coverage collected through the + // normal execution data process, but requires a flush to be done + // instead of simply being available on disk at all times. + if (classname.startsWith("android/") + || classname.startsWith("com/android/i18n/") + || classname.startsWith("com/android/icu/") + || classname.startsWith("dalvik/") + || classname.startsWith("java/") + || classname.startsWith("libcore/") + || classname.startsWith("org/apache/") + || classname.startsWith("sun/")) { + entry = new ExecutionData(classid, classname, probecount); + } else { + try { + int pid = getPid(); + if (PID != pid) { + PID = pid; + rebuildExecutionData(pid); + } + entry = new MappedExecutionData( + classid, classname, probecount); + } catch (IOException e) { + // Fall back to non-memory-mapped execution data. + entry = new ExecutionData( + classid, classname, probecount); + } + } + // END android-change DATA.put(classid, entry); } else { entry.assertCompatibility(classid, classname, probecount); @@ -72,6 +118,34 @@ public final class Offline { return entry; } } + + private static void rebuildExecutionData(int pid) throws IOException { + MappedExecutionData.prepareFile(pid); + synchronized (DATA) { + for (IExecutionData execData : DATA.values()) { + if (execData instanceof MappedExecutionData) { + // Create new instances of MappedExecutionData using the + // new file, but don't copy the old data. Old data will + // remain in its existing file and can be merged during + // post-processing. + DATA.put( + execData.getId(), + new MappedExecutionData( + execData.getId(), + execData.getName(), + execData.getProbeCount())); + } + } + } + } + + /** + * 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/MappedExecutionData.java b/org.jacoco.core/src/org/jacoco/core/data/MappedExecutionData.java new file mode 100644 index 00000000..39b90fb6 --- /dev/null +++ b/org.jacoco.core/src/org/jacoco/core/data/MappedExecutionData.java @@ -0,0 +1,324 @@ +// BEGIN android-change +package org.jacoco.core.data; + +import static java.lang.String.format; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; +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 static FileChannel CHANNEL; + + 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) + throws IOException { + this.id = id; + this.name = name; + this.probeCount = probeCount; + + createMemoryMappedProbeArray(id, name, probeCount); + } + + /** + * 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) throws IOException { + // TODO: Figure out a more portable way to do this. Currently needed to avoid + // cross-VM race conditions when writing/mapping the file. Since most processes + // are forked from zygote, they will initially share the same output file, but + // without synchronization across VMs, this can cause simultaneous maps/writes from + // different VMs to interrupt each other, resulting in malformed execution data. + // Adding file locks did not resolve this issue. Note that only new classes that + // were loaded after the fork will end up in the new file. Classes that were + // already loaded will end up in the original output file for the pre-forked + // process, which is OK. + if (CHANNEL == null) { + throw new IOException("Memory mapped file was not initialized."); + } + + 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); + } + } + + /** + * Creates the output file that will be mapped for probe data. + */ + public 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); + } + } + + /** + * 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 false. + */ + 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 true, 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 (true) if + * this probe or the corresponding other probe was executed. So the result + * is + * + *
+	 * A or B
+	 * 
+ * + * 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 flag if the + * corresponding other probe was executed. For flag==true this + * corresponds to + * + *
+	 * A or B
+	 * 
+ * + * For flag==false this can be considered as a subtraction + * + *
+	 * A and not B
+	 * 
+ * + * 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 + * true 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 true. + * + * @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 -- cgit v1.2.3 From 24205b1075320a719b73ecbb27969bb2fee1c722 Mon Sep 17 00:00:00 2001 From: Oliver Nguyen Date: Fri, 25 Sep 2020 19:47:18 +0000 Subject: Revert "Implement memory-mapped ExecutionData class." This reverts commit cb523bf186baa02b7478c81a7a64d2a2ee3d6b5f. Reason for revert: Fix boot failure Change-Id: I7480ca95e548ea663b3d16ca62cc5b5ec3d30514 --- .../src/org/jacoco/agent/rt/internal/Offline.java | 76 +---- .../org/jacoco/core/data/MappedExecutionData.java | 324 --------------------- 2 files changed, 1 insertion(+), 399 deletions(-) delete mode 100644 org.jacoco.core/src/org/jacoco/core/data/MappedExecutionData.java 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 445722af..ee9d40b1 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,6 @@ *******************************************************************************/ package org.jacoco.agent.rt.internal; -import java.io.File; -import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Properties; @@ -20,7 +18,6 @@ import java.util.Properties; import org.jacoco.core.data.ExecutionData; 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; @@ -33,7 +30,6 @@ public final class Offline { // BEGIN android-change // private static final RuntimeData DATA; private static final Map DATA = new HashMap(); - private static int PID = -1; // END android-change private static final String CONFIG_RESOURCE = "/jacoco-agent.properties"; @@ -68,49 +64,7 @@ public final class Offline { synchronized (DATA) { IExecutionData entry = DATA.get(classid); if (entry == null) { - // BEGIN android-change - // The list below are not allowed to use the memory-mapped - // implementation due either: - // 1) They are loaded at VM initialization time. - // a) android.* - // b) dalvik.* - // c) libcore.* - // 2) They are used by the memory-mapped execution data - // implementation, which would cause a stack overflow due - // to the circular dependency. - // a) com.android.i18n.* - // b) com.android.icu.* - // c) java.* - // d) org.apache.* - // e) sun.* - // These classes can still have coverage collected through the - // normal execution data process, but requires a flush to be done - // instead of simply being available on disk at all times. - if (classname.startsWith("android/") - || classname.startsWith("com/android/i18n/") - || classname.startsWith("com/android/icu/") - || classname.startsWith("dalvik/") - || classname.startsWith("java/") - || classname.startsWith("libcore/") - || classname.startsWith("org/apache/") - || classname.startsWith("sun/")) { - entry = new ExecutionData(classid, classname, probecount); - } else { - try { - int pid = getPid(); - if (PID != pid) { - PID = pid; - rebuildExecutionData(pid); - } - entry = new MappedExecutionData( - classid, classname, probecount); - } catch (IOException e) { - // Fall back to non-memory-mapped execution data. - entry = new ExecutionData( - classid, classname, probecount); - } - } - // END android-change + entry = new ExecutionData(classid, classname, probecount); DATA.put(classid, entry); } else { entry.assertCompatibility(classid, classname, probecount); @@ -118,34 +72,6 @@ public final class Offline { return entry; } } - - private static void rebuildExecutionData(int pid) throws IOException { - MappedExecutionData.prepareFile(pid); - synchronized (DATA) { - for (IExecutionData execData : DATA.values()) { - if (execData instanceof MappedExecutionData) { - // Create new instances of MappedExecutionData using the - // new file, but don't copy the old data. Old data will - // remain in its existing file and can be merged during - // post-processing. - DATA.put( - execData.getId(), - new MappedExecutionData( - execData.getId(), - execData.getName(), - execData.getProbeCount())); - } - } - } - } - - /** - * 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/MappedExecutionData.java b/org.jacoco.core/src/org/jacoco/core/data/MappedExecutionData.java deleted file mode 100644 index 39b90fb6..00000000 --- a/org.jacoco.core/src/org/jacoco/core/data/MappedExecutionData.java +++ /dev/null @@ -1,324 +0,0 @@ -// BEGIN android-change -package org.jacoco.core.data; - -import static java.lang.String.format; - -import java.io.File; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.nio.channels.FileChannel; -import java.nio.channels.FileLock; -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 static FileChannel CHANNEL; - - 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) - throws IOException { - this.id = id; - this.name = name; - this.probeCount = probeCount; - - createMemoryMappedProbeArray(id, name, probeCount); - } - - /** - * 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) throws IOException { - // TODO: Figure out a more portable way to do this. Currently needed to avoid - // cross-VM race conditions when writing/mapping the file. Since most processes - // are forked from zygote, they will initially share the same output file, but - // without synchronization across VMs, this can cause simultaneous maps/writes from - // different VMs to interrupt each other, resulting in malformed execution data. - // Adding file locks did not resolve this issue. Note that only new classes that - // were loaded after the fork will end up in the new file. Classes that were - // already loaded will end up in the original output file for the pre-forked - // process, which is OK. - if (CHANNEL == null) { - throw new IOException("Memory mapped file was not initialized."); - } - - 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); - } - } - - /** - * Creates the output file that will be mapped for probe data. - */ - public 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); - } - } - - /** - * 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 false. - */ - 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 true, 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 (true) if - * this probe or the corresponding other probe was executed. So the result - * is - * - *
-	 * A or B
-	 * 
- * - * 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 flag if the - * corresponding other probe was executed. For flag==true this - * corresponds to - * - *
-	 * A or B
-	 * 
- * - * For flag==false this can be considered as a subtraction - * - *
-	 * A and not B
-	 * 
- * - * 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 - * true 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 true. - * - * @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 -- cgit v1.2.3 From 4748cfa55873c56fd89c71d25f9bc285131bbba1 Mon Sep 17 00:00:00 2001 From: Oliver Nguyen Date: Thu, 1 Oct 2020 16:10:18 -0700 Subject: Implement delegate that can swap to memory-mapped execution data. Implements memory-mapped ExecutionData class. Test: m EMMA_INSTRUMENT=true EMMA_INSTRUMENT_FRAMEWORK=true CLANG_COVERAGE=true and check for /data/misc/trace/jacoco-*.mm.ec files Bug: 169426258 Change-Id: I0eb564bc66650e2fd53573dd173dc141a8f4ffbe Change-Id: I8bc1f724071f267b3d44350eb96d20900068d66f --- .../src/org/jacoco/agent/rt/internal/Offline.java | 59 +++- .../jacoco/core/data/ExecutionDataDelegate.java | 197 +++++++++++++ .../org/jacoco/core/data/MappedExecutionData.java | 304 +++++++++++++++++++++ 3 files changed, 557 insertions(+), 3 deletions(-) create mode 100644 org.jacoco.core/src/org/jacoco/core/data/ExecutionDataDelegate.java create mode 100644 org.jacoco.core/src/org/jacoco/core/data/MappedExecutionData.java 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 ee9d40b1..2350ce55 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 @@ public final class Offline { // BEGIN android-change // private static final RuntimeData DATA; - private static final Map DATA = new HashMap(); + private static final Map DATA = new HashMap(); + private static FileChannel CHANNEL; // END android-change private static final String CONFIG_RESOURCE = "/jacoco-agent.properties"; @@ -62,9 +71,10 @@ public final class Offline { // 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 @@ public final class Offline { 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) { + throw new RuntimeException(e); + } + } + + /** + * 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 00000000..cc6b3cc8 --- /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) { + throw new RuntimeException(e); + } + } 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 false. + */ + public void reset() { + delegate.reset(); + } + + /** + * Checks whether any probe has been hit. + * + * @return true, 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 (true) if + * this probe or the corresponding other probe was executed. So the result + * is + * + *
+	 * A or B
+	 * 
+ * + * 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 flag if the + * corresponding other probe was executed. For flag==true this + * corresponds to + * + *
+	 * A or B
+	 * 
+ * + * For flag==false this can be considered as a subtraction + * + *
+	 * A and not B
+	 * 
+ * + * 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 + * true 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 true. + * + * @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/MappedExecutionData.java b/org.jacoco.core/src/org/jacoco/core/data/MappedExecutionData.java new file mode 100644 index 00000000..7e74d17e --- /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 false. + */ + 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 true, 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 (true) if + * this probe or the corresponding other probe was executed. So the result + * is + * + *
+	 * A or B
+	 * 
+ * + * 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 flag if the + * corresponding other probe was executed. For flag==true this + * corresponds to + * + *
+	 * A or B
+	 * 
+ * + * For flag==false this can be considered as a subtraction + * + *
+	 * A and not B
+	 * 
+ * + * 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 + * true 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 true. + * + * @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 -- cgit v1.2.3 From ea2018aa31f4178c9fa2b3bd00db9961c73a8477 Mon Sep 17 00:00:00 2001 From: Oliver Nguyen Date: Thu, 22 Oct 2020 12:09:54 -0700 Subject: Handle exceptions instead of passing them on. Exceptions propagated down the stack are causing instability issues and random failures. Fall back where possible to normal ExecutionData instances instead. Test: m EMMA_INSTRUMENT=true EMMA_INSTRUMENT_FRAMEWORK=true CLANG_COVERAGE=true and check boot Bug: 171333204 Change-Id: I091d66d7aacbbbe70db10cc1a1c9b5ffbda7131b --- org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/Offline.java | 2 +- org.jacoco.core/src/org/jacoco/core/data/ExecutionDataDelegate.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 2350ce55..99a054e7 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 @@ -94,7 +94,7 @@ public final class Offline { data.convert(CHANNEL); } } catch (IOException e) { - throw new RuntimeException(e); + // TODO(olivernguyen): Add logging to debug issues more easily. } } diff --git a/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataDelegate.java b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataDelegate.java index cc6b3cc8..7cbe989f 100644 --- a/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataDelegate.java +++ b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataDelegate.java @@ -18,7 +18,7 @@ public class ExecutionDataDelegate implements IExecutionData { try { delegate = new MappedExecutionData(id, name, probeCount, channel); } catch (IOException e) { - throw new RuntimeException(e); + delegate = new ExecutionData(id, name, probeCount); } } else { delegate = new ExecutionData(id, name, probeCount); -- cgit v1.2.3 From 79f63e354708d65cb356a228e9b82143cc5e53ec Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Fri, 12 Feb 2021 19:49:42 -0800 Subject: [LSC] Add LOCAL_LICENSE_KINDS to external/jacoco Added SPDX-license-identifier-Apache-2.0 SPDX-license-identifier-BSD SPDX-license-identifier-EPL SPDX-license-identifier-MIT to: Android.bp Bug: 68860345 Bug: 151177513 Bug: 151953481 Test: m all Exempt-From-Owner-Approval: janitorial work Change-Id: Iebec9d59a31ff71bc989573e72e05737bd3910d1 --- Android.bp | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/Android.bp b/Android.bp index 7b7d3f49..726af1d3 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, -- cgit v1.2.3