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