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