1 /* 2 * Copyright (C) 2024 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.internal.protolog; 18 19 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; 20 21 import static org.junit.Assert.assertFalse; 22 import static org.junit.Assert.assertThrows; 23 import static org.junit.Assert.assertTrue; 24 import static org.mockito.ArgumentMatchers.any; 25 import static org.mockito.ArgumentMatchers.anyLong; 26 import static org.mockito.ArgumentMatchers.eq; 27 import static org.mockito.Mockito.never; 28 import static org.mockito.Mockito.verify; 29 import static org.mockito.Mockito.when; 30 31 import static java.io.File.createTempFile; 32 import static java.nio.file.Files.createTempDirectory; 33 34 import android.content.Context; 35 import android.os.SystemClock; 36 import android.platform.test.annotations.Presubmit; 37 import android.tools.ScenarioBuilder; 38 import android.tools.traces.TraceConfig; 39 import android.tools.traces.TraceConfigs; 40 import android.tools.traces.io.ResultReader; 41 import android.tools.traces.io.ResultWriter; 42 import android.tools.traces.monitors.PerfettoTraceMonitor; 43 import android.tools.traces.protolog.ProtoLogTrace; 44 import android.tracing.perfetto.DataSource; 45 import android.util.proto.ProtoInputStream; 46 47 import androidx.test.filters.SmallTest; 48 49 import com.android.internal.protolog.common.IProtoLogGroup; 50 import com.android.internal.protolog.common.LogDataType; 51 import com.android.internal.protolog.common.LogLevel; 52 53 import com.google.common.truth.Truth; 54 55 import org.junit.After; 56 import org.junit.Before; 57 import org.junit.Test; 58 import org.junit.runner.RunWith; 59 import org.junit.runners.JUnit4; 60 import org.mockito.Mockito; 61 import org.mockito.MockitoAnnotations; 62 63 import java.io.File; 64 import java.io.IOException; 65 import java.util.List; 66 import java.util.Random; 67 import java.util.TreeMap; 68 import java.util.concurrent.atomic.AtomicInteger; 69 70 import perfetto.protos.Protolog; 71 import perfetto.protos.ProtologCommon; 72 73 /** 74 * Test class for {@link ProtoLogImpl}. 75 */ 76 @SuppressWarnings("ConstantConditions") 77 @SmallTest 78 @Presubmit 79 @RunWith(JUnit4.class) 80 public class PerfettoProtoLogImplTest { 81 private final File mTracingDirectory = createTempDirectory("temp").toFile(); 82 83 private final ResultWriter mWriter = new ResultWriter() 84 .forScenario(new ScenarioBuilder() 85 .forClass(createTempFile("temp", "").getName()).build()) 86 .withOutputDir(mTracingDirectory) 87 .setRunComplete(); 88 89 private final TraceConfigs mTraceConfig = new TraceConfigs( 90 new TraceConfig(false, true, false), 91 new TraceConfig(false, true, false), 92 new TraceConfig(false, true, false), 93 new TraceConfig(false, true, false) 94 ); 95 96 private PerfettoProtoLogImpl mProtoLog; 97 private Protolog.ProtoLogViewerConfig.Builder mViewerConfigBuilder; 98 private File mFile; 99 private Runnable mCacheUpdater; 100 101 private ProtoLogViewerConfigReader mReader; 102 PerfettoProtoLogImplTest()103 public PerfettoProtoLogImplTest() throws IOException { 104 } 105 106 @Before setUp()107 public void setUp() throws Exception { 108 MockitoAnnotations.initMocks(this); 109 final Context testContext = getInstrumentation().getContext(); 110 mFile = testContext.getFileStreamPath("tracing_test.dat"); 111 //noinspection ResultOfMethodCallIgnored 112 mFile.delete(); 113 114 mViewerConfigBuilder = Protolog.ProtoLogViewerConfig.newBuilder() 115 .addGroups( 116 Protolog.ProtoLogViewerConfig.Group.newBuilder() 117 .setId(1) 118 .setName(TestProtoLogGroup.TEST_GROUP.toString()) 119 .setTag(TestProtoLogGroup.TEST_GROUP.getTag()) 120 ).addMessages( 121 Protolog.ProtoLogViewerConfig.MessageData.newBuilder() 122 .setMessageId(1) 123 .setMessage("My Test Debug Log Message %b") 124 .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_DEBUG) 125 .setGroupId(1) 126 ).addMessages( 127 Protolog.ProtoLogViewerConfig.MessageData.newBuilder() 128 .setMessageId(2) 129 .setMessage("My Test Verbose Log Message %b") 130 .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_VERBOSE) 131 .setGroupId(1) 132 ).addMessages( 133 Protolog.ProtoLogViewerConfig.MessageData.newBuilder() 134 .setMessageId(3) 135 .setMessage("My Test Warn Log Message %b") 136 .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_WARN) 137 .setGroupId(1) 138 ).addMessages( 139 Protolog.ProtoLogViewerConfig.MessageData.newBuilder() 140 .setMessageId(4) 141 .setMessage("My Test Error Log Message %b") 142 .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_ERROR) 143 .setGroupId(1) 144 ).addMessages( 145 Protolog.ProtoLogViewerConfig.MessageData.newBuilder() 146 .setMessageId(5) 147 .setMessage("My Test WTF Log Message %b") 148 .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_WTF) 149 .setGroupId(1) 150 ); 151 152 ViewerConfigInputStreamProvider viewerConfigInputStreamProvider = Mockito.mock( 153 ViewerConfigInputStreamProvider.class); 154 Mockito.when(viewerConfigInputStreamProvider.getInputStream()) 155 .thenAnswer(it -> new ProtoInputStream(mViewerConfigBuilder.build().toByteArray())); 156 157 mCacheUpdater = () -> {}; 158 mReader = Mockito.spy(new ProtoLogViewerConfigReader(viewerConfigInputStreamProvider)); 159 mProtoLog = new PerfettoProtoLogImpl( 160 viewerConfigInputStreamProvider, mReader, new TreeMap<>(), 161 () -> mCacheUpdater.run()); 162 } 163 164 @After tearDown()165 public void tearDown() { 166 if (mFile != null) { 167 //noinspection ResultOfMethodCallIgnored 168 mFile.delete(); 169 } 170 ProtoLogImpl.setSingleInstance(null); 171 } 172 173 @Test isEnabled_returnsFalseByDefault()174 public void isEnabled_returnsFalseByDefault() { 175 assertFalse(mProtoLog.isProtoEnabled()); 176 } 177 178 @Test isEnabled_returnsTrueAfterStart()179 public void isEnabled_returnsTrueAfterStart() { 180 PerfettoTraceMonitor traceMonitor = 181 PerfettoTraceMonitor.newBuilder().enableProtoLog().build(); 182 try { 183 traceMonitor.start(); 184 assertTrue(mProtoLog.isProtoEnabled()); 185 } finally { 186 traceMonitor.stop(mWriter); 187 } 188 } 189 190 @Test isEnabled_returnsFalseAfterStop()191 public void isEnabled_returnsFalseAfterStop() { 192 PerfettoTraceMonitor traceMonitor = 193 PerfettoTraceMonitor.newBuilder().enableProtoLog().build(); 194 try { 195 traceMonitor.start(); 196 assertTrue(mProtoLog.isProtoEnabled()); 197 } finally { 198 traceMonitor.stop(mWriter); 199 } 200 201 assertFalse(mProtoLog.isProtoEnabled()); 202 } 203 204 @Test defaultMode()205 public void defaultMode() throws IOException { 206 PerfettoTraceMonitor traceMonitor = 207 PerfettoTraceMonitor.newBuilder().enableProtoLog(false).build(); 208 try { 209 traceMonitor.start(); 210 // Shouldn't be logging anything except WTF unless explicitly requested in the group 211 // override. 212 mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1, 213 LogDataType.BOOLEAN, null, new Object[]{true}); 214 mProtoLog.log(LogLevel.VERBOSE, TestProtoLogGroup.TEST_GROUP, 2, 215 LogDataType.BOOLEAN, null, new Object[]{true}); 216 mProtoLog.log(LogLevel.WARN, TestProtoLogGroup.TEST_GROUP, 3, 217 LogDataType.BOOLEAN, null, new Object[]{true}); 218 mProtoLog.log(LogLevel.ERROR, TestProtoLogGroup.TEST_GROUP, 4, 219 LogDataType.BOOLEAN, null, new Object[]{true}); 220 mProtoLog.log(LogLevel.WTF, TestProtoLogGroup.TEST_GROUP, 5, 221 LogDataType.BOOLEAN, null, new Object[]{true}); 222 } finally { 223 traceMonitor.stop(mWriter); 224 } 225 226 final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig); 227 final ProtoLogTrace protolog = reader.readProtoLogTrace(); 228 229 Truth.assertThat(protolog.messages).hasSize(1); 230 Truth.assertThat(protolog.messages.getFirst().getLevel()).isEqualTo(LogLevel.WTF); 231 } 232 233 @Test respectsOverrideConfigs_defaultMode()234 public void respectsOverrideConfigs_defaultMode() throws IOException { 235 PerfettoTraceMonitor traceMonitor = 236 PerfettoTraceMonitor.newBuilder().enableProtoLog(true, 237 List.of(new PerfettoTraceMonitor.Builder.ProtoLogGroupOverride( 238 TestProtoLogGroup.TEST_GROUP.toString(), LogLevel.DEBUG, true))) 239 .build(); 240 try { 241 traceMonitor.start(); 242 mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1, 243 LogDataType.BOOLEAN, null, new Object[]{true}); 244 mProtoLog.log(LogLevel.VERBOSE, TestProtoLogGroup.TEST_GROUP, 2, 245 LogDataType.BOOLEAN, null, new Object[]{true}); 246 mProtoLog.log(LogLevel.WARN, TestProtoLogGroup.TEST_GROUP, 3, 247 LogDataType.BOOLEAN, null, new Object[]{true}); 248 mProtoLog.log(LogLevel.ERROR, TestProtoLogGroup.TEST_GROUP, 4, 249 LogDataType.BOOLEAN, null, new Object[]{true}); 250 mProtoLog.log(LogLevel.WTF, TestProtoLogGroup.TEST_GROUP, 5, 251 LogDataType.BOOLEAN, null, new Object[]{true}); 252 } finally { 253 traceMonitor.stop(mWriter); 254 } 255 256 final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig); 257 final ProtoLogTrace protolog = reader.readProtoLogTrace(); 258 259 Truth.assertThat(protolog.messages).hasSize(5); 260 Truth.assertThat(protolog.messages.get(0).getLevel()).isEqualTo(LogLevel.DEBUG); 261 Truth.assertThat(protolog.messages.get(1).getLevel()).isEqualTo(LogLevel.VERBOSE); 262 Truth.assertThat(protolog.messages.get(2).getLevel()).isEqualTo(LogLevel.WARN); 263 Truth.assertThat(protolog.messages.get(3).getLevel()).isEqualTo(LogLevel.ERROR); 264 Truth.assertThat(protolog.messages.get(4).getLevel()).isEqualTo(LogLevel.WTF); 265 } 266 267 @Test respectsOverrideConfigs_allEnabledMode()268 public void respectsOverrideConfigs_allEnabledMode() throws IOException { 269 PerfettoTraceMonitor traceMonitor = 270 PerfettoTraceMonitor.newBuilder().enableProtoLog(true, 271 List.of(new PerfettoTraceMonitor.Builder.ProtoLogGroupOverride( 272 TestProtoLogGroup.TEST_GROUP.toString(), LogLevel.WARN, false))) 273 .build(); 274 try { 275 traceMonitor.start(); 276 mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1, 277 LogDataType.BOOLEAN, null, new Object[]{true}); 278 mProtoLog.log(LogLevel.VERBOSE, TestProtoLogGroup.TEST_GROUP, 2, 279 LogDataType.BOOLEAN, null, new Object[]{true}); 280 mProtoLog.log(LogLevel.WARN, TestProtoLogGroup.TEST_GROUP, 3, 281 LogDataType.BOOLEAN, null, new Object[]{true}); 282 mProtoLog.log(LogLevel.ERROR, TestProtoLogGroup.TEST_GROUP, 4, 283 LogDataType.BOOLEAN, null, new Object[]{true}); 284 mProtoLog.log(LogLevel.WTF, TestProtoLogGroup.TEST_GROUP, 5, 285 LogDataType.BOOLEAN, null, new Object[]{true}); 286 } finally { 287 traceMonitor.stop(mWriter); 288 } 289 290 final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig); 291 final ProtoLogTrace protolog = reader.readProtoLogTrace(); 292 293 Truth.assertThat(protolog.messages).hasSize(3); 294 Truth.assertThat(protolog.messages.get(0).getLevel()).isEqualTo(LogLevel.WARN); 295 Truth.assertThat(protolog.messages.get(1).getLevel()).isEqualTo(LogLevel.ERROR); 296 Truth.assertThat(protolog.messages.get(2).getLevel()).isEqualTo(LogLevel.WTF); 297 } 298 299 @Test respectsAllEnabledMode()300 public void respectsAllEnabledMode() throws IOException { 301 PerfettoTraceMonitor traceMonitor = 302 PerfettoTraceMonitor.newBuilder().enableProtoLog(true, List.of()) 303 .build(); 304 try { 305 traceMonitor.start(); 306 mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1, 307 LogDataType.BOOLEAN, null, new Object[]{true}); 308 mProtoLog.log(LogLevel.VERBOSE, TestProtoLogGroup.TEST_GROUP, 2, 309 LogDataType.BOOLEAN, null, new Object[]{true}); 310 mProtoLog.log(LogLevel.WARN, TestProtoLogGroup.TEST_GROUP, 3, 311 LogDataType.BOOLEAN, null, new Object[]{true}); 312 mProtoLog.log(LogLevel.ERROR, TestProtoLogGroup.TEST_GROUP, 4, 313 LogDataType.BOOLEAN, null, new Object[]{true}); 314 mProtoLog.log(LogLevel.WTF, TestProtoLogGroup.TEST_GROUP, 5, 315 LogDataType.BOOLEAN, null, new Object[]{true}); 316 } finally { 317 traceMonitor.stop(mWriter); 318 } 319 320 final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig); 321 final ProtoLogTrace protolog = reader.readProtoLogTrace(); 322 323 Truth.assertThat(protolog.messages).hasSize(5); 324 Truth.assertThat(protolog.messages.get(0).getLevel()).isEqualTo(LogLevel.DEBUG); 325 Truth.assertThat(protolog.messages.get(1).getLevel()).isEqualTo(LogLevel.VERBOSE); 326 Truth.assertThat(protolog.messages.get(2).getLevel()).isEqualTo(LogLevel.WARN); 327 Truth.assertThat(protolog.messages.get(3).getLevel()).isEqualTo(LogLevel.ERROR); 328 Truth.assertThat(protolog.messages.get(4).getLevel()).isEqualTo(LogLevel.WTF); 329 } 330 331 @Test log_logcatEnabledExternalMessage()332 public void log_logcatEnabledExternalMessage() { 333 when(mReader.getViewerString(anyLong())).thenReturn("test %b %d %% 0x%x %s %f"); 334 PerfettoProtoLogImpl implSpy = Mockito.spy(mProtoLog); 335 TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true); 336 TestProtoLogGroup.TEST_GROUP.setLogToProto(false); 337 338 implSpy.log( 339 LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null, 340 new Object[]{true, 10000, 30000, "test", 0.000003}); 341 342 verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq( 343 LogLevel.INFO), 344 eq("test true 10000 % 0x7530 test 3.0E-6")); 345 verify(mReader).getViewerString(eq(1234L)); 346 } 347 348 @Test log_logcatEnabledInvalidMessage()349 public void log_logcatEnabledInvalidMessage() { 350 when(mReader.getViewerString(anyLong())).thenReturn("test %b %d %% %x %s %f"); 351 PerfettoProtoLogImpl implSpy = Mockito.spy(mProtoLog); 352 TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true); 353 TestProtoLogGroup.TEST_GROUP.setLogToProto(false); 354 355 implSpy.log( 356 LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null, 357 new Object[]{true, 10000, 0.0001, 0.00002, "test"}); 358 359 verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq( 360 LogLevel.INFO), 361 eq("UNKNOWN MESSAGE (1234) true 10000 1.0E-4 2.0E-5 test")); 362 verify(mReader).getViewerString(eq(1234L)); 363 } 364 365 @Test log_logcatEnabledInlineMessage()366 public void log_logcatEnabledInlineMessage() { 367 when(mReader.getViewerString(anyLong())).thenReturn("test %d"); 368 PerfettoProtoLogImpl implSpy = Mockito.spy(mProtoLog); 369 TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true); 370 TestProtoLogGroup.TEST_GROUP.setLogToProto(false); 371 372 implSpy.log( 373 LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d", 374 new Object[]{5}); 375 376 verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq( 377 LogLevel.INFO), eq("test 5")); 378 verify(mReader, never()).getViewerString(anyLong()); 379 } 380 381 @Test log_logcatEnabledNoMessage()382 public void log_logcatEnabledNoMessage() { 383 when(mReader.getViewerString(anyLong())).thenReturn(null); 384 PerfettoProtoLogImpl implSpy = Mockito.spy(mProtoLog); 385 TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true); 386 TestProtoLogGroup.TEST_GROUP.setLogToProto(false); 387 388 implSpy.log( 389 LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null, 390 new Object[]{5}); 391 392 verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq( 393 LogLevel.INFO), eq("UNKNOWN MESSAGE (1234) 5")); 394 verify(mReader).getViewerString(eq(1234L)); 395 } 396 397 @Test log_logcatDisabled()398 public void log_logcatDisabled() { 399 when(mReader.getViewerString(anyLong())).thenReturn("test %d"); 400 PerfettoProtoLogImpl implSpy = Mockito.spy(mProtoLog); 401 TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false); 402 403 implSpy.log( 404 LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d", 405 new Object[]{5}); 406 407 verify(implSpy, never()).passToLogcat(any(), any(), any()); 408 verify(mReader, never()).getViewerString(anyLong()); 409 } 410 411 @Test log_protoEnabled()412 public void log_protoEnabled() throws Exception { 413 final long messageHash = addMessageToConfig( 414 ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_INFO, 415 "My test message :: %s, %d, %o, %x, %f, %e, %g, %b"); 416 417 PerfettoTraceMonitor traceMonitor = 418 PerfettoTraceMonitor.newBuilder().enableProtoLog().build(); 419 long before; 420 long after; 421 try { 422 traceMonitor.start(); 423 assertTrue(mProtoLog.isProtoEnabled()); 424 425 before = SystemClock.elapsedRealtimeNanos(); 426 mProtoLog.log( 427 LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, messageHash, 428 0b1110101001010100, null, 429 new Object[]{"test", 1, 2, 3, 0.4, 0.5, 0.6, true}); 430 after = SystemClock.elapsedRealtimeNanos(); 431 } finally { 432 traceMonitor.stop(mWriter); 433 } 434 435 final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig); 436 final ProtoLogTrace protolog = reader.readProtoLogTrace(); 437 438 Truth.assertThat(protolog.messages).hasSize(1); 439 Truth.assertThat(protolog.messages.getFirst().getTimestamp().getElapsedNanos()) 440 .isAtLeast(before); 441 Truth.assertThat(protolog.messages.getFirst().getTimestamp().getElapsedNanos()) 442 .isAtMost(after); 443 Truth.assertThat(protolog.messages.getFirst().getMessage()) 444 .isEqualTo("My test message :: test, 2, 4, 6, 0.400000, 5.000000e-01, 0.6, true"); 445 } 446 addMessageToConfig(ProtologCommon.ProtoLogLevel logLevel, String message)447 private long addMessageToConfig(ProtologCommon.ProtoLogLevel logLevel, String message) { 448 final long messageId = new Random().nextLong(); 449 mViewerConfigBuilder.addMessages(Protolog.ProtoLogViewerConfig.MessageData.newBuilder() 450 .setMessageId(messageId) 451 .setMessage(message) 452 .setLevel(logLevel) 453 .setGroupId(1) 454 ); 455 456 return messageId; 457 } 458 459 @Test log_invalidParamsMask()460 public void log_invalidParamsMask() { 461 final long messageHash = addMessageToConfig( 462 ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_INFO, 463 "My test message :: %s, %d, %f, %b"); 464 PerfettoTraceMonitor traceMonitor = 465 PerfettoTraceMonitor.newBuilder().enableProtoLog().build(); 466 long before; 467 long after; 468 try { 469 traceMonitor.start(); 470 before = SystemClock.elapsedRealtimeNanos(); 471 mProtoLog.log( 472 LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, messageHash, 473 0b01100100, null, 474 new Object[]{"test", 1, 0.1, true}); 475 after = SystemClock.elapsedRealtimeNanos(); 476 } finally { 477 traceMonitor.stop(mWriter); 478 } 479 480 final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig); 481 assertThrows(IllegalStateException.class, reader::readProtoLogTrace); 482 } 483 484 @Test log_protoDisabled()485 public void log_protoDisabled() throws Exception { 486 PerfettoTraceMonitor traceMonitor = 487 PerfettoTraceMonitor.newBuilder().enableProtoLog(false).build(); 488 try { 489 traceMonitor.start(); 490 mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1, 491 0b11, null, new Object[]{true}); 492 } finally { 493 traceMonitor.stop(mWriter); 494 } 495 496 final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig); 497 final ProtoLogTrace protolog = reader.readProtoLogTrace(); 498 499 Truth.assertThat(protolog.messages).isEmpty(); 500 } 501 502 @Test stackTraceTrimmed()503 public void stackTraceTrimmed() throws IOException { 504 PerfettoTraceMonitor traceMonitor = 505 PerfettoTraceMonitor.newBuilder().enableProtoLog(true, 506 List.of(new PerfettoTraceMonitor.Builder.ProtoLogGroupOverride( 507 TestProtoLogGroup.TEST_GROUP.toString(), LogLevel.DEBUG, 508 true))) 509 .build(); 510 try { 511 traceMonitor.start(); 512 513 ProtoLogImpl.setSingleInstance(mProtoLog); 514 ProtoLogImpl.d(TestProtoLogGroup.TEST_GROUP, 1, 515 0b11, null, true); 516 } finally { 517 traceMonitor.stop(mWriter); 518 } 519 520 final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig); 521 final ProtoLogTrace protolog = reader.readProtoLogTrace(); 522 523 Truth.assertThat(protolog.messages).hasSize(1); 524 String stacktrace = protolog.messages.getFirst().getStacktrace(); 525 Truth.assertThat(stacktrace) 526 .doesNotContain(PerfettoProtoLogImpl.class.getSimpleName() + ".java"); 527 Truth.assertThat(stacktrace).doesNotContain(DataSource.class.getSimpleName() + ".java"); 528 Truth.assertThat(stacktrace) 529 .doesNotContain(ProtoLogImpl.class.getSimpleName() + ".java"); 530 Truth.assertThat(stacktrace).contains(PerfettoProtoLogImplTest.class.getSimpleName()); 531 Truth.assertThat(stacktrace).contains("stackTraceTrimmed"); 532 } 533 534 @Test cacheIsUpdatedWhenTracesStartAndStop()535 public void cacheIsUpdatedWhenTracesStartAndStop() { 536 final AtomicInteger cacheUpdateCallCount = new AtomicInteger(0); 537 mCacheUpdater = cacheUpdateCallCount::incrementAndGet; 538 539 PerfettoTraceMonitor traceMonitor1 = 540 PerfettoTraceMonitor.newBuilder().enableProtoLog(true, 541 List.of(new PerfettoTraceMonitor.Builder.ProtoLogGroupOverride( 542 TestProtoLogGroup.TEST_GROUP.toString(), LogLevel.WARN, 543 false))) 544 .build(); 545 546 PerfettoTraceMonitor traceMonitor2 = 547 PerfettoTraceMonitor.newBuilder().enableProtoLog(true, 548 List.of(new PerfettoTraceMonitor.Builder.ProtoLogGroupOverride( 549 TestProtoLogGroup.TEST_GROUP.toString(), LogLevel.DEBUG, 550 false))) 551 .build(); 552 553 Truth.assertThat(cacheUpdateCallCount.get()).isEqualTo(0); 554 555 try { 556 traceMonitor1.start(); 557 558 Truth.assertThat(cacheUpdateCallCount.get()).isEqualTo(1); 559 560 try { 561 traceMonitor2.start(); 562 563 Truth.assertThat(cacheUpdateCallCount.get()).isEqualTo(2); 564 } finally { 565 traceMonitor2.stop(mWriter); 566 } 567 568 Truth.assertThat(cacheUpdateCallCount.get()).isEqualTo(3); 569 570 } finally { 571 traceMonitor1.stop(mWriter); 572 } 573 574 Truth.assertThat(cacheUpdateCallCount.get()).isEqualTo(4); 575 } 576 577 @Test isEnabledUpdatesBasedOnRunningTraces()578 public void isEnabledUpdatesBasedOnRunningTraces() { 579 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.DEBUG)) 580 .isFalse(); 581 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.VERBOSE)) 582 .isFalse(); 583 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.INFO)) 584 .isFalse(); 585 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WARN)) 586 .isFalse(); 587 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.ERROR)) 588 .isFalse(); 589 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WTF)).isTrue(); 590 591 PerfettoTraceMonitor traceMonitor1 = 592 PerfettoTraceMonitor.newBuilder().enableProtoLog(true, 593 List.of(new PerfettoTraceMonitor.Builder.ProtoLogGroupOverride( 594 TestProtoLogGroup.TEST_GROUP.toString(), LogLevel.WARN, 595 false))) 596 .build(); 597 598 PerfettoTraceMonitor traceMonitor2 = 599 PerfettoTraceMonitor.newBuilder().enableProtoLog(true, 600 List.of(new PerfettoTraceMonitor.Builder.ProtoLogGroupOverride( 601 TestProtoLogGroup.TEST_GROUP.toString(), LogLevel.DEBUG, 602 false))) 603 .build(); 604 605 try { 606 traceMonitor1.start(); 607 608 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.DEBUG)) 609 .isFalse(); 610 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.VERBOSE)) 611 .isFalse(); 612 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.INFO)) 613 .isFalse(); 614 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WARN)) 615 .isTrue(); 616 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.ERROR)) 617 .isTrue(); 618 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WTF)) 619 .isTrue(); 620 621 try { 622 traceMonitor2.start(); 623 624 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.DEBUG)) 625 .isTrue(); 626 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, 627 LogLevel.VERBOSE)).isTrue(); 628 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.INFO)) 629 .isTrue(); 630 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WARN)) 631 .isTrue(); 632 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.ERROR)) 633 .isTrue(); 634 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WTF)) 635 .isTrue(); 636 } finally { 637 traceMonitor2.stop(mWriter); 638 } 639 640 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.DEBUG)) 641 .isFalse(); 642 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.VERBOSE)) 643 .isFalse(); 644 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.INFO)) 645 .isFalse(); 646 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WARN)) 647 .isTrue(); 648 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.ERROR)) 649 .isTrue(); 650 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WTF)) 651 .isTrue(); 652 } finally { 653 traceMonitor1.stop(mWriter); 654 } 655 656 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.DEBUG)) 657 .isFalse(); 658 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.VERBOSE)) 659 .isFalse(); 660 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.INFO)) 661 .isFalse(); 662 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WARN)) 663 .isFalse(); 664 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.ERROR)) 665 .isFalse(); 666 Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WTF)) 667 .isTrue(); 668 } 669 670 private enum TestProtoLogGroup implements IProtoLogGroup { 671 TEST_GROUP(true, true, false, "TEST_TAG"); 672 673 private final boolean mEnabled; 674 private volatile boolean mLogToProto; 675 private volatile boolean mLogToLogcat; 676 private final String mTag; 677 678 /** 679 * @param enabled set to false to exclude all log statements for this group from 680 * compilation, 681 * they will not be available in runtime. 682 * @param logToProto enable binary logging for the group 683 * @param logToLogcat enable text logging for the group 684 * @param tag name of the source of the logged message 685 */ TestProtoLogGroup(boolean enabled, boolean logToProto, boolean logToLogcat, String tag)686 TestProtoLogGroup(boolean enabled, boolean logToProto, boolean logToLogcat, String tag) { 687 this.mEnabled = enabled; 688 this.mLogToProto = logToProto; 689 this.mLogToLogcat = logToLogcat; 690 this.mTag = tag; 691 } 692 693 @Override isEnabled()694 public boolean isEnabled() { 695 return mEnabled; 696 } 697 698 @Override isLogToProto()699 public boolean isLogToProto() { 700 return mLogToProto; 701 } 702 703 @Override isLogToLogcat()704 public boolean isLogToLogcat() { 705 return mLogToLogcat; 706 } 707 708 @Override isLogToAny()709 public boolean isLogToAny() { 710 return mLogToLogcat || mLogToProto; 711 } 712 713 @Override getTag()714 public String getTag() { 715 return mTag; 716 } 717 718 @Override setLogToProto(boolean logToProto)719 public void setLogToProto(boolean logToProto) { 720 this.mLogToProto = logToProto; 721 } 722 723 @Override setLogToLogcat(boolean logToLogcat)724 public void setLogToLogcat(boolean logToLogcat) { 725 this.mLogToLogcat = logToLogcat; 726 } 727 728 @Override getId()729 public int getId() { 730 return ordinal(); 731 } 732 733 } 734 } 735