1 /*
2  * Copyright (C) 2018 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 import java.io.File;
18 import java.lang.reflect.Method;
19 import java.util.Base64;
20 
21 public class Main {
main(String[] args)22   public static void main(String[] args) throws ClassNotFoundException {
23     System.loadLibrary(args[0]);
24 
25     // Run the initialization routine. This will enable hidden API checks in
26     // the runtime, in case they are not enabled by default.
27     init();
28 
29     // Load the '-ex' APK and attach it to the boot class path.
30     appendToBootClassLoader(DEX_EXTRA, /* isCorePlatform */ false);
31 
32     // Find the test class in boot class loader and verify that its members are hidden.
33     Class<?> klass = Class.forName("art.Test999", true, BOOT_CLASS_LOADER);
34     assertFieldIsHidden(klass, "before redefinition");
35     assertMethodIsHidden(klass, "before redefinition");
36 
37     // Redefine the class using JVMTI. Use dex file without hiddenapi flags.
38     art.Redefinition.setTestConfiguration(art.Redefinition.Config.COMMON_REDEFINE);
39     art.Redefinition.doCommonClassRedefinition(klass, CLASS_BYTES, DEX_BYTES);
40 
41     // Verify that the class members are still hidden.
42     assertFieldIsHidden(klass, "after first redefinition");
43     assertMethodIsHidden(klass, "after first redefinition");
44   }
45 
assertMethodIsHidden(Class<?> klass, String msg)46   private static void assertMethodIsHidden(Class<?> klass, String msg) {
47     try {
48       klass.getDeclaredMethod("foo");
49       // Unexpected. Should have thrown NoSuchMethodException.
50       throw new RuntimeException("Method should not be accessible " + msg);
51     } catch (NoSuchMethodException ex) {
52     }
53   }
54 
assertFieldIsHidden(Class<?> klass, String msg)55   private static void assertFieldIsHidden(Class<?> klass, String msg) {
56     try {
57       klass.getDeclaredField("bar");
58       // Unexpected. Should have thrown NoSuchFieldException.
59       throw new RuntimeException("Field should not be accessible " + msg);
60     } catch (NoSuchFieldException ex) {
61     }
62   }
63 
64   private static final String DEX_EXTRA =
65       new File(System.getenv("DEX_LOCATION"), "999-redefine-hiddenapi-ex.jar").getAbsolutePath();
66 
67   private static ClassLoader BOOT_CLASS_LOADER = Object.class.getClassLoader();
68 
69   // Native functions. Note that these are implemented in 674-hiddenapi/hiddenapi.cc.
appendToBootClassLoader(String dexPath, boolean isCorePlatform)70   private static native void appendToBootClassLoader(String dexPath, boolean isCorePlatform);
init()71   private static native void init();
72 
73   /**
74    * base64 encoded class/dex file for
75    *
76    * public class Test999 {
77    *   public void foo() {
78    *     System.out.println("Goodbye");
79    *   }
80    *
81    *   public int bar = 64;
82    * }
83    */
84   private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
85     "yv66vgAAADUAIAoABwARCQAGABIJABMAFAgAFQoAFgAXBwAYBwAZAQADYmFyAQABSQEABjxpbml0" +
86     "PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAANmb28BAApTb3VyY2VGaWxlAQAMVGVz" +
87     "dDk5OS5qYXZhDAAKAAsMAAgACQcAGgwAGwAcAQAHR29vZGJ5ZQcAHQwAHgAfAQALYXJ0L1Rlc3Q5" +
88     "OTkBABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lv" +
89     "L1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xh" +
90     "bmcvU3RyaW5nOylWACEABgAHAAAAAQABAAgACQAAAAIAAQAKAAsAAQAMAAAAJwACAAEAAAALKrcA" +
91     "ASoQQLUAArEAAAABAA0AAAAKAAIAAAATAAQAGAABAA4ACwABAAwAAAAlAAIAAQAAAAmyAAMSBLYA" +
92     "BbEAAAABAA0AAAAKAAIAAAAVAAgAFgABAA8AAAACABA=");
93   private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
94     "ZGV4CjAzNQDlfmgFfKulToQpDF+P4dsgeOkgfzzH+5lgAwAAcAAAAHhWNBIAAAAAAAAAALQCAAAQ" +
95     "AAAAcAAAAAcAAACwAAAAAgAAAMwAAAACAAAA5AAAAAQAAAD0AAAAAQAAABQBAAAsAgAANAEAAIYB" +
96     "AACOAQAAlwEAAJoBAACpAQAAwAEAANQBAADoAQAA/AEAAAoCAAANAgAAEQIAABYCAAAbAgAAIAIA" +
97     "ACkCAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAJAAAACQAAAAYAAAAAAAAACgAAAAYAAACAAQAA" +
98     "AQAAAAsAAAAFAAIADQAAAAEAAAAAAAAAAQAAAAwAAAACAAEADgAAAAMAAAAAAAAAAQAAAAEAAAAD" +
99     "AAAAAAAAAAgAAAAAAAAAoAIAAAAAAAACAAEAAQAAAHQBAAAIAAAAcBADAAEAEwBAAFkQAAAOAAMA" +
100     "AQACAAAAeQEAAAgAAABiAAEAGgEBAG4gAgAQAA4AEwAOQAAVAA54AAAAAQAAAAQABjxpbml0PgAH" +
101     "R29vZGJ5ZQABSQANTGFydC9UZXN0OTk5OwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABJMamF2YS9s" +
102     "YW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0" +
103     "OTk5LmphdmEAAVYAAlZMAANiYXIAA2ZvbwADb3V0AAdwcmludGxuAHV+fkQ4eyJjb21waWxhdGlv" +
104     "bi1tb2RlIjoiZGVidWciLCJtaW4tYXBpIjoxLCJzaGEtMSI6ImQyMmFiNGYxOWI3NTYxNDQ3NTI4" +
105     "NTdjYTg2YjJjZWU0ZGQ5Y2ExNjYiLCJ2ZXJzaW9uIjoiMS40LjktZGV2In0AAAEBAQABAIGABLQC" +
106     "AQHUAgAAAAAOAAAAAAAAAAEAAAAAAAAAAQAAABAAAABwAAAAAgAAAAcAAACwAAAAAwAAAAIAAADM" +
107     "AAAABAAAAAIAAADkAAAABQAAAAQAAAD0AAAABgAAAAEAAAAUAQAAASAAAAIAAAA0AQAAAyAAAAIA" +
108     "AAB0AQAAARAAAAEAAACAAQAAAiAAABAAAACGAQAAACAAAAEAAACgAgAAAxAAAAEAAACwAgAAABAA" +
109     "AAEAAAC0AgAA");
110 }
111