1 /* 2 * Copyright (C) 2017 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 android.app.cts; 18 19 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE; 20 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE_PRE_26; 21 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE; 22 import static android.content.Context.BIND_ALLOW_OOM_MANAGEMENT; 23 import static android.content.Context.BIND_AUTO_CREATE; 24 import static android.content.Context.BIND_NOT_FOREGROUND; 25 26 import static com.android.app2.AlertWindowService.MSG_ADD_ALERT_WINDOW; 27 import static com.android.app2.AlertWindowService.MSG_ON_ALERT_WINDOW_ADDED; 28 import static com.android.app2.AlertWindowService.MSG_ON_ALERT_WINDOW_REMOVED; 29 import static com.android.app2.AlertWindowService.MSG_REMOVE_ALERT_WINDOW; 30 import static com.android.app2.AlertWindowService.MSG_REMOVE_ALL_ALERT_WINDOWS; 31 import static com.android.app2.AlertWindowService.NOTIFICATION_MESSENGER_EXTRA; 32 33 import static org.junit.Assert.assertEquals; 34 import static org.junit.Assert.fail; 35 36 import android.app.ActivityManager; 37 import android.app.ActivityManager.RunningAppProcessInfo; 38 import android.content.ComponentName; 39 import android.content.Context; 40 import android.content.Intent; 41 import android.content.ServiceConnection; 42 import android.content.pm.PackageManager; 43 import android.content.pm.PackageManager.NameNotFoundException; 44 import android.os.Handler; 45 import android.os.IBinder; 46 import android.os.Looper; 47 import android.os.Message; 48 import android.os.Messenger; 49 import android.os.SystemClock; 50 import android.platform.test.annotations.Presubmit; 51 import android.support.test.InstrumentationRegistry; 52 import android.support.test.runner.AndroidJUnit4; 53 import android.util.Log; 54 55 import com.android.app2.AlertWindowService; 56 import com.android.compatibility.common.util.SystemUtil; 57 58 import org.junit.After; 59 import org.junit.Before; 60 import org.junit.Test; 61 import org.junit.runner.RunWith; 62 63 import java.util.concurrent.TimeUnit; 64 import java.util.function.Function; 65 66 /** 67 * Build: mmma -j32 cts/tests/app 68 * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test CtsAppTestCases android.app.cts.AlertWindowsTests 69 */ 70 @Presubmit 71 @RunWith(AndroidJUnit4.class) 72 public class AlertWindowsTests { 73 74 private static final String TAG = "AlertWindowsTests"; 75 76 private static final boolean DEBUG = false; 77 private static final long WAIT_TIME_MS = 2 * 1000; 78 79 private static final String SDK25_PACKAGE_NAME = "com.android.appSdk25"; 80 81 private Messenger mService; 82 private String mServicePackageName; 83 private int mServiceUid; 84 85 private PackageManager mPm; 86 87 private ActivityManager mAm; 88 private ActivityManager mAm25; // ActivityManager created for an SDK 25 app context. 89 90 private final Messenger mMessenger = new Messenger(new IncomingHandler(Looper.getMainLooper())); 91 private final Object mAddedLock = new Object(); 92 private final Object mRemoveLock = new Object(); 93 94 @Before setUp()95 public void setUp() throws Exception { 96 if (DEBUG) Log.e(TAG, "setUp"); 97 final Context context = InstrumentationRegistry.getTargetContext(); 98 99 mPm = context.getPackageManager(); 100 101 mAm = context.getSystemService(ActivityManager.class); 102 mAm25 = context.createPackageContext(SDK25_PACKAGE_NAME, 0) 103 .getSystemService(ActivityManager.class); 104 105 final Intent intent = new Intent(); 106 intent.setClassName(AlertWindowService.class.getPackage().getName(), 107 AlertWindowService.class.getName()); 108 intent.putExtra(NOTIFICATION_MESSENGER_EXTRA, mMessenger); 109 // Needs to be both BIND_NOT_FOREGROUND and BIND_ALLOW_OOM_MANAGEMENT to avoid the binding 110 // to this instrumentation test from increasing its importance. 111 context.bindService(intent, mConnection, 112 BIND_AUTO_CREATE | BIND_NOT_FOREGROUND | BIND_ALLOW_OOM_MANAGEMENT); 113 synchronized (mConnection) { 114 // Wait for alert window service to be connection before processing. 115 mConnection.wait(WAIT_TIME_MS); 116 } 117 } 118 119 @After tearDown()120 public void tearDown() throws Exception { 121 if (DEBUG) Log.e(TAG, "tearDown"); 122 if (mService != null) { 123 mService.send(Message.obtain(null, MSG_REMOVE_ALL_ALERT_WINDOWS)); 124 } 125 final Context context = InstrumentationRegistry.getTargetContext(); 126 context.unbindService(mConnection); 127 mAm = null; 128 } 129 130 @Test testAlertWindowOomAdj()131 public void testAlertWindowOomAdj() throws Exception { 132 setAlertWindowPermission(true /* allow */); 133 134 135 assertPackageImportance(IMPORTANCE_PERCEPTIBLE, IMPORTANCE_PERCEPTIBLE_PRE_26); 136 137 // TODO AM.getUidImportance() sometimes return a different value from what 138 // getPackageImportance() returns... b/37950472 139 // assertUidImportance(IMPORTANCE_PERCEPTIBLE, IMPORTANCE_PERCEPTIBLE_PRE_26); 140 141 addAlertWindow(); 142 // Process importance should be increased to visible when the service has an alert window. 143 assertPackageImportance(IMPORTANCE_VISIBLE, IMPORTANCE_VISIBLE); 144 145 addAlertWindow(); 146 assertPackageImportance(IMPORTANCE_VISIBLE, IMPORTANCE_VISIBLE); 147 148 setAlertWindowPermission(false /* allow */); 149 // Process importance should no longer be visible since its alert windows are not allowed to 150 // be visible. 151 assertPackageImportance(IMPORTANCE_PERCEPTIBLE, IMPORTANCE_PERCEPTIBLE_PRE_26); 152 153 setAlertWindowPermission(true /* allow */); 154 // They can show again so importance should be visible again. 155 assertPackageImportance(IMPORTANCE_VISIBLE, IMPORTANCE_VISIBLE); 156 157 removeAlertWindow(); 158 assertPackageImportance(IMPORTANCE_VISIBLE, IMPORTANCE_VISIBLE); 159 160 removeAlertWindow(); 161 // Process importance should no longer be visible when the service no longer as alert 162 // windows. 163 assertPackageImportance(IMPORTANCE_PERCEPTIBLE, IMPORTANCE_PERCEPTIBLE_PRE_26); 164 } 165 addAlertWindow()166 private void addAlertWindow() throws Exception { 167 mService.send(Message.obtain(null, MSG_ADD_ALERT_WINDOW)); 168 synchronized (mAddedLock) { 169 // Wait for window addition confirmation before proceeding. 170 mAddedLock.wait(WAIT_TIME_MS); 171 } 172 } 173 removeAlertWindow()174 private void removeAlertWindow() throws Exception { 175 mService.send(Message.obtain(null, MSG_REMOVE_ALERT_WINDOW)); 176 synchronized (mRemoveLock) { 177 // Wait for window removal confirmation before proceeding. 178 mRemoveLock.wait(WAIT_TIME_MS); 179 } 180 } 181 setAlertWindowPermission(boolean allow)182 private void setAlertWindowPermission(boolean allow) throws Exception { 183 final String cmd = "appops set " + mServicePackageName 184 + " android:system_alert_window " + (allow ? "allow" : "deny"); 185 SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(), cmd); 186 } 187 assertImportance(Function<ActivityManager, Integer> apiCaller, int expectedForO, int expectedForPreO)188 private void assertImportance(Function<ActivityManager, Integer> apiCaller, 189 int expectedForO, int expectedForPreO) throws Exception { 190 final long TIMEOUT = SystemClock.uptimeMillis() + TimeUnit.SECONDS.toMillis(30); 191 int actual; 192 193 do { 194 // TODO: We should try to use ActivityManagerTest.UidImportanceListener here to listen 195 // for changes in the uid importance. However, the way it is currently structured 196 // doesn't really work for this use case right now... 197 Thread.sleep(500); 198 actual = apiCaller.apply(mAm); 199 } while (actual != expectedForO && (SystemClock.uptimeMillis() < TIMEOUT)); 200 201 assertEquals(expectedForO, actual); 202 203 // Check the result for pre-O apps. 204 assertEquals(expectedForPreO, (int) apiCaller.apply(mAm25)); 205 } 206 207 /** 208 * Make sure {@link ActivityManager#getPackageImportance} returns the expected value. 209 */ assertPackageImportance(int expectedForO, int expectedForPreO)210 private void assertPackageImportance(int expectedForO, int expectedForPreO) throws Exception { 211 assertImportance(am -> am.getPackageImportance(mServicePackageName), 212 expectedForO, expectedForPreO); 213 } 214 215 /** 216 * Make sure {@link ActivityManager#getUidImportance(int)} returns the expected value. 217 */ assertUidImportance(int expectedForO, int expectedForPreO)218 private void assertUidImportance(int expectedForO, int expectedForPreO) throws Exception { 219 assertImportance(am -> am.getUidImportance(mServiceUid), 220 expectedForO, expectedForPreO); 221 } 222 223 private final ServiceConnection mConnection = new ServiceConnection() { 224 @Override 225 public void onServiceConnected(ComponentName name, IBinder service) { 226 if (DEBUG) Log.e(TAG, "onServiceConnected"); 227 mService = new Messenger(service); 228 mServicePackageName = name.getPackageName(); 229 try { 230 mServiceUid = mPm.getPackageUid(mServicePackageName, 0); 231 } catch (NameNotFoundException e) { 232 throw new RuntimeException("getPackageUid() failed.", e); 233 } 234 synchronized (mConnection) { 235 notifyAll(); 236 } 237 } 238 239 @Override 240 public void onServiceDisconnected(ComponentName name) { 241 if (DEBUG) Log.e(TAG, "onServiceDisconnected"); 242 mService = null; 243 mServicePackageName = null; 244 mServiceUid = 0; 245 } 246 }; 247 248 private class IncomingHandler extends Handler { 249 IncomingHandler(Looper looper)250 IncomingHandler(Looper looper) { 251 super(looper); 252 } 253 254 @Override handleMessage(Message msg)255 public void handleMessage(Message msg) { 256 switch (msg.what) { 257 case MSG_ON_ALERT_WINDOW_ADDED: 258 synchronized (mAddedLock) { 259 if (DEBUG) Log.e(TAG, "MSG_ON_ALERT_WINDOW_ADDED"); 260 mAddedLock.notifyAll(); 261 } 262 break; 263 case MSG_ON_ALERT_WINDOW_REMOVED: 264 synchronized (mRemoveLock) { 265 if (DEBUG) Log.e(TAG, "MSG_ON_ALERT_WINDOW_REMOVED"); 266 mRemoveLock.notifyAll(); 267 } 268 break; 269 default: 270 super.handleMessage(msg); 271 } 272 } 273 } 274 } 275