1 /* 2 * Copyright (C) 2014 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.systemui.recents.events; 18 19 import android.os.Handler; 20 import android.os.Looper; 21 import android.os.SystemClock; 22 import android.os.UserHandle; 23 import android.util.Log; 24 25 import com.android.systemui.recents.misc.ReferenceCountedTrigger; 26 27 import java.io.PrintWriter; 28 import java.lang.ref.WeakReference; 29 import java.lang.reflect.InvocationTargetException; 30 import java.lang.reflect.Method; 31 import java.lang.reflect.Modifier; 32 import java.util.ArrayList; 33 import java.util.Collections; 34 import java.util.Comparator; 35 import java.util.HashMap; 36 import java.util.List; 37 38 /** 39 * Represents a subscriber, which implements various event bus handler methods. 40 */ 41 class Subscriber { 42 private WeakReference<Object> mSubscriber; 43 44 long registrationTime; 45 Subscriber(Object subscriber, long registrationTime)46 Subscriber(Object subscriber, long registrationTime) { 47 mSubscriber = new WeakReference<>(subscriber); 48 this.registrationTime = registrationTime; 49 } 50 toString(int priority)51 public String toString(int priority) { 52 Object sub = mSubscriber.get(); 53 String id = Integer.toHexString(System.identityHashCode(sub)); 54 return sub.getClass().getSimpleName() + " [0x" + id + ", P" + priority + "]"; 55 } 56 getReference()57 public Object getReference() { 58 return mSubscriber.get(); 59 } 60 } 61 62 /** 63 * Represents an event handler with a priority. 64 */ 65 class EventHandler { 66 int priority; 67 Subscriber subscriber; 68 EventHandlerMethod method; 69 EventHandler(Subscriber subscriber, EventHandlerMethod method, int priority)70 EventHandler(Subscriber subscriber, EventHandlerMethod method, int priority) { 71 this.subscriber = subscriber; 72 this.method = method; 73 this.priority = priority; 74 } 75 76 @Override toString()77 public String toString() { 78 return subscriber.toString(priority) + " " + method.toString(); 79 } 80 } 81 82 /** 83 * Represents the low level method handling a particular event. 84 */ 85 class EventHandlerMethod { 86 private Method mMethod; 87 Class<? extends EventBus.Event> eventType; 88 EventHandlerMethod(Method method, Class<? extends EventBus.Event> eventType)89 EventHandlerMethod(Method method, Class<? extends EventBus.Event> eventType) { 90 mMethod = method; 91 mMethod.setAccessible(true); 92 this.eventType = eventType; 93 } 94 invoke(Object target, EventBus.Event event)95 public void invoke(Object target, EventBus.Event event) 96 throws InvocationTargetException, IllegalAccessException { 97 mMethod.invoke(target, event); 98 } 99 100 @Override toString()101 public String toString() { 102 return mMethod.getName() + "(" + eventType.getSimpleName() + ")"; 103 } 104 } 105 106 /** 107 * A simple in-process event bus. It is simple because we can make assumptions about the state of 108 * SystemUI and Recent's lifecycle. 109 * 110 * <p> 111 * Currently, there is a single EventBus that handles {@link EventBus.Event}s for each subscriber 112 * on the main application thread. Publishers can send() events to synchronously call subscribers 113 * of that event, or post() events to be processed in the next run of the {@link Looper}. 114 * 115 * <p> 116 * Subscribers must be registered with a particular EventBus before they will receive events, and 117 * handler methods must match a specific signature. 118 * 119 * <p> 120 * Event method signature:<ul> 121 * <li>Methods must be public final 122 * <li>Methods must return void 123 * <li>Methods must be called "onBusEvent" 124 * <li>Methods must take one parameter, of class type deriving from {@link EventBus.Event} 125 * </ul> 126 * 127 * </p> 128 * Each subscriber can be registered with a given priority (default 1), and events will be dispatch 129 * in decreasing order of priority. For subscribers with the same priority, events will be 130 * dispatched by latest registration time to earliest. 131 * 132 * <p> 133 * Caveats:<ul> 134 * <li>The EventBus keeps a {@link WeakReference} to the publisher to prevent memory leaks, so 135 * there must be another strong reference to the publisher for it to not get garbage-collected and 136 * continue receiving events. 137 * <li>Because the event handlers are called back using reflection, the EventBus is not intended 138 * for use in tight, performance criticial loops. For most user input/system callback events, this 139 * is generally of low enough frequency to use the EventBus. 140 * <li>Because the event handlers are called back using reflection, there will often be no 141 * references to them from actual code. The proguard configuration will be need to be updated to 142 * keep these extra methods: 143 * 144 * -keepclassmembers class ** { 145 * public void onBusEvent(**); 146 * public void onInterprocessBusEvent(**); 147 * } 148 * -keepclassmembers class ** extends **.EventBus$InterprocessEvent { 149 * public <init>(android.os.Bundle); 150 * } 151 * 152 * <li>Subscriber registration can be expensive depending on the subscriber's {@link Class}. This 153 * is only done once per class type, but if possible, it is best to pre-register an instance of 154 * that class beforehand or when idle. 155 * <li>Each event should be sent once. Events may hold internal information about the current 156 * dispatch, or may be queued to be dispatched on another thread (if posted from a non-main thread), 157 * so it may be unsafe to edit, change, or re-send the event again. 158 * <li>Events should follow a pattern of public-final POD (plain old data) objects, where they are 159 * initialized by the constructor and read by each subscriber of that event. Subscribers should 160 * never alter events as they are processed, and this enforces that pattern. 161 * </ul> 162 * 163 * <p> 164 * Future optimizations: 165 * <li>throw exception/log when a subscriber loses the reference 166 * <li>trace cost per registration & invocation 167 * <li>trace cross-process invocation 168 * <li>register(subscriber, Class<?>...) -- pass in exact class types you want registered 169 * <li>setSubscriberEventHandlerPriority(subscriber, Class<Event>, priority) 170 * <li>allow subscribers to implement interface, ie. EventBus.Subscriber, which lets then test a 171 * message before invocation (ie. check if task id == this task id) 172 * <li>add postOnce() which automatically debounces 173 * <li>add postDelayed() which delays / postDelayedOnce() which delays and bounces 174 * <li>consolidate register() and registerInterprocess() 175 * <li>sendForResult<ReturnType>(Event) to send and get a result, but who will send the 176 * result? 177 * </p> 178 */ 179 public class EventBus { 180 181 private static final String TAG = "EventBus"; 182 private static final boolean DEBUG_TRACE_ALL = false; 183 184 /** 185 * An event super class that allows us to track internal event state across subscriber 186 * invocations. 187 * 188 * Events should not be edited by subscribers. 189 */ 190 public static class Event implements Cloneable { 191 // Indicates that this event's dispatch should be traced and logged to logcat 192 boolean trace; 193 // Indicates that this event must be posted on the EventBus's looper thread before invocation 194 boolean requiresPost; 195 // Not currently exposed, allows a subscriber to cancel further dispatch of this event 196 boolean cancelled; 197 198 // Only accessible from derived events Event()199 protected Event() {} 200 201 /** 202 * Called by the EventBus prior to dispatching this event to any subscriber of this event. 203 */ onPreDispatch()204 void onPreDispatch() { 205 // Do nothing 206 } 207 208 /** 209 * Called by the EventBus after dispatching this event to every subscriber of this event. 210 */ onPostDispatch()211 void onPostDispatch() { 212 // Do nothing 213 } 214 215 @Override clone()216 protected Object clone() throws CloneNotSupportedException { 217 Event evt = (Event) super.clone(); 218 // When cloning an event, reset the cancelled-dispatch state 219 evt.cancelled = false; 220 return evt; 221 } 222 } 223 224 /** 225 * An event that represents an animated state change, which allows subscribers to coordinate 226 * callbacks which happen after the animation has taken place. 227 * 228 * Internally, it is guaranteed that increment() and decrement() will be called before and the 229 * after the event is dispatched. 230 */ 231 public static class AnimatedEvent extends Event { 232 233 private final ReferenceCountedTrigger mTrigger = new ReferenceCountedTrigger(); 234 235 // Only accessible from derived events AnimatedEvent()236 protected AnimatedEvent() {} 237 238 /** 239 * Returns the reference counted trigger that coordinates the animations for this event. 240 */ getAnimationTrigger()241 public ReferenceCountedTrigger getAnimationTrigger() { 242 return mTrigger; 243 } 244 245 /** 246 * Adds a callback that is guaranteed to be called after the state has changed regardless of 247 * whether an actual animation took place. 248 */ addPostAnimationCallback(Runnable r)249 public void addPostAnimationCallback(Runnable r) { 250 mTrigger.addLastDecrementRunnable(r); 251 } 252 253 @Override onPreDispatch()254 void onPreDispatch() { 255 mTrigger.increment(); 256 } 257 258 @Override onPostDispatch()259 void onPostDispatch() { 260 mTrigger.decrement(); 261 } 262 263 @Override clone()264 protected Object clone() throws CloneNotSupportedException { 265 throw new CloneNotSupportedException(); 266 } 267 } 268 269 /** 270 * An event that can be reusable, only used for situations where we want to reduce memory 271 * allocations when events are sent frequently (ie. on scroll). 272 */ 273 public static class ReusableEvent extends Event { 274 275 private int mDispatchCount; 276 ReusableEvent()277 protected ReusableEvent() {} 278 279 @Override onPostDispatch()280 void onPostDispatch() { 281 super.onPostDispatch(); 282 mDispatchCount++; 283 } 284 285 @Override clone()286 protected Object clone() throws CloneNotSupportedException { 287 throw new CloneNotSupportedException(); 288 } 289 } 290 291 /** 292 * Proguard must also know, and keep, all methods matching this signature. 293 * 294 * -keepclassmembers class ** { 295 * public void onBusEvent(**); 296 * public void onInterprocessBusEvent(**); 297 * } 298 */ 299 private static final String METHOD_PREFIX = "onBusEvent"; 300 301 // The default priority of all subscribers 302 private static final int DEFAULT_SUBSCRIBER_PRIORITY = 1; 303 304 // Orders the handlers by priority and registration time 305 private static final Comparator<EventHandler> EVENT_HANDLER_COMPARATOR = new Comparator<EventHandler>() { 306 @Override 307 public int compare(EventHandler h1, EventHandler h2) { 308 // Rank the handlers by priority descending, followed by registration time descending. 309 // aka. the later registered 310 if (h1.priority != h2.priority) { 311 return h2.priority - h1.priority; 312 } else { 313 return Long.compare(h2.subscriber.registrationTime, h1.subscriber.registrationTime); 314 } 315 } 316 }; 317 318 // Used for initializing the default bus 319 private static final Object sLock = new Object(); 320 private static volatile EventBus sDefaultBus; 321 322 // The handler to post all events 323 private Handler mHandler; 324 325 /** 326 * Map from event class -> event handler list. Keeps track of the actual mapping from event 327 * to subscriber method. 328 */ 329 private HashMap<Class<? extends Event>, ArrayList<EventHandler>> mEventTypeMap = new HashMap<>(); 330 331 /** 332 * Map from subscriber class -> event handler method lists. Used to determine upon registration 333 * of a new subscriber whether we need to read all the subscriber's methods again using 334 * reflection or whether we can just add the subscriber to the event type map. 335 */ 336 private HashMap<Class<? extends Object>, ArrayList<EventHandlerMethod>> mSubscriberTypeMap = new HashMap<>(); 337 338 /** 339 * Set of all currently registered subscribers 340 */ 341 private ArrayList<Subscriber> mSubscribers = new ArrayList<>(); 342 343 // For tracing 344 private int mCallCount; 345 private long mCallDurationMicros; 346 347 /** 348 * Private constructor to create an event bus for a given looper. 349 */ EventBus(Looper looper)350 private EventBus(Looper looper) { 351 mHandler = new Handler(looper); 352 } 353 354 /** 355 * @return the default event bus for the application's main thread. 356 */ getDefault()357 public static EventBus getDefault() { 358 if (sDefaultBus == null) 359 synchronized (sLock) { 360 if (sDefaultBus == null) { 361 if (DEBUG_TRACE_ALL) { 362 logWithPid("New EventBus"); 363 } 364 sDefaultBus = new EventBus(Looper.getMainLooper()); 365 } 366 } 367 return sDefaultBus; 368 } 369 370 /** 371 * Registers a subscriber to receive events with the default priority. 372 * 373 * @param subscriber the subscriber to handle events. If this is the first instance of the 374 * subscriber's class type that has been registered, the class's methods will 375 * be scanned for appropriate event handler methods. 376 */ register(Object subscriber)377 public void register(Object subscriber) { 378 registerSubscriber(subscriber, DEFAULT_SUBSCRIBER_PRIORITY); 379 } 380 381 /** 382 * Registers a subscriber to receive events with the given priority. 383 * 384 * @param subscriber the subscriber to handle events. If this is the first instance of the 385 * subscriber's class type that has been registered, the class's methods will 386 * be scanned for appropriate event handler methods. 387 * @param priority the priority that this subscriber will receive events relative to other 388 * subscribers 389 */ register(Object subscriber, int priority)390 public void register(Object subscriber, int priority) { 391 registerSubscriber(subscriber, priority); 392 } 393 394 /** 395 * Remove all EventHandlers pointing to the specified subscriber. This does not remove the 396 * mapping of subscriber type to event handler method, in case new instances of this subscriber 397 * are registered. 398 */ unregister(Object subscriber)399 public void unregister(Object subscriber) { 400 if (DEBUG_TRACE_ALL) { 401 logWithPid("unregister()"); 402 } 403 404 // Fail immediately if we are being called from the non-main thread 405 long callingThreadId = Thread.currentThread().getId(); 406 if (callingThreadId != mHandler.getLooper().getThread().getId()) { 407 throw new RuntimeException("Can not unregister() a subscriber from a non-main thread."); 408 } 409 410 // Return early if this is not a registered subscriber 411 if (!findRegisteredSubscriber(subscriber, true /* removeFoundSubscriber */)) { 412 return; 413 } 414 415 Class<?> subscriberType = subscriber.getClass(); 416 ArrayList<EventHandlerMethod> subscriberMethods = mSubscriberTypeMap.get(subscriberType); 417 if (subscriberMethods != null) { 418 // For each of the event handlers the subscriber handles, remove all references of that 419 // handler 420 for (EventHandlerMethod method : subscriberMethods) { 421 ArrayList<EventHandler> eventHandlers = mEventTypeMap.get(method.eventType); 422 for (int i = eventHandlers.size() - 1; i >= 0; i--) { 423 if (eventHandlers.get(i).subscriber.getReference() == subscriber) { 424 eventHandlers.remove(i); 425 } 426 } 427 } 428 } 429 } 430 431 /** 432 * Sends an event to the subscribers of the given event type immediately. This can only be 433 * called from the same thread as the EventBus's looper thread (for the default EventBus, this 434 * is the main application thread). 435 */ send(Event event)436 public void send(Event event) { 437 // Fail immediately if we are being called from the non-main thread 438 long callingThreadId = Thread.currentThread().getId(); 439 if (callingThreadId != mHandler.getLooper().getThread().getId()) { 440 throw new RuntimeException("Can not send() a message from a non-main thread."); 441 } 442 443 if (DEBUG_TRACE_ALL) { 444 logWithPid("send(" + event.getClass().getSimpleName() + ")"); 445 } 446 447 // Reset the event's cancelled state 448 event.requiresPost = false; 449 event.cancelled = false; 450 queueEvent(event); 451 } 452 453 /** 454 * Post a message to the subscribers of the given event type. The messages will be posted on 455 * the EventBus's looper thread (for the default EventBus, this is the main application thread). 456 */ post(Event event)457 public void post(Event event) { 458 if (DEBUG_TRACE_ALL) { 459 logWithPid("post(" + event.getClass().getSimpleName() + ")"); 460 } 461 462 // Reset the event's cancelled state 463 event.requiresPost = true; 464 event.cancelled = false; 465 queueEvent(event); 466 } 467 468 /** 469 * If this method is called from the main thread, it will be handled directly. If this method 470 * is not called from the main thread, it will be posted onto the main thread. 471 */ sendOntoMainThread(Event event)472 public void sendOntoMainThread(Event event) { 473 long callingThreadId = Thread.currentThread().getId(); 474 if (callingThreadId != mHandler.getLooper().getThread().getId()) { 475 post(event); 476 } else { 477 send(event); 478 } 479 } 480 481 /** 482 * @return a dump of the current state of the EventBus 483 */ dump(String prefix, PrintWriter writer)484 public void dump(String prefix, PrintWriter writer) { 485 writer.println(dumpInternal(prefix)); 486 } 487 dumpInternal(String prefix)488 public String dumpInternal(String prefix) { 489 String innerPrefix = prefix + " "; 490 String innerInnerPrefix = innerPrefix + " "; 491 StringBuilder output = new StringBuilder(); 492 output.append(prefix); 493 output.append("Registered class types:"); 494 output.append("\n"); 495 ArrayList<Class<?>> subsciberTypes = new ArrayList<>(mSubscriberTypeMap.keySet()); 496 Collections.sort(subsciberTypes, new Comparator<Class<?>>() { 497 @Override 498 public int compare(Class<?> o1, Class<?> o2) { 499 return o1.getSimpleName().compareTo(o2.getSimpleName()); 500 } 501 }); 502 for (int i = 0; i < subsciberTypes.size(); i++) { 503 Class<?> clz = subsciberTypes.get(i); 504 output.append(innerPrefix); 505 output.append(clz.getSimpleName()); 506 output.append("\n"); 507 } 508 output.append(prefix); 509 output.append("Event map:"); 510 output.append("\n"); 511 ArrayList<Class<?>> classes = new ArrayList<>(mEventTypeMap.keySet()); 512 Collections.sort(classes, new Comparator<Class<?>>() { 513 @Override 514 public int compare(Class<?> o1, Class<?> o2) { 515 return o1.getSimpleName().compareTo(o2.getSimpleName()); 516 } 517 }); 518 for (int i = 0; i < classes.size(); i++) { 519 Class<?> clz = classes.get(i); 520 output.append(innerPrefix); 521 output.append(clz.getSimpleName()); 522 output.append(" -> "); 523 output.append("\n"); 524 ArrayList<EventHandler> handlers = mEventTypeMap.get(clz); 525 for (EventHandler handler : handlers) { 526 Object subscriber = handler.subscriber.getReference(); 527 if (subscriber != null) { 528 String id = Integer.toHexString(System.identityHashCode(subscriber)); 529 output.append(innerInnerPrefix); 530 output.append(subscriber.getClass().getSimpleName()); 531 output.append(" [0x" + id + ", #" + handler.priority + "]"); 532 output.append("\n"); 533 } 534 } 535 } 536 return output.toString(); 537 } 538 539 /** 540 * Registers a new subscriber. 541 */ registerSubscriber(Object subscriber, int priority)542 private void registerSubscriber(Object subscriber, int priority) { 543 // Fail immediately if we are being called from the non-main thread 544 long callingThreadId = Thread.currentThread().getId(); 545 if (callingThreadId != mHandler.getLooper().getThread().getId()) { 546 throw new RuntimeException("Can not register() a subscriber from a non-main thread."); 547 } 548 549 // Return immediately if this exact subscriber is already registered 550 if (findRegisteredSubscriber(subscriber, false /* removeFoundSubscriber */)) { 551 return; 552 } 553 554 long t1 = 0; 555 if (DEBUG_TRACE_ALL) { 556 t1 = SystemClock.currentTimeMicro(); 557 logWithPid("registerSubscriber(" + subscriber.getClass().getSimpleName() + ")"); 558 } 559 Subscriber sub = new Subscriber(subscriber, SystemClock.uptimeMillis()); 560 Class<?> subscriberType = subscriber.getClass(); 561 ArrayList<EventHandlerMethod> subscriberMethods = mSubscriberTypeMap.get(subscriberType); 562 if (subscriberMethods != null) { 563 if (DEBUG_TRACE_ALL) { 564 logWithPid("Subscriber class type already registered"); 565 } 566 567 // If we've parsed this subscriber type before, just add to the set for all the known 568 // events 569 for (EventHandlerMethod method : subscriberMethods) { 570 ArrayList<EventHandler> eventTypeHandlers = mEventTypeMap.get(method.eventType); 571 eventTypeHandlers.add(new EventHandler(sub, method, priority)); 572 sortEventHandlersByPriority(eventTypeHandlers); 573 } 574 mSubscribers.add(sub); 575 return; 576 } else { 577 if (DEBUG_TRACE_ALL) { 578 logWithPid("Subscriber class type requires registration"); 579 } 580 581 // If we are parsing this type from scratch, ensure we add it to the subscriber type 582 // map, and pull out he handler methods below 583 subscriberMethods = new ArrayList<>(); 584 mSubscriberTypeMap.put(subscriberType, subscriberMethods); 585 mSubscribers.add(sub); 586 } 587 588 // Find all the valid event bus handler methods of the subscriber 589 Method[] methods = subscriberType.getDeclaredMethods(); 590 for (Method m : methods) { 591 Class<?>[] parameterTypes = m.getParameterTypes(); 592 if (isValidEventBusHandlerMethod(m, parameterTypes)) { 593 Class<? extends Event> eventType = (Class<? extends Event>) parameterTypes[0]; 594 ArrayList<EventHandler> eventTypeHandlers = mEventTypeMap.get(eventType); 595 if (eventTypeHandlers == null) { 596 eventTypeHandlers = new ArrayList<>(); 597 mEventTypeMap.put(eventType, eventTypeHandlers); 598 } 599 EventHandlerMethod method = new EventHandlerMethod(m, eventType); 600 EventHandler handler = new EventHandler(sub, method, priority); 601 eventTypeHandlers.add(handler); 602 subscriberMethods.add(method); 603 sortEventHandlersByPriority(eventTypeHandlers); 604 605 if (DEBUG_TRACE_ALL) { 606 logWithPid(" * Method: " + m.getName() + 607 " event: " + parameterTypes[0].getSimpleName()); 608 } 609 } 610 } 611 if (DEBUG_TRACE_ALL) { 612 logWithPid("Registered " + subscriber.getClass().getSimpleName() + " in " + 613 (SystemClock.currentTimeMicro() - t1) + " microseconds"); 614 } 615 } 616 617 /** 618 * Adds a new message. 619 */ queueEvent(final Event event)620 private void queueEvent(final Event event) { 621 ArrayList<EventHandler> eventHandlers = mEventTypeMap.get(event.getClass()); 622 if (eventHandlers == null) { 623 // This is just an optimization to return early if there are no handlers. However, we 624 // should still ensure that we call pre/post dispatch callbacks so that AnimatedEvents 625 // are still cleaned up correctly if a listener has not been registered to handle them 626 event.onPreDispatch(); 627 event.onPostDispatch(); 628 return; 629 } 630 631 // Prepare this event 632 boolean hasPostedEvent = false; 633 event.onPreDispatch(); 634 635 // We need to clone the list in case a subscriber unregisters itself during traversal 636 // TODO: Investigate whether we can skip the object creation here 637 eventHandlers = (ArrayList<EventHandler>) eventHandlers.clone(); 638 int eventHandlerCount = eventHandlers.size(); 639 for (int i = 0; i < eventHandlerCount; i++) { 640 final EventHandler eventHandler = eventHandlers.get(i); 641 if (eventHandler.subscriber.getReference() != null) { 642 if (event.requiresPost) { 643 mHandler.post(() -> processEvent(eventHandler, event)); 644 hasPostedEvent = true; 645 } else { 646 processEvent(eventHandler, event); 647 } 648 } 649 } 650 651 // Clean up after this event, deferring until all subscribers have been called 652 if (hasPostedEvent) { 653 mHandler.post(event::onPostDispatch); 654 } else { 655 event.onPostDispatch(); 656 } 657 } 658 659 /** 660 * Processes and dispatches the given event to the given event handler, on the thread of whoever 661 * calls this method. 662 */ processEvent(final EventHandler eventHandler, final Event event)663 private void processEvent(final EventHandler eventHandler, final Event event) { 664 // Skip if the event was already cancelled 665 if (event.cancelled) { 666 if (event.trace || DEBUG_TRACE_ALL) { 667 logWithPid("Event dispatch cancelled"); 668 } 669 return; 670 } 671 672 try { 673 if (event.trace || DEBUG_TRACE_ALL) { 674 logWithPid(" -> " + eventHandler.toString()); 675 } 676 Object sub = eventHandler.subscriber.getReference(); 677 if (sub != null) { 678 long t1 = 0; 679 if (DEBUG_TRACE_ALL) { 680 t1 = SystemClock.currentTimeMicro(); 681 } 682 eventHandler.method.invoke(sub, event); 683 if (DEBUG_TRACE_ALL) { 684 long duration = (SystemClock.currentTimeMicro() - t1); 685 mCallDurationMicros += duration; 686 mCallCount++; 687 logWithPid(eventHandler.method.toString() + " duration: " + duration + 688 " microseconds, avg: " + (mCallDurationMicros / mCallCount)); 689 } 690 } else { 691 Log.e(TAG, "Failed to deliver event to null subscriber"); 692 } 693 } catch (IllegalAccessException e) { 694 Log.e(TAG, "Failed to invoke method", e.getCause()); 695 } catch (InvocationTargetException e) { 696 throw new RuntimeException(e.getCause()); 697 } 698 } 699 700 /** 701 * Returns whether this subscriber is currently registered. If {@param removeFoundSubscriber} 702 * is true, then remove the subscriber before returning. 703 */ findRegisteredSubscriber(Object subscriber, boolean removeFoundSubscriber)704 private boolean findRegisteredSubscriber(Object subscriber, boolean removeFoundSubscriber) { 705 for (int i = mSubscribers.size() - 1; i >= 0; i--) { 706 Subscriber sub = mSubscribers.get(i); 707 if (sub.getReference() == subscriber) { 708 if (removeFoundSubscriber) { 709 mSubscribers.remove(i); 710 } 711 return true; 712 } 713 } 714 return false; 715 } 716 717 /** 718 * @return whether {@param method} is a valid (normal or interprocess) event bus handler method 719 */ isValidEventBusHandlerMethod(Method method, Class<?>[] parameterTypes)720 private boolean isValidEventBusHandlerMethod(Method method, Class<?>[] parameterTypes) { 721 int modifiers = method.getModifiers(); 722 if (Modifier.isPublic(modifiers) && 723 Modifier.isFinal(modifiers) && 724 method.getReturnType().equals(Void.TYPE) && 725 parameterTypes.length == 1) { 726 if (EventBus.Event.class.isAssignableFrom(parameterTypes[0]) && 727 method.getName().startsWith(METHOD_PREFIX)) { 728 return true; 729 } else { 730 if (DEBUG_TRACE_ALL) { 731 if (!EventBus.Event.class.isAssignableFrom(parameterTypes[0])) { 732 logWithPid(" Expected method take an Event-based parameter: " + method.getName()); 733 } 734 } 735 } 736 } else { 737 if (DEBUG_TRACE_ALL) { 738 if (!Modifier.isPublic(modifiers)) { 739 logWithPid(" Expected method to be public: " + method.getName()); 740 } else if (!Modifier.isFinal(modifiers)) { 741 logWithPid(" Expected method to be final: " + method.getName()); 742 } else if (!method.getReturnType().equals(Void.TYPE)) { 743 logWithPid(" Expected method to return null: " + method.getName()); 744 } 745 } 746 } 747 return false; 748 } 749 750 /** 751 * Sorts the event handlers by priority and registration time. 752 */ sortEventHandlersByPriority(List<EventHandler> eventHandlers)753 private void sortEventHandlersByPriority(List<EventHandler> eventHandlers) { 754 Collections.sort(eventHandlers, EVENT_HANDLER_COMPARATOR); 755 } 756 757 /** 758 * Helper method to log the given {@param text} with the current process and user id. 759 */ logWithPid(String text)760 private static void logWithPid(String text) { 761 Log.d(TAG, "[" + android.os.Process.myPid() + ", u" + UserHandle.myUserId() + "] " + text); 762 } 763 } 764