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 com.android.server.wm;
     18 
     19 import static org.junit.Assert.assertArrayEquals;
     20 import static org.junit.Assert.assertEquals;
     21 import static org.junit.Assert.assertFalse;
     22 import static org.junit.Assert.assertTrue;
     23 import static org.mockito.ArgumentMatchers.any;
     24 import static org.mockito.ArgumentMatchers.eq;
     25 import static org.mockito.Mockito.doAnswer;
     26 import static org.mockito.Mockito.mock;
     27 import static org.mockito.Mockito.verify;
     28 import static org.mockito.Mockito.verifyZeroInteractions;
     29 
     30 import android.content.Context;
     31 import android.platform.test.annotations.Presubmit;
     32 import android.support.test.InstrumentationRegistry;
     33 import android.support.test.filters.SmallTest;
     34 import android.support.test.filters.FlakyTest;
     35 import android.support.test.runner.AndroidJUnit4;
     36 import android.util.proto.ProtoOutputStream;
     37 
     38 import com.android.internal.util.Preconditions;
     39 import com.android.server.wm.WindowManagerTraceProto;
     40 
     41 import org.junit.After;
     42 import org.junit.Before;
     43 import org.junit.Ignore;
     44 import org.junit.Test;
     45 import org.junit.runner.RunWith;
     46 
     47 import java.io.File;
     48 import java.io.FileInputStream;
     49 import java.io.InputStream;
     50 import java.io.PrintWriter;
     51 import java.nio.charset.StandardCharsets;
     52 
     53 /**
     54  * Test class for {@link WindowTracing}.
     55  *
     56  * Build/Install/Run:
     57  *  bit FrameworksServicesTests:com.android.server.wm.WindowTracingTest
     58  */
     59 @SmallTest
     60 @FlakyTest(bugId = 74078662)
     61 @Presubmit
     62 @RunWith(AndroidJUnit4.class)
     63 public class WindowTracingTest extends WindowTestsBase {
     64 
     65     private static final byte[] MAGIC_HEADER = new byte[] {
     66         0x9, 0x57, 0x49, 0x4e, 0x54, 0x52, 0x41, 0x43, 0x45,
     67     };
     68 
     69     private Context mTestContext;
     70     private WindowTracing mWindowTracing;
     71     private WindowManagerService mWmMock;
     72     private File mFile;
     73 
     74     @Override
     75     @Before
     76     public void setUp() throws Exception {
     77         super.setUp();
     78 
     79         mWmMock = mock(WindowManagerService.class);
     80 
     81         mTestContext = InstrumentationRegistry.getContext();
     82 
     83         mFile = mTestContext.getFileStreamPath("tracing_test.dat");
     84         mFile.delete();
     85 
     86         mWindowTracing = new WindowTracing(mFile);
     87     }
     88 
     89     @Test
     90     public void isEnabled_returnsFalseByDefault() throws Exception {
     91         assertFalse(mWindowTracing.isEnabled());
     92     }
     93 
     94     @Test
     95     public void isEnabled_returnsTrueAfterStart() throws Exception {
     96         mWindowTracing.startTrace(mock(PrintWriter.class));
     97         assertTrue(mWindowTracing.isEnabled());
     98     }
     99 
    100     @Test
    101     public void isEnabled_returnsFalseAfterStop() throws Exception {
    102         mWindowTracing.startTrace(mock(PrintWriter.class));
    103         mWindowTracing.stopTrace(mock(PrintWriter.class));
    104         assertFalse(mWindowTracing.isEnabled());
    105     }
    106 
    107     @Test
    108     public void trace_discared_whenNotTracing() throws Exception {
    109         mWindowTracing.traceStateLocked("where", mWmMock);
    110         verifyZeroInteractions(mWmMock);
    111     }
    112 
    113     @Test
    114     public void trace_dumpsWindowManagerState_whenTracing() throws Exception {
    115         mWindowTracing.startTrace(mock(PrintWriter.class));
    116         mWindowTracing.traceStateLocked("where", mWmMock);
    117 
    118         verify(mWmMock).writeToProtoLocked(any(), eq(true));
    119     }
    120 
    121     @Test
    122     public void traceFile_startsWithMagicHeader() throws Exception {
    123         mWindowTracing.startTrace(mock(PrintWriter.class));
    124         mWindowTracing.stopTrace(mock(PrintWriter.class));
    125 
    126         byte[] header = new byte[MAGIC_HEADER.length];
    127         try (InputStream is = new FileInputStream(mFile)) {
    128             assertEquals(MAGIC_HEADER.length, is.read(header));
    129             assertArrayEquals(MAGIC_HEADER, header);
    130         }
    131     }
    132 
    133     @Test
    134     @Ignore("Figure out why this test is crashing when setting up mWmMock.")
    135     public void tracing_endsUpInFile() throws Exception {
    136         mWindowTracing.startTrace(mock(PrintWriter.class));
    137 
    138         doAnswer((inv) -> {
    139             inv.<ProtoOutputStream>getArgument(0).write(
    140                     WindowManagerTraceProto.WHERE, "TEST_WM_PROTO");
    141             return null;
    142         }).when(mWmMock).writeToProtoLocked(any(), any());
    143         mWindowTracing.traceStateLocked("TEST_WHERE", mWmMock);
    144 
    145         mWindowTracing.stopTrace(mock(PrintWriter.class));
    146 
    147         byte[] file = new byte[1000];
    148         int fileLength;
    149         try (InputStream is = new FileInputStream(mFile)) {
    150             fileLength = is.read(file);
    151             assertTrue(containsBytes(file, fileLength,
    152                     "TEST_WHERE".getBytes(StandardCharsets.UTF_8)));
    153             assertTrue(containsBytes(file, fileLength,
    154                     "TEST_WM_PROTO".getBytes(StandardCharsets.UTF_8)));
    155         }
    156     }
    157 
    158     @Override
    159     @After
    160     public void tearDown() throws Exception {
    161         super.tearDown();
    162 
    163         mFile.delete();
    164     }
    165 
    166     /** Return true if {@code needle} appears anywhere in {@code haystack[0..length]} */
    167     boolean containsBytes(byte[] haystack, int haystackLenght, byte[] needle) {
    168         Preconditions.checkArgument(haystackLenght > 0);
    169         Preconditions.checkArgument(needle.length > 0);
    170 
    171         outer: for (int i = 0; i <= haystackLenght - needle.length; i++) {
    172             for (int j = 0; j < needle.length; j++) {
    173                 if (haystack[i+j] != needle[j]) {
    174                     continue outer;
    175                 }
    176             }
    177             return true;
    178         }
    179         return false;
    180     }
    181 
    182     @Test
    183     public void test_containsBytes() {
    184         byte[] haystack = "hello_world".getBytes(StandardCharsets.UTF_8);
    185         assertTrue(containsBytes(haystack, haystack.length,
    186                 "hello".getBytes(StandardCharsets.UTF_8)));
    187         assertTrue(containsBytes(haystack, haystack.length,
    188                 "world".getBytes(StandardCharsets.UTF_8)));
    189         assertFalse(containsBytes(haystack, 6,
    190                 "world".getBytes(StandardCharsets.UTF_8)));
    191         assertFalse(containsBytes(haystack, haystack.length,
    192                 "world_".getBytes(StandardCharsets.UTF_8)));
    193         assertFalse(containsBytes(haystack, haystack.length,
    194                 "absent".getBytes(StandardCharsets.UTF_8)));
    195     }
    196 }
    197