Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

timob-14520: Android: Anvil: android/android/android -> jsActivityUrl failed #4622

Merged
merged 3 commits into from
Sep 14, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ public static void postOnRuntime(Runnable runnable)
*/
public static Object sendBlockingMainMessage(Message message)
{
return threadLocalMessenger.get().sendBlockingMessage(message, mainMessenger, null);
return threadLocalMessenger.get().sendBlockingMessage(message, mainMessenger, null, -1);
}

/**
Expand All @@ -156,7 +156,7 @@ public static Object sendBlockingMainMessage(Message message)
*/
public static Object sendBlockingMainMessage(Message message, Object asyncArg)
{
return threadLocalMessenger.get().sendBlockingMessage(message, mainMessenger, asyncArg);
return threadLocalMessenger.get().sendBlockingMessage(message, mainMessenger, asyncArg, -1);
}

/**
Expand All @@ -169,7 +169,7 @@ public static Object sendBlockingMainMessage(Message message, Object asyncArg)
*/
public static Object sendBlockingRuntimeMessage(Message message)
{
return threadLocalMessenger.get().sendBlockingMessage(message, runtimeMessenger, null);
return threadLocalMessenger.get().sendBlockingMessage(message, runtimeMessenger, null, -1);
}

/**
Expand All @@ -183,7 +183,23 @@ public static Object sendBlockingRuntimeMessage(Message message)
*/
public static Object sendBlockingRuntimeMessage(Message message, Object asyncArg)
{
return threadLocalMessenger.get().sendBlockingMessage(message, runtimeMessenger, asyncArg);
return threadLocalMessenger.get().sendBlockingMessage(message, runtimeMessenger, asyncArg, -1);
}

/**
* Sends a message to an {@link java.util.concurrent.ArrayBlockingQueue#ArrayBlockingQueue(int) ArrayBlockingQueue},
* and dispatch messages on the current
* queue while blocking on the passed in AsyncResult. The blocking is done on the KrollRuntime thread.
* If maxTimeout > 0, it will throw an error and return when we cannot get the permission from the semaphore within maxTimeout.
* @param message the message to send.
* @param asyncArg the argument to be added to AsyncResult.
* @param maxTimeout the maximum time to wait for a permit from the semaphore, in the unit of milliseconds.
* @return The getResult() value of the AsyncResult put on the message.
* @module.api
*/
public static Object sendBlockingRuntimeMessage(Message message, Object asyncArg, long maxTimeout)
{
return threadLocalMessenger.get().sendBlockingMessage(message, runtimeMessenger, asyncArg, maxTimeout);
}


Expand All @@ -209,39 +225,46 @@ public Handler getHandler()

/**
* Sends a message to an {@link java.util.concurrent.ArrayBlockingQueue#ArrayBlockingQueue(int) ArrayBlockingQueue}, and dispatch messages on the current
* queue while blocking on the passed in AsyncResult.
* queue while blocking on the passed in AsyncResult. If maxTimeout > 0 and the cannot get the permission from
* the semaphore within maxTimeout, throw an error and return.
* @param message The message to send.
* @param targetMessenger The TiMessenger to send it to.
* @param asyncArg argument to be added to the AsyncResult put on the message.
* @param maxTimeout the maximum time to wait for a permit from the semaphore.
* @return The getResult() value of the AsyncResult put on the message.
*/
private Object sendBlockingMessage(Message message, TiMessenger targetMessenger, Object asyncArg)
private Object sendBlockingMessage(Message message, TiMessenger targetMessenger, Object asyncArg, final long maxTimeout)
{
@SuppressWarnings("serial")
AsyncResult wrappedAsyncResult = new AsyncResult(asyncArg) {
@Override
public Object getResult()
{
int timeout = 0;
long elapsedTime = 0;
try {
// TODO: create a multi-semaphore condition
// here so we don't unnecessarily poll
while (!tryAcquire(timeout, TimeUnit.MILLISECONDS)) {
if (messageQueue.size() == 0) {
timeout = 50;

} else {
dispatchPendingMessages();
}
}

elapsedTime += timeout;
if (maxTimeout > 0 && elapsedTime > maxTimeout) {
setException(new Throwable("getResult() has timed out."));
break;
}
}
} catch (InterruptedException e) {
Log.e(TAG, "Interrupted waiting for async result", e);
dispatchPendingMessages();
}

if (exception != null) {
throw new RuntimeException(exception);
Log.e(TAG, "Unable to get the result from the blocking message.", exception);
}

return result;
Expand Down
41 changes: 32 additions & 9 deletions android/titanium/src/java/org/appcelerator/kroll/KrollProxy.java
Original file line number Diff line number Diff line change
Expand Up @@ -753,23 +753,46 @@ public boolean fireEventToParent(String eventName, Object data)
*/
public boolean fireSyncEvent(String event, Object data)
{
if (hierarchyHasListener(event)) {
if (KrollRuntime.getInstance().isRuntimeThread()) {
return doFireEvent(event, data);
if (KrollRuntime.getInstance().isRuntimeThread()) {
return doFireEvent(event, data);

} else {
Message message = getRuntimeHandler().obtainMessage(MSG_FIRE_SYNC_EVENT);
message.getData().putString(PROPERTY_NAME, event);
} else {
Message message = getRuntimeHandler().obtainMessage(MSG_FIRE_SYNC_EVENT);
message.getData().putString(PROPERTY_NAME, event);

return (Boolean) TiMessenger.sendBlockingRuntimeMessage(message, data);
}
return (Boolean) TiMessenger.sendBlockingRuntimeMessage(message, data);
}
}

/**
* Fires an event synchronously via KrollRuntime thread, which can be intercepted on JS side.
* @param event the event to be fired.
* @param data the data to be sent.
* @param maxTimeout the maximum time to wait for the result to return, in the unit of milliseconds.
* @return whether this proxy has an eventListener for this event.
* @module.api
*/
public boolean fireSyncEvent(String event, Object data, long maxTimeout)
{
if (KrollRuntime.getInstance().isRuntimeThread()) {
return doFireEvent(event, data);

} else {
Message message = getRuntimeHandler().obtainMessage(MSG_FIRE_SYNC_EVENT);
message.getData().putString(PROPERTY_NAME, event);

Object result = TiMessenger.sendBlockingRuntimeMessage(message, data, maxTimeout);
return TiConvert.toBoolean(result, false);
}
return false;
}

@SuppressWarnings({ "rawtypes", "unchecked" })
public boolean doFireEvent(String event, Object data)
{
if (!hierarchyHasListener(event)) {
return false;
}

boolean bubbles = false;
boolean reportSuccess = false;
int code = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,8 @@ protected void onCreate(Bundle savedInstanceState)
windowCreated();

if (activityProxy != null) {
activityProxy.fireSyncEvent(TiC.EVENT_CREATE, null);
// Fire the sync event with a timeout, so the main thread won't be blocked too long to get an ANR. (TIMOB-13253)
activityProxy.fireSyncEvent(TiC.EVENT_CREATE, null, 4000);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 seconds may be cutting it close, since Android throws ANR if main thread is not responding to UI input within 5s. Also, we should move this value into a constant.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why aren't we doing the same for main thread?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested with mFoundry project and it took 2.5 sec to fire the create event. So I use 4 sec to give it a little more buffer. I did not do the same thing for the main thread because it's out of the scope of this ticket and I think it's risky since it will affect all the blocking messages.

}

// set the current activity back to what it was originally
Expand Down Expand Up @@ -984,7 +985,8 @@ protected void onResume()
TiApplication.updateActivityTransitionState(false);

if (activityProxy != null) {
activityProxy.fireSyncEvent(TiC.EVENT_RESUME, null);
// Fire the sync event with a timeout, so the main thread won't be blocked too long to get an ANR. (TIMOB-13253)
activityProxy.fireSyncEvent(TiC.EVENT_RESUME, null, 4000);
}

synchronized (lifecycleListeners.synchronizedList()) {
Expand Down Expand Up @@ -1042,7 +1044,8 @@ protected void onStart()
Activity tempCurrentActivity = tiApp.getCurrentActivity();
tiApp.setCurrentActivity(this, this);

activityProxy.fireSyncEvent(TiC.EVENT_START, null);
// Fire the sync event with a timeout, so the main thread won't be blocked too long to get an ANR. (TIMOB-13253)
activityProxy.fireSyncEvent(TiC.EVENT_START, null, 4000);

// set the current activity back to what it was originally
tiApp.setCurrentActivity(this, tempCurrentActivity);
Expand Down