• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 com.android.bootimageprofile;
18 
19 import static org.junit.Assert.assertTrue;
20 
21 import com.android.tradefed.device.ITestDevice;
22 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
23 import com.android.tradefed.testtype.IDeviceTest;
24 
25 import org.junit.Test;
26 import org.junit.runner.RunWith;
27 
28 @RunWith(DeviceJUnit4ClassRunner.class)
29 public class BootImageProfileTest implements IDeviceTest {
30     private ITestDevice mTestDevice;
31     private static final String SYSTEM_SERVER_PROFILE =
32             "/data/misc/profiles/cur/0/android/primary.prof";
33     private static final boolean USE_PHENOTYPE = false;
34 
35     @Override
setDevice(ITestDevice testDevice)36     public void setDevice(ITestDevice testDevice) {
37         mTestDevice = testDevice;
38     }
39 
40     @Override
getDevice()41     public ITestDevice getDevice() {
42         return mTestDevice;
43     }
44 
getProperty(String property)45     private String getProperty(String property) throws Exception {
46         if (USE_PHENOTYPE) {
47             return mTestDevice.getProperty("persist.device_config.runtime_native_boot."
48                     + property);
49         } else {
50             return mTestDevice.executeShellCommand("getprop dalvik.vm." + property).trim();
51         }
52     }
53 
setProperty(String property, String value)54     private String setProperty(String property, String value) throws Exception {
55         if (USE_PHENOTYPE) {
56             return mTestDevice.executeShellCommand(
57                 "device_config put runtime_native_boot " + property + " " + value);
58         } else {
59             return mTestDevice.executeShellCommand(
60                 "setprop dalvik.vm." + property + " " + value);
61         }
62     }
63 
64     /**
65      * Validate that the boot image profile properties are set.
66      */
validateProperties()67     public void validateProperties() throws Exception {
68         String res = getProperty("profilebootclasspath");
69         assertTrue("profile boot class path not enabled: " + res, "true".equals(res));
70         res = getProperty("profilesystemserver");
71         assertTrue("profile system server not enabled: " + res, "true".equals(res));
72     }
73 
forceSaveProfile(String pkg)74     private boolean forceSaveProfile(String pkg) throws Exception {
75         String pid = mTestDevice.executeShellCommand("pidof " + pkg).trim();
76         if (pid.length() == 0) {
77             // Not yet running.
78             return false;
79         }
80         String res = mTestDevice.executeShellCommand("kill -s SIGUSR1 " + pid).trim();
81         return res.length() == 0;
82     }
83 
84     @Test
testSystemServerProfile()85     public void testSystemServerProfile() throws Exception {
86         final int numIterations = 30;
87         String res;
88         // Set properties and wait for them to be readable.
89         for (int i = 1; i <= numIterations; ++i) {
90             String pbcp = getProperty("profilebootclasspath");
91             boolean profileBootClassPath = "true".equals(pbcp);
92             String pss = getProperty("profilesystemserver");
93             boolean profileSystemServer = "true".equals(pss);
94             if (profileBootClassPath && profileSystemServer) {
95                 break;
96             }
97             if (i == numIterations) {
98                 assertTrue("profile system server not enabled: " + pss, profileSystemServer);
99                 assertTrue("profile boot class path not enabled: " + pbcp, profileBootClassPath);
100             }
101 
102             setProperty("profilebootclasspath", "true");
103             setProperty("profilesystemserver", "true");
104             Thread.sleep(1000);
105         }
106 
107         // Restart shell and wait for system boot.
108         res = mTestDevice.executeShellCommand("stop");
109         assertTrue("stop shell: " + res, res.length() == 0);
110         res = mTestDevice.executeShellCommand("start");
111         assertTrue("start shell: " + res, res.length() == 0);
112         for (int i = 1; i <= numIterations; ++i) {
113             String pbcp = getProperty("profilebootclasspath");
114             boolean profileBootClassPath = "true".equals(pbcp);
115             String pss = getProperty("profilesystemserver");
116             boolean profileSystemServer = "true".equals(pss);
117             if (profileBootClassPath && profileSystemServer) {
118                 break;
119             }
120             if (i == numIterations) {
121                 assertTrue("profile system server not enabled: " + pss, profileSystemServer);
122                 assertTrue("profile boot class path not enabled: " + pbcp, profileBootClassPath);
123             }
124             Thread.sleep(1000);
125         }
126 
127         // Trunacte the profile before force it to be saved to prevent previous profiles
128         // causing the test to pass.
129         res = mTestDevice.executeShellCommand("truncate -s 0 " + SYSTEM_SERVER_PROFILE).trim();
130         assertTrue(res, res.length() == 0);
131         // Wait up to 20 seconds for the profile to be saved.
132         for (int i = 1; i <= numIterations; ++i) {
133             // Force save the profile since we truncated it.
134             if (forceSaveProfile("system_server")) {
135                 // Might fail if system server is not yet running.
136                 String s = mTestDevice.executeShellCommand(
137                         "wc -c <" + SYSTEM_SERVER_PROFILE).trim();
138                 if ("0".equals(s)) {
139                     Thread.sleep(1000);
140                     continue;
141                 }
142             }
143 
144             // In case the profile is partially saved, wait an extra second.
145             Thread.sleep(1000);
146 
147             // Validate that properties are still set.
148             validateProperties();
149 
150             // Validate that the profile is non empty.
151             res = mTestDevice.executeShellCommand("profman --dump-only --profile-file="
152                     + SYSTEM_SERVER_PROFILE);
153             boolean sawFramework = false;
154             boolean sawServices = false;
155             for (String line : res.split("\n")) {
156                 if (line.contains("framework.jar")) {
157                     sawFramework = true;
158                 } else if (line.contains("framework-minus-apex.jar")) {
159                     sawFramework = true;
160                 } else if (line.contains("services.jar")) {
161                     sawServices = true;
162                 }
163             }
164             if (i == numIterations) {
165                 // Only assert for last iteration since there are race conditions where the package
166                 // manager might not be started whewn the profile saves.
167                 assertTrue("Did not see framework.jar in " + res, sawFramework);
168                 assertTrue("Did not see services.jar in " + res, sawServices);
169             }
170 
171             // Test the profile contents contain common methods for core-oj that would normally be
172             // AOT compiled. Also test that services.jar has PackageManagerService.<init> since the
173             // package manager service should always be created during boot.
174             res = mTestDevice.executeShellCommand(
175                     "profman --dump-classes-and-methods --profile-file="
176                     + SYSTEM_SERVER_PROFILE + " --apk=/apex/com.android.art/javalib/core-oj.jar"
177                     + " --apk=/system/framework/services.jar");
178             boolean sawObjectInit = false;
179             boolean sawPmInit = false;
180             for (String line : res.split("\n")) {
181                 if (line.contains("Ljava/lang/Object;-><init>()V")) {
182                     sawObjectInit = true;
183                 } else if (line.contains("Lcom/android/server/pm/PackageManagerService;-><init>")) {
184                     sawPmInit = true;
185                 }
186             }
187             if (i == numIterations) {
188                 assertTrue("Did not see Object.<init> in " + res, sawObjectInit);
189                 assertTrue("Did not see PackageManagerService.<init> in " + res, sawPmInit);
190             }
191 
192             if (sawFramework && sawServices && sawObjectInit && sawPmInit) {
193                 break;  // Asserts passed, exit.
194             }
195         }
196     }
197 }
198