Java tutorial
/* * 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 com.taobao.weex.bridge; import android.content.Context; 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.v4.util.ArrayMap; import android.text.TextUtils; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.taobao.weex.WXEnvironment; import com.taobao.weex.WXRenderErrorCode; import com.taobao.weex.WXSDKInstance; import com.taobao.weex.WXSDKManager; import com.taobao.weex.adapter.IWXJSExceptionAdapter; import com.taobao.weex.adapter.IWXUserTrackAdapter; import com.taobao.weex.common.IWXBridge; import com.taobao.weex.common.IWXDebugProxy; import com.taobao.weex.common.WXConfig; import com.taobao.weex.common.WXErrorCode; import com.taobao.weex.common.WXException; import com.taobao.weex.common.WXJSBridgeMsgType; import com.taobao.weex.common.WXJSExceptionInfo; import com.taobao.weex.common.WXRefreshData; import com.taobao.weex.common.WXRuntimeException; import com.taobao.weex.common.WXThread; import com.taobao.weex.dom.DOMAction; import com.taobao.weex.dom.WXDomModule; import com.taobao.weex.dom.action.Action; import com.taobao.weex.dom.action.Actions; import com.taobao.weex.dom.action.TraceableAction; import com.taobao.weex.tracing.WXTracing; import com.taobao.weex.utils.WXExceptionUtils; import com.taobao.weex.utils.WXFileUtils; import com.taobao.weex.utils.WXJsonUtils; import com.taobao.weex.utils.WXLogUtils; import com.taobao.weex.utils.WXUtils; import com.taobao.weex.utils.WXViewUtils; import com.taobao.weex.utils.batch.BactchExecutor; import com.taobao.weex.utils.batch.Interceptor; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.InputStreamReader; import java.lang.reflect.Constructor; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Stack; import static com.taobao.weex.bridge.WXModuleManager.getDomModule; import static com.taobao.weex.bridge.WXModuleManager.createDomModule; /** * 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 { public static final String METHOD_CREATE_INSTANCE = "createInstance"; 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 METHOD_CALLBACK = "callback"; public static final String METHOD_REFRESH_INSTANCE = "refreshInstance"; public static final String METHOD_NOTIFY_TRIM_MEMORY = "notifyTrimMemory"; public static final String METHOD_NOTIFY_SERIALIZE_CODE_CACHE = "notifySerializeCodeCache"; 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 int INIT_FRAMEWORK_OK = 1; private static final int CRASHREINIT = 50; static volatile WXBridgeManager mBridgeManager; private static long LOW_MEM_VALUE = 120; private volatile static int reInitCount = 1; private static String crashUrl = null; private static long lastCrashTime = 0; /** * Whether JS Framework(main.js) has been initialized. */ private volatile static boolean mInit = false; /** * 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 IWXDebugProxy 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 List<String> mDestroyedInstanceId = new ArrayList<>(); 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; } // setJSFrameworkInit and isJSFrameworkInit may use on diff thread // use volatile private boolean isJSFrameworkInit() { return mInit; } private void setJSFrameworkInit(boolean init) { mInit = init; } private void initWXBridge(boolean remoteDebug) { if (remoteDebug && WXEnvironment.isApkDebugable()) { WXEnvironment.sDebugServerConnectable = true; } if (mWxDebugProxy != null) { mWxDebugProxy.stop(false); } if (WXEnvironment.sDebugServerConnectable && (WXEnvironment.isApkDebugable() || WXEnvironment.sForceEnableDevTool)) { if (WXEnvironment.getApplication() != null) { try { Class clazz = Class.forName("com.taobao.weex.devtools.debug.DebugServerProxy"); if (clazz != null) { Constructor constructor = clazz.getConstructor(Context.class, WXBridgeManager.class); if (constructor != null) { mWxDebugProxy = (IWXDebugProxy) constructor.newInstance(WXEnvironment.getApplication(), WXBridgeManager.this); if (mWxDebugProxy != null) { mWxDebugProxy.start(); } } } } catch (Throwable e) { //Ignore, It will throw Exception on Release environment } WXServiceManager.execAllCacheJsService(); } else { WXLogUtils.e("WXBridgeManager", "WXEnvironment.sApplication is null, skip init Inspector"); WXLogUtils.w("WXBridgeManager", new Throwable("WXEnvironment.sApplication is null when init Inspector")); } } if (remoteDebug && mWxDebugProxy != null) { mWXBridge = mWxDebugProxy.getWXBridge(); } else { mWXBridge = new WXBridge(); } } public void stopRemoteDebug() { if (mWxDebugProxy != null) { mWxDebugProxy.stop(true); } } 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; } } return WXModuleManager.callModuleMethod(instanceId, moduleStr, methodStr, args); } /** * Model switch. For now, debug model and release model are supported */ public void restart() { setJSFrameworkInit(false); initWXBridge(WXEnvironment.sRemoteDebugMode); } /** * Set current Instance * * @param instanceId {@link WXSDKInstance#mInstanceId} */ public synchronized void setStackTopInstance(final String instanceId) { post(new Runnable() { @Override public void run() { mNextTickTasks.setStackTopInstance(instanceId); } }, instanceId); } @Override public void post(Runnable r) { if (mInterceptor != null && mInterceptor.take(r)) { //task is token by the interceptor return; } if (mJSHandler == null) { return; } mJSHandler.post(WXThread.secure(r)); } @Override public void setInterceptor(Interceptor interceptor) { mInterceptor = interceptor; } public void post(Runnable r, Object token) { if (mJSHandler == null) { return; } Message m = Message.obtain(mJSHandler, WXThread.secure(r)); m.obj = token; m.sendToTarget(); } 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 (WXEnvironment.isApkDebugable()) { 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 = 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.getErrorCode(), "callNativeModule", err, null); } return null; } public Object callNativeModule(String instanceId, String module, String method, JSONArray arguments, JSONObject options) { if (WXEnvironment.isApkDebugable()) { 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 = 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] callNative exception: " + WXLogUtils.getStackTrace(e); WXLogUtils.e(err); WXExceptionUtils.commitCriticalExceptionRT(instanceId, WXErrorCode.WX_KEY_EXCEPTION_INVOKE.getErrorCode(), "callNativeModule", err, null); } return null; } public Object callNativeComponent(String instanceId, String componentRef, String method, JSONArray arguments, Object options) { if (WXEnvironment.isApkDebugable()) { 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 = getDomModule(instanceId); dom.invokeMethod(componentRef, method, arguments); } catch (Exception e) { WXLogUtils.e("[WXBridgeManager] callNative exception: ", e); WXExceptionUtils.commitCriticalExceptionRT(instanceId, WXErrorCode.WX_KEY_EXCEPTION_INVOKE.getErrorCode(), "callNativeComponent", WXLogUtils.getStackTrace(e), null); } return null; } /** * Dispatch the native task to be executed. * * @param instanceId {@link WXSDKInstance#mInstanceId} * @param tasks tasks to be executed * @param callback next tick id */ public int callNative(String instanceId, String tasks, String callback) { if (TextUtils.isEmpty(tasks)) { String err = "[WXBridgeManager] callNative: call Native tasks is null"; WXLogUtils.e(err); WXExceptionUtils.commitCriticalExceptionRT(instanceId, WXErrorCode.WX_KEY_EXCEPTION_INVOKE.getErrorCode(), "callNative", err + "| INSTANCE_RENDERING_ERROR will be set", null); return IWXBridge.INSTANCE_RENDERING_ERROR; } if (WXEnvironment.isApkDebugable()) { 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 start = System.currentTimeMillis(); long parseNanos = System.nanoTime(); JSONArray array = JSON.parseArray(tasks); parseNanos = System.nanoTime() - parseNanos; if (WXSDKManager.getInstance().getSDKInstance(instanceId) != null) { WXSDKManager.getInstance().getSDKInstance(instanceId).jsonParseTime(System.currentTimeMillis() - start); } int size = array.size(); if (size > 0) { try { JSONObject task; for (int i = 0; i < size; ++i) { task = (JSONObject) array.get(i); if (task != null && WXSDKManager.getInstance().getSDKInstance(instanceId) != null) { Object target = task.get(MODULE); if (target != null) { if (WXDomModule.WXDOM.equals(target)) { WXDomModule dom = getDomModule(instanceId); dom.callDomMethod(task, parseNanos); } else { JSONObject optionObj = task.getJSONObject(OPTIONS); callModuleMethod(instanceId, (String) target, (String) task.get(METHOD), (JSONArray) task.get(ARGS), optionObj); } } else if (task.get(COMPONENT) != null) { //call component WXDomModule dom = getDomModule(instanceId); 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.getErrorCode(), "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; } // callCreateBody public int callCreateBody(String instanceId, String tasks, String callback) { if (TextUtils.isEmpty(tasks)) { // if (WXEnvironment.isApkDebugable()) { WXLogUtils.d("[WXBridgeManager] callCreateBody: call CreateBody tasks is null"); // } WXExceptionUtils.commitCriticalExceptionRT(instanceId, WXErrorCode.WX_KEY_EXCEPTION_INVOKE.getErrorCode(), "callCreateBody", "tasks is empty, INSTANCE_RENDERING_ERROR will be set", null); return IWXBridge.INSTANCE_RENDERING_ERROR; } // if (WXEnvironment.isApkDebugable()) { mLodBuilder.append("[WXBridgeManager] callCreateBody >>>> 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; } try { if (WXSDKManager.getInstance().getSDKInstance(instanceId) != null) { long start = System.currentTimeMillis(); long nanosTemp = System.nanoTime(); JSONObject domObject = JSON.parseObject(tasks); nanosTemp = System.nanoTime() - nanosTemp; WXDomModule domModule = getDomModule(instanceId); Action action = Actions.getCreateBody(domObject); domModule.postAction((DOMAction) action, true); if (WXTracing.isAvailable() && action instanceof TraceableAction) { ((TraceableAction) action).mParseJsonNanos = nanosTemp; ((TraceableAction) action).mStartMillis = start; ((TraceableAction) action).onStartDomExecute(instanceId, "createBody", "_root", domObject.getString("type"), tasks); } } } catch (Exception e) { WXLogUtils.e("[WXBridgeManager] callCreateBody exception: ", e); WXExceptionUtils.commitCriticalExceptionRT(instanceId, WXErrorCode.WX_KEY_EXCEPTION_INVOKE.getErrorCode(), "callCreateBody", 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 (WXEnvironment.isApkDebugable()) { 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) { WXDomModule domModule = getDomModule(instanceId); Action action = Actions.getUpdateFinish(); domModule.postAction((DOMAction) action, false); } } catch (Exception e) { WXLogUtils.e("[WXBridgeManager] callUpdateFinish exception: ", e); WXExceptionUtils.commitCriticalExceptionRT(instanceId, WXErrorCode.WX_KEY_EXCEPTION_INVOKE.getErrorCode(), "callUpdateFinish", 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; } // callCreateFinish public int callCreateFinish(String instanceId, String callback) { // if (WXEnvironment.isApkDebugable()) { mLodBuilder.append("[WXBridgeManager] callCreateFinish >>>> 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) { WXDomModule domModule = getDomModule(instanceId); Action action = Actions.getCreateFinish(); domModule.postAction((DOMAction) action, false); } } catch (Exception e) { WXLogUtils.e("[WXBridgeManager] callCreateFinish exception: ", e); WXExceptionUtils.commitCriticalExceptionRT(instanceId, WXErrorCode.WX_KEY_EXCEPTION_INVOKE.getErrorCode(), "callUpdateFinish", 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; } // callRefreshFinish public int callRefreshFinish(String instanceId, String callback) { if (WXEnvironment.isApkDebugable()) { 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 { if (WXSDKManager.getInstance().getSDKInstance(instanceId) != null) { WXDomModule domModule = getDomModule(instanceId); Action action = Actions.getRefreshFinish(); domModule.postAction((DOMAction) action, false); } } catch (Exception e) { WXLogUtils.e("[WXBridgeManager] callRefreshFinish exception: ", e); WXExceptionUtils.commitCriticalExceptionRT(instanceId, WXErrorCode.WX_KEY_EXCEPTION_INVOKE.getErrorCode(), "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; } // callUpdateAttrs public int callUpdateAttrs(String instanceId, String ref, String task, String callback) { if (TextUtils.isEmpty(task)) { WXLogUtils.e("[WXBridgeManager] callUpdateAttrs: call UpdateAttrs tasks is null"); WXExceptionUtils.commitCriticalExceptionRT(instanceId, WXErrorCode.WX_KEY_EXCEPTION_INVOKE.getErrorCode(), "callUpdateAttrs", "call UpdateAttrs tasks is null| INSTANCE_RENDERING_ERROR will be set", null); return IWXBridge.INSTANCE_RENDERING_ERROR; } if (WXEnvironment.isApkDebugable()) { mLodBuilder.append("[WXBridgeManager] callUpdateAttrs >>>> instanceId:").append(instanceId) .append(", ref:").append(ref).append(", task:").append(task).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) { WXDomModule domModule = getDomModule(instanceId); long start = System.currentTimeMillis(); long parseNanos = System.nanoTime(); JSONObject domObject = JSON.parseObject(task); parseNanos = System.nanoTime() - parseNanos; Action action = Actions.getUpdateAttrs(ref, domObject); domModule.postAction((DOMAction) action, false); if (WXTracing.isAvailable() && action instanceof TraceableAction) { ((TraceableAction) action).mStartMillis = start; ((TraceableAction) action).mParseJsonNanos = parseNanos; ((TraceableAction) action).onStartDomExecute(instanceId, "updateAttrs", domObject.getString("ref"), domObject.getString("type"), task); } } } catch (Exception e) { WXLogUtils.e("[WXBridgeManager] callUpdateAttrs exception: ", e); WXExceptionUtils.commitCriticalExceptionRT(instanceId, WXErrorCode.WX_KEY_EXCEPTION_INVOKE.getErrorCode(), "callUpdateAttrs", 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; } // callUpdateStyle public int callUpdateStyle(String instanceId, String ref, String task, String callback) { if (TextUtils.isEmpty(task)) { WXLogUtils.e("[WXBridgeManager] callUpdateStyle: call UpdateStyle tasks is null"); WXExceptionUtils.commitCriticalExceptionRT(instanceId, WXErrorCode.WX_KEY_EXCEPTION_INVOKE.getErrorCode(), "callUpdateStyle", "task is empty", null); return IWXBridge.INSTANCE_RENDERING_ERROR; } if (WXEnvironment.isApkDebugable()) { mLodBuilder.append("[WXBridgeManager] callUpdateStyle >>>> instanceId:").append(instanceId) .append(", ref:").append(ref).append(", task:").append(task).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) { WXDomModule domModule = getDomModule(instanceId); long start = System.currentTimeMillis(); long nanosTemp = System.nanoTime(); JSONObject domObject = JSON.parseObject(task); nanosTemp = System.nanoTime() - nanosTemp; Action action = Actions.getUpdateStyle(ref, domObject, false); domModule.postAction((DOMAction) action, false); if (WXTracing.isAvailable() && action instanceof TraceableAction) { ((TraceableAction) action).mParseJsonNanos = nanosTemp; ((TraceableAction) action).mStartMillis = start; ((TraceableAction) action).onStartDomExecute(instanceId, "updateStyle", ref, domObject.getString("type"), domObject.toJSONString()); } } } catch (Exception e) { WXLogUtils.e("[WXBridgeManager] callUpdateStyle exception: ", e); WXExceptionUtils.commitCriticalExceptionRT(instanceId, WXErrorCode.WX_KEY_EXCEPTION_INVOKE.getErrorCode(), "callUpdateStyle", 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; } // callUpdateStyle public int callRemoveElement(String instanceId, String ref, String callback) { if (WXEnvironment.isApkDebugable()) { 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 { if (WXSDKManager.getInstance().getSDKInstance(instanceId) != null) { WXDomModule domModule = getDomModule(instanceId); Action action = Actions.getRemoveElement(ref); domModule.postAction((DOMAction) action, false); if (WXTracing.isAvailable() && action instanceof TraceableAction) { ((TraceableAction) action).onStartDomExecute(instanceId, "removeElement", ref, null, ref); } } } catch (Exception e) { WXLogUtils.e("[WXBridgeManager] callRemoveElement exception: ", e); WXExceptionUtils.commitCriticalExceptionRT(instanceId, WXErrorCode.WX_KEY_EXCEPTION_INVOKE.getErrorCode(), "callRemoveElement", 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; } // callMoveElement public int callMoveElement(String instanceId, String ref, String parentref, String index, String callback) { if (WXEnvironment.isApkDebugable()) { 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 { if (WXSDKManager.getInstance().getSDKInstance(instanceId) != null) { WXDomModule domModule = getDomModule(instanceId); Action action = Actions.getMoveElement(ref, parentref, Integer.parseInt(index)); domModule.postAction((DOMAction) action, false); } } catch (Exception e) { WXLogUtils.e("[WXBridgeManager] callMoveElement exception: ", e); WXExceptionUtils.commitCriticalExceptionRT(instanceId, WXErrorCode.WX_KEY_EXCEPTION_INVOKE.getErrorCode(), "callMoveElement", 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 callAddEvent(String instanceId, String ref, String event, String callback) { // if (WXEnvironment.isApkDebugable()) { 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 { if (WXSDKManager.getInstance().getSDKInstance(instanceId) != null) { WXDomModule domModule = getDomModule(instanceId); Action action = Actions.getAddEvent(ref, event); domModule.postAction((DOMAction) action, false); if (WXTracing.isAvailable() && action instanceof TraceableAction) { ((TraceableAction) action).onStartDomExecute(instanceId, "addEvent", ref, null, event); } } } catch (Exception e) { WXLogUtils.e("[WXBridgeManager] callAddEvent exception: ", e); WXExceptionUtils.commitCriticalExceptionRT(instanceId, WXErrorCode.WX_KEY_EXCEPTION_INVOKE.getErrorCode(), "callAddEvent", 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 callRemoveEvent(String instanceId, String ref, String event, String callback) { if (WXEnvironment.isApkDebugable()) { 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 { if (WXSDKManager.getInstance().getSDKInstance(instanceId) != null) { WXDomModule domModule = getDomModule(instanceId); Action action = Actions.getRemoveEvent(ref, event); domModule.postAction((DOMAction) action, false); if (WXTracing.isAvailable() && action instanceof TraceableAction) { ((TraceableAction) action).onStartDomExecute(instanceId, "removeEvent", ref, null, event); } } } catch (Exception e) { WXLogUtils.e("[WXBridgeManager] callRemoveEvent exception: ", e); WXExceptionUtils.commitCriticalExceptionRT(instanceId, WXErrorCode.WX_KEY_EXCEPTION_INVOKE.getErrorCode(), "callAddEvent", 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 callAddElement(String instanceId, String ref, String dom, String index, String callback) { if (WXEnvironment.isApkDebugable()) { mLodBuilder.append("[WXBridgeManager] callNative::callAddElement >>>> instanceId:").append(instanceId) .append(", ref:").append(ref).append(", dom:").append(dom).append(", callback:") .append(callback); WXLogUtils.d(mLodBuilder.substring(0)); mLodBuilder.setLength(0); } if (mDestroyedInstanceId != null && mDestroyedInstanceId.contains(instanceId)) { return IWXBridge.DESTROY_INSTANCE; } if (WXSDKManager.getInstance().getSDKInstance(instanceId) != null) { long start = System.currentTimeMillis(); long nanosTemp = System.nanoTime(); JSONObject domObject = JSON.parseObject(dom); nanosTemp = System.nanoTime() - nanosTemp; if (WXSDKManager.getInstance().getSDKInstance(instanceId) != null) { WXSDKManager.getInstance().getSDKInstance(instanceId) .jsonParseTime(System.currentTimeMillis() - start); } WXDomModule domModule = getDomModule(instanceId); DOMAction addElementAction = Actions.getAddElement(domObject, ref, Integer.parseInt(index)); domModule.postAction(addElementAction, false); if (WXTracing.isAvailable() && addElementAction instanceof TraceableAction) { ((TraceableAction) addElementAction).mParseJsonNanos = nanosTemp; ((TraceableAction) addElementAction).mStartMillis = start; ((TraceableAction) addElementAction).onStartDomExecute(instanceId, "addElement", domObject.getString("ref"), domObject.getString("type"), dom); } } 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) { try { String url = null; WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId); if (instance != null) { url = instance.getBundleUrl(); } try { if (WXEnvironment.getApplication() != null) { crashFile = WXEnvironment.getApplication().getApplicationContext().getCacheDir().getPath() + crashFile; // Log.e("jsengine", "callReportCrashReloadPage crashFile:" + crashFile); } } catch (Throwable e) { e.printStackTrace(); } callReportCrash(crashFile, instanceId, url); if (reInitCount > CRASHREINIT) { return IWXBridge.INSTANCE_RENDERING_ERROR; } reInitCount++; // reinit frame work setJSFrameworkInit(false); 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 = shouReloadCurrentInstance( WXSDKManager.getInstance().getSDKInstance(instanceId).getBundleUrl()); WXDomModule domModule = getDomModule(instanceId); Action action = Actions.getReloadPage(instanceId, reloadThisInstance); domModule.postAction((DOMAction) action, true); } } catch (Exception e) { WXLogUtils.e("[WXBridgeManager] callReloadPage exception: ", e); WXExceptionUtils.commitCriticalExceptionRT(instanceId, WXErrorCode.WX_KEY_EXCEPTION_INVOKE.getErrorCode(), "callReloadPage", WXLogUtils.getStackTrace(e), null); } return IWXBridge.INSTANCE_RENDERING_ERROR; } public boolean shouReloadCurrentInstance(String aUrl) { long time = System.currentTimeMillis(); if (crashUrl == null || (crashUrl != null && !crashUrl.equals(aUrl)) || ((time - lastCrashTime) > 15000)) { crashUrl = aUrl; lastCrashTime = time; return true; } lastCrashTime = time; return false; } public void callReportCrash(String crashFile, final String instanceId, final String url) { // statistic weexjsc process crash Date date = new Date(); DateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); 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); br.close(); } catch (Exception e) { e.printStackTrace(); } } else { WXLogUtils.e("[WXBridgeManager] callReportCrash crash file is empty"); } 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 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); } /** * 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) { 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"); } addJSEventTask(METHOD_FIRE_EVENT, instanceId, params, ref, type, data, domChanges); sendMessage(instanceId, WXJSBridgeMsgType.CALL_JS_BATCH); } 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; } addJSTask(METHOD_CALLBACK, instanceId, callback, data, keepAlive); sendMessage(instanceId, WXJSBridgeMsgType.CALL_JS_BATCH); } /** * 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 { if (!isJSFrameworkInit()) { WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId); if (instance != null) { instance.onRenderError( WXRenderErrorCode.DegradPassivityCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED .getDegradErrorCode(), WXRenderErrorCode.DegradPassivityCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED .getDegradErrorMsg() + "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 }; invokeExecJS(instanceId, null, METHOD_REFRESH_INSTANCE, args); WXLogUtils.renderPerformanceLog("invokeRefreshInstance", System.currentTimeMillis() - start); } catch (Throwable e) { String err = "[WXBridgeManager] invokeRefreshInstance " + WXLogUtils.getStackTrace(e); WXExceptionUtils.commitCriticalExceptionRT(instanceId, WXErrorCode.WX_KEY_EXCEPTION_INVOKE.getErrorCode(), "invokeRefreshInstance", err, null); WXLogUtils.e(err); } } // public void commitJSBridgeAlarmMonitor(String instanceId, WXErrorCode errCode, String errMsg) { // WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId); // if (instance == null || errCode == null) { // return; // } // // TODO: We should move WXPerformance and IWXUserTrackAdapter // // into a adapter level. // // comment out the line below to prevent commiting twice. // //instance.commitUTStab(WXConst.JS_BRIDGE, errCode, errMsg); // // IWXUserTrackAdapter adapter = WXSDKManager.getInstance().getIWXUserTrackAdapter(); // if (adapter == null) { // return; // } // WXPerformance performance = new WXPerformance(); // performance.args = instance.getBundleUrl(); // performance.errCode = errCode.getErrorCode(); // if (errCode != WXErrorCode.WX_SUCCESS) { // performance.appendErrMsg(TextUtils.isEmpty(errMsg) ? errCode.getErrorMsg() : errMsg); // WXLogUtils.e("wx_monitor", performance.toString()); // } // adapter.commit(WXEnvironment.getApplication(), null, IWXUserTrackAdapter.JS_BRIDGE, performance, instance.getUserTrackParams()); // } // public void commitJSFrameworkAlarmMonitor(final String type, final WXErrorCode errorCode, String errMsg) { // if (TextUtils.isEmpty(type) || errorCode == null) { // return; // } // if (WXSDKManager.getInstance().getWXStatisticsListener() != null) { // WXSDKManager.getInstance().getWXStatisticsListener().onException("0", // errorCode.getErrorCode(), // TextUtils.isEmpty(errMsg) ? errorCode.getErrorMsg() : errMsg); // } // // final IWXUserTrackAdapter userTrackAdapter = WXSDKManager.getInstance().getIWXUserTrackAdapter(); // if (userTrackAdapter == null) { // return; // } // WXPerformance performance = new WXPerformance(); // performance.errCode = errorCode.getErrorCode(); // if (errorCode != WXErrorCode.WX_SUCCESS) { // performance.appendErrMsg(TextUtils.isEmpty(errMsg) ? errorCode.getErrorMsg() : errMsg); // WXLogUtils.e("wx_monitor", performance.toString()); // } // userTrackAdapter.commit(WXEnvironment.getApplication(), null, type, performance, null); // } public void commitJscCrashAlarmMonitor(final String type, final WXErrorCode errorCode, String errMsg, String instanceId, String url) { if (TextUtils.isEmpty(type) || errorCode == null) { return; } String method = "callReportCrash"; String exception = "weexjsc process crash and restart exception"; Map<String, String> extParams = new HashMap<String, String>(); extParams.put("jscCrashStack", errMsg); IWXJSExceptionAdapter adapter = WXSDKManager.getInstance().getIWXJSExceptionAdapter(); if (adapter != null) { WXJSExceptionInfo jsException = new WXJSExceptionInfo(instanceId, url, errorCode.getErrorCode(), method, exception, extParams); adapter.onJSException(jsException); // if (WXEnvironment.isApkDebugable()) { WXLogUtils.e(jsException.toString()); // } } } /** * Create instance. */ public void createInstance(final String instanceId, final String 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 is not exist"); return; } if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(template) || mJSHandler == null) { instance.onRenderError( WXRenderErrorCode.DegradPassivityCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getDegradErrorCode(), WXRenderErrorCode.DegradPassivityCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getDegradErrorMsg() + " instanceId==" + instanceId + " template ==" + template + " mJSHandler== " + mJSHandler.toString()); return; } if (!isJSFrameworkInit() && reInitCount == 1 && !WXEnvironment.sDebugServerConnectable) { instance.onRenderError( WXRenderErrorCode.DegradPassivityCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getDegradErrorCode(), WXRenderErrorCode.DegradPassivityCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED.getDegradErrorMsg() + " isJSFrameworkInit==" + isJSFrameworkInit() + " reInitCount == 1"); post(new Runnable() { @Override public void run() { initFramework(""); } }, instanceId); return; } WXModuleManager.createDomModule(instance); post(new Runnable() { @Override public void run() { long start = System.currentTimeMillis(); invokeCreateInstance(instance, template, options, data); final long totalTime = System.currentTimeMillis() - start; WXSDKManager.getInstance().postOnUiThread(new Runnable() { @Override public void run() { instance.createInstanceFinished(totalTime); } }, 0); } }, instanceId); } private void invokeCreateInstance(@NonNull WXSDKInstance instance, String template, Map<String, Object> options, String data) { initFramework(""); if (mMock) { mock(instance.getInstanceId()); } else { if (!isJSFrameworkInit()) { String err = "[WXBridgeManager] invokeCreateInstance: framework.js uninitialized."; instance.onRenderError( WXRenderErrorCode.DegradPassivityCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED .getDegradErrorCode(), WXRenderErrorCode.DegradPassivityCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED .getDegradErrorMsg()); WXLogUtils.e(err); return; } try { if (WXEnvironment.isApkDebugable()) { WXLogUtils.d("createInstance >>>> instanceId:" + instance.getInstanceId() + ", options:" + WXJsonUtils.fromObjectToJSONString(options) + ", data:" + data); } WXJSObject instanceIdObj = new WXJSObject(WXJSObject.String, instance.getInstanceId()); WXJSObject instanceObj = new WXJSObject(WXJSObject.String, template); WXJSObject optionsObj = new WXJSObject(WXJSObject.JSON, options == null ? "{}" : WXJsonUtils.fromObjectToJSONString(options)); WXJSObject dataObj = new WXJSObject(WXJSObject.JSON, data == null ? "{}" : data); WXJSObject[] args = { instanceIdObj, instanceObj, optionsObj, dataObj }; instance.setTemplate(template); invokeExecJS(instance.getInstanceId(), null, METHOD_CREATE_INSTANCE, args, false); } catch (Throwable e) { String err = "[WXBridgeManager] invokeCreateInstance " + e.getCause() + instance.getTemplateInfo(); instance.onRenderError( WXRenderErrorCode.DegradPassivityCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED .getDegradErrorCode(), WXRenderErrorCode.DegradPassivityCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED .getDegradErrorMsg() + err); WXLogUtils.e(err); } } } 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); } private void removeTaskByInstance(String instanceId) { mNextTickTasks.removeFromMapAndStack(instanceId); } private void invokeDestroyInstance(String instanceId) { try { if (WXEnvironment.isApkDebugable()) { WXLogUtils.d("destroyInstance >>>> instanceId:" + instanceId); } WXJSObject instanceIdObj = new WXJSObject(WXJSObject.String, instanceId); WXJSObject[] args = { instanceIdObj }; if (isJSFrameworkInit()) { invokeExecJS(instanceId, null, METHOD_DESTROY_INSTANCE, args); } } catch (Throwable e) { String err = "[WXBridgeManager] invokeDestroyInstance " + e.getCause(); WXExceptionUtils.commitCriticalExceptionRT(instanceId, WXErrorCode.WX_KEY_EXCEPTION_INVOKE.getErrorCode(), "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(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.execJS(instanceId, namespace, function, args); } 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); } } private void initFramework(String framework) { if (!isJSFrameworkInit()) { if (TextUtils.isEmpty(framework)) { // if (WXEnvironment.isApkDebugable()) { WXLogUtils.d("weex JS framework from assets"); // } framework = WXFileUtils.loadAsset("main.js", WXEnvironment.getApplication()); } if (TextUtils.isEmpty(framework)) { setJSFrameworkInit(false); WXExceptionUtils.commitCriticalExceptionRT(null, WXErrorCode.WX_ERR_JS_FRAMEWORK.getErrorCode(), "initFramework", "framework is empty!! ", null); return; } try { if (WXSDKManager.getInstance().getWXStatisticsListener() != null) { WXSDKManager.getInstance().getWXStatisticsListener().onJsFrameworkStart(); } long start = System.currentTimeMillis(); String crashFile = ""; try { crashFile = WXEnvironment.getApplication().getApplicationContext().getCacheDir().getPath(); } catch (Exception e) { e.printStackTrace(); } boolean pieSupport = true; try { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { pieSupport = false; } } catch (Exception e) { e.printStackTrace(); } WXLogUtils.d( "[WXBridgeManager] initFrameworkEnv crashFile:" + crashFile + " pieSupport:" + pieSupport); // extends initFramework if (mWXBridge.initFrameworkEnv(framework, assembleDefaultOptions(), crashFile, pieSupport) == INIT_FRAMEWORK_OK) { WXEnvironment.sJSLibInitTime = System.currentTimeMillis() - start; WXLogUtils.renderPerformanceLog("initFramework", WXEnvironment.sJSLibInitTime); WXEnvironment.sSDKInitTime = System.currentTimeMillis() - WXEnvironment.sSDKInitStart; WXLogUtils.renderPerformanceLog("SDKInitTime", WXEnvironment.sSDKInitTime); setJSFrameworkInit(true); if (WXSDKManager.getInstance().getWXStatisticsListener() != null) { WXSDKManager.getInstance().getWXStatisticsListener().onJsFrameworkReady(); } execRegisterFailTask(); WXEnvironment.JsFrameworkInit = true; registerDomModule(); String reinitInfo = ""; if (reInitCount > 1) { reinitInfo = "reinit Framework:"; } } else { if (reInitCount > 1) { WXLogUtils.e("[WXBridgeManager] invokeReInitFramework ExecuteJavaScript fail"); String err = "[WXBridgeManager] invokeReInitFramework ExecuteJavaScript fail reinit FrameWork"; WXExceptionUtils.commitCriticalExceptionRT(null, WXErrorCode.WX_ERR_JS_FRAMEWORK.getErrorCode(), "initFramework", "reInitCount = " + reInitCount + err, null); } else { WXLogUtils.e("[WXBridgeManager] invokeInitFramework ExecuteJavaScript fail"); String err = "[WXBridgeManager] invokeInitFramework ExecuteJavaScript fail"; WXExceptionUtils.commitCriticalExceptionRT(null, WXErrorCode.WX_ERR_JS_FRAMEWORK.getErrorCode(), "initFramework", err, null); } } } catch (Throwable e) { if (reInitCount > 1) { WXLogUtils.e("[WXBridgeManager] invokeInitFramework ", e); String err = "[WXBridgeManager] invokeInitFramework reinit FrameWork exception!#" + e.toString(); WXExceptionUtils.commitCriticalExceptionRT(null, WXErrorCode.WX_ERR_JS_FRAMEWORK.getErrorCode(), "initFramework", "reInitCount ==" + reInitCount + err, null); } else { WXLogUtils.e("[WXBridgeManager] invokeInitFramework ", e); String err = "[WXBridgeManager] invokeInitFramework exception!#" + e.toString(); WXExceptionUtils.commitCriticalExceptionRT(null, WXErrorCode.WX_ERR_JS_FRAMEWORK.getErrorCode(), "initFramework", err, null); } } } } @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; } } task = ((ArrayList) task).toArray(); WXJSObject[] args = { new WXJSObject(WXJSObject.String, instanceId), new WXJSObject(WXJSObject.JSON, WXJsonUtils.fromObjectToJSONString(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.getErrorCode(), "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() { 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)); 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")); wxParams.setOptions(WXEnvironment.getCustomOptions()); 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, mRegisterComponentFailList); } }, null); } } } /** * Registered component */ public void registerComponents(final List<Map<String, Object>> components) { if (mJSHandler == null || components == null || components.size() == 0) { return; } post(new Runnable() { @Override public void run() { invokeRegisterComponents(components, mRegisterComponentFailList); } }, null); } public void execJSService(final String service) { post(new Runnable() { @Override public void run() { invokeExecJSService(service, mRegisterServiceFailList); } }); } 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.getErrorCode(), "invokeExecJSService", WXErrorCode.WX_KEY_EXCEPTION_INVOKE_JSSERVICE_EXECUTE.getErrorMsg() + "[WXBridgeManager] invokeRegisterService:" + WXLogUtils.getStackTrace(e), data); } } private 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 = { new WXJSObject(WXJSObject.JSON, WXJsonUtils.fromObjectToJSONString(modules)) }; try { mWXBridge.execJS("", null, METHOD_REGISTER_MODULES, args); } catch (Throwable e) { WXExceptionUtils.commitCriticalExceptionRT(null, WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_MODULES.getErrorCode(), "invokeRegisterModules", WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_MODULES.getErrorMsg() + " \n " + e.getMessage() + modules.entrySet().toString(), null); WXLogUtils.e("[WXBridgeManager] invokeRegisterModules:", e); } } 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 = { new WXJSObject(WXJSObject.JSON, WXJsonUtils.fromObjectToJSONString(components)) }; try { mWXBridge.execJS("", null, METHOD_REGISTER_COMPONENTS, args); } catch (Throwable e) { WXLogUtils.e("[WXBridgeManager] invokeRegisterComponents ", e); WXExceptionUtils.commitCriticalExceptionRT(null, WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_CONTENT_FAILED.getErrorCode(), METHOD_REGISTER_COMPONENTS, WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_CONTENT_FAILED.getErrorMsg() + args.toString() + WXLogUtils.getStackTrace(e), 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; if (instanceId != null && (instance = WXSDKManager.getInstance().getSDKInstance(instanceId)) != null) { exception += "\n getTemplateInfo==" + instance.getTemplateInfo();//add network header info if (METHOD_CREATE_INSTANCE.equals(function)) { try { if (isJSFrameworkInit() && reInitCount > 1 && !instance.isNeedReLoad()) { // JSONObject domObject = JSON.parseObject(tasks); WXDomModule domModule = getDomModule(instanceId); Action action = Actions.getReloadPage(instanceId, true); domModule.postAction((DOMAction) action, true); instance.setNeedLoad(true); return; } else { instance.onRenderError(//DegradPassivity to H5 WXRenderErrorCode.DegradPassivityCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED .getDegradErrorCode(), WXRenderErrorCode.DegradPassivityCode.WX_DEGRAD_ERR_INSTANCE_CREATE_FAILED .getDegradErrorMsg() + "reportJSException >>>> instanceId:" + instanceId + ", exception function:" + function + ", exception:" + exception); return; } } catch (Exception e) { e.printStackTrace(); } } instance.onJSException(WXErrorCode.WX_ERR_JS_EXECUTE.getErrorCode(), function, exception); } IWXJSExceptionAdapter adapter = WXSDKManager.getInstance().getIWXJSExceptionAdapter(); if (adapter != null) { String bundleUrl; String exceptionId = instanceId; if (instanceId == "" || instanceId == null) { exceptionId = "instanceIdisNull"; } if (instance == null) { if (("initFramework").equals(function)) { bundleUrl = "jsExceptionBeforeRenderInstanceNull"; 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) { e.printStackTrace(); } } file.delete(); } } catch (Throwable throwable) { } } } catch (Throwable e) { e.printStackTrace(); } exception += "\n" + exceptionExt; WXLogUtils.e("reportJSException:" + exception); } else if (function == null) { bundleUrl = "jsExceptionInstanceAndFunctionNull"; } else { bundleUrl = "jsExceptionInstanceNull" + function; } } else { bundleUrl = instance.getBundleUrl(); } // WXJSExceptionInfo jsException = new WXJSExceptionInfo(exceptionId, bundleUrl, WXErrorCode.WX_ERR_JS_EXECUTE.getErrorCode(), function, exception, null); // adapter.onJSException(jsException); WXExceptionUtils.commitCriticalExceptionRT(exceptionId, WXErrorCode.WX_KEY_EXCEPTION_WXBRIDGE.getErrorCode(), function, WXErrorCode.WX_KEY_EXCEPTION_WXBRIDGE.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() { } 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; } }