Eliminate non interested parts of content capture perf test

The ActivityTestRule#launchActivity uses startActivitySync, that
will wait until the enter animation is finished. So the metrics
are usually dominated by the animation duration. And because the
test rapidly loops launch and finish, the animation style may be
different. Then the result may not be meaningful.

Because the original purpose of the test is to ensure the frame time,
the timestamp at CALLBACK_COMMIT is more accurate. Also skip the
the animation so the test can run faster about 80%.

Bug: 258883870
Test: atest android.view.contentcapture.LoginTest
Change-Id: I529672e7a60bca8420e96d6c900d95848f94108e
This commit is contained in:
Riddle Hsu
2022-12-12 14:22:51 +00:00
parent b29e4dc3a3
commit 69a9eb0aa1
4 changed files with 94 additions and 25 deletions

View File

@@ -18,6 +18,8 @@
<application>
<uses-library android:name="android.test.runner" />
<activity android:name="android.perftests.utils.PerfTestActivity"
android:exported="true" />
<activity android:name="android.view.contentcapture.CustomTestActivity"
android:exported="true">
</activity>

View File

@@ -22,18 +22,20 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat
import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
import android.app.Activity;
import android.app.Application;
import android.app.Instrumentation;
import android.content.ContentCaptureOptions;
import android.content.Context;
import android.content.Intent;
import android.os.BatteryManager;
import android.os.UserHandle;
import android.perftests.utils.PerfStatusReporter;
import android.perftests.utils.PerfTestActivity;
import android.provider.Settings;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.test.rule.ActivityTestRule;
import com.android.compatibility.common.util.ActivitiesWatcher;
import com.android.compatibility.common.util.ActivitiesWatcher.ActivityWatcher;
@@ -53,18 +55,18 @@ import org.junit.runners.model.Statement;
public abstract class AbstractContentCapturePerfTestCase {
private static final String TAG = AbstractContentCapturePerfTestCase.class.getSimpleName();
private static final long GENERIC_TIMEOUT_MS = 10_000;
protected static final long GENERIC_TIMEOUT_MS = 5_000;
private static int sOriginalStayOnWhilePluggedIn;
private static Context sContext = getInstrumentation().getTargetContext();
protected static final Instrumentation sInstrumentation = getInstrumentation();
protected static final Context sContext = sInstrumentation.getTargetContext();
protected ActivitiesWatcher mActivitiesWatcher;
private MyContentCaptureService.ServiceWatcher mServiceWatcher;
/** A simple activity as the task root to reduce the noise of pause and animation time. */
protected Activity mEntryActivity;
@Rule
public ActivityTestRule<CustomTestActivity> mActivityRule =
new ActivityTestRule<>(CustomTestActivity.class, false, false);
private MyContentCaptureService.ServiceWatcher mServiceWatcher;
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@@ -220,6 +222,17 @@ public abstract class AbstractContentCapturePerfTestCase {
}
}
@Before
public void setUp() {
mEntryActivity = sInstrumentation.startActivitySync(
PerfTestActivity.createLaunchIntent(sInstrumentation.getContext()));
}
@After
public void tearDown() {
mEntryActivity.finishAndRemoveTask();
}
/**
* Sets {@link MyContentCaptureService} as the service for the current user and waits until
* its created, then add the perf test package into allow list.
@@ -247,21 +260,25 @@ public abstract class AbstractContentCapturePerfTestCase {
return launchActivity(R.layout.test_login_activity, 0);
}
/**
* Returns the intent which will launch CustomTestActivity.
*/
protected Intent getLaunchIntent(int layoutId, int numViews) {
final Intent intent = new Intent(sContext, CustomTestActivity.class)
// Use NEW_TASK because the context is not activity. It is still in the same task
// of PerfTestActivity because of the same task affinity. Use NO_ANIMATION because
// this test focuses on launch time instead of animation duration.
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION);
intent.putExtra(INTENT_EXTRA_LAYOUT_ID, layoutId);
intent.putExtra(INTENT_EXTRA_CUSTOM_VIEWS, numViews);
return intent;
}
/**
* Launch test activity with give layout and parameter
*/
protected CustomTestActivity launchActivity(int layoutId, int numViews) {
final Intent intent = new Intent(sContext, CustomTestActivity.class);
intent.putExtra(INTENT_EXTRA_LAYOUT_ID, layoutId);
intent.putExtra(INTENT_EXTRA_CUSTOM_VIEWS, numViews);
return mActivityRule.launchActivity(intent);
}
protected void finishActivity() {
try {
mActivityRule.finishActivity();
} catch (IllegalStateException e) {
// no op
}
final Intent intent = getLaunchIntent(layoutId, numViews);
return (CustomTestActivity) sInstrumentation.startActivitySync(intent);
}
}

View File

@@ -19,6 +19,10 @@ package android.view.contentcapture;
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Looper;
import android.os.RemoteCallback;
import android.view.Choreographer;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -31,6 +35,8 @@ import com.android.perftests.contentcapture.R;
public class CustomTestActivity extends Activity {
public static final String INTENT_EXTRA_LAYOUT_ID = "layout_id";
public static final String INTENT_EXTRA_CUSTOM_VIEWS = "custom_view_number";
static final String INTENT_EXTRA_FINISH_ON_IDLE = "finish";
static final String INTENT_EXTRA_DRAW_CALLBACK = "draw_callback";
public static final int MAX_VIEWS = 500;
private static final int CUSTOM_CONTAINER_LAYOUT_ID = R.layout.test_container_activity;
@@ -47,6 +53,34 @@ public class CustomTestActivity extends Activity {
getIntent().getIntExtra(INTENT_EXTRA_CUSTOM_VIEWS, MAX_VIEWS));
}
}
final RemoteCallback drawCallback = getIntent().getParcelableExtra(
INTENT_EXTRA_DRAW_CALLBACK, RemoteCallback.class);
if (drawCallback != null) {
getWindow().getDecorView().addOnAttachStateChangeListener(
new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
Choreographer.getInstance().postCallback(
Choreographer.CALLBACK_COMMIT,
// Report that the first frame is drawn.
() -> drawCallback.sendResult(null), null /* token */);
}
@Override
public void onViewDetachedFromWindow(View v) {
}
});
}
if (getIntent().getBooleanExtra(INTENT_EXTRA_FINISH_ON_IDLE, false)) {
Looper.myQueue().addIdleHandler(() -> {
// Finish without animation.
finish();
overridePendingTransition(0 /* enterAnim */, 0 /* exitAnim */);
return false;
});
}
}
private void createCustomViews(LinearLayout root, int number) {

View File

@@ -15,9 +15,10 @@
*/
package android.view.contentcapture;
import static com.android.compatibility.common.util.ActivitiesWatcher.ActivityLifecycle.CREATED;
import static com.android.compatibility.common.util.ActivitiesWatcher.ActivityLifecycle.DESTROYED;
import android.content.Intent;
import android.os.RemoteCallback;
import android.perftests.utils.BenchmarkState;
import android.view.View;
@@ -80,17 +81,32 @@ public class LoginTest extends AbstractContentCapturePerfTestCase {
}
private void testActivityLaunchTime(int layoutId, int numViews) throws Throwable {
final Object drawNotifier = new Object();
final Intent intent = getLaunchIntent(layoutId, numViews);
intent.putExtra(CustomTestActivity.INTENT_EXTRA_FINISH_ON_IDLE, true);
intent.putExtra(CustomTestActivity.INTENT_EXTRA_DRAW_CALLBACK,
new RemoteCallback(result -> {
synchronized (drawNotifier) {
drawNotifier.notifyAll();
}
}));
final ActivityWatcher watcher = startWatcher();
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
launchActivity(layoutId, numViews);
mEntryActivity.startActivity(intent);
synchronized (drawNotifier) {
try {
drawNotifier.wait(GENERIC_TIMEOUT_MS);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
// Ignore the time to finish the activity
state.pauseTiming();
watcher.waitFor(CREATED);
finishActivity();
watcher.waitFor(DESTROYED);
sInstrumentation.waitForIdleSync();
state.resumeTiming();
}
}
@@ -142,12 +158,12 @@ public class LoginTest extends AbstractContentCapturePerfTestCase {
while (state.keepRunning()) {
// Only count the time of onVisibilityAggregated()
state.pauseTiming();
mActivityRule.runOnUiThread(() -> {
sInstrumentation.runOnMainSync(() -> {
state.resumeTiming();
view.onVisibilityAggregated(false);
state.pauseTiming();
});
mActivityRule.runOnUiThread(() -> {
sInstrumentation.runOnMainSync(() -> {
state.resumeTiming();
view.onVisibilityAggregated(true);
state.pauseTiming();