1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package art;
18 
19 import java.util.function.Consumer;
20 import java.util.Base64;
21 
22 public class Test919 {
23 
24   static class Transform {
25     private Consumer<String> reporter;
Transform(Consumer<String> reporter)26     public Transform(Consumer<String> reporter) {
27       this.reporter = reporter;
28     }
29 
Start()30     private void Start() {
31       reporter.accept("hello - private");
32     }
33 
Finish()34     private void Finish() {
35       reporter.accept("goodbye - private");
36     }
37 
sayHi(Runnable r)38     public void sayHi(Runnable r) {
39       reporter.accept("Pre Start private method call");
40       Start();
41       reporter.accept("Post Start private method call");
42       r.run();
43       reporter.accept("Pre Finish private method call");
44       Finish();
45       reporter.accept("Post Finish private method call");
46     }
47   }
48 
49 
50   // What follows is the base64 encoded representation of the following class:
51   //
52   // import java.util.function.Consumer;
53   //
54   // static class Transform {
55   //   private Consumer<String> reporter;
56   //   public Transform(Consumer<String> reporter) {
57   //     this.reporter = reporter;
58   //   }
59   //
60   //   private void Start() {
61   //     reporter.accept("Hello - private - Transformed");
62   //   }
63   //
64   //   private void Finish() {
65   //     reporter.accept("Goodbye - private - Transformed");
66   //   }
67   //
68   //   public void sayHi(Runnable r) {
69   //     reporter.accept("pre Start private method call - Transformed");
70   //     Start();
71   //     reporter.accept("post Start private method call - Transformed");
72   //     r.run();
73   //     reporter.accept("pre Finish private method call - Transformed");
74   //     Finish();
75   //     reporter.accept("post Finish private method call - Transformed");
76   //   }
77   // }
78   private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
79     "yv66vgAAADQAOAoADgAfCQANACAIACELACIAIwgAJAgAJQoADQAmCAAnCwAoACkIACoKAA0AKwgA" +
80     "LAcALgcAMQEACHJlcG9ydGVyAQAdTGphdmEvdXRpbC9mdW5jdGlvbi9Db25zdW1lcjsBAAlTaWdu" +
81     "YXR1cmUBADFMamF2YS91dGlsL2Z1bmN0aW9uL0NvbnN1bWVyPExqYXZhL2xhbmcvU3RyaW5nOz47" +
82     "AQAGPGluaXQ+AQAgKExqYXZhL3V0aWwvZnVuY3Rpb24vQ29uc3VtZXI7KVYBAARDb2RlAQAPTGlu" +
83     "ZU51bWJlclRhYmxlAQA0KExqYXZhL3V0aWwvZnVuY3Rpb24vQ29uc3VtZXI8TGphdmEvbGFuZy9T" +
84     "dHJpbmc7PjspVgEABVN0YXJ0AQADKClWAQAGRmluaXNoAQAFc2F5SGkBABcoTGphdmEvbGFuZy9S" +
85     "dW5uYWJsZTspVgEAClNvdXJjZUZpbGUBAAxUZXN0OTE5LmphdmEMABMAGQwADwAQAQAdSGVsbG8g" +
86     "LSBwcml2YXRlIC0gVHJhbnNmb3JtZWQHADIMADMANAEAH0dvb2RieWUgLSBwcml2YXRlIC0gVHJh" +
87     "bnNmb3JtZWQBACtwcmUgU3RhcnQgcHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRyYW5zZm9ybWVkDAAY" +
88     "ABkBACxwb3N0IFN0YXJ0IHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAcANQwANgAZ" +
89     "AQAscHJlIEZpbmlzaCBwcml2YXRlIG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQMABoAGQEALXBv" +
90     "c3QgRmluaXNoIHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAcANwEAFWFydC9UZXN0" +
91     "OTE5JFRyYW5zZm9ybQEACVRyYW5zZm9ybQEADElubmVyQ2xhc3NlcwEAEGphdmEvbGFuZy9PYmpl" +
92     "Y3QBABtqYXZhL3V0aWwvZnVuY3Rpb24vQ29uc3VtZXIBAAZhY2NlcHQBABUoTGphdmEvbGFuZy9P" +
93     "YmplY3Q7KVYBABJqYXZhL2xhbmcvUnVubmFibGUBAANydW4BAAthcnQvVGVzdDkxOQAgAA0ADgAA" +
94     "AAEAAgAPABAAAQARAAAAAgASAAQAAQATABQAAgAVAAAAKgACAAIAAAAKKrcAASortQACsQAAAAEA" +
95     "FgAAAA4AAwAAAAgABAAJAAkACgARAAAAAgAXAAIAGAAZAAEAFQAAACgAAgABAAAADCq0AAISA7kA" +
96     "BAIAsQAAAAEAFgAAAAoAAgAAAA0ACwAOAAIAGgAZAAEAFQAAACgAAgABAAAADCq0AAISBbkABAIA" +
97     "sQAAAAEAFgAAAAoAAgAAABEACwASAAEAGwAcAAEAFQAAAG8AAgACAAAAOyq0AAISBrkABAIAKrcA" +
98     "Byq0AAISCLkABAIAK7kACQEAKrQAAhIKuQAEAgAqtwALKrQAAhIMuQAEAgCxAAAAAQAWAAAAIgAI" +
99     "AAAAFQALABYADwAXABoAGAAgABkAKwAaAC8AGwA6ABwAAgAdAAAAAgAeADAAAAAKAAEADQAtAC8A" +
100     "CA==");
101   private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
102     "ZGV4CjAzNQBeEZYBAAAAAAAAAAAAAAAAAAAAAAAAAACMBgAAcAAAAHhWNBIAAAAAAAAAAMgFAAAi" +
103     "AAAAcAAAAAkAAAD4AAAABAAAABwBAAABAAAATAEAAAcAAABUAQAAAQAAAIwBAADgBAAArAEAAKwB" +
104     "AACvAQAAsgEAALoBAAC+AQAAxAEAAMwBAADtAQAADAIAACUCAAA0AgAAWAIAAHgCAACXAgAAqwIA" +
105     "AMECAADVAgAA8wIAABIDAAAZAwAAJwMAADIDAAA1AwAAOQMAAEEDAABOAwAAVAMAAIMDAACxAwAA" +
106     "3wMAAAwEAAAWBAAAGwQAACIEAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAAEQAAABUAAAAV" +
107     "AAAACAAAAAAAAAAWAAAACAAAADQEAAAWAAAACAAAADwEAAAWAAAACAAAACwEAAAAAAcAHgAAAAAA" +
108     "AwACAAAAAAAAAAUAAAAAAAAAEgAAAAAAAgAgAAAABQAAAAIAAAAGAAAAHwAAAAcAAQAXAAAAAAAA" +
109     "AAAAAAAFAAAAAAAAABMAAACoBQAARAUAAAAAAAABKAABPAAGPGluaXQ+AAI+OwAEPjspVgAGRmlu" +
110     "aXNoAB9Hb29kYnllIC0gcHJpdmF0ZSAtIFRyYW5zZm9ybWVkAB1IZWxsbyAtIHByaXZhdGUgLSBU" +
111     "cmFuc2Zvcm1lZAAXTGFydC9UZXN0OTE5JFRyYW5zZm9ybTsADUxhcnQvVGVzdDkxOTsAIkxkYWx2" +
112     "aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNs" +
113     "YXNzOwAdTGRhbHZpay9hbm5vdGF0aW9uL1NpZ25hdHVyZTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAU" +
114     "TGphdmEvbGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3RyaW5nOwAcTGphdmEvdXRpbC9mdW5j" +
115     "dGlvbi9Db25zdW1lcgAdTGphdmEvdXRpbC9mdW5jdGlvbi9Db25zdW1lcjsABVN0YXJ0AAxUZXN0" +
116     "OTE5LmphdmEACVRyYW5zZm9ybQABVgACVkwABmFjY2VwdAALYWNjZXNzRmxhZ3MABG5hbWUALXBv" +
117     "c3QgRmluaXNoIHByaXZhdGUgbWV0aG9kIGNhbGwgLSBUcmFuc2Zvcm1lZAAscG9zdCBTdGFydCBw" +
118     "cml2YXRlIG1ldGhvZCBjYWxsIC0gVHJhbnNmb3JtZWQALHByZSBGaW5pc2ggcHJpdmF0ZSBtZXRo" +
119     "b2QgY2FsbCAtIFRyYW5zZm9ybWVkACtwcmUgU3RhcnQgcHJpdmF0ZSBtZXRob2QgY2FsbCAtIFRy" +
120     "YW5zZm9ybWVkAAhyZXBvcnRlcgADcnVuAAVzYXlIaQAFdmFsdWUAAAAAAQAAAAcAAAABAAAABQAA" +
121     "AAEAAAAGAAAACAEABw4BAw8BAg8AEQAHDgEIDwANAAcOAQgPABUBAAcOAQgPAQMPAQgPAQMPAQgP" +
122     "AQMPAQgPAAACAAIAAQAAAEQEAAAGAAAAcBAEAAAAWwEAAA4AAwABAAIAAABQBAAACQAAAFQgAAAb" +
123     "AQYAAAByIAYAEAAOAAAAAwABAAIAAABYBAAACQAAAFQgAAAbAQcAAAByIAYAEAAOAAAABAACAAIA" +
124     "AABgBAAAKgAAAFQgAAAbAR0AAAByIAYAEABwEAIAAgBUIAAAGwEbAAAAciAGABAAchAFAAMAVCAA" +
125     "ABsBHAAAAHIgBgAQAHAQAQACAFQgAAAbARoAAAByIAYAEAAOAAABAwEAAgCBgAT8CAECmAkBArwJ" +
126     "AwHgCQICASEYAQIDAhgECBkXFAIEASEcBBcQFwEXDxcDAgQBIRwFFwAXEBcBFw8XBAAAAAIAAABc" +
127     "BQAAYgUAAAEAAABrBQAAAQAAAHkFAACMBQAAAQAAAAEAAAAAAAAAAAAAAJgFAAAAAAAAoAUAABAA" +
128     "AAAAAAAAAQAAAAAAAAABAAAAIgAAAHAAAAACAAAACQAAAPgAAAADAAAABAAAABwBAAAEAAAAAQAA" +
129     "AEwBAAAFAAAABwAAAFQBAAAGAAAAAQAAAIwBAAACIAAAIgAAAKwBAAABEAAAAwAAACwEAAADIAAA" +
130     "BAAAAEQEAAABIAAABAAAAHwEAAAAIAAAAQAAAEQFAAAEIAAABAAAAFwFAAADEAAAAwAAAIwFAAAG" +
131     "IAAAAQAAAKgFAAAAEAAAAQAAAMgFAAA=");
132 
133   // A class that we can use to keep track of the output of this test.
134   private static class TestWatcher implements Consumer<String> {
135     private StringBuilder sb;
TestWatcher()136     public TestWatcher() {
137       sb = new StringBuilder();
138     }
139 
140     @Override
accept(String s)141     public void accept(String s) {
142       sb.append(s);
143       sb.append('\n');
144     }
145 
getOutput()146     public String getOutput() {
147       return sb.toString();
148     }
149   }
150 
run()151   public static void run() {
152     Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE);
153     TestWatcher w = new TestWatcher();
154     doTest(new Transform(w), w);
155   }
156 
doTest(Transform t, TestWatcher w)157   public static void doTest(Transform t, TestWatcher w) {
158     Runnable do_redefinition = () -> {
159       w.accept("transforming calling function");
160       Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES);
161     };
162     // This just prints something out to show we are running the Runnable.
163     Runnable say_nothing = () -> { w.accept("Not doing anything here"); };
164 
165     // Try and redefine.
166     t.sayHi(say_nothing);
167     t.sayHi(do_redefinition);
168     t.sayHi(say_nothing);
169 
170     // Print output of last run.
171     System.out.print(w.getOutput());
172   }
173 }
174