Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 82615642 authored by Mårten Kongstad's avatar Mårten Kongstad Committed by Todd Kennedy
Browse files

OverlayDeviceTests: don't rely on Thread#sleep

When a request to enable an overlay is received by the overlay manager
service, there is some lead time before the affected process is updated.
Tests need to wait until this happens. Remove the calls to Thread#sleep;
instead, poll for a change to AssetManager#getApkPaths (which is faster
and more reliable).

Bug: 130257643
Test: atest OverlayDeviceTests
Change-Id: I9f7e6207a68431859bacac0462a2bab94b4efc2d
parent 50e31711
Loading
Loading
Loading
Loading
+77 −0
Original line number Diff line number Diff line
/*
 * 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.overlaytest;

import static java.util.concurrent.TimeUnit.SECONDS;

import android.app.UiAutomation;
import android.content.res.Resources;
import android.os.ParcelFileDescriptor;

import androidx.test.InstrumentationRegistry;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.concurrent.Executor;
import java.util.concurrent.FutureTask;

class LocalOverlayManager {
    private static final long TIMEOUT = 30;

    public static void setEnabledAndWait(Executor executor, final String packageName,
            boolean enable) throws Exception {
        final String pattern = (enable ? "[x]" : "[ ]") + " " + packageName;
        if (executeShellCommand("cmd overlay list").contains(pattern)) {
            // nothing to do, overlay already in the requested state
            return;
        }

        final Resources res = InstrumentationRegistry.getContext().getResources();
        final String[] oldApkPaths = res.getAssets().getApkPaths();
        FutureTask<Boolean> task = new FutureTask<>(() -> {
            while (true) {
                if (!Arrays.equals(oldApkPaths, res.getAssets().getApkPaths())) {
                    return true;
                }
                Thread.sleep(10);
            }
        });
        executor.execute(task);
        executeShellCommand("cmd overlay " + (enable ? "enable " : "disable ") + packageName);
        task.get(TIMEOUT, SECONDS);
    }

    private static String executeShellCommand(final String command)
            throws Exception {
        final UiAutomation uiAutomation =
                InstrumentationRegistry.getInstrumentation().getUiAutomation();
        final ParcelFileDescriptor pfd = uiAutomation.executeShellCommand(command);
        try (InputStream in = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
            final BufferedReader reader = new BufferedReader(
                    new InputStreamReader(in, StandardCharsets.UTF_8));
            StringBuilder str = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                str.append(line);
            }
            return str.toString();
        }
    }
}
+0 −58
Original line number Diff line number Diff line
@@ -21,13 +21,11 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import android.app.UiAutomation;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.os.LocaleList;
import android.os.ParcelFileDescriptor;
import android.util.AttributeSet;
import android.util.Xml;

@@ -569,60 +567,4 @@ public abstract class OverlayBaseTest {
        setLocale(new Locale("sv", "SE"));
        assertResource(resId, 200, 400, 600);
    }

    /**
     * Executes the shell command and reads all the output to ensure the command ran and didn't
     * get stuck buffering on output.
     */
    protected static String executeShellCommand(UiAutomation automation, String command)
            throws Exception {
        final ParcelFileDescriptor pfd = automation.executeShellCommand(command);
        try (InputStream in = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
            final BufferedReader reader = new BufferedReader(
                    new InputStreamReader(in, StandardCharsets.UTF_8));
            StringBuilder str = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                str.append(line);
            }
            return str.toString();
        }
    }

    /**
     * Enables overlay packages and waits for a configuration change event before
     * returning, to guarantee that Resources are up-to-date.
     * @param packages the list of package names to enable.
     */
    protected static void enableOverlayPackages(String... packages) throws Exception {
        enableOverlayPackages(true, packages);
    }

    /**
     * Disables overlay packages and waits for a configuration change event before
     * returning, to guarantee that Resources are up-to-date.
     * @param packages the list of package names to disable.
     */
    protected static void disableOverlayPackages(String... packages) throws Exception {
        enableOverlayPackages(false, packages);
    }

    /**
     * Enables/disables overlay packages and waits for a configuration change event before
     * returning, to guarantee that Resources are up-to-date.
     * @param enable enables the overlays when true, disables when false.
     * @param packages the list of package names to enable/disable.
     */
    private static void enableOverlayPackages(boolean enable, String[] packages)
            throws Exception {
        final UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation()
                .getUiAutomation();
        for (final String pkg : packages) {
            executeShellCommand(uiAutomation,
                    "cmd overlay " + (enable ? "enable " : "disable ") + pkg);
        }

        // Wait for the overlay change to propagate.
        Thread.sleep(1000);
    }
}
+6 −1
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import java.util.concurrent.Executor;

@RunWith(JUnit4.class)
@MediumTest
public class WithMultipleOverlaysTest extends OverlayBaseTest {
@@ -31,6 +33,9 @@ public class WithMultipleOverlaysTest extends OverlayBaseTest {

    @BeforeClass
    public static void enableOverlay() throws Exception {
        enableOverlayPackages(APP_OVERLAY_ONE_PKG, APP_OVERLAY_TWO_PKG, FRAMEWORK_OVERLAY_PKG);
        Executor executor = (cmd) -> new Thread(cmd).start();
        LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_ONE_PKG, true);
        LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_TWO_PKG, true);
        LocalOverlayManager.setEnabledAndWait(executor, FRAMEWORK_OVERLAY_PKG, true);
    }
}
+6 −2
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import java.util.concurrent.Executor;

@RunWith(JUnit4.class)
@MediumTest
public class WithOverlayTest extends OverlayBaseTest {
@@ -31,7 +33,9 @@ public class WithOverlayTest extends OverlayBaseTest {

    @BeforeClass
    public static void enableOverlay() throws Exception {
        disableOverlayPackages(APP_OVERLAY_TWO_PKG);
        enableOverlayPackages(APP_OVERLAY_ONE_PKG, FRAMEWORK_OVERLAY_PKG);
        Executor executor = (cmd) -> new Thread(cmd).start();
        LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_ONE_PKG, true);
        LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_TWO_PKG, false);
        LocalOverlayManager.setEnabledAndWait(executor, FRAMEWORK_OVERLAY_PKG, true);
    }
}
+6 −1
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import java.util.concurrent.Executor;

@RunWith(JUnit4.class)
@MediumTest
public class WithoutOverlayTest extends OverlayBaseTest {
@@ -31,6 +33,9 @@ public class WithoutOverlayTest extends OverlayBaseTest {

    @BeforeClass
    public static void disableOverlays() throws Exception {
        disableOverlayPackages(APP_OVERLAY_ONE_PKG, APP_OVERLAY_TWO_PKG, FRAMEWORK_OVERLAY_PKG);
        Executor executor = (cmd) -> new Thread(cmd).start();
        LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_ONE_PKG, false);
        LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_TWO_PKG, false);
        LocalOverlayManager.setEnabledAndWait(executor, FRAMEWORK_OVERLAY_PKG, false);
    }
}