From d063d912e5580222b1822b152de315420cef49ee Mon Sep 17 00:00:00 2001 From: Jeff Hao Date: Mon, 8 Sep 2014 09:38:18 -0700 Subject: [PATCH] Change when sampling thread is reset during shutdown to prevent races. Also adds some extra argument checking and testing for tracing. Bug: 17412385 (cherry picked from commit f8bdd4e783842577e49f418a0b5962ba49dfdd93) Change-Id: Ifc4f1a296155d73255b29d264b5475024e6419da --- runtime/trace.cc | 17 ++++-- test/099-vmdebug/expected.txt | 19 ++++++ test/099-vmdebug/info.txt | 1 + test/099-vmdebug/src/Main.java | 130 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 163 insertions(+), 4 deletions(-) create mode 100644 test/099-vmdebug/expected.txt create mode 100644 test/099-vmdebug/info.txt create mode 100644 test/099-vmdebug/src/Main.java diff --git a/runtime/trace.cc b/runtime/trace.cc index ca5e150b8..6dcc5fe6b 100644 --- a/runtime/trace.cc +++ b/runtime/trace.cc @@ -334,8 +334,14 @@ void Trace::Start(const char* trace_filename, int trace_fd, int buffer_size, int return; } } - Runtime* runtime = Runtime::Current(); - runtime->GetThreadList()->SuspendAll(); + + // Check interval if sampling is enabled + if (sampling_enabled && interval_us <= 0) { + LOG(ERROR) << "Invalid sampling interval: " << interval_us; + ScopedObjectAccess soa(self); + ThrowRuntimeException("Invalid sampling interval: %d", interval_us); + return; + } // Open trace file if not going directly to ddms. std::unique_ptr trace_file; @@ -348,13 +354,15 @@ void Trace::Start(const char* trace_filename, int trace_fd, int buffer_size, int } if (trace_file.get() == NULL) { PLOG(ERROR) << "Unable to open trace file '" << trace_filename << "'"; - runtime->GetThreadList()->ResumeAll(); ScopedObjectAccess soa(self); ThrowRuntimeException("Unable to open trace file '%s'", trace_filename); return; } } + Runtime* runtime = Runtime::Current(); + runtime->GetThreadList()->SuspendAll(); + // Create Trace object. { MutexLock mu(self, *Locks::trace_lock_); @@ -383,6 +391,7 @@ void Trace::Start(const char* trace_filename, int trace_fd, int buffer_size, int } } } + runtime->GetThreadList()->ResumeAll(); } @@ -399,7 +408,6 @@ void Trace::Stop() { the_trace = the_trace_; the_trace_ = NULL; sampling_pthread = sampling_pthread_; - sampling_pthread_ = 0U; } } if (the_trace != NULL) { @@ -421,6 +429,7 @@ void Trace::Stop() { if (sampling_pthread != 0U) { CHECK_PTHREAD_CALL(pthread_join, (sampling_pthread, NULL), "sampling thread shutdown"); + sampling_pthread_ = 0U; } } diff --git a/test/099-vmdebug/expected.txt b/test/099-vmdebug/expected.txt new file mode 100644 index 000000000..579f98fe7 --- /dev/null +++ b/test/099-vmdebug/expected.txt @@ -0,0 +1,19 @@ +Confirm enable/disable +status=0 +status=1 +status=0 +Confirm sampling +status=2 +status=0 +Test starting when already started +status=1 +status=1 +Test stopping when already stopped +status=0 +status=0 +Test tracing with empty filename +Got expected exception +Test tracing with bogus (< 1024 && != 0) filesize +Got expected exception +Test sampling with bogus (<= 0) interval +Got expected exception diff --git a/test/099-vmdebug/info.txt b/test/099-vmdebug/info.txt new file mode 100644 index 000000000..7f8808698 --- /dev/null +++ b/test/099-vmdebug/info.txt @@ -0,0 +1 @@ +Tests of private dalvik.system.VMDebug support for method tracing. diff --git a/test/099-vmdebug/src/Main.java b/test/099-vmdebug/src/Main.java new file mode 100644 index 000000000..d51ec6e1d --- /dev/null +++ b/test/099-vmdebug/src/Main.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Method; + +public class Main { + public static void main(String[] args) throws Exception { + String name = System.getProperty("java.vm.name"); + if (!"Dalvik".equals(name)) { + System.out.println("This test is not supported on " + name); + return; + } + testMethodTracing(); + } + + private static void testMethodTracing() throws Exception { + String tempFileName; + if (new File("/tmp").isDirectory()) { + tempFileName = "/tmp/test.trace"; + } else if (new File("/sdcard").isDirectory()) { + tempFileName = "/sdcard/test.trace"; + } else { + System.out.println("Can't find proper output directory for trace file"); + return; + } + File tempFile = new File(tempFileName); + tempFile.delete(); + + System.out.println("Confirm enable/disable"); + System.out.println("status=" + VMDebug.getMethodTracingMode()); + VMDebug.startMethodTracing(tempFileName, 0, 0, false, 0); + System.out.println("status=" + VMDebug.getMethodTracingMode()); + VMDebug.stopMethodTracing(); + System.out.println("status=" + VMDebug.getMethodTracingMode()); + if (tempFile.length() == 0) { + System.out.println("ERROR: tracing output file is empty"); + } + + System.out.println("Confirm sampling"); + VMDebug.startMethodTracing(tempFileName, 0, 0, true, 1000); + System.out.println("status=" + VMDebug.getMethodTracingMode()); + VMDebug.stopMethodTracing(); + System.out.println("status=" + VMDebug.getMethodTracingMode()); + if (tempFile.length() == 0) { + System.out.println("ERROR: sample tracing output file is empty"); + } + + System.out.println("Test starting when already started"); + VMDebug.startMethodTracing(tempFileName, 0, 0, false, 0); + System.out.println("status=" + VMDebug.getMethodTracingMode()); + VMDebug.startMethodTracing(tempFileName, 0, 0, false, 0); + System.out.println("status=" + VMDebug.getMethodTracingMode()); + + System.out.println("Test stopping when already stopped"); + VMDebug.stopMethodTracing(); + System.out.println("status=" + VMDebug.getMethodTracingMode()); + VMDebug.stopMethodTracing(); + System.out.println("status=" + VMDebug.getMethodTracingMode()); + + System.out.println("Test tracing with empty filename"); + try { + VMDebug.startMethodTracing("", 0, 0, false, 0); + System.out.println("Should have thrown an exception"); + } catch (Exception e) { + System.out.println("Got expected exception"); + } + + System.out.println("Test tracing with bogus (< 1024 && != 0) filesize"); + try { + VMDebug.startMethodTracing(tempFileName, 1000, 0, false, 0); + System.out.println("Should have thrown an exception"); + } catch (Exception e) { + System.out.println("Got expected exception"); + } + + System.out.println("Test sampling with bogus (<= 0) interval"); + try { + VMDebug.startMethodTracing(tempFileName, 0, 0, true, 0); + System.out.println("Should have thrown an exception"); + } catch (Exception e) { + System.out.println("Got expected exception"); + } + + tempFile.delete(); + } + + private static class VMDebug { + private static final Method startMethodTracingMethod; + private static final Method stopMethodTracingMethod; + private static final Method getMethodTracingModeMethod; + static { + try { + Class c = Class.forName("dalvik.system.VMDebug"); + startMethodTracingMethod = c.getDeclaredMethod("startMethodTracing", String.class, + Integer.TYPE, Integer.TYPE, Boolean.TYPE, Integer.TYPE); + stopMethodTracingMethod = c.getDeclaredMethod("stopMethodTracing"); + getMethodTracingModeMethod = c.getDeclaredMethod("getMethodTracingMode"); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void startMethodTracing(String filename, int bufferSize, int flags, + boolean samplingEnabled, int intervalUs) throws Exception { + startMethodTracingMethod.invoke(null, filename, bufferSize, flags, samplingEnabled, + intervalUs); + } + public static void stopMethodTracing() throws Exception { + stopMethodTracingMethod.invoke(null); + } + public static int getMethodTracingMode() throws Exception { + return (int) getMethodTracingModeMethod.invoke(null); + } + } +} -- 2.11.0