cordova icon indicating copy to clipboard operation
cordova copied to clipboard

Ignoring exec() from previous page load.

Open safayildirim opened this issue 5 years ago • 10 comments

Bug Report

Problem

As you know, when orientation change on android platform, activity is killed and regenerated. Because of this, cordova platform is also regenerated. In this point, until cordova-android 9 version, all versions have executed the pluginInitialized method everytime when orientation changed but on cordova-android 9 it sometimes executes, sometimes not. When it is not called, log prints below lines.

gap_init called from restricted origin:
D/CordovaBridge: Ignoring exec() from previous page load.

After I searched for a solution on platform source code, I noticed that below code section is removed on cordova-android 9. When I readded lines on information section below, it works perfectly. Finally my question is that what issue prevent cordova calling pluginInitialize method every time when orientation changed?

I added some logs to CordovaBridge.java file. pluginInitialize method is not called because in below method jsMessageQueue.isBridgeEnabled() returns false.

private boolean verifySecret(String action, int bridgeSecret) throws IllegalAccessException {
    Log.d("TAG", action + "---" + jsMessageQueue.isBridgeEnabled());
    if (!jsMessageQueue.isBridgeEnabled()) { //This line returns false sometimes.
        if (bridgeSecret == -1) {
            LOG.d(LOG_TAG, action + " call made before bridge was enabled.");
        } else {
            LOG.d(LOG_TAG, "Ignoring " + action + " from previous page load.");
        }
        return false;
    }
    // Bridge secret wrong and bridge not due to it being from the previous page.
    if (expectedBridgeSecret < 0 || bridgeSecret != expectedBridgeSecret) {
        LOG.e(LOG_TAG, "Bridge access attempt with wrong secret token, possibly from malicious code. Disabling exec() bridge!");
        clearBridgeSecret();
        throw new IllegalAccessException();
    }
    return true;
}

When jsMessageQueue.isBridgeEnabled() returns false, no method on onDeviceReady event is called. These are all logs.

I/CordovaActivity: Apache Cordova native platform version 9.0.0 is starting
D/CordovaActivity: CordovaActivity.onCreate()
D/SystemWebViewEngine: CordovaWebView is running on device made by: HUAWEI
D/PluginManager: init()
D/CordovaWebViewImpl: >>> loadUrl(file:///android_asset/www/index.html)
D/ActivityThread: add activity client record, r= ActivityRecord{d6daa05 token=android.os.BinderProxy@c3ccfde {com.example.hmsappmessaging/com.example.application.MainActivity}} token= android.os.BinderProxy@c3ccfde
D/CordovaActivity: Started the activity.
W/cr_AwContents: Application attempted to call on a destroyed WebView
    java.lang.Throwable
        at org.chromium.android_webview.AwContents.p(chromium-TrichromeWebViewGoogle.aab-stable-428014133:2)
        at vM.loadingStateChanged(chromium-TrichromeWebViewGoogle.aab-stable-428014133:2)
        at android.os.MessageQueue.nativePollOnce(Native Method)
        at android.os.MessageQueue.next(MessageQueue.java:363)
        at android.os.Looper.loop(Looper.java:173)
        at android.app.ActivityThread.main(ActivityThread.java:8178)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1101)
D/HiTouch_PressGestureDetector: onAttached, package=com.example.hmsappmessaging, windowType=1, mHiTouchRestricted=false
D/mali_winsys: EGLint new_window_surface(egl_winsys_display *, void *, EGLSurface, EGLConfig, egl_winsys_surface **, EGLBoolean) returns 0x3000
D/Whitelist: java.lang.NullPointerException: Attempt to invoke interface method 'int java.lang.CharSequence.length()' on a null object reference
D/Whitelist: java.lang.NullPointerException: Attempt to invoke interface method 'int java.lang.CharSequence.length()' on a null object reference
E/CordovaBridge: gap_init called from restricted origin: 
D/TAG: setBridgeMode() called with: value = [-1]
D/CordovaWebViewImpl: onPageDidNavigate(file:///android_asset/www/index.html)
D/CordovaWebViewImpl: onPageFinished(file:///android_asset/www/index.html)
D/TAG: jsExec() called with: bridgeSecret = [0]
D/TAG: exec()---false
D/CordovaBridge: Ignoring exec() from previous page load.
D/TAG: jsExec() called with: bridgeSecret = [0]
D/TAG: exec()---false
D/CordovaBridge: Ignoring exec() from previous page load.
D/TAG: jsExec() called with: bridgeSecret = [0]
D/TAG: exec()---false
D/CordovaBridge: Ignoring exec() from previous page load.
I/chromium: [INFO:CONSOLE(23)] "Running [email protected]", source: file:///android_asset/www/js/index.js (23)
D/TAG: jsExec() called with: bridgeSecret = [0]
D/TAG: exec()---false
D/CordovaBridge: Ignoring exec() from previous page load.
D/TAG: jsExec() called with: bridgeSecret = [0
D/TAG: exec()---false
D/CordovaBridge: Ignoring exec() from previous page load.
D/TAG: jsExec() called with: bridgeSecret = [0]
D/TAG: exec()---false
D/CordovaBridge: Ignoring exec() from previous page load.
D/TAG: jsExec() called with: bridgeSecret = [0]
D/TAG: exec()---false
D/CordovaBridge: Ignoring exec() from previous page load.
D/mali_winsys: EGLint new_window_surface(egl_winsys_display *, void *, EGLSurface, EGLConfig, egl_winsys_surface **, EGLBoolean) returns 

What is expected to happen?

When orientation is changed, pluginInitialize method on native must be called everytime.

What does actually happen?

It is called sometimes, sometimes not.

Information

When I add below lines to the cordova.js file, everything works perfectly. These lines are removed from platform on cordova-android 9.0.0.

var utils = require('cordova/utils');
// Replace navigator before any modules are required(), to ensure it happens as soon as possible.
// We replace it so that properties that can't be clobbered can instead be overridden.
function replaceNavigator (origNavigator) {
    var CordovaNavigator = function () {};
    CordovaNavigator.prototype = origNavigator;
    var newNavigator = new CordovaNavigator();
    // This work-around really only applies to new APIs that are newer than Function.bind.
    // Without it, APIs such as getGamepads() break.
    if (CordovaNavigator.bind) {
        for (var key in origNavigator) {
            if (typeof origNavigator[key] === 'function') {
                newNavigator[key] = origNavigator[key].bind(origNavigator);
            } else {
                (function (k) {
                    utils.defineGetterSetter(newNavigator, key, function () {
                        return origNavigator[k];
                    });
                })(key);
            }
        }
    }
    return newNavigator;
}

if (window.navigator) {
    window.navigator = replaceNavigator(window.navigator);
}

Command or Code

Just change orientation.

Environment, Platform, Device

Windows 10 Cordova CLI 10.0.0 Cordova Android 9.0.0 Huawei P Smart Pro(probably all devices)

Version information

❯ cordova -v 10.0.0 ❯ cordova platform ls Installed platforms: android 9.0.0

Checklist

  • [X] I searched for existing GitHub issues
  • [X] I updated all Cordova tooling to most recent version
  • [X] I included all the necessary information above

safayildirim avatar Jan 18 '21 09:01 safayildirim

Thanks for reporting this issue and for the great information provided so far!

Apparently I am to blame for this: https://github.com/apache/cordova-js/pull/215. Now we just need to find out what exactly is happening and how to fix it.

Could it be that the JS-code you said you added back to cordova.js is missing the following lines:

if (window.navigator) {
    window.navigator = replaceNavigator(window.navigator);
}

Without calling replaceNavigator, nothing should be happening at all... :thinking:

raphinesse avatar Jan 26 '21 09:01 raphinesse

If you could provide a minimal app that lets us reproduce this issue, that would be very helpful.

raphinesse avatar Jan 26 '21 09:01 raphinesse

Thanks for reporting this issue and for the great information provided so far!

Apparently I am to blame for this: apache/cordova-js#215. Now we just need to find out what exactly is happening and how to fix it.

Could it be that the JS-code you said you added back to cordova.js is missing the following lines:

if (window.navigator) {
    window.navigator = replaceNavigator(window.navigator);
}

Without calling replaceNavigator, nothing should be happening at all... 🤔

Yes, I forgot to add these three last line while I was copying it :). Thank you for support.

safayildirim avatar Jan 26 '21 11:01 safayildirim

If you could provide a minimal app that lets us reproduce this issue, that would be very helpful.

https://github.com/Zeevac/myApp Here it is a demo application to show issue.When you changed orientation, It will print 'blabla' to the console sometimes. But it has to print it everytime. If you try enough times, you will see that exec calls will be ignored by cordova. But if you add lines I mentioned in first message to the cordova.js, it works perfectly.

safayildirim avatar Jan 26 '21 11:01 safayildirim

Hello @raphinesse. Is there any news?

safayildirim avatar Jan 29 '21 05:01 safayildirim

Thanks for your feedback. There is no progress on my side yet. I'll look into it when I find the time. Unfortunately spare time is scarce for me at the moment.

If you or someone else wants to further help moving this forward, here's the next steps I would take:

  • Find out how the navigator replacement code actually does anything. As described in the linked PR where I removed it, the assignment should not do anything per spec, as window.navigator is a read-only property. Thus replaceNavigator is probably modifying the origNavigator object in some non-obvious way.

  • Understand how the missing changes in the navigator object break the JS/native bridge

  • Figure out how we want to fix this issue. Adding the old code back should not be the first choice, as it is misleading and not strict-mode compliant and we are eventually trying to get there.

raphinesse avatar Feb 01 '21 09:02 raphinesse

Thanks for your feedback. There is no progress on my side yet. I'll look into it when I find the time. Unfortunately spare time is scarce for me at the moment.

If you or someone else wants to further help moving this forward, here's the next steps I would take:

* Find out how the navigator replacement code actually does anything.
  As described in the linked PR where I removed it, the assignment should not do anything per spec, as `window.navigator` is a read-only property. Thus `replaceNavigator` is probably modifying the `origNavigator` object in some non-obvious way.

* Understand how the missing changes in the navigator object break the JS/native bridge

* Figure out how we want to fix this issue.
  Adding the old code back should not be the first choice, as it is misleading and not strict-mode compliant and we are eventually trying to get there.

Any news? We are behind our schedule and it is very important to solve this issue.

safayildirim avatar Feb 24 '21 10:02 safayildirim

Unfortunately there's no news on my side. Like many other I work on Cordova only in my spare time, which is rather scarce at the moment.

If this issue blocks your product, you have at least three options:

  • Patch your local cordova.js (just re-insert the removed code) in a before_prepare hook
  • Try to move the progress of this issue along by working on the ToDos I posted above
  • Hope that someone else resolves this issue

I understand that the lack of progress must be frustrating, but there's not much I can do right now.

raphinesse avatar Feb 26 '21 07:02 raphinesse

any status? very annoying bug.

asv avatar Aug 26 '22 05:08 asv

I'm also seeing Ignoring exec() from previous page load. somewhat randomly. This is causing my app to essentially softlock because plugin code that I'm calling from javascript just isn't running.

terreng avatar Oct 19 '22 03:10 terreng