Merge release/20190525 into master.
diff --git a/android/sdk/src/main/java/org/apache/weex/WXEnvironment.java b/android/sdk/src/main/java/org/apache/weex/WXEnvironment.java
index dd467b3..7fc01e6 100644
--- a/android/sdk/src/main/java/org/apache/weex/WXEnvironment.java
+++ b/android/sdk/src/main/java/org/apache/weex/WXEnvironment.java
@@ -515,7 +515,7 @@
     return application.getApplicationContext().getCacheDir().getPath();
   }
 
-  public static boolean extractSo() {
+  public static String extractSo() {
     File sourceFile = new File(getApplication().getApplicationContext().getApplicationInfo().sourceDir);
     final String soDesPath = copySoDesDir();
     if (sourceFile.exists() && !TextUtils.isEmpty(soDesPath)) {
@@ -524,11 +524,11 @@
       } catch (IOException e) {
         WXLogUtils.e("extractSo error " + e.getMessage());
 //        e.printStackTrace();
-        return false;
+        return null;
       }
-      return true;
+      return soDesPath;
     }
-    return false;
+    return null;
   }
 
   private static String findIcuPath() {
@@ -593,9 +593,9 @@
       return soPath;
     } else {
       //unzip from apk file
-      final boolean success = extractSo();
-      if (success) {
-        return new File(getCacheDir(), realName).getAbsolutePath();
+      final String extractSoPath = extractSo();
+      if (!TextUtils.isEmpty(extractSoPath)) {
+        return new File(extractSoPath, realName).getAbsolutePath();
       }
     }
     return soPath;
diff --git a/android/sdk/src/main/java/org/apache/weex/WXSDKInstance.java b/android/sdk/src/main/java/org/apache/weex/WXSDKInstance.java
index 0ea578c..3779727 100644
--- a/android/sdk/src/main/java/org/apache/weex/WXSDKInstance.java
+++ b/android/sdk/src/main/java/org/apache/weex/WXSDKInstance.java
@@ -35,6 +35,7 @@
 import android.support.annotation.WorkerThread;
 import android.support.v4.util.ArrayMap;
 import android.text.TextUtils;
+import android.util.Log;
 import android.view.Menu;
 import android.view.View;
 import android.view.ViewGroup;
@@ -68,6 +69,8 @@
 import org.apache.weex.dom.WXEvent;
 import org.apache.weex.http.WXHttpUtil;
 import org.apache.weex.instance.InstanceOnFireEventInterceptor;
+import org.apache.weex.jsEngine.JSContext;
+import org.apache.weex.jsEngine.JSEngine;
 import org.apache.weex.layout.ContentBoxMeasurement;
 import org.apache.weex.performance.WXInstanceApm;
 import org.apache.weex.performance.WXStateRecord;
@@ -209,6 +212,9 @@
 
   private String mRenderType = RenderTypes.RENDER_TYPE_NATIVE;
 
+  private boolean mPageDirty = true;
+  private boolean mFixMultiThreadBug = false;
+
   public TimeCalculator mTimeCalculator;
   /**
    * Default Width And Viewport is 750,
@@ -527,9 +533,18 @@
     mApmForInstance = new WXInstanceApm(mInstanceId);
     WXSDKManager.getInstance().getAllInstanceMap().put(mInstanceId,this);
     mTimeCalculator = new TimeCalculator(this);
+    initFixMultiThreadFlag();
   }
 
 
+  private void initFixMultiThreadFlag() {
+    IWXConfigAdapter adapter = WXSDKManager.getInstance().getWxConfigAdapter();
+    if (adapter != null) {
+      String config = adapter.getConfig("android_weex_ext_config", "fixMultiThreadBug", "true");
+      mFixMultiThreadBug = Boolean.parseBoolean(config);
+    }
+  }
+
   /**
    * For unittest only.
    */
@@ -584,6 +599,7 @@
   }
 
   public void init(Context context) {
+    initFixMultiThreadFlag();
     RegisterCache.getInstance().idle(true);
     mContext = context;
     mContainerInfo = new HashMap<>(4);
@@ -2397,15 +2413,32 @@
   }
 
   public void OnVSync() {
-    boolean forceLayout = WXBridgeManager.getInstance().notifyLayout(getInstanceId());
-    if(forceLayout) {
+    if(mFixMultiThreadBug) {
+      if(!mPageDirty) {
+        return;
+      }
       WXBridgeManager.getInstance().post(new Runnable() {
         @Override
         public void run() {
-          WXBridgeManager.getInstance().forceLayout(getInstanceId());
+          boolean forceLayout = WXBridgeManager.getInstance().notifyLayout(getInstanceId());
+          if(forceLayout) {
+            WXBridgeManager.getInstance().forceLayout(getInstanceId());
+          }
         }
       });
+    } else  {
+      boolean forceLayout = WXBridgeManager.getInstance().notifyLayout(getInstanceId());
+      if(forceLayout) {
+        WXBridgeManager.getInstance().post(new Runnable() {
+          @Override
+          public void run() {
+            WXBridgeManager.getInstance().forceLayout(getInstanceId());
+          }
+        });
+      }
     }
+
+
   }
 
   public void addContentBoxMeasurement(long renderObjectPtr, ContentBoxMeasurement contentBoxMeasurement) {
@@ -2459,4 +2492,12 @@
     String result = adapter.getConfig("wxeagle", "disable_skip_framework_init", "false");
     return "true".equals(result);
   }
+
+  public boolean isPageDirty() {
+    return mPageDirty;
+  }
+
+  public void setPageDirty(boolean mPageDirty) {
+    this.mPageDirty = mPageDirty;
+  }
 }
diff --git a/android/sdk/src/main/java/org/apache/weex/bridge/WXBridge.java b/android/sdk/src/main/java/org/apache/weex/bridge/WXBridge.java
index ac02b42..05fd44d 100755
--- a/android/sdk/src/main/java/org/apache/weex/bridge/WXBridge.java
+++ b/android/sdk/src/main/java/org/apache/weex/bridge/WXBridge.java
@@ -934,4 +934,13 @@
     nativeSetDeviceDisplayOfPage(instanceId,width,height);
   }
 
+  @CalledByNative
+  @Override
+  public void setPageDirty(String instanceId, boolean dirty) {
+    WXSDKInstance sdkInstance = WXSDKManager.getInstance().getSDKInstance(instanceId);
+    if(sdkInstance != null) {
+      sdkInstance.setPageDirty(dirty);
+    }
+  }
+
 }
diff --git a/android/sdk/src/main/java/org/apache/weex/bridge/WXBridgeManager.java b/android/sdk/src/main/java/org/apache/weex/bridge/WXBridgeManager.java
index 18da955..c7873c3 100755
--- a/android/sdk/src/main/java/org/apache/weex/bridge/WXBridgeManager.java
+++ b/android/sdk/src/main/java/org/apache/weex/bridge/WXBridgeManager.java
@@ -61,6 +61,7 @@
 import org.apache.weex.common.WXRuntimeException;
 import org.apache.weex.common.WXThread;
 import org.apache.weex.dom.CSSShorthand;
+import org.apache.weex.jsEngine.JSEngine;
 import org.apache.weex.layout.ContentBoxMeasurement;
 import org.apache.weex.performance.WXInstanceApm;
 import org.apache.weex.performance.WXStateRecord;
@@ -381,6 +382,7 @@
     WXStateRecord.getInstance().recoreJsfmInitHistory("setJsfmInitFlag:"+init);
     if (init == true) {
       onJsFrameWorkInitSuccees();
+      JSEngine.getInstance().engineInitFinished();
     }
   }
 
@@ -909,7 +911,7 @@
         WXStateRecord.getInstance().onJSEngineReload(TextUtils.isEmpty(instanceId)?"null":instanceId);
          commitJscCrashAlarmMonitor(IWXUserTrackAdapter.JS_BRIDGE, WXErrorCode.WX_ERR_RELOAD_PAGE, "reboot jsc Engine", instanceId, url,extInfo);
       }
-
+      JSEngine.getInstance().engineCrashed();
       WXLogUtils.e("reInitCount:"+reInitCount);
 
       if (reInitCount > CRASHREINIT) {
diff --git a/android/sdk/src/main/java/org/apache/weex/common/IWXBridge.java b/android/sdk/src/main/java/org/apache/weex/common/IWXBridge.java
index 01858ea..f829306 100755
--- a/android/sdk/src/main/java/org/apache/weex/common/IWXBridge.java
+++ b/android/sdk/src/main/java/org/apache/weex/common/IWXBridge.java
@@ -230,5 +230,5 @@
 
   void setDeviceDisplayOfPage(String instanceId, float width, float height);
 
-
+  void setPageDirty(String instanceId, boolean dirty);
 }
diff --git a/android/sdk/src/main/java/org/apache/weex/jsEngine/CallBackCode.java b/android/sdk/src/main/java/org/apache/weex/jsEngine/CallBackCode.java
new file mode 100644
index 0000000..428c66c
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/jsEngine/CallBackCode.java
@@ -0,0 +1,32 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.weex.jsEngine;
+
+public class CallBackCode {
+
+    public static final CallBackCode ERROR_JSENGINE_CRASHED = new CallBackCode(-1, "js engine Crashed");
+    public static final CallBackCode JSENGINE_INIT_FINISH = new CallBackCode(1, "js Engine init finished");
+    public int code;
+    public String msg;
+
+    private CallBackCode(int code, String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/jsEngine/EnvCallback.java b/android/sdk/src/main/java/org/apache/weex/jsEngine/EnvCallback.java
new file mode 100644
index 0000000..37287ec
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/jsEngine/EnvCallback.java
@@ -0,0 +1,23 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.weex.jsEngine;
+
+public interface EnvCallback {
+    void error(CallBackCode code);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/jsEngine/JSBiz.java b/android/sdk/src/main/java/org/apache/weex/jsEngine/JSBiz.java
new file mode 100644
index 0000000..c0195c4
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/jsEngine/JSBiz.java
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.weex.jsEngine;
+
+public class JSBiz {
+    private String bizName;
+    private String bizId;
+
+    public JSBiz(String id, String name) {
+        this.bizId = id;
+        this.bizName = name;
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/jsEngine/JSContext.java b/android/sdk/src/main/java/org/apache/weex/jsEngine/JSContext.java
new file mode 100644
index 0000000..e2324d9
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/jsEngine/JSContext.java
@@ -0,0 +1,122 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.weex.jsEngine;
+
+import org.apache.weex.base.CalledByNative;
+import org.apache.weex.bridge.WXBridgeManager;
+import org.apache.weex.utils.WXLogUtils;
+
+import java.io.Serializable;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static org.apache.weex.jsEngine.JSEngine.mCreatedJSContext;
+
+public class JSContext implements Serializable {
+    private ConcurrentHashMap<String, JSFunction> funcMap = new ConcurrentHashMap<>();
+    //JSEnginePtrContainer
+    private long mNativeContextPtr = 0;
+
+    private JSException mExceptionTransfer = null;
+
+    protected JSContext() {
+        WXBridgeManager.getInstance().post(new Runnable() {
+            @Override
+            public void run() {
+                mNativeContextPtr = nativeCreateContext();
+                mCreatedJSContext.put(mNativeContextPtr, JSContext.this);
+            }
+        });
+    }
+
+    public void registerException(JSException e) {
+        mExceptionTransfer = e;
+    }
+
+    public void destroy() {
+        mCreatedJSContext.remove(mNativeContextPtr);
+        mExceptionTransfer = null;
+        WXBridgeManager.getInstance().post(new Runnable() {
+            @Override
+            public void run() {
+                if (mNativeContextPtr != 0) {
+                    long tmp = mNativeContextPtr;
+                    mNativeContextPtr = 0;
+                    nativeDestroyContext(tmp);
+                }
+            }
+        });
+    }
+
+    public void bindFunction(final String name, final JSFunction function) {
+        WXBridgeManager.getInstance().post(new Runnable() {
+            @Override
+            public void run() {
+                funcMap.put(name, function);
+                nativeBindFunc(mNativeContextPtr, name);
+            }
+        });
+    }
+
+    public void unBindFunction(final String name) {
+        WXBridgeManager.getInstance().post(new Runnable() {
+            @Override
+            public void run() {
+                funcMap.remove(name);
+                nativeUnBindFunc(mNativeContextPtr, name);
+            }
+        });
+    }
+
+    public void Eval(final String script) {
+        WXBridgeManager.getInstance().post(new Runnable() {
+            @Override
+            public void run() {
+                nativeExecJS(mNativeContextPtr, script);
+            }
+        });
+    }
+
+
+    @CalledByNative
+    public String Invoke(String name, String args) {
+        JSFunction jsFunction = funcMap.get(name);
+        if (jsFunction != null) {
+            WXLogUtils.d("jsEngine invoke " + name + " arg:" + args);
+            return jsFunction.invoke(args);
+        }
+        return "";
+    }
+
+    @CalledByNative
+    public void Exception(String exception) {
+        if (exception != null && mExceptionTransfer != null) {
+            this.mExceptionTransfer.exception(exception);
+        }
+    }
+
+    private native long nativeCreateContext();
+
+    private native void nativeDestroyContext(long ctxPtr);
+
+    private native void nativeBindFunc(long ctxPtr, String name);
+
+    private native void nativeUnBindFunc(long ctxPtr, String name);
+
+    private native void nativeExecJS(long ctxPtr, String script);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/jsEngine/JSEngine.java b/android/sdk/src/main/java/org/apache/weex/jsEngine/JSEngine.java
new file mode 100644
index 0000000..86b8d63
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/jsEngine/JSEngine.java
@@ -0,0 +1,99 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.weex.jsEngine;
+
+import android.support.annotation.Nullable;
+import android.util.Log;
+
+import org.apache.weex.WXSDKEngine;
+import org.apache.weex.utils.WXLogUtils;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static org.apache.weex.jsEngine.CallBackCode.ERROR_JSENGINE_CRASHED;
+import static org.apache.weex.jsEngine.CallBackCode.JSENGINE_INIT_FINISH;
+
+public class JSEngine implements Serializable {
+    private static JSEngine mJsEngine = null;
+
+    public static final ConcurrentHashMap<Long, JSContext> mCreatedJSContext = new ConcurrentHashMap<>();
+
+    private static final ConcurrentHashMap<JSBiz, EnvCallback> mEnvCallbacks = new ConcurrentHashMap<>();
+
+    private JSEngine() {
+    }
+
+    public static JSEngine getInstance() {
+        if (mJsEngine == null) {
+            synchronized (JSEngine.class) {
+                if (mJsEngine == null) {
+                    mJsEngine = new JSEngine();
+                }
+            }
+        }
+        return mJsEngine;
+    }
+
+    public void registerEnvCallback(JSBiz biz, EnvCallback e) {
+        if (biz == null || e == null) {
+            return;
+        }
+        mEnvCallbacks.put(biz, e);
+    }
+
+    public void unRegisterEnvCallback(JSBiz biz) {
+        if (biz == null) {
+            return;
+        }
+        mEnvCallbacks.remove(biz);
+    }
+
+
+    @Nullable
+    public JSContext createJSContext() {
+        if (!WXSDKEngine.isInitialized()) {
+            WXLogUtils.e("Create JSContext Failed because of weex has not been initialized");
+            return null;
+        }
+        return new JSContext();
+    }
+
+    public void engineInitFinished() {
+        for (Map.Entry<JSBiz, EnvCallback> next : mEnvCallbacks.entrySet()) {
+            next.getValue().error(JSENGINE_INIT_FINISH);
+        }
+    }
+
+    public void engineCrashed() {
+        for (Map.Entry<JSBiz, EnvCallback> next : mEnvCallbacks.entrySet()) {
+            next.getValue().error(ERROR_JSENGINE_CRASHED);
+        }
+
+        HashMap<Long, JSContext> map = new HashMap<>(mCreatedJSContext);
+        mCreatedJSContext.clear();
+        for (Map.Entry<Long, JSContext> next : map.entrySet()) {
+            JSContext value = next.getValue();
+            value.destroy();
+        }
+        map.clear();
+    }
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/jsEngine/JSException.java b/android/sdk/src/main/java/org/apache/weex/jsEngine/JSException.java
new file mode 100644
index 0000000..cefa998
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/jsEngine/JSException.java
@@ -0,0 +1,23 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.weex.jsEngine;
+
+public interface JSException {
+    void exception(String exception);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/jsEngine/JSFunction.java b/android/sdk/src/main/java/org/apache/weex/jsEngine/JSFunction.java
new file mode 100644
index 0000000..ea71105
--- /dev/null
+++ b/android/sdk/src/main/java/org/apache/weex/jsEngine/JSFunction.java
@@ -0,0 +1,23 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.weex.jsEngine;
+
+public interface JSFunction {
+    String invoke(String args);
+}
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/WXFileUtils.java b/android/sdk/src/main/java/org/apache/weex/utils/WXFileUtils.java
index feaec62..6b1e941 100644
--- a/android/sdk/src/main/java/org/apache/weex/utils/WXFileUtils.java
+++ b/android/sdk/src/main/java/org/apache/weex/utils/WXFileUtils.java
@@ -42,6 +42,8 @@
 import java.util.zip.ZipInputStream;
 import org.apache.weex.WXEnvironment;
 
+import static org.apache.weex.utils.WXSoInstallMgrSdk._cpuType;
+
 public class WXFileUtils {
 
   /**
@@ -213,7 +215,7 @@
       if(zipEntry.isDirectory()){
         continue;
       }
-      if(zipEntry.getName().contains("lib/armeabi/") &&
+      if(zipEntry.getName().contains("lib/" + _cpuType() + "/") &&
               (zipEntry.getName().contains("weex") || zipEntry.getName().equals(
                   String.format(Locale.ENGLISH, "lib%s.so", WXEnvironment.CORE_JSC_SO_NAME)))){
         String[] fileNames = zipEntry.getName().split("/");
diff --git a/android/sdk/src/main/java/org/apache/weex/utils/WXSoInstallMgrSdk.java b/android/sdk/src/main/java/org/apache/weex/utils/WXSoInstallMgrSdk.java
index e5140a7..a5da705 100644
--- a/android/sdk/src/main/java/org/apache/weex/utils/WXSoInstallMgrSdk.java
+++ b/android/sdk/src/main/java/org/apache/weex/utils/WXSoInstallMgrSdk.java
@@ -271,8 +271,8 @@
 
 
       if(!oldfile.exists()) {
-        WXEnvironment.extractSo();
-        oldfile = new File(copyPath, STARTUPSO);
+        String extractSoPath = WXEnvironment.extractSo();
+        oldfile = new File(extractSoPath, STARTUPSO);
       }
 
       if (oldfile.exists()) {
@@ -341,7 +341,7 @@
     }
   }
 
-  private static String _cpuType() {
+  public static String _cpuType() {
     if(TextUtils.isEmpty(mAbi)) {
       try {
         mAbi = Build.CPU_ABI;
diff --git a/android/settings.gradle b/android/settings.gradle
index 1baeb8d..a0d9042 100644
--- a/android/settings.gradle
+++ b/android/settings.gradle
@@ -18,18 +18,6 @@
  */
 rootProject.name = 'weex-project'
 
-def updateSubmodule(){
-    def command = "git submodule update --init --remote"
-    exec {
-        executable "bash"
-        args "-c", command
-    }
-}
-
-//if (new File('../.git').exists()) {
-//    updateSubmodule()
-//}
-
 include ":playground"
 project(":playground").projectDir=new File("../weex-playground/android/playground")
 
diff --git a/weex_core/Source/CMakeLists.txt b/weex_core/Source/CMakeLists.txt
index 508aaea..19135ca 100755
--- a/weex_core/Source/CMakeLists.txt
+++ b/weex_core/Source/CMakeLists.txt
@@ -149,6 +149,9 @@
     ./android/bridge/multi_process_and_so_initializer.cpp
     ./android/bridge/multi_so_initializer.cpp
     ./android/wrap/wml_bridge.cpp
+    ./android/wrap/js_context.cpp
+    ./android/wrap/js_processer.h
+    ./android/wrap/js_processer.cpp
     ./android/utils/cache_utils.cpp
     ./android/utils/params_utils.cpp
     ./android/utils/so_utils.cpp
diff --git a/weex_core/Source/android/bridge/platform/android_side.cpp b/weex_core/Source/android/bridge/platform/android_side.cpp
index 17057a7..7b97f8e 100755
--- a/weex_core/Source/android/bridge/platform/android_side.cpp
+++ b/weex_core/Source/android/bridge/platform/android_side.cpp
@@ -523,4 +523,11 @@
 
   return wx_bridge_->GetMeasureFunc(env, pageId, renderObjectPtr).Release();
 }
+void AndroidSide::SetPageDirty(const char *page_id, bool dirty) {
+  JNIEnv *env = base::android::AttachCurrentThread();
+  if (env == nullptr)
+    return;
+
+  wx_bridge_->SetPageDirty(env, page_id, dirty);
+}
 }  // namespace WeexCore
diff --git a/weex_core/Source/android/bridge/platform/android_side.h b/weex_core/Source/android/bridge/platform/android_side.h
index 550e50a..6e4093c 100755
--- a/weex_core/Source/android/bridge/platform/android_side.h
+++ b/weex_core/Source/android/bridge/platform/android_side.h
@@ -55,6 +55,7 @@
                            const char* method, const char* arguments,
                            int arguments_length, const char* options,
                            int options_length) override;
+  void SetPageDirty(const char* page_id, bool dirty) override ;
   void SetTimeout(const char* callback_id, const char* time) override;
   void NativeLog(const char* str_array) override;
   int UpdateFinish(const char* page_id, const char* task, int taskLen,
diff --git a/weex_core/Source/android/bridge/script/script_side_in_multi_process.cpp b/weex_core/Source/android/bridge/script/script_side_in_multi_process.cpp
index 36e853c..c858908 100644
--- a/weex_core/Source/android/bridge/script/script_side_in_multi_process.cpp
+++ b/weex_core/Source/android/bridge/script/script_side_in_multi_process.cpp
@@ -593,6 +593,26 @@
   return;
 }
 
+int64_t ScriptSideInMultiProcess::JsAction(long ctxContainer, int32_t jsActionType, const char *arg) {
+  try {
+    if(sender_ == nullptr) {
+      LOGE("UpdateGlobalConfig sender is null");
+      return 0;
+    }
+    std::unique_ptr<IPCSerializer> serializer(createIPCSerializer());
+    serializer->setMsg(static_cast<uint32_t>(IPCJSMsg::JSACTION));
+    serializer->add((int64_t) ctxContainer);
+    serializer->add(jsActionType);
+    serializer->add(arg, strlen(arg));
+    std::unique_ptr<IPCBuffer> buffer = serializer->finish();
+    std::unique_ptr<IPCResult> result = sender_->send(buffer.get());
+    return result->get<int64_t>();
+  } catch (IPCException &e) {
+    LOGE("%s", e.msg());
+  }
+  return 0;
+}
+
 }  // namespace script
 }  // namespace bridge
 }  // namespace WeexCore
diff --git a/weex_core/Source/android/bridge/script/script_side_in_multi_process.h b/weex_core/Source/android/bridge/script/script_side_in_multi_process.h
index b4793be..13568fb 100644
--- a/weex_core/Source/android/bridge/script/script_side_in_multi_process.h
+++ b/weex_core/Source/android/bridge/script/script_side_in_multi_process.h
@@ -74,6 +74,8 @@
 
   void SetLogType(const int logLevel, const bool isPerf) override;
 
+  virtual int64_t JsAction(long ctxContainer, int32_t jsActionType, const char *arg) override;
+
     ScriptSideInMultiProcess();
 
   virtual ~ScriptSideInMultiProcess();
diff --git a/weex_core/Source/android/bridge/script/script_side_in_multi_so.cpp b/weex_core/Source/android/bridge/script/script_side_in_multi_so.cpp
index 73c4e0c..b2d4580 100644
--- a/weex_core/Source/android/bridge/script/script_side_in_multi_so.cpp
+++ b/weex_core/Source/android/bridge/script/script_side_in_multi_so.cpp
@@ -190,7 +190,14 @@
     return;
   }
   return script_side_functions_->funcSetLogType(logLevel, isPerf);
+}
 
+int64_t ScriptSideInMultiSo::JsAction(long ctxContainer, int32_t jsActionType, const char *arg) {
+  if(script_side_functions_ == nullptr) {
+    LOGE("ScriptSideInMultiSo::UpdateInitFrameworkParams script_side_functions_ is null");
+    return 0;
+  }
+  return script_side_functions_->funcJSAction(ctxContainer, jsActionType, arg);
 }
 
 }  // namespace script
diff --git a/weex_core/Source/android/bridge/script/script_side_in_multi_so.h b/weex_core/Source/android/bridge/script/script_side_in_multi_so.h
index bd7faa0..d692a36 100644
--- a/weex_core/Source/android/bridge/script/script_side_in_multi_so.h
+++ b/weex_core/Source/android/bridge/script/script_side_in_multi_so.h
@@ -73,6 +73,8 @@
 
   void SetLogType(const int logLevel, const bool isPerf)override ;
 
+  int64_t JsAction(long ctxContainer, int32_t jsActionType, const char *arg) override ;
+
     ScriptSideInMultiSo();
 
   virtual ~ScriptSideInMultiSo();
diff --git a/weex_core/Source/android/bridge/script_bridge_in_multi_process.cpp b/weex_core/Source/android/bridge/script_bridge_in_multi_process.cpp
index 4a3dbff..459323b 100644
--- a/weex_core/Source/android/bridge/script_bridge_in_multi_process.cpp
+++ b/weex_core/Source/android/bridge/script_bridge_in_multi_process.cpp
@@ -16,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+#include "android/wrap/js_context.h"
+#include "android/wrap/js_processer.h"
+#include "base/android/jsengine_ptr_container.h"
 #include "base/log_defines.h"
 #include "script_bridge_in_multi_process.h"
 
@@ -32,9 +35,9 @@
 #include "base/android/jni/android_jni.h"
 #include "core/bridge/script/core_side_in_script.h"
 #include "core/manager/weex_core_manager.h"
-#include "third_party/IPC/IPCArguments.h"                                         
-#include "third_party/IPC/IPCHandler.h"                                           
-#include "third_party/IPC/IPCMessageJS.h" 
+#include "third_party/IPC/IPCArguments.h"
+#include "third_party/IPC/IPCHandler.h"
+#include "third_party/IPC/IPCMessageJS.h"
 #include "third_party/IPC/IPCResult.h"
 
 namespace WeexCore {
@@ -42,7 +45,7 @@
 static std::unique_ptr<IPCResult> HandleSetJSVersion(IPCArguments *arguments) {
   WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
       weex::base::MakeCopyable([version = std::unique_ptr<char[]>(
-                                    getArumentAsCStr(arguments, 0))] {
+          getArumentAsCStr(arguments, 0))] {
         WeexCoreManager::Instance()->script_bridge()->core_side()->SetJSVersion(
             version.get());
       }));
@@ -73,8 +76,9 @@
 
   WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
       weex::base::MakeCopyable([pageId = std::string(pageId == nullptr ? "" : pageId),
-                                funcS = std::string(func == nullptr ? "" : func),
-                                exceptionStr = std::string(exceptionInfo == nullptr ? "" : exceptionInfo)] {
+                                   funcS = std::string(func == nullptr ? "" : func),
+                                   exceptionStr =
+                                   std::string(exceptionInfo == nullptr ? "" : exceptionInfo)] {
         WeexCoreManager::Instance()
             ->script_bridge()
             ->core_side()
@@ -103,7 +107,7 @@
   auto arg2 = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 1));
   WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
       weex::base::MakeCopyable([callbackID = std::move(arg1),
-                                time = std::move(arg2)] {
+                                   time = std::move(arg2)] {
         WeexCoreManager::Instance()->script_bridge()->core_side()->SetTimeout(
             callbackID.get(), time.get());
       }));
@@ -134,8 +138,8 @@
   auto arg3 = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 2));
   WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
       weex::base::MakeCopyable([pageId = std::move(arg1),
-                                callbackID = std::move(arg2),
-                                time = std::move(arg3)] {
+                                   callbackID = std::move(arg2),
+                                   time = std::move(arg3)] {
         WeexCoreManager::Instance()->script_bridge()->core_side()->SetInterval(
             pageId.get(), callbackID.get(), time.get());
       }));
@@ -188,8 +192,8 @@
   WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
       weex::base::MakeCopyable(
           [pageId = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 0)),
-           task = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 1)),
-           callback = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 2))] {
+              task = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 1)),
+              callback = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 2))] {
             if (pageId != nullptr && task != nullptr) {
               WeexCoreManager::Instance()
                   ->script_bridge()
@@ -210,20 +214,19 @@
   weex::base::WaitableEvent event;
   char *retVal = nullptr;
   WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
-          weex::base::MakeCopyable(
-                  [pageId = std::move(arg1), t = type,
-                          args = std::move(arg3), returnResult = &retVal, e = &event] {
-                      *returnResult =
-                              const_cast<char *>(WeexCoreManager::Instance()
-                                      ->script_bridge()
-                                      ->core_side()
-                                      ->CallGCanvasLinkNative(pageId.get(),t,args.get()));
-                      e->Signal();
-                  }));
+      weex::base::MakeCopyable(
+          [pageId = std::move(arg1), t = type,
+              args = std::move(arg3), returnResult = &retVal, e = &event] {
+            *returnResult =
+                const_cast<char *>(WeexCoreManager::Instance()
+                    ->script_bridge()
+                    ->core_side()
+                    ->CallGCanvasLinkNative(pageId.get(), t, args.get()));
+            e->Signal();
+          }));
 
   event.Wait();
 
-
   JNIEnv *env = base::android::AttachCurrentThread();
 //  jstring jPageId = getArgumentAsJString(env, arguments, 0);
 //  const char *pageId = env->GetStringUTFChars(jPageId, NULL);
@@ -239,38 +242,37 @@
 //    retVal = WeexCoreManager::Instance()->script_bridge()->core_side()->CallGCanvasLinkNative(pageId, type,
 //                                                                                     args);
 
-      std::unique_ptr<IPCResult> ret = createVoidResult();
-      if (retVal) {
+  std::unique_ptr<IPCResult> ret = createVoidResult();
+  if (retVal) {
     jstring jDataStr = env->NewStringUTF(retVal);
     ret = std::unique_ptr<IPCResult>(
         new IPCStringResult(jstring2WeexString(env, jDataStr)));
     env->DeleteLocalRef(jDataStr);
     retVal = NULL;
-      }
+  }
 //      env->DeleteLocalRef(jPageId);
 //      env->DeleteLocalRef(val);
-      return ret;
+  return ret;
 }
 
 static std::unique_ptr<IPCResult> HandleT3DLinkNative(IPCArguments *arguments) {
 
-
   auto typeStr = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 0));
   int type = atoi(typeStr.get());
   auto arg1 = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 1));
   weex::base::WaitableEvent event;
   char *retVal = nullptr;
   WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
-          weex::base::MakeCopyable(
-                  [args = std::move(arg1), t = type,
-                          returnResult = &retVal, e = &event] {
-                      *returnResult =
-                              const_cast<char *>(WeexCoreManager::Instance()
-                                      ->script_bridge()
-                                      ->core_side()
-                                      ->CallT3DLinkNative(t, args.get()));
-                      e->Signal();
-                  }));
+      weex::base::MakeCopyable(
+          [args = std::move(arg1), t = type,
+              returnResult = &retVal, e = &event] {
+            *returnResult =
+                const_cast<char *>(WeexCoreManager::Instance()
+                    ->script_bridge()
+                    ->core_side()
+                    ->CallT3DLinkNative(t, args.get()));
+            e->Signal();
+          }));
 
   event.Wait();
 
@@ -316,9 +318,9 @@
   WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
       weex::base::MakeCopyable(
           [pageId = std::move(arg1), module = std::move(arg2),
-           method = std::move(arg3), argumentsData = std::move(arg4),
-           optionsData = std::move(arg5), length1 = argumentsDataLength,
-           length2 = optionsDataLength, result = &ret, e = &event] {
+              method = std::move(arg3), argumentsData = std::move(arg4),
+              optionsData = std::move(arg5), length1 = argumentsDataLength,
+              length2 = optionsDataLength, result = &ret, e = &event] {
             *result =
                 WeexCoreManager::Instance()
                     ->script_bridge()
@@ -334,24 +336,20 @@
    * when Wait timeout, ret is null.  switch case will crash.
    * make default value, to avoid the crash
    * */
-  if(ret.get() == nullptr){
-     ret = std::make_unique<ValueWithType>((int32_t)-1);
+  if (ret.get() == nullptr) {
+    ret = std::make_unique<ValueWithType>((int32_t) -1);
   }
 
   std::unique_ptr<IPCResult> result;
   switch (ret->type) {
-    case ParamsType::INT32:
-      result = createInt32Result(ret->value.int32Value);
+    case ParamsType::INT32:result = createInt32Result(ret->value.int32Value);
       break;
-    case ParamsType::INT64:
-      result = createInt64Result(ret->value.int64Value);
+    case ParamsType::INT64:result = createInt64Result(ret->value.int64Value);
       break;
     case ParamsType::FLOAT:
-    case ParamsType::DOUBLE:
-      result = createDoubleResult(ret->value.doubleValue);
+    case ParamsType::DOUBLE:result = createDoubleResult(ret->value.doubleValue);
       break;
-    case ParamsType::VOID:
-      result = createVoidResult();
+    case ParamsType::VOID:result = createVoidResult();
       break;
     case ParamsType::BYTEARRAY:
       result = createByteArrayResult(ret->value.byteArray->content,
@@ -365,8 +363,7 @@
       result =
           std::unique_ptr<IPCResult>(new IPCStringResult(ret->value.string));
       break;
-    default:
-      result = createVoidResult();
+    default:result = createVoidResult();
       break;
   }
   // Need to free
@@ -393,9 +390,9 @@
   WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
       weex::base::MakeCopyable(
           [pageId = std::move(arg1), ref = std::move(arg2),
-           method = std::move(arg3), argumentsData = std::move(arg4),
-           optionsData = std::move(arg5), l1 = argumentsDataLength,
-           l2 = optionsDataLength] {
+              method = std::move(arg3), argumentsData = std::move(arg4),
+              optionsData = std::move(arg5), l1 = argumentsDataLength,
+              l2 = optionsDataLength] {
             if (pageId != nullptr && ref != nullptr && method != nullptr) {
               WeexCoreManager::Instance()
                   ->script_bridge()
@@ -452,9 +449,9 @@
     IPCArguments *arguments) {
   WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
       weex::base::MakeCopyable([page_id = std::unique_ptr<char[]>(
-                                    getArumentAsCStr(arguments, 0)),
-                                dom_str = std::unique_ptr<char[]>(
-                                    getArumentAsCStr(arguments, 1))] {
+          getArumentAsCStr(arguments, 0)),
+                                   dom_str = std::unique_ptr<char[]>(
+                                       getArumentAsCStr(arguments, 1))] {
         WeexCoreManager::Instance()->script_bridge()->core_side()->CreateBody(
             page_id.get(), dom_str.get(), strlen(dom_str.get()));
       }));
@@ -480,9 +477,9 @@
   auto arg4 = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 3));
   WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
       weex::base::MakeCopyable([page_id = std::move(arg1),
-                                parent_ref = std::move(arg2),
-                                dom_str = std::move(arg3),
-                                index_cstr = std::move(arg4)] {
+                                   parent_ref = std::move(arg2),
+                                   dom_str = std::move(arg3),
+                                   index_cstr = std::move(arg4)] {
         const char *index_char =
             index_cstr.get() == nullptr ? "\0" : index_cstr.get();
         int index = atoi(index_char);
@@ -582,7 +579,7 @@
     return createInt32Result(0);
   WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
       weex::base::MakeCopyable([pageId = std::move(arg1), ref = std::move(arg2),
-                                parentRef = std::move(arg3), index = index] {
+                                   parentRef = std::move(arg3), index = index] {
         WeexCoreManager::Instance()->script_bridge()->core_side()->MoveElement(
             pageId.get(), ref.get(), parentRef.get(), index);
       }));
@@ -616,7 +613,7 @@
     return createInt32Result(0);
   WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
       weex::base::MakeCopyable([pageId = std::move(arg1), ref = std::move(arg2),
-                                event = std::move(arg3)] {
+                                   event = std::move(arg3)] {
         WeexCoreManager::Instance()->script_bridge()->core_side()->AddEvent(
             pageId.get(), ref.get(), event.get());
       }));
@@ -646,7 +643,7 @@
     return createInt32Result(0);
   WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
       weex::base::MakeCopyable([pageId = std::move(arg1), ref = std::move(arg2),
-                                event = std::move(arg3)] {
+                                   event = std::move(arg3)] {
         WeexCoreManager::Instance()->script_bridge()->core_side()->RemoveEvent(
             pageId.get(), ref.get(), event.get());
       }));
@@ -676,7 +673,7 @@
     return createInt32Result(0);
   WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
       weex::base::MakeCopyable([page_id = std::move(arg1),
-                                ref = std::move(arg2), data = std::move(arg3)] {
+                                   ref = std::move(arg2), data = std::move(arg3)] {
         if (page_id.get() == nullptr || ref.get() == nullptr ||
             data.get() == nullptr)
           return;
@@ -707,7 +704,7 @@
   auto arg3 = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 2));
   WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
       weex::base::MakeCopyable([page_id = std::move(arg1),
-                                ref = std::move(arg2), data = std::move(arg3)] {
+                                   ref = std::move(arg2), data = std::move(arg3)] {
         if (page_id.get() == nullptr || ref.get() == nullptr ||
             data.get() == nullptr)
           return;
@@ -761,9 +758,9 @@
   int result = -1;
   WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
       weex::base::MakeCopyable([pageId = std::move(arg1),
-                                task = std::move(arg2),
-                                callback = std::move(arg3), ret = &result,
-                                event = &event] {
+                                   task = std::move(arg2),
+                                   callback = std::move(arg3), ret = &result,
+                                   event = &event] {
         WeexCoreManager::Instance()->script_bridge()->core_side()->UpdateFinish(
             pageId.get(), task.get(), strlen(task.get()), callback.get(),
             strlen(callback.get()));
@@ -809,8 +806,8 @@
   auto arg3 = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 2));
   WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
       weex::base::MakeCopyable([pageId = std::move(arg1),
-                                task = std::move(arg2),
-                                callback = std::move(arg3)] {
+                                   task = std::move(arg2),
+                                   callback = std::move(arg3)] {
         WeexCoreManager::Instance()
             ->script_bridge()
             ->core_side()
@@ -853,12 +850,12 @@
   int i = getArumentAsCStrLen(arguments, 0);
   WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
       weex::base::MakeCopyable([jData = std::unique_ptr<char[]>(
-                                    getArumentAsCStr(arguments, 0)),
-              length = i,
-                                jVmId = std::unique_ptr<char[]>(
-                                    getArumentAsCStr(arguments, 1))] {
+          getArumentAsCStr(arguments, 0)),
+                                   length = i,
+                                   jVmId = std::unique_ptr<char[]>(
+                                       getArumentAsCStr(arguments, 1))] {
         WeexCoreManager::Instance()->script_bridge()->core_side()->PostMessage(
-            jVmId.get(), jData.get(),length);
+            jVmId.get(), jData.get(), length);
       }));
   return createInt32Result(static_cast<int32_t>(true));
 }
@@ -874,14 +871,14 @@
   WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
       weex::base::MakeCopyable(
           [clientId = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 0)),
-           dataS = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 1)),
-                  length = i,
-           callbackS = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 2)),
-           vmId = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 3))] {
+              dataS = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 1)),
+              length = i,
+              callbackS = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 2)),
+              vmId = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 3))] {
             WeexCoreManager::Instance()
                 ->script_bridge()
                 ->core_side()
-                ->DispatchMessage(clientId.get(), dataS.get(),length,
+                ->DispatchMessage(clientId.get(), dataS.get(), length,
                                   callbackS.get(), vmId.get());
           }));
   return createInt32Result(static_cast<int32_t>(true));
@@ -894,14 +891,14 @@
   WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
       weex::base::MakeCopyable(
           [clientId = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 0)),
-           dataS = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 1)),
-           vmId = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 2)),
-           length = i, e = &event, r = &result]() {
+              dataS = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 1)),
+              vmId = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 2)),
+              length = i, e = &event, r = &result]() {
             *r = WeexCoreManager::Instance()
-                     ->script_bridge()
-                     ->core_side()
-                     ->DispatchMessageSync(clientId.get(), dataS.get(), length,
-                                           vmId.get());
+                ->script_bridge()
+                ->core_side()
+                ->DispatchMessageSync(clientId.get(), dataS.get(), length,
+                                      vmId.get());
             e->Signal();
           }));
   event.Wait();
@@ -938,39 +935,84 @@
 }
 
 std::unique_ptr<IPCResult> UpdateComponentData(IPCArguments *arguments) {
-    auto arg1 = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 0));
-    auto arg2 = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 1));
-    auto arg3 = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 2));
-    WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
-        weex::base::MakeCopyable(
-            [page_id = std::move(arg1), cid = std::move(arg2), json_data = std::move(arg3)]() {
-              WeexCoreManager::Instance()
-                  ->script_bridge()
-                  ->core_side()
-                  ->UpdateComponentData(page_id.get(), cid.get(), json_data.get());
-            }));
-    return createInt32Result(static_cast<int32_t>(true));
+  auto arg1 = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 0));
+  auto arg2 = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 1));
+  auto arg3 = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 2));
+  WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
+      weex::base::MakeCopyable(
+          [page_id = std::move(arg1), cid = std::move(arg2), json_data = std::move(arg3)]() {
+            WeexCoreManager::Instance()
+                ->script_bridge()
+                ->core_side()
+                ->UpdateComponentData(page_id.get(), cid.get(), json_data.get());
+          }));
+  return createInt32Result(static_cast<int32_t>(true));
 }
 
-
-
-
 std::unique_ptr<IPCResult> HeartBeat(IPCArguments *arguments) {
   auto arg1 = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 0));
   WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
-          weex::base::MakeCopyable(
-                  [pageId = std::move(arg1)]() {
-                      if (pageId != nullptr) {
-                        LOGE("HeartBeat %s", pageId.get());
-                        WeexCoreManager::Instance()
-                                ->script_bridge()
-                                ->core_side()
-                                ->CallNative(pageId.get(), "HeartBeat", "HeartBeat");
-                      }
-                  }));
+      weex::base::MakeCopyable(
+          [pageId = std::move(arg1)]() {
+            if (pageId != nullptr) {
+              LOGE("HeartBeat %s", pageId.get());
+              WeexCoreManager::Instance()
+                  ->script_bridge()
+                  ->core_side()
+                  ->CallNative(pageId.get(), "HeartBeat", "HeartBeat");
+            }
+          }));
   return createInt32Result(static_cast<int32_t>(true));
 }
 
+std::unique_ptr<IPCResult> HandleJSActionCallBack(IPCArguments *arguments) {
+  char *string_ptr = getArumentAsCStr(arguments, 0);
+  char *str_type = getArumentAsCStr(arguments, 1);
+  int callBackType = atoi(str_type);
+  long ptr = atol(string_ptr);
+  if (ptr == 0) {
+    return createVoidResult();
+  }
+
+  if (callBackType == static_cast<uint32_t>(JSCALLBACK::INVOKE)) {
+    auto arg1 = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 2));
+    auto arg2 = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 3));
+    weex::base::WaitableEvent event;
+    char *ret = nullptr;
+    WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
+        weex::base::MakeCopyable(
+            [method = std::move(arg1), arg = std::move(arg2), result = &ret, e = &event,
+                cptr = ptr]() {
+              WeexCore::JSContext *ctx = android::JSContainerProcesser::ExtraJsContext(cptr);
+              if (ctx != nullptr) {
+                *result = ctx->JsActionCallBack(method.get(), arg.get());
+              } else {
+                LOGD_TAG("JSEngine",
+                         "ctx %ld has been Released, CallBack in WeexCore %s -> %s",
+                         cptr,
+                         method.get(),
+                         arg.get());
+              }
+              e->Signal();
+            }));
+    event.Wait();
+    if (ret != nullptr) {
+      return createCharArrayResult(ret);
+    }
+  } else if (callBackType == static_cast<uint32_t>(JSCALLBACK::EXCEPTION)) {
+    auto exception = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 2));
+    WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
+        weex::base::MakeCopyable(
+            [e = std::move(exception), cptr = ptr]() {
+              WeexCore::JSContext *ctx = android::JSContainerProcesser::ExtraJsContext(cptr);
+              if (ctx != nullptr) {
+                ctx->JsActionException(e.get());
+              }
+            }));
+  }
+  return createVoidResult();
+}
+
 std::unique_ptr<IPCResult> HandleLogDetail(IPCArguments *arguments) {
   auto arg1 = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 0));
   auto arg2 = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 1));
@@ -986,6 +1028,7 @@
                         ? ((int) (WeexCore::LogLevel::Debug)) : atoi(level_str.get());
             long line =
                 (line_ptr == nullptr || line_ptr.get() == nullptr) ? 0 : atol(line_ptr.get());
+
             weex::base::LogImplement::getLog()->log((WeexCore::LogLevel) level,
                                                     tag_ptr.get(),
                                                     file_ptr.get(),
@@ -1087,6 +1130,9 @@
                            HeartBeat);
   handler->registerHandler(static_cast<uint32_t>(IPCProxyMsg::POSTLOGDETAIL),
                            HandleLogDetail);
+
+  handler->registerHandler(static_cast<uint32_t>(IPCProxyMsg::JSACTIONCALLBACK),
+                           HandleJSActionCallBack);
 }
 
 }  // namespace WeexCore
diff --git a/weex_core/Source/android/jsengine/CMakeLists.txt b/weex_core/Source/android/jsengine/CMakeLists.txt
index fd61378..098e376 100644
--- a/weex_core/Source/android/jsengine/CMakeLists.txt
+++ b/weex_core/Source/android/jsengine/CMakeLists.txt
@@ -111,6 +111,8 @@
         object/weex_object_holder.cpp
         object/weex_simple_object.h
         object/weex_simple_object.cpp
+        object/js_action.h
+        object/js_action.cpp
 
         task/impl/init_framework_task.cpp
         task/impl/create_app_context_task.cpp
@@ -124,6 +126,7 @@
         task/impl/exe_js_services_task.cpp
         task/impl/exe_js_on_instance_task.cpp
         task/impl/exe_js_task.cpp
+        task/impl/js_action_task.cpp
         task/impl/take_heap_snapshot.cpp
         task/impl/native_timer_task.cpp
         task/impl/update_init_framework_params_task.cpp
diff --git a/weex_core/Source/android/jsengine/bridge/platform/platform_side_multi_process.cpp b/weex_core/Source/android/jsengine/bridge/platform/platform_side_multi_process.cpp
index 868dd21..e44ca52 100644
--- a/weex_core/Source/android/jsengine/bridge/platform/platform_side_multi_process.cpp
+++ b/weex_core/Source/android/jsengine/bridge/platform/platform_side_multi_process.cpp
@@ -675,6 +675,9 @@
   std::unique_ptr<IPCResult> result = sender->send(buffer.get());
   return result->get<int>();
 }
+void PlatformSideInMultiProcess::SetPageDirty(const char *page_id, bool dirty) {
+//do Nothing
+}
 
 int PlatformSideInMultiProcess::HasTransitionPros(
     const char *page_id, const char *ref,
diff --git a/weex_core/Source/android/jsengine/bridge/platform/platform_side_multi_process.h b/weex_core/Source/android/jsengine/bridge/platform/platform_side_multi_process.h
index 51b6d86..56ec729 100644
--- a/weex_core/Source/android/jsengine/bridge/platform/platform_side_multi_process.h
+++ b/weex_core/Source/android/jsengine/bridge/platform/platform_side_multi_process.h
@@ -60,6 +60,7 @@
                            const char* method, const char* arguments,
                            int arguments_length, const char* options,
                            int options_length) override;
+  void SetPageDirty(const char* page_id, bool dirty) override ;
   void SetTimeout(const char* callback_id, const char* time) override;
   void NativeLog(const char* str_array) override;
   int UpdateFinish(const char* page_id, const char* task, int taskLen,
diff --git a/weex_core/Source/android/jsengine/bridge/script/script_bridge_in_multi_process.cpp b/weex_core/Source/android/jsengine/bridge/script/script_bridge_in_multi_process.cpp
index fc4a1f8..e1b4971 100644
--- a/weex_core/Source/android/jsengine/bridge/script/script_bridge_in_multi_process.cpp
+++ b/weex_core/Source/android/jsengine/bridge/script/script_bridge_in_multi_process.cpp
@@ -224,6 +224,9 @@
 
                 handler->registerHandler(static_cast<uint32_t>(IPCJSMsg::SETLOGLEVEL),
                                          setLogType);
+
+                handler->registerHandler(static_cast<uint32_t>(IPCJSMsg::JSACTION),
+                                         JsAction);
             }
 
             std::unique_ptr<IPCResult> ScriptBridgeInMultiProcess::InitFramework(
@@ -531,6 +534,27 @@
             return createVoidResult();
         }
 
+        std::unique_ptr<IPCResult> ScriptBridgeInMultiProcess::JsAction(
+            IPCArguments *arguments) {
+            LOGD("ScriptBridgeInMultiProcess::JsAction");
+            const long ctxContainer = (long) (arguments->get<int64_t>(0));
+            const int32_t jsActionType = arguments->get<int32_t>(1);
+            
+            if(jsActionType == static_cast<int32_t>(JSACTION::CREATE)) {
+                LOGE_TAG("dyyLog","JSACTION::CREATE")
+                auto jsActionCtx = WeexEnv::getEnv()->createJSAction(ctxContainer);
+                return createInt64Result((long)(jsActionCtx));
+            } else if(jsActionType == static_cast<int32_t>(JSACTION::DESTROY)) {
+                LOGE_TAG("dyyLog", "adelete JSActionTask");
+                WeexEnv::getEnv()->destroyJSAction(ctxContainer);
+                return createInt32Result(static_cast<int32_t>(true));
+            }
+
+            const char *args = GetUTF8StringFromIPCArg(arguments, 2);
+            Instance()->script_side()->JsAction(ctxContainer, jsActionType, args);
+            return createInt32Result(static_cast<int32_t>(true));
+        }
+
 
             std::unique_ptr<IPCResult> ScriptBridgeInMultiProcess::TakeHeapSnapshot(
                     IPCArguments *arguments) {
diff --git a/weex_core/Source/android/jsengine/bridge/script/script_bridge_in_multi_process.h b/weex_core/Source/android/jsengine/bridge/script/script_bridge_in_multi_process.h
index 7190ef3..1112287 100644
--- a/weex_core/Source/android/jsengine/bridge/script/script_bridge_in_multi_process.h
+++ b/weex_core/Source/android/jsengine/bridge/script/script_bridge_in_multi_process.h
@@ -67,6 +67,7 @@
   IPC_METHOD(UpdateGlobalConfig)
   IPC_METHOD(UpdateInitFrameworkParams)
   IPC_METHOD(setLogType)
+  IPC_METHOD(JsAction)
 
  private:
   static ScriptBridgeInMultiProcess* g_instance;
diff --git a/weex_core/Source/android/jsengine/bridge/script/script_bridge_in_multi_so.cpp b/weex_core/Source/android/jsengine/bridge/script/script_bridge_in_multi_so.cpp
index 972cd16..da77aff 100644
--- a/weex_core/Source/android/jsengine/bridge/script/script_bridge_in_multi_so.cpp
+++ b/weex_core/Source/android/jsengine/bridge/script/script_bridge_in_multi_so.cpp
@@ -60,7 +60,7 @@
       ExecJSOnAppWithResult, CallJSOnAppContext, DestroyAppContext,
       ExecJSService,         ExecTimeCallback,   ExecJS,
       ExecJSWithResult,      ExecJSWithCallback, CreateInstance,     ExecJSOnInstance,
-      DestroyInstance,       UpdateGlobalConfig,  UpdateInitFrameworkParams, SetLogType};
+      DestroyInstance,       UpdateGlobalConfig,  UpdateInitFrameworkParams, SetLogType, JsAction};
   auto functions = (FunctionsExposedByJS *)malloc(sizeof(FunctionsExposedByJS));
   memset(functions, 0, sizeof(FunctionsExposedByJS));
   memcpy(functions, &temp, sizeof(FunctionsExposedByJS));
@@ -161,6 +161,10 @@
   return Instance()->script_side()->SetLogType(logLevel, isPerf);
 }
 
+int64_t ScriptBridgeInMultiSo::JsAction(long ctxContainer, int32_t jsActionType, const char *arg) {
+   return Instance()->script_side()->JsAction(ctxContainer, jsActionType, arg);
+}
+
 
 }  // namespace js
 }  // namespace bridge
diff --git a/weex_core/Source/android/jsengine/bridge/script/script_bridge_in_multi_so.h b/weex_core/Source/android/jsengine/bridge/script/script_bridge_in_multi_so.h
index 1700fee..bc1c268 100644
--- a/weex_core/Source/android/jsengine/bridge/script/script_bridge_in_multi_so.h
+++ b/weex_core/Source/android/jsengine/bridge/script/script_bridge_in_multi_so.h
@@ -79,6 +79,8 @@
 
   static void SetLogType(const int logLevel, const bool isPerf);
 
+  static int64_t JsAction(long ctxContainer, int32_t jsActionType, const char *arg);
+
  private:
   static ScriptBridgeInMultiSo *g_instance;
   static ScriptBridgeInMultiSo *Instance() {
diff --git a/weex_core/Source/android/jsengine/bridge/script/script_side_in_queue.cpp b/weex_core/Source/android/jsengine/bridge/script/script_side_in_queue.cpp
index 67054ea..c1f6d30 100644
--- a/weex_core/Source/android/jsengine/bridge/script/script_side_in_queue.cpp
+++ b/weex_core/Source/android/jsengine/bridge/script/script_side_in_queue.cpp
@@ -21,6 +21,7 @@
 //
 
 #include <object/weex_env.h>
+#include <task/impl/js_action_task.h>
 #include "script_side_in_queue.h"
 
 #include "android/jsengine/task/impl/init_framework_task.h"
@@ -134,13 +135,13 @@
   weexTaskQueue_->addTask(new ExeJsServicesTask(String::fromUTF8(source)));
   if (WeexEnv::getEnv()->enableBackupThread()) {
     ExeJsServicesTask *task = new ExeJsServicesTask(String::fromUTF8(source));
-    if(WeexEnv::getEnv()->can_m_cache_task_() && weexTaskQueue_bk_ == nullptr){
+    if (WeexEnv::getEnv()->can_m_cache_task_() && weexTaskQueue_bk_ == nullptr) {
       WeexEnv::getEnv()->m_task_cache_.push_back(task);
       LOGD("cache ExecJsService %d", WeexEnv::getEnv()->m_task_cache_.size());
     } else {
       weexTaskQueue_bk_->addTask(task);
     }
-    
+
   }
 
   return 1;
@@ -169,7 +170,7 @@
 
   if (instanceId == nullptr || strlen(instanceId) == 0) {
     if (WeexEnv::getEnv()->enableBackupThread()) {
-      if(WeexEnv::getEnv()->can_m_cache_task_() && weexTaskQueue_bk_ == nullptr){
+      if (WeexEnv::getEnv()->can_m_cache_task_() && weexTaskQueue_bk_ == nullptr) {
         WeexEnv::getEnv()->m_task_cache_.push_back(task->clone());
         LOGD("cache ExecJS %d", WeexEnv::getEnv()->m_task_cache_.size());
       } else {
@@ -238,13 +239,13 @@
     }
   }
 
-  if(backUpThread) {
+  if (backUpThread) {
     useBackUpWeexRuntime(instanceId);
   }
 
   auto string = String::fromUTF8(script);
   if (string.isEmpty()) {
-    LOG_TLOG("jsEngine","%s id CreateInstance's script is null", instanceId);
+    LOG_TLOG("jsEngine", "%s id CreateInstance's script is null", instanceId);
     return 0;
   }
   CreateInstanceTask *task = new CreateInstanceTask(String::fromUTF8(instanceId),
@@ -263,19 +264,19 @@
 }
 
 void ScriptSideInQueue::SetLogType(const int logLevel, const bool isPerf) {
-  LOGE("jsEngine setLog Level %d in Performance mode %s", logLevel, isPerf ? "true" :"false");
-  weex::base::LogImplement::getLog()->setPrintLevel((WeexCore::LogLevel)logLevel);
+  LOGE("jsEngine setLog Level %d in Performance mode %s", logLevel, isPerf ? "true" : "false");
+  weex::base::LogImplement::getLog()->setPrintLevel((WeexCore::LogLevel) logLevel);
   weex::base::LogImplement::getLog()->setPerfMode(isPerf);
 };
 
 std::unique_ptr<WeexJSResult> ScriptSideInQueue::ExecJSOnInstance(const char *instanceId,
-                                                                  const char *script,int type) {
-  LOGD("ScriptSideInQueue::ExecJSOnInstance type:%d",type);
+                                                                  const char *script, int type) {
+  LOGD("ScriptSideInQueue::ExecJSOnInstance type:%d", type);
   ExeJsOnInstanceTask *task = new ExeJsOnInstanceTask(String::fromUTF8(instanceId),
                                                       String::fromUTF8(script));
   taskQueue(instanceId, false)->addTask(task);
-  if (type == -1){
-      //don't need wait. just run js.
+  if (type == -1) {
+    //don't need wait. just run js.
     std::unique_ptr<WeexJSResult> returnResult;
     returnResult.reset(new WeexJSResult());
     LOGD("test-> return default result");
@@ -298,8 +299,8 @@
   LOGD("ScriptSideInQueue::UpdateGlobalConfig");
   weexTaskQueue_->addTask(new UpdateGlobalConfigTask(String::fromUTF8(config)));
   if (WeexEnv::getEnv()->enableBackupThread()) {
-    UpdateGlobalConfigTask* task = new UpdateGlobalConfigTask(String::fromUTF8(config));
-    if(WeexEnv::getEnv()->can_m_cache_task_() && weexTaskQueue_bk_ == nullptr){
+    UpdateGlobalConfigTask *task = new UpdateGlobalConfigTask(String::fromUTF8(config));
+    if (WeexEnv::getEnv()->can_m_cache_task_() && weexTaskQueue_bk_ == nullptr) {
       WeexEnv::getEnv()->m_task_cache_.push_back(task);
     } else {
       weexTaskQueue_bk_->addTask(task);
@@ -309,12 +310,14 @@
   return 1;
 }
 
-int ScriptSideInQueue::UpdateInitFrameworkParams(const std::string& key, const std::string& value, const std::string& desc){
- LOGD("ScriptSideInQueue::UpdateInitFrameworkParams");
+int ScriptSideInQueue::UpdateInitFrameworkParams(const std::string &key,
+                                                 const std::string &value,
+                                                 const std::string &desc) {
+  LOGD("ScriptSideInQueue::UpdateInitFrameworkParams");
   weexTaskQueue_->addTask(new UpdateInitFrameworkParamsTask(key, value, desc));
   if (WeexEnv::getEnv()->enableBackupThread()) {
-    UpdateInitFrameworkParamsTask* task = new UpdateInitFrameworkParamsTask(key, value, desc);
-    if(WeexEnv::getEnv()->can_m_cache_task_() && weexTaskQueue_bk_ == nullptr){
+    UpdateInitFrameworkParamsTask *task = new UpdateInitFrameworkParamsTask(key, value, desc);
+    if (WeexEnv::getEnv()->can_m_cache_task_() && weexTaskQueue_bk_ == nullptr) {
       WeexEnv::getEnv()->m_task_cache_.push_back(task);
     } else {
       weexTaskQueue_bk_->addTask(task);
@@ -324,7 +327,6 @@
   return 1;
 }
 
-
 void ScriptSideInQueue::useBackUpWeexRuntime(std::string id) {
   usingBackThreadId.push_back(id);
 }
@@ -356,7 +358,8 @@
     if (weexTaskQueue_bk_ == nullptr) {
       weexTaskQueue_bk_ = new WeexTaskQueue(weexTaskQueue_->isMultiProgress);
       WeexEnv::getEnv()->set_m_cache_task_(false);
-      for (std::deque<WeexTask *>::iterator it = WeexEnv::getEnv()->m_task_cache_.begin(); it < WeexEnv::getEnv()->m_task_cache_.end(); ++it) {
+      for (std::deque<WeexTask *>::iterator it = WeexEnv::getEnv()->m_task_cache_.begin();
+           it < WeexEnv::getEnv()->m_task_cache_.end(); ++it) {
         auto reference = *it;
         weexTaskQueue_bk_->addTask(std::move(reference));
       }
@@ -372,6 +375,11 @@
   }
   return weexTaskQueue_;
 }
+int64_t ScriptSideInQueue::JsAction(long ctxContainer, int32_t jsActionType, const char *arg) {
+  WeexTask *task = new JSActionTask(ctxContainer, jsActionType, arg);
+  weexTaskQueue_->addTask(task);
+  return 0;
+}
 }  // namespace js
 }  // namespace bridge
 
diff --git a/weex_core/Source/android/jsengine/bridge/script/script_side_in_queue.h b/weex_core/Source/android/jsengine/bridge/script/script_side_in_queue.h
index 2b7ecd1..d014cae 100644
--- a/weex_core/Source/android/jsengine/bridge/script/script_side_in_queue.h
+++ b/weex_core/Source/android/jsengine/bridge/script/script_side_in_queue.h
@@ -100,6 +100,8 @@
                 int UpdateInitFrameworkParams(const std::string& key, const std::string& value, const std::string& desc) override;
                 void SetLogType(const int logLevel, const bool isPerf) override;
 
+               int64_t JsAction(long ctxContainer, int32_t jsActionType, const char *arg) override ;
+
             private:
                 std::vector<std::string> usingBackThreadId;
 
diff --git a/weex_core/Source/android/jsengine/bridge/script/script_side_in_simple.cpp b/weex_core/Source/android/jsengine/bridge/script/script_side_in_simple.cpp
index aba1f51..916c6cc 100644
--- a/weex_core/Source/android/jsengine/bridge/script/script_side_in_simple.cpp
+++ b/weex_core/Source/android/jsengine/bridge/script/script_side_in_simple.cpp
@@ -146,8 +146,10 @@
 void ScriptSideInSimple::SetLogType(const int logLevel, const bool isPerf) {
   //do nothing
 }
+int64_t ScriptSideInSimple::JsAction(long ctxContainer, int32_t jsActionType, const char *arg) {
 
-
+  return 0;
+}
 
 }  // namespace js
 }  // namespace bridge
diff --git a/weex_core/Source/android/jsengine/bridge/script/script_side_in_simple.h b/weex_core/Source/android/jsengine/bridge/script/script_side_in_simple.h
index ebea353..1cbeedc 100644
--- a/weex_core/Source/android/jsengine/bridge/script/script_side_in_simple.h
+++ b/weex_core/Source/android/jsengine/bridge/script/script_side_in_simple.h
@@ -77,6 +77,9 @@
 
   void SetLogType(const int logLevel, const bool isPerf) override;
 
+  int64_t JsAction(long ctxContainer, int32_t jsActionType, const char *arg) override ;
+
+
   inline void set_runtime(WeexRuntime *runtime) { runtime_ = runtime; }
 
   ScriptSideInSimple() : runtime_(nullptr) {}
diff --git a/weex_core/Source/android/jsengine/object/js_action.cpp b/weex_core/Source/android/jsengine/object/js_action.cpp
new file mode 100644
index 0000000..e5356e6
--- /dev/null
+++ b/weex_core/Source/android/jsengine/object/js_action.cpp
@@ -0,0 +1,216 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+//
+// Created by 董亚运 on 2019-08-10.
+//
+#include "js_action.h"
+#include "weex_env.h"
+
+std::map<JSObjectRef, JSAction::jsFunction *>
+    JSAction::jsFunction::objMap = std::map<JSObjectRef, JSAction::jsFunction *>();
+std::mutex JSAction::jsFunction::mutex;
+
+std::map<std::string, JSAction::jsFunction *>
+    JSAction::functionMap = std::map<std::string, JSAction::jsFunction *>();
+void JSAction::EvaluateScript(std::string js) {
+  JSValueRef exception = nullptr;
+  JSEvaluateScript(m_ContextRef,
+                   JSStringCreateWithUTF8CString(js.c_str()),
+                   nullptr,
+                   nullptr,
+                   0,
+                   &exception);
+
+  if (exception != nullptr) {
+    if (JSValueIsNull(m_ContextRef, exception)) {
+      return;
+    }
+
+    JSStringRef str = JSValueToStringCopy(m_ContextRef, exception, nullptr);
+    std::string result;
+    size_t max_bytes = JSStringGetMaximumUTF8CStringSize(str);
+    result.resize(max_bytes);
+    size_t bytes_written = JSStringGetUTF8CString(str, &(result)[0], max_bytes);
+    if (max_bytes == 0) {
+      return;
+    }
+    result.resize(bytes_written - 1);
+    JSStringRelease(str);
+    std::unique_ptr<BackToWeexCoreQueue> &ptr = WeexEnv::getEnv()->m_back_to_weex_core_thread;
+    if (ptr == nullptr || ptr.get() == nullptr) {
+      return;
+    }
+    BackToWeexCoreQueue *bwq = ptr.get();
+
+    BackToWeexCoreQueue::IPCTask
+        *t = new BackToWeexCoreQueue::IPCTask(IPCProxyMsg::JSACTIONCALLBACK);
+
+    auto temp = std::to_string(this->m_ctxContainer);
+    t->addParams(temp.c_str(), temp.length());
+
+    temp = std::to_string(static_cast<int32_t >(JSCALLBACK::EXCEPTION));
+    t->addParams(temp.c_str(), temp.length());
+    t->addParams(result.c_str(), result.length());
+    bwq->addTask(t);
+  }
+}
+void JSAction::BindFunction(std::string name) {
+  JSAction::jsFunction *&pJsFunction = functionMap[name];
+  if (pJsFunction != nullptr) {
+    delete pJsFunction;
+  }
+  JSAction::jsFunction
+      *pFunction = new JSAction::jsFunction(name, m_ContextRef, this->m_ctxContainer);
+  functionMap[name] = pFunction;
+}
+
+JSValueRef JSAction::jsFunction::StaticFunctionCallback(JSContextRef ctx,
+                                                        JSObjectRef function,
+                                                        JSObjectRef thisObject,
+                                                        size_t argumentCount,
+                                                        JSValueRef const *arguments,
+                                                        JSValueRef *exception) {
+  jsFunction *&pFunction = objMap[function];
+  if (pFunction == nullptr) {
+    return nullptr;
+  }
+
+  std::unique_ptr<BackToWeexCoreQueue> &ptr = WeexEnv::getEnv()->m_back_to_weex_core_thread;
+  if (ptr == nullptr || ptr.get() == nullptr) {
+    return nullptr;
+  }
+
+  BackToWeexCoreQueue *bwq = ptr.get();
+
+  const char *name = pFunction->m_name_.c_str();
+
+  std::string result;
+  if (argumentCount > 0) {
+    JSValueRef const pValue = arguments[argumentCount - 1];
+    if (JSValueIsString(ctx, pValue)) {
+      JSStringRef pString = JSValueToStringCopy(ctx, pValue, nullptr);
+      size_t max_bytes = JSStringGetMaximumUTF8CStringSize(pString);
+      result.resize(max_bytes);
+      size_t bytes_written = JSStringGetUTF8CString(pString, &(result)[0], max_bytes);
+      if (max_bytes == 0) {
+        return nullptr;
+      }
+      result.resize(bytes_written - 1);
+      JSStringRelease(pString);
+    }
+  }
+
+  auto
+      *t = new BackToWeexCoreQueue::IPCTask(IPCProxyMsg::JSACTIONCALLBACK);
+
+  auto temp = std::to_string(pFunction->m_ctxContainer);
+  t->addParams(temp.c_str(), temp.length());
+  temp = std::to_string(static_cast<int32_t >(JSCALLBACK::INVOKE));
+  t->addParams(temp.c_str(), temp.length());
+  t->addParams(name, strlen(name));
+  t->addParams(result.c_str(), result.size());
+
+  LOGD_TAG("JSEngine","CallBack %s -> %s", name,result.c_str());
+
+  auto future = std::unique_ptr<BackToWeexCoreQueue::Future>(
+      new BackToWeexCoreQueue::Future());
+  t->set_future(future.get());
+  bwq->addTask(t);
+  std::unique_ptr<IPCResult> ipc_ret = future.get()->waitResult();
+
+  if (ipc_ret->getType() == IPCType::CHARARRAY) {
+    const char *string = ipc_ret.get()->getByteArrayContent();
+    if (string == nullptr) {
+      return JSValueMakeNull(ctx);
+    }
+    JSStringRef pJSString = JSStringCreateWithUTF8CString(string);
+    return JSValueMakeString(ctx, pJSString);
+  }
+  return JSValueMakeNull(ctx);
+}
+JSObjectRef JSAction::jsFunction::StaticConstructorCallback(JSContextRef ctx,
+                                                            JSObjectRef constructor,
+                                                            size_t argumentCount,
+                                                            JSValueRef const *arguments,
+                                                            JSValueRef *exception) {
+  return nullptr;
+}
+bool JSAction::jsFunction::StaticHasInstanceCallback(JSContextRef ctx,
+                                                     JSObjectRef constructor,
+                                                     JSValueRef possibleInstance,
+                                                     JSValueRef *exception) {
+  return false;
+}
+void JSAction::jsFunction::StaticFinalizeCallback(JSObjectRef object) {
+}
+JSValueRef JSAction::jsFunction::GetProperty(JSContextRef ctx,
+                                             JSObjectRef object,
+                                             JSStringRef propertyName,
+                                             JSValueRef *exception) {
+
+  std::string result;
+  size_t max_bytes = JSStringGetMaximumUTF8CStringSize(propertyName);
+  result.resize(max_bytes);
+  size_t bytes_written = JSStringGetUTF8CString(propertyName, &(result)[0], max_bytes);
+  if (max_bytes == 0) {
+    return nullptr;
+  }
+  result.resize(bytes_written - 1);
+
+  if (JSObjectHasProperty(ctx, object, propertyName)) {
+    return JSObjectGetProperty(ctx, object, propertyName, nullptr);
+  }
+
+  return JSValueMakeUndefined(ctx);
+}
+
+namespace {
+std::once_flag hostObjectClassOnceFlag;
+JSClassRef hostObjectClass{};
+} // namespace
+
+JSAction::jsFunction::jsFunction(std::string name, JSContextRef ctx,
+                                 long ctxContainer) {
+  ctxRef = ctx;
+  m_ctxContainer = ctxContainer;
+
+  std::call_once(hostObjectClassOnceFlag, []() {
+    JSClassDefinition definition = kJSClassDefinitionEmpty;
+    definition.version = 0;
+    definition.finalize = StaticFinalizeCallback;
+    definition.callAsFunction = StaticFunctionCallback;
+    definition.callAsConstructor = StaticConstructorCallback;
+    definition.hasInstance = StaticHasInstanceCallback;
+    hostObjectClass = JSClassCreate(&definition);
+  });
+
+  m_name_ = name;
+  JSStringRef jssName = JSStringCreateWithUTF8CString(name.c_str());
+  objRef = JSObjectMake(ctx, hostObjectClass, jssName);
+  JSValueProtect(ctx, objRef);
+  JSObjectSetProperty(ctx, JSContextGetGlobalObject(ctx), jssName, objRef, 0,
+                      nullptr);
+  mutex.lock();
+  objMap[objRef] = this;
+  mutex.unlock();
+}
+
+JSAction::jsFunction::~jsFunction() {
+
+}
diff --git a/weex_core/Source/android/jsengine/object/js_action.h b/weex_core/Source/android/jsengine/object/js_action.h
new file mode 100644
index 0000000..4e954ad
--- /dev/null
+++ b/weex_core/Source/android/jsengine/object/js_action.h
@@ -0,0 +1,113 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+//
+// Created by 董亚运 on 2019-08-10.
+//
+
+#ifndef WEEX_PROJECT_RUN_JS_NOT_FOR_WEEX_H
+#define WEEX_PROJECT_RUN_JS_NOT_FOR_WEEX_H
+
+#include <string>
+
+#ifdef USE_JS_RUNTIME
+#include "js_runtime/weex/task/back_to_weex_core_queue.h"
+#include "js_runtime/weex/object/weex_global_object_v2.h"
+#include "js_runtime/runtime/jsc/jsc_utils.h"
+#else
+#include "android/jsengine/task/back_to_weex_core_queue.h"
+#include "android/jsengine/object/weex_global_object.h"
+#include "android/jsengine/weex_jsc_utils.h"
+#endif
+
+class JSAction {
+ public:
+  JSAction(long ctxContainer) {
+    this->m_ctxContainer = ctxContainer;
+    JSGlobalContextRef pContext = JSGlobalContextCreateInGroup(nullptr, nullptr);
+    m_ContextRef = (JSContextRef) pContext;
+    m_globalObjectRef = JSContextGetGlobalObject(m_ContextRef);
+    JSValueProtect(m_ContextRef, m_globalObjectRef);
+  }
+
+  ~JSAction() {
+    if (m_ContextRef != nullptr) {
+      JSGlobalContextRelease((JSGlobalContextRef) m_ContextRef);
+    }
+  }
+
+  void EvaluateScript(std::string js);
+
+  void BindFunction(std::string name);
+
+  void UnBindFunction(std::string name) {
+    JSAction::jsFunction *&pFunction = functionMap[name];
+    if (pFunction != nullptr) {
+      delete pFunction;
+    }
+  }
+
+  class jsFunction {
+   public:
+    jsFunction(std::string name, JSContextRef ctx, long ctxContainer);
+
+    ~jsFunction();
+
+   private:
+    static JSValueRef StaticFunctionCallback(JSContextRef ctx,
+                                             JSObjectRef function,
+                                             JSObjectRef thisObject,
+                                             size_t argumentCount,
+                                             const JSValueRef arguments[],
+                                             JSValueRef *exception);
+    static JSObjectRef StaticConstructorCallback(JSContextRef ctx,
+                                                 JSObjectRef constructor,
+                                                 size_t argumentCount,
+                                                 const JSValueRef arguments[],
+                                                 JSValueRef *exception);
+    static bool StaticHasInstanceCallback(JSContextRef ctx, JSObjectRef constructor,
+                                          JSValueRef possibleInstance, JSValueRef *exception);
+
+    static void StaticFinalizeCallback(JSObjectRef object);
+
+    static JSValueRef GetProperty(JSContextRef ctx,
+                                  JSObjectRef object,
+                                  JSStringRef propertyName,
+                                  JSValueRef *exception);
+    std::string m_name_;
+
+    long m_ctxContainer;
+
+   private:
+    JSObjectRef objRef;
+    JSClassRef classRef;
+    JSContextRef ctxRef;
+
+    static std::map<JSObjectRef, JSAction::jsFunction *> objMap;
+    static std::mutex mutex;
+
+  };
+
+ private:
+  JSObjectRef m_globalObjectRef;
+  JSContextRef m_ContextRef;
+  long m_ctxContainer;
+  static std::map<std::string, JSAction::jsFunction *> functionMap;
+};
+
+#endif //WEEX_PROJECT_RUN_JS_NOT_FOR_WEEX_H
diff --git a/weex_core/Source/android/jsengine/object/weex_env.cpp b/weex_core/Source/android/jsengine/object/weex_env.cpp
index 355f29c..9cabe3b 100644
--- a/weex_core/Source/android/jsengine/object/weex_env.cpp
+++ b/weex_core/Source/android/jsengine/object/weex_env.cpp
@@ -105,9 +105,29 @@
                       const char *file,
                       unsigned long line,
                       const char *log) {
-
   if (scriptBridge_ == nullptr) {
     return false;
   }
   return scriptBridge_->core_side()->Log(level, tag, file, line, log);
 }
+void WeexEnv::destroyJSAction(long ctxContainer) {
+  if (ctxContainer == 0) {
+    return;
+  }
+  JSAction *pAction = m_jsActionMap[ctxContainer];
+  delete pAction;
+  pAction = nullptr;
+  m_jsActionMap.erase(ctxContainer);
+}
+JSAction *WeexEnv::createJSAction(long ctxContainer) {
+  auto jsAction = new JSAction(ctxContainer);
+  m_jsActionMap[ctxContainer] = jsAction;
+  return jsAction;
+}
+JSAction *WeexEnv::getJSAction(long ctxContainer) {
+  if (ctxContainer == 0) {
+    return nullptr;
+  }
+
+  return m_jsActionMap[ctxContainer];
+}
diff --git a/weex_core/Source/android/jsengine/object/weex_env.h b/weex_core/Source/android/jsengine/object/weex_env.h
index 053c727..aa3d7ae 100644
--- a/weex_core/Source/android/jsengine/object/weex_env.h
+++ b/weex_core/Source/android/jsengine/object/weex_env.h
@@ -34,11 +34,13 @@
 #include <android/jsengine/task/weex_task.h>
 #include "android/jsengine/task/back_to_weex_core_queue.h"
 #include "android/jsengine/task/timer_queue.h"
+#include "base/android/jsengine_ptr_container.h"
 #endif
 
 
 #include "android/jsengine/weex_ipc_server.h"
 #include "android/jsengine/weex_ipc_client.h"
+#include "js_action.h"
 
 class WeexEnv {
 
@@ -85,6 +87,11 @@
         WeexEnv::enableTrace_ = enableTrace_;
     }
 
+    JSAction* createJSAction(long ctxContainer);
+
+    JSAction* getJSAction(long ctxContainer);
+
+    void destroyJSAction(long ctxContainer);
 
     void initIPC();
 
@@ -141,12 +148,11 @@
  public:
   volatile bool can_m_cache_task_() const;
   void set_m_cache_task_(volatile bool m_cache_task_);
+
  private:
-
   ThreadLocker thread_locker_;
-
-   std::unique_ptr<crash_handler::CrashHandlerInfo> crashHandler;
-
+  std::unique_ptr<crash_handler::CrashHandlerInfo> crashHandler;
+  std::map<long, JSAction*> m_jsActionMap;
 };
 
 
diff --git a/weex_core/Source/android/jsengine/task/impl/js_action_task.cpp b/weex_core/Source/android/jsengine/task/impl/js_action_task.cpp
new file mode 100644
index 0000000..b8a156b
--- /dev/null
+++ b/weex_core/Source/android/jsengine/task/impl/js_action_task.cpp
@@ -0,0 +1,46 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+//
+// Created by 董亚运 on 2019-08-18.
+//
+
+#include "object/weex_env.h"
+#include "js_action_task.h"
+JSActionTask::JSActionTask(long ctxContainer, const int32_t jsActionType, const std::string arg)
+    : WeexTask("") {
+  this->m_ctxContainer = ctxContainer;
+  this->m_js_action_type = jsActionType;
+  this->m_arg = arg;
+}
+void JSActionTask::run(WeexRuntime *runtime) {
+  JSAction *pAction = WeexEnv::getEnv()->getJSAction(this->m_ctxContainer);
+  if(pAction == nullptr) {
+    return;
+  }
+  if (pAction) {
+    if (this->m_js_action_type == static_cast<int32_t>(JSACTION::BIND)) {
+      pAction->BindFunction(m_arg.c_str());
+    } else if (this->m_js_action_type == static_cast<int32_t>(JSACTION::UNBIND)) {
+      pAction->UnBindFunction(m_arg.c_str());
+    } else if (this->m_js_action_type == static_cast<int32_t>(JSACTION::EXEJS)) {
+      pAction->EvaluateScript(m_arg.c_str());
+    }
+  }
+
+}
diff --git a/weex_core/Source/android/jsengine/task/impl/js_action_task.h b/weex_core/Source/android/jsengine/task/impl/js_action_task.h
new file mode 100644
index 0000000..1289bf1
--- /dev/null
+++ b/weex_core/Source/android/jsengine/task/impl/js_action_task.h
@@ -0,0 +1,49 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+//
+// Created by 董亚运 on 2019-08-18.
+//
+
+#ifndef WEEX_PROJECT_JS_ACTION_TASK_H
+#define WEEX_PROJECT_JS_ACTION_TASK_H
+
+#include "android/jsengine/task/weex_task.h"
+
+class JSActionTask : public WeexTask {
+ public:
+  explicit JSActionTask(long ctxContainer, const int32_t jsActionType, const std::string arg);
+  void run(WeexRuntime *runtime) override;
+
+  std::string taskName() {
+    return "JSActionTask";
+  };
+
+
+  ~JSActionTask() {
+
+  }
+
+ private:
+  long m_ctxContainer;
+  int32_t m_js_action_type;
+  std::string m_arg;
+
+};
+
+#endif //WEEX_PROJECT_JS_ACTION_TASK_H
diff --git a/weex_core/Source/android/jsengine/weex_runtime.cpp b/weex_core/Source/android/jsengine/weex_runtime.cpp
index 5468834..e5a5192 100644
--- a/weex_core/Source/android/jsengine/weex_runtime.cpp
+++ b/weex_core/Source/android/jsengine/weex_runtime.cpp
@@ -20,6 +20,7 @@
 // Created by Darin on 28/04/2018.
 //
 
+#include <object/js_action.h>
 #include "android/jsengine/weex_runtime.h"
 
 #include "android/jsengine/bridge/script/script_bridge_in_multi_so.h"
@@ -607,15 +608,12 @@
                                 const String &extendsApi,
                                 std::vector<INIT_FRAMEWORK_PARAMS*>& params) {
     LOG_TLOG("jsEngine","id --> %s CreateInstance start", instanceId.utf8().data());
-
     JSGlobalObject *impl_globalObject = weexObjectHolder->m_globalObject.get();
     JSGlobalObject *globalObject;
     if (instanceId == "") {
         globalObject = impl_globalObject;
     } else {
-
       WeexGlobalObject * temp_object = nullptr;
-
       auto iterator = weexObjectHolder->m_jsInstanceGlobalObjectMap.find(instanceId.utf8().data());
       if (iterator != weexObjectHolder->m_jsInstanceGlobalObjectMap.end()) {
           temp_object = weexObjectHolder->m_jsInstanceGlobalObjectMap[instanceId.utf8().data()];
diff --git a/weex_core/Source/android/utils/jni_load.cc b/weex_core/Source/android/utils/jni_load.cc
index 624a1ae..8b4e13a 100644
--- a/weex_core/Source/android/utils/jni_load.cc
+++ b/weex_core/Source/android/utils/jni_load.cc
@@ -18,6 +18,7 @@
  */
 
 #include <jni.h>
+#include <android/wrap/js_context.h>
 #include "core/bridge/platform_bridge.h"
 #include "android/bridge/platform/android_bridge.h"
 #include "core/manager/weex_core_manager.h"
@@ -49,7 +50,8 @@
                 WeexCore::LogUtils::RegisterJNIUtils(env) &&
                 WeexCore::WXMap::RegisterJNIUtils(env) &&
                 WeexCore::HashSet::RegisterJNIUtils(env) &&
-                weex::core::network::DefaultRequestHandler::RegisterJNIUtils(env);
+                weex::core::network::DefaultRequestHandler::RegisterJNIUtils(env) &&
+                WeexCore::JSContext::RegisterJNIUtils(env);
   if (result) {
     WeexCore::SoUtils::Init(env);
     WeexCore::WMLBridge::RegisterJNIUtils(env);
diff --git a/weex_core/Source/android/wrap/js_context.cpp b/weex_core/Source/android/wrap/js_context.cpp
new file mode 100644
index 0000000..4226341
--- /dev/null
+++ b/weex_core/Source/android/wrap/js_context.cpp
@@ -0,0 +1,203 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+//
+// Created by 董亚运 on 2019-08-18.
+//
+
+#include <android/base/string/scoped_jstring_utf8.h>
+#include <android/base/string/string_utils.h>
+#include <IPCMessageJS.h>
+#include "js_context.h"
+#include "core/manager/weex_core_manager.h"
+#include "base/android/jniprebuild/jniheader/JSContext_jni.h"
+#include "js_processer.h"
+
+bool WeexCore::JSContext::RegisterJNIUtils(JNIEnv *env) {
+  return RegisterNativesImpl(env);
+}
+
+static intptr_t g_JSContext_JSActionException = 0;
+static void Java_JSContext_JSActionException(JNIEnv *env,
+                                             jobject obj,
+                                             jstring exception) {
+  jmethodID method_id =
+      base::android::GetMethod(
+          env, g_JSContext_clazz,
+          base::android::INSTANCE_METHOD,
+          "Exception",
+          "("
+          "Ljava/lang/String;"
+          ")"
+          "V",
+          &g_JSContext_JSActionException);
+  if (method_id == nullptr) {
+    return;
+  }
+  env->CallVoidMethod(obj, method_id, exception);
+  base::android::CheckException(env);
+}
+
+static intptr_t g_JSContext_JSActionCallBack = 0;
+static jstring Java_JSContext_JSActionCallBack(JNIEnv *env,
+                                               jobject obj,
+                                               jstring method,
+                                               jstring arg) {
+  jmethodID method_id =
+      base::android::GetMethod(
+          env, g_JSContext_clazz,
+          base::android::INSTANCE_METHOD,
+          "Invoke",
+          "("
+          "Ljava/lang/String;"
+          "Ljava/lang/String;"
+          ")"
+          "Ljava/lang/String;",
+          &g_JSContext_JSActionCallBack);
+  if (method_id == nullptr) {
+    return nullptr;
+  }
+  jstring ret = (jstring) env->CallObjectMethod(obj, method_id, method, arg);
+  base::android::CheckException(env);
+  return ret;
+}
+void JSContext::JsActionException(const char *exception) {
+  JNIEnv *env = ::base::android::AttachCurrentThread();
+  auto exception_str = base::android::ScopedLocalJavaRef<jstring>(
+      env, newJString(env, exception));
+  Java_JSContext_JSActionException(env, jni_object(), exception_str.Get());
+}
+char *JSContext::JsActionCallBack(const char *method, const char *args) {
+  JNIEnv *env = ::base::android::AttachCurrentThread();
+  auto method_str = base::android::ScopedLocalJavaRef<jstring>(
+      env, newJString(env, method));
+  auto args_str = base::android::ScopedLocalJavaRef<jstring>(
+      env, newJString(env, args));
+  jstring pJstring =
+      Java_JSContext_JSActionCallBack(env, jni_object(), method_str.Get(), args_str.Get());
+  if (pJstring != nullptr) {
+    ScopedJStringUTF8 func_str(env, pJstring);
+    char *m = new char[strlen(func_str.getChars()) + 1];
+    memset(m, 0, strlen(func_str.getChars()) + 1);
+    memcpy(m, func_str.getChars(), strlen(func_str.getChars()));
+    return const_cast<char *>(m);
+  } else {
+    return nullptr;
+  }
+}
+
+static jlong nativeCreateContext(JNIEnv *env, jobject jcaller) {
+  JNIEnv *env_tmp = ::base::android::AttachCurrentThread();
+
+  auto ptr_js_context = new WeexCore::JSContext();
+  ptr_js_context->Reset(env_tmp, jcaller);
+
+  auto ptr_container = android::JSContainerProcesser::CreateJSPtrContainer();
+  (*ptr_container)->m_ptr_weexcore_js_context = (long) ptr_js_context;
+  long long_ptr_ptr_container = (long) ptr_container;
+  int64_t jssPtr = WeexCoreManager::Instance()
+      ->getPlatformBridge()
+      ->core_side()->JsAction(long_ptr_ptr_container, static_cast<int32_t>(JSACTION::CREATE), "");
+  (*ptr_container)->m_ptr_jss_js_action = (long) jssPtr;
+  return long_ptr_ptr_container;
+}
+
+static void nativeDestroyContext(JNIEnv *env, jobject jcaller,
+                                 jlong ctxContainer) {
+  JNIEnv *env_tmp = ::base::android::AttachCurrentThread();
+
+  auto pContext = android::JSContainerProcesser::ExtraJsContext((long) ctxContainer);
+  if (pContext == nullptr) {
+    return;
+  }
+  if (!pContext->jni_object()) {
+    pContext->Reset(env_tmp, jcaller);
+  }
+  WeexCoreManager::Instance()->getPlatformBridge()->core_side()->JsAction(
+      (long) ctxContainer, static_cast<int32_t>(JSACTION::DESTROY), "");
+
+  android::JSContainerProcesser::DestroyJSPtrContainer((long) ctxContainer);
+
+}
+
+static void nativeBindFunc(JNIEnv *env, jobject jcaller,
+                           jlong ctxContainer,
+                           jstring func) {
+  JNIEnv *env_tmp = ::base::android::AttachCurrentThread();
+  ScopedJStringUTF8 func_str(env_tmp, func);
+
+  JSContext *pContext = android::JSContainerProcesser::ExtraJsContext((long) ctxContainer);
+  if (pContext == nullptr) {
+    return;
+  }
+
+  if (!pContext->jni_object()) {
+    pContext->Reset(env_tmp, jcaller);
+  }
+
+  WeexCoreManager::Instance()
+      ->getPlatformBridge()
+      ->core_side()->JsAction((long) ctxContainer,
+                              static_cast<int32_t >(JSACTION::BIND),
+                              func_str.getChars());
+}
+
+static void nativeUnBindFunc(JNIEnv *env, jobject jcaller,
+                             jlong ctxContainer,
+                             jstring func) {
+  JNIEnv *env_tmp = ::base::android::AttachCurrentThread();
+
+  JSContext *pContext = android::JSContainerProcesser::ExtraJsContext((long) ctxContainer);
+
+  if (pContext == nullptr) {
+    return;
+  }
+
+  if (!pContext->jni_object()) {
+    pContext->Reset(env_tmp, jcaller);
+  }
+
+  ScopedJStringUTF8 func_str(env_tmp, func);
+  WeexCoreManager::Instance()
+      ->getPlatformBridge()
+      ->core_side()->JsAction((long) ctxContainer,
+                              static_cast<int32_t >(JSACTION::UNBIND),
+                              func_str.getChars());
+}
+
+static void nativeExecJS(JNIEnv *env, jobject jcaller,
+                         jlong ctxContainer,
+                         jstring script) {
+  JNIEnv *env_tmp = ::base::android::AttachCurrentThread();
+  JSContext *pContext = android::JSContainerProcesser::ExtraJsContext((long) ctxContainer);
+
+  if (pContext == nullptr) {
+    return;
+  }
+
+  if (!pContext->jni_object()) {
+    pContext->Reset(env_tmp, jcaller);
+  }
+
+  ScopedJStringUTF8 func_str(env_tmp, script);
+  WeexCoreManager::Instance()
+      ->getPlatformBridge()
+      ->core_side()->JsAction((long) ctxContainer,
+                              static_cast<int32_t >(JSACTION::EXEJS),
+                              func_str.getChars());
+}
diff --git a/weex_core/Source/android/wrap/js_context.h b/weex_core/Source/android/wrap/js_context.h
new file mode 100644
index 0000000..9196b01
--- /dev/null
+++ b/weex_core/Source/android/wrap/js_context.h
@@ -0,0 +1,42 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+//
+// Created by 董亚运 on 2019-08-18.
+//
+
+#ifndef WEEX_PROJECT_JS_CONTEXT_H
+#define WEEX_PROJECT_JS_CONTEXT_H
+#include <jni.h>
+#include <base/android/jni/jni_object_wrap.h>
+#include "android/jsengine_ptr_container.h"
+namespace WeexCore {
+class JSContext : public JNIObjectWrap {
+ public:
+  explicit JSContext() {
+  };
+
+  ~JSContext() {
+  }
+
+  char *JsActionCallBack(const char *method, const char *args);
+  void JsActionException(const char *exception);
+  static bool RegisterJNIUtils(JNIEnv *env);
+};
+}
+#endif //WEEX_PROJECT_JS_CONTEXT_H
diff --git a/weex_core/Source/android/wrap/js_processer.cpp b/weex_core/Source/android/wrap/js_processer.cpp
new file mode 100644
index 0000000..c94752d
--- /dev/null
+++ b/weex_core/Source/android/wrap/js_processer.cpp
@@ -0,0 +1,116 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+//
+// Created by 董亚运 on 2019-10-23.
+//
+
+#include "js_processer.h"
+namespace android {
+
+std::vector<base::android::JSEnginePtrContainer **> JSContainerProcesser::m_saved_container;
+
+base::android::JSEnginePtrContainer **JSContainerProcesser::CreateJSPtrContainer() {
+  base::android::JSEnginePtrContainer **result = nullptr;
+  result = new base::android::JSEnginePtrContainer *[1];
+  auto ptr_container = new base::android::JSEnginePtrContainer();
+  *result = ptr_container;
+  LOGD_TAG("JSEngine",
+           "Create %ld",
+           (long) result);
+
+  m_saved_container.push_back(result);
+  return result;
+}
+void JSContainerProcesser::DestroyJSPtrContainer(long ctxContainer) {
+  if (ctxContainer == 0) {
+    return;
+  }
+
+  auto **realPtr = (base::android::JSEnginePtrContainer **) ctxContainer;
+  removeContainer(realPtr);
+
+  if (*realPtr == nullptr) {
+    return;
+  }
+
+  long contextPtr = (*realPtr)->m_ptr_weexcore_js_context;
+  if (contextPtr == 0) {
+    return;
+  }
+
+  LOGD_TAG("JSEngine",
+           "Destroy %ld",
+           (long) realPtr);
+
+  auto pContext = (WeexCore::JSContext *) contextPtr;
+  delete pContext;
+  pContext = nullptr;
+
+  delete (*realPtr);
+  *realPtr = nullptr;
+
+  delete realPtr;
+  realPtr = nullptr;
+}
+WeexCore::JSContext *JSContainerProcesser::ExtraJsContext(long ctxContainer) {
+  if (ctxContainer == 0) {
+    return nullptr;
+  }
+
+  auto **realPtr = (base::android::JSEnginePtrContainer **) ctxContainer;
+  if (*realPtr == nullptr) {
+    return nullptr;
+  }
+
+  if (!hasContainer(realPtr)) {
+    LOGD_TAG("JSEngine", "Do not Has Container");
+    return nullptr;
+  }
+
+  long contextPtr = (*realPtr)->m_ptr_weexcore_js_context;
+  if (contextPtr == 0) {
+    return nullptr;
+  }
+  auto jsContext = (WeexCore::JSContext *) contextPtr;
+  return jsContext;
+}
+
+bool JSContainerProcesser::hasContainer(base::android::JSEnginePtrContainer **ptr) {
+  auto it = findContainer(ptr);
+  return it != m_saved_container.end();
+}
+
+std::vector<base::android::JSEnginePtrContainer **>::iterator JSContainerProcesser::findContainer(
+    base::android::JSEnginePtrContainer **ptr) {
+  auto it = m_saved_container.begin();
+  while (it != m_saved_container.end()) {
+    if (*it == ptr) {
+      break;
+    }
+    it++;
+  }
+  return it;
+}
+void JSContainerProcesser::removeContainer(base::android::JSEnginePtrContainer **ptr) {
+  auto it = findContainer(ptr);
+  if (it != m_saved_container.end()) {
+    m_saved_container.erase(it);
+  }
+}
+}  // namespace android
\ No newline at end of file
diff --git a/weex_core/Source/android/wrap/js_processer.h b/weex_core/Source/android/wrap/js_processer.h
new file mode 100644
index 0000000..697e853
--- /dev/null
+++ b/weex_core/Source/android/wrap/js_processer.h
@@ -0,0 +1,48 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+//
+// Created by 董亚运 on 2019-10-23.
+//
+
+#ifndef WEEX_PROJECT_JS_PROCESSER_H
+#define WEEX_PROJECT_JS_PROCESSER_H
+
+#include <vector>
+#include "android/jsengine_ptr_container.h"
+#include "android/wrap/js_context.h"
+
+namespace android {
+class JSContainerProcesser {
+ public:
+  static base::android::JSEnginePtrContainer **CreateJSPtrContainer();
+  static void DestroyJSPtrContainer(long ctxContainer);
+  static WeexCore::JSContext *ExtraJsContext(long ctxContainer);
+
+ private:
+
+  static std::vector<base::android::JSEnginePtrContainer **>::iterator findContainer(base::android::JSEnginePtrContainer **ptr);
+  static bool hasContainer(base::android::JSEnginePtrContainer **ptr);
+  static void removeContainer(base::android::JSEnginePtrContainer **ptr);
+
+  static std::vector<base::android::JSEnginePtrContainer **> m_saved_container;
+
+};
+
+}  // namespace android
+#endif //WEEX_PROJECT_JS_PROCESSER_H
diff --git a/weex_core/Source/android/wrap/wx_bridge.cpp b/weex_core/Source/android/wrap/wx_bridge.cpp
index 21ba6fc..756db51 100755
--- a/weex_core/Source/android/wrap/wx_bridge.cpp
+++ b/weex_core/Source/android/wrap/wx_bridge.cpp
@@ -1171,6 +1171,15 @@
                                         jCallback.Get());
 }
 
+void WXBridge::SetPageDirty(JNIEnv *env, const char *page_id, bool dirty) {
+  auto jPageId = base::android::ScopedLocalJavaRef<jstring>(
+      env, env->NewStringUTF(page_id));
+  Java_WXBridge_setPageDirty(env,
+                             jni_object(),
+                             jPageId.Get(),
+                             static_cast<jboolean>(dirty ? 1 : 0));
+}
+
 void WXBridge::SetTimeout(JNIEnv* env, const char* callback_id,
                           const char* time) {
   auto jCallbackID = base::android::ScopedLocalJavaRef<jstring>(
diff --git a/weex_core/Source/android/wrap/wx_bridge.h b/weex_core/Source/android/wrap/wx_bridge.h
index 579bdb6..89c45a1 100755
--- a/weex_core/Source/android/wrap/wx_bridge.h
+++ b/weex_core/Source/android/wrap/wx_bridge.h
@@ -98,6 +98,7 @@
   int RenderSuccess(JNIEnv *env, const char *page_id);
   int UpdateFinish(JNIEnv *env, const char *page_id, const char *task,
                    const char *callback);
+  void SetPageDirty(JNIEnv* env, const char *page_id, bool dirty);
   void SetTimeout(JNIEnv *env, const char *callback_id, const char *time);
   void CallNativeComponent(JNIEnv *env, const char *page_id, const char *ref,
                            const char *method, const char *arguments,
diff --git a/weex_core/Source/base/CMakeLists.txt b/weex_core/Source/base/CMakeLists.txt
index 27e60bc..11088bd 100644
--- a/weex_core/Source/base/CMakeLists.txt
+++ b/weex_core/Source/base/CMakeLists.txt
@@ -91,6 +91,7 @@
         android/jni/jbytearray_ref.cpp
         android/jni/scoped_java_ref.h
         android/jni/scoped_java_ref.cpp
+        android/jsengine_ptr_container.h
         android/ThreadLocker.h
         android/ThreadLocker.cpp
        )
diff --git a/weex_core/Source/base/android/jniprebuild/jniheader/JSContext_jni.h b/weex_core/Source/base/android/jniprebuild/jniheader/JSContext_jni.h
new file mode 100644
index 0000000..18e03d7
--- /dev/null
+++ b/weex_core/Source/base/android/jniprebuild/jniheader/JSContext_jni.h
@@ -0,0 +1,97 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+//
+// Created by 董亚运 on 2019-08-18.
+//
+
+#ifndef WEEX_PROJECT_JSCONTEXT_JNI_H
+#define WEEX_PROJECT_JSCONTEXT_JNI_H
+#include <jni.h>
+#include "base/android/jni/android_jni.h"
+
+const char kJSContextClassPath[] = "org/apache/weex/jsEngine/JSContext";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_JSContext_clazz = NULL;
+
+/*
+   public native void nativeBindFunc(String name);
+
+    public native void nativeUnBindFunc(String name);
+
+    public native void nativeExecJS(String script);
+ */
+
+static jlong nativeCreateContext(JNIEnv *env, jobject jcaller);
+
+static void nativeDestroyContext(JNIEnv *env, jobject jcaller, jlong ctxContainer);
+
+static void nativeBindFunc(JNIEnv *env, jobject jcaller, jlong ctxContainer, jstring func);
+
+static void nativeUnBindFunc(JNIEnv *env, jobject jcaller, jlong ctxContainer, jstring func);
+
+static void nativeExecJS(JNIEnv *env, jobject jcaller, jlong ctxContainer, jstring script);
+
+static const JNINativeMethod kMethodsJSContext[] = {
+    {"nativeCreateContext",
+     "("
+     ")"
+     "J",
+     reinterpret_cast<void *>(nativeCreateContext)},
+    {"nativeDestroyContext",
+     "("
+     "J"
+     ")"
+     "V",
+     reinterpret_cast<void *>(nativeDestroyContext)},
+    {"nativeBindFunc",
+     "("
+     "J"
+     "Ljava/lang/String;"
+     ")"
+     "V",
+     reinterpret_cast<void *>(nativeBindFunc)},
+    {"nativeUnBindFunc",
+     "("
+     "J"
+     "Ljava/lang/String;"
+     ")"
+     "V",
+     reinterpret_cast<void *>(nativeUnBindFunc)},
+    {"nativeExecJS",
+     "("
+     "J"
+     "Ljava/lang/String;"
+     ")"
+     "V",
+     reinterpret_cast<void *>(nativeExecJS)}};
+
+static bool RegisterNativesImpl(JNIEnv *env) {
+  g_JSContext_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kJSContextClassPath).Get()));
+  const int kMethodsWXBridgeSize =
+      sizeof(kMethodsJSContext) / sizeof(kMethodsJSContext[0]);
+  if (env->RegisterNatives(g_JSContext_clazz, kMethodsJSContext,
+                           kMethodsWXBridgeSize) < 0) {
+    return false;
+  }
+
+  return true;
+}
+
+#endif  // WEEX_PROJECT_JSCONTEXT_JNI_H
diff --git a/weex_core/Source/base/android/jniprebuild/jniheader/WXBridge_jni.h b/weex_core/Source/base/android/jniprebuild/jniheader/WXBridge_jni.h
index b1fef6f..3b68c16 100755
--- a/weex_core/Source/base/android/jniprebuild/jniheader/WXBridge_jni.h
+++ b/weex_core/Source/base/android/jniprebuild/jniheader/WXBridge_jni.h
@@ -367,6 +367,30 @@
 
 }
 
+static intptr_t g_WXBridge_setPageDirty = 0;
+static void Java_WXBridge_setPageDirty(JNIEnv *env, jobject obj, jstring
+page_id, jboolean dirty) {
+  /* Must call RegisterNativesImpl()  */
+  //CHECK_CLAZZ(env, obj,
+  //    WXBridge_clazz(env));
+  jmethodID method_id =
+      base::android::GetMethod(
+          env, WXBridge_clazz(env),
+          base::android::INSTANCE_METHOD,
+          "setPageDirty",
+          "("
+          "Ljava/lang/String;"
+          "Z"
+          ")"
+          "V",
+          &g_WXBridge_setPageDirty);
+
+  env->CallVoidMethod(obj,
+                      method_id, page_id, dirty);
+  base::android::CheckException(env);
+}
+
+
 static intptr_t g_WXBridge_setTimeoutNative = 0;
 static void Java_WXBridge_setTimeoutNative(JNIEnv *env, jobject obj, jstring
 callbackId,
@@ -379,7 +403,6 @@
           env, WXBridge_clazz(env),
           base::android::INSTANCE_METHOD,
           "setTimeoutNative",
-
           "("
           "Ljava/lang/String;"
           "Ljava/lang/String;"
diff --git a/weex_core/Source/base/android/jsengine_ptr_container.h b/weex_core/Source/base/android/jsengine_ptr_container.h
new file mode 100644
index 0000000..e89a32a
--- /dev/null
+++ b/weex_core/Source/base/android/jsengine_ptr_container.h
@@ -0,0 +1,42 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#ifndef _JSENGINE_PTR_CONTAINER_H_
+#define _JSENGINE_PTR_CONTAINER_H_
+
+namespace base {
+namespace android {
+class JSEnginePtrContainer {
+ public:
+  JSEnginePtrContainer(){
+    this->m_ptr_jss_js_action = 0;
+    this->m_ptr_weexcore_js_context = 0;
+  };
+
+  ~JSEnginePtrContainer() {
+    this->m_ptr_jss_js_action = 0;
+    this->m_ptr_weexcore_js_context = 0;
+  }
+
+  long m_ptr_jss_js_action;
+  long m_ptr_weexcore_js_context;
+};
+}  // namespace android
+}  // namespace base
+
+#endif  //_JSENGINE_PTR_CONTAINER_H_
\ No newline at end of file
diff --git a/weex_core/Source/core/bridge/platform/core_side_in_platform.cpp b/weex_core/Source/core/bridge/platform/core_side_in_platform.cpp
index 31dcbf1..192b9bf 100644
--- a/weex_core/Source/core/bridge/platform/core_side_in_platform.cpp
+++ b/weex_core/Source/core/bridge/platform/core_side_in_platform.cpp
@@ -35,6 +35,8 @@
 #include "core/bridge/eagle_bridge.h"
 #include "third_party/json11/json11.hpp"
 #include "core/moniter/render_performance.h"
+#include "core_side_in_platform.h"
+
 #ifdef OS_ANDROID
 #include <android/utils/params_utils.h>
 #include <wson/wson.h>
@@ -645,5 +647,11 @@
     return page->getPerformance()->cssLayoutTime;
 }
 
+int64_t CoreSideInPlatform::JsAction(long ctxContainer, int32_t jsActionType, const char *arg) {
+  return WeexCoreManager::Instance()
+      ->script_bridge()
+      ->script_side()
+      ->JsAction(ctxContainer, jsActionType, arg);
+}
 
 }  // namespace WeexCore
diff --git a/weex_core/Source/core/bridge/platform/core_side_in_platform.h b/weex_core/Source/core/bridge/platform/core_side_in_platform.h
index c815d30..df894d0 100644
--- a/weex_core/Source/core/bridge/platform/core_side_in_platform.h
+++ b/weex_core/Source/core/bridge/platform/core_side_in_platform.h
@@ -115,6 +115,8 @@
   void SetLogType(const int logType, const bool isPerf) override;
   double GetLayoutTime(const char* instanceId) const override;
 
+  int64_t JsAction(long ctxContainer, int32_t jsActionType, const char *arg) override ;
+
 private:
   DISALLOW_COPY_AND_ASSIGN(CoreSideInPlatform);
 };
diff --git a/weex_core/Source/core/bridge/platform_bridge.h b/weex_core/Source/core/bridge/platform_bridge.h
index 1d6973a..39a4b80 100644
--- a/weex_core/Source/core/bridge/platform_bridge.h
+++ b/weex_core/Source/core/bridge/platform_bridge.h
@@ -140,6 +140,7 @@
     virtual int UpdateInitFrameworkParams(const std::string& key, const std::string& value, const std::string& desc) = 0;
 
     virtual void SetLogType(const int logType, const bool isPerf) = 0;
+    virtual int64_t JsAction(long ctxContainer, int32_t jsActionType, const char *arg) = 0;
 
     virtual double GetLayoutTime(const char* instanceId) const {return 0;}
 
@@ -191,6 +192,10 @@
     virtual std::unique_ptr<ValueWithType> RegisterPluginComponent(const char *name, const char *class_name, const char *version) = 0;
     virtual void PostTaskOnComponentThread(const weex::base::Closure closure) = 0;
 #endif
+#if OS_ANDROID
+    virtual void SetPageDirty(const char* page_id, bool dirty) = 0;
+#endif
+
     virtual void SetTimeout(const char* callback_id, const char* time) = 0;
     virtual void NativeLog(const char* str_array) = 0;
     virtual int UpdateFinish(const char* page_id, const char* task, int taskLen,
@@ -229,6 +234,8 @@
                        float bottom, float left, float right, float height,
                        float width, bool isRTL, int index) = 0;
 
+
+
     virtual int UpdateStyle(
         const char* pageId, const char* ref,
         std::vector<std::pair<std::string, std::string>>* style,
diff --git a/weex_core/Source/core/bridge/script_bridge.h b/weex_core/Source/core/bridge/script_bridge.h
index bcb43e0..46aa64c 100644
--- a/weex_core/Source/core/bridge/script_bridge.h
+++ b/weex_core/Source/core/bridge/script_bridge.h
@@ -160,6 +160,8 @@
 
     virtual void SetLogType(const int logLevel, const bool isPerf) = 0;
 
+    virtual int64_t JsAction(long ctxContainer, int32_t jsActionType, const char *arg) = 0;
+
     inline ScriptBridge *bridge() { return bridge_; }
 
 
diff --git a/weex_core/Source/core/render/page/render_page.cpp b/weex_core/Source/core/render/page/render_page.cpp
index 7560848..79a3644 100755
--- a/weex_core/Source/core/render/page/render_page.cpp
+++ b/weex_core/Source/core/render/page/render_page.cpp
@@ -804,5 +804,13 @@
   Batch();
   return true;
 }
-  
+void RenderPage::set_is_dirty(bool dirty) {
+    this->is_dirty_.store(dirty);
+#if OS_ANDROID
+    WeexCore::WeexCoreManager::Instance()->
+        getPlatformBridge()->
+        platform_side()->SetPageDirty(this->page_id().c_str(),dirty);
+#endif
+}
+
 }  // namespace WeexCore
diff --git a/weex_core/Source/core/render/page/render_page.h b/weex_core/Source/core/render/page/render_page.h
index 10f67b4..2f060be 100644
--- a/weex_core/Source/core/render/page/render_page.h
+++ b/weex_core/Source/core/render/page/render_page.h
@@ -142,7 +142,7 @@
 
   inline bool is_dirty() { return this->is_dirty_.load(); }
 
-  inline void set_is_dirty(bool dirty) { this->is_dirty_.store(dirty); }
+  void set_is_dirty(bool dirty);
 
   inline void set_is_render_container_width_wrap_content(bool wrap) {
     this->is_render_container_width_wrap_content_.store(wrap);
diff --git a/weex_core/Source/include/WeexApiHeader.h b/weex_core/Source/include/WeexApiHeader.h
index 759afa6..5b31734 100644
--- a/weex_core/Source/include/WeexApiHeader.h
+++ b/weex_core/Source/include/WeexApiHeader.h
@@ -267,6 +267,7 @@
 typedef int (*FuncUpdateInitFrameworkParams)(const std::string& key, const std::string& value, const std::string& desc);
 
 typedef void (*FuncSetLogType)(const int logLevel, const bool isPerf);
+typedef int64_t (*FuncJSAction)(long ctxContainer, int32_t jsAction, const char *arg);
 
 typedef struct FunctionsExposedByJS {
     FuncInitFramework funcInitFramework;
@@ -286,6 +287,7 @@
     FuncUpdateGlobalConfig funcUpdateGlobalConfig;
     FuncUpdateInitFrameworkParams funcUpdateInitFrameworkParams;
     FuncSetLogType funcSetLogType;
+    FuncJSAction funcJSAction;
 } FunctionsExposedByJS;
 
 
diff --git a/weex_core/Source/js_runtime/CMakeLists.txt b/weex_core/Source/js_runtime/CMakeLists.txt
index 139209a..b62b59b 100644
--- a/weex_core/Source/js_runtime/CMakeLists.txt
+++ b/weex_core/Source/js_runtime/CMakeLists.txt
@@ -168,6 +168,8 @@
         ${WEEX_CORE_SOURCE_DIR}/android/jsengine/object/args.cpp
         ${WEEX_CORE_SOURCE_DIR}/android/jsengine/object/weex_env.h
         ${WEEX_CORE_SOURCE_DIR}/android/jsengine/object/weex_env.cpp
+        ${WEEX_CORE_SOURCE_DIR}/android/jsengine/object/js_action.h
+        ${WEEX_CORE_SOURCE_DIR}/android/jsengine/object/js_action.cpp
 
         weex/task/impl/init_framework_task.cpp
         weex/task/impl/create_app_context_task.cpp
@@ -181,6 +183,7 @@
         weex/task/impl/exe_js_services_task.cpp
         weex/task/impl/exe_js_on_instance_task.cpp
         weex/task/impl/exe_js_task.cpp
+        weex/task/impl/js_action_task.cpp
         weex/task/impl/take_heap_snapshot.cpp
         weex/task/impl/native_timer_task.cpp
         weex/task/impl/update_init_framework_params_task.cpp
diff --git a/weex_core/Source/js_runtime/weex/bridge/script/script_side_in_queue.cpp b/weex_core/Source/js_runtime/weex/bridge/script/script_side_in_queue.cpp
index 2b71b9f..483eb4e 100644
--- a/weex_core/Source/js_runtime/weex/bridge/script/script_side_in_queue.cpp
+++ b/weex_core/Source/js_runtime/weex/bridge/script/script_side_in_queue.cpp
@@ -38,6 +38,7 @@
 #include "js_runtime/weex/task/impl/exe_js_task.h"
 #include "js_runtime/weex/task/impl/take_heap_snapshot.h"
 #include "js_runtime/weex/task/impl/native_timer_task.h"
+#include "js_runtime/weex/task/impl/js_action_task.h"
 
 namespace weex {
 namespace bridge {
@@ -357,6 +358,13 @@
   }
   return weexTaskQueue_;
 }
+
+int64_t ScriptSideInQueue::JsAction(long ctxContainer, int32_t jsActionType, const char *arg) {
+  WeexTask *task = new JSActionTask(ctxContainer, jsActionType, arg);
+  weexTaskQueue_->addTask(task);
+  return 0;
+}
+
 }  // namespace js
 }  // namespace bridge
 
diff --git a/weex_core/Source/js_runtime/weex/bridge/script/script_side_in_simple.cpp b/weex_core/Source/js_runtime/weex/bridge/script/script_side_in_simple.cpp
index fee2931..5a41f66 100644
--- a/weex_core/Source/js_runtime/weex/bridge/script/script_side_in_simple.cpp
+++ b/weex_core/Source/js_runtime/weex/bridge/script/script_side_in_simple.cpp
@@ -147,6 +147,9 @@
   //do nothing
 }
 
+int64_t ScriptSideInSimple::JsAction(long ctxContainer, int32_t jsActionType, const char *arg) {
+  return 0;
+}
 
 }  // namespace js
 }  // namespace bridge
diff --git a/weex_core/Source/js_runtime/weex/task/impl/js_action_task.cpp b/weex_core/Source/js_runtime/weex/task/impl/js_action_task.cpp
new file mode 100644
index 0000000..7ebaf9c
--- /dev/null
+++ b/weex_core/Source/js_runtime/weex/task/impl/js_action_task.cpp
@@ -0,0 +1,46 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+//
+// Created by 董亚运 on 2019-08-18.
+//
+
+#include "android/jsengine/object/weex_env.h"
+#include "js_action_task.h"
+JSActionTask::JSActionTask(long ctxContainer, const int32_t jsActionType, const std::string arg)
+    : WeexTask("") {
+  this->m_ctxContainer = ctxContainer;
+  this->m_js_action_type = jsActionType;
+  this->m_arg = arg;
+}
+void JSActionTask::run(WeexRuntime *runtime) {
+  JSAction *pAction = WeexEnv::getEnv()->getJSAction(this->m_ctxContainer);
+  if(pAction == nullptr) {
+    return;
+  }
+  if (pAction) {
+    if (this->m_js_action_type == static_cast<int32_t>(JSACTION::BIND)) {
+      pAction->BindFunction(m_arg.c_str());
+    } else if (this->m_js_action_type == static_cast<int32_t>(JSACTION::UNBIND)) {
+      pAction->UnBindFunction(m_arg.c_str());
+    } else if (this->m_js_action_type == static_cast<int32_t>(JSACTION::EXEJS)) {
+      pAction->EvaluateScript(m_arg.c_str());
+    }
+  }
+
+}
diff --git a/weex_core/Source/js_runtime/weex/task/impl/js_action_task.h b/weex_core/Source/js_runtime/weex/task/impl/js_action_task.h
new file mode 100644
index 0000000..8b30b6b
--- /dev/null
+++ b/weex_core/Source/js_runtime/weex/task/impl/js_action_task.h
@@ -0,0 +1,49 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+//
+// Created by 董亚运 on 2019-08-18.
+//
+
+#ifndef WEEX_PROJECT_JS_ACTION_TASK_H
+#define WEEX_PROJECT_JS_ACTION_TASK_H
+
+#include "js_runtime/weex/task/weex_task.h"
+
+class JSActionTask : public WeexTask {
+ public:
+  explicit JSActionTask(long ctxContainer, const int32_t jsActionType, const std::string arg);
+  void run(WeexRuntime *runtime) override;
+
+  std::string taskName() {
+    return "JSActionTask";
+  };
+
+
+  ~JSActionTask() {
+
+  }
+
+ private:
+  long m_ctxContainer;
+  int32_t m_js_action_type;
+  std::string m_arg;
+
+};
+
+#endif //WEEX_PROJECT_JS_ACTION_TASK_H
diff --git a/weex_core/Source/third_party/IPC/IPCMessageJS.h b/weex_core/Source/third_party/IPC/IPCMessageJS.h
index af7cc0b..2c9fc70 100644
--- a/weex_core/Source/third_party/IPC/IPCMessageJS.h
+++ b/weex_core/Source/third_party/IPC/IPCMessageJS.h
@@ -45,6 +45,7 @@
     CALLJSONAPPCONTEXT,
     DESTORYAPPCONTEXT,
     SETLOGLEVEL,
+    JSACTION,
 };
 
 // Message from Script to Core in ScriptBridge
@@ -78,9 +79,23 @@
     UPDATECOMPONENTDATA,
     HEARTBEAT,
     POSTLOGDETAIL,
+    JSACTIONCALLBACK,
 };
 // Message from Script to Core in ScriptBridge
 
+enum class JSACTION {
+  CREATE,
+  DESTROY,
+  BIND,
+  UNBIND,
+  EXEJS,
+};
+
+enum class JSCALLBACK {
+  INVOKE,
+  EXCEPTION,
+};
+
 // Message from Core to Platform in PlatformBridge
 enum class IPCMsgFromCoreToPlatform {
 	INVOKE_MEASURE_FUNCTION = 100,