1 /*
2  * Copyright (C) 2019 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.wm;
18 
19 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
20 
21 import static com.android.window.flags.Flags.windowSessionRelayoutInfo;
22 
23 import android.app.Activity;
24 import android.content.Context;
25 import android.os.Bundle;
26 import android.os.RemoteException;
27 import android.perftests.utils.BenchmarkState;
28 import android.perftests.utils.PerfStatusReporter;
29 import android.perftests.utils.PerfTestActivity;
30 import android.platform.test.annotations.Presubmit;
31 import android.util.MergedConfiguration;
32 import android.view.IWindow;
33 import android.view.IWindowSession;
34 import android.view.InsetsSourceControl;
35 import android.view.InsetsState;
36 import android.view.SurfaceControl;
37 import android.view.View;
38 import android.view.WindowManager;
39 import android.view.WindowManagerGlobal;
40 import android.view.WindowRelayoutResult;
41 import android.widget.LinearLayout;
42 import android.window.ClientWindowFrames;
43 
44 import androidx.test.filters.LargeTest;
45 import androidx.test.rule.ActivityTestRule;
46 
47 import org.junit.Rule;
48 import org.junit.Test;
49 import org.junit.runner.RunWith;
50 import org.junit.runners.Parameterized;
51 
52 import java.util.Arrays;
53 import java.util.Collection;
54 import java.util.function.IntSupplier;
55 
56 @RunWith(Parameterized.class)
57 @LargeTest
58 @Presubmit
59 public class RelayoutPerfTest extends WindowManagerPerfTestBase
60         implements BenchmarkState.CustomizedIterationListener {
61     private int mIteration;
62 
63     @Rule
64     public final PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
65 
66     @Rule
67     public final ActivityTestRule<PerfTestActivity> mActivityRule =
68             new ActivityTestRule<>(PerfTestActivity.class);
69 
70     /** This is only a placement to match the input parameters from {@link #getParameters}. */
71     @Parameterized.Parameter(0)
72     public String testName;
73 
74     /** The visibilities to loop for relayout. */
75     @Parameterized.Parameter(1)
76     public int[] visibilities;
77 
78     /**
79      * Each row will be mapped into {@link #testName} and {@link #visibilities} of a new test
80      * instance according to the index of the parameter.
81      */
82     @Parameterized.Parameters(name = "{0}")
getParameters()83     public static Collection<Object[]> getParameters() {
84         return Arrays.asList(new Object[][] {
85                 { "Visible", new int[] { View.VISIBLE } },
86                 { "Invisible~Visible", new int[] { View.INVISIBLE, View.VISIBLE } },
87                 { "Gone~Visible", new int[] { View.GONE, View.VISIBLE } },
88                 { "Gone~Invisible", new int[] { View.GONE, View.INVISIBLE } }
89         });
90     }
91 
92     @Test
testRelayout()93     public void testRelayout() throws Throwable {
94         final Activity activity = mActivityRule.getActivity();
95         final ContentView contentView = new ContentView(activity);
96         mActivityRule.runOnUiThread(() -> activity.setContentView(contentView));
97         getInstrumentation().waitForIdleSync();
98 
99         final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
100         state.setCustomizedIterations(getProfilingIterations(), this);
101         final RelayoutRunner relayoutRunner = new RelayoutRunner(activity, contentView.getWindow(),
102                 () -> visibilities[mIteration++ % visibilities.length]);
103         relayoutRunner.runBenchmark(state);
104     }
105 
106     @Override
onStart(int iteration)107     public void onStart(int iteration) {
108         startProfiling(RelayoutPerfTest.class.getSimpleName() + "_" + testName
109                 + "_MethodTracing_" + iteration + ".trace");
110     }
111 
112     @Override
onFinished(int iteration)113     public void onFinished(int iteration) {
114         stopProfiling();
115     }
116 
117     /** A placeholder view to get IWindow. */
118     private static class ContentView extends LinearLayout {
ContentView(Context context)119         ContentView(Context context) {
120             super(context);
121         }
122 
123         @Override
getWindow()124         protected IWindow getWindow() {
125             return super.getWindow();
126         }
127     }
128 
129     private static class RelayoutRunner {
130         final ClientWindowFrames mOutFrames = new ClientWindowFrames();
131         final MergedConfiguration mOutMergedConfiguration = new MergedConfiguration();
132         final InsetsState mOutInsetsState = new InsetsState();
133         final InsetsSourceControl.Array mOutControls = new InsetsSourceControl.Array();
134         final Bundle mOutBundle = windowSessionRelayoutInfo() ? null : new Bundle();
135         final WindowRelayoutResult mOutRelayoutResult;
136         final IWindow mWindow;
137         final View mView;
138         final WindowManager.LayoutParams mParams;
139         final int mWidth;
140         final int mHeight;
141         final SurfaceControl mOutSurfaceControl;
142 
143         final IntSupplier mViewVisibility;
144         int mRelayoutSeq;
145         int mFlags;
146 
RelayoutRunner(Activity activity, IWindow window, IntSupplier visibilitySupplier)147         RelayoutRunner(Activity activity, IWindow window, IntSupplier visibilitySupplier) {
148             mWindow = window;
149             mView = activity.getWindow().getDecorView();
150             mParams = (WindowManager.LayoutParams) mView.getLayoutParams();
151             mWidth = mView.getMeasuredWidth();
152             mHeight = mView.getMeasuredHeight();
153             mOutSurfaceControl = mView.getViewRootImpl().getSurfaceControl();
154             mViewVisibility = visibilitySupplier;
155             mOutRelayoutResult = windowSessionRelayoutInfo()
156                     ? new WindowRelayoutResult(mOutFrames, mOutMergedConfiguration,
157                             mOutSurfaceControl, mOutInsetsState, mOutControls)
158                     : null;
159         }
160 
runBenchmark(BenchmarkState state)161         void runBenchmark(BenchmarkState state) throws RemoteException {
162             final IWindowSession session = WindowManagerGlobal.getWindowSession();
163             while (state.keepRunning()) {
164                 mRelayoutSeq++;
165                 if (windowSessionRelayoutInfo()) {
166                     session.relayout(mWindow, mParams, mWidth, mHeight,
167                             mViewVisibility.getAsInt(), mFlags, mRelayoutSeq, 0 /* lastSyncSeqId */,
168                             mOutRelayoutResult);
169                 } else {
170                     session.relayoutLegacy(mWindow, mParams, mWidth, mHeight,
171                             mViewVisibility.getAsInt(), mFlags, mRelayoutSeq, 0 /* lastSyncSeqId */,
172                             mOutFrames, mOutMergedConfiguration, mOutSurfaceControl,
173                             mOutInsetsState, mOutControls, mOutBundle);
174                 }
175             }
176         }
177     }
178 }
179