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&lt;?&gt;...) -- 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&lt;ReturnType&gt;(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