You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ag...@apache.org on 2013/06/28 18:00:57 UTC

[37/50] [abbrv] android commit: [CB-3927] Fix start-up race condition that could cause exec() responses to be dropped.

[CB-3927] Fix start-up race condition that could cause exec() responses to be dropped.

Requires a change to the JS as well.


Project: http://git-wip-us.apache.org/repos/asf/cordova-android/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-android/commit/9cb14838
Tree: http://git-wip-us.apache.org/repos/asf/cordova-android/tree/9cb14838
Diff: http://git-wip-us.apache.org/repos/asf/cordova-android/diff/9cb14838

Branch: refs/heads/2.9.x
Commit: 9cb14838e8554ed2d28d317b37f76685fa76432e
Parents: 6fe66ad
Author: Jeffrey Willms <jb...@google.com>
Authored: Fri Jun 21 18:30:50 2013 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Fri Jun 21 18:30:50 2013 -0400

----------------------------------------------------------------------
 .../src/org/apache/cordova/api/PluginEntry.java | 13 ++++++
 .../org/apache/cordova/api/PluginManager.java   | 49 +++++++++++++++++++-
 2 files changed, 60 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/9cb14838/framework/src/org/apache/cordova/api/PluginEntry.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/api/PluginEntry.java b/framework/src/org/apache/cordova/api/PluginEntry.java
index 9b9af6b..f66dcda 100755
--- a/framework/src/org/apache/cordova/api/PluginEntry.java
+++ b/framework/src/org/apache/cordova/api/PluginEntry.java
@@ -64,6 +64,19 @@ public class PluginEntry {
     }
 
     /**
+     * Alternate constructor
+     *
+     * @param service               The name of the service
+     * @param plugin                The plugin associated with this entry
+     */
+    public PluginEntry(String service, CordovaPlugin plugin) {
+        this.service = service;
+        this.plugin = plugin;
+        this.pluginClass = plugin.getClass().getName();
+        this.onload = false;
+    }
+
+    /**
      * Create plugin object.
      * If plugin is already created, then just return it.
      *

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/9cb14838/framework/src/org/apache/cordova/api/PluginManager.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/api/PluginManager.java b/framework/src/org/apache/cordova/api/PluginManager.java
index adaec90..0a42b3a 100755
--- a/framework/src/org/apache/cordova/api/PluginManager.java
+++ b/framework/src/org/apache/cordova/api/PluginManager.java
@@ -22,7 +22,9 @@ import java.io.IOException;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map.Entry;
+import java.util.concurrent.atomic.AtomicInteger;
 
+import org.apache.cordova.CordovaArgs;
 import org.apache.cordova.CordovaWebView;
 import org.json.JSONException;
 import org.xmlpull.v1.XmlPullParserException;
@@ -55,6 +57,8 @@ public class PluginManager {
     // This would allow how all URLs are handled to be offloaded to a plugin
     protected HashMap<String, String> urlMap = new HashMap<String, String>();
 
+    private AtomicInteger numPendingUiExecs;
+
     /**
      * Constructor.
      *
@@ -65,6 +69,7 @@ public class PluginManager {
         this.ctx = ctx;
         this.app = app;
         this.firstRun = true;
+        this.numPendingUiExecs = new AtomicInteger(0);
     }
 
     /**
@@ -86,6 +91,9 @@ public class PluginManager {
             this.clearPluginObjects();
         }
 
+        // Insert PluginManager service
+        this.addService(new PluginEntry("PluginManager", new PluginManagerService()));
+
         // Start up all plugins that have onload specified
         this.startupPlugins();
     }
@@ -201,8 +209,23 @@ public class PluginManager {
      * @param rawArgs       An Array literal string containing any arguments needed in the
      *                      plugin execute method.
      */
-    public void exec(String service, String action, String callbackId, String rawArgs) {
-        CordovaPlugin plugin = this.getPlugin(service);
+    public void exec(final String service, final String action, final String callbackId, final String rawArgs) {
+        if (numPendingUiExecs.get() > 0) {
+            numPendingUiExecs.getAndIncrement();
+            this.ctx.getActivity().runOnUiThread(new Runnable() {
+                public void run() {
+                    execHelper(service, action, callbackId, rawArgs);
+                    numPendingUiExecs.getAndDecrement();
+                }
+            });
+        } else {
+            Log.d(TAG, "running exec normally");
+            execHelper(service, action, callbackId, rawArgs);
+        }
+    }
+
+    private void execHelper(final String service, final String action, final String callbackId, final String rawArgs) {
+        CordovaPlugin plugin = getPlugin(service);
         if (plugin == null) {
             Log.d(TAG, "exec() call to unknown plugin: " + service);
             PluginResult cr = new PluginResult(PluginResult.Status.CLASS_NOT_FOUND_EXCEPTION);
@@ -396,4 +419,26 @@ public class PluginManager {
         LOG.e(TAG, "https://git-wip-us.apache.org/repos/asf?p=incubator-cordova-android.git;a=blob;f=framework/res/xml/plugins.xml");
         LOG.e(TAG, "=====================================================================================");
     }
+
+    private class PluginManagerService extends CordovaPlugin {
+        @Override
+        public boolean execute(String action, CordovaArgs args, final CallbackContext callbackContext) throws JSONException {
+            if ("startup".equals(action)) {
+                // The onPageStarted event of CordovaWebViewClient resets the queue of messages to be returned to javascript in response
+                // to exec calls. Since this event occurs on the UI thread and exec calls happen on the WebCore thread it is possible
+                // that onPageStarted occurs after exec calls have started happening on a new page, which can cause the message queue
+                // to be reset between the queuing of a new message and its retrieval by javascript. To avoid this from happening,
+                // javascript always sends a "startup" exec upon loading a new page which causes all future exec calls to happen on the UI
+                // thread (and hence after onPageStarted) until there are no more pending exec calls remaining.
+                numPendingUiExecs.getAndIncrement();
+                ctx.getActivity().runOnUiThread(new Runnable() {
+                    public void run() {
+                        numPendingUiExecs.getAndDecrement();
+                    }
+                });
+                return true;
+            }
+            return false;
+        }
+    }
 }