test/hotspot/jtreg/runtime/appcds/jvmti/InstrumentationApp.java
changeset 57567 b000362a89a0
parent 57566 ad84ae073248
child 57568 460ac76019f4
equal deleted inserted replaced
57566:ad84ae073248 57567:b000362a89a0
     1 /*
       
     2  * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  *
       
    23  */
       
    24 
       
    25 import java.lang.instrument.ClassDefinition;
       
    26 import java.lang.instrument.Instrumentation;
       
    27 import java.lang.instrument.UnmodifiableClassException;
       
    28 import java.net.URL;
       
    29 import java.net.URLClassLoader;
       
    30 import java.io.File;
       
    31 import java.io.FileWriter;
       
    32 import java.security.CodeSigner;
       
    33 import java.security.CodeSource;
       
    34 import java.security.ProtectionDomain;
       
    35 import sun.hotspot.WhiteBox;
       
    36 
       
    37 public class InstrumentationApp {
       
    38     static WhiteBox wb = WhiteBox.getWhiteBox();
       
    39 
       
    40     public static final String COO_CLASS_NAME = "InstrumentationApp$Coo";
       
    41 
       
    42     public static interface Intf {            // Loaded from Boot class loader (-Xbootclasspath/a).
       
    43         public String get();
       
    44     }
       
    45     public static class Bar implements Intf { // Loaded from Boot class loader.
       
    46         public String get() {
       
    47             // The initial transform:
       
    48             //      change "buzz" -> "fuzz"
       
    49             // The re-transform:
       
    50             //      change "buzz" -> "guzz"
       
    51             return "buzz";
       
    52         }
       
    53     }
       
    54     public static class Foo implements Intf { // Loaded from AppClassLoader, or from a custom loader
       
    55         public String get() {
       
    56             // The initial transform:
       
    57             //      change "buzz" -> "fuzz"
       
    58             // The re-transform:
       
    59             //      change "buzz" -> "guzz"
       
    60             return "buzz";
       
    61         }
       
    62     }
       
    63     public static class Coo implements Intf { // Loaded from custom class loader.
       
    64         public String get() {
       
    65             // The initial transform:
       
    66             //      change "buzz" -> "fuzz"
       
    67             // The re-transform:
       
    68             //      change "buzz" -> "guzz"
       
    69             return "buzz";
       
    70         }
       
    71     }
       
    72 
       
    73     // This class file should be archived if AppCDSv2 is enabled on this platform. See
       
    74     // the comments around the call to TestCommon.dump in InstrumentationTest.java.
       
    75     public static class ArchivedIfAppCDSv2Enabled {}
       
    76 
       
    77     public static boolean isAppCDSV2Enabled() {
       
    78         return wb.isSharedClass(ArchivedIfAppCDSv2Enabled.class);
       
    79     }
       
    80 
       
    81     public static class MyLoader extends URLClassLoader {
       
    82         public MyLoader(URL[] urls, ClassLoader parent, File jar) {
       
    83             super(urls, parent);
       
    84             this.jar = jar;
       
    85         }
       
    86         File jar;
       
    87 
       
    88         @Override
       
    89         protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
       
    90             synchronized (getClassLoadingLock(name)) {
       
    91                 // First, check if the class has already been loaded
       
    92                 Class<?> clz = findLoadedClass(name);
       
    93                 if (clz != null) {
       
    94                     return clz;
       
    95                 }
       
    96 
       
    97                 if (name.equals(COO_CLASS_NAME)) {
       
    98                     try {
       
    99                         byte[] buff = Util.getClassFileFromJar(jar, name);
       
   100                         return defineClass(name, buff, 0, buff.length);
       
   101                     } catch (Throwable t) {
       
   102                         t.printStackTrace();
       
   103                         throw new RuntimeException("Unexpected", t);
       
   104                     }
       
   105                 }
       
   106             }
       
   107             return super.loadClass(name, resolve);
       
   108         }
       
   109     }
       
   110 
       
   111     static int numTests = 0;
       
   112     static int failed = 0;
       
   113     static boolean isAttachingAgent = false;
       
   114     static Instrumentation instrumentation;
       
   115 
       
   116     public static void main(String args[]) throws Throwable {
       
   117         System.out.println("INFO: AppCDSv1 " + (wb.isSharedClass(InstrumentationApp.class) ? "enabled" :"disabled"));
       
   118         System.out.println("INFO: AppCDSv2 " + (isAppCDSV2Enabled()                        ? "enabled" : "disabled"));
       
   119 
       
   120         String flagFile = args[0];
       
   121         File bootJar = new File(args[1]);
       
   122         File appJar  = new File(args[2]);
       
   123         File custJar = new File(args[3]);
       
   124         waitAttach(flagFile);
       
   125 
       
   126         instrumentation = InstrumentationRegisterClassFileTransformer.getInstrumentation();
       
   127         System.out.println("INFO: instrumentation = " + instrumentation);
       
   128 
       
   129         testBootstrapCDS("Bootstrap Loader", bootJar);
       
   130         testAppCDSv1("Application Loader", appJar);
       
   131 
       
   132         if (isAppCDSV2Enabled()) {
       
   133           testAppCDSv2("Custom Loader (unregistered)", custJar);
       
   134         }
       
   135 
       
   136         if (failed > 0) {
       
   137             throw new RuntimeException("FINAL RESULT: " + failed + " out of " + numTests + " test case(s) have failed");
       
   138         } else {
       
   139             System.out.println("FINAL RESULT: All " + numTests + " test case(s) have passed!");
       
   140         }
       
   141     }
       
   142 
       
   143     static void waitAttach(String flagFile) throws Throwable {
       
   144         // See InstrumentationTest.java for the hand-shake protocol.
       
   145         if (!flagFile.equals("noattach")) {
       
   146             File f = new File(flagFile);
       
   147             try (FileWriter fw = new FileWriter(f)) {
       
   148                 long pid = ProcessHandle.current().pid();
       
   149                 System.out.println("my pid = " + pid);
       
   150                 fw.write(Long.toString(pid));
       
   151                 fw.write("\n");
       
   152                 for (int i=0; i<10; i++) {
       
   153                   // Parent process waits until we have written more than 100 bytes, so it won't
       
   154                   // read a partial pid
       
   155                   fw.write("==========");
       
   156                 }
       
   157                 fw.close();
       
   158             }
       
   159 
       
   160             long start = System.currentTimeMillis();
       
   161             while (f.exists()) {
       
   162                 long elapsed = System.currentTimeMillis() - start;
       
   163                 System.out.println(".... (" + elapsed + ") waiting for deletion of " + f);
       
   164                 Thread.sleep(1000);
       
   165             }
       
   166             System.out.println("Attach succeeded (child)");
       
   167             isAttachingAgent = true;
       
   168         }
       
   169     }
       
   170 
       
   171     static void testBootstrapCDS(String group, File jar) throws Throwable {
       
   172         doTest(group, new Bar(), jar);
       
   173     }
       
   174 
       
   175     static void testAppCDSv1(String group, File jar) throws Throwable {
       
   176         doTest(group, new Foo(), jar);
       
   177     }
       
   178 
       
   179     static void testAppCDSv2(String group, File jar) throws Throwable {
       
   180         URL[] urls = new URL[] {jar.toURI().toURL()};
       
   181         MyLoader loader = new MyLoader(urls, InstrumentationApp.class.getClassLoader(), jar);
       
   182         Class klass = loader.loadClass(COO_CLASS_NAME);
       
   183         doTest(group, (Intf)klass.newInstance(), jar);
       
   184     }
       
   185 
       
   186     static void doTest(String group, Intf object, File jar) throws Throwable {
       
   187         Class klass = object.getClass();
       
   188         System.out.println();
       
   189         System.out.println("++++++++++++++++++++++++++");
       
   190         System.out.println("Test group: " + group);
       
   191         System.out.println("Testing with classloader = " + klass.getClassLoader());
       
   192         System.out.println("Testing with class       = " + klass);
       
   193         System.out.println("++++++++++++++++++++++++++");
       
   194 
       
   195         // Initial transform
       
   196         String f = object.get();
       
   197         assertTrue(f.equals("fuzz"), "object.get(): Initial transform should give 'fuzz'", f);
       
   198 
       
   199         // Retransform
       
   200         f = "(failed)";
       
   201         try {
       
   202             instrumentation.retransformClasses(klass);
       
   203             f = object.get();
       
   204         } catch (UnmodifiableClassException|UnsupportedOperationException e) {
       
   205             e.printStackTrace();
       
   206         }
       
   207         assertTrue(f.equals("guzz"), "object.get(): retransformation should give 'guzz'", f);
       
   208 
       
   209         // Redefine
       
   210         byte[] buff = Util.getClassFileFromJar(jar, klass.getName());
       
   211         Util.replace(buff, "buzz", "huzz");
       
   212         f = "(failed)";
       
   213         try {
       
   214             instrumentation.redefineClasses(new ClassDefinition(klass, buff));
       
   215             f = object.get();
       
   216         } catch (UnmodifiableClassException|UnsupportedOperationException e) {
       
   217             e.printStackTrace();
       
   218         }
       
   219         assertTrue(f.equals("quzz"), "object.get(): redefinition should give 'quzz'", f);
       
   220 
       
   221         System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++ (done)\n\n");
       
   222     }
       
   223 
       
   224     private static void assertTrue(boolean expr, String msg, String string) {
       
   225         numTests ++;
       
   226         System.out.printf("Test case %2d ", numTests);
       
   227 
       
   228         if (expr) {
       
   229             System.out.println("PASSED: " + msg + " and we got '" + string + "'");
       
   230         } else {
       
   231             failed ++;
       
   232             System.out.println("FAILED: " + msg + " but we got '" + string + "'");
       
   233         }
       
   234     }
       
   235 }