Remove native printing from test 980 and reliance on print internals

In preparation for a making a CTS test out of this make the test not
rely on internal allocation patterns of the 'System.out' object and
not make use of std::cout.

Test: ./test.py --host -j40
Change-Id: Ib7e874aaec71f93e834cf94ac5fe96663536691a
diff --git a/test/980-redefine-object/check b/test/980-redefine-object/check
index 987066f..07b21b3 100755
--- a/test/980-redefine-object/check
+++ b/test/980-redefine-object/check
@@ -17,4 +17,4 @@
 # The number of paused background threads (and therefore InterruptedExceptions)
 # can change so we will just delete their lines from the log.
 
-sed "/Object allocated of type 'Ljava\/lang\/InterruptedException;'/d" "$2" | diff --strip-trailing-cr -q "$1" - >/dev/null
+sed "/Object allocated of type 'java\.lang\.InterruptedException'/d" "$2" | diff --strip-trailing-cr -q "$1" - >/dev/null
diff --git a/test/980-redefine-object/expected.txt b/test/980-redefine-object/expected.txt
index 6e9bce0..4c294bc 100644
--- a/test/980-redefine-object/expected.txt
+++ b/test/980-redefine-object/expected.txt
@@ -2,51 +2,31 @@
 	Allocating an j.l.Object before redefining Object class
 	Allocating a Transform before redefining Object class
 	Redefining the Object class to add a hook into the <init> method
-Object allocated of type 'Ljava/lang/StringBuilder;'
-Object allocated of type 'Ljava/nio/HeapCharBuffer;'
 	Allocating an j.l.Object after redefining Object class
-Object allocated of type 'Ljava/lang/Object;'
-Object allocated of type 'Ljava/lang/StringBuilder;'
-Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+Object allocated of type 'java.lang.Object'
 	Allocating a Transform after redefining Object class
-Object allocated of type 'LTransform;'
-Object allocated of type 'Ljava/lang/StringBuilder;'
-Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+Object allocated of type 'Transform'
 	Allocating an int[] after redefining Object class
-Object allocated of type 'Ljava/lang/StringBuilder;'
-Object allocated of type 'Ljava/nio/HeapCharBuffer;'
 	Allocating an array list
-Object allocated of type 'Ljava/util/ArrayList;'
-Object allocated of type 'Ljava/lang/StringBuilder;'
-Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+Object allocated of type 'java.util.ArrayList'
 	Adding a bunch of stuff to the array list
-Object allocated of type 'Ljava/lang/Object;'
-Object allocated of type 'Ljava/lang/Object;'
-Object allocated of type 'LTransform;'
-Object allocated of type 'Ljava/lang/StringBuilder;'
-Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+Object allocated of type 'java.lang.Object'
+Object allocated of type 'java.lang.Object'
+Object allocated of type 'Transform'
 	Allocating a linked list
-Object allocated of type 'Ljava/util/LinkedList;'
-Object allocated of type 'Ljava/lang/StringBuilder;'
-Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+Object allocated of type 'java.util.LinkedList'
 	Adding a bunch of stuff to the linked list
-Object allocated of type 'Ljava/lang/Object;'
-Object allocated of type 'Ljava/util/LinkedList$Node;'
-Object allocated of type 'Ljava/lang/Object;'
-Object allocated of type 'Ljava/util/LinkedList$Node;'
-Object allocated of type 'Ljava/util/LinkedList$Node;'
-Object allocated of type 'Ljava/util/LinkedList$Node;'
-Object allocated of type 'Ljava/util/LinkedList$Node;'
-Object allocated of type 'Ljava/util/LinkedList$Node;'
-Object allocated of type 'LTransform;'
-Object allocated of type 'Ljava/util/LinkedList$Node;'
-Object allocated of type 'Ljava/lang/StringBuilder;'
-Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+Object allocated of type 'java.lang.Object'
+Object allocated of type 'java.util.LinkedList$Node'
+Object allocated of type 'java.lang.Object'
+Object allocated of type 'java.util.LinkedList$Node'
+Object allocated of type 'java.util.LinkedList$Node'
+Object allocated of type 'java.util.LinkedList$Node'
+Object allocated of type 'java.util.LinkedList$Node'
+Object allocated of type 'java.util.LinkedList$Node'
+Object allocated of type 'Transform'
+Object allocated of type 'java.util.LinkedList$Node'
 	Throwing from down 4 stack frames
-Object allocated of type 'Ljava/lang/Exception;'
-Object allocated of type 'Ljava/lang/StringBuilder;'
-Object allocated of type 'Ljava/nio/HeapCharBuffer;'
+Object allocated of type 'java.lang.Exception'
 	Exception caught.
-Object allocated of type 'Ljava/lang/StringBuilder;'
-Object allocated of type 'Ljava/nio/HeapCharBuffer;'
 	Finishing test!
diff --git a/test/980-redefine-object/redefine_object.cc b/test/980-redefine-object/redefine_object.cc
deleted file mode 100644
index 1faf1a1..0000000
--- a/test/980-redefine-object/redefine_object.cc
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#include <inttypes.h>
-#include <iostream>
-
-#include "android-base/stringprintf.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "jni.h"
-#include "jvmti.h"
-#include "scoped_utf_chars.h"
-
-// Test infrastructure
-#include "jni_binder.h"
-#include "jvmti_helper.h"
-#include "test_env.h"
-
-namespace art {
-namespace Test980RedefineObjects {
-
-extern "C" JNIEXPORT void JNICALL Java_Main_bindFunctionsForClass(
-    JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass target) {
-  BindFunctionsOnClass(jvmti_env, env, target);
-}
-
-extern "C" JNIEXPORT void JNICALL Java_art_test_TestWatcher_NotifyConstructed(
-    JNIEnv* env, jclass TestWatcherClass ATTRIBUTE_UNUSED, jobject constructed) {
-  char* sig = nullptr;
-  char* generic_sig = nullptr;
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->GetClassSignature(env->GetObjectClass(constructed),
-                                                         &sig,
-                                                         &generic_sig))) {
-    // Exception.
-    return;
-  }
-  std::cout << "Object allocated of type '" << sig << "'" << std::endl;
-  jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(sig));
-  jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(generic_sig));
-}
-
-}  // namespace Test980RedefineObjects
-}  // namespace art
diff --git a/test/980-redefine-object/src-ex/TestWatcher.java b/test/980-redefine-object/src-ex/TestWatcher.java
index d15e688..c38e07b 100644
--- a/test/980-redefine-object/src-ex/TestWatcher.java
+++ b/test/980-redefine-object/src-ex/TestWatcher.java
@@ -16,10 +16,60 @@
 
 package art.test;
 
+import java.util.concurrent.locks.ReentrantLock;
+
 public class TestWatcher {
-  // NB This function is native since it is called in the Object.<init> method and so cannot cause
-  // any java allocations at all. The normal System.out.print* functions will cause allocations to
-  // occur so we cannot use them. This means the easiest way to report the object as being created
-  // is to go into native code and do it there.
-  public static native void NotifyConstructed(Object o);
+  // Lock to synchronize access to the static state of this class.
+  private static final ReentrantLock lock = new ReentrantLock();
+  private static volatile boolean criticalFailure = false;
+  private static boolean reportingEnabled = true;
+  private static boolean doingReport = false;
+
+  private static void MonitorEnter() {
+    lock.lock();
+  }
+
+  private static void MonitorExit() {
+    // Need to do this manually since we need to notify critical failure but would deadlock if
+    // waited for the unlock.
+    if (!lock.isHeldByCurrentThread()) {
+      NotifyCriticalFailure();
+      throw new IllegalMonitorStateException("Locking error!");
+    } else {
+      lock.unlock();
+    }
+  }
+
+  // Stops reporting. Must be paired with an EnableReporting call.
+  public static void DisableReporting() {
+    MonitorEnter();
+    reportingEnabled = false;
+  }
+
+  // Stops reporting. Must be paired with a DisableReporting call.
+  public static void EnableReporting() {
+    reportingEnabled = true;
+    MonitorExit();
+  }
+
+  public static void NotifyCriticalFailure() {
+    criticalFailure = true;
+  }
+
+  public static void NotifyConstructed(Object o) {
+    if (criticalFailure) {
+      // Something went very wrong. We are probably trying to report it so don't get in the way.
+      return;
+    }
+    MonitorEnter();
+    // We could enter an infinite loop if println allocates (which it does) so we disable
+    // reporting while we are doing a report. Since we are synchronized we won't miss any
+    // allocations.
+    if (reportingEnabled && !doingReport) {
+      doingReport = true;
+      System.out.println("Object allocated of type '" + o.getClass().getName() + "'");
+      doingReport = false;
+    }
+    MonitorExit();
+  }
 }
diff --git a/test/980-redefine-object/src/Main.java b/test/980-redefine-object/src/Main.java
index a50215e..7a82fde 100644
--- a/test/980-redefine-object/src/Main.java
+++ b/test/980-redefine-object/src/Main.java
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Base64;
 import java.util.LinkedList;
@@ -287,6 +288,31 @@
   private static final String LISTENER_LOCATION =
       System.getenv("DEX_LOCATION") + "/980-redefine-object-ex.jar";
 
+  private static Method doEnableReporting;
+  private static Method doDisableReporting;
+
+  private static void DisableReporting() {
+    if (doDisableReporting == null) {
+      return;
+    }
+    try {
+      doDisableReporting.invoke(null);
+    } catch (Exception e) {
+      throw new Error("Unable to disable reporting!");
+    }
+  }
+
+  private static void EnableReporting() {
+    if (doEnableReporting == null) {
+      return;
+    }
+    try {
+      doEnableReporting.invoke(null);
+    } catch (Exception e) {
+      throw new Error("Unable to enable reporting!");
+    }
+  }
+
   public static void main(String[] args) {
     art.Main.bindAgentJNIForClass(Main.class);
     doTest();
@@ -298,8 +324,8 @@
       addToBootClassLoader(LISTENER_LOCATION);
       // Load TestWatcher from the bootclassloader and make sure it is initialized.
       Class<?> testwatcher_class = Class.forName("art.test.TestWatcher", true, null);
-      // Bind the native functions of testwatcher_class.
-      bindFunctionsForClass(testwatcher_class);
+      doEnableReporting = testwatcher_class.getDeclaredMethod("EnableReporting");
+      doDisableReporting = testwatcher_class.getDeclaredMethod("DisableReporting");
     } catch (Exception e) {
       throw new Error("Exception while making testwatcher", e);
     }
@@ -308,9 +334,9 @@
   // NB This function will cause 2 objects of type "Ljava/nio/HeapCharBuffer;" and
   // "Ljava/nio/HeapCharBuffer;" to be allocated each time it is called.
   private static void safePrintln(Object o) {
-    System.out.flush();
-    System.out.print("\t" + o + "\n");
-    System.out.flush();
+    DisableReporting();
+    System.out.println("\t" + o);
+    EnableReporting();
   }
 
   private static void throwFrom(int depth) throws Exception {
@@ -382,8 +408,6 @@
 
   private static native void addToBootClassLoader(String s);
 
-  private static native void bindFunctionsForClass(Class<?> target);
-
   // Transforms the class
   private static native void doCommonClassRedefinition(Class<?> target,
                                                        byte[] class_file,
diff --git a/test/Android.bp b/test/Android.bp
index 8059a2f..538fac4 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -297,7 +297,6 @@
         "936-search-onload/search_onload.cc",
         "944-transform-classloaders/classloader.cc",
         "945-obsolete-native/obsolete_native.cc",
-        "980-redefine-object/redefine_object.cc",
         "983-source-transform-verify/source_transform.cc",
         "984-obsolete-invoke/obsolete_invoke.cc",
     ],