diff options
author | Sebastien Hertz <shertz@google.com> | 2016-11-22 16:30:04 +0100 |
---|---|---|
committer | Sebastien Hertz <shertz@google.com> | 2016-11-30 10:00:24 +0100 |
commit | 312795872e0cb0b310c74f4fb5260f60f49ab077 (patch) | |
tree | 5770cefb34df9f90ddd1cab699de83479a035cb0 | |
parent | a0639e64a1d751290a8015b2a8cf2013f0070050 (diff) | |
download | apache-harmony-312795872e0cb0b310c74f4fb5260f60f49ab077.tar.gz |
Test class prepare event from the debuggerandroid-7.1.2_r9android-7.1.2_r8android-7.1.2_r6android-7.1.2_r5android-7.1.2_r4android-7.1.2_r39android-7.1.2_r38android-7.1.2_r37android-7.1.2_r36android-7.1.2_r33android-7.1.2_r32android-7.1.2_r30android-7.1.2_r3android-7.1.2_r29android-7.1.2_r28android-7.1.2_r27android-7.1.2_r25android-7.1.2_r24android-7.1.2_r23android-7.1.2_r2android-7.1.2_r19android-7.1.2_r18android-7.1.2_r17android-7.1.2_r16android-7.1.2_r15android-7.1.2_r14android-7.1.2_r13android-7.1.2_r12android-7.1.2_r11android-7.1.2_r10android-7.1.2_r1nougat-mr2.3-releasenougat-mr2.2-releasenougat-mr2.1-releasenougat-mr2-security-releasenougat-mr2-releasenougat-mr2-pixel-releasenougat-mr2-dev
Checks that we properly receive CLASS_PREPARE event triggered by a
command (ReferenceType.GetValues) processed by the debugger thread.
Bug: 33032664
Test: art/tools/run-jdwp-tests.sh '--mode=host' '--variant=X64'
(cherry picked from commit e8a964ca684f4b2d72e69b79c08f248b81e4baca)
Change-Id: I4dbc354df1e6bb550d2826753fc0d7e88ded1418
3 files changed, 203 insertions, 0 deletions
diff --git a/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/Events/ClassPrepare002Debuggee.java b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/Events/ClassPrepare002Debuggee.java new file mode 100644 index 0000000..9928bd4 --- /dev/null +++ b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/Events/ClassPrepare002Debuggee.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.jpda.tests.jdwp.Events; + +import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer; +import org.apache.harmony.jpda.tests.share.SyncDebuggee; + +/** + * Debuggee for ClassPrepare002Test unit test. + */ +public class ClassPrepare002Debuggee extends SyncDebuggee { + + public static void main(String[] args) { + runDebuggee(ClassPrepare002Debuggee.class); + } + + @Override + public void run() { + logWriter.println("ClassPrepare002Debuggee started"); + + // Load TestClassA *without* initializing the class and notify the test. + try { + Class.forName("org.apache.harmony.jpda.tests.jdwp.Events.TestClassA", false, + getClass().getClassLoader()); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_READY); + + // Wait for the test to finish. + synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE); + + logWriter.println("ClassPrepare002Debuggee finished"); + } +} + +/** + * The class that will be investigated by the debugger for its static fields + * (ReferenceType.GetValues command). + */ +class TestClassA { + static TestClassB field = new TestClassB(); +} + +/** + * The class that will cause the CLASS PREPARE event when the debugger investigates static fields + * of the other class above. + */ +class TestClassB { +} diff --git a/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/Events/ClassPrepare002Test.java b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/Events/ClassPrepare002Test.java new file mode 100644 index 0000000..37a2c5a --- /dev/null +++ b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/Events/ClassPrepare002Test.java @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.jpda.tests.jdwp.Events; + +import java.io.IOException; +import org.apache.harmony.jpda.tests.framework.jdwp.CommandPacket; +import org.apache.harmony.jpda.tests.framework.jdwp.EventBuilder; +import org.apache.harmony.jpda.tests.framework.jdwp.EventPacket; +import org.apache.harmony.jpda.tests.framework.jdwp.JDWPCommands; +import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants; +import org.apache.harmony.jpda.tests.framework.jdwp.ParsedEvent; +import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket; +import org.apache.harmony.jpda.tests.framework.jdwp.ParsedEvent.Event_CLASS_PREPARE; +import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer; + +/** + * JDWP unit test for CLASS_PREPARE events sent from the debugger thread. + */ +public class ClassPrepare002Test extends JDWPEventTestCase { + @Override + protected String getDebuggeeClassName() { + return ClassPrepare002Debuggee.class.getName(); + } + + /** + * Tests that the CLASS_PREPARE event can be sent from the runtime's debugger thread. + * + * This test starts by requesting a CLASS_PREPARE event then sends a ReferenceType.GetValues + * command to cause the debugger thread to report a CLASS_PREPARE event. After checking the + * content of the event packet, we clear the event request then resume the debuggee. + */ + public void testClassPrepareCausedByDebugger() { + logWriter.println("testClassPrepareCausedByDebugger started"); + + synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY); + + // The TestClassA must be loaded but not initialized. + long classIDOfA = getClassIDBySignature(getClassSignature(TestClassA.class)); + + // Restrict class prepare only to the tested class. + String classPrepareClassName = "org.apache.harmony.jpda.tests.jdwp.Events.TestClassB"; + + // Request CLASS_PREPARE event. The event will be caused by the debugger thread when + // handling the ReferenceType.GetValues command we're going to send just after. + EventBuilder eventBuilder = new EventBuilder(JDWPConstants.EventKind.CLASS_PREPARE, + JDWPConstants.SuspendPolicy.EVENT_THREAD); + eventBuilder.setClassMatch(classPrepareClassName); + ReplyPacket eventReply = debuggeeWrapper.vmMirror.setEvent(eventBuilder.build()); + checkReplyPacket(eventReply, "Failed to set CLASS_PREPARE event"); + int classPrepareRequestId = eventReply.getNextValueAsInt(); + assertAllDataRead(eventReply); + + // Send a ReferenceType.GetValues command to force class initialization. This will trigger + // the CLASS_PREPARE event from the debugger thread. + logWriter.println("=> CHECK: send ReferenceType.GetValues"); + long fieldId = checkField(classIDOfA, "field"); + CommandPacket getValuesCommand = new CommandPacket( + JDWPCommands.ReferenceTypeCommandSet.CommandSetID, + JDWPCommands.ReferenceTypeCommandSet.GetValuesCommand); + getValuesCommand.setNextValueAsReferenceTypeID(classIDOfA); + getValuesCommand.setNextValueAsInt(1); + getValuesCommand.setNextValueAsFieldID(fieldId); + + // Send command but does not wait for reply because this will cause a CLASS_PREPARE event + // that will suspend every thread. + int rtGetValuesCommandId = -1; + try { + rtGetValuesCommandId = debuggeeWrapper.vmMirror.sendCommand(getValuesCommand); + } catch (IOException e) { + fail("Failed to send ReferenceType.GetValues command"); + } + + // Wait for the class prepare event. + EventPacket eventPacket = debuggeeWrapper.vmMirror + .receiveCertainEvent(JDWPConstants.EventKind.CLASS_PREPARE); + ParsedEvent[] parsedEvents = ParsedEvent.parseEventPacket(eventPacket); + assertNotNull(parsedEvents); + logWriter.println("Received " + parsedEvents.length + " event(s)"); + assertEquals(1, parsedEvents.length); + + // Check event is the expected one. + ParsedEvent parsedEvent = parsedEvents[0]; + // Only expect CLASS_PREPARE event. + assertEquals(JDWPConstants.EventKind.CLASS_PREPARE, parsedEvent.getEventKind()); + // CLASS_PREPARE events caused by the debugger must have an ALL + // suspend policy. + assertEquals(JDWPConstants.SuspendPolicy.ALL, parsedEvent.getSuspendPolicy()); + // Check that its the event that we have requested. + assertEquals(classPrepareRequestId, parsedEvent.getRequestID()); + Event_CLASS_PREPARE classPrepareEvent = (Event_CLASS_PREPARE) parsedEvent; + // The JDWP spec says that if the event was caused by the debugger thread, the thread ID + // must be 0. + assertEquals(0, classPrepareEvent.getThreadID()); + // Check that it is the expected class. + assertEquals(getClassSignature(classPrepareClassName), classPrepareEvent.getSignature()); + + // Check that we received the reply of the command that caused the CLASS_PREPARE event. + logWriter.println("=> CHECK: receive ReferenceType.GetValues reply (" + + rtGetValuesCommandId + ")"); + ReplyPacket getValuesReply = null; + try { + getValuesReply = debuggeeWrapper.vmMirror.receiveReply(rtGetValuesCommandId); + } catch (InterruptedException | IOException e) { + fail("Failed to receive ReferenceType.GetValues reply"); + } + checkReplyPacket(getValuesReply, "Failed to receive ReferenceType.GetValues reply"); + + // Clear the CLASS_PREPARE event request. + debuggeeWrapper.vmMirror.clearEvent(JDWPConstants.EventKind.CLASS_PREPARE, + classPrepareRequestId); + + // Resume all threads suspended by the CLASS_PREPARE event. + debuggeeWrapper.vmMirror.resume(); + + // Let the debuggee finish. + synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE); + + logWriter.println("testClassPrepareCausedByDebugger finished"); + } +} diff --git a/jdwp/src/test/java/org/apache/harmony/jpda/tests/share/AllTests.java b/jdwp/src/test/java/org/apache/harmony/jpda/tests/share/AllTests.java index 44e4211..69b7c8b 100644 --- a/jdwp/src/test/java/org/apache/harmony/jpda/tests/share/AllTests.java +++ b/jdwp/src/test/java/org/apache/harmony/jpda/tests/share/AllTests.java @@ -90,6 +90,7 @@ public class AllTests { suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.Events.BreakpointMultipleTest.class); suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.Events.BreakpointOnCatchTest.class); suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.Events.BreakpointTest.class); + suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.Events.ClassPrepare002Test.class); suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.Events.ClassPrepareTest.class); suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.Events.CombinedEvents002Test.class); suite.addTestSuite(org.apache.harmony.jpda.tests.jdwp.Events.CombinedEvents003Test.class); |