• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.base;
6 
7 import android.os.Handler;
8 import android.os.Message;
9 import android.util.Log;
10 
11 import java.lang.reflect.InvocationTargetException;
12 import java.lang.reflect.Method;
13 
14 class SystemMessageHandler extends Handler {
15 
16     private static final String TAG = "SystemMessageHandler";
17 
18     private static final int SCHEDULED_WORK = 1;
19     private static final int DELAYED_SCHEDULED_WORK = 2;
20 
21     // Native class pointer set by the constructor of the SharedClient native class.
22     private long mMessagePumpDelegateNative = 0;
23     private long mDelayedScheduledTimeTicks = 0;
24 
25     // Reflected API for marking a message as asynchronous. This is a workaround
26     // to provide fair Chromium task dispatch when served by the Android UI
27     // thread's Looper, avoiding stalls when the Looper has a sync barrier.
28     // Note: Use of this API is experimental and likely to evolve in the future.
29     private Method mMessageMethodSetAsynchronous;
30 
SystemMessageHandler(long messagePumpDelegateNative)31     private SystemMessageHandler(long messagePumpDelegateNative) {
32         mMessagePumpDelegateNative = messagePumpDelegateNative;
33 
34         try {
35             Class<?> messageClass = Class.forName("android.os.Message");
36             mMessageMethodSetAsynchronous = messageClass.getMethod(
37                     "setAsynchronous", new Class[]{boolean.class});
38         } catch (ClassNotFoundException e) {
39             Log.e(TAG, "Failed to find android.os.Message class:" + e);
40         } catch (NoSuchMethodException e) {
41             Log.e(TAG, "Failed to load Message.setAsynchronous method:" + e);
42         } catch (RuntimeException e) {
43             Log.e(TAG, "Exception while loading Message.setAsynchronous method: " + e);
44         }
45 
46     }
47 
48     @Override
handleMessage(Message msg)49     public void handleMessage(Message msg) {
50         if (msg.what == DELAYED_SCHEDULED_WORK) {
51             mDelayedScheduledTimeTicks = 0;
52         }
53         nativeDoRunLoopOnce(mMessagePumpDelegateNative, mDelayedScheduledTimeTicks);
54     }
55 
56     @SuppressWarnings("unused")
57     @CalledByNative
scheduleWork()58     private void scheduleWork() {
59         sendMessage(obtainAsyncMessage(SCHEDULED_WORK));
60     }
61 
62     @SuppressWarnings("unused")
63     @CalledByNative
scheduleDelayedWork(long delayedTimeTicks, long millis)64     private void scheduleDelayedWork(long delayedTimeTicks, long millis) {
65         if (mDelayedScheduledTimeTicks != 0) {
66             removeMessages(DELAYED_SCHEDULED_WORK);
67         }
68         mDelayedScheduledTimeTicks = delayedTimeTicks;
69         sendMessageDelayed(obtainAsyncMessage(DELAYED_SCHEDULED_WORK), millis);
70     }
71 
72     @SuppressWarnings("unused")
73     @CalledByNative
removeAllPendingMessages()74     private void removeAllPendingMessages() {
75         removeMessages(SCHEDULED_WORK);
76         removeMessages(DELAYED_SCHEDULED_WORK);
77     }
78 
obtainAsyncMessage(int what)79     private Message obtainAsyncMessage(int what) {
80         Message msg = Message.obtain();
81         msg.what = what;
82         if (mMessageMethodSetAsynchronous != null) {
83             // If invocation fails, assume this is indicative of future
84             // failures, and avoid log spam by nulling the reflected method.
85             try {
86                 mMessageMethodSetAsynchronous.invoke(msg, true);
87             } catch (IllegalAccessException e) {
88                 Log.e(TAG, "Illegal access to asynchronous message creation, disabling.");
89                 mMessageMethodSetAsynchronous = null;
90             } catch (IllegalArgumentException e) {
91                 Log.e(TAG, "Illegal argument for asynchronous message creation, disabling.");
92                 mMessageMethodSetAsynchronous = null;
93             } catch (InvocationTargetException e) {
94                 Log.e(TAG, "Invocation exception during asynchronous message creation, disabling.");
95                 mMessageMethodSetAsynchronous = null;
96             } catch (RuntimeException e) {
97                 Log.e(TAG, "Runtime exception during asynchronous message creation, disabling.");
98                 mMessageMethodSetAsynchronous = null;
99             }
100         }
101         return msg;
102     }
103 
104     @CalledByNative
create(long messagePumpDelegateNative)105     private static SystemMessageHandler create(long messagePumpDelegateNative) {
106         return new SystemMessageHandler(messagePumpDelegateNative);
107     }
108 
nativeDoRunLoopOnce( long messagePumpDelegateNative, long delayedScheduledTimeTicks)109     private native void nativeDoRunLoopOnce(
110             long messagePumpDelegateNative, long delayedScheduledTimeTicks);
111 }
112