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