• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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.cts.runner;
18 
19 import android.app.ActivityManager;
20 import android.app.KeyguardManager;
21 import android.content.Context;
22 import android.content.pm.PackageManager;
23 import android.text.TextUtils;
24 import android.util.Log;
25 
26 import androidx.test.internal.runner.listener.InstrumentationRunListener;
27 
28 import junit.framework.TestCase;
29 
30 import org.junit.runner.Description;
31 import org.junit.runner.notification.RunListener;
32 
33 import java.io.BufferedReader;
34 import java.io.File;
35 import java.io.IOException;
36 import java.io.InputStreamReader;
37 import java.lang.Class;
38 import java.lang.ReflectiveOperationException;
39 import java.lang.reflect.Field;
40 import java.lang.reflect.Modifier;
41 import java.net.Authenticator;
42 import java.net.CookieHandler;
43 import java.net.ResponseCache;
44 import java.util.Locale;
45 import java.util.Properties;
46 import java.util.TimeZone;
47 
48 import javax.net.ssl.HostnameVerifier;
49 import javax.net.ssl.HttpsURLConnection;
50 import javax.net.ssl.SSLSocketFactory;
51 
52 /**
53  * A {@link RunListener} for CTS. Sets the system properties necessary for many
54  * core tests to run. This is needed because there are some core tests that need
55  * writing access to the file system.
56  * Finally, we add a means to free memory allocated by a TestCase after its
57  * execution.
58  */
59 public class CtsTestRunListener extends InstrumentationRunListener {
60 
61     private static final String TAG = "CtsTestRunListener";
62 
63     private TestEnvironment mEnvironment;
64     private Class<?> lastClass;
65 
66     @Override
testRunStarted(Description description)67     public void testRunStarted(Description description) throws Exception {
68         mEnvironment = new TestEnvironment(getInstrumentation().getTargetContext());
69 
70         // We might want to move this to /sdcard, if is is mounted/writable.
71         File cacheDir = getInstrumentation().getTargetContext().getCacheDir();
72         System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath());
73 
74         // attempt to disable keyguard, if current test has permission to do so
75         // TODO: move this to a better place, such as InstrumentationTestRunner
76         // ?
77         if (getInstrumentation().getContext().checkCallingOrSelfPermission(
78                 android.Manifest.permission.DISABLE_KEYGUARD)
79                 == PackageManager.PERMISSION_GRANTED) {
80             Log.i(TAG, "Disabling keyguard");
81             KeyguardManager keyguardManager =
82                     (KeyguardManager) getInstrumentation().getContext().getSystemService(
83                             Context.KEYGUARD_SERVICE);
84             keyguardManager.newKeyguardLock("cts").disableKeyguard();
85         } else {
86             Log.i(TAG, "Test lacks permission to disable keyguard. " +
87                     "UI based tests may fail if keyguard is up");
88         }
89     }
90 
91     @Override
testStarted(Description description)92     public void testStarted(Description description) throws Exception {
93         if (description.getTestClass() != lastClass) {
94             lastClass = description.getTestClass();
95             printMemory(description.getTestClass());
96         }
97 
98         mEnvironment.reset();
99     }
100 
101     @Override
testFinished(Description description)102     public void testFinished(Description description) {
103         // no way to implement this in JUnit4...
104         // offending test cases that need this logic should probably be cleaned
105         // up individually
106         // if (test instanceof TestCase) {
107         // cleanup((TestCase) test);
108         // }
109     }
110 
111     /**
112      * Dumps some memory info.
113      */
printMemory(Class<?> testClass)114     private void printMemory(Class<?> testClass) {
115         Runtime runtime = Runtime.getRuntime();
116 
117         long total = runtime.totalMemory();
118         long free = runtime.freeMemory();
119         long used = total - free;
120 
121         Log.d(TAG, "Total memory  : " + total);
122         Log.d(TAG, "Used memory   : " + used);
123         Log.d(TAG, "Free memory   : " + free);
124 
125         String tempdir = System.getProperty("java.io.tmpdir", "");
126         // TODO: Remove these extra Logs added to debug a specific timeout problem.
127         Log.d(TAG, "java.io.tmpdir is:" + tempdir);
128 
129         if (!TextUtils.isEmpty(tempdir)) {
130             String[] commands = {"df", tempdir};
131             BufferedReader in = null;
132             try {
133                 Log.d(TAG, "About to .exec df");
134                 Process proc = runtime.exec(commands);
135                 Log.d(TAG, ".exec returned");
136                 in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
137                 Log.d(TAG, "Stream reader created");
138                 String line;
139                 while ((line = in.readLine()) != null) {
140                     Log.d(TAG, line);
141                 }
142             } catch (IOException e) {
143                 Log.d(TAG, "Exception: " + e.toString());
144                 // Well, we tried
145             } finally {
146                 Log.d(TAG, "In finally");
147                 if (in != null) {
148                     try {
149                         in.close();
150                     } catch (IOException e) {
151                         // Meh
152                     }
153                 }
154             }
155         }
156 
157         Log.d(TAG, "Now executing : " + testClass.getName());
158     }
159 
160     /**
161      * Nulls all non-static reference fields in the given test class. This
162      * method helps us with those test classes that don't have an explicit
163      * tearDown() method. Normally the garbage collector should take care of
164      * everything, but since JUnit keeps references to all test cases, a little
165      * help might be a good idea.
166      */
cleanup(TestCase test)167     private void cleanup(TestCase test) {
168         Class<?> clazz = test.getClass();
169 
170         while (clazz != TestCase.class) {
171             Field[] fields = clazz.getDeclaredFields();
172             for (int i = 0; i < fields.length; i++) {
173                 Field f = fields[i];
174                 if (!f.getType().isPrimitive() &&
175                         !Modifier.isStatic(f.getModifiers())) {
176                     try {
177                         f.setAccessible(true);
178                         f.set(test, null);
179                     } catch (Exception ignored) {
180                         // Nothing we can do about it.
181                     }
182                 }
183             }
184 
185             clazz = clazz.getSuperclass();
186         }
187     }
188 
189     private interface TestEnvironmentResetter {
getDateFormatIs24Hour()190         Boolean getDateFormatIs24Hour();
setDateFormatIs24Hour(Boolean value)191         void setDateFormatIs24Hour(Boolean value);
createDefaultProperties()192         Properties createDefaultProperties();
193     }
194 
195     private static class AndroidTestEnvironmentResetter implements TestEnvironmentResetter {
196         private final Field mDateFormatIs24HourField;
197 
AndroidTestEnvironmentResetter()198         AndroidTestEnvironmentResetter() {
199             try {
200                 Class<?> dateFormatClass = Class.forName("java.text.DateFormat");
201                 mDateFormatIs24HourField = dateFormatClass.getDeclaredField("is24Hour");
202             } catch (ReflectiveOperationException e) {
203                 throw new AssertionError("Missing DateFormat.is24Hour", e);
204             }
205         }
206 
207         @Override
getDateFormatIs24Hour()208         public Boolean getDateFormatIs24Hour() {
209             try {
210                 return (Boolean) mDateFormatIs24HourField.get(null);
211             } catch (ReflectiveOperationException e) {
212                 throw new AssertionError("Unable to get java.text.DateFormat.is24Hour", e);
213             }
214         }
215 
216         @Override
setDateFormatIs24Hour(Boolean value)217         public void setDateFormatIs24Hour(Boolean value) {
218             try {
219                 mDateFormatIs24HourField.set(null, value);
220             } catch (ReflectiveOperationException e) {
221                 throw new AssertionError("Unable to set java.text.DateFormat.is24Hour", e);
222             }
223         }
224 
225         @Override
createDefaultProperties()226         public Properties createDefaultProperties() {
227             return new Properties();
228         }
229     }
230 
231     private static class StubTestEnvironmentResetter implements TestEnvironmentResetter {
232         @Override
getDateFormatIs24Hour()233         public Boolean getDateFormatIs24Hour() {
234             return false;
235         }
236 
237         @Override
setDateFormatIs24Hour(Boolean value)238         public void setDateFormatIs24Hour(Boolean value) {
239         }
240 
241         @Override
createDefaultProperties()242         public Properties createDefaultProperties() {
243             return System.getProperties();
244         }
245     }
246 
247     // http://code.google.com/p/vogar/source/browse/trunk/src/vogar/target/TestEnvironment.java
248     static class TestEnvironment {
249         private final static TestEnvironmentResetter sTestEnvironmentResetter;
250         static {
251             if (System.getProperty("java.vendor").toLowerCase().contains("android")) {
252                 sTestEnvironmentResetter = new AndroidTestEnvironmentResetter();
253             } else {
254                 sTestEnvironmentResetter = new StubTestEnvironmentResetter();
255             }
256         }
257 
258         private final Locale mDefaultLocale;
259         private final TimeZone mDefaultTimeZone;
260         private final HostnameVerifier mHostnameVerifier;
261         private final SSLSocketFactory mSslSocketFactory;
262         private final Properties mProperties;
263         private final Boolean mDefaultIs24Hour;
264 
TestEnvironment(Context context)265         TestEnvironment(Context context) {
266             mDefaultLocale = Locale.getDefault();
267             mDefaultTimeZone = TimeZone.getDefault();
268             mHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
269             mSslSocketFactory = HttpsURLConnection.getDefaultSSLSocketFactory();
270 
271             mProperties = sTestEnvironmentResetter.createDefaultProperties();
272             mProperties.setProperty("user.home", "");
273             mProperties.setProperty("java.io.tmpdir", context.getCacheDir().getAbsolutePath());
274             // The CDD mandates that devices that support WiFi are the only ones that will have
275             // multicast.
276             PackageManager pm = context.getPackageManager();
277             mProperties.setProperty("android.cts.device.multicast",
278                     Boolean.toString(pm.hasSystemFeature(PackageManager.FEATURE_WIFI)));
279             mDefaultIs24Hour = sTestEnvironmentResetter.getDateFormatIs24Hour();
280 
281             // There are tests in libcore that should be disabled for low ram devices. They can't
282             // access ActivityManager to call isLowRamDevice, but can read system properties.
283             ActivityManager activityManager =
284                     (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
285             mProperties.setProperty("android.cts.device.lowram",
286                     Boolean.toString(activityManager.isLowRamDevice()));
287         }
288 
reset()289         void reset() {
290             System.setProperties(null);
291             System.setProperties(mProperties);
292             Locale.setDefault(mDefaultLocale);
293             TimeZone.setDefault(mDefaultTimeZone);
294             Authenticator.setDefault(null);
295             CookieHandler.setDefault(null);
296             ResponseCache.setDefault(null);
297             HttpsURLConnection.setDefaultHostnameVerifier(mHostnameVerifier);
298             HttpsURLConnection.setDefaultSSLSocketFactory(mSslSocketFactory);
299             sTestEnvironmentResetter.setDateFormatIs24Hour(mDefaultIs24Hour);
300         }
301     }
302 }
303