content: /*
   * 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.bridge;
  
  import static org.apache.weex.bridge.WXModuleManager.createDomModule;
  
  import android.content.Context;
  import android.net.Uri;
  import android.os.Build;
  import android.os.Handler;
  import android.os.Handler.Callback;
  import android.os.Looper;
  import android.os.Message;
  import android.support.annotation.NonNull;
  import android.support.annotation.Nullable;
  import android.support.annotation.RestrictTo;
  import android.support.annotation.RestrictTo.Scope;
  import android.support.annotation.UiThread;
  import android.support.v4.util.ArrayMap;
  import android.text.TextUtils;
  import android.util.Log;
  import android.util.Pair;
  import com.alibaba.fastjson.JSON;
  import com.alibaba.fastjson.JSONArray;
  import com.alibaba.fastjson.JSONObject;
  import org.apache.weex.Script;
  import org.apache.weex.WXEnvironment;
  import org.apache.weex.WXSDKEngine;
  import org.apache.weex.WXSDKInstance;
  import org.apache.weex.WXSDKManager;
  import org.apache.weex.adapter.IWXConfigAdapter;
  import org.apache.weex.adapter.IWXJSExceptionAdapter;
  import org.apache.weex.adapter.IWXJsFileLoaderAdapter;
  import org.apache.weex.adapter.IWXJscProcessManager;
  import org.apache.weex.adapter.IWXUserTrackAdapter;
  import org.apache.weex.common.IWXBridge;
  import org.apache.weex.common.IWXDebugConfig;
  import org.apache.weex.common.WXConfig;
  import org.apache.weex.common.WXErrorCode;
  import org.apache.weex.common.WXException;
  import org.apache.weex.common.WXJSBridgeMsgType;
  import org.apache.weex.common.WXJSExceptionInfo;
  import org.apache.weex.common.WXRefreshData;
  import org.apache.weex.common.WXRenderStrategy;
  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;
  import org.apache.weex.ui.WXComponentRegistry;
  import org.apache.weex.ui.WXRenderManager;
  import org.apache.weex.ui.action.ActionReloadPage;
  import org.apache.weex.ui.action.BasicGraphicAction;
  import org.apache.weex.ui.action.GraphicActionAddChildToRichtext;
  import org.apache.weex.ui.action.GraphicActionAddElement;
  import org.apache.weex.ui.action.GraphicActionAddEvent;
  import org.apache.weex.ui.action.GraphicActionAppendTreeCreateFinish;
  import org.apache.weex.ui.action.GraphicActionCreateBody;
  import org.apache.weex.ui.action.GraphicActionCreateFinish;
  import org.apache.weex.ui.action.GraphicActionLayout;
  import org.apache.weex.ui.action.GraphicActionMoveElement;
  import org.apache.weex.ui.action.GraphicActionRefreshFinish;
  import org.apache.weex.ui.action.GraphicActionRemoveChildFromRichtext;
  import org.apache.weex.ui.action.GraphicActionRemoveElement;
  import org.apache.weex.ui.action.GraphicActionRemoveEvent;
  import org.apache.weex.ui.action.GraphicActionRenderSuccess;
  import org.apache.weex.ui.action.GraphicActionUpdateAttr;
  import org.apache.weex.ui.action.GraphicActionUpdateRichtextAttr;
  import org.apache.weex.ui.action.GraphicActionUpdateRichtextStyle;
  import org.apache.weex.ui.action.GraphicActionUpdateStyle;
  import org.apache.weex.ui.action.GraphicPosition;
  import org.apache.weex.ui.action.GraphicSize;
  import org.apache.weex.ui.component.WXComponent;
  import org.apache.weex.ui.module.WXDomModule;
  import org.apache.weex.utils.WXExceptionUtils;
  import org.apache.weex.utils.WXFileUtils;
  import org.apache.weex.utils.WXJsonUtils;
  import org.apache.weex.utils.WXLogUtils;
  import org.apache.weex.utils.WXUtils;
  import org.apache.weex.utils.WXViewUtils;
  import org.apache.weex.utils.WXWsonJSONSwitch;
  import org.apache.weex.utils.batch.BactchExecutor;
  import org.apache.weex.utils.batch.Interceptor;
  import org.apache.weex.utils.tools.LogDetail;
  import java.io.BufferedReader;
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.FileReader;
  import java.io.InputStreamReader;
  import java.io.Serializable;
  import java.lang.reflect.Constructor;
  import java.lang.reflect.Method;
  import java.text.DateFormat;
  import java.text.SimpleDateFormat;
  import java.util.*;
  import java.util.concurrent.CountDownLatch;
  import java.util.concurrent.TimeUnit;
  import java.util.regex.Pattern;
  
  /**
   * Manager class for communication between JavaScript and Android.
   * <ol>
   * <li>
   * Handle Android to JavaScript call, can be one of the following
   * <ul>
   * <li>{@link #createInstance(String, String, Map, String)}</li>
   * <li>{@link #destroyInstance(String)}</li>
   * <li>{@link #refreshInstance(String, WXRefreshData)}</li>
   * <li>{@link #registerModules(Map)}</li>
   * <li>{@link #registerComponents(List)}</li>
   * <li>{@link #invokeCallJSBatch(Message)}</li>
   * </ul>
   * </li>
   * <li>
   * Handle JavaScript to Android call
   * </li>
   * <li>
   * Handle next tick of message.
   * </li>
   * </ol>
   */
  public class WXBridgeManager implements Callback, BactchExecutor {
  
    private static Class clazz_debugProxy = null;
    public static final String METHOD_CREATE_INSTANCE = "createInstance";
    public static final String METHOD_CREATE_PAGE_WITH_CONTENT = "CreatePageWithContent";
    public static final String METHOD_UPDATE_COMPONENT_WITH_DATA = "UpdateComponentData";
    private static final String METHOD_POST_TASK_TO_MSG_LOOP = "PostTaskToMsgLoop";
    private static final String METHOD_JSFM_NOT_INIT_IN_EAGLE_MODE = "JsfmNotInitInEagleMode";
    private static final String METHOD_MOVE_RENDER_OBJECT = "RenderPage::MoveRenderObject";
    public static final String METHOD_DESTROY_INSTANCE = "destroyInstance";
    public static final String METHOD_CALL_JS = "callJS";
    public static final String METHOD_SET_TIMEOUT = "setTimeoutCallback";
    public static final String METHOD_REGISTER_MODULES = "registerModules";
    public static final String METHOD_REGISTER_COMPONENTS = "registerComponents";
    public static final String METHOD_FIRE_EVENT = "fireEvent";
    public static final String METHD_FIRE_EVENT_SYNC = "fireEventSync";
    public static final String METHD_COMPONENT_HOOK_SYNC = "componentHook";
    public static final String METHOD_CALLBACK = "callback";
    public static final String METHOD_REFRESH_INSTANCE = "refreshInstance";
    public static final String METHOD_FIRE_EVENT_ON_DATA_RENDER_NODE = "fireEventOnDataRenderNode";
    public static final String METHOD_NOTIFY_TRIM_MEMORY = "notifyTrimMemory";
    public static final String METHOD_NOTIFY_SERIALIZE_CODE_CACHE =
            "notifySerializeCodeCache";
    public static final String METHOD_CREATE_INSTANCE_CONTEXT = "createInstanceContext";
  
    public static final String KEY_METHOD = "method";
    public static final String KEY_ARGS = "args";
  
    // args
    public static final String COMPONENT = "component";
    public static final String REF = "ref";
    public static final String MODULE = "module";
    public static final String METHOD = "method";
    public static final String KEY_PARAMS = "params";
    public static final String ARGS = "args";
    public static final String OPTIONS = "options";
    public static final String INITLOGFILE = "/jsserver_start.log";
    private static final String NON_CALLBACK = "-1";
    private static final String UNDEFINED = "undefined";
    private static final String BUNDLE_TYPE = "bundleType";
    private static final String RENDER_STRATEGY = "renderStrategy";
    private static final int INIT_FRAMEWORK_OK = 1;
    private static final int CRASHREINIT = 50;
    static volatile WXBridgeManager mBridgeManager;
    private static long LOW_MEM_VALUE = 120;
    public volatile static int reInitCount = 1;
    private volatile static int sInitFrameWorkCount = 0;
    private static String crashUrl = null;
    private static long lastCrashTime = 0;
  
    private static String mRaxApi = null;
  //  private static String mRaxExtApi = null;
  
    // add for clound setting, default value is true
    // can use it to control weex sandbox
    // if true will open weex sandbox for multi context
    private volatile static boolean isSandBoxContext = true;
  
    // add for cloud setting, default value is false.
    // weexcore use single process or not
    private static boolean isUseSingleProcess = false;
    // add for cloud setting, default value is false.
    // jsEngine use multiThread or not
    private volatile static boolean isJsEngineMultiThreadEnable = false;
  
    public enum BundType {
      Vue,
      Rax,
      Others
    };
  
    private static final boolean BRIDGE_LOG_SWITCH = false;
  
    /**
     * Whether JS Framework(main.js) has been initialized.
     */
    private volatile static boolean mInit = false;
  
    private static String globalConfig = "none";
    private static String GLOBAL_CONFIG_KEY = "global_switch_config";
  
    private static Map<String, String> mWeexCoreEnvOptions = new HashMap<>();
  
    /**
     * package
     **/
    Handler mJSHandler;
    /**
     * next tick tasks, can set priority
     */
    private WXHashMap<String, ArrayList<WXHashMap<String, Object>>> mNextTickTasks = new WXHashMap<>();
    /**
     * JSThread
     */
    private WXThread mJSThread;
    private IWXBridge mWXBridge;
    private Object mWxDebugProxy;
  
    private boolean mMock = false;
  
    private List<Map<String, Object>> mRegisterComponentFailList = new ArrayList<>(8);
    private List<Map<String, Object>> mRegisterModuleFailList = new ArrayList<>(8);
    private List<String> mRegisterServiceFailList = new ArrayList<>(8);
    private HashSet<String> mDestroyedInstanceId = new HashSet<>();
    private StringBuilder mLodBuilder = new StringBuilder(50);
    private Interceptor mInterceptor;
    private WXParams mInitParams;
  
    private WXBridgeManager() {
      initWXBridge(WXEnvironment.sRemoteDebugMode);
      mJSThread = new WXThread("WeexJSBridgeThread", this);
      mJSHandler = mJSThread.getHandler();
    }
  
    public static WXBridgeManager getInstance() {
      if (mBridgeManager == null) {
        synchronized (WXBridgeManager.class) {
          if (mBridgeManager == null) {
            mBridgeManager = new WXBridgeManager();
          }
        }
      }
      return mBridgeManager;
    }
  
    public void setUseSingleProcess(final boolean flag) {
      if (flag != isUseSingleProcess) {
        isUseSingleProcess = flag;
  //      //we should reinit framework if js framework has been initialized
  //      if (isJSFrameworkInit()) {
  //        if (isJSThread()) {
  //          WXSDKEngine.reload();
  //        } else {
  //          post(new Runnable() {
  //            @Override
  //            public void run() {
  //              WXSDKEngine.reload();
  //            }
  //          });
  //        }
  //      }
      }
    }
  
    public void onInteractionTimeUpdate(final String instanceId){
      post(new Runnable() {
        @Override
        public void run() {
          if (mWXBridge instanceof WXBridge ){
            ((WXBridge)mWXBridge).nativeOnInteractionTimeUpdate(instanceId);
          }
        }
      });
    }
  
    public boolean jsEngineMultiThreadEnable() {
      return isJsEngineMultiThreadEnable;
    }
  
    public void checkJsEngineMultiThread() {
      boolean flag = false;
      IWXJscProcessManager wxJscProcessManager = WXSDKManager.getInstance().getWXJscProcessManager();
      if(wxJscProcessManager!=null) {
        flag = wxJscProcessManager.enableBackupThread();
      }
  
      if(flag == WXBridgeManager.isJsEngineMultiThreadEnable) {
          return;
      }
  
      WXBridgeManager.isJsEngineMultiThreadEnable = flag;
      //we should reinit framework if js framework has been initialized
      if (isJSFrameworkInit()) {
        if (isJSThread()) {
          WXSDKEngine.reload();
        } else {
          post(new Runnable() {
            @Override
            public void run() {
              WXSDKEngine.reload();
            }
          });
        }
      }
    }
    public void setSandBoxContext(final boolean flag) {
      if (flag != isSandBoxContext) {
        isSandBoxContext = flag;
        // use diff context reinit jsf
        if (isJSThread()) {
  
          setJSFrameworkInit(false);
          WXModuleManager.resetAllModuleState();
          String jsf = "";
          if (!isSandBoxContext) {
            jsf = WXFileUtils.loadAsset("main.js", WXEnvironment.getApplication());
          } else {
            jsf = WXFileUtils.loadAsset("weex-main-jsfm.js", WXEnvironment.getApplication());
          }
          initFramework(jsf);
          WXServiceManager.reload();
          WXModuleManager.reload();
          WXComponentRegistry.reload();
        } else {
          post(new Runnable() {
            @Override
            public void run() {
              setJSFrameworkInit(false);
              WXModuleManager.resetAllModuleState();
              String jsf = "";
              if (!isSandBoxContext) {
                jsf = WXFileUtils.loadAsset("main.js", WXEnvironment.getApplication());
              } else {
                jsf = WXFileUtils.loadAsset("weex-main-jsfm.js", WXEnvironment.getApplication());
              }
              initFramework(jsf);
              WXServiceManager.reload();
              WXModuleManager.reload();
              WXComponentRegistry.reload();
            }
          });
        }
      }
    }
  
    // setJSFrameworkInit and isJSFrameworkInit may use on diff thread
    // use volatile
    @RestrictTo(Scope.LIBRARY)
    boolean isJSFrameworkInit() {
      return mInit;
    }
  
    private void setJSFrameworkInit(boolean init) {
      mInit = init;
      WXStateRecord.getInstance().recoreJsfmInitHistory("setJsfmInitFlag:"+init);
      if (init == true) {
        onJsFrameWorkInitSuccees();
        JSEngine.getInstance().engineInitFinished();
      }
    }
  
    private void initWXBridge(boolean remoteDebug) {
      if (remoteDebug && WXEnvironment.isApkDebugable()) {
        WXEnvironment.sDebugServerConnectable = true;
      }
  
      if (WXEnvironment.sDebugServerConnectable && (WXEnvironment.isApkDebugable() || WXEnvironment.sForceEnableDevTool)) {
        if (WXEnvironment.getApplication() != null) {
          try {
            if (clazz_debugProxy == null) {
              clazz_debugProxy = Class.forName("com.taobao.weex.devtools.debug.DebugServerProxy");
            }
            if (clazz_debugProxy != null) {
              Constructor constructor = clazz_debugProxy.getConstructor(Context.class, IWXDebugConfig.class);
              if (constructor != null) {
                mWxDebugProxy = constructor.newInstance(WXEnvironment.getApplication(),
                        new IWXDebugConfig() {
                          @Override
                          public WXBridgeManager getWXJSManager() {
                            return WXBridgeManager.this;
                          }
  
                          @Override
                          public WXDebugJsBridge getWXDebugJsBridge() {
                            return new WXDebugJsBridge();
                          }
                        });
                if (mWxDebugProxy != null) {
                  Method method_start = clazz_debugProxy.getMethod("start");
                  if (method_start != null) {
                    method_start.invoke(mWxDebugProxy);
                  }
                }
              }
            }
          } catch (Throwable e) {
            //Ignore, It will throw Exception on Release environment
          }
          WXServiceManager.execAllCacheJsService();
        } else {
          WXLogUtils.e("WXBridgeManager", "WXEnvironment.sApplication is null, skip init Inspector");
        }
      }
      if (remoteDebug && mWxDebugProxy != null) {
        try {
          if (clazz_debugProxy == null ) {
            clazz_debugProxy = Class.forName("com.taobao.weex.devtools.debug.DebugServerProxy");
          }
          if (clazz_debugProxy != null) {
            Method method_getWXBridge = clazz_debugProxy.getMethod("getWXBridge");
            if (method_getWXBridge != null) {
              mWXBridge = (IWXBridge) method_getWXBridge.invoke(mWxDebugProxy);
            }
          }
        } catch (Throwable e) {
          //Ignore, It will throw Exception on Release environment
        }
      } else {
        mWXBridge = new WXBridge();
      }
    }
  
    public String dumpIpcPageInfo(){
      if (mWXBridge instanceof WXBridge){
        return ((WXBridge)mWXBridge).nativeDumpIpcPageQueueInfo();
      }
      return "";
    }
  
    public boolean isRebootExceedLimit(){
      return reInitCount > CRASHREINIT;
    }
  
    public void stopRemoteDebug() {
      if (mWxDebugProxy != null) {
        try {
          if (clazz_debugProxy == null) {
            clazz_debugProxy = Class.forName("com.taobao.weex.devtools.debug.DebugServerProxy");
          }
          if (clazz_debugProxy != null) {
            Method method_stop = clazz_debugProxy.getMethod("stop", boolean.class);
            if (method_stop != null) {
              method_stop.invoke(mWxDebugProxy, true);
            }
          }
        } catch (Throwable e) {
          //Ignore, It will throw Exception on Release environment
        }
      }
    }
  
    public Object callModuleMethod(String instanceId, String moduleStr, String methodStr, JSONArray args) {
      return callModuleMethod(instanceId, moduleStr, methodStr, args, null);
    }
  
    public Object callModuleMethod(String instanceId, String moduleStr, String methodStr, JSONArray args, JSONObject options) {
      WXSDKInstance wxsdkInstance = WXSDKManager.getInstance()
              .getSDKInstance(instanceId);
      if (wxsdkInstance == null) {
        return null;
      }
      if (wxsdkInstance.isNeedValidate()
              && WXSDKManager.getInstance().getValidateProcessor() != null) {
        WXValidateProcessor.WXModuleValidateResult validateResult = WXSDKManager
                .getInstance().getValidateProcessor()
                .onModuleValidate(wxsdkInstance, moduleStr, methodStr, args, options);
        if (validateResult == null) {
          return null;
        }
        if (validateResult.isSuccess) {
          return WXModuleManager.callModuleMethod(instanceId, moduleStr, methodStr,
                  args);
        } else {
          JSONObject validateInfo = validateResult.validateInfo;
          if (validateInfo != null) {
            WXLogUtils.e("[WXBridgeManager] module validate fail. >>> " + validateInfo.toJSONString());
          }
          return validateInfo;
        }
      }
      try {
        return WXModuleManager.callModuleMethod(instanceId, moduleStr, methodStr, args);
      }catch(NumberFormatException e){
        ArrayMap<String, String> ext = new ArrayMap<>();
        ext.put("moduleName", moduleStr);
        ext.put("methodName", methodStr);
        ext.put("args", args.toJSONString());
        WXLogUtils.e("[WXBridgeManager] callNative : numberFormatException when parsing string to numbers in args", ext.toString());
        return null;
      }
    }
  
    /**
     * Model switch. For now, debug model and release model are supported
     */
    public void restart() {
      setJSFrameworkInit(false);
      WXModuleManager.resetAllModuleState();
      initWXBridge(WXEnvironment.sRemoteDebugMode);
      mWXBridge.resetWXBridge(WXEnvironment.sRemoteDebugMode);
    }
  
    /**
     * Set current Instance
     *
     * @param instanceId {@link WXSDKInstance#getInstanceId()}
     */
    public synchronized void setStackTopInstance(final String instanceId) {
      post(new Runnable() {
  
        @Override
        public void run() {
          mNextTickTasks.setStackTopInstance(instanceId);
        }
      },instanceId, null, null);
    }
  
    @Override
    public void post(Runnable r) {
        postWithName(r,null,null);
    }
  
    public void postWithName(Runnable r, WXSDKInstance instance, String runnableName) {
     Runnable secure = WXThread.secure(r,instance, runnableName);
      if (mInterceptor != null && mInterceptor.take(secure)) {
        //task is token by the interceptor
        return;
      }
      if (mJSHandler == null) {
        return;
      }
  
      mJSHandler.post(secure);
    }
  
    @Override
    public void setInterceptor(Interceptor interceptor) {
      mInterceptor = interceptor;
    }
  
    public void post(Runnable r, Object token, WXSDKInstance instance, String runnableName) {
      if (mJSHandler == null) {
        return;
      }
  
      Message m = Message.obtain(mJSHandler, WXThread.secure(r, instance, runnableName));
      m.obj = token;
      m.sendToTarget();
    }
  
    public void post(Runnable r, Object token) {
      post(r, token, null, null);
    }
  
    public void postDelay(Runnable r,long delayMillis){
      if (mJSHandler == null) {
        return;
      }
      mJSHandler.postDelayed(WXThread.secure(r),delayMillis);
    }
  
    void setTimeout(String callbackId, String time) {
      Message message = Message.obtain();
      message.what = WXJSBridgeMsgType.SET_TIMEOUT;
      TimerInfo timerInfo = new TimerInfo();
      timerInfo.callbackId = callbackId;
      timerInfo.time = (long) Float.parseFloat(time);
      message.obj = timerInfo;
  
      mJSHandler.sendMessageDelayed(message, timerInfo.time);
    }
  
    public void sendMessageDelayed(Message message, long delayMillis) {
      if (message == null || mJSHandler == null || mJSThread == null
              || !mJSThread.isWXThreadAlive() || mJSThread.getLooper() == null) {
        return;
      }
      mJSHandler.sendMessageDelayed(message, delayMillis);
    }
  
    public void removeMessage(int what, Object obj) {
      if (mJSHandler == null || mJSThread == null
              || !mJSThread.isWXThreadAlive() || mJSThread.getLooper() == null) {
        return;
      }
      mJSHandler.removeMessages(what, obj);
    }
  
    public Object callNativeModule(String instanceId, String module, String method, JSONArray arguments, Object options) {
  
      if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(module) || TextUtils.isEmpty(method)) {
        WXLogUtils.d("[WXBridgeManager] call callNativeModule arguments is null");
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callNativeModule",
                "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
        return IWXBridge.INSTANCE_RENDERING_ERROR;
      }
  
      if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
        mLodBuilder.append("[WXBridgeManager] callNativeModule >>>> instanceId:").append(instanceId)
                .append(", module:").append(module).append(", method:").append(method).append(", arguments:").append(arguments);
        WXLogUtils.d(mLodBuilder.substring(0));
        mLodBuilder.setLength(0);
      }
  
      try {
        if (WXDomModule.WXDOM.equals(module)) {
          WXDomModule dom = WXModuleManager.getDomModule(instanceId);
          return dom.callDomMethod(method, arguments);
        } else {
          return callModuleMethod(instanceId, module,
                method, arguments);
        }
      } catch (Exception e) {
        String err = "[WXBridgeManager] callNative exception: " + WXLogUtils.getStackTrace(e);
        WXLogUtils.e(err);
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callNativeModule",
                err, null);
      }
  
      return null;
    }
  
    public Object callNativeModule(String instanceId, String module, String method, JSONArray arguments, JSONObject options) {
  
      if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(module) || TextUtils.isEmpty(method)) {
        WXLogUtils.d("[WXBridgeManager] call callNativeModule arguments is null");
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callNativeModule",
                "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
        return IWXBridge.INSTANCE_RENDERING_ERROR;
      }
  
      if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
        mLodBuilder.append("[WXBridgeManager] callNativeModule >>>> instanceId:").append(instanceId)
                .append(", module:").append(module).append(", method:").append(method).append(", arguments:").append(arguments);
        WXLogUtils.d(mLodBuilder.substring(0));
        mLodBuilder.setLength(0);
      }
  
      try {
        if (WXDomModule.WXDOM.equals(module)) {
          WXDomModule dom = WXModuleManager.getDomModule(instanceId);
          if(dom != null){
            return dom.callDomMethod(method, arguments);
          } else {
            createDomModule(WXSDKManager.getInstance().getSDKInstance(instanceId));
          }
        } else {
          return callModuleMethod(instanceId, module,
                method, arguments, options);
        }
      } catch (Exception e) {
        String err = "[WXBridgeManager] callNativeModule exception: " + WXLogUtils.getStackTrace(e);
        WXLogUtils.e(err);
      }
  
      return null;
    }
  
    public Object callNativeComponent(String instanceId, String componentRef, String method, JSONArray arguments, Object options) {
  
      if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(componentRef) || TextUtils.isEmpty(method)) {
        WXLogUtils.d("[WXBridgeManager] call callNativeComponent arguments is null");
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callNativeComponent",
                "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
        return IWXBridge.INSTANCE_RENDERING_ERROR;
      }
  
      if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
        mLodBuilder.append("[WXBridgeManager] callNativeComponent >>>> instanceId:").append(instanceId)
                .append(", componentRef:").append(componentRef).append(", method:").append(method).append(", arguments:").append(arguments);
        WXLogUtils.d(mLodBuilder.substring(0));
        mLodBuilder.setLength(0);
      }
  
      try {
        WXDomModule dom = WXModuleManager.getDomModule(instanceId);
        if (null != dom){
          dom.invokeMethod(componentRef, method, arguments);
        }else {
          WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
          if(null == instance || !instance.isDestroy()){
            WXLogUtils.e("WXBridgeManager","callNativeComponent exception :null == dom ,method:"+method);
          }
        }
  
      } catch (Exception e) {
        WXLogUtils.e("[WXBridgeManager] callNativeComponent exception: ", e);
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callNativeComponent",
                WXLogUtils.getStackTrace(e), null);
      }
      return null;
    }
  
    /**
     * Dispatch the native task to be executed.
     *
     * @param instanceId {@link WXSDKInstance#getInstanceId()}
     * @param tasks      tasks to be executed
     * @param callback   next tick id
     */
    public int callNative(String instanceId, JSONArray tasks, String callback) {
  
      if (TextUtils.isEmpty(instanceId) || tasks == null) {
        WXLogUtils.d("[WXBridgeManager] call callNative arguments is null");
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callNative",
                "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
        return IWXBridge.INSTANCE_RENDERING_ERROR;
      }
  
      if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
        mLodBuilder.append("[WXBridgeManager] callNative >>>> instanceId:").append(instanceId)
                .append(", tasks:").append(tasks).append(", callback:").append(callback);
        WXLogUtils.d(mLodBuilder.substring(0));
        mLodBuilder.setLength(0);
      }
  
      if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
        return IWXBridge.DESTROY_INSTANCE;
      }
  
  
      long parseNanos = System.nanoTime();
      JSONArray array = tasks;
      parseNanos = System.nanoTime() - parseNanos;
  
      if (null != array && array.size() > 0) {
        int size = array.size();
        try {
          JSONObject task;
          for (int i = 0; i < size; ++i) {
            task = (JSONObject) array.get(i);
            if (task != null && WXSDKManager.getInstance().getSDKInstance(instanceId) != null) {
              Object module = task.get(MODULE);
              if (module != null) {
                if (WXDomModule.WXDOM.equals(module)) {
                  WXDomModule dom = WXModuleManager.getDomModule(instanceId);
                  dom.callDomMethod(task, parseNanos);
                } else {
                  JSONObject optionObj = task.getJSONObject(OPTIONS);
                  WXStateRecord.getInstance().recordAction(instanceId,"callModuleMethod:"+instanceId+","+module+","+task.get(METHOD));
                  callModuleMethod(instanceId, (String) module,
                          (String) task.get(METHOD), (JSONArray) task.get(ARGS), optionObj);
                }
              } else if (task.get(COMPONENT) != null) {
                WXDomModule dom = WXModuleManager.getDomModule(instanceId);
                WXStateRecord.getInstance().recordAction(instanceId,"callDomMethod:"+instanceId+","+task.get(METHOD));
                dom.invokeMethod((String) task.get(REF), (String) task.get(METHOD), (JSONArray) task.get(ARGS));
              } else {
                throw new IllegalArgumentException("unknown callNative");
              }
            }
          }
        } catch (Exception e) {
          WXLogUtils.e("[WXBridgeManager] callNative exception: ", e);
          WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                  WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callNative",
                  WXLogUtils.getStackTrace(e) , null);
        }
      }
  
      if (UNDEFINED.equals(callback) || NON_CALLBACK.equals(callback)) {
        return IWXBridge.INSTANCE_RENDERING_ERROR;
      }
      // get next tick
      getNextTick(instanceId, callback);
      return IWXBridge.INSTANCE_RENDERING;
    }
  
    // callUpdateFinish
    public int callUpdateFinish(String instanceId, String callback) {
  
      if (TextUtils.isEmpty(instanceId)) {
        WXLogUtils.d("[WXBridgeManager] call callUpdateFinish arguments is null");
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callUpdateFinish",
                "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
        return IWXBridge.INSTANCE_RENDERING_ERROR;
      }
  
      if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
        mLodBuilder.append("[WXBridgeManager] callUpdateFinish >>>> instanceId:").append(instanceId)
                .append(", callback:").append(callback);
        WXLogUtils.d(mLodBuilder.substring(0));
        mLodBuilder.setLength(0);
      }
  
      if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
        return IWXBridge.DESTROY_INSTANCE;
      }
  
      try {
        if (WXSDKManager.getInstance().getSDKInstance(instanceId) != null) {
        }
      } catch (Exception e) {
        WXLogUtils.e("[WXBridgeManager] callUpdateFinish exception: ", e);
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callUpdateFinish",
                WXLogUtils.getStackTrace(e), null);
      }
  
      if (callback == null || callback.isEmpty() || UNDEFINED.equals(callback) || NON_CALLBACK.equals(callback)) {
        return IWXBridge.INSTANCE_RENDERING_ERROR;
      }
      // get next tick
      getNextTick(instanceId, callback);
      return IWXBridge.INSTANCE_RENDERING;
    }
  
    // callRefreshFinish
    public int callRefreshFinish(String instanceId, String callback) {
  
      if (TextUtils.isEmpty(instanceId)) {
        WXLogUtils.d("[WXBridgeManager] call callRefreshFinish arguments is null");
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callRefreshFinish",
                "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
        return IWXBridge.INSTANCE_RENDERING_ERROR;
      }
  
      if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
        mLodBuilder.append("[WXBridgeManager] callRefreshFinish >>>> instanceId:").append(instanceId)
                .append(", callback:").append(callback);
        WXLogUtils.d(mLodBuilder.substring(0));
        mLodBuilder.setLength(0);
      }
  
      if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
        return IWXBridge.DESTROY_INSTANCE;
      }
  
      try {
          WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
          if (instance != null) {
            GraphicActionRefreshFinish action = new GraphicActionRefreshFinish(instance);
            WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(instanceId, action);
          }
      } catch (Exception e) {
        WXLogUtils.e("[WXBridgeManager] callRefreshFinish exception: ", e);
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callRefreshFinish",
                WXLogUtils.getStackTrace(e), null);
      }
  
      if (UNDEFINED.equals(callback) || NON_CALLBACK.equals(callback)) {
        return IWXBridge.INSTANCE_RENDERING_ERROR;
      }
      // get next tick
      getNextTick(instanceId, callback);
      return IWXBridge.INSTANCE_RENDERING;
  
    }
  
    public int callReportCrashReloadPage(String instanceId, String crashFile) {
      boolean isCrashFileEmpty = TextUtils.isEmpty(crashFile);
      try {
        String url = null;
        WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
        if (instance != null) {
          url = instance.getBundleUrl();
          instance.setHasException(true);
        }
        Map<String,String> extInfo = new HashMap<>(2);
        extInfo.put("weexCoreThreadStackTrace:",WXBridgeManager.getInstance().getWeexCoreThreadStackTrace());
        extInfo.put("wxStateInfo",WXStateRecord.getInstance().getStateInfo().toString());
  
        if(!isCrashFileEmpty) {
          try {
              if (WXEnvironment.getApplication() != null) {
                  crashFile = mInitParams.getCrashFilePath() + crashFile;
                  Log.d("jsengine", "callReportCrashReloadPage crashFile:" + crashFile);
              }
          } catch (Throwable e) {
            WXLogUtils.e(WXLogUtils.getStackTrace(e));
          }
          WXStateRecord.getInstance().onJSCCrash(TextUtils.isEmpty(instanceId)?"null":instanceId);
          callReportCrash(crashFile, instanceId, url,extInfo);
        } else {
          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) {
          WXExceptionUtils.commitCriticalExceptionRT("jsEngine", WXErrorCode.WX_ERR_RELOAD_PAGE_EXCEED_LIMIT,
              "callReportCrashReloadPage","reInitCount:"+reInitCount,extInfo);
          return IWXBridge.INSTANCE_RENDERING_ERROR;
        }
        reInitCount++;
        // reinit frame work
        setJSFrameworkInit(false);
        WXModuleManager.resetAllModuleState();
        initScriptsFramework("");
  
        if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
          return IWXBridge.DESTROY_INSTANCE;
        }
      } catch (Exception e) {
        WXLogUtils.e("[WXBridgeManager] callReportCrashReloadPage exception: ", e);
      }
      try {
  
        if (WXSDKManager.getInstance().getSDKInstance(instanceId) != null) {
          boolean reloadThisInstance = shouldReloadCurrentInstance(
                  WXSDKManager.getInstance().getSDKInstance(instanceId).getBundleUrl());
          new ActionReloadPage(instanceId, reloadThisInstance).executeAction();
        }
  
      } catch (Exception e) {
        WXLogUtils.e("[WXBridgeManager] callReloadPage exception: ", e);
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callReportCrashReloadPage",
                WXLogUtils.getStackTrace(e), null);
      }
      return IWXBridge.INSTANCE_RENDERING_ERROR;
    }
  
    public boolean shouldReloadCurrentInstance(String aUrl) {
      long time = System.currentTimeMillis();
      String bizUrl = aUrl;
      IWXConfigAdapter adapter = WXSDKManager.getInstance().getWxConfigAdapter();
      if (adapter != null) {
          boolean check_biz_url = Boolean.parseBoolean(adapter
                  .getConfig("android_weex_ext_config",
                          "check_biz_url",
                          "true"));
          WXLogUtils.e("check_biz_url : " + check_biz_url);
          if(check_biz_url && !TextUtils.isEmpty(aUrl)) {
              Uri uri = Uri.parse(aUrl);
              if(uri != null) {
                  bizUrl = uri.buildUpon().clearQuery().build().toString();
              }
          }
      }
  
      if (crashUrl == null ||
              (crashUrl != null && !crashUrl.equals(bizUrl)) ||
              ((time - lastCrashTime) > 15000)) {
        crashUrl = bizUrl;
        lastCrashTime = time;
        return true;
      }
      lastCrashTime = time;
      return false;
    }
  
    public void callReportCrash(String crashFile, final String instanceId, final String url,final Map<String,String> extInfo) {
      // statistic weex core process crash
      Date date = new Date();
      DateFormat format = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US);
      String time = format.format(date);
      final String origin_filename = crashFile + "." + time;
      File oldfile = new File(crashFile);
      File newfile = new File(origin_filename);
      if (oldfile.exists()) {
        oldfile.renameTo(newfile);
      }
      Thread t = new Thread(new Runnable() {
        public void run() {
          try {
            File file = new File(origin_filename);
            if (file.exists()) {
              if (file.length() > 0) {
                StringBuilder result = new StringBuilder();
                try {
                  BufferedReader br = new BufferedReader(new FileReader(origin_filename));
                  String s = null;
                  // boolean foundStart = false;
                  while ((s = br.readLine()) != null) {
                    if ("".equals(s)) {
                      continue;
                    }
                    // if (("r0:").equals(s)) {
                    //  break;
                    // }
                    result.append(s + "\n");
                  }
                  commitJscCrashAlarmMonitor(IWXUserTrackAdapter.JS_BRIDGE, WXErrorCode.WX_ERR_JSC_CRASH, result.toString(), instanceId, url,extInfo);
                  br.close();
                } catch (Exception e) {
                  WXLogUtils.e(WXLogUtils.getStackTrace(e));
                }
              } else {
                WXLogUtils.e("[WXBridgeManager] callReportCrash crash file is empty");
              }
              if(!WXEnvironment.isApkDebugable())
                file.delete();
            }
          } catch (Throwable throwable) {
            WXLogUtils.e("[WXBridgeManager] callReportCrash exception: ", throwable);
          }
        }
      });
      t.start();
    }
  
    private void getNextTick(final String instanceId, final String callback) {
      addJSTask(METHOD_CALLBACK, instanceId, callback, "{}");
      sendMessage(instanceId, WXJSBridgeMsgType.CALL_JS_BATCH);
    }
  
    private void getNextTick(final String instanceId) {
      addJSTask(METHOD_CALLBACK, instanceId, "", "{}");
      sendMessage(instanceId, WXJSBridgeMsgType.CALL_JS_BATCH);
    }
  
    public String syncExecJsOnInstanceWithResult(final String instanceId, final String js, final int type) {
      final CountDownLatch waitLatch = new CountDownLatch(1);
      EventResult callback = new EventResult(){
        @Override
        public void onCallback(Object result) {
          super.onCallback(result);
          waitLatch.countDown();
        }
      };
      try{
        execJSOnInstance(callback, instanceId, js, type);
        waitLatch.await(100, TimeUnit.MILLISECONDS);
        if (callback != null && callback.getResult() != null) {
          return  callback.getResult().toString();
        }
        return "";
      }catch (Throwable e){
        WXLogUtils.e("syncCallExecJsOnInstance", e);
        return  "";
      }
    }
  
    public void loadJsBundleInPreInitMode(final String instanceId, final String js){
      post(new Runnable() {
        @Override
        public void run() {
          invokeExecJSOnInstance(instanceId, js, -1);
          WXSDKInstance instance = WXSDKManager.getInstance().getAllInstanceMap().get(instanceId);
          if (null != instance && instance.isPreInitMode()){
            instance.getApmForInstance().onStage(WXInstanceApm.KEY_PAGE_STAGES_LOAD_BUNDLE_END);
            instance.getApmForInstance().onStageWithTime(WXInstanceApm.KEY_PAGE_STAGES_END_EXCUTE_BUNDLE,WXUtils.getFixUnixTime()+600);
          }
        }
      });
    }
  
    /**
     * ref, type, data, domChanges
     * */
    public EventResult syncCallJSEventWithResult(final String method, final String instanceId, final List<Object> params, final Object... args) {
      final CountDownLatch waitLatch = new CountDownLatch(1);
      EventResult callback = new EventResult(){
        @Override
        public void onCallback(Object result) {
          super.onCallback(result);
          waitLatch.countDown();
        }
      };
      try{
        asyncCallJSEventWithResult(callback, method, instanceId, params, args);
        waitLatch.await(100, TimeUnit.MILLISECONDS);
        return  callback;
      }catch (Exception e){
        WXLogUtils.e("syncCallJSEventWithResult", e);
        return  callback;
      }
    }
  
    public void asyncCallJSEventVoidResult(final String method, final String instanceId, final List<Object> params, final Object... args) {
      post(new Runnable() {
        @Override
        public void run() {
          try{
            if (args == null || args.length == 0) {
              return;
            }
  
            ArrayList<Object> argsList = new ArrayList<>();
            for (Object arg : args) {
              argsList.add(arg);
            }
            if (params != null) {
              ArrayMap map = new ArrayMap(4);
              map.put(KEY_PARAMS, params);
              argsList.add(map);
            }
  
            WXHashMap<String, Object> task = new WXHashMap<>();
            task.put(KEY_METHOD, method);
            task.put(KEY_ARGS, argsList);
            Object[] tasks = {task};
            WXJSObject[] jsArgs = {
                    new WXJSObject(WXJSObject.String, instanceId),
                    WXWsonJSONSwitch.toWsonOrJsonWXJSObject(tasks)};
            invokeExecJS(String.valueOf(instanceId), null, METHOD_CALL_JS, jsArgs, true);
            jsArgs[0] = null;
            jsArgs = null;
          }catch (Exception e){
            WXLogUtils.e("asyncCallJSEventVoidResult" , e);
          }
        }
      });
    }
  
    /**
     * aync call js event and return result in eventResult callback
     * */
    private void asyncCallJSEventWithResult(final EventResult eventCallback, final String method, final String instanceId, final List<Object> params, final Object... args) {
      post(new Runnable() {
        @Override
        public void run() {
          Object result = null;
          try{
            if (args == null || args.length == 0) {
              return;
            }
  
            ArrayList<Object> argsList = new ArrayList<>();
            for (Object arg : args) {
              argsList.add(arg);
            }
            if (params != null) {
              ArrayMap map = new ArrayMap(4);
              map.put(KEY_PARAMS, params);
              argsList.add(map);
            }
  
            WXHashMap<String, Object> task = new WXHashMap<>();
            task.put(KEY_METHOD, method);
            task.put(KEY_ARGS, argsList);
            Object[] tasks = {task};
            WXJSObject[] jsArgs = {
                    new WXJSObject(WXJSObject.String, instanceId),
                    WXWsonJSONSwitch.toWsonOrJsonWXJSObject(tasks)};
            ResultCallback<byte[]> resultCallback = null;
            if (eventCallback != null) {
              resultCallback = new ResultCallback<byte[]>() {
                @Override
                public void onReceiveResult(byte[] result) {
                  JSONArray arrayResult = (JSONArray) WXWsonJSONSwitch.parseWsonOrJSON(result);
                  if(arrayResult != null && arrayResult.size() > 0){
                    eventCallback.onCallback(arrayResult.get(0));
                  }
                }
              };
            }
            invokeExecJSWithCallback(String.valueOf(instanceId), null, METHOD_CALL_JS,
                    jsArgs, resultCallback, true);
            jsArgs[0] = null;
          }catch (Exception e){
            WXLogUtils.e("asyncCallJSEventWithResult" , e);
          }
        }
      });
    }
  
    private void addJSEventTask(final String method, final String instanceId, final List<Object> params, final Object... args) {
      post(new Runnable() {
        @Override
        public void run() {
          if (args == null || args.length == 0) {
            return;
          }
  
          ArrayList<Object> argsList = new ArrayList<>();
          for (Object arg : args) {
            argsList.add(arg);
          }
          if (params != null) {
            ArrayMap map = new ArrayMap(4);
            map.put(KEY_PARAMS, params);
            argsList.add(map);
          }
  
          WXHashMap<String, Object> task = new WXHashMap<>();
          task.put(KEY_METHOD, method);
          task.put(KEY_ARGS, argsList);
  
  
          if (mNextTickTasks.get(instanceId) == null) {
            ArrayList<WXHashMap<String, Object>> list = new ArrayList<>();
            list.add(task);
            mNextTickTasks.put(instanceId, list);
          } else {
            mNextTickTasks.get(instanceId).add(task);
          }
        }
      });
    }
  
    private void addJSTask(final String method, final String instanceId, final Object... args) {
      addJSEventTask(method, instanceId, null, args);
    }
  
    private void sendMessage(String instanceId, int what) {
      Message msg = Message.obtain(mJSHandler);
      msg.obj = instanceId;
      msg.what = what;
      msg.sendToTarget();
    }
  
    /**
     * Initialize JavaScript framework
     *
     * @param framework String representation of the framework to be init.
     */
    public synchronized void initScriptsFramework(String framework) {
      Message msg = mJSHandler.obtainMessage();
      msg.obj = framework;
      msg.what = WXJSBridgeMsgType.INIT_FRAMEWORK;
      msg.setTarget(mJSHandler);
      msg.sendToTarget();
    }
  
    @Deprecated
    public void fireEvent(final String instanceId, final String ref,
                          final String type, final Map<String, Object> data) {
      this.fireEvent(instanceId, ref, type, data, null);
    }
  
    /**
     * Do not direct invoke this method in Components, use {@link WXSDKInstance#fireEvent(String, String, Map, Map)} instead.
     *
     * @param instanceId
     * @param ref
     * @param type
     * @param data
     * @param domChanges
     */
    @Deprecated
    public void fireEvent(final String instanceId, final String ref,
                          final String type, final Map<String, Object> data, final Map<String, Object> domChanges) {
      fireEventOnNode(instanceId, ref, type, data, domChanges);
    }
  
    /**
     * Notify the JavaScript about the event happened on Android
     */
    public void fireEventOnNode(final String instanceId, final String ref,
                                final String type, final Map<String, Object> data, final Map<String, Object> domChanges) {
      fireEventOnNode(instanceId, ref, type, data, domChanges, null, null);
    }
  
    /**
     * Notify the JavaScript about the event happened on Android
     */
    public void fireEventOnNode(final String instanceId, final String ref,
                                final String type, final Map<String, Object> data,
                                final Map<String, Object> domChanges, List<Object> params){
      fireEventOnNode(instanceId, ref, type, data, domChanges, params, null);
    }
  
    public void fireEventOnNode(final String instanceId, final String ref,
                                final String type, final Map<String, Object> data,
                                final Map<String, Object> domChanges, List<Object> params,  EventResult callback) {
      if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref)
              || TextUtils.isEmpty(type) || mJSHandler == null) {
        return;
      }
      if (!checkMainThread()) {
        throw new WXRuntimeException(
                "fireEvent must be called by main thread");
      }
      WXSDKInstance instance = WXSDKManager.getInstance().getAllInstanceMap().get(instanceId);
      if (instance != null && instance.isUsingEaglePlugin()) {
        int mode = instance.getEaglePlugin().isSupportFireEvent(instanceId);
        if (mode == WXEaglePlugin.NOT_SUPPORT){
          return;
        }
        fireEventOnDataRenderNode(instance.getEaglePlugin(), instanceId, ref, type, data, domChanges);
        if (mode == WXEaglePlugin.EAGLE_ONLY){
          return;
        }
        //assert mode == WXEaglePlugin.EAGLE_AND_SCRIPT
      }
  
      if (callback == null) {
        addJSEventTask(METHOD_FIRE_EVENT, instanceId, params, ref, type, data, domChanges);
        sendMessage(instanceId, WXJSBridgeMsgType.CALL_JS_BATCH);
      } else {
        asyncCallJSEventWithResult(callback, METHD_FIRE_EVENT_SYNC, instanceId, params, ref, type, data, domChanges);
      }
    }
  
    private void fireEventOnDataRenderNode(final WXEaglePlugin eaglePlugin, final String instanceId, final String ref,
                                           final String type, final Map<String, Object> data, final Map<String, Object> domChanges) {
      mJSHandler.postDelayed(WXThread.secure(new Runnable() {
        @Override
        public void run() {
          try {
            long start = System.currentTimeMillis();
            if (WXEnvironment.isApkDebugable()) {
              WXLogUtils.d("fireEventOnDataRenderNode >>>> instanceId:" + instanceId
                  + ", data:" + data);
            }
            eaglePlugin.fireEvent(instanceId, ref, type,
                (data == null || data.isEmpty()) ? "{}" : JSON.toJSONString(data),
                (domChanges == null || domChanges.isEmpty()) ? "{}" : JSON.toJSONString(domChanges));
            WXLogUtils.renderPerformanceLog("fireEventOnDataRenderNode", System.currentTimeMillis() - start);
          } catch (Throwable e) {
            String err = "[WXBridgeManager] fireEventOnDataRenderNode " + WXLogUtils.getStackTrace(e);
            WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "fireEventOnDataRenderNode",
                err, null);
            WXLogUtils.e(err);
          }
        }
      }), 0);
    }
  
    private boolean checkMainThread() {
      return Looper.myLooper() == Looper.getMainLooper();
    }
  
  
    /**
     * Invoke JavaScript callback. Use {@link JSCallback} instead.
     *
     * @see #callback(String, String, String)
     */
    @Deprecated
    public void callback(String instanceId, String callback, String data) {
      callback(instanceId, callback, data, false);
    }
  
    /**
     * Invoke JavaScript callback. Use {@link JSCallback} instead.
     */
    @Deprecated
    public void callback(final String instanceId, final String callback,
                         final Map<String, Object> data) {
      callback(instanceId, callback, data, false);
    }
  
    /**
     * Use {@link JSCallback} instead.
     *
     * @param instanceId Weex Instance Id
     * @param callback   callback referenece handle
     * @param data       callback data
     * @param keepAlive  if keep callback instance alive for later use
     */
    @Deprecated
    public void callback(final String instanceId, final String callback,
                         final Object data, boolean keepAlive) {
      callbackJavascript(instanceId, callback, data, keepAlive);
    }
  
    /**
     * Callback to Javascript function.
     *
     * @param instanceId Weex Instance Id
     * @param callback   callback referenece handle
     * @param data       callback data
     * @param keepAlive  if keep callback instance alive for later use
     */
    void callbackJavascript(final String instanceId, final String callback,
                            final Object data, boolean keepAlive) {
      if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(callback)
          || mJSHandler == null) {
        return;
      }
  
      WXSDKInstance instance = WXSDKManager.getInstance().getAllInstanceMap().get(instanceId);
      if (instance != null && instance.isUsingEaglePlugin()) {
        int mode = instance.getEaglePlugin().isSupportJSCallback(instanceId);
        if (mode == WXEaglePlugin.NOT_SUPPORT) {
          return;
        }
        callbackJavascriptOnDataRender(instance.getEaglePlugin(), instanceId, callback, data, keepAlive);
        if (mode == WXEaglePlugin.EAGLE_ONLY) {
          return;
        }
        //assert mode == WXEaglePlugin.EAGLE_AND_SCRIPT
      }
  
  
      addJSTask(METHOD_CALLBACK, instanceId, callback, data, keepAlive);
      sendMessage(instanceId, WXJSBridgeMsgType.CALL_JS_BATCH);
    }
  
    void callbackJavascriptOnDataRender(final WXEaglePlugin eaglePlugin, final String instanceId, final String callback, final Object data, final boolean keepAlive){
      mJSHandler.postDelayed(WXThread.secure(new Runnable() {
        @Override
        public void run() {
          try {
            long start = System.currentTimeMillis();
            String data_str = JSON.toJSONString(data);
            if (WXEnvironment.isApkDebugable()) {
              WXLogUtils.d("callbackJavascriptOnDataRender >>>> instanceId:" + instanceId
                  + ", data:" + data_str);
            }
            eaglePlugin.invokeJSCallback(instanceId, callback, data_str, keepAlive);
            WXLogUtils.renderPerformanceLog("callbackJavascriptOnDataRender", System.currentTimeMillis() - start);
          } catch (Throwable e) {
            String err = "[WXBridgeManager] callbackJavascriptOnDataRender " + WXLogUtils.getStackTrace(e);
            WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callbackJavascriptOnDataRender",
                err, null);
            WXLogUtils.e(err);
          }
        }
      }), 0);
    }
  
    /**
     * Refresh instance
     */
    public void refreshInstance(final String instanceId, final WXRefreshData jsonData) {
      if (TextUtils.isEmpty(instanceId) || jsonData == null) {
        return;
      }
      mJSHandler.postDelayed(WXThread.secure(new Runnable() {
        @Override
        public void run() {
          invokeRefreshInstance(instanceId, jsonData);
        }
      }), 0);
    }
  
    private void invokeRefreshInstance(String instanceId, WXRefreshData refreshData) {
      try {
        WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
        if (!isSkipFrameworkInit(instanceId) && !isJSFrameworkInit()) {
          if (instance != null) {
            instance.onRenderError(
                    WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorCode(),
                    WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorMsg()
                            + "invokeRefreshInstance FAILED for JSFrameworkInit FAILED, intance will invoke instance.onRenderError"
            );
          }
          String err = "[WXBridgeManager] invokeRefreshInstance: framework.js uninitialized.";
          WXLogUtils.e(err);
          return;
        }
        long start = System.currentTimeMillis();
        if (WXEnvironment.isApkDebugable()) {
          WXLogUtils.d("refreshInstance >>>> instanceId:" + instanceId
                  + ", data:" + refreshData.data + ", isDirty:" + refreshData.isDirty);
        }
  
        if (refreshData.isDirty) {
          return;
        }
        WXJSObject instanceIdObj = new WXJSObject(WXJSObject.String,
                instanceId);
        WXJSObject dataObj = new WXJSObject(WXJSObject.JSON,
                refreshData.data == null ? "{}" : refreshData.data);
        WXJSObject[] args = {instanceIdObj, dataObj};
        mWXBridge.refreshInstance(instanceId, null, METHOD_REFRESH_INSTANCE, args);
      } catch (Throwable e) {
        String err = "[WXBridgeManager] invokeRefreshInstance " + WXLogUtils.getStackTrace(e);
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "invokeRefreshInstance",
                err, null);
        WXLogUtils.e(err);
      }
    }
  
    public void commitJscCrashAlarmMonitor(final String type, final WXErrorCode errorCode, String errMsg,
                                           String instanceId, String url,Map<String, String> extInfo) {
      if (TextUtils.isEmpty(type) || errorCode == null) {
        return;
      }
  
      Log.d("ReportCrash", " commitJscCrashAlarmMonitor errMsg " + errMsg);
      String method = "callReportCrash";
      String exception = "weex core process crash and restart exception";
      Map<String, String> extParams = new HashMap<String, String>();
      extParams.put("jscCrashStack", errMsg);
      if (null != extInfo){
        extParams.putAll(extInfo);
      }
      IWXJSExceptionAdapter adapter = WXSDKManager.getInstance().getIWXJSExceptionAdapter();
      if (adapter != null) {
        WXJSExceptionInfo jsException = new WXJSExceptionInfo(instanceId, url, errorCode, method, exception, extParams);
        adapter.onJSException(jsException);
        // if (WXEnvironment.isApkDebugable()) {
        WXLogUtils.e(jsException.toString());
        // }
      }
    }
  
    private boolean isSkipFrameworkInit(String instanceId) {
      final WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
      return isSkipFrameworkInit(instance);
    }
  
    private boolean isSkipFrameworkInit(WXSDKInstance instance) {
      if (instance == null) {
        return false;
      }
      return instance.skipFrameworkInit();
    }
  
    /**
     * Create instance.
     */
    public void createInstance(final String instanceId, final String template,
                               final Map<String, Object> options, final String data) {
      createInstance(instanceId, new Script(template), options, data);
    }
  
    public void setLogLevel(final int level, final boolean isPerf) {
      post(new Runnable() {
        @Override
        public void run() {
          if(mWXBridge != null) {
            mWXBridge.setLogType(level, isPerf);
          }
        }
      });
    }
  
    public void createInstance(final String instanceId, final Script template,
                               final Map<String, Object> options, final String data) {
      final WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
      if (instance == null) {
        WXLogUtils.e("WXBridgeManager", "createInstance failed, SDKInstance does not exist");
        return;
      }
      if (TextUtils.isEmpty(instanceId) || template == null || template.isEmpty() || mJSHandler == null) {
        instance.onRenderError(
                WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorCode(),
                WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorMsg() +
                        " instanceId==" + instanceId + " template ==" + template + " mJSHandler== " + mJSHandler.toString()
        );
  
        instance.getApmForInstance().onStage("createInstance failed return; "+TextUtils.isEmpty(instanceId)+ ","+template.isEmpty()+","+(mJSHandler ==null));
        return;
      }
  
      if (!isSkipFrameworkInit(instanceId) && !isJSFrameworkInit() && reInitCount == 1 && !WXEnvironment.sDebugServerConnectable) {
        instance.onRenderError(
                WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorCode(),
                WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorMsg() +
                        " isJSFrameworkInit==" + isJSFrameworkInit() + " reInitCount == 1" );
        instance.getApmForInstance().onStage("createInstance failed jsfm isn't init return;");
        post(new Runnable() {
          @Override
          public void run() {
            initFramework("");
          }
        }, instanceId, instance,"initFrameworkInCreateInstance");
        return;
      }
  
      WXModuleManager.createDomModule(instance);
      instance.getApmForInstance().onStage(WXInstanceApm.KEY_PAGE_STAGES_LOAD_BUNDLE_START);
      post(new Runnable() {
        @Override
        public void run() {
          instance.getApmForInstance().onStage("wxLoadBundleStartOnJsThread");
          long start = System.currentTimeMillis();
          mWXBridge.setPageArgument(instanceId, "renderTimeOrigin", String.valueOf(instance.getWXPerformance().renderTimeOrigin));
          mWXBridge.setInstanceRenderType(instance.getInstanceId(), instance.getRenderType());
          invokeCreateInstance(instance, template, options, data);
          long end = System.currentTimeMillis();
          instance.getWXPerformance().callCreateInstanceTime = end - start;
          instance.getWXPerformance().communicateTime =  instance.getWXPerformance().callCreateInstanceTime;
        }
      }, instanceId, instance,"createInstance");
    }
  
    private void invokeCreateInstance(@NonNull WXSDKInstance instance, Script template,
                                      Map<String, Object> options, String data) {
      // add for sandbox, will delete on sandbox ok
      if (!isSkipFrameworkInit(instance)){
        initFramework("");
      }
  
      if (mMock) {
        mock(instance.getInstanceId());
      } else {
        if (!isSkipFrameworkInit(instance) && !isJSFrameworkInit()) {
          String err = "[WXBridgeManager] invokeCreateInstance: framework.js uninitialized.";
          instance.onRenderError(
                  WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorCode(),
                  WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorMsg()
          );
          WXLogUtils.e(err);
          instance.getApmForInstance().onStage("framework.js uninitialized and return");
          return;
        }
  
        WXModuleManager.registerWhenCreateInstance();
  
        try {
          BundType type = BundType.Others;
          try {
            long start = System.currentTimeMillis();
            type = getBundleType(instance.getBundleUrl(), template.getContent());
  
            if (WXEnvironment.isOpenDebugLog()) {
              long end = System.currentTimeMillis();
              WXLogUtils.e("end getBundleType type:" + type.toString() + " time:" + (end - start));
            }
          } catch (Throwable e) {
            WXLogUtils.e(WXLogUtils.getStackTrace(e));
          }
  
          try {
            if (options == null) {
              options = new HashMap<>();
            }
            // on file there is { "framework": "Vue" } or others
            if (options.get(BUNDLE_TYPE) == null) {
              // may vue or Rax
              if (type == BundType.Vue) {
                options.put(BUNDLE_TYPE, "Vue");
              } else if (type == BundType.Rax) {
                options.put(BUNDLE_TYPE, "Rax");
              } else {
                options.put(BUNDLE_TYPE, "Others");
              }
              Object recordBundleType = options.get(BUNDLE_TYPE);
              if (recordBundleType instanceof String && "Others".equalsIgnoreCase((String)recordBundleType)){
                //same as iOS record
                recordBundleType = "other";
              }
              if (null != recordBundleType){
                instance.getApmForInstance().addProperty(WXInstanceApm.KEY_PAGE_PROPERTIES_BUNDLE_TYPE, recordBundleType);
              }
            }
            if (options.get("env") == null) {
              options.put("env", mInitParams.toMap());
            }
          } catch (Throwable e) {
            WXLogUtils.e(WXLogUtils.getStackTrace(e));
          }
          instance.bundleType = type;
          if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
            WXLogUtils.d("createInstance >>>> instanceId:" + instance.getInstanceId()
                    + ", options:"
                    + WXJsonUtils.fromObjectToJSONString(options)
                    + ", data:" + data);
          }
          WXJSObject instanceIdObj = new WXJSObject(WXJSObject.String,
                  instance.getInstanceId());
          WXJSObject instanceObj;
          WXJSObject scriptType;
          if (TextUtils.isEmpty(template.getContent())){
            //byte[]
            instanceObj = new WXJSObject(WXJSObject.String,
                template.getBinary());
            scriptType = new WXJSObject(WXJSObject.String, "binary");
          } else {
            //String
            instanceObj = new WXJSObject(WXJSObject.String,
                template.getContent());
            scriptType = new WXJSObject(WXJSObject.NUMBER, "string");
          }
  
  
          Object extraOption = null;
          if(options != null && options.containsKey("extraOption")) {
             extraOption = options.get("extraOption");
             options.remove("extraOption");
          }
  
          WXJSObject extraOptionObj = new WXJSObject(WXJSObject.JSON,
                  extraOption == null ? "{}"
                          : WXJsonUtils.fromObjectToJSONString(extraOption));
  
  
          WXJSObject optionsObj = new WXJSObject(WXJSObject.JSON,
                  options == null ? "{}"
                          : WXJsonUtils.fromObjectToJSONString(options));
          optionsObj = optionObjConvert(isSandBoxContext, type, optionsObj);
          WXJSObject dataObj = new WXJSObject(WXJSObject.JSON,
                  data == null ? "{}" : data);
  
          WXJSObject apiObj;
          if (type == BundType.Rax || instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER) {
            if (mRaxApi == null) {
              IWXJsFileLoaderAdapter iwxJsFileLoaderAdapter = WXSDKEngine.getIWXJsFileLoaderAdapter();
              if(iwxJsFileLoaderAdapter != null) {
                mRaxApi = iwxJsFileLoaderAdapter.loadRaxApi();
              }
  
              if(TextUtils.isEmpty(mRaxApi)) {
                mRaxApi =  WXFileUtils.loadAsset("weex-rax-api.js", WXEnvironment.getApplication());
              }
            }
            apiObj = new WXJSObject(WXJSObject.String,
                    mRaxApi);
          } else {
            apiObj = new WXJSObject(WXJSObject.String,
                    "");
          }
  
          // When render strategy is data_render, put it into options. Others keep null.
          WXJSObject renderStrategy = null;
          if (instance.isUsingEaglePlugin()) {
            //Eagle use plugin name as renderStrategy
            renderStrategy = new WXJSObject(WXJSObject.String, instance.getEaglePluginName());
          } else if (instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER_BINARY || instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER) {
            //todo just for compat
            //using eagle mode without eagle plugin, will report exception in c if no plugin was found.
            renderStrategy = new WXJSObject(WXJSObject.String, "DATA_RENDER");
          } else if (instance.getRenderStrategy() == WXRenderStrategy.JSON_RENDER) {
            renderStrategy = new WXJSObject(WXJSObject.String, WXRenderStrategy.JSON_RENDER.getFlag());
          }
  
          WXJSObject[] args = {instanceIdObj, instanceObj, optionsObj,
                  dataObj, apiObj, renderStrategy, extraOptionObj};
  
          instance.setTemplate(template.getContent());
  
          instance.getApmForInstance().onStage(WXInstanceApm.KEY_PAGE_STAGES_LOAD_BUNDLE_END);
  
          // if { "framework": "Vue" } or  { "framework": "Rax" } will use invokeCreateInstanceContext
          // others will use invokeExecJS
          if (!isSandBoxContext) {
            instance.getApmForInstance().onStage("!isSandBoxContext,and excute");
            WXLogUtils.e("Instance " + instance.getInstanceId() + " Did Not Render in SandBox Mode");
            invokeExecJS(instance.getInstanceId(), null, METHOD_CREATE_INSTANCE, args, false);
            return;
          }
          if (type == BundType.Vue || type == BundType.Rax
                  || instance.isUsingEaglePlugin()
                  || instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER_BINARY //Todo only for compat when plugin not registered
                  || instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER
                  || instance.getRenderStrategy() == WXRenderStrategy.JSON_RENDER) {
            instance.getApmForInstance().onStage("wxBeforeInvokeCreateInstanceContext");
  
            WXLogUtils.d("Instance " + instance.getInstanceId() + " Render in SandBox Mode And Render Type is "
                    + type + " Render Strategy is " + instance.getRenderStrategy());
            //extra args for create instance.
            args = Arrays.copyOf(args,args.length+1);
            args[args.length -1 ] = scriptType;
  
            int ret = invokeCreateInstanceContext(instance.getInstanceId(), null, "createInstanceContext", args, false);
            instance.getApmForInstance().onStage(WXInstanceApm.KEY_PAGE_STAGES_LOAD_BUNDLE_END);
            if(ret == 0) {
              String err = "[WXBridgeManager] invokeCreateInstance : " + instance.getTemplateInfo();
              WXLogUtils.e("Instance " + instance.getInstanceId() + "Render error : " + err);
              instance.onRenderError(
                      WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorCode(),
                      WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorMsg() + err);
            }
            return;
          } else {
            //bad case for js bundle with out bundletype header //vue or rax
            //WXExceptionUtils.commitCriticalExceptionRT(
            //      instance.getInstanceId(),
            //      WXErrorCode.WX_KEY_EXCEPTION_NO_BUNDLE_TYPE,
            //      "invokeCreateInstance",
            //      WXErrorCode.WX_KEY_EXCEPTION_NO_BUNDLE_TYPE.getErrorMsg(),
            //      null
            //);
  
            WXLogUtils.d("Instance " + instance.getInstanceId() + "Did not Render in SandBox Mode And Render Type is "
                  + type + " Render Strategy is " + instance.getRenderStrategy());
            instance.getApmForInstance().onStage("StartInvokeExecJSBadBundleType");
            invokeExecJS(instance.getInstanceId(), null, METHOD_CREATE_INSTANCE, args, false);
            instance.getApmForInstance().onStage(WXInstanceApm.KEY_PAGE_STAGES_LOAD_BUNDLE_END);
            return;
          }
        } catch (Throwable e) {
          String err = "[WXBridgeManager] invokeCreateInstance " + e.getCause()
                  + instance.getTemplateInfo();
          instance.getApmForInstance().onStage("createInstance error :"+e.toString());
          WXLogUtils.e("Instance " + instance.getInstanceId() + "Render error : " + err);
          instance.onRenderError(
                  WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorCode(),
                  WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorMsg() + err);
          WXLogUtils.e(err);
        }
      }
    }
  
    public WXJSObject optionObjConvert(boolean useSandBox, BundType type, WXJSObject opt) {
      if (!useSandBox) {
        return opt;
      }
      try {
        String data = opt.data.toString();
        JSONObject obj = JSON.parseObject(data);
        JSONObject optEnv;
        if ((optEnv = obj.getJSONObject("env")) != null) {
          JSONObject opts = optEnv.getJSONObject("options");
          if (opts != null) {
            for (String s : opts.keySet()) {
              optEnv.put(s, opts.getString(s));
            }
          }
        }
        return new WXJSObject(WXJSObject.JSON, obj.toString());
      } catch (Throwable e) {
        WXLogUtils.e(WXLogUtils.getStackTrace(e));
      }
      return opt;
  
    }
  
    /**
     * check bundleType
     * @param url
     * @param temp
     * @return
     */
    public BundType getBundleType(String url, String temp) {
      try {
        if (url != null) {
          Uri uri = Uri.parse(url);
          String type = uri.getQueryParameter(BUNDLE_TYPE);
          if ("Vue".equals(type) || "vue".equals(type)) {
            return BundType.Vue;
          } else if ("Rax".equals(type) || "rax".equals(type)) {
            return BundType.Rax;
          }
        }
        if (temp != null) {
          final String FRAMEWORK="framework", VUE="vue", RAX="rax";
  
          // Find the first line that starts with '//' and convert it to json
          int bundleTypeStart = temp.indexOf("//");
          int bundleTypeEnd = temp.indexOf("\n", bundleTypeStart);
          JSONObject bundleType = JSONObject.parseObject(
              temp.substring(bundleTypeStart+2, bundleTypeEnd));
          String type = bundleType.getString(FRAMEWORK);
          if(VUE.equalsIgnoreCase(type)){
            return BundType.Vue;
          }
          else if(RAX.equalsIgnoreCase(type)){
            return BundType.Rax;
          }
          else{
            // '//{ "framework": "Vue"}' is not found.
            String regEx = "(use)(\\s+)(weex:vue)";
            Pattern pattern = Pattern.compile(regEx, Pattern.CASE_INSENSITIVE);
            if (pattern.matcher(temp).find()) {
              return BundType.Vue;
            }
            regEx = "(use)(\\s+)(weex:rax)";
            pattern = Pattern.compile(regEx, Pattern.CASE_INSENSITIVE);
            if (pattern.matcher(temp).find()) {
              return BundType.Rax;
            }
          }
        }
        return BundType.Others;
      } catch (Throwable e) {
        WXLogUtils.e(WXLogUtils.getStackTrace(e));
        return BundType.Others;
      }
    }
  
    private void mock(String instanceId) {
  
    }
  
    public void destroyInstance(final String instanceId) {
      if (mJSHandler == null
              || TextUtils.isEmpty(instanceId)) {
        return;
      }
      if (mDestroyedInstanceId != null) {
        mDestroyedInstanceId.add(instanceId);
      }
      // clear message with instanceId
      mJSHandler.removeCallbacksAndMessages(instanceId);
      post(new Runnable() {
        @Override
        public void run() {
          removeTaskByInstance(instanceId);
          invokeDestroyInstance(instanceId);
        }
      }, instanceId, null, "destroyInstance");
    }
  
    private void removeTaskByInstance(String instanceId) {
      mNextTickTasks.removeFromMapAndStack(instanceId);
    }
  
    private void invokeDestroyInstance(String instanceId) {
      try {
        if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
          WXLogUtils.d("destroyInstance >>>> instanceId:" + instanceId);
        }
        WXJSObject instanceIdObj = new WXJSObject(WXJSObject.String,
                instanceId);
        WXJSObject[] args = {instanceIdObj};
        if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
          invokeDestoryInstance(instanceId, null, METHOD_DESTROY_INSTANCE, args, true);
          // invokeExecJS(instanceId, null, METHOD_DESTROY_INSTANCE, args);
        }
      } catch (Throwable e) {
        String err = "[WXBridgeManager] invokeDestroyInstance " + e.getCause();
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "invokeDestroyInstance", err, null);
        WXLogUtils.e(err);
      }
    }
  
    @Override
    public boolean handleMessage(Message msg) {
      if (msg == null) {
        return false;
      }
  
      int what = msg.what;
      switch (what) {
        case WXJSBridgeMsgType.INIT_FRAMEWORK:
          invokeInitFramework(msg);
          break;
        case WXJSBridgeMsgType.CALL_JS_BATCH:
          invokeCallJSBatch(msg);
          break;
        case WXJSBridgeMsgType.SET_TIMEOUT:
          TimerInfo timerInfo = (TimerInfo) msg.obj;
          if (timerInfo == null) {
            break;
          }
          WXJSObject obj = new WXJSObject(WXJSObject.String, timerInfo.callbackId);
          WXJSObject[] args = {obj};
          invokeExecJS("", null, METHOD_SET_TIMEOUT, args);
          break;
        case WXJSBridgeMsgType.TAKE_HEAP_SNAPSHOT:
          if (msg.obj != null) {
            String filename = (String) msg.obj;
            mWXBridge.takeHeapSnapshot(filename);
          }
          break;
        default:
          break;
      }
      return false;
    }
  
    private void invokeExecJS(String instanceId, String namespace, String function, WXJSObject[] args) {
      invokeExecJS(instanceId, namespace, function, args, true);
    }
  
    public void invokeExecJS(final String instanceId, final String namespace, final String function,
                             final WXJSObject[] args, boolean logTaskDetail) {
      if (WXEnvironment.isOpenDebugLog() && BRIDGE_LOG_SWITCH) {
        mLodBuilder.append("callJS >>>> instanceId:").append(instanceId)
                .append("function:").append(function);
        if (logTaskDetail) {
          mLodBuilder.append(" tasks:").append(argsToJSON(args));
        }
        WXLogUtils.d(mLodBuilder.substring(0));
        mLodBuilder.setLength(0);
      }
      final long start = System.currentTimeMillis();
      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
  
      if (instance != null && instance.isUsingEaglePlugin()) {
        final WXEaglePlugin eaglePlugin = instance.getEaglePlugin();
        int mode = eaglePlugin.isSupportInvokeExecJS(instanceId);
        if (mode == WXEaglePlugin.NOT_SUPPORT){
          return;
        }
        WXThread.secure(new Runnable() {
          @Override
          public void run() {
            eaglePlugin.invokeExecJS(instanceId, namespace, function,args );
          }
        }, instance, "ExecJsEagle").run();
        if (mode == WXEaglePlugin.EAGLE_ONLY){
          if (null != instance){
            long diff = System.currentTimeMillis()-start;
            instance.getApmForInstance().updateFSDiffStats(WXInstanceApm.KEY_PAGE_STATS_FS_CALL_JS_NUM,1);
            instance.getApmForInstance().updateFSDiffStats(WXInstanceApm.KEY_PAGE_STATS_FS_CALL_JS_TIME,diff);
            instance.callJsTime(diff);
          }
          return;
        }
        //assert mode == WXEaglePlugin.EAGLE_AND_SCRIPT
      }
  
      WXThread.secure(new Runnable() {
        @Override
        public void run() {
          mWXBridge.execJS(instanceId, namespace, function, args);
        }
      }, instance, "ExecJs").run();
      if (null != instance){
        long diff = System.currentTimeMillis()-start;
        instance.getApmForInstance().updateFSDiffStats(WXInstanceApm.KEY_PAGE_STATS_FS_CALL_JS_NUM,1);
        instance.getApmForInstance().updateFSDiffStats(WXInstanceApm.KEY_PAGE_STATS_FS_CALL_JS_TIME,diff);
        instance.callJsTime(diff);
      }
    }
  
    private Pair<Pair<String,Object>,Boolean> extractCallbackArgs(String data) {
      try {
        JSONArray obj = JSON.parseArray(data);
        JSONObject arg_obj = obj.getJSONObject(0);
        JSONArray args = arg_obj.getJSONArray("args");
        if (args.size()!=3){
          return null;
        }
        String method = arg_obj.getString("method");
        if (!"callback".equals(method)){
          return null;
        }
  
        return new Pair<Pair<String,Object>, Boolean>(new Pair<String, Object>(args.getString(0), args.getJSONObject(1)),args.getBooleanValue(2));
      } catch (Exception e) {
        return null;
      }
    }
  
    public int invokeCreateInstanceContext(String instanceId, String namespace, String function,
                                            WXJSObject[] args, boolean logTaskDetail) {
      WXLogUtils.d("invokeCreateInstanceContext instanceId:" + instanceId + " function:"
              + function + String.format(" isJSFrameworkInit：%b", isJSFrameworkInit()));
      mLodBuilder.append("createInstanceContext >>>> instanceId:").append(instanceId)
              .append("function:").append(function);
      if (logTaskDetail)
        mLodBuilder.append(" tasks:").append(WXJsonUtils.fromObjectToJSONString(args));
      WXLogUtils.d(mLodBuilder.substring(0));
      mLodBuilder.setLength(0);
      // }
      return mWXBridge.createInstanceContext(instanceId, namespace, function, args);
    }
  
    public void invokeDestoryInstance(String instanceId, String namespace, String function,
                                      WXJSObject[] args, boolean logTaskDetail) {
      // if (WXEnvironment.isApkDebugable()) {
      mLodBuilder.append("callJS >>>> instanceId:").append(instanceId)
              .append("function:").append(function);
      if (logTaskDetail)
        mLodBuilder.append(" tasks:").append(WXJsonUtils.fromObjectToJSONString(args));
      WXLogUtils.d(mLodBuilder.substring(0));
      mLodBuilder.setLength(0);
      // }
      mWXBridge.removeInstanceRenderType(instanceId);
      mWXBridge.destoryInstance(instanceId, namespace, function, args);
    }
  
    private void execJSOnInstance(final EventResult eventCallback, final String instanceId, final String js, final int type) {
      post(new Runnable() {
        @Override
        public void run() {
          String ret = invokeExecJSOnInstance(instanceId, js, type);
          eventCallback.onCallback(ret);
        }
      });
    }
  
    private String invokeExecJSOnInstance(String instanceId, String js, int type) {
      // if (WXEnvironment.isApkDebugable()) {
      mLodBuilder.append("execJSOnInstance >>>> instanceId:").append(instanceId);
      WXLogUtils.d(mLodBuilder.substring(0));
      mLodBuilder.setLength(0);
      // }
      if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
        return mWXBridge.execJSOnInstance(instanceId, js, type);
      }
      return null;
    }
  
    private void invokeExecJSWithCallback(String instanceId, String namespace, String function,
                                          WXJSObject[] args , ResultCallback callback, boolean logTaskDetail){
      if (WXEnvironment.isOpenDebugLog() && BRIDGE_LOG_SWITCH) {
        mLodBuilder.append("callJS >>>> instanceId:").append(instanceId)
                .append("function:").append(function);
        if(logTaskDetail) {
          mLodBuilder.append(" tasks:").append(argsToJSON(args));
        }
        WXLogUtils.d(mLodBuilder.substring(0));
        mLodBuilder.setLength(0);
      }
      if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
        mWXBridge.execJSWithCallback(instanceId, namespace, function, args, callback);
      }
    }
  
    public @NonNull static String argsToJSON(WXJSObject[] args) {
      StringBuilder builder = new StringBuilder();
      builder.append("[");
      for(WXJSObject object : args){
        builder.append(WXWsonJSONSwitch.fromObjectToJSONString(object));
        builder.append(",");
      }
      builder.append("]");
      return  builder.toString();
    }
  
    private void invokeInitFramework(Message msg) {
      String framework = "";
      if (msg.obj != null) {
        framework = (String) msg.obj;
      }
  
      if (WXUtils.getAvailMemory(WXEnvironment.getApplication()) > LOW_MEM_VALUE) {
        initFramework(framework);
      }
    }
  
    public static long sInitFrameWorkTimeOrigin;
    public static StringBuilder sInitFrameWorkMsg = new StringBuilder();
  
    private void initFramework(String framework) {
      LogDetail logDetail = new LogDetail();
      logDetail.name("initFramework");
      logDetail.taskStart();
      if (WXSDKEngine.isSoInitialized() && !isJSFrameworkInit()) {
        sInitFrameWorkTimeOrigin = System.currentTimeMillis();
        if (TextUtils.isEmpty(framework)) {
          // if (WXEnvironment.isApkDebugable()) {
          WXLogUtils.d("weex JS framework from assets");
          // }
  
          LogDetail logDetail2 = new LogDetail();
          logDetail2.name("loadJSFramework");
          logDetail2.taskStart();
  
          IWXJsFileLoaderAdapter wxJsFileLoaderAdapter = WXSDKEngine.getIWXJsFileLoaderAdapter();
  
          if (!isSandBoxContext) {
            if(wxJsFileLoaderAdapter != null) {
              framework = wxJsFileLoaderAdapter.loadJsFramework();
            }
  
            if(TextUtils.isEmpty(framework)) {
              framework = WXFileUtils.loadAsset("main.js", WXEnvironment.getApplication());
            }
          } else {
            if(wxJsFileLoaderAdapter != null) {
              framework = wxJsFileLoaderAdapter.loadJsFrameworkForSandBox();
            }
  
            if(TextUtils.isEmpty(framework)) {
              framework = WXFileUtils.loadAsset("weex-main-jsfm.js", WXEnvironment.getApplication());
            }
          }
          sInitFrameWorkMsg.append("| weex JS framework from assets, isSandBoxContext: ").append(isSandBoxContext);
          logDetail2.taskEnd();
        }
        if (TextUtils.isEmpty(framework)) {
          setJSFrameworkInit(false);
          sInitFrameWorkMsg.append("| framework isEmpty ");
          WXExceptionUtils.commitCriticalExceptionRT(null, WXErrorCode.WX_ERR_JS_FRAMEWORK,
                  "initFramework", "framework is empty!! ", null);
          return;
        }
        try {
          if (WXSDKManager.getInstance().getWXStatisticsListener() != null) {
            long start = System.currentTimeMillis();
            WXSDKManager.getInstance().getWXStatisticsListener().onJsFrameworkStart();
            WXEnvironment.sJSFMStartListenerTime = System.currentTimeMillis() - start;
            try {
              IWXUserTrackAdapter adapter = WXSDKManager.getInstance().getIWXUserTrackAdapter();
              if (null != adapter){
                Map<String,Serializable> params = new HashMap<>(1);
                params.put("time",String.valueOf(WXEnvironment.sJSFMStartListenerTime));
                adapter.commit(WXEnvironment.getApplication(),"sJSFMStartListener",IWXUserTrackAdapter.COUNTER,null,params);
              }
            }catch (Exception e){
              WXLogUtils.e(WXLogUtils.getStackTrace(e));
            }
          }
  
          long start = System.currentTimeMillis();
          String crashFile = "";
          try {
            crashFile = WXEnvironment.getApplication().getApplicationContext().getCacheDir().getPath();
          } catch (Exception e) {
            WXLogUtils.e(WXLogUtils.getStackTrace(e));
          }
          boolean pieSupport = true;
          try {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
              pieSupport = false;
            }
          } catch (Exception e) {
            WXLogUtils.e(WXLogUtils.getStackTrace(e));
          }
          sInitFrameWorkMsg.append(" | pieSupport:").append(pieSupport);
          WXLogUtils.d("[WXBridgeManager] initFrameworkEnv crashFile:" + crashFile + " pieSupport:" + pieSupport);
          // extends initFramework
          LogDetail logDetail3 = new LogDetail();
          logDetail3.name("native initFrameworkEnv");
          logDetail3.taskStart();
          if (mWXBridge.initFrameworkEnv(framework, assembleDefaultOptions(), crashFile, pieSupport) == INIT_FRAMEWORK_OK) {
            logDetail3.taskEnd();
            WXEnvironment.sJSLibInitTime = System.currentTimeMillis() - start;
            WXEnvironment.sSDKInitTime = System.currentTimeMillis() - WXEnvironment.sSDKInitStart;
            setJSFrameworkInit(true);
            logDetail.taskEnd();
            if (WXSDKManager.getInstance().getWXStatisticsListener() != null) {
              WXSDKManager.getInstance().getWXStatisticsListener().onJsFrameworkReady();
            }
  
            execRegisterFailTask();
            WXEnvironment.JsFrameworkInit = true;
            WXSDKManager.getInstance().notifyInitSuccess();
            sInitFrameWorkCount++;
            WXLogUtils.e("initFrameWorkCount :"+ sInitFrameWorkCount);
            registerDomModule();
            trackComponentAndModulesTime();
          } else {
            sInitFrameWorkMsg.append(" | ExecuteJavaScript fail, reInitCount").append(reInitCount);
            if (reInitCount > 1) {
              WXLogUtils.e("[WXBridgeManager] invokeReInitFramework  ExecuteJavaScript fail");
            } else {
              WXLogUtils.e("[WXBridgeManager] invokeInitFramework  ExecuteJavaScript fail");
            }
          }
        } catch (Throwable e) {
          sInitFrameWorkMsg.append(" | invokeInitFramework exception ").append(e.toString());
          if (reInitCount > 1) {
            WXLogUtils.e("[WXBridgeManager] invokeInitFramework ", e);
          } else {
            WXLogUtils.e("[WXBridgeManager] invokeInitFramework ", e);
          }
        }
  
      }
    }
  
    private void trackComponentAndModulesTime() {
      post(new Runnable() {
        @Override
        public void run() {
          WXEnvironment.sComponentsAndModulesReadyTime = System.currentTimeMillis() - WXEnvironment.sSDKInitStart;
        }
      });
    }
  
    @SuppressWarnings("unchecked")
    private void invokeCallJSBatch(Message message) {
      if (mNextTickTasks.isEmpty() || !isJSFrameworkInit()) {
        if (!isJSFrameworkInit()) {
          WXLogUtils.e("[WXBridgeManager] invokeCallJSBatch: framework.js uninitialized!!  message:" + message.toString());
        }
        return;
      }
  
      try {
        Object instanceId = message.obj;
  
        Object task = null;
        Stack<String> instanceStack = mNextTickTasks.getInstanceStack();
        int size = instanceStack.size();
        for (int i = size - 1; i >= 0; i--) {
          instanceId = instanceStack.get(i);
          task = mNextTickTasks.remove(instanceId);
          if (task != null && !((ArrayList) task).isEmpty()) {
            break;
          }
        }
        if (null != task){
          task = ((ArrayList) task).toArray();
  
          WXJSObject[] args = {
              new WXJSObject(WXJSObject.String, instanceId),
              WXWsonJSONSwitch.toWsonOrJsonWXJSObject(task)};
  
          invokeExecJS(String.valueOf(instanceId), null, METHOD_CALL_JS, args);
        }
      } catch (Throwable e) {
        WXLogUtils.e("WXBridgeManager", e);
        String err = "invokeCallJSBatch#" + WXLogUtils.getStackTrace(e);
        WXExceptionUtils.commitCriticalExceptionRT(null, WXErrorCode.WX_ERR_JS_FRAMEWORK,
                "invokeCallJSBatch", err, null);
      }
  
      // If task is not empty, loop until it is empty
      if (!mNextTickTasks.isEmpty()) {
        mJSHandler.sendEmptyMessage(WXJSBridgeMsgType.CALL_JS_BATCH);
      }
    }
  
    private WXParams assembleDefaultOptions() {
      checkJsEngineMultiThread();
  
      Map<String, String> config = WXEnvironment.getConfig();
      WXParams wxParams = new WXParams();
      wxParams.setPlatform(config.get(WXConfig.os));
      wxParams.setCacheDir(config.get(WXConfig.cacheDir));
      wxParams.setOsVersion(config.get(WXConfig.sysVersion));
      wxParams.setAppVersion(config.get(WXConfig.appVersion));
      wxParams.setWeexVersion(config.get(WXConfig.weexVersion));
      wxParams.setDeviceModel(config.get(WXConfig.sysModel));
      wxParams.setShouldInfoCollect(config.get("infoCollect"));
      wxParams.setLogLevel(config.get(WXConfig.logLevel));
      wxParams.setLayoutDirection(config.get(WXConfig.layoutDirection));
      wxParams.setUseSingleProcess(isUseSingleProcess ? "true" : "false");
      wxParams.setCrashFilePath(WXEnvironment.getCrashFilePath(WXEnvironment.getApplication().getApplicationContext()));
      wxParams.setLibJsbPath(WXEnvironment.CORE_JSB_SO_PATH);
      wxParams.setLibJssPath(WXEnvironment.getLibJssRealPath());
      wxParams.setLibIcuPath(WXEnvironment.getLibJssIcuPath());
      wxParams.setLibLdPath(WXEnvironment.getLibLdPath());
      String libJScRealPath = WXEnvironment.getLibJScRealPath();
      wxParams.setLibJscPath(TextUtils.isEmpty(libJScRealPath)? "" : new File(libJScRealPath).getParent());
      String appName = config.get(WXConfig.appName);
      if (!TextUtils.isEmpty(appName)) {
        wxParams.setAppName(appName);
      }
      wxParams.setDeviceWidth(TextUtils.isEmpty(config.get("deviceWidth")) ? String.valueOf(WXViewUtils.getScreenWidth(WXEnvironment.sApplication)) : config.get("deviceWidth"));
      wxParams.setDeviceHeight(TextUtils.isEmpty(config.get("deviceHeight")) ? String.valueOf(WXViewUtils.getScreenHeight(WXEnvironment.sApplication)) : config.get("deviceHeight"));
      Map<String, String> customOptions = WXEnvironment.getCustomOptions();
      customOptions.put("enableBackupThread", String.valueOf(jsEngineMultiThreadEnable()));
      IWXJscProcessManager wxJscProcessManager = WXSDKManager.getInstance().getWXJscProcessManager();
      if(wxJscProcessManager != null) {
        customOptions.put("enableBackupThreadCache", String.valueOf(wxJscProcessManager.enableBackUpThreadCache()));
      }
  
      if (!WXEnvironment.sUseRunTimeApi){
        customOptions.put("__enable_native_promise__","true");
      }
  
      String enableAlarmSignal = "true";
      IWXConfigAdapter adapter = WXSDKManager.getInstance().getWxConfigAdapter();
      if (null != adapter){
        try {
          if (adapter.checkMode("white_screen_fix_open")){
            WXEnvironment.isWsFixMode = true;
            enableAlarmSignal = "true";
          }else {
            enableAlarmSignal = adapter.getConfigWhenInit("wxapm","enableAlarmSignal",enableAlarmSignal);
            WXEnvironment.isWsFixMode = "true".equalsIgnoreCase(enableAlarmSignal);
          }
        }catch (Exception e){
          e.printStackTrace();
        }
      }
      if (null != enableAlarmSignal){
        customOptions.put("enableAlarmSignal",enableAlarmSignal);
      }
      WXLogUtils.e("weex","enableAlarmSignal:"+enableAlarmSignal);
  
      wxParams.setOptions(customOptions);
      wxParams.setNeedInitV8(WXSDKManager.getInstance().needInitV8());
      mInitParams = wxParams;
      return wxParams;
    }
  
    public WXParams getInitParams() {
      return mInitParams;
    }
  
    private void execRegisterFailTask() {
  
      if (mRegisterModuleFailList.size() > 0) {
        List<Map<String, Object>> moduleReceiver = new ArrayList<>();
        for (int i = 0, moduleCount = mRegisterModuleFailList.size(); i < moduleCount; ++i) {
          invokeRegisterModules(mRegisterModuleFailList.get(i), moduleReceiver);
        }
        mRegisterModuleFailList.clear();
        if (moduleReceiver.size() > 0) {
          mRegisterModuleFailList.addAll(moduleReceiver);
        }
      }
  
      if (mRegisterComponentFailList.size() > 0) {
        List<Map<String, Object>> receiver = new ArrayList<>();
        invokeRegisterComponents(mRegisterComponentFailList, receiver);
        mRegisterComponentFailList.clear();
        if (receiver.size() > 0) {
          mRegisterComponentFailList.addAll(receiver);
        }
      }
  
      if (mRegisterServiceFailList.size() > 0) {
        List<String> receiver = new ArrayList<>();
        for (String service : mRegisterServiceFailList) {
          invokeExecJSService(service, receiver);
        }
        mRegisterServiceFailList.clear();
        if (receiver.size() > 0) {
          mRegisterServiceFailList.addAll(receiver);
        }
      }
    }
  
    /**
     * Register Android module
     *
     * @param modules the format is like
     *                {'dom':['updateAttrs','updateStyle'],'event':['openUrl']}
     */
  
    public void registerModules(final Map<String, Object> modules) {
      if (modules != null && modules.size() != 0) {
        if (isJSThread()) {
          invokeRegisterModules(modules, mRegisterModuleFailList);
        } else {
          post(new Runnable() {
            @Override
            public void run() {
              invokeRegisterModules(modules, mRegisterModuleFailList);
            }
          });
        }
      }
    }
  
    /**
     * Registered component
     */
    public void registerComponents(final List<Map<String, Object>> components) {
      if (mJSHandler == null || components == null
              || components.size() == 0) {
        return;
      }
      Runnable runnable = new Runnable() {
        @Override
        public void run() {
          invokeRegisterComponents(components, mRegisterComponentFailList);
        }
      };
  
      if(isJSThread() && isJSFrameworkInit()){
        runnable.run();
      }else{
        post(runnable);
      }
    }
  
    public void execJSService(final String service) {
      postWithName(new Runnable() {
        @Override
        public void run() {
          invokeExecJSService(service, mRegisterServiceFailList);
        }
      },null,"execJSService");
    }
  
    private void invokeExecJSService(String service, List<String> receiver) {
      try {
        if (!isJSFrameworkInit()) {
          WXLogUtils.e("[WXBridgeManager] invoke execJSService: framework.js uninitialized.");
          receiver.add(service);
          return;
        }
        mWXBridge.execJSService(service);
      } catch (Throwable e) {
        WXLogUtils.e("[WXBridgeManager] invokeRegisterService:", e);
  
        Map<String, String> data = new HashMap<String, String>();
        data.put("inputParams",service + "||" + receiver.toString());
  
        WXExceptionUtils.commitCriticalExceptionRT("invokeExecJSService",
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_JSSERVICE_EXECUTE,
                "invokeExecJSService",
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_JSSERVICE_EXECUTE.getErrorMsg()
                        + "[WXBridgeManager] invokeRegisterService:"
                        + WXLogUtils.getStackTrace(e),
                data);
      }
    }
  
    public boolean isJSThread() {
      return mJSThread != null && mJSThread.getId() == Thread.currentThread().getId();
    }
  
    private void invokeRegisterModules(Map<String, Object> modules, List<Map<String, Object>> failReceiver) {
      if (modules == null || !isJSFrameworkInit()) {
        if (!isJSFrameworkInit()) {
          WXLogUtils.d("[WXinvokeRegisterModulesBridgeManager] invokeRegisterModules: framework.js uninitialized.");
        }
        failReceiver.add(modules);
        return;
      }
  
      WXJSObject[] args = {WXWsonJSONSwitch.toWsonOrJsonWXJSObject(modules)};
      String errorMsg = null;
      try {
          if(0 == mWXBridge.execJS("", null, METHOD_REGISTER_MODULES, args)) {
              errorMsg = "execJS error";
          }
        try {
          Iterator<String> iter = modules.keySet().iterator();
          while (iter.hasNext()) {
            String module = iter.next();
            if (module != null) {
              WXModuleManager.resetModuleState(module, true);
              //WXLogUtils.e("[WXBridgeManager]invokeRegisterModules METHOD_REGISTER_MODULES success module:" + module);
            }
          }
        } catch (Throwable e) {
          WXLogUtils.e("Weex [invokeRegisterModules]", e);
        }
      } catch (Throwable e) {
        errorMsg = WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_MODULES.getErrorMsg() +
                  " \n " + e.getMessage() + modules.entrySet().toString();
      }
  
      if(!TextUtils.isEmpty(errorMsg)) {
          WXLogUtils.e("[WXBridgeManager] invokeRegisterModules:", errorMsg);
          WXExceptionUtils.commitCriticalExceptionRT(null,
                  WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_MODULES,
                  "invokeRegisterModules", errorMsg,
                  null );
      }
    }
  
    private void invokeRegisterComponents(List<Map<String, Object>> components, List<Map<String, Object>> failReceiver) {
      if (components == failReceiver) {
        throw new RuntimeException("Fail receiver should not use source.");
      }
      if (!isJSFrameworkInit()) {
        //WXLogUtils.e("[WXBridgeManager] invokeRegisterComponents: framework.js uninitialized.");
  
        for (Map<String, Object> comp : components) {
          failReceiver.add(comp);
        }
        return;
      }
      if (components == null) {
        return;
      }
  
      WXJSObject[] args = {WXWsonJSONSwitch.toWsonOrJsonWXJSObject(components)};
      String errorMsg = null;
      try {
        if(0 == mWXBridge.execJS("", null, METHOD_REGISTER_COMPONENTS, args)) {
            errorMsg = "execJS error";
        }
      } catch (Throwable e) {
          errorMsg = WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_COMPONENT
                  + args.toString()
                  + WXLogUtils.getStackTrace(e);
      }
  
      if(!TextUtils.isEmpty(errorMsg)) {
          WXLogUtils.e("[WXBridgeManager] invokeRegisterComponents ", errorMsg);
          WXExceptionUtils.commitCriticalExceptionRT(null,
                  WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_COMPONENT,
                  METHOD_REGISTER_COMPONENTS, errorMsg,
                  null);
      }
    }
  
    public void destroy() {
      if (mJSThread != null) {
        mJSThread.quit();
      }
      mBridgeManager = null;
      if (mDestroyedInstanceId != null) {
        mDestroyedInstanceId.clear();
      }
  
    }
  
    /**
     * Report JavaScript Exception
     */
    public void reportJSException(String instanceId, String function,
                                  String exception) {
      WXLogUtils.e("reportJSException >>>> instanceId:" + instanceId
              + ", exception function:" + function + ", exception:"
              + exception);
      WXSDKInstance instance = null;
      WXErrorCode reportErrorCode = WXErrorCode.WX_ERR_JS_EXECUTE;
      if (instanceId != null && (instance = WXSDKManager.getInstance().getSDKInstance(instanceId)) != null) {
        instance.setHasException(true);
        exception +=   "\n getTemplateInfo==" +instance.getTemplateInfo();//add network header info
        if ((METHOD_CREATE_INSTANCE.equals(function)) || !instance.isContentMd5Match()) {
          try {
            //data render mode should report exception instead of reload page,
            // so we use !isSkipFrameworkInit(instanceId) to skip the positive branch of if clause.
            if (!isSkipFrameworkInit(instanceId) && isJSFrameworkInit() && (reInitCount > 1 && reInitCount < 10) && !instance.isNeedReLoad()) {
              new ActionReloadPage(instanceId, true).executeAction();
              instance.setNeedLoad(true);
              return;
            } else {
              String errorMsg = new StringBuilder()
                  .append(WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorMsg())
                  .append(", exception function:").append(function)
                  .append(", exception:").append(exception)
                  .append(", extInitTime:").append(System.currentTimeMillis()-WXBridgeManager.sInitFrameWorkTimeOrigin).append("ms")
                  .append(", extInitErrorMsg:").append(WXBridgeManager.sInitFrameWorkMsg.toString())
                  .toString();
              instance.onRenderError(//DegradPassivity to H5
                       WXErrorCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getErrorCode(),
                       errorMsg
              );
              if (!WXEnvironment.sInAliWeex){
                WXExceptionUtils.commitCriticalExceptionRT(instanceId, WXErrorCode.WX_RENDER_ERR_JS_CREATE_INSTANCE, function,exception,null);
              }
              return;
            }
          } catch (Exception e) {
            WXLogUtils.e(WXLogUtils.getStackTrace(e));
          }
        }
        if (METHOD_CREATE_INSTANCE.equals(function) && !instance.getApmForInstance().hasAddView){
          reportErrorCode = WXErrorCode.WX_RENDER_ERR_JS_CREATE_INSTANCE;
        } else if ( METHOD_CREATE_INSTANCE_CONTEXT.equals(function) && !instance.getApmForInstance().hasAddView){
          reportErrorCode = WXErrorCode.WX_RENDER_ERR_JS_CREATE_INSTANCE_CONTEXT;
        } else if (
            (METHOD_UPDATE_COMPONENT_WITH_DATA.equals(function) ||
            METHOD_CREATE_PAGE_WITH_CONTENT.equals(function) ||
            METHOD_POST_TASK_TO_MSG_LOOP.equals(function) ||
                METHOD_JSFM_NOT_INIT_IN_EAGLE_MODE.equals(function) )
            && !instance.getApmForInstance().hasAddView){
          reportErrorCode = WXErrorCode.WX_DEGRAD_EAGLE_RENDER_ERROR;
        } else if (METHOD_MOVE_RENDER_OBJECT.equals(function)) {
          reportErrorCode = WXErrorCode.WX_ERROR_MOVE_RENDER_OBJECT_OUT_OF_BOUNDS;
        }
        instance.onJSException(reportErrorCode.getErrorCode(), function, exception);
      }
      doReportJSException(instanceId,function,reportErrorCode,exception);
    }
  
    private void doReportJSException(String instanceId, String function,WXErrorCode reportCode, String exception){
      WXSDKInstance instance = WXSDKManager.getInstance().getAllInstanceMap().get(instanceId);
      IWXJSExceptionAdapter adapter = WXSDKManager.getInstance().getIWXJSExceptionAdapter();
      if (adapter != null) {
        String exceptionId = instanceId;
  
        if (TextUtils.isEmpty(instanceId)) {
          exceptionId = "instanceIdisNull";
        }
  
        if (instance == null) {
          if (("initFramework").equals(function)) {
            String exceptionExt = null;
            try {
              if (WXEnvironment.getApplication() != null) {
                final String fileName = WXEnvironment.getApplication().getApplicationContext().getCacheDir().getPath() + INITLOGFILE;
                try {
                  File file = new File(fileName);
                  if (file.exists()) {
                    if (file.length() > 0) {
                      StringBuilder result = new StringBuilder();
                      try {
                        InputStreamReader read = new InputStreamReader(new FileInputStream(file), "UTF-8");
                        BufferedReader br = new BufferedReader(read);
                        String s = null;
                        while ((s = br.readLine()) != null) {
                          result.append(s + "\n");
                        }
                        exceptionExt = result.toString();
                        br.close();
                      } catch (Exception e) {
                        WXLogUtils.e(WXLogUtils.getStackTrace(e));
                      }
                    }
                    file.delete();
                  }
                } catch (Throwable throwable) {
                  WXLogUtils.e(WXLogUtils.getStackTrace(throwable));
                }
              }
            } catch (Throwable e) {
              WXLogUtils.e(WXLogUtils.getStackTrace(e));
            }
            exception += "\n" + exceptionExt;
            WXLogUtils.e("reportJSException:" + exception);
  
          }
        }
  
  
        WXExceptionUtils.commitCriticalExceptionRT(exceptionId, reportCode,
              function,
            reportCode.getErrorMsg() + exception,
              null);
  
      }
    }
  
    private void registerDomModule() throws WXException {
      /** Tell Javascript Framework what methods you have. This is Required.**/
      Map<String, Object> domMap = new HashMap<>();
      domMap.put(WXDomModule.WXDOM, WXDomModule.METHODS);
      registerModules(domMap);
    }
  
    //This method is deprecated because of performance issue.
    @Deprecated
    public void notifyTrimMemory() {
  
    }
  
    /**
     * update js server global config, current support turn wson off
     * by pass wson_off
     * */
    public static void  updateGlobalConfig(String config) {
      if(TextUtils.isEmpty(config)){
        config = "none";
      }
      if(!TextUtils.equals(config, globalConfig)){
        globalConfig = config;
        WXEnvironment.addCustomOptions(GLOBAL_CONFIG_KEY, globalConfig);
        Runnable runnable = new Runnable() {
          @Override
          public void run() {
            if(mBridgeManager != null){
              if(mBridgeManager.isJSFrameworkInit()){
                if(mBridgeManager.mWXBridge instanceof WXBridge) {
                  final WXBridge bridge = (WXBridge) mBridgeManager.mWXBridge;
                  bridge.nativeUpdateGlobalConfig(globalConfig);
                }
              }
            }
            if(globalConfig.contains(WXWsonJSONSwitch.WSON_OFF)){
              WXWsonJSONSwitch.USE_WSON = false;
            }else{
              WXWsonJSONSwitch.USE_WSON = true;
            }
          }
        };
        if(mBridgeManager != null && mBridgeManager.isJSFrameworkInit()){
          mBridgeManager.post(runnable);
        }else{
          runnable.run();
        }
      }
    }
  
    public
    @Nullable
    Looper getJSLooper() {
      Looper ret = null;
      if (mJSThread != null) {
        ret = mJSThread.getLooper();
      }
      return ret;
    }
  
    public void notifySerializeCodeCache() {
      post(new Runnable() {
        @Override
        public void run() {
          if (!isJSFrameworkInit())
            return;
  
          invokeExecJS("", null, METHOD_NOTIFY_SERIALIZE_CODE_CACHE, new WXJSObject[0]);
        }
      });
    }
  
    public void takeJSHeapSnapshot(String filename) {
      Message msg = mJSHandler.obtainMessage();
      msg.obj = filename;
      msg.what = WXJSBridgeMsgType.TAKE_HEAP_SNAPSHOT;
      msg.setTarget(mJSHandler);
      msg.sendToTarget();
    }
  
    public static class TimerInfo {
  
      public String callbackId;
      public long time;
      public String instanceId;
    }
  
    public int callCreateBody(String pageId, String componentType, String ref,
                              HashMap<String, String> styles, HashMap<String, String> attributes, HashSet<String> events,
                              float[] margins, float[] paddings, float[] borders) {
  
      if (TextUtils.isEmpty(pageId) || TextUtils.isEmpty(componentType) || TextUtils.isEmpty(ref)) {
        WXLogUtils.d("[WXBridgeManager] call callCreateBody arguments is null");
        WXExceptionUtils.commitCriticalExceptionRT(pageId,
                WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callCreateBody",
                "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
        return IWXBridge.INSTANCE_RENDERING_ERROR;
      }
  
      if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
        mLodBuilder.append("[WXBridgeManager] callCreateBody >>>> pageId:").append(pageId)
                .append(", componentType:").append(componentType).append(", ref:").append(ref)
                .append(", styles:").append(styles == null ? "{}" : styles.toString())
                .append(", attributes:").append(attributes)
                .append(", events:").append(events);
        WXLogUtils.d(mLodBuilder.substring(0));
        mLodBuilder.setLength(0);
      }
  
      if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(pageId)) {
        return IWXBridge.DESTROY_INSTANCE;
      }
  
      try {
        WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(pageId);
        if (instance != null) {
          final BasicGraphicAction action = new GraphicActionCreateBody(instance, ref, componentType,
                  styles, attributes, events, margins, paddings, borders);
          WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
        }
      } catch (Exception e) {
        WXLogUtils.e("[WXBridgeManager] callCreateBody exception: ", e);
        WXExceptionUtils.commitCriticalExceptionRT(pageId,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callCreateBody",
                WXLogUtils.getStackTrace(e), null);
      }
  
      return IWXBridge.INSTANCE_RENDERING;
    }
  
    public int callAddElement(String pageId, String componentType, String ref, int index, String parentRef,
                              HashMap<String, String> styles, HashMap<String, String> attributes, HashSet<String> events,
                              float[] margins, float[] paddings, float[] borders,boolean willLayout) {
      if (TextUtils.isEmpty(pageId) || TextUtils.isEmpty(componentType) || TextUtils.isEmpty(ref)) {
        if (WXEnvironment.isApkDebugable()){
          WXLogUtils.d("[WXBridgeManager] call callAddElement arguments is null");
        }
        WXExceptionUtils.commitCriticalExceptionRT(pageId,
                WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callAddElement",
                "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
        return IWXBridge.INSTANCE_RENDERING_ERROR;
      }
  
      if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
        mLodBuilder.append("[WXBridgeManager] callAddElement >>>> pageId:").append(pageId)
                .append(", componentType:").append(componentType).append(", ref:").append(ref).append(", index:").append(index)
                .append(", parentRef:").append(parentRef)
                .append(", styles:").append(styles == null ? "{}" : styles.toString())
                .append(", attributes:").append(attributes)
                .append(", events:").append(events);
        WXLogUtils.d(mLodBuilder.substring(0));
        mLodBuilder.setLength(0);
      }
  
      if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(pageId)) {
        return IWXBridge.DESTROY_INSTANCE;
      }
  
      try {
        WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(pageId);
        if (instance != null) {
          final GraphicActionAddElement action = new GraphicActionAddElement(instance, ref, componentType, parentRef, index,
              styles, attributes, events, margins, paddings, borders);
          if(willLayout) {
            instance.addInActiveAddElementAction(ref, action);
          }else{
            WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(pageId, action);
          }
        }
      } catch (Exception e) {
        WXLogUtils.e("[WXBridgeManager] callAddElement exception: ", e);
        WXExceptionUtils.commitCriticalExceptionRT(pageId,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callAddElement",
                WXLogUtils.getStackTrace(e), null);
      }
  
      return IWXBridge.INSTANCE_RENDERING;
    }
  
    public int callRemoveElement(String instanceId, String ref) {
  
      if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref)) {
        if (WXEnvironment.isApkDebugable()){
          WXLogUtils.d("[WXBridgeManager] call callRemoveElement arguments is null");
        }
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callRemoveElement",
                "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
        return IWXBridge.INSTANCE_RENDERING_ERROR;
      }
  
      if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
        mLodBuilder.append("[WXBridgeManager] callRemoveElement >>>> instanceId:").append(instanceId)
                .append(", ref:").append(ref);
        WXLogUtils.d(mLodBuilder.substring(0));
        mLodBuilder.setLength(0);
      }
  
      if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
        return IWXBridge.DESTROY_INSTANCE;
      }
  
      try {
        WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
        if (instance != null) {
          final BasicGraphicAction action = new GraphicActionRemoveElement(instance, ref);
          if(instance.getInActiveAddElementAction(ref)!=null){
            instance.removeInActiveAddElmentAction(ref);
          }
          else {
            WXSDKManager.getInstance().getWXRenderManager()
                .postGraphicAction(action.getPageId(), action);
          }
        }
      } catch (Exception e) {
        WXLogUtils.e("[WXBridgeManager] callRemoveElement exception: ", e);
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callRemoveElement",
                WXLogUtils.getStackTrace(e), null);
      }
  
      return IWXBridge.INSTANCE_RENDERING;
    }
  
    public int callMoveElement(String instanceId, String ref, String parentref, int index) {
  
      if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref) || TextUtils.isEmpty(parentref)) {
        if (WXEnvironment.isApkDebugable()){
          WXLogUtils.d("[WXBridgeManager] call callMoveElement arguments is null");
        }
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callMoveElement",
                "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
        return IWXBridge.INSTANCE_RENDERING_ERROR;
      }
  
      if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
        mLodBuilder.append("[WXBridgeManager] callMoveElement >>>> instanceId:").append(instanceId)
                .append(", parentref:").append(parentref)
                .append(", index:").append(index)
                .append(", ref:").append(ref);
        WXLogUtils.d(mLodBuilder.substring(0));
        mLodBuilder.setLength(0);
      }
  
      if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
        return IWXBridge.DESTROY_INSTANCE;
      }
  
      try {
        WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
        if (instance != null) {
          final BasicGraphicAction action = new GraphicActionMoveElement(instance, ref, parentref, index);
          WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
        }
      } catch (Exception e) {
        WXLogUtils.e("[WXBridgeManager] callMoveElement exception: ", e);
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callMoveElement",
                WXLogUtils.getStackTrace(e), null);
      }
  
      return IWXBridge.INSTANCE_RENDERING;
    }
  
    public int callAddEvent(String instanceId, String ref, String event) {
  
      if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref) || TextUtils.isEmpty(event)) {
        if (WXEnvironment.isApkDebugable()){
          WXLogUtils.d("[WXBridgeManager] call callAddEvent arguments is null");
        }
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callAddEvent",
                "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
        return IWXBridge.INSTANCE_RENDERING_ERROR;
      }
  
      if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
        mLodBuilder.append("[WXBridgeManager] callAddEvent >>>> instanceId:").append(instanceId)
                .append(", ref:").append(ref)
                .append(", event:").append(event);
        WXLogUtils.d(mLodBuilder.substring(0));
        mLodBuilder.setLength(0);
      }
  
      if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
        return IWXBridge.DESTROY_INSTANCE;
      }
  
      try {
        WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
        if (instance != null) {
          new GraphicActionAddEvent(instance, ref, event).executeActionOnRender();
        }
      } catch (Exception e) {
        WXLogUtils.e("[WXBridgeManager] callAddEvent exception: ", e);
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callAddEvent",
                WXLogUtils.getStackTrace(e), null);
      }
  
      // get next tick
      getNextTick(instanceId);
      return IWXBridge.INSTANCE_RENDERING;
    }
  
    public int callRemoveEvent(String instanceId, String ref, String event) {
  
      if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref) || TextUtils.isEmpty(event)) {
        if (WXEnvironment.isApkDebugable()){
          WXLogUtils.d("[WXBridgeManager] call callRemoveEvent arguments is null");
        }
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callRemoveEvent",
                "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
        return IWXBridge.INSTANCE_RENDERING_ERROR;
      }
  
      if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
        mLodBuilder.append("[WXBridgeManager] callRemoveEvent >>>> instanceId:").append(instanceId)
                .append(", ref:").append(ref)
                .append(", event:").append(event);
        WXLogUtils.d(mLodBuilder.substring(0));
        mLodBuilder.setLength(0);
      }
  
      if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
        return IWXBridge.DESTROY_INSTANCE;
      }
  
      try {
        WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
        if (instance != null) {
          new GraphicActionRemoveEvent(instance, ref, event).executeActionOnRender();
        }
      } catch (Exception e) {
        WXLogUtils.e("[WXBridgeManager] callRemoveEvent exception: ", e);
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callRemoveEvent",
                WXLogUtils.getStackTrace(e), null);
      }
  
      // get next tick
      getNextTick(instanceId);
      return IWXBridge.INSTANCE_RENDERING;
    }
  
    public int callUpdateStyle(String instanceId, String ref, HashMap<String, Object> styles,
                               HashMap<String, String> paddings,
                               HashMap<String, String> margins,
                               HashMap<String, String> borders) {
  
      if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref)) {
        if (WXEnvironment.isApkDebugable()){
          WXLogUtils.d("[WXBridgeManager] call callUpdateStyle arguments is null");
        }
  
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callUpdateStyle",
                "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
        return IWXBridge.INSTANCE_RENDERING_ERROR;
      }
  
      if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
        mLodBuilder.append("[WXBridgeManager] callUpdateStyle >>>> instanceId:").append(instanceId)
                .append(", ref:").append(ref).append(", styles:").append(styles == null ? "{}" : styles.toString())
                .append(", paddings:").append(paddings.toString())
                        .append(", margins:").append(margins.toString())
                                .append(", borders:").append(borders.toString());
        WXLogUtils.d(mLodBuilder.substring(0));
        mLodBuilder.setLength(0);
      }
  
      if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
        return IWXBridge.DESTROY_INSTANCE;
      }
  
      try {
        WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
        if (instance != null) {
          final BasicGraphicAction action = new GraphicActionUpdateStyle(instance, ref, styles, paddings, margins, borders);
          WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
        }
      } catch (Exception e) {
        WXLogUtils.e("[WXBridgeManager] callUpdateStyle exception: ", e);
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callUpdateStyle",
                WXLogUtils.getStackTrace(e), null);
      }
  
      return IWXBridge.INSTANCE_RENDERING;
    }
  
    public int callUpdateAttrs(String instanceId, String ref, HashMap<String, String> attrs) {
  
      if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref)) {
        if (WXEnvironment.isApkDebugable()){
          WXLogUtils.d("[WXBridgeManager] call callUpdateAttrs arguments is null");
        }
  
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callUpdateAttrs",
                "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
        return IWXBridge.INSTANCE_RENDERING_ERROR;
      }
  
      if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
        mLodBuilder.append("[WXBridgeManager] callUpdateAttrs >>>> instanceId:").append(instanceId)
                .append(", ref:").append(ref).append(", attrs:").append(attrs.toString());
        WXLogUtils.d(mLodBuilder.substring(0));
        mLodBuilder.setLength(0);
      }
  
      if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
        return IWXBridge.DESTROY_INSTANCE;
      }
  
      try {
        WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
        if (instance != null) {
          final BasicGraphicAction action = new GraphicActionUpdateAttr(instance, ref, attrs);
          WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
        }
      } catch (Exception e) {
        WXLogUtils.e("[WXBridgeManager] callUpdateAttrs exception: ", e);
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callUpdateAttrs",
                WXLogUtils.getStackTrace(e), null);
      }
  
      return IWXBridge.INSTANCE_RENDERING;
    }
  
    private void setExceedGPULimitComponentsInfo(String instanceId,String ref,GraphicSize layoutSize){
      float limit = WXRenderManager.getOpenGLRenderLimitValue();
      if(limit > 0 && (layoutSize.getHeight() > limit || layoutSize.getWidth() > limit)){
        JSONObject ext = new JSONObject();
        WXComponent component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(instanceId,ref);
        ext.put("GPU limit",String.valueOf(limit));
        ext.put("component.width",String.valueOf(layoutSize.getWidth()));
        ext.put("component.height",String.valueOf(layoutSize.getHeight()));
        if (component.getComponentType() != null && !component.getComponentType().isEmpty()) {
          ext.put("component.type", component.getComponentType());
        }
        if (component.getStyles() != null && !component.getStyles().isEmpty()) {
          ext.put("component.style", component.getStyles().toString());
        }
        if (component.getAttrs() != null && !component.getAttrs().isEmpty()) {
          ext.put("component.attr", component.getAttrs().toString());
        }
        if (component.getEvents() != null && !component.getEvents().isEmpty()) {
          ext.put("component.event", component.getEvents().toString());
        }
        if (component.getMargin() != null) {
          ext.put("component.margin", component.getMargin().toString());
        }
        if (component.getPadding() != null) {
          ext.put("component.padding", component.getPadding().toString());
        }
        if (component.getBorder() != null) {
          ext.put("component.border", component.getBorder().toString());
        }
        WXSDKManager.getInstance().getSDKInstance(instanceId).setComponentsInfoExceedGPULimit(ext);
      }
    }
  
    public int callAddChildToRichtext(String instanceId, String nodeType, String ref, String parentRef, String richTextRef,
                                      HashMap<String, String> styles, HashMap<String, String> attrs){
      if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref)) {
        if (WXEnvironment.isApkDebugable()){
          WXLogUtils.d("[WXBridgeManager] call callAddChildToRichtext arguments is null");
        }
  
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callAddChildToRichtext",
                "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
        return IWXBridge.INSTANCE_RENDERING_ERROR;
      }
  
      if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
        mLodBuilder.append("[WXBridgeManager] callAddChildToRichtext >>>> instanceId:").append(instanceId)
                .append(", nodeType:").append(nodeType).append(", ref:").append(ref).append(", parentRef:")
                .append(parentRef).append(", richTextRef:").append(richTextRef).append(", styles:")
                .append(styles.toString()).append(", attrs:").append(attrs.toString());
        WXLogUtils.d(mLodBuilder.substring(0));
        mLodBuilder.setLength(0);
      }
  
      if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
        return IWXBridge.DESTROY_INSTANCE;
      }
      try {
        WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
        if (instance != null) {
          final BasicGraphicAction action = new GraphicActionAddChildToRichtext(instance,nodeType,ref,parentRef,richTextRef,styles,attrs
          );
          WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
        }
      } catch (Exception e) {
        WXLogUtils.e("[WXBridgeManager] callAddChildToRichtext exception: ", WXLogUtils.getStackTrace(e));
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callAddChildToRichtext",
                WXLogUtils.getStackTrace(e), null);
      }
  
      return IWXBridge.INSTANCE_RENDERING;
    }
  
    public int callRemoveChildFromRichtext(String instanceId, String ref, String parentRef, String richTextRef){
      if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref)) {
        if (WXEnvironment.isApkDebugable()){
          WXLogUtils.d("[WXBridgeManager] call callRemoveChildFromRichtext arguments is null");
        }
  
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callRemoveChildFromRichtext",
                "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
        return IWXBridge.INSTANCE_RENDERING_ERROR;
      }
  
      if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
        mLodBuilder.append("[WXBridgeManager] callRemoveChildFromRichtext >>>> instanceId:").append(instanceId)
                .append(", ref:").append(ref).append(", parentRef:").append(parentRef).append(", richTextRef:").append(richTextRef);
        WXLogUtils.d(mLodBuilder.substring(0));
        mLodBuilder.setLength(0);
      }
  
      if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
        return IWXBridge.DESTROY_INSTANCE;
      }
      try {
        WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
        if (instance != null) {
          final BasicGraphicAction action = new GraphicActionRemoveChildFromRichtext(instance, ref, parentRef, richTextRef);
          WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
        }
      } catch (Exception e) {
        WXLogUtils.e("[WXBridgeManager] callRemoveChildFromRichtext exception: ", e);
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callRemoveChildFromRichtext",
                WXLogUtils.getStackTrace(e), null);
      }
  
      return IWXBridge.INSTANCE_RENDERING;
    }
  
    public int callUpdateRichtextStyle(String instanceId, String ref, HashMap<String, String> styles, String parentRef, String richTextRef){
      if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref)) {
        if (WXEnvironment.isApkDebugable()){
          WXLogUtils.d("[WXBridgeManager] call callUpdateRichtextStyle arguments is null");
        }
  
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callUpdateRichtextStyle",
                "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
        return IWXBridge.INSTANCE_RENDERING_ERROR;
      }
  
      if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
        mLodBuilder.append("[WXBridgeManager] callUpdateRichtextStyle >>>> instanceId:").append(instanceId)
                .append(", ref:").append(ref).append(", styles:").append(styles.toString()).append(", parentRef:")
                .append(parentRef).append(", richTextRef:").append(richTextRef);
        WXLogUtils.d(mLodBuilder.substring(0));
        mLodBuilder.setLength(0);
      }
  
      if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
        return IWXBridge.DESTROY_INSTANCE;
      }
      try {
        WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
        if (instance != null) {
          final BasicGraphicAction action = new GraphicActionUpdateRichtextStyle(instance, ref, styles, parentRef, richTextRef);
          WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
        }
      } catch (Exception e) {
        WXLogUtils.e("[WXBridgeManager] callUpdateRichtextStyle exception: ", e);
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callUpdateRichtextStyle",
                WXLogUtils.getStackTrace(e), null);
      }
  
      return IWXBridge.INSTANCE_RENDERING;
    }
    public int callUpdateRichtextChildAttr(String instanceId, String ref, HashMap<String, String> attrs, String parentRef, String richTextRef){
      if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref)) {
        if (WXEnvironment.isApkDebugable()){
          WXLogUtils.d("[WXBridgeManager] call callUpdateRichtextChildAttr arguments is null");
        }
  
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callUpdateRichtextChildAttr",
                "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
        return IWXBridge.INSTANCE_RENDERING_ERROR;
      }
  
      if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
        mLodBuilder.append("[WXBridgeManager] callUpdateRichtextChildAttr >>>> instanceId:").append(instanceId)
                .append(", ref:").append(ref).append(", attrs:").append(attrs.toString()).append(", parentRef:")
                .append(parentRef).append(", richTextRef:").append(richTextRef);
        WXLogUtils.d(mLodBuilder.substring(0));
        mLodBuilder.setLength(0);
      }
  
      if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
        return IWXBridge.DESTROY_INSTANCE;
      }
      try {
        WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
        if (instance != null) {
          final BasicGraphicAction action = new GraphicActionUpdateRichtextAttr(instance, ref, attrs, parentRef, richTextRef);
          WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
        }
      } catch (Exception e) {
        WXLogUtils.e("[WXBridgeManager] callUpdateRichtextChildAttr exception: ", e);
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callUpdateRichtextChildAttr",
                WXLogUtils.getStackTrace(e), null);
      }
  
      return IWXBridge.INSTANCE_RENDERING;
    }
  
    public int callLayout(String pageId, String ref, int top, int bottom, int left, int right, int height, int width, boolean isRTL, int index) {
  
      if (TextUtils.isEmpty(pageId) || TextUtils.isEmpty(ref)) {
          if (WXEnvironment.isApkDebugable()){
              WXLogUtils.d("[WXBridgeManager] call callLayout arguments is null");
          }
  
        WXExceptionUtils.commitCriticalExceptionRT(pageId,
                WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callLayout",
                "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
        return IWXBridge.INSTANCE_RENDERING_ERROR;
      }
  
      if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
        mLodBuilder.append("[WXBridgeManager] callLayout >>>> instanceId:").append(pageId)
              .append(", ref:").append(ref).append(", height:").append(height).append(", width:").append(width)
                .append(", top:").append(top)
                .append(", bottom:").append(bottom)
                .append(", left:").append(left)
                .append(", right:").append(right);
        WXLogUtils.d(mLodBuilder.substring(0));
        mLodBuilder.setLength(0);
      }
  
      if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(pageId)) {
        return IWXBridge.DESTROY_INSTANCE;
      }
  
      try {
        WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(pageId);
        if (instance != null) {
          GraphicSize size = new GraphicSize(width, height);
          GraphicPosition position = new GraphicPosition(left, top, right, bottom);
          setExceedGPULimitComponentsInfo(pageId,ref,size);
          GraphicActionAddElement addAction = instance.getInActiveAddElementAction(ref);
          if(addAction!=null) {
            addAction.setRTL(isRTL);
            addAction.setSize(size);
            addAction.setPosition(position);
            if(!TextUtils.equals(ref, WXComponent.ROOT)) {
              addAction.setIndex(index);
            }
            WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(pageId, addAction);
            instance.removeInActiveAddElmentAction(ref);
          }
          else {
            final BasicGraphicAction action = new GraphicActionLayout(instance, ref, position, size, isRTL);
            WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(action.getPageId(), action);
          }
        }
      } catch (Exception e) {
        WXLogUtils.e("[WXBridgeManager] callLayout exception: ", e);
        WXExceptionUtils.commitCriticalExceptionRT(pageId,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callLayout",
                WXLogUtils.getStackTrace(e), null);
      }
  
      return IWXBridge.INSTANCE_RENDERING;
    }
  
    public int callAppendTreeCreateFinish(String instanceId, String ref) {
  
      if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(ref)) {
        WXLogUtils.d("[WXBridgeManager] call callAppendTreeCreateFinish arguments is null");
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callAppendTreeCreateFinish",
                "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
        return IWXBridge.INSTANCE_RENDERING_ERROR;
      }
  
      if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
        mLodBuilder.append("[WXBridgeManager] callAppendTreeCreateFinish >>>> instanceId:").append(instanceId)
                .append(", ref:").append(ref);
        WXLogUtils.d(mLodBuilder.substring(0));
        mLodBuilder.setLength(0);
      }
  
      if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
        return IWXBridge.DESTROY_INSTANCE;
      }
  
      try {
        WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
        GraphicActionAppendTreeCreateFinish action = new GraphicActionAppendTreeCreateFinish(instance, ref);
        WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(instanceId, action);
      } catch (Exception e) {
        WXLogUtils.e("[WXBridgeManager] callAppendTreeCreateFinish exception: ", e);
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callAppendTreeCreateFinish",
                WXLogUtils.getStackTrace(e), null);
      }
  
      return IWXBridge.INSTANCE_RENDERING;
    }
  
    public int callCreateFinish(String instanceId) {
  
      if (TextUtils.isEmpty(instanceId)) {
        WXLogUtils.d("[WXBridgeManager] call callCreateFinish arguments is null");
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callCreateFinish",
                "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
        return IWXBridge.INSTANCE_RENDERING_ERROR;
      }
  
      if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
        mLodBuilder.append("[WXBridgeManager] callCreateFinish >>>> instanceId:").append(instanceId);
        WXLogUtils.d(mLodBuilder.substring(0));
        mLodBuilder.setLength(0);
      }
  
      if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
        return IWXBridge.DESTROY_INSTANCE;
      }
  
      try {
        long start = System.currentTimeMillis();
        WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
        if (instance != null) {
          instance.getApmForInstance().onStage("callCreateFinish");
          instance.firstScreenCreateInstanceTime(start);
          GraphicActionCreateFinish action = new GraphicActionCreateFinish(instance);
          WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(instanceId, action);
        }
      } catch (Exception e) {
        WXLogUtils.e("[WXBridgeManager] callCreateFinish exception: ", e);
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callCreateFinish",
                WXLogUtils.getStackTrace(e), null);
      }
  
      return IWXBridge.INSTANCE_RENDERING;
    }
  
    public int callRenderSuccess(String instanceId) {
  
      if (TextUtils.isEmpty(instanceId)) {
        WXLogUtils.d("[WXBridgeManager] call callRenderSuccess arguments is null");
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_RENDER_ERR_BRIDGE_ARG_NULL, "callRenderSuccess",
                "arguments is empty, INSTANCE_RENDERING_ERROR will be set", null);
        return IWXBridge.INSTANCE_RENDERING_ERROR;
      }
  
      if (WXEnvironment.isApkDebugable() && BRIDGE_LOG_SWITCH) {
        mLodBuilder.append("[WXBridgeManager] callRenderSuccess >>>> instanceId:").append(instanceId);
        WXLogUtils.d(mLodBuilder.substring(0));
        mLodBuilder.setLength(0);
      }
  
      if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) {
        return IWXBridge.DESTROY_INSTANCE;
      }
  
      try {
        WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
        if (instance != null) {
          instance.getApmForInstance().onStage("callRenderSuccess");
          GraphicActionRenderSuccess action = new GraphicActionRenderSuccess(instance);
          WXSDKManager.getInstance().getWXRenderManager().postGraphicAction(instanceId, action);
        }
      } catch (Exception e) {
        WXLogUtils.e("[WXBridgeManager] callRenderSuccess exception: ", e);
        WXExceptionUtils.commitCriticalExceptionRT(instanceId,
                WXErrorCode.WX_KEY_EXCEPTION_INVOKE_BRIDGE, "callRenderSuccess",
                WXLogUtils.getStackTrace(e), null);
      }
  
      return IWXBridge.INSTANCE_RENDERING;
    }
  
    public ContentBoxMeasurement getMeasurementFunc(String instanceId, long renderObjectPtr) {
      ContentBoxMeasurement contentBoxMeasurement = null;
      WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
      if (instance != null) {
        contentBoxMeasurement = instance.getContentBoxMeasurement(renderObjectPtr);
      }
      return contentBoxMeasurement;
    }
  
    public void bindMeasurementToRenderObject(long ptr){
      if (isJSFrameworkInit()) {
        mWXBridge.bindMeasurementToRenderObject(ptr);
      }
    }
  
  
    /**
     * Native: Layout
     * @param instanceId
     * @return
     */
    @UiThread
    public boolean notifyLayout(String instanceId) {
      if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
        return mWXBridge.notifyLayout(instanceId);
      }
      return false;
    }
  
    @UiThread
    public void forceLayout(String instanceId) {
      if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
        mWXBridge.forceLayout(instanceId);
      }
    }
  
    /**
     * native: OnInstanceClose
     * should be called on JSThread
     * @param instanceId
     */
    public void onInstanceClose(String instanceId) {
      if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
        mWXBridge.onInstanceClose(instanceId);
      }
    }
  
    /**
     * native: SetDefaultHeightAndWidthIntoRootDom
     * @param instanceId
     * @param defaultWidth
     * @param defaultHeight
     */
    public void setDefaultRootSize(final String instanceId, final float defaultWidth, final float defaultHeight, final boolean isWidthWrapContent, final boolean isHeightWrapContent) {
      if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
        mWXBridge.setDefaultHeightAndWidthIntoRootDom(instanceId, defaultWidth, defaultHeight, isWidthWrapContent, isHeightWrapContent);
      }
    }
  
    public void setRenderContentWrapContentToCore(boolean wrap, final String instanceId) {
      if (isJSFrameworkInit()) {
        mWXBridge.setRenderContainerWrapContent(wrap, instanceId);
      }
    }
  
    public void setStyleWidth(String instanceId, String ref, float value) {
      if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
        mWXBridge.setStyleWidth(instanceId, ref, value);
      }
    }
  
    public void setStyleHeight(String instanceId, String ref, float value) {
      if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
        mWXBridge.setStyleHeight(instanceId, ref, value);
      }
    }
  
    public long[] getFirstScreenRenderTime(String instanceId) {
      if (isJSFrameworkInit()) {
        return mWXBridge.getFirstScreenRenderTime(instanceId);
      }
      return new long[]{0, 0, 0};
    }
  
    public long[] getRenderFinishTime(String instanceId) {
      if (isJSFrameworkInit()) {
        return mWXBridge.getRenderFinishTime(instanceId);
      }
      return new long[]{0, 0, 0};
    }
  
    public void setDeviceDisplay(final String instanceId, final float deviceWidth, final float deviceHeight, final float scale) {
      post(new Runnable() {
        @Override
        public void run() {
          mWXBridge.setDeviceDisplay(instanceId, deviceWidth, deviceHeight, scale);
        }
      });
    }
  
    public void updateInitDeviceParams(final String width, final String height, final String density, final String statusHeight){
      if(!isJSFrameworkInit()){
        return;
      }
      post(new Runnable() {
        @Override
        public void run() {
          mWXBridge.updateInitFrameworkParams(WXConfig.deviceWidth, width, WXConfig.deviceWidth);
        }
      });
      post(new Runnable() {
        @Override
        public void run() {
          mWXBridge.updateInitFrameworkParams(WXConfig.deviceHeight, height, WXConfig.deviceHeight);
        }
      });
  
      post(new Runnable() {
        @Override
        public void run() {
          mWXBridge.updateInitFrameworkParams(WXConfig.scale,  density, WXConfig.scale);
        }
      });
  
      if(statusHeight != null){
        post(new Runnable() {
          @Override
          public void run() {
            mWXBridge.updateInitFrameworkParams(WXConfig.androidStatusBarHeight,  statusHeight, WXConfig.androidStatusBarHeight);
          }
        });
      }
    }
  
    public void setMargin(String instanceId, String ref, CSSShorthand.EDGE edge, float value) {
      if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
        mWXBridge.setMargin(instanceId, ref, edge, value);
      }
    }
  
    public void setPadding(String instanceId, String ref, CSSShorthand.EDGE edge, float value) {
      if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
        mWXBridge.setPadding(instanceId, ref, edge, value);
      }
    }
  
    public void setPosition(String instanceId, String ref, CSSShorthand.EDGE edge, float value) {
      if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
        mWXBridge.setPosition(instanceId, ref, edge, value);
      }
    }
  
    public void markDirty(String instanceId, String ref, boolean dirty) {
      if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
        mWXBridge.markDirty(instanceId, ref, dirty);
      }
    }
    public void setViewPortWidth(String instanceId,float viewPortWidth){
      if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
        mWXBridge.setViewPortWidth(instanceId,viewPortWidth);
      }
    }
    public void setPageArgument(String instanceId,String key,String value){
      if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
        mWXBridge.setPageArgument(instanceId,key,value);
      }
    }
    public void reloadPageLayout(String instanceId){
      if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
        mWXBridge.reloadPageLayout(instanceId);
      }
    }
  
    public void setDeviceDisplayOfPage(String instanceId,float width,float height){
      if (isSkipFrameworkInit(instanceId) || isJSFrameworkInit()) {
        mWXBridge.setDeviceDisplayOfPage(instanceId,width,height);
      }
    }
  
    public int callHasTransitionPros(String instanceId, String ref, HashMap<String, String> styles) {
      WXComponent component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(instanceId, ref);
      if (null == component || null == component.getTransition() || null == component.getTransition().getProperties()) {
        return IWXBridge.DESTROY_INSTANCE;
      }
  
      for(String property : component.getTransition().getProperties()){
        if(styles.containsKey(property)){
          return IWXBridge.INSTANCE_RENDERING;
        }
      }
      return IWXBridge.INSTANCE_RENDERING_ERROR;
    }
  
    public void registerCoreEnv(String key, String value) {
      if (isJSFrameworkInit())
        mWXBridge.registerCoreEnv(key, value);
      else
        mWeexCoreEnvOptions.put(key, value);
    }
  
    private void onJsFrameWorkInitSuccees() {
      for (Map.Entry<String, String> entry : mWeexCoreEnvOptions.entrySet()) {
        mWXBridge.registerCoreEnv(entry.getKey(), entry.getValue());
      }
      mWeexCoreEnvOptions.clear();
    }
  
    public  String getWeexCoreThreadStackTrace(){
      if (null == mJSThread){
        return "null == mJSThread";
      }
      StringBuilder stringBuilder = new StringBuilder();
  
      try {
        stringBuilder.append(String.format("Thread Name: '%s'\n", mJSThread.getName()));
        stringBuilder.append(String.format(Locale.ENGLISH,"\"%s\" prio=%d tid=%d %s\n", mJSThread.getName(), mJSThread.getPriority(), mJSThread.getId(), mJSThread.getState()));
  
        for (StackTraceElement e: mJSThread.getStackTrace()){
          stringBuilder.append(String.format("\tat %s\n", e.toString()));
        }
      } catch (Exception var8) {
        Log.e("weex", "getJSThreadStackTrace error:", var8);
      }
      return stringBuilder.toString();
    }
  
  }
  