summaryrefslogtreecommitdiff
path: root/apct-tests/perftests/utils
diff options
context:
space:
mode:
authorFelipe Leme <felipeal@google.com>2018-04-30 09:39:55 -0700
committerFelipe Leme <felipeal@google.com>2018-05-01 12:40:33 -0700
commit6378b48f239963cfad496f9c7ffec3b99d1a1fd4 (patch)
tree67f584199cdea591f09a140a04653323ad2ddad9 /apct-tests/perftests/utils
parent633c4d9875c019539d6e6f0821977b8d586e64e8 (diff)
Initial PERF tests for autofill.
These tests render an activity that has 2 autofillable views (username and password) and keep focusing between then, observing what happens in 4 scenarios: 1. No autofill service (baseline) 2. Autofill service returning no datasets. 3. Autofill service returning a dataset with username and password. 4. Autofill service returning a dataset with just username. Because this change introduced a helper class to run shell commands without needing the UiAutomator package, it also changed the MultiUserPerfTests to use such helper. Test: mmma -j ./frameworks/base/apct-tests/perftests/core/ && \ adb install -r $OUT/data/app/CorePerfTests/CorePerfTests.apk && \ adb shell am instrument -w -e class android.view.autofill.AutofillPerfTest \ com.android.perftests.core/android.support.test.runner.AndroidJUnitRunner Test: mmma -j ./frameworks/base/apct-tests/perftests/multiuser && \ adb install -r $OUT/data/app/MultiUserPerfTests/MultiUserPerfTests.apk && \ adb shell am instrument -w -e class android.multiuser.UserLifecycleTests \ com.android.perftests.multiuser/android.support.test.runner.AndroidJUnitRunner Bug: 38345816 Change-Id: Ie283dff8dd19c38ea829de9164b23aae2bfeb015
Diffstat (limited to 'apct-tests/perftests/utils')
-rw-r--r--apct-tests/perftests/utils/Android.mk4
-rw-r--r--apct-tests/perftests/utils/src/android/perftests/utils/OneTimeSettingsListener.java82
-rw-r--r--apct-tests/perftests/utils/src/android/perftests/utils/SettingsHelper.java118
-rw-r--r--apct-tests/perftests/utils/src/android/perftests/utils/ShellHelper.java64
4 files changed, 267 insertions, 1 deletions
diff --git a/apct-tests/perftests/utils/Android.mk b/apct-tests/perftests/utils/Android.mk
index 55c13b087626..604f0adbe23e 100644
--- a/apct-tests/perftests/utils/Android.mk
+++ b/apct-tests/perftests/utils/Android.mk
@@ -1,7 +1,9 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android-support-test \
+ androidx.annotation_annotation
# Build all java files in the java subdirectory
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/OneTimeSettingsListener.java b/apct-tests/perftests/utils/src/android/perftests/utils/OneTimeSettingsListener.java
new file mode 100644
index 000000000000..37af4c7f6181
--- /dev/null
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/OneTimeSettingsListener.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2018 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 android.perftests.utils;
+
+import static android.perftests.utils.SettingsHelper.NAMESPACE_SECURE;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings;
+
+import androidx.annotation.NonNull;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Helper used to block tests until a secure settings value has been updated.
+ */
+public final class OneTimeSettingsListener extends ContentObserver {
+ private final CountDownLatch mLatch = new CountDownLatch(1);
+ private final ContentResolver mResolver;
+ private final String mKey;
+ private final int mTimeoutMs;
+
+ public OneTimeSettingsListener(@NonNull Context context, @NonNull String namespace,
+ @NonNull String key, int timeoutMs) {
+ super(new Handler(Looper.getMainLooper()));
+ mKey = key;
+ mResolver = context.getContentResolver();
+ mTimeoutMs = timeoutMs;
+ final Uri uri;
+ switch (namespace) {
+ case NAMESPACE_SECURE:
+ uri = Settings.Secure.getUriFor(key);
+ break;
+ default:
+ throw new IllegalArgumentException("invalid namespace: " + namespace);
+ }
+ mResolver.registerContentObserver(uri, false, this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ mResolver.unregisterContentObserver(this);
+ mLatch.countDown();
+ }
+
+ /**
+ * Blocks for a few seconds until it's called, or throws an {@link IllegalStateException} if
+ * it isn't.
+ */
+ public void assertCalled() {
+ try {
+ final boolean updated = mLatch.await(mTimeoutMs, TimeUnit.MILLISECONDS);
+ if (!updated) {
+ throw new IllegalStateException(
+ "Settings " + mKey + " not called in " + mTimeoutMs + "ms");
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new IllegalStateException("Interrupted", e);
+ }
+ }
+}
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/SettingsHelper.java b/apct-tests/perftests/utils/src/android/perftests/utils/SettingsHelper.java
new file mode 100644
index 000000000000..d7d1d6b7f817
--- /dev/null
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/SettingsHelper.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2018 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 android.perftests.utils;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.text.TextUtils;
+
+import java.util.Objects;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/**
+ * Provides utilities to interact with the device's {@link Settings}.
+ */
+public final class SettingsHelper {
+
+ public static final String NAMESPACE_SECURE = "secure";
+
+ private static int DEFAULT_TIMEOUT_MS = 5000;
+
+ /**
+ * Uses a Shell command to "asynchronously" set the given preference, returning right away.
+ */
+ public static void set(@NonNull String namespace, @NonNull String key, @Nullable String value) {
+ if (value == null) {
+ delete(namespace, key);
+ return;
+ }
+ ShellHelper.runShellCommand("settings put %s %s %s default", namespace, key, value);
+ }
+
+ /**
+ * Uses a Shell command to "synchronously" set the given preference by registering a listener
+ * and wait until it's set.
+ */
+ public static void syncSet(@NonNull Context context, @NonNull String namespace,
+ @NonNull String key, @Nullable String value) {
+ if (value == null) {
+ syncDelete(context, namespace, key);
+ return;
+ }
+
+ String currentValue = get(namespace, key);
+ if (value.equals(currentValue)) {
+ // Already set, ignore
+ return;
+ }
+
+ OneTimeSettingsListener observer = new OneTimeSettingsListener(context, namespace, key,
+ DEFAULT_TIMEOUT_MS);
+ set(namespace, key, value);
+ observer.assertCalled();
+ assertNewValue(namespace, key, value);
+ }
+
+ /**
+ * Uses a Shell command to "asynchronously" delete the given preference, returning right away.
+ */
+ public static void delete(@NonNull String namespace, @NonNull String key) {
+ ShellHelper.runShellCommand("settings delete %s %s", namespace, key);
+ }
+
+ /**
+ * Uses a Shell command to "synchronously" delete the given preference by registering a listener
+ * and wait until it's called.
+ */
+ public static void syncDelete(@NonNull Context context, @NonNull String namespace,
+ @NonNull String key) {
+ String currentValue = get(namespace, key);
+ if (currentValue == null || currentValue.equals("null")) {
+ // Already set, ignore
+ return;
+ }
+
+ OneTimeSettingsListener observer = new OneTimeSettingsListener(context, namespace, key,
+ DEFAULT_TIMEOUT_MS);
+ delete(namespace, key);
+ observer.assertCalled();
+ assertNewValue(namespace, key, "null");
+ }
+
+ /**
+ * Gets the value of a given preference using Shell command.
+ */
+ @NonNull
+ public static String get(@NonNull String namespace, @NonNull String key) {
+ return ShellHelper.runShellCommand("settings get %s %s", namespace, key);
+ }
+
+ private static void assertNewValue(@NonNull String namespace, @NonNull String key,
+ @Nullable String expectedValue) {
+ String actualValue = get(namespace, key);
+ if (!Objects.equals(actualValue, expectedValue)) {
+ throw new AssertionError("invalid value for " + namespace + ":" + key + ": expected '"
+ + actualValue + "' , got '" + expectedValue + "'");
+ }
+ }
+
+ private SettingsHelper() {
+ throw new UnsupportedOperationException("contain static methods only");
+ }
+}
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/ShellHelper.java b/apct-tests/perftests/utils/src/android/perftests/utils/ShellHelper.java
new file mode 100644
index 000000000000..cae87fb9c6e4
--- /dev/null
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/ShellHelper.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 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 android.perftests.utils;
+
+import android.app.UiAutomation;
+import android.os.ParcelFileDescriptor;
+import android.support.test.InstrumentationRegistry;
+import android.text.TextUtils;
+import android.util.AndroidRuntimeException;
+import android.util.Log;
+
+import java.io.FileInputStream;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Provides Shell-based utilities such as running a command.
+ */
+public final class ShellHelper {
+
+ /**
+ * Runs a Shell command, returning a trimmed response.
+ */
+ @NonNull
+ public static String runShellCommand(@NonNull String template, Object...args) {
+ String command = String.format(template, args);
+ UiAutomation automan = InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation();
+ ParcelFileDescriptor pfd = automan.executeShellCommand(command);
+ byte[] buf = new byte[512];
+ int bytesRead;
+ try(FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
+ StringBuilder stdout = new StringBuilder();
+ while ((bytesRead = fis.read(buf)) != -1) {
+ stdout.append(new String(buf, 0, bytesRead));
+ }
+ String result = stdout.toString();
+ return TextUtils.isEmpty(result) ? "" : result.trim();
+ } catch (Exception e) {
+ throw new AndroidRuntimeException("Command '" + command + "' failed: ", e);
+ } finally {
+ // Must disconnect UI automation after every call, otherwise its accessibility service
+ // skews the performance tests.
+ automan.destroy();
+ }
+ }
+
+ private ShellHelper() {
+ throw new UnsupportedOperationException("contain static methods only");
+ }
+}